aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/fs/psp/psp-stream.cpp291
-rw-r--r--backends/fs/psp/psp-stream.h32
-rw-r--r--backends/module.mk1
-rw-r--r--backends/platform/ds/arm7/source/main.cpp4
-rw-r--r--backends/platform/ds/arm9/makefile2
-rw-r--r--backends/platform/ds/arm9/source/dsmain.cpp4
-rw-r--r--backends/platform/ds/commoninclude/NDS/scummvm_ipc.h12
-rw-r--r--backends/platform/gp2x/graphics.cpp5
-rw-r--r--backends/platform/gp2xwiz/gp2xwiz-graphics.cpp5
-rw-r--r--backends/platform/linuxmoto/linuxmoto-graphics.cpp5
-rw-r--r--backends/platform/ps2/Makefile.ps291
-rw-r--r--backends/platform/ps2/elf32.h209
-rw-r--r--backends/platform/ps2/main_prog.ld97
-rw-r--r--backends/platform/ps2/module.mk3
-rw-r--r--backends/platform/ps2/plugin.ld214
-rw-r--r--backends/platform/ps2/plugin.syms8
-rw-r--r--backends/platform/ps2/ps2loader.cpp721
-rw-r--r--backends/platform/ps2/ps2loader.h137
-rw-r--r--backends/platform/ps2/systemps2.cpp6
-rw-r--r--backends/platform/psp/Makefile9
-rw-r--r--backends/platform/psp/audio.cpp181
-rw-r--r--backends/platform/psp/audio.h69
-rw-r--r--backends/platform/psp/display_client.cpp15
-rw-r--r--backends/platform/psp/display_manager.cpp3
-rw-r--r--backends/platform/psp/module.mk5
-rw-r--r--backends/platform/psp/mp3.cpp487
-rw-r--r--backends/platform/psp/mp3.h121
-rw-r--r--backends/platform/psp/osys_psp.cpp45
-rw-r--r--backends/platform/psp/osys_psp.h4
-rw-r--r--backends/platform/psp/psp.spec2
-rw-r--r--backends/platform/psp/psp_main.cpp3
-rw-r--r--backends/platform/psp/thread.cpp52
-rw-r--r--backends/platform/psp/thread.h56
-rw-r--r--backends/platform/samsungtv/main.cpp2
-rw-r--r--backends/platform/sdl/graphics.cpp5
-rw-r--r--backends/platform/sdl/main.cpp2
-rw-r--r--backends/platform/sdl/sdl.cpp8
-rw-r--r--backends/platform/sdl/sdl.h2
-rw-r--r--backends/plugins/ps2/ps2-provider.cpp108
-rw-r--r--backends/plugins/ps2/ps2-provider.h (renamed from engines/sci/graphics/maciconbar.h)32
-rw-r--r--backends/saves/default/default-saves.cpp4
-rw-r--r--base/commandLine.cpp35
-rw-r--r--base/commandLine.h2
-rw-r--r--base/main.cpp6
-rw-r--r--common/error.h10
-rw-r--r--common/macresman.cpp10
-rw-r--r--common/str.h6
-rw-r--r--common/stream.h2
-rw-r--r--common/unzip.cpp4
-rwxr-xr-xconfigure4
-rw-r--r--engines/dialogs.cpp45
-rw-r--r--engines/dialogs.h43
-rw-r--r--engines/drascula/animation.cpp2
-rw-r--r--engines/drascula/drascula.cpp1
-rw-r--r--engines/drascula/objects.cpp3
-rw-r--r--engines/m4/animation.cpp531
-rw-r--r--engines/m4/animation.h106
-rw-r--r--engines/m4/assets.cpp29
-rw-r--r--engines/m4/assets.h10
-rw-r--r--engines/m4/compression.h4
-rw-r--r--engines/m4/console.cpp56
-rw-r--r--engines/m4/console.h3
-rw-r--r--engines/m4/converse.cpp8
-rw-r--r--engines/m4/dialogs.cpp26
-rw-r--r--engines/m4/font.cpp57
-rw-r--r--engines/m4/font.h48
-rw-r--r--engines/m4/globals.h1
-rw-r--r--engines/m4/graphics.cpp174
-rw-r--r--engines/m4/graphics.h40
-rw-r--r--engines/m4/gui.cpp30
-rw-r--r--engines/m4/m4.cpp12
-rw-r--r--engines/m4/m4.h3
-rw-r--r--engines/m4/m4_views.cpp2
-rw-r--r--engines/m4/mads_anim.cpp16
-rw-r--r--engines/m4/mads_logic.cpp68
-rw-r--r--engines/m4/mads_logic.h3
-rw-r--r--engines/m4/mads_menus.cpp56
-rw-r--r--engines/m4/mads_scene.cpp599
-rw-r--r--engines/m4/mads_scene.h86
-rw-r--r--engines/m4/mads_views.cpp1074
-rw-r--r--engines/m4/mads_views.h201
-rw-r--r--engines/m4/sprite.h12
-rw-r--r--engines/mohawk/console.cpp2
-rw-r--r--engines/mohawk/detection.cpp36
-rw-r--r--engines/mohawk/graphics.cpp12
-rw-r--r--engines/mohawk/graphics.h12
-rw-r--r--engines/mohawk/jpeg.cpp87
-rw-r--r--engines/mohawk/jpeg.h (renamed from graphics/video/codecs/mjpeg.h)25
-rw-r--r--engines/mohawk/module.mk10
-rw-r--r--engines/mohawk/mohawk.cpp2
-rw-r--r--engines/mohawk/myst.cpp2
-rw-r--r--engines/mohawk/myst_pict.cpp (renamed from graphics/pict.cpp)213
-rw-r--r--engines/mohawk/myst_pict.h (renamed from graphics/pict.h)56
-rw-r--r--engines/mohawk/myst_scripts.cpp2
-rw-r--r--engines/mohawk/riven.cpp18
-rw-r--r--engines/mohawk/riven.h8
-rw-r--r--engines/mohawk/riven_external.cpp58
-rw-r--r--engines/mohawk/riven_external.h2
-rw-r--r--engines/mohawk/riven_scripts.cpp18
-rw-r--r--engines/mohawk/video/cinepak.cpp (renamed from graphics/video/codecs/cinepak.cpp)27
-rw-r--r--engines/mohawk/video/cinepak.h (renamed from graphics/video/codecs/cinepak.h)18
-rw-r--r--engines/mohawk/video/qdm2.cpp (renamed from graphics/video/codecs/qdm2.cpp)272
-rw-r--r--engines/mohawk/video/qdm2.h289
-rw-r--r--engines/mohawk/video/qdm2data.h (renamed from graphics/video/codecs/qdm2data.h)8
-rw-r--r--engines/mohawk/video/qt_player.cpp (renamed from graphics/video/qt_decoder.cpp)272
-rw-r--r--engines/mohawk/video/qt_player.h (renamed from graphics/video/qt_decoder.h)39
-rw-r--r--engines/mohawk/video/qtrle.cpp (renamed from graphics/video/codecs/qtrle.cpp)16
-rw-r--r--engines/mohawk/video/qtrle.h (renamed from graphics/video/codecs/qtrle.h)18
-rw-r--r--engines/mohawk/video/rpza.cpp (renamed from graphics/video/codecs/rpza.cpp)14
-rw-r--r--engines/mohawk/video/rpza.h (renamed from graphics/video/codecs/rpza.h)18
-rw-r--r--engines/mohawk/video/smc.cpp (renamed from graphics/video/codecs/smc.cpp)6
-rw-r--r--engines/mohawk/video/smc.h (renamed from graphics/video/codecs/smc.h)16
-rw-r--r--engines/mohawk/video/video.cpp (renamed from engines/mohawk/video.cpp)66
-rw-r--r--engines/mohawk/video/video.h (renamed from engines/mohawk/video.h)21
-rw-r--r--engines/parallaction/debug.cpp27
-rw-r--r--engines/parallaction/debug.h1
-rw-r--r--engines/parallaction/dialogue.cpp4
-rw-r--r--engines/parallaction/exec_br.cpp2
-rw-r--r--engines/parallaction/graphics.cpp6
-rw-r--r--engines/parallaction/input.cpp15
-rw-r--r--engines/parallaction/objects.h4
-rw-r--r--engines/parallaction/parallaction.cpp112
-rw-r--r--engines/parallaction/parallaction.h2
-rw-r--r--engines/parallaction/parallaction_br.cpp4
-rw-r--r--engines/parallaction/parser.cpp9
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/parallaction/sound_br.cpp4
-rw-r--r--engines/saga/saga.cpp14
-rw-r--r--engines/sci/console.cpp155
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection.cpp207
-rw-r--r--engines/sci/engine/features.cpp88
-rw-r--r--engines/sci/engine/game.cpp173
-rw-r--r--engines/sci/engine/kernel.cpp6
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel32.cpp36
-rw-r--r--engines/sci/engine/kevent.cpp56
-rw-r--r--engines/sci/engine/kfile.cpp118
-rw-r--r--engines/sci/engine/kgraphics.cpp113
-rw-r--r--engines/sci/engine/klists.cpp52
-rw-r--r--engines/sci/engine/kmisc.cpp22
-rw-r--r--engines/sci/engine/kmovement.cpp141
-rw-r--r--engines/sci/engine/kparse.cpp40
-rw-r--r--engines/sci/engine/kpathing.cpp66
-rw-r--r--engines/sci/engine/kscripts.cpp36
-rw-r--r--engines/sci/engine/kstring.cpp36
-rw-r--r--engines/sci/engine/savegame.cpp202
-rw-r--r--engines/sci/engine/savegame.h2
-rw-r--r--engines/sci/engine/script.cpp298
-rw-r--r--engines/sci/engine/scriptdebug.cpp46
-rw-r--r--engines/sci/engine/seg_manager.cpp46
-rw-r--r--engines/sci/engine/seg_manager.h44
-rw-r--r--engines/sci/engine/segment.cpp425
-rw-r--r--engines/sci/engine/segment.h238
-rw-r--r--engines/sci/engine/selector.cpp44
-rw-r--r--engines/sci/engine/selector.h31
-rw-r--r--engines/sci/engine/state.cpp68
-rw-r--r--engines/sci/engine/state.h23
-rw-r--r--engines/sci/engine/vm.cpp142
-rw-r--r--engines/sci/engine/vm.h54
-rw-r--r--engines/sci/event.cpp3
-rw-r--r--engines/sci/graphics/animate.cpp87
-rw-r--r--engines/sci/graphics/animate.h3
-rw-r--r--engines/sci/graphics/compare.cpp68
-rw-r--r--engines/sci/graphics/controls.cpp18
-rw-r--r--engines/sci/graphics/coordadjuster.cpp16
-rw-r--r--engines/sci/graphics/frameout.cpp54
-rw-r--r--engines/sci/graphics/gui.cpp7
-rw-r--r--engines/sci/graphics/gui.h2
-rw-r--r--engines/sci/graphics/maciconbar.cpp91
-rw-r--r--engines/sci/graphics/menu.cpp8
-rw-r--r--engines/sci/graphics/paint16.cpp5
-rw-r--r--engines/sci/graphics/paint16.h2
-rw-r--r--engines/sci/graphics/palette.cpp7
-rw-r--r--engines/sci/graphics/picture.cpp51
-rw-r--r--engines/sci/graphics/picture.h9
-rw-r--r--engines/sci/graphics/ports.cpp3
-rw-r--r--engines/sci/graphics/ports.h2
-rw-r--r--engines/sci/graphics/screen.cpp13
-rw-r--r--engines/sci/module.mk2
-rw-r--r--engines/sci/parser/grammar.cpp5
-rw-r--r--engines/sci/parser/said.cpp7
-rw-r--r--engines/sci/parser/said.y7
-rw-r--r--engines/sci/resource.cpp894
-rw-r--r--engines/sci/resource.h57
-rw-r--r--engines/sci/resource_audio.cpp706
-rw-r--r--engines/sci/sci.cpp15
-rw-r--r--engines/sci/sci.h3
-rw-r--r--engines/sci/sound/audio.cpp12
-rw-r--r--engines/sci/sound/midiparser_sci.cpp26
-rw-r--r--engines/sci/sound/midiparser_sci.h13
-rw-r--r--engines/sci/sound/music.cpp95
-rw-r--r--engines/sci/sound/music.h11
-rw-r--r--engines/sci/sound/soundcmd.cpp231
-rw-r--r--engines/scumm/charset.cpp2
-rw-r--r--engines/scumm/debugger.cpp2
-rw-r--r--engines/scumm/dialogs.cpp213
-rw-r--r--engines/scumm/dialogs.h24
-rw-r--r--engines/scumm/he/resource_he.cpp4
-rw-r--r--engines/scumm/input.cpp2
-rw-r--r--engines/scumm/scumm-md5.h5
-rw-r--r--engines/scumm/scumm.cpp18
-rw-r--r--engines/scumm/scumm.h2
-rw-r--r--engines/sword1/animation.cpp38
-rw-r--r--engines/sword1/animation.h1
-rw-r--r--engines/sword2/animation.cpp37
-rw-r--r--engines/sword2/animation.h1
-rw-r--r--engines/tinsel/handle.cpp3
-rw-r--r--graphics/conversion.h7
-rw-r--r--graphics/module.mk8
-rw-r--r--graphics/video/avi_decoder.cpp24
-rw-r--r--graphics/video/codecs/mjpeg.cpp73
-rw-r--r--graphics/video/codecs/qdm2.h54
-rw-r--r--graphics/video/smk_decoder.cpp4
-rw-r--r--gui/ListWidget.cpp8
-rw-r--r--gui/ListWidget.h4
-rw-r--r--gui/about.cpp35
-rw-r--r--gui/editable.cpp2
-rw-r--r--gui/themes/default.inc1383
-rw-r--r--gui/themes/scummclassic.zipbin52242 -> 54108 bytes
-rw-r--r--gui/themes/scummclassic/classic_layout.stx35
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx44
-rw-r--r--gui/themes/scummmodern.zipbin158233 -> 159866 bytes
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx35
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx37
-rw-r--r--ports.mk8
-rw-r--r--sound/decoders/adpcm.cpp4
-rw-r--r--sound/decoders/mp3.cpp15
-rw-r--r--sound/decoders/voc.cpp2
-rw-r--r--sound/mods/rjp1.cpp2
-rw-r--r--test/common/str.h24
-rw-r--r--tools/create_msvc/create_msvc.cpp3
-rw-r--r--tools/md5table.c4
-rw-r--r--tools/module.mk6
-rw-r--r--tools/scumm-md5.txt3
235 files changed, 7419 insertions, 8659 deletions
diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp
index 9bcbe9d7cf..8cb7dfea17 100644
--- a/backends/fs/psp/psp-stream.cpp
+++ b/backends/fs/psp/psp-stream.cpp
@@ -32,48 +32,28 @@
#include <errno.h>
-#define MIN2(a,b) ((a < b) ? a : b)
-#define MIN3(a,b,c) ( (a < b) ? (a < c ? a : c) : (b < c ? b : c) )
-
-//#define __PSP_PRINT_TO_FILE__ /* For debugging suspend stuff, we have no screen output */
-//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
+//#define __PSP_PRINT_TO_FILE__
+//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
-
#include "backends/platform/psp/trace.h"
-//#define DEBUG_BUFFERS /* to see the contents of the buffers being read */
-
-#ifdef DEBUG_BUFFERS
-void printBuffer(byte *ptr, uint32 len) {
- uint32 printLen = len <= 10 ? len : 10;
-
- for (int i = 0; i < printLen; i++) {
- PSP_INFO_PRINT("%x ", ptr[i]);
- }
-
- if (len > 10) {
- PSP_INFO_PRINT("... ");
- for (int i = len - 10; i < len; i++)
- PSP_INFO_PRINT("%x ", ptr[i]);
- }
-
- PSP_INFO_PRINT("\n");
-}
-#endif
-
-
PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode)
- : StdioStream((void *)1), _path(path), _writeMode(writeMode),
- _ferror(false), _pos(0),
- _physicalPos(0), _fileSize(0), _inCache(false), _eos(false),
- _cacheStartOffset(-1), _cache(0),
- _errorSuspend(0), _errorSource(0),
- _errorPos(0), _errorHandle(0), _suspendCount(0) {
+ : StdioStream((void *)1), _path(path), _writeMode(writeMode) {
DEBUG_ENTER_FUNC();
- // assert(!path.empty()); // do we need this?
+ assert(!path.empty());
_handle = (void *)0; // Need to do this since base class asserts not 0.
+ _ferror = false;
+ _feof = false;
+ _pos = 0;
+
+ /* for error checking */
+ _errorSuspend = 0;
+ _errorSource = 0;
+ _errorPos = 0;
+ _errorHandle = 0;
+ _suspendCount = 0;
}
PSPIoStream::~PSPIoStream() {
@@ -83,12 +63,9 @@ PSPIoStream::~PSPIoStream() {
PSP_DEBUG_PRINT_FUNC("Suspended\n");
PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended
- // Must do this before fclose() or resume() will reopen.
+ // Must do this before fclose() or resume() will reopen.
- fclose((FILE *)_handle); // We don't need a critical section. Worst case, the handle gets closed on its own
-
- if (_cache)
- free(_cache);
+ fclose((FILE *)_handle); // We don't need a critical section(?). Worst case, the handle gets closed on its own
PowerMan.endCriticalSection();
}
@@ -105,16 +82,6 @@ void *PSPIoStream::open() {
_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); // open
- if (_handle) {
- // Get the file size
- fseek((FILE *)_handle, 0, SEEK_END); // go to the end
- _fileSize = ftell((FILE *)_handle);
- fseek((FILE *)_handle, 0, SEEK_SET); // back to the beginning
-
- // Allocate the cache
- _cache = (char *)memalign(64, CACHE_SIZE);
- }
-
PowerMan.registerSuspend(this); // Register with the powermanager to be suspended
PowerMan.endCriticalSection();
@@ -124,183 +91,100 @@ void *PSPIoStream::open() {
bool PSPIoStream::err() const {
DEBUG_ENTER_FUNC();
-
- if (_ferror) // We dump since no printing to screen with suspend
- PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], \
- _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n",
- _ferror, _errorSource, _errorSuspend, _pos,
- _errorPos, _errorHandle, _suspendCount);
+ if (_ferror)
+ PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n",
+ _ferror, _errorSource, _errorSuspend, _pos, _errorPos, _errorHandle, _suspendCount);
return _ferror;
}
void PSPIoStream::clearErr() {
- _ferror = false;
+ _ferror = false; // Remove regular error bit
}
bool PSPIoStream::eos() const {
- return _eos;
+ return _feof;
}
int32 PSPIoStream::pos() const {
return _pos;
}
+
int32 PSPIoStream::size() const {
- return _fileSize;
+ DEBUG_ENTER_FUNC();
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSP_DEBUG_PRINT_FUNC("Suspended\n");
+
+ fseek((FILE *)_handle, 0, SEEK_END);
+ int32 length = ftell((FILE *)_handle);
+ fseek((FILE *)_handle, _pos, SEEK_SET);
+
+ if (_pos < 0 || length < 0) { // Check for errors
+ _errorSource = 2;
+ PSP_ERROR("pos[%d] or length[%d] < 0!\n", _pos, length);
+ _ferror = true;
+ length = -1; // If our oldPos is bad, we want length to be bad too to signal
+ clearerr((FILE *)_handle);
+ }
+
+ PowerMan.endCriticalSection();
+
+ return length;
}
bool PSPIoStream::seek(int32 offs, int whence) {
DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT_FUNC("offset[0x%x], whence[%d], _pos[0x%x], _physPos[0x%x]\n", offs, whence, _pos, _physicalPos);
- _eos = false;
-
- int32 posToSearchFor = 0;
- switch (whence) {
- case SEEK_CUR:
- posToSearchFor = _pos;
- break;
- case SEEK_END:
- posToSearchFor = _fileSize; // unsure. Does it take us here or to EOS - 1?
- break;
- }
- posToSearchFor += offs;
-
- // Check for bad values
- if (posToSearchFor < 0) {
- _ferror = true;
- return false;
- }
-
- if (posToSearchFor > _fileSize) {
+
+ // Check if we can access the file
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSP_DEBUG_PRINT_FUNC("Suspended\n");
+
+ int ret = fseek((FILE *)_handle, offs, whence);
+
+ if (ret != 0) {
_ferror = true;
- _eos = true;
- return false;
+ PSP_ERROR("fseek returned with [%d], non-zero\n", ret);
+ clearerr((FILE *)_handle);
+ _feof = feof((FILE *)_handle);
+ _errorSource = 3;
+ } else { // everything ok
+ _feof = false; // Reset eof flag since we know it was ok
}
-
- // See if we can find it in cache
- if (isOffsetInCache(posToSearchFor)) {
- PSP_DEBUG_PRINT("seek offset[0x%x] found in cache. Cache starts[0x%x]\n", posToSearchFor, _cacheStartOffset);
- _inCache = true;
- } else { // not in cache
- _inCache = false;
- }
- _pos = posToSearchFor;
- return true;
+
+ _pos = ftell((FILE *)_handle); // update pos
+
+ PowerMan.endCriticalSection();
+
+ return (ret == 0);
}
uint32 PSPIoStream::read(void *ptr, uint32 len) {
DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x], ptr[%p]\n", _path.c_str(), len, ptr);
-
- if (_ferror || _eos)
- return 0;
-
- byte *destPtr = (byte *)ptr;
- uint32 lenFromFile = len; // how much we read from the actual file
- uint32 lenFromCache = 0; // how much we read from cache
- uint32 lenRemainingInFile = _fileSize - _pos;
-
- if (lenFromFile > lenRemainingInFile) {
- lenFromFile = lenRemainingInFile;
- _eos = true;
- }
-
- // Are we in cache?
- if (_inCache && isCacheValid()) {
- uint32 offsetInCache = _pos - _cacheStartOffset;
- // We can read at most what's in the cache or the remaining size of the file
- lenFromCache = MIN2(lenFromFile, CACHE_SIZE - offsetInCache); // unsure
-
- PSP_DEBUG_PRINT("reading 0x%x bytes from cache to %p. pos[0x%x] physPos[0x%x] cacheStart[0x%x]\n", lenFromCache, destPtr, _pos, _physicalPos, _cacheStartOffset);
-
- memcpy(destPtr, &_cache[offsetInCache], lenFromCache);
- _pos += lenFromCache;
-
- if (lenFromCache < lenFromFile) { // there's more to copy from the file
- lenFromFile -= lenFromCache;
- lenRemainingInFile -= lenFromCache; // since we moved pos
- destPtr += lenFromCache;
- } else { // we're done
-#ifdef DEBUG_BUFFERS
- printBuffer((byte *)ptr, len);
-#endif
-
- return lenFromCache; // how much we actually read
- }
- }
-
+ // Check if we can access the file
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSP_DEBUG_PRINT_FUNC("Suspended\n");
-
-
- synchronizePhysicalPos(); // we need to update our physical position
-
- if (lenFromFile <= MIN_READ_SIZE) { // We load the cache in case the read is small enough
- // This optimization is based on the principle that reading 1 byte is as expensive as 1000 bytes
- uint32 lenToCopyToCache = MIN2((uint32)MIN_READ_SIZE, lenRemainingInFile); // at most remaining file size
-
- PSP_DEBUG_PRINT("filling cache with 0x%x bytes from physicalPos[0x%x]. cacheStart[0x%x], pos[0x%x], fileSize[0x%x]\n", lenToCopyToCache, _physicalPos, _cacheStartOffset, _pos, _fileSize);
-
- size_t ret = fread(_cache, 1, lenToCopyToCache, (FILE *)_handle);
- if (ret != lenToCopyToCache) {
- PSP_ERROR("in filling cache, failed to get 0x%x bytes. Only got 0x%x\n", lenToCopyToCache, ret);
- _ferror = true;
- clearerr((FILE *)_handle);
- }
- _cacheStartOffset = _physicalPos;
- _inCache = true;
-
- _physicalPos += ret;
-
- PSP_DEBUG_PRINT("copying 0x%x bytes from cache to %p\n", lenFromFile, destPtr);
-
- // Copy to the destination buffer from cache
- memcpy(destPtr, _cache, lenFromFile);
- _pos += lenFromFile;
-
- } else { // Too big for cache. No caching
- PSP_DEBUG_PRINT("reading 0x%x bytes from file to %p. Pos[0x%x], physPos[0x%x]\n", lenFromFile, destPtr, _pos, _physicalPos);
- size_t ret = fread(destPtr, 1, lenFromFile, (FILE *)_handle);
-
- _physicalPos += ret; // Update pos
- _pos = _physicalPos;
-
- if (ret != lenFromFile) { // error
- PSP_ERROR("fread returned [0x%x] instead of len[0x%x]\n", ret, lenFromFile);
+
+ PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len);
+
+ size_t ret = fread((byte *)ptr, 1, len, (FILE *)_handle);
+
+ _pos += ret; // Update pos
+
+ if (ret != len) { // Check for eof
+ _feof = feof((FILE *)_handle);
+ if (!_feof) { // It wasn't an eof. Must be an error
_ferror = true;
clearerr((FILE *)_handle);
- _errorSource = 4;
+ _pos = ftell((FILE *)_handle); // Update our position
+ _errorSource = 4;
+ PSP_ERROR("fread returned ret[%d] instead of len[%d]\n", ret, len);
}
- _inCache = false;
}
PowerMan.endCriticalSection();
-#ifdef DEBUG_BUFFERS
- printBuffer((byte *)ptr, len);
-#endif
-
- return lenFromCache + lenFromFile; // total of what was copied
-}
-
-// TODO: Test if seeking backwards/forwards has any effect on performance
-inline bool PSPIoStream::synchronizePhysicalPos() {
- if (_pos != _physicalPos) {
- if (fseek((FILE *)_handle, _pos - _physicalPos, SEEK_CUR) != 0)
- return false;
- _physicalPos = _pos;
- }
-
- return true;
-}
-
-inline bool PSPIoStream::isOffsetInCache(uint32 offset) {
- if (_cacheStartOffset != -1 &&
- offset >= (uint32)_cacheStartOffset &&
- offset < (uint32)(_cacheStartOffset + CACHE_SIZE))
- return true;
- return false;
+ return ret;
}
uint32 PSPIoStream::write(const void *ptr, uint32 len) {
@@ -309,30 +193,18 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) {
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSP_DEBUG_PRINT_FUNC("Suspended\n");
- PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x]\n", _path.c_str(), len);
+ PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len);
- if (_ferror)
- return 0;
-
- _eos = false; // we can't have eos with write
- synchronizePhysicalPos();
-
size_t ret = fwrite(ptr, 1, len, (FILE *)_handle);
- // If we're making the file bigger, adjust the size
- if (_physicalPos + (int)ret > _fileSize)
- _fileSize = _physicalPos + ret;
- _physicalPos += ret;
- _pos = _physicalPos;
- _inCache = false;
- _cacheStartOffset = -1; // invalidate cache
+ _pos += ret;
if (ret != len) { // Set error
_ferror = true;
clearerr((FILE *)_handle);
_pos = ftell((FILE *)_handle); // Update pos
_errorSource = 5;
- PSP_ERROR("fwrite returned[0x%x] instead of len[0x%x]\n", ret, len);
+ PSP_ERROR("fwrite returned[%d] instead of len[%d]\n", ret, len);
}
PowerMan.endCriticalSection();
@@ -352,7 +224,7 @@ bool PSPIoStream::flush() {
_ferror = true;
clearerr((FILE *)_handle);
_errorSource = 6;
- PSP_ERROR("fflush returned ret[%d]\n", ret);
+ PSP_ERROR("fflush returned ret[%u]\n", ret);
}
PowerMan.endCriticalSection();
@@ -414,9 +286,6 @@ int PSPIoStream::resume() {
// Resume our previous position
if (_handle > 0 && _pos > 0) {
ret = fseek((FILE *)_handle, _pos, SEEK_SET);
-
- _physicalPos = _pos;
- _inCache = false;
if (ret != 0) { // Check for problem
_errorSuspend = ResumeError;
diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h
index 9fd1ad0470..673630b685 100644
--- a/backends/fs/psp/psp-stream.h
+++ b/backends/fs/psp/psp-stream.h
@@ -35,39 +35,25 @@
*/
class PSPIoStream : public StdioStream, public Suspendable {
protected:
- Common::String _path;
- int _fileSize;
- bool _writeMode; // for resuming in the right mode
- int _physicalPos; // position in the real file
- int _pos; // position. Sometimes virtual
- bool _inCache; // whether we're in cache (virtual) mode
- bool _eos; // EOS flag
-
+ Common::String _path; /* Need to maintain for reopening after suspend */
+ bool _writeMode; /* "" */
+ int _pos; /* "" */
+ mutable int _ferror; /* Save file ferror */
+ mutable bool _feof; /* and eof */
+
enum {
SuspendError = 2,
ResumeError = 3
};
- enum {
- CACHE_SIZE = 1024,
- MIN_READ_SIZE = 1024 // reading less than 1024 takes exactly the same time as 1024
- };
-
- // For caching
- char *_cache;
- int _cacheStartOffset; // starting offset of the cache. -1 when cache is invalid
-
- mutable int _ferror; // file error state
- int _errorSuspend; // for debugging
+ int _errorSuspend;
mutable int _errorSource;
+
+ // Error checking
int _errorPos;
void * _errorHandle;
int _suspendCount;
- bool synchronizePhysicalPos(); // synchronize the physical and virtual positions
- bool isOffsetInCache(uint32 pos); // check if an offset is found in cache
- bool isCacheValid() { return _cacheStartOffset != -1; }
-
public:
/**
diff --git a/backends/module.mk b/backends/module.mk
index 59df56b468..46c9e166a6 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -35,6 +35,7 @@ MODULE_OBJS := \
plugins/sdl/sdl-provider.o \
plugins/win32/win32-provider.o \
plugins/psp/psp-provider.o \
+ plugins/ps2/ps2-provider.o \
saves/savefile.o \
saves/default/default-saves.o \
saves/posix/posix-saves.o \
diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp
index a4cde02ba6..7029d96405 100644
--- a/backends/platform/ds/arm7/source/main.cpp
+++ b/backends/platform/ds/arm7/source/main.cpp
@@ -38,7 +38,7 @@
#include <system.h>
#include <stdlib.h>
#include <string.h>
-#include <registers_alt.h> // Needed for SOUND_CR
+//#include <registers_alt.h> // not needed in current libnds
#include <NDS/scummvm_ipc.h>
//////////////////////////////////////////////////////////////////////
#ifdef USE_DEBUGGER
@@ -590,7 +590,7 @@ int main(int argc, char ** argv) {
IPC->reset = false;
- //fifoInit();
+ fifoInit();
for (int r = 0; r < 8; r++) {
IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512);
diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile
index 7f03f4c310..eca170ef96 100644
--- a/backends/platform/ds/arm9/makefile
+++ b/backends/platform/ds/arm9/makefile
@@ -75,7 +75,7 @@ else
ifdef DS_BUILD_K
else
- # USE_MAD = 1
+ USE_MAD = 1
endif
endif
endif
diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp
index 5a63e5f08f..7eb02f9070 100644
--- a/backends/platform/ds/arm9/source/dsmain.cpp
+++ b/backends/platform/ds/arm9/source/dsmain.cpp
@@ -702,7 +702,7 @@ void displayMode8Bit() {
- consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 2, 0, true, true);
+ consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 2, 0, true);
// Set this again because consoleinit resets it
videoSetMode(MODE_5_2D | (consoleEnable? DISPLAY_BG0_ACTIVE: 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP);
@@ -940,7 +940,7 @@ void displayMode16Bit() {
SUB_BG0_CR = BG_MAP_BASE(4) | BG_TILE_BASE(0);
SUB_BG0_Y0 = 0;
- consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false, true);
+ consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false);
// consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(4), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
for (int r = 0; r < 32 * 32; r++) {
diff --git a/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h b/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h
index f41548f400..9344be68f9 100644
--- a/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h
+++ b/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h
@@ -33,18 +33,6 @@
//////////////////////////////////////////////////////////////////////
-typedef struct sTransferSoundData {
-//---------------------------------------------------------------------------------
- const void *data;
- u32 len;
- u32 rate;
- u8 vol;
- u8 pan;
- u8 format;
- u8 PADDING;
-} TransferSoundData, * pTransferSoundData;
-
-
//---------------------------------------------------------------------------------
diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp
index 4a3c668c52..1888cbe47c 100644
--- a/backends/platform/gp2x/graphics.cpp
+++ b/backends/platform/gp2x/graphics.cpp
@@ -1405,6 +1405,7 @@ void OSystem_GP2X::drawMouse() {
SDL_Rect zoomdst;
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
int tmpScreenWidth, tmpScreenHeight;
@@ -1425,12 +1426,16 @@ void OSystem_GP2X::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
index 6abddd52f3..ff3bd725be 100644
--- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
+++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
@@ -149,6 +149,7 @@ void OSystem_GP2XWIZ::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
if (_videoMode.mode == GFX_HALF && !_overlayVisible){
@@ -161,12 +162,16 @@ void OSystem_GP2XWIZ::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
index a39416ebc4..d66d41dfab 100644
--- a/backends/platform/linuxmoto/linuxmoto-graphics.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
@@ -168,6 +168,7 @@ void OSystem_LINUXMOTO::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
@@ -180,12 +181,16 @@ void OSystem_LINUXMOTO::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2
index bf7ac0aca0..d6ebc9bfc8 100644
--- a/backends/platform/ps2/Makefile.ps2
+++ b/backends/platform/ps2/Makefile.ps2
@@ -1,39 +1,52 @@
# $Header: Exp $
include $(PS2SDK)/Defs.make
-PS2_EXTRA = /works/devel/ps2/sdk-extra
+PS2_EXTRA = /home/tony/GSOC/ps2/sdk-extra
PS2_EXTRA_INCS = /zlib/include /libmad/ee/include /SjPcm/ee/src /tremor
-PS2_EXTRA_LIBS = /zlib/lib /libmad/ee/lib /SjPcm/ee/lib /tremor/tremor
+PS2_EXTRA_LIBS = /zlib/lib /libmad/ee/lib /SjPcm/ee/lib /vorbis /tremor/tremor
-ENABLED=STATIC_PLUGIN
+# Set to 1 to enable, 0 to disable dynamic modules
+DYNAMIC_MODULES = 1
+
+VERBOSE_BUILD=0
+
+# Test for dynamic plugins
+ifeq ($(DYNAMIC_MODULES),1)
+ENABLED = DYNAMIC_PLUGIN
+DEFINES += -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+else
+ENABLED = STATIC_PLUGIN
+endif
ENABLE_SCUMM = $(ENABLED)
-ENABLE_SCUMM_7_8 = $(ENABLED)
-ENABLE_HE = $(ENABLED)
+#ENABLE_SCUMM_7_8 = $(ENABLED)
+#ENABLE_HE = $(ENABLED)
ENABLE_AGI = $(ENABLED)
-ENABLE_AGOS = $(ENABLED)
-ENABLE_CINE = $(ENABLED)
-ENABLE_CRUISE = $(ENABLED)
-ENABLE_DRASCULA = $(ENABLED)
-ENABLE_GOB = $(ENABLED)
-ENABLE_KYRA = $(ENABLED)
-ENABLE_LURE = $(ENABLED)
+#ENABLE_AGOS = $(ENABLED)
+#ENABLE_CINE = $(ENABLED)
+#ENABLE_CRUISE = $(ENABLED)
+#ENABLE_DRASCULA = $(ENABLED)
+#ENABLE_GOB = $(ENABLED)
+#ENABLE_KYRA = $(ENABLED)
+#ENABLE_LURE = $(ENABLED)
# ENABLE_M4 = $(ENABLED)
-ENABLE_MADE = $(ENABLED)
-ENABLE_PARALLACTION = $(ENABLED)
-ENABLE_QUEEN = $(ENABLED)
-ENABLE_SAGA = $(ENABLED)
-ENABLE_SAGA2 = $(ENABLED)
-ENABLE_IHNM = $(ENABLED)
-ENABLE_SKY = $(ENABLED)
-ENABLE_SWORD1 = $(ENABLED)
-ENABLE_SWORD2 = $(ENABLED)
+#ENABLE_MADE = $(ENABLED)
+#ENABLE_PARALLACTION = $(ENABLED)
+#ENABLE_QUEEN = $(ENABLED)
+#ENABLE_SAGA = $(ENABLED)
+#ENABLE_SAGA2 = $(ENABLED)
+#ENABLE_IHNM = $(ENABLED)
+#ENABLE_SKY = $(ENABLED)
+#ENABLE_SWORD1 = $(ENABLED)
+#ENABLE_SWORD2 = $(ENABLED)
# ENABLE_TINSEL = $(ENABLED)
-ENABLE_TOUCHE = $(ENABLED)
+#ENABLE_TOUCHE = $(ENABLED)
HAVE_GCC3 = true
-CC = ee-gcc
+CC = ee-gcc
CXX = ee-g++
AS = ee-gcc
LD = ee-gcc
@@ -46,15 +59,21 @@ RM = rm -f
srcdir = ../../..
VPATH = $(srcdir)
INCDIR = ../../../
-# DEPDIR = .deps
+DEPDIR = .deps
+CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
-DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar
+# Variables for dynamic plugin building
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = plugin.syms elf/scummvm.elf
+PLUGIN_LDFLAGS = -nostartfiles -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -Wl,-q,--just-symbols=elf/scummvm.org.elf,-Tlinkfile,--retain-symbols-file,plugin.syms -lstdc++ -lc
+DEFINES = -DUSE_VORBIS -DUSE_MAD -DUSE_TREMOR -DUSE_ZLIB -DFORCE_RTL -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar -fno-exceptions -fno-rtti
-INCLUDES = $(addprefix -I$(PS2_EXTRA),$(PS2_EXTRA_INCS))
+INCLUDES = $(addprefix -I$(PS2_EXTRA),$(PS2_EXTRA_INCS))
INCLUDES += -I $(PS2SDK)/ee/include -I $(PS2SDK)/common/include -I ./common -I . -I $(srcdir) -I $(srcdir)/engines
-TARGET = elf/scummvm.elf
+TARGET = elf/scummvm
OBJS := backends/platform/ps2/DmaPipe.o \
backends/platform/ps2/Gs2dScreen.o \
@@ -71,20 +90,20 @@ OBJS := backends/platform/ps2/DmaPipe.o \
backends/platform/ps2/systemps2.o \
backends/platform/ps2/ps2mutex.o \
backends/platform/ps2/ps2time.o \
- backends/platform/ps2/ps2debug.o
+ backends/platform/ps2/ps2debug.o \
+ backends/platform/ps2/ps2loader.o
MODULE_DIRS += .
include $(srcdir)/Makefile.common
-LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(PS2SDK)/ee/startup/linkfile
-LDFLAGS += -L $(PS2SDK)/ee/lib -L .
+LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T main_prog.ld #$(PS2SDK)/ee/startup/linkfile
+LDFLAGS += -G 0 -L $(PS2SDK)/ee/lib -L .
LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))
-LDFLAGS += -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lmad -ltremor -lz -lm -lc -lfileXio -lkernel -lstdc++
-LDFLAGS += -s
-
-all: $(TARGET)
+LDFLAGS += -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lmad -ltremor -lz -lm -lc -lfileXio -lkernel -lstdc++
+LDFLAGS +=
-$(TARGET): $(OBJS)
- $(LD) $^ $(LDFLAGS) -o $@
+all: $(TARGET).elf
+$(TARGET).elf: $(OBJS)
+ $(LD) $(PRE_OBJS_FLAGS) $(OBJS) $(POST_OBJS_FLAGS) $(LDFLAGS) -o $@
diff --git a/backends/platform/ps2/elf32.h b/backends/platform/ps2/elf32.h
new file mode 100644
index 0000000000..616cc4b4d2
--- /dev/null
+++ b/backends/platform/ps2/elf32.h
@@ -0,0 +1,209 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_ELF_H
+#define BACKENDS_ELF_H
+
+/* ELF stuff */
+
+typedef unsigned short Elf32_Half, Elf32_Section;
+typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define SELFMAG 6
+
+/* ELF File format structures. Look up ELF structure for more details */
+
+// ELF header (contains info about the file)
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+// Should be in e_ident
+#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
+
+// e_type values
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable */
+#define ET_EXEC 2 /* executable */
+#define ET_DYN 3 /* shared object */
+#define ET_CORE 4 /* core file */
+
+// e_machine values
+#define EM_MIPS 8
+
+
+// Program header (contains info about segment)
+typedef struct {
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+// p_type values
+#define PT_NULL 0 /* ignored */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking info */
+#define PT_INTERP 3 /* info about interpreter */
+#define PT_NOTE 4 /* note segment */
+#define PT_SHLIB 5 /* reserved */
+#define PT_PHDR 6 /* Program header table */
+#define PT_MIPS_REGINFO 0x70000000 /* register usage info */
+
+// p_flags value
+#define PF_X 1 /* execute */
+#define PF_W 2 /* write */
+#define PF_R 4 /* read */
+
+// Section header (contains info about section)
+typedef struct {
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+// sh_type values
+#define SHT_NULL 0 /* Inactive section */
+#define SHT_PROGBITS 1 /* Proprietary */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addend */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Info for dynamic linking */
+#define SHT_NOTE 7 /* Note section */
+#define SHT_NOBITS 8 /* Occupies no space */
+#define SHT_REL 9 /* Relocation entries without addend */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
+#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */
+
+// sh_flags values
+#define SHF_WRITE 0 /* writable section */
+#define SHF_ALLOC 2 /* section occupies memory */
+#define SHF_EXECINSTR 4 /* machine instructions */
+#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */
+
+
+// Symbol entry (contain info about a symbol)
+typedef struct {
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+// Extract from the st_info
+#define SYM_TYPE(x) ((x)&0xF)
+#define SYM_BIND(x) ((x)>>4)
+
+
+// Symbol binding values from st_info
+#define STB_LOCAL 0 /* Symbol not visible outside object */
+#define STB_GLOBAL 1 /* Symbol visible to all object files */
+#define STB_WEAK 2 /* Similar to STB_GLOBAL */
+
+// Symbol type values from st_info
+#define STT_NOTYPE 0 /* Not specified */
+#define STT_OBJECT 1 /* Data object e.g. variable */
+#define STT_FUNC 2 /* Function */
+#define STT_SECTION 3 /* Section */
+#define STT_FILE 4 /* Source file associated with object file */
+
+// Special section header index values from st_shndex
+#define SHN_UNDEF 0
+#define SHN_LOPROC 0xFF00 /* Extended values */
+#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
+#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
+#define SHN_HIPROC 0xFF1F
+#define SHN_HIRESERVE 0xFFFF
+
+// Relocation entry (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+// Access macros for the relocation info
+#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */
+#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
+
+// MIPS relocation types
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+#define R_MIPS_GOTHI16 13
+#define R_MIPS_GOTLO16 14
+#define R_MIPS_CALLHI16 15
+#define R_MIPS_CALLLO16 16
+
+// Mock function to get value of global pointer
+#define getGP() ({ \
+ unsigned int __valgp; \
+ __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
+ __valgp; \
+})
+
+#endif /* BACKENDS_ELF_H */
diff --git a/backends/platform/ps2/main_prog.ld b/backends/platform/ps2/main_prog.ld
new file mode 100644
index 0000000000..de4b534135
--- /dev/null
+++ b/backends/platform/ps2/main_prog.ld
@@ -0,0 +1,97 @@
+ENTRY(_start);
+
+SECTIONS {
+ .text 0x00100000: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ }
+
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ KEEP(*crtbegin*.o(.ctors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors))
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ }
+ .dtors ALIGN(16): {
+ KEEP(*crtbegin*.o(.dtors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors))
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ _gp = ALIGN(128) + 0x7ff0;
+ .lit4 ALIGN(128): { *(.lit4) }
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+
+ __plugin_hole_start = .;
+ . = _gp + 0x7ff0;
+ __plugin_hole_end = .;
+
+ COMMON :
+ {
+ *(COMMON)
+ }
+ . = ALIGN(128);
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+}
diff --git a/backends/platform/ps2/module.mk b/backends/platform/ps2/module.mk
index 86b12cb668..69a28b93c4 100644
--- a/backends/platform/ps2/module.mk
+++ b/backends/platform/ps2/module.mk
@@ -16,7 +16,8 @@ MODULE_OBJS := \
systemps2.o \
ps2mutex.o \
ps2time.o \
- ps2debug.o
+ ps2debug.o \
+ ps2loader.o
MODULE_DIRS += \
backends/platform/ps2/
diff --git a/backends/platform/ps2/plugin.ld b/backends/platform/ps2/plugin.ld
new file mode 100644
index 0000000000..d6ca6dcfe6
--- /dev/null
+++ b/backends/platform/ps2/plugin.ld
@@ -0,0 +1,214 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips",
+ "elf32-littlemips")
+OUTPUT_ARCH(mips:5900)
+SEARCH_DIR("/home/tony/GSOC/ps2/tools/ee/ee/lib");
+PHDRS
+{
+ plugin PT_LOAD ;
+ shorts PT_LOAD ;
+}
+/* Do we need any of these for elf?
+ __DYNAMIC = 0;
+_DYNAMIC_LINK = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x100000;
+ .interp : { *(.interp) } : plugin
+ .reginfo : { *(.reginfo) } : plugin
+ .dynamic : { *(.dynamic) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+ *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+ *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+ *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ _ftext = . ;
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.mips16.fn.*) *(.mips16.call.*)
+ } =0
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(128) + (. & (128 - 1));
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(32 / 8);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { *(.preinit_array) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { *(.init_array) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { *(.fini_array) }
+ PROVIDE (__fini_array_end = .);
+ .data :
+ {
+ _fdata = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .eh_frame : { KEEP (*(.eh_frame)) }
+ .gcc_except_table : { *(.gcc_except_table) }
+ .dynamic : { *(.dynamic) }
+ .ctors :
+ {
+ ___plugin_ctors = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __plugin_ctors_end = .;
+ }
+ .dtors :
+ {
+ ___plugin_dtors = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+ .jcr : { KEEP (*(.jcr)) }
+
+ . = __plugin_hole_start;
+
+ .got : { *(.got.plt) *(.got) } : shorts
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ _fbss = .;
+ .sbss :
+ {
+ PROVIDE (__sbss_start = .);
+ PROVIDE (___sbss_start = .);
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ PROVIDE (__sbss_end = .);
+ PROVIDE (___sbss_end = .);
+ }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+ }
+ . = ALIGN(32 / 8);
+ _end = .;
+ PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+
+ /* Symbols needed by crt0.s */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+}
diff --git a/backends/platform/ps2/plugin.syms b/backends/platform/ps2/plugin.syms
new file mode 100644
index 0000000000..24ee1a19dc
--- /dev/null
+++ b/backends/platform/ps2/plugin.syms
@@ -0,0 +1,8 @@
+PLUGIN_getVersion
+PLUGIN_getType
+PLUGIN_getTypeVersion
+PLUGIN_getObject
+___plugin_ctors
+___plugin_ctors_end
+___plugin_dtors
+___plugin_dtors_end
diff --git a/backends/platform/ps2/ps2loader.cpp b/backends/platform/ps2/ps2loader.cpp
new file mode 100644
index 0000000000..bea697bf07
--- /dev/null
+++ b/backends/platform/ps2/ps2loader.cpp
@@ -0,0 +1,721 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <sys/_default_fcntl.h>
+
+#include <ps2utils.h>
+
+#include "backends/platform/ps2/ps2loader.h"
+//#include "backends/platform/ps2/powerman.h" //TODO
+
+//#define __PS2_DEBUG_PLUGINS__
+
+#ifdef __PS2_DEBUG_PLUGINS__
+#define DBG(x,...) fprintf(stderr,x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) fprintf(stderr,x, ## __VA_ARGS__)
+
+extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
+extern char __plugin_hole_end; // Indicates end of hole in program file
+extern char _gp[]; // Value of gp register
+
+DECLARE_SINGLETON(ShortSegmentManager) // For singleton
+
+// Get rid of symbol table in memory
+void DLObject::discard_symtab() {
+ free(_symtab);
+ free(_strtab);
+ _symtab = NULL;
+ _strtab = NULL;
+ _symbol_cnt = 0;
+}
+
+// Unload all objects from memory
+void DLObject::unload() {
+ discard_symtab();
+ free(_segment);
+ _segment = NULL;
+
+ if (_shortsSegment) {
+ ShortsMan.deleteSegment(_shortsSegment);
+ _shortsSegment = NULL;
+ }
+}
+
+/**
+ * Follow the instruction of a relocation section.
+ *
+ * @param fd File Descriptor
+ * @param offset Offset into the File
+ * @param size Size of relocation section
+ * @param relSegment Base address of relocated segment in memory (memory offset)
+ *
+ */
+bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) {
+ Elf32_Rel *rel = NULL; // relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (lseek(fd, offset, SEEK_SET) < 0 ||
+ read(fd, rel, size) != (ssize_t)size) {
+ seterror("Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ int cnt = size / sizeof(*rel);
+
+ DBG("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
+
+ bool seenHi16 = false; // For treating HI/LO16 commands
+ int firstHi16 = -1; // Mark the point of the first hi16 seen
+ Elf32_Addr ahl = 0; // Calculated addend
+ int a = 0; // Addend: taken from the target
+
+ unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives
+ unsigned int relocation = 0;
+ int debugRelocs[10] = {0}; // For debugging
+ int extendedHi16 = 0; // Count extended hi16 treatments
+ Elf32_Addr lastHiSymVal = 0;
+ bool hi16InShorts = false;
+
+#define DEBUG_NUM 2
+
+ // Loop over relocation entries
+ for (int i = 0; i < cnt; i++) {
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code
+ unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
+
+ unsigned int origTarget = *target; // Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+
+ case R_MIPS_HI16: // Absolute addressing.
+ if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
+ firstHi16 < 0) { // Only process first in block of HI16s
+ firstHi16 = i; // Keep the first Hi16 we saw
+ seenHi16 = true;
+ ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
+
+ lastHiSymVal = sym->st_value;
+ hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments
+ if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
+ DBG("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n",
+ i, rel[i].r_offset, ahl, *target);
+ }
+ break;
+
+ case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
+ if (!seenHi16) { // We MUST have seen HI16 first
+ seterror("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i);
+ free(rel);
+ return false;
+ }
+
+ // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
+ // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
+ // and will be screened out above
+ bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
+
+ // Correct the bug by getting the proper value in ahl (taken from the current symbol)
+ if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
+ ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
+ ahl += (sym->st_value & 0xffff0000);
+ }
+
+ ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
+ a = *target & 0xffff; // Take lower 16 bits of the target
+ a = (a << 16) >> 16; // Sign extend them
+ ahl += a; // Add lower 16 bits. AHL is now complete
+
+ // Fix: we can have LO16 access to the short segment sometimes
+ if (lo16InShorts) {
+ relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
+ } else // It's in the regular segment
+ relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment
+
+ if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
+ for (int j = firstHi16; j < i; j++) {
+ if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s
+
+ lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target
+ *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
+ *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
+ if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
+ }
+ firstHi16 = -1; // Reset so we'll know we treated it
+ } else {
+ extendedHi16++;
+ }
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of current target
+ *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
+
+ if (debugRelocs[1]++ < DEBUG_NUM)
+ DBG("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
+ DBG("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_26: // Absolute addressing (for jumps and branches only)
+ if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
+ a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
+ a = (a << 6) >> 6; // Sign extend a
+ relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset
+ *target &= 0xfc000000; // Clean lower 26 target bits
+ *target |= (relocation & 0x03ffffff);
+
+ if (debugRelocs[3]++ < DEBUG_NUM)
+ DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ } else {
+ if (debugRelocs[4]++ < DEBUG_NUM)
+ DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_GPREL16: // GP Relative addressing
+ if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
+ ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole
+ a = *target & 0xffff; // Get 16 bits' worth of the addend
+ a = (a << 16) >> 16; // Sign extend it
+
+ relocation = a + _shortsSegment->getOffset();
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of the target
+ *target |= relocation & 0xffff;
+
+ if (debugRelocs[5]++ < DEBUG_NUM)
+ DBG("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n",
+ i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
+ }
+
+ break;
+
+ case R_MIPS_32: // Absolute addressing
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+
+ if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
+ relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
+ else // We're in the main section
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+ *target = relocation;
+
+ if (debugRelocs[6]++ < DEBUG_NUM)
+ DBG("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ }
+ break;
+
+ default:
+ seterror("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i);
+ free(rel);
+ return false;
+ }
+ }
+
+ DBG("Done with relocation. extendedHi16=%d\n\n", extendedHi16);
+
+ free(rel);
+ return true;
+}
+
+bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) {
+ // Start reading the elf header. Check for errors
+ if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
+ memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC
+ ehdr->e_type != ET_EXEC || // Check for executable
+ ehdr->e_machine != EM_MIPS || // Check for MIPS machine type
+ ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
+ ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
+ seterror("Invalid file type.");
+ return false;
+ }
+
+ DBG("phoff = %d, phentsz = %d, phnum = %d\n",
+ ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
+
+ return true;
+}
+
+bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
+ // Read program header
+ if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
+ read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) {
+ seterror("Program header load failed.");
+ return false;
+ }
+
+ // Check program header values
+ if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
+ seterror("Invalid program header.");
+ return false;
+ }
+
+ DBG("offs = %x, filesz = %x, memsz = %x, align = %x\n",
+ phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
+
+ return true;
+
+}
+
+bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) {
+
+ char *baseAddress = 0;
+
+ // We need to take account of non-allocated segment for shorts
+ if (phdr->p_flags & PF_X) { // This is a relocated segment
+
+ // Attempt to allocate memory for segment
+ int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
+ DBG("extra mem is %x\n", extra);
+
+ if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI
+
+ if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
+ seterror("Out of memory.\n");
+ return false;
+ }
+ DBG("allocated segment @ %p\n", _segment);
+
+ // Get offset to load segment into
+ baseAddress = (char *)_segment + phdr->p_vaddr;
+ _segmentSize = phdr->p_memsz + extra;
+ } else { // This is a shorts section.
+ _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
+
+ baseAddress = _shortsSegment->getStart();
+ DBG("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n",
+ _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset());
+
+ }
+
+ // Set bss segment to 0 if necessary (assumes bss is at the end)
+ if (phdr->p_memsz > phdr->p_filesz) {
+ DBG("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
+ memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+ // Read the segment into memory
+ if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 ||
+ read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
+ seterror("Segment load failed.");
+ return false;
+ }
+
+ return true;
+}
+
+
+Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) {
+
+ Elf32_Shdr *shdr = NULL;
+
+ // Allocate memory for section headers
+ if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
+ seterror("Out of memory.");
+ return NULL;
+ }
+
+ // Read from file into section headers
+ if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 ||
+ read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) !=
+ (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) {
+ seterror("Section headers load failed.");
+ return NULL;
+ }
+
+ return shdr;
+}
+
+int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, looking for symbol table linked to a string table
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+ //DBG("Section %d: type = %x, size = %x, entsize = %x, link = %x\n",
+ // i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link);
+
+ if (shdr[i].sh_type == SHT_SYMTAB &&
+ shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
+ shdr[i].sh_link < ehdr->e_shnum &&
+ shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
+ _symtab_sect < 0) {
+ _symtab_sect = i;
+ }
+ }
+
+ // Check for no symbol table
+ if (_symtab_sect < 0) {
+ seterror("No symbol table.");
+ return -1;
+ }
+
+ DBG("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size);
+
+ // Allocate memory for symbol table
+ if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) {
+ seterror("Out of memory.");
+ return -1;
+ }
+
+ // Read symbol table into memory
+ if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
+ read(fd, _symtab, shdr[_symtab_sect].sh_size) !=
+ (ssize_t)shdr[_symtab_sect].sh_size) {
+ seterror("Symbol table load failed.");
+ return -1;
+ }
+
+ // Set number of symbols
+ _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
+ DBG("Loaded %d symbols.\n", _symbol_cnt);
+
+ return _symtab_sect;
+
+}
+
+bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) {
+
+ int string_sect = shdr[_symtab_sect].sh_link;
+
+ // Allocate memory for string table
+ if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read string table into memory
+ if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
+ read(fd, _strtab, shdr[string_sect].sh_size) !=
+ (ssize_t)shdr[string_sect].sh_size) {
+ seterror("Symbol table strings load failed.");
+ return false;
+ }
+ return true;
+}
+
+void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) {
+
+ int shortsCount = 0, othersCount = 0;
+ DBG("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset);
+
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++) {
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
+ othersCount++;
+ s->st_value += offset;
+ if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ } else { // shorts section
+ shortsCount++;
+ s->st_value += shortsOffset;
+ if (!_shortsSegment->inSegment((char *)s->st_value))
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ }
+
+ }
+
+ }
+
+ DBG("Relocated %d short symbols, %d others.\n", shortsCount, othersCount);
+}
+
+bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, finding relocation sections
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+
+ Elf32_Shdr *curShdr = &(shdr[i]);
+ //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
+
+ if (curShdr->sh_type == SHT_REL && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+ if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
+ if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) {
+ return false;
+ }
+ } else { // In Shorts segment
+ if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
+ return false;
+ }
+ }
+
+ }
+ }
+
+ return true;
+}
+
+
+bool DLObject::load(int fd) {
+ fprintf(stderr, "In DLObject::load\n");
+
+ Elf32_Ehdr ehdr; // ELF header
+ Elf32_Phdr phdr; // Program header
+ Elf32_Shdr *shdr; // Section header
+ bool ret = true;
+
+ if (readElfHeader(fd, &ehdr) == false) {
+ return false;
+ }
+
+ for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments
+
+ fprintf(stderr, "Loading segment %d\n", i);
+
+ if (readProgramHeaders(fd, &ehdr, &phdr, i) == false)
+ return false;
+
+ if (!loadSegment(fd, &phdr))
+ return false;
+ }
+
+ if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL)
+ ret = false;
+
+ if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0))
+ ret = false;
+
+ if (ret && (loadStringTable(fd, shdr) == false))
+ ret = false;
+
+ if (ret)
+ relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address
+
+ if (ret && (relocateRels(fd, &ehdr, shdr) == false))
+ ret = false;
+
+ free(shdr);
+
+ return ret;
+}
+
+bool DLObject::open(const char *path) {
+ int fd;
+ void *ctors_start, *ctors_end;
+
+ DBG("open(\"%s\")\n", path);
+
+ // Get the address of the global pointer
+ _gpVal = (unsigned int) & _gp;
+ DBG("_gpVal is %x\n", _gpVal);
+
+ PowerMan.beginCriticalSection();
+
+ if ((fd = ::open(path, O_RDONLY)) < 0) {
+ seterror("%s not found.", path);
+ return false;
+ }
+
+ // Try to load and relocate
+ if (!load(fd)) {
+ ::close(fd);
+ unload();
+ return false;
+ }
+
+ ::close(fd);
+
+ PowerMan.endCriticalSection();
+
+ // flush data cache
+ sceKernelDcacheWritebackAll();
+
+ // Get the symbols for the global constructors and destructors
+ ctors_start = symbol("___plugin_ctors");
+ ctors_end = symbol("___plugin_ctors_end");
+ _dtors_start = symbol("___plugin_dtors");
+ _dtors_end = symbol("___plugin_dtors_end");
+
+ if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL ||
+ _dtors_end == NULL) {
+ seterror("Missing ctors/dtors.");
+ _dtors_start = _dtors_end = NULL;
+ unload();
+ return false;
+ }
+
+ DBG("Calling constructors.\n");
+ for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
+ (**f)();
+
+ DBG("%s opened ok.\n", path);
+ return true;
+}
+
+bool DLObject::close() {
+ if (_dtors_start != NULL && _dtors_end != NULL)
+ for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
+ (**f)();
+ _dtors_start = _dtors_end = NULL;
+ unload();
+ return true;
+}
+
+void *DLObject::symbol(const char *name) {
+ DBG("symbol(\"%s\")\n", name);
+
+ if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) {
+ seterror("No symbol table loaded.");
+ return NULL;
+ }
+
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++) {
+
+ // We can only import symbols that are global or weak in the plugin
+ if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) &&
+ /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient
+ !strcmp(name, _strtab + s->st_name)) {
+
+ // We found the symbol
+ DBG("=> %p\n", (void*)s->st_value);
+ return (void*)s->st_value;
+ }
+ }
+
+ seterror("Symbol \"%s\" not found.", name);
+ return NULL;
+}
+
+
+
+ShortSegmentManager::ShortSegmentManager() {
+ _shortsStart = &__plugin_hole_start ;
+ _shortsEnd = &__plugin_hole_end;
+}
+
+ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) {
+ char *lastAddress = origAddr;
+ Common::List<Segment *>::iterator i;
+
+ // Find a block that fits, starting from the beginning
+ for (i = _list.begin(); i != _list.end(); ++i) {
+ char *currAddress = (*i)->getStart();
+
+ if ((int)(currAddress - lastAddress) >= size) break;
+
+ lastAddress = (*i)->getEnd();
+ }
+
+ if ((Elf32_Addr)lastAddress & 3)
+ lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
+
+ if (lastAddress + size > _shortsEnd) {
+ seterror("Error. No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n",
+ size, lastAddress, _shortsEnd);
+ return NULL;
+ }
+
+ Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
+
+ if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum
+
+ _list.insert(i, seg);
+
+ DBG("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n",
+ size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
+
+ return seg;
+}
+
+void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
+ DBG("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd());
+ _list.remove(seg);
+ delete seg;
+}
+
+static char dlerr[MAXDLERRLEN];
+
+void *dlopen(const char *filename, int flags) {
+ DLObject *obj = new DLObject(dlerr);
+ if (obj->open(filename))
+ return (void *)obj;
+ delete obj;
+ return NULL;
+}
+
+int dlclose(void *handle) {
+ DLObject *obj = (DLObject *)handle;
+ if (obj == NULL) {
+ strcpy(dlerr, "Handle is NULL.");
+ return -1;
+ }
+ if (obj->close()) {
+ delete obj;
+ return 0;
+ }
+ return -1;
+}
+
+void *dlsym(void *handle, const char *symbol) {
+ if (handle == NULL) {
+ strcpy(dlerr, "Handle is NULL.");
+ return NULL;
+ }
+ return ((DLObject *)handle)->symbol(symbol);
+}
+
+const char *dlerror() {
+ return dlerr;
+}
+
+void dlforgetsyms(void *handle) {
+ if (handle != NULL)
+ ((DLObject *)handle)->discard_symtab();
+}
+
+
+#endif /* DYNAMIC_MODULES && __PLAYSTATION2__ */
diff --git a/backends/platform/ps2/ps2loader.h b/backends/platform/ps2/ps2loader.h
new file mode 100644
index 0000000000..7c412e7b05
--- /dev/null
+++ b/backends/platform/ps2/ps2loader.h
@@ -0,0 +1,137 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef PS2LOADER_H
+#define PS2LOADER_H
+
+#include "elf32.h"
+#include "common/list.h"
+#include "common/singleton.h"
+
+#define MAXDLERRLEN 80
+
+#define ShortsMan ShortSegmentManager::instance()
+
+class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> {
+private:
+ char *_shortsStart;
+ char *_shortsEnd;
+
+public:
+ char *getShortsStart() {
+ return _shortsStart;
+ }
+ bool inGeneralSegment(char *addr) {
+ return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd);
+ }
+
+ class Segment {
+ private:
+ friend class ShortSegmentManager;
+ Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {}
+ ~Segment() {}
+ char *_startAddress; // Start of shorts segment in memory
+ int _size; // Size of shorts segment
+ char *_origAddress; // Original address this segment was supposed to be at
+ public:
+ char *getStart() {
+ return _startAddress;
+ }
+ char *getEnd() {
+ return (_startAddress + _size);
+ }
+ Elf32_Addr getOffset() {
+ return (Elf32_Addr)(_startAddress - _origAddress);
+ }
+ bool inSegment(char *addr) {
+ return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size);
+ }
+ };
+
+ Segment *newSegment(int size, char *origAddr);
+ void deleteSegment(Segment *);
+
+private:
+ ShortSegmentManager();
+ friend class Common::Singleton<ShortSegmentManager>;
+ Common::List<Segment *> _list;
+ char *_highestAddress;
+};
+
+
+
+
+class DLObject {
+protected:
+ char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */
+
+ ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
+ void *_segment, *_symtab;
+ char *_strtab;
+ int _symbol_cnt;
+ int _symtab_sect;
+ void *_dtors_start, *_dtors_end;
+
+ unsigned int _gpVal; // Value of Global Pointer
+ int _segmentSize;
+
+ void seterror(const char *fmt, ...);
+ void unload();
+ bool relocate(int fd, unsigned long offset, unsigned long size, void *);
+ bool load(int fd);
+
+ bool readElfHeader(int fd, Elf32_Ehdr *ehdr);
+ bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
+ bool loadSegment(int fd, Elf32_Phdr *phdr);
+ Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr);
+ int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ bool loadStringTable(int fd, Elf32_Shdr *shdr);
+ void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset);
+ bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+
+public:
+ bool open(const char *path);
+ bool close();
+ void *symbol(const char *name);
+ void discard_symtab();
+
+ DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL),
+ _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) ,
+ _segmentSize(0) {}
+};
+
+
+
+#define RTLD_LAZY 0
+
+extern "C" {
+ void *dlopen(const char *filename, int flags);
+ int dlclose(void *handle);
+ void *dlsym(void *handle, const char *symbol);
+ const char *dlerror();
+ void dlforgetsyms(void *handle);
+}
+
+#endif /* PS2LOADER_H */
diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp
index 7659d5194d..120f6ee157 100644
--- a/backends/platform/ps2/systemps2.cpp
+++ b/backends/platform/ps2/systemps2.cpp
@@ -59,6 +59,8 @@
#include "backends/platform/ps2/ps2debug.h"
#include "backends/fs/ps2/ps2-fs-factory.h"
+#include "backends/plugins/ps2/ps2-provider.h"
+
#include "backends/saves/default/default-saves.h"
#include "common/config-manager.h"
@@ -132,6 +134,10 @@ extern "C" int main(int argc, char *argv[]) {
g_systemPs2->init();
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new PS2PluginProvider());
+#endif
+
sioprintf("init done. starting ScummVM.\n");
int res = scummvm_main(argc, argv);
sioprintf("scummvm_main terminated: %d\n", res);
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 7f8bb63b0a..8e83563d10 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -129,8 +129,7 @@ SDLFLAGS := $(shell $(PSPBIN)/sdl-config --cflags)
SDLLIBS := $(shell $(PSPBIN)/sdl-config --libs)
# PSP LIBS
PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \
- -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \
- -lpspkernel
+ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspkernel
# Add in PSPSDK includes and libraries.
CXXFLAGS += $(SDLFLAGS)
@@ -148,10 +147,8 @@ OBJS := powerman.o \
cursor.o \
trace.o \
psploader.o \
- pspkeyboard.o \
- audio.o \
- thread.o \
- mp3.o
+ pspkeyboard.o
+
# Include common Scummvm makefile
include $(srcdir)/Makefile.common
diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp
deleted file mode 100644
index bf1fb9ab41..0000000000
--- a/backends/platform/psp/audio.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
- *
- */
-
-#include <pspthreadman.h>
-#include <pspaudio.h>
-
-#include "common/scummsys.h"
-#include "backends/platform/psp/audio.h"
-#include "backends/platform/psp/thread.h"
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
-//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
-
-#include "backends/platform/psp/trace.h"
-
-bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, callbackFunc callback, void *userData) {
- DEBUG_ENTER_FUNC();
- if (_init) {
- PSP_ERROR("audio device already initialized\n");
- return true;
- }
-
- PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n",
- freq, numOfChannels, numOfSamples, callback, (uint32)userData);
-
- numOfSamples = PSP_AUDIO_SAMPLE_ALIGN(numOfSamples);
- uint32 bufLen = numOfSamples * numOfChannels * NUM_BUFFERS * sizeof(uint16);
-
- PSP_DEBUG_PRINT("total buffer size[%d]\n", bufLen);
-
- _buffers[0] = (byte *)memalign(64, bufLen);
- if (!_buffers[0]) {
- PSP_ERROR("failed to allocate memory for audio buffers\n");
- return false;
- }
- memset(_buffers[0], 0, bufLen); // clean the buffer
-
- // Fill in the rest of the buffer pointers
- byte *pBuffer = _buffers[0];
- for (int i = 1; i < NUM_BUFFERS; i++) {
- pBuffer += numOfSamples * numOfChannels * sizeof(uint16);
- _buffers[i] = pBuffer;
- }
-
- // Reserve a HW channel for our audio
- _pspChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, numOfSamples, numOfChannels == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO);
- if (_pspChannel < 0) {
- PSP_ERROR("failed to reserve audio channel\n");
- return false;
- }
-
- PSP_DEBUG_PRINT("reserved channel[%d] for audio\n", _pspChannel);
-
- // Save our data
- _numOfChannels = numOfChannels;
- _numOfSamples = numOfSamples;
- _bufferSize = numOfSamples * numOfChannels * sizeof(uint16); // should be the right size to send the app
- _callback = callback;
- _userData = userData;
- _bufferToFill = 0;
- _bufferToPlay = 0;
-
- _init = true;
- _paused = true; // start in paused mode
-
- createThread();
-
- return true;
-}
-
-bool PspAudio::createThread() {
- DEBUG_ENTER_FUNC();
- int threadId = sceKernelCreateThread("audioThread", thread, PRIORITY_AUDIO_THREAD, STACK_AUDIO_THREAD, THREAD_ATTR_USER, 0);
-
- if (threadId < 0) { // error
- PSP_ERROR("failed to create audio thread. Error code %d\n", threadId);
- return false;
- }
-
- PspAudio *_this = this; // trick to get into context when the thread starts
-
- if (sceKernelStartThread(threadId, sizeof(uint32 *), &_this) < 0) {
- PSP_ERROR("failed to start thread %d\n", threadId);
- return false;
- }
-
- PSP_DEBUG_PRINT("created audio thread[%x]\n", threadId);
-
- return true;
-}
-
-// Static function to be called upon thread startup. Will call a non-static function
-int PspAudio::thread(SceSize, void *__this) {
- DEBUG_ENTER_FUNC();
- PspAudio *_this = *(PspAudio **)__this; // get our this for the context
-
- _this->audioThread();
- return 0;
-};
-
-// The real thread function
-void PspAudio::audioThread() {
- assert(_callback);
- PSP_DEBUG_PRINT_FUNC("audio thread started\n");
-
- while (_init) { // Keep looping so long as we haven't been told to stop
- if (_paused)
- PSP_DEBUG_PRINT("audio thread paused\n");
- while (_paused) { // delay until we stop pausing
- sceKernelDelayThread(100000); // 100ms
- if (!_paused)
- PSP_DEBUG_PRINT("audio thread unpaused\n");
- }
-
- PSP_DEBUG_PRINT("remaining samples[%d]\n", remainingSamples);
-
- PSP_DEBUG_PRINT("filling buffer[%d]\n", _bufferToFill);
- _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in
- nextBuffer(_bufferToFill);
-
- PSP_DEBUG_PRINT("playing buffer[%d].\n", _bufferToPlay);
- playBuffer();
- nextBuffer(_bufferToPlay);
- } // while _init
-
- // destroy everything
- free(_buffers[0]);
- sceAudioChRelease(_pspChannel);
- PSP_DEBUG_PRINT("audio thread exiting. ****************************\n");
-}
-
-// Much faster than using %
-inline void PspAudio::nextBuffer(int &bufferIdx) {
- DEBUG_ENTER_FUNC();
- bufferIdx++;
- if (bufferIdx >= NUM_BUFFERS)
- bufferIdx = 0;
-}
-
-// Don't do it with blocking
-inline bool PspAudio::playBuffer() {
- DEBUG_ENTER_FUNC();
- int ret;
- if (_numOfChannels == 1)
- ret = sceAudioOutputBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
- else
- ret = sceAudioOutputPannedBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
-
- if (ret < 0) {
- PSP_ERROR("failed to output audio. Error[%d]\n", ret);
- return false;
- }
- return true;
-}
-
-void PspAudio::close() {
- PSP_DEBUG_PRINT("close had been called ***************\n");
- _init = false;
-}
diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h
deleted file mode 100644
index 603f8f6bfc..0000000000
--- a/backends/platform/psp/audio.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
- *
- */
-
-#ifndef PSP_AUDIO_H
-#define PSP_AUDIO_H
-
-class PspAudio {
-public:
- enum {
- NUM_BUFFERS = 2,
- FREQUENCY = 44100 /* only frequency we allow */
- };
- typedef void (* callbackFunc)(void *userData, byte *samples, int len);
- PspAudio() : _pspChannel(0),
- _numOfChannels(0), _numOfSamples(0), _callback(0),
- _bufferToPlay(0), _bufferToFill(0),
- _init(false), _paused(true) {
- for (int i=0; i<NUM_BUFFERS; i++)
- _buffers[i] = 0;
- }
- ~PspAudio() { close(); }
- bool playBuffer();
- void nextBuffer(int &bufferIdx);
- static int thread(SceSize, void *);
- void audioThread();
- bool open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, callbackFunc callback, void *userData);
- bool createThread();
- void close();
- uint32 getFrequency() { return FREQUENCY; }
- void pause() { _paused = true; }
- void unpause() { _paused = false; }
-
-private:
- int _pspChannel; // chosen hardware output channel
- uint32 _numOfChannels; // 1 for mono; 2 for stereo
- uint32 _numOfSamples;
- callbackFunc _callback; // the callback to call between outputting audio
- void *_userData; // userData to send with callback
- byte *_buffers[NUM_BUFFERS];
- int _bufferToPlay; // the next buffer to output
- int _bufferToFill;
- int _bufferSize;
- bool _init; // flag for initialization
- bool _paused;
-};
-
-#endif /* PSP_AUDIO_H */
diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp
index c5a6250188..90c41e796d 100644
--- a/backends/platform/psp/display_client.cpp
+++ b/backends/platform/psp/display_client.cpp
@@ -686,18 +686,17 @@ void GuRenderer::fillVertices(Vertex *vertices) {
uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0;
uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0;
- // Save scaled offset on screen
- float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x);
- float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y);
-
float imageStartX, imageStartY, imageEndX, imageEndY;
- imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x));
- imageStartY = gapY + scaledOffsetOnScreenY;
+ imageStartX = gapX + (scaleSourceToOutputX(_maxTextureOffset.x));
+ imageStartY = gapY;
+
+ imageStartX += scaleSourceToOutputX(_offsetOnScreen.x);
+ imageStartY += scaleSourceToOutputY(_offsetOnScreen.y);
if (_fullScreen) { // shortcut
- imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX;
- imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake
+ imageEndX = PSP_SCREEN_WIDTH - gapX;
+ imageEndY = PSP_SCREEN_HEIGHT - gapY;
} else { /* !fullScreen */
imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width);
imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height);
diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp
index c2f21e084b..0982512a86 100644
--- a/backends/platform/psp/display_manager.cpp
+++ b/backends/platform/psp/display_manager.cpp
@@ -34,7 +34,6 @@
#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/cursor.h"
#include "backends/platform/psp/pspkeyboard.h"
-#include "backends/platform/psp/thread.h"
#define USE_DISPLAY_CALLBACK // to use callback for finishing the render
#include "backends/platform/psp/display_manager.h"
@@ -65,7 +64,7 @@ const OSystem::GraphicsMode DisplayManager::_supportedModes[] = {
void MasterGuRenderer::setupCallbackThread() {
DEBUG_ENTER_FUNC();
- int thid = sceKernelCreateThread("displayCbThread", guCallbackThread, PRIORITY_DISPLAY_THREAD, STACK_DISPLAY_THREAD, THREAD_ATTR_USER, 0);
+ int thid = sceKernelCreateThread("displayCbThread", guCallbackThread, 0x11, 4*1024, THREAD_ATTR_USER, 0);
PSP_DEBUG_PRINT("Display CB thread id is %x\n", thid);
diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk
index 99170ce7fb..f7191fe14f 100644
--- a/backends/platform/psp/module.mk
+++ b/backends/platform/psp/module.mk
@@ -12,10 +12,7 @@ MODULE_OBJS := powerman.o \
cursor.o \
trace.o \
psploader.o \
- pspkeyboard.o \
- audio.o \
- thread.o \
- mp3.o
+ pspkeyboard.o
MODULE_DIRS += \
backends/platform/psp/
diff --git a/backends/platform/psp/mp3.cpp b/backends/platform/psp/mp3.cpp
deleted file mode 100644
index 972c5a8ba8..0000000000
--- a/backends/platform/psp/mp3.cpp
+++ /dev/null
@@ -1,487 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-
-#include "common/debug.h"
-#include "common/stream.h"
-#include "common/util.h"
-#include "common/singleton.h"
-#include "common/mutex.h"
-
-#include "sound/audiostream.h"
-
-#include <pspaudiocodec.h>
-#include <psputility_modules.h>
-#include <pspthreadman.h>
-#include <pspsysmem.h>
-#include <pspmodulemgr.h>
-#include <psputility_avmodules.h>
-#include <mad.h>
-#include "backends/platform/psp/mp3.h"
-
-//#define DISABLE_PSP_MP3 // to make us use the regular MAD decoder instead
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-#include "backends/platform/psp/trace.h"
-
-//#define PRINT_BUFFERS /* to debug MP3 buffers */
-
-namespace Audio {
-
-class Mp3PspStream;
-
-bool Mp3PspStream::_decoderInit = false; // has the decoder been initialized
-#ifdef DISABLE_PSP_MP3
-bool Mp3PspStream::_decoderFail = true; // pretend the decoder failed
-#else
-bool Mp3PspStream::_decoderFail = false; // has the decoder failed to load
-#endif
-
-bool Mp3PspStream::initDecoder() {
- DEBUG_ENTER_FUNC();
-
- if (_decoderInit) {
- PSP_ERROR("Already initialized!");
- return true;
- }
-
- // Based on PSP firmware version, we need to do different things to do Media Engine processing
- uint32 firmware = sceKernelDevkitVersion();
- PSP_DEBUG_PRINT("Firmware version 0x%x\n", firmware);
- if (firmware == 0x01050001){
- if (!loadStartAudioModule((char *)(void *)"flash0:/kd/me_for_vsh.prx",
- PSP_MEMORY_PARTITION_KERNEL)) {
- PSP_ERROR("failed to load me_for_vsh.prx. ME cannot start.\n");
- _decoderFail = true;
- return false;
- }
- if (!loadStartAudioModule((char *)(void *)"flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL)) {
- PSP_ERROR("failed to load audiocodec.prx. ME cannot start.\n");
- _decoderFail = true;
- return false;
- }
- } else {
- if (sceUtilityLoadAvModule(PSP_AV_MODULE_AVCODEC) < 0) {
- PSP_ERROR("failed to load AVCODEC module.\n");
- _decoderFail = true;
- return false;
- }
- }
-
- PSP_INFO_PRINT("Using PSP's ME for MP3\n"); // important to know this is happening
-
- _decoderInit = true;
- return true;
-}
-
-bool Mp3PspStream::stopDecoder() {
- DEBUG_ENTER_FUNC();
-
- if (!_decoderInit)
- return true;
-
- // Based on PSP firmware version, we need to do different things to do Media Engine processing
- if (sceKernelDevkitVersion() == 0x01050001){
-/* if (!unloadAudioModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL) ||
- !unloadAudioModule("flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL) {
- PSP_ERROR("failed to unload audio module\n");
- return false;
- }
-*/
- }else{
- if (sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) < 0) {
- PSP_ERROR("failed to unload avcodec module\n");
- return false;
- }
- }
-
- _decoderInit = false;
- return true;
-}
-
-//Load a PSP audio module
-bool Mp3PspStream::loadStartAudioModule(const char *modname, int partition){
- DEBUG_ENTER_FUNC();
-
- SceKernelLMOption option;
- SceUID modid;
-
- memset(&option, 0, sizeof(option));
- option.size = sizeof(option);
- option.mpidtext = partition;
- option.mpiddata = partition;
- option.position = 0;
- option.access = 1;
-
- modid = sceKernelLoadModule(modname, 0, &option);
- if (modid < 0) {
- PSP_ERROR("Failed to load module %s. Got error 0x%x\n", modname, modid);
- return false;
- }
-
- int ret = sceKernelStartModule(modid, 0, NULL, NULL, NULL);
- if (ret < 0) {
- PSP_ERROR("Failed to start module %s. Got error 0x%x\n", modname, ret);
- return false;
- }
- return true;
-}
-
-// TODO: make parallel function for unloading the 1.50 modules
-
-Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
- _inStream(inStream),
- _disposeAfterUse(dispose),
- _pcmLength(0),
- _posInFrame(0),
- _state(MP3_STATE_INIT),
- _length(0, 1000),
- _sampleRate(0),
- _totalTime(mad_timer_zero) {
-
- DEBUG_ENTER_FUNC();
-
- assert(_decoderInit); // must be initialized by now
-
- // let's leave the buffer guard -- who knows, it may be good?
- memset(_buf, 0, sizeof(_buf));
- memset(_codecInBuffer, 0, sizeof(_codecInBuffer));
-
- initStream(); // init needed stuff for the stream
-
- while (_state != MP3_STATE_EOS)
- findValidHeader(); // get a first header so we can read basic stuff
-
- _sampleRate = _header.samplerate; // copy it before it gets destroyed
-
- _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate());
-
- //initStreamME(); // init the stuff needed for the ME to work
-
- deinitStream();
- //releaseStreamME();
-
- _state = MP3_STATE_INIT;
-}
-
-int Mp3PspStream::initStream() {
- DEBUG_ENTER_FUNC();
-
- if (_state != MP3_STATE_INIT)
- deinitStream();
-
- // Init MAD
- mad_stream_init(&_stream);
- mad_header_init(&_header);
-
- // Reset the stream data
- _inStream->seek(0, SEEK_SET);
- _totalTime = mad_timer_zero;
- _posInFrame = 0;
-
- // Update state
- _state = MP3_STATE_READY;
-
- // Read the first few sample bytes into the buffer
- readMP3DataIntoBuffer();
-
- return true;
-}
-
-bool Mp3PspStream::initStreamME() {
- // The following will eventually go into the thread
- sceAudiocodecReleaseEDRAM(_codecParams); // do we need this?
-
- memset(_codecParams, 0, sizeof(_codecParams));
-
- // Init the MP3 hardware
- int ret = 0;
- ret = sceAudiocodecCheckNeedMem(_codecParams, 0x1002);
- if (ret < 0) {
- PSP_ERROR("failed to init MP3 ME module. sceAudiocodecCheckNeedMem returned 0x%x.\n", ret);
- return false;
- }
- PSP_DEBUG_PRINT("sceAudiocodecCheckNeedMem returned %d\n", ret);
- ret = sceAudiocodecGetEDRAM(_codecParams, 0x1002);
- if (ret < 0) {
- PSP_ERROR("failed to init MP3 ME module. sceAudiocodecGetEDRAM returned 0x%x.\n", ret);
- return false;
- }
- PSP_DEBUG_PRINT("sceAudioCodecGetEDRAM returned %d\n", ret);
-
- PSP_DEBUG_PRINT("samplerate[%d]\n", _sampleRate);
- _codecParams[10] = _sampleRate;
-
- ret = sceAudiocodecInit(_codecParams, 0x1002);
- if (ret < 0) {
- PSP_ERROR("failed to init MP3 ME module. sceAudiocodecInit returned 0x%x.\n", ret);
- return false;
- }
-
- return true;
-}
-
-Mp3PspStream::~Mp3PspStream() {
- DEBUG_ENTER_FUNC();
-
- deinitStream();
- releaseStreamME(); // free the memory used for this stream
-
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _inStream;
-}
-
-void Mp3PspStream::deinitStream() {
- DEBUG_ENTER_FUNC();
-
- if (_state == MP3_STATE_INIT)
- return;
-
- // Deinit MAD
- mad_header_finish(&_header);
- mad_stream_finish(&_stream);
-
- _state = MP3_STATE_EOS;
-}
-
-void Mp3PspStream::releaseStreamME() {
- sceAudiocodecReleaseEDRAM(_codecParams);
-}
-
-void Mp3PspStream::decodeMP3Data() {
- DEBUG_ENTER_FUNC();
-
- do {
- if (_state == MP3_STATE_INIT) {
- initStream();
- initStreamME();
- }
-
- if (_state == MP3_STATE_EOS)
- return;
-
- findValidHeader(); // seach for next valid header
-
- while (_state == MP3_STATE_READY) {
- _stream.error = MAD_ERROR_NONE;
-
- uint32 frame_size = _stream.next_frame - _stream.this_frame;
- uint32 samplesPerFrame = _header.layer == MAD_LAYER_III ? 576 : 1152; // Varies by layer
- // calculate frame size -- try
- //uint32 calc_frame_size = ((144 * _header.bitrate) / 22050) + (_header.flags & MAD_FLAG_PADDING ? 1 : 0);
-
- // Get stereo/mono
- uint32 multFactor = 1;
- if (_header.mode != MAD_MODE_SINGLE_CHANNEL) // mono - x2 for 16bit
- multFactor *= 2; // stereo - x4 for 16bit
-
- PSP_DEBUG_PRINT("MP3 frame size[%d]. Samples[%d]. Multfactor[%d] pad[%d]\n", frame_size, samplesPerFrame, multFactor, _header.flags & MAD_FLAG_PADDING);
- memcpy(_codecInBuffer, _stream.this_frame, frame_size); // we need it aligned
-
- // set up parameters for ME
- _codecParams[6] = (unsigned long)_codecInBuffer;
- _codecParams[8] = (unsigned long)_pcmSamples;
- _codecParams[7] = frame_size;
- _codecParams[9] = samplesPerFrame * multFactor; // x2 for stereo
-
- // debug
-#ifdef PRINT_BUFFERS
- PSP_DEBUG_PRINT("mp3 frame:\n");
- for (int i=0; i < (int)frame_size; i++) {
- PSP_DEBUG_PRINT_SAMELN("%x ", _codecInBuffer[i]);
- }
- PSP_DEBUG_PRINT("\n");
-#endif
- // Decode the next frame
- // This function blocks. We'll want to put it in a thread
- int ret = sceAudiocodecDecode(_codecParams, 0x1002);
- if (ret < 0) {
- PSP_ERROR("failed to decode MP3 data in ME. sceAudiocodecDecode returned 0x%x\n", ret);
- // handle error here
- }
-
-#ifdef PRINT_BUFFERS
- PSP_DEBUG_PRINT("PCM frame:\n");
- for (int i=0; i < (int)_codecParams[9]; i+=2) { // changed from i+=2
- PSP_DEBUG_PRINT_SAMELN("%d ", (int16)_pcmSamples[i]);
- }
- PSP_DEBUG_PRINT("\n");
-#endif
- _pcmLength = samplesPerFrame;
- _posInFrame = 0;
- break;
- }
- } while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);
-
- if (_stream.error != MAD_ERROR_NONE) // catch EOS
- _state = MP3_STATE_EOS;
-}
-
-void Mp3PspStream::readMP3DataIntoBuffer() {
- DEBUG_ENTER_FUNC();
-
- uint32 remaining = 0;
-
- // Give up immediately if we already used up all data in the stream
- if (_inStream->eos()) {
- _state = MP3_STATE_EOS;
- return;
- }
-
- if (_stream.next_frame) {
- // If there is still data in the MAD stream, we need to preserve it.
- // Note that we use memmove, as we are reusing the same buffer,
- // and hence the data regions we copy from and to may overlap.
- remaining = _stream.bufend - _stream.next_frame;
- assert(remaining < BUFFER_SIZE); // Paranoia check
- memmove(_buf, _stream.next_frame, remaining); // TODO: may want another buffer
- }
-
- // Try to read the next block
- uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining);
- if (size <= 0) {
- _state = MP3_STATE_EOS;
- return;
- }
-
- // Feed the data we just read into the stream decoder
- _stream.error = MAD_ERROR_NONE;
- mad_stream_buffer(&_stream, _buf, size + remaining); // just setup the pointers
-}
-
-bool Mp3PspStream::seek(const Timestamp &where) {
- DEBUG_ENTER_FUNC();
-
- if (where == _length) {
- _state = MP3_STATE_EOS;
- return true;
- } else if (where > _length) {
- return false;
- }
-
- const uint32 time = where.msecs();
-
- mad_timer_t destination;
- mad_timer_set(&destination, time / 1000, time % 1000, 1000);
-
- // Check if we need to rewind
- if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) {
- initStream();
- initStreamME();
- }
-
- // The ME will need clear data no matter what once we seek?
- //if (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
- // initStreamME();
-
- // Skip ahead
- while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
- findValidHeader();
-
- return (_state != MP3_STATE_EOS);
-}
-
-// Seek in the stream, finding the next valid header
-void Mp3PspStream::findValidHeader() {
- DEBUG_ENTER_FUNC();
-
- if (_state != MP3_STATE_READY)
- return;
-
- // If necessary, load more data into the stream decoder
- if (_stream.error == MAD_ERROR_BUFLEN)
- readMP3DataIntoBuffer();
-
- while (_state != MP3_STATE_EOS) {
- _stream.error = MAD_ERROR_NONE;
-
- // Decode the next header.
- if (mad_header_decode(&_header, &_stream) == -1) {
- if (_stream.error == MAD_ERROR_BUFLEN) {
- readMP3DataIntoBuffer(); // Read more data
- continue;
- } else if (MAD_RECOVERABLE(_stream.error)) {
- debug(6, "MP3PSPStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
- continue;
- } else {
- warning("MP3PSPStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
- break;
- }
- }
-
- // Sum up the total playback time so far
- mad_timer_add(&_totalTime, _header.duration);
- break;
- }
-
- if (_stream.error != MAD_ERROR_NONE)
- _state = MP3_STATE_EOS;
-}
-
-int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) {
- DEBUG_ENTER_FUNC();
-
- int samples = 0;
-#ifdef PRINT_BUFFERS
- int16 *debugBuffer = buffer;
-#endif
-
- // Keep going as long as we have input available
- while (samples < numSamples && _state != MP3_STATE_EOS) {
- const int len = MIN(numSamples, samples + (int)(_pcmLength - _posInFrame) * MAD_NCHANNELS(&_header));
-
- while (samples < len) {
- *buffer++ = _pcmSamples[_posInFrame << 1];
- samples++;
- if (MAD_NCHANNELS(&_header) == 2) {
- *buffer++ = _pcmSamples[(_posInFrame << 1) + 1];
- samples++;
- }
- _posInFrame++; // always skip an extra sample since ME always outputs stereo
- }
-
- //memcpy(buffer, &_pcmSamples[_posInFrame], len << 1); // 16 bits
- //_posInFrame += len; // next time we start from the middle
-
- if (_posInFrame >= _pcmLength) {
- // We used up all PCM data in the current frame -- read & decode more
- decodeMP3Data();
- }
- }
-
-#ifdef PRINT_BUFFERS
- PSP_INFO_PRINT("buffer:\n");
- for (int i = 0; i<numSamples; i++)
- PSP_INFO_PRINT("%d ", debugBuffer[i]);
- PSP_INFO_PRINT("\n\n");
-#endif
-
- return samples;
-}
-
-} // End of namespace Audio
-
-
diff --git a/backends/platform/psp/mp3.h b/backends/platform/psp/mp3.h
deleted file mode 100644
index f8802f930c..0000000000
--- a/backends/platform/psp/mp3.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef SOUND_MP3_PSP_H
-#define SOUND_MP3_PSP_H
-
-#include "common/types.h"
-#include "common/scummsys.h"
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Audio {
-
-class AudioStream;
-class SeekableAudioStream;
-
-class Mp3PspStream : public SeekableAudioStream {
-protected:
- enum State {
- MP3_STATE_INIT, // Need to init the decoder
- MP3_STATE_READY, // ready for processing data
- MP3_STATE_EOS // end of data reached (may need to loop)
- };
-
- #define MAX_SAMPLES_PER_FRAME 2048 * 2
- int16 _pcmSamples[MAX_SAMPLES_PER_FRAME] __attribute__((aligned(64))); // samples to output PCM data into
- byte _codecInBuffer[3072] __attribute__((aligned(64))); // the codec always needs alignment
- unsigned long _codecParams[65]__attribute__((aligned(64))); // TODO: change to struct
-
- Common::SeekableReadStream *_inStream;
- DisposeAfterUse::Flag _disposeAfterUse;
-
- uint32 _pcmLength; // how many pcm samples we have (/2 for mono)
-
- uint _posInFrame; // position in frame
- State _state; // what state the stream is in
-
- Timestamp _length;
- uint32 _sampleRate;
-
- mad_timer_t _totalTime;
- mad_stream _stream; //
- mad_header _header; // This is all we need from libmad
-
- static bool _decoderInit; // has the decoder been initialized
- static bool _decoderFail; // has the decoder failed to load
-
- enum {
- BUFFER_SIZE = 5 * 8192
- };
-
- // This buffer contains a slab of input data
- byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
-
- void decodeMP3Data();
- void readMP3DataIntoBuffer();
-
- static bool loadStartAudioModule(const char *modname, int partition);
- int initStream();
- void findValidHeader();
- void deinitStream();
-
- // to init and uninit ME decoder
- static bool initDecoder();
- static bool stopDecoder();
-
- // ME functions for stream
- bool initStreamME();
- void releaseStreamME();
-
-public:
- Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose);
- ~Mp3PspStream();
-
- // This function avoids having to create streams when it's not possible
- static inline bool isOkToCreateStream() {
- if (_decoderFail) // fatal failure
- return false;
- if (!_decoderInit) // if we're not initialized
- if (!initDecoder()) // check if we failed init
- return false;
- return true;
- }
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool endOfData() const { return _state == MP3_STATE_EOS; }
- bool isStereo() const { return MAD_NCHANNELS(&_header) == 2; }
- int getRate() const { return _header.samplerate; }
-
- bool seek(const Timestamp &where);
- Timestamp getLength() const { return _length; }
-};
-
-} // End of namespace Audio
-
-#endif // #ifndef SOUND_MP3_PSP_H
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index a36ae1847f..58d98bc219 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -37,7 +37,6 @@
#include "backends/platform/psp/psppixelformat.h"
#include "backends/platform/psp/osys_psp.h"
#include "backends/platform/psp/powerman.h"
-#include "backends/platform/psp/thread.h"
#include "backends/saves/psp/psp-saves.h"
#include "backends/timer/default/default-timer.h"
@@ -49,7 +48,6 @@
#include "backends/platform/psp/trace.h"
-#define USE_PSP_AUDIO
#define SAMPLES_PER_SEC 44100
@@ -60,11 +58,7 @@ static int timer_handler(int t) {
}
void OSystem_PSP::initSDL() {
-#ifdef USE_PSP_AUDIO
- SDL_Init(0);
-#else
- SDL_Init(SDL_INIT_AUDIO);
-#endif
+ SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER);
}
OSystem_PSP::~OSystem_PSP() {}
@@ -91,7 +85,7 @@ void OSystem_PSP::initBackend() {
_inputHandler.init();
initSDL();
-
+
_savefile = new PSPSaveFileManager;
_timer = new DefaultTimerManager();
@@ -299,18 +293,17 @@ bool OSystem_PSP::pollEvent(Common::Event &event) {
return _inputHandler.getAllInputs(event);
}
+
uint32 OSystem_PSP::getMillis() {
- return PspThread::getMillis();
+ return SDL_GetTicks();
}
void OSystem_PSP::delayMillis(uint msecs) {
- PspThread::delayMillis(msecs);
+ SDL_Delay(msecs);
}
void OSystem_PSP::setTimerCallback(TimerProc callback, int interval) {
- _pspTimer.setCallback((PspTimer::CallbackFunc)callback);
- _pspTimer.setIntervalMs(interval);
- _pspTimer.start();
+ SDL_SetTimer(interval, (SDL_TimerCallback)callback);
}
OSystem::MutexRef OSystem_PSP::createMutex(void) {
@@ -338,6 +331,8 @@ void OSystem_PSP::mixCallback(void *sys, byte *samples, int len) {
}
void OSystem_PSP::setupMixer(void) {
+ SDL_AudioSpec desired;
+ SDL_AudioSpec obtained;
// Determine the desired output sampling frequency.
uint32 samplesPerSec = 0;
@@ -354,22 +349,6 @@ void OSystem_PSP::setupMixer(void) {
while (samples * 16 > samplesPerSec * 2)
samples >>= 1;
- assert(!_mixer);
-
-#ifdef USE_PSP_AUDIO
- if (!_audio.open(samplesPerSec, 2, samples, mixCallback, this)) {
- PSP_ERROR("failed to open audio\n");
- return;
- }
- samplesPerSec = _audio.getFrequency(); // may have been changed by audio system
- _mixer = new Audio::MixerImpl(this, samplesPerSec);
- assert(_mixer);
- _mixer->setReady(true);
- _audio.unpause();
-#else
- SDL_AudioSpec obtained;
- SDL_AudioSpec desired;
-
memset(&desired, 0, sizeof(desired));
desired.freq = samplesPerSec;
desired.format = AUDIO_S16SYS;
@@ -377,7 +356,8 @@ void OSystem_PSP::setupMixer(void) {
desired.samples = samples;
desired.callback = mixCallback;
desired.userdata = this;
-
+
+ assert(!_mixer);
if (SDL_OpenAudio(&desired, &obtained) != 0) {
warning("Could not open audio: %s", SDL_GetError());
_mixer = new Audio::MixerImpl(this, samplesPerSec);
@@ -396,15 +376,10 @@ void OSystem_PSP::setupMixer(void) {
SDL_PauseAudio(0);
}
-#endif /* USE_PSP_AUDIO */
}
void OSystem_PSP::quit() {
-#ifdef USE_PSP_AUDIO
- _audio.close();
-#else
SDL_CloseAudio();
-#endif
SDL_Quit();
sceKernelExitGame();
}
diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h
index 3f075d0139..8c5b40dcdf 100644
--- a/backends/platform/psp/osys_psp.h
+++ b/backends/platform/psp/osys_psp.h
@@ -38,8 +38,6 @@
#include "backends/platform/psp/pspkeyboard.h"
#include "backends/platform/psp/display_manager.h"
#include "backends/platform/psp/input.h"
-#include "backends/platform/psp/audio.h"
-#include "backends/timer/psp/timer.h"
#include <SDL.h>
@@ -57,8 +55,6 @@ private:
DisplayManager _displayManager;
PSPKeyboard _keyboard;
InputHandler _inputHandler;
- PspAudio _audio;
- PspTimer _pspTimer;
void initSDL();
diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec
index ac325b7fd6..debdab3208 100644
--- a/backends/platform/psp/psp.spec
+++ b/backends/platform/psp/psp.spec
@@ -1,3 +1,3 @@
%rename lib old_lib
*lib:
-%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel
+%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspkernel
diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp
index e6940eba13..e568184990 100644
--- a/backends/platform/psp/psp_main.cpp
+++ b/backends/platform/psp/psp_main.cpp
@@ -39,7 +39,6 @@
#include <base/main.h>
#include <base/plugins.h>
#include "backends/platform/psp/powerman.h"
-#include "backends/platform/psp/thread.h"
#include "backends/plugins/psp/psp-provider.h"
#include "backends/platform/psp/psppixelformat.h"
@@ -141,7 +140,7 @@ int CallbackThread(SceSize /*size*/, void *arg) {
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void) {
- int thid = sceKernelCreateThread("power_thread", CallbackThread, PRIORITY_POWER_THREAD, STACK_POWER_THREAD, THREAD_ATTR_USER, 0);
+ int thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, THREAD_ATTR_USER, 0);
if (thid >= 0) {
sceKernelStartThread(thid, 0, 0);
}
diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp
deleted file mode 100644
index 88e7b6fe38..0000000000
--- a/backends/platform/psp/thread.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.h $
- * $Id: osys_psp.h 49173 2010-05-24 03:05:17Z bluddy $
- *
- */
-
-#include <time.h>
-#include <psptypes.h>
-#include <psprtc.h>
-#include <pspthreadman.h>
-
-#include "backends/platform/psp/thread.h"
-
-void PspThread::delayMillis(uint32 ms) {
- sceKernelDelayThread(ms * 1000);
-}
-
-void PspThread::delayMicros(uint32 us) {
- sceKernelDelayThread(us);
-}
-
-uint32 PspThread::getMillis() {
- uint32 ticks[2];
- sceRtcGetCurrentTick((u64 *)ticks);
- return (ticks[0]/1000);
-}
-
-uint32 PspThread::getMicros() {
- uint32 ticks[2];
- sceRtcGetCurrentTick((u64 *)ticks);
- return ticks[0];
-}
-
diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h
deleted file mode 100644
index e83eead68e..0000000000
--- a/backends/platform/psp/thread.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/portdefs.h $
- * $Id: portdefs.h 38687 2009-02-21 12:08:52Z joostp $
- *
- */
-
-#ifndef PSP_THREAD_H
-#define PSP_THREAD_H
-
-#include "common/scummsys.h"
-
-class PspThread {
-public:
- static void delayMillis(uint32 ms);
- static void delayMicros(uint32 us);
- static uint32 getMillis();
- static uint32 getMicros();
-};
-
-enum ThreadPriority {
- PRIORITY_MAIN_THREAD = 36,
- PRIORITY_TIMER_THREAD = 30,
- PRIORITY_AUDIO_THREAD = 25, // must be higher than timer or we get stuttering
- PRIORITY_POWER_THREAD = 20, // quite a light thread
- PRIORITY_DISPLAY_THREAD = 17 // very light thread for callbacks only
-};
-
-enum StackSizes {
- STACK_AUDIO_THREAD = 16 * 1024,
- STACK_TIMER_THREAD = 32 * 1024,
- STACK_DISPLAY_THREAD = 2 * 1024,
- STACK_POWER_THREAD = 4 * 1024
-};
-
-#endif /* PSP_THREADS_H */
-
-
diff --git a/backends/platform/samsungtv/main.cpp b/backends/platform/samsungtv/main.cpp
index 2c025b750c..a6b8376912 100644
--- a/backends/platform/samsungtv/main.cpp
+++ b/backends/platform/samsungtv/main.cpp
@@ -43,7 +43,7 @@ extern "C" int Game_Main(char *path, char *) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(0, 0);
- ((OSystem_SDL *)g_system)->deinit();
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp
index 82670cfcb7..9d0d872c3d 100644
--- a/backends/platform/sdl/graphics.cpp
+++ b/backends/platform/sdl/graphics.cpp
@@ -1673,6 +1673,7 @@ void OSystem_SDL::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
dst.x = _mouseCurState.x;
@@ -1680,12 +1681,16 @@ void OSystem_SDL::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/sdl/main.cpp b/backends/platform/sdl/main.cpp
index 13e614a4a2..b38b815438 100644
--- a/backends/platform/sdl/main.cpp
+++ b/backends/platform/sdl/main.cpp
@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
- ((OSystem_SDL *)g_system)->deinit();
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index f8ae824acf..e54d70e8b2 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -482,7 +482,7 @@ bool OSystem_SDL::getFeatureState(Feature f) {
}
}
-void OSystem_SDL::deinit() {
+void OSystem_SDL::quit() {
if (_cdrom) {
SDL_CDStop(_cdrom);
SDL_CDClose(_cdrom);
@@ -504,14 +504,10 @@ void OSystem_SDL::deinit() {
SDL_Quit();
- // Event Manager requires save manager for storing
+ // Even Manager requires save manager for storing
// recorded events
delete getEventManager();
delete _savefile;
-}
-
-void OSystem_SDL::quit() {
- deinit();
#if !defined(SAMSUNGTV)
exit(0);
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 341a59c8cf..b6baa52391 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -202,8 +202,6 @@ public:
// Quit
virtual void quit(); // overloaded by CE backend
- void deinit();
-
virtual void getTimeAndDate(TimeDate &t) const;
virtual Common::TimerManager *getTimerManager();
diff --git a/backends/plugins/ps2/ps2-provider.cpp b/backends/plugins/ps2/ps2-provider.cpp
new file mode 100644
index 0000000000..3e966bbd08
--- /dev/null
+++ b/backends/plugins/ps2/ps2-provider.cpp
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
+
+#include "backends/plugins/ps2/ps2-provider.h"
+#include "backends/plugins/dynamic-plugin.h"
+#include "common/fs.h"
+
+#include "backends/platform/ps2/ps2loader.h"
+
+
+class PS2Plugin : public DynamicPlugin {
+protected:
+ void *_dlHandle;
+ Common::String _filename;
+
+ virtual VoidFunc findSymbol(const char *symbol) {
+ void *func = dlsym(_dlHandle, symbol);
+ if (!func)
+ warning("Failed loading symbol '%s' from plugin '%s' (%s)", symbol, _filename.c_str(), dlerror());
+
+ // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
+ // standard and POSIX: ISO C++ disallows casting between function pointers
+ // and data pointers, but dlsym always returns a void pointer. For details,
+ // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
+ assert(sizeof(VoidFunc) == sizeof(func));
+ VoidFunc tmp;
+ memcpy(&tmp, &func, sizeof(VoidFunc));
+ return tmp;
+ }
+
+public:
+ PS2Plugin(const Common::String &filename)
+ : _dlHandle(0), _filename(filename) {}
+
+ ~PS2Plugin() {
+ if (_dlHandle) unloadPlugin();
+ }
+
+ bool loadPlugin() {
+ assert(!_dlHandle);
+ _dlHandle = dlopen(_filename.c_str(), RTLD_LAZY);
+
+ if (!_dlHandle) {
+ warning("Failed loading plugin '%s' (%s)", _filename.c_str(), dlerror());
+ return false;
+ }
+
+ bool ret = DynamicPlugin::loadPlugin();
+
+ if (ret)
+ dlforgetsyms(_dlHandle);
+
+ return ret;
+ }
+
+ void unloadPlugin() {
+ DynamicPlugin::unloadPlugin();
+ if (_dlHandle) {
+ if (dlclose(_dlHandle) != 0)
+ warning("Failed unloading plugin '%s' (%s)", _filename.c_str(), dlerror());
+ _dlHandle = 0;
+ }
+ }
+};
+
+
+Plugin* PS2PluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new PS2Plugin(node.getPath());
+}
+
+bool PS2PluginProvider::isPluginFilename(const Common::FSNode &node) const {
+ // Check the plugin suffix
+ Common::String filename = node.getName();
+ fprintf(stderr, "Testing name %s", filename.c_str());
+ if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg")) {
+ fprintf(stderr," fail.\n");
+ return false;
+ }
+
+ fprintf(stderr," success!\n");
+ return true;
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
diff --git a/engines/sci/graphics/maciconbar.h b/backends/plugins/ps2/ps2-provider.h
index 71e65fcb40..6a357db63d 100644
--- a/engines/sci/graphics/maciconbar.h
+++ b/backends/plugins/ps2/ps2-provider.h
@@ -23,33 +23,21 @@
*
*/
-#ifndef SCI_GRAPHICS_MACICONBAR_H
-#define SCI_GRAPHICS_MACICONBAR_H
+#ifndef BACKENDS_PLUGINS_PS2_PS2_PROVIDER_H
+#define BACKENDS_PLUGINS_PS2_PS2_PROVIDER_H
-#include "common/array.h"
+#include "base/plugins.h"
-#include "sci/engine/vm.h"
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
-namespace Graphics {
- struct Surface;
-}
+class PS2PluginProvider : public FilePluginProvider {
+protected:
+ Plugin* createPlugin(const Common::FSNode &node) const;
-namespace Sci {
+ bool isPluginFilename(const Common::FSNode &node) const;
-class GfxMacIconBar {
-public:
- GfxMacIconBar() {}
- ~GfxMacIconBar() {}
-
- void addIcon(reg_t obj);
- void drawIcons();
-
-private:
- Common::Array<reg_t> _iconBarObjects;
-
- void remapColors(Graphics::Surface *surf, byte *palette);
};
-} // End of namespace Sci
+#endif // defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
-#endif
+#endif /* BACKENDS_PLUGINS_PS2_PS2_PROVIDER_H */
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 1ab898d2d6..6a91f2cbe1 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -131,11 +131,11 @@ bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
// There is a nicely portable workaround, too: Make this method overloadable.
if (remove(file.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
- if (errno == EACCES)
+ /* if (errno == EACCES)
setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());
if (errno == ENOENT)
- setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
+ setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid"); */
#endif
return false;
} else {
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 207ff79c4c..8fa2f54b03 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -602,9 +602,7 @@ static void listTargets() {
}
/** List all saves states for the given target. */
-static Common::Error listSaves(const char *target) {
- Common::Error result = Common::kNoError;
-
+static void listSaves(const char *target) {
// FIXME HACK
g_system->initBackend();
@@ -629,14 +627,13 @@ static Common::Error listSaves(const char *target) {
GameDescriptor game = EngineMan.findGame(gameid, &plugin);
if (!plugin) {
- warning("Could not find any plugin to handle target '%s' (gameid '%s')", target, gameid.c_str());
- return Common::kPluginNotFound;
+ error("Could not find any plugin to handle target '%s' (gameid '%s')", target, gameid.c_str());
+ return;
}
if (!(*plugin)->hasFeature(MetaEngine::kSupportsListSaves)) {
// TODO: Include more info about the target (desc, engine name, ...) ???
printf("ScummVM does not support listing save states for target '%s' (gameid '%s') .\n", target, gameid.c_str());
- result = Common::kPluginNotSupportSaves;
} else {
// Query the plugin for a list of savegames
SaveStateList saveList = (*plugin)->listSaves(target);
@@ -646,9 +643,6 @@ static Common::Error listSaves(const char *target) {
printf(" Slot Description \n"
" ---- ------------------------------------------------------\n");
- if (saveList.size() == 0)
- result = Common::kNoSavesError;
-
for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
printf(" %-4s %s\n", x->save_slot().c_str(), x->description().c_str());
// TODO: Could also iterate over the full hashmap, printing all key-value pairs
@@ -657,8 +651,6 @@ static Common::Error listSaves(const char *target) {
// Revert to the old active domain
ConfMan.setActiveDomain(oldDomain);
-
- return result;
}
/** Lists all usable themes */
@@ -871,7 +863,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
#endif // DISABLE_COMMAND_LINE
-Common::Error processSettings(Common::String &command, Common::StringMap &settings) {
+bool processSettings(Common::String &command, Common::StringMap &settings) {
#ifndef DISABLE_COMMAND_LINE
@@ -880,33 +872,34 @@ Common::Error processSettings(Common::String &command, Common::StringMap &settin
// have been loaded.
if (command == "list-targets") {
listTargets();
- return Common::kNoError;
+ return false;
} else if (command == "list-games") {
listGames();
- return Common::kNoError;
+ return false;
} else if (command == "list-saves") {
- return listSaves(settings["list-saves"].c_str());
+ listSaves(settings["list-saves"].c_str());
+ return false;
} else if (command == "list-themes") {
listThemes();
- return Common::kNoError;
+ return false;
} else if (command == "version") {
printf("%s\n", gScummVMFullVersion);
printf("Features compiled in: %s\n", gScummVMFeatures);
- return Common::kNoError;
+ return false;
} else if (command == "help") {
printf(HELP_STRING, s_appName);
- return Common::kNoError;
+ return false;
}
#ifdef DETECTOR_TESTING_HACK
else if (command == "test-detector") {
runDetectorTest();
- return Common::kNoError;
+ return false;
}
#endif
#ifdef UPGRADE_ALL_TARGETS_HACK
else if (command == "upgrade-targets") {
upgradeTargets();
- return Common::kNoError;
+ return false;
}
#endif
@@ -978,7 +971,7 @@ Common::Error processSettings(Common::String &command, Common::StringMap &settin
ConfMan.set(key, value, Common::ConfigManager::kTransientDomain);
}
- return Common::kArgumentNotProcessed;
+ return true;
}
} // End of namespace Base
diff --git a/base/commandLine.h b/base/commandLine.h
index c7e8d8b0d0..8801ed17d8 100644
--- a/base/commandLine.h
+++ b/base/commandLine.h
@@ -33,7 +33,7 @@ namespace Base {
void registerDefaults();
Common::String parseCommandLine(Common::StringMap &settings, int argc, const char * const *argv);
-Common::Error processSettings(Common::String &command, Common::StringMap &settings);
+bool processSettings(Common::String &command, Common::StringMap &settings);
} // End of namespace Base
diff --git a/base/main.cpp b/base/main.cpp
index bfb6611a91..2658d1dc67 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -340,10 +340,8 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
// Process the remaining command line settings. Must be done after the
// config file and the plugins have been loaded.
- Common::Error res;
-
- if ((res = Base::processSettings(command, settings)) != Common::kArgumentNotProcessed)
- return res;
+ if (!Base::processSettings(command, settings))
+ return 0;
// Init the backend. Must take place after all config data (including
// the command line params) was read.
diff --git a/common/error.h b/common/error.h
index 7aff8d40b9..c4d383e508 100644
--- a/common/error.h
+++ b/common/error.h
@@ -59,16 +59,10 @@ enum Error {
kPathNotDirectory, ///< The specified path does not point to a directory
kPathNotFile, ///< The specified path does not point to a file
- kCreatingFileFailed, ///< Failed creating a (savestate) file
- kReadingFailed, ///< Failed to read a file (permission denied?)
+ kCreatingFileFailed,
+ kReadingFailed, ///< Failed creating a (savestate) file
kWritingFailed, ///< Failure to write data -- disk full?
- // The following are used by --list-saves
- kPluginNotFound, ///< Failed to find plugin to handle tager
- kPluginNotSupportSaves, ///< Failed if plugin does not support saves
- kNoSavesError, ///< There are no saves to show
-
- kArgumentNotProcessed, ///< Used in command line parsing
kUnknownError ///< Catch-all error, used if no other error code matches
};
diff --git a/common/macresman.cpp b/common/macresman.cpp
index 6a6a818083..de78cedf61 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -439,11 +439,6 @@ Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 res
_stream->seek(_dataOffset + _resLists[typeNum][resNum].dataOffset);
uint32 len = _stream->readUint32BE();
-
- // Ignore resources with 0 length
- if (!len)
- return 0;
-
return _stream->readStream(len);
}
@@ -453,11 +448,6 @@ Common::SeekableReadStream *MacResManager::getResource(const Common::String &fil
if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) {
_stream->seek(_dataOffset + _resLists[i][j].dataOffset);
uint32 len = _stream->readUint32BE();
-
- // Ignore resources with 0 length
- if (!len)
- return 0;
-
return _stream->readStream(len);
}
}
diff --git a/common/str.h b/common/str.h
index 189c37adb4..12e2b0d2d3 100644
--- a/common/str.h
+++ b/common/str.h
@@ -222,12 +222,6 @@ public:
typedef const char * const_iterator;
iterator begin() {
- // Since the user could potentially
- // change the string via the returned
- // iterator we have to assure we are
- // pointing to a unique storage.
- makeUnique();
-
return _str;
}
diff --git a/common/stream.h b/common/stream.h
index 11041fa3ce..b6afcd85a9 100644
--- a/common/stream.h
+++ b/common/stream.h
@@ -156,7 +156,7 @@ public:
class ReadStream : virtual public Stream {
public:
/**
- * Returns true if a read failed because the stream end has been reached.
+ * Returns true if a read failed because the stream has been reached.
* This flag is cleared by clearErr().
* For a SeekableReadStream, it is also cleared by a successful seek.
*/
diff --git a/common/unzip.cpp b/common/unzip.cpp
index e46106025e..a83f70d671 100644
--- a/common/unzip.cpp
+++ b/common/unzip.cpp
@@ -1433,11 +1433,11 @@ Common::SeekableReadStream *ZipArchive::createReadStreamForMember(const Common::
unz_file_info fileInfo;
unzOpenCurrentFile(_zipFile);
unzGetCurrentFileInfo(_zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- byte *buffer = (byte *)malloc(fileInfo.uncompressed_size);
+ byte *buffer = (byte *)calloc(fileInfo.uncompressed_size+1, 1);
assert(buffer);
unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size);
unzCloseCurrentFile(_zipFile);
- return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size, DisposeAfterUse::YES);
+ return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size+1, DisposeAfterUse::YES);
// FIXME: instead of reading all into a memory stream, we could
// instead create a new ZipStream class. But then we have to be
diff --git a/configure b/configure
index 17da22fb8f..2edcd1798b 100755
--- a/configure
+++ b/configure
@@ -1506,10 +1506,6 @@ if test -n "$_host"; then
_ar="$_host-ar cru"
_ranlib=$_host-ranlib
;;
- mips-sgi*)
- _endian=big
- _need_memalign=yes
- ;;
motoezx)
DEFINES="$DEFINES -DUNIX -DMOTOEZX"
ASFLAGS="$ASFLAGS -mfpu=vfp"
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
index 954bc81470..73ba591b4b 100644
--- a/engines/dialogs.cpp
+++ b/engines/dialogs.cpp
@@ -35,9 +35,8 @@
#include "gui/GuiManager.h"
#include "gui/launcher.h"
#include "gui/ListWidget.h"
-#include "gui/options.h"
-#include "gui/saveload.h"
#include "gui/ThemeEval.h"
+#include "gui/saveload.h"
#include "engines/dialogs.h"
#include "engines/engine.h"
@@ -50,17 +49,16 @@
using GUI::CommandSender;
using GUI::StaticTextWidget;
-class ConfigDialog : public GUI::OptionsDialog {
-protected:
-#ifdef SMALL_SCREEN_DEVICE
- GUI::Dialog *_keysDialog;
-#endif
-
-public:
- ConfigDialog(bool subtitleControls);
- ~ConfigDialog();
-
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+enum {
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kPlayCmd = 'PLAY',
+ kOptionsCmd = 'OPTN',
+ kHelpCmd = 'HELP',
+ kAboutCmd = 'ABOU',
+ kQuitCmd = 'QUIT',
+ kRTLCmd = 'RTL ',
+ kChooseCmd = 'CHOS'
};
MainMenuDialog::MainMenuDialog(Engine *engine)
@@ -97,12 +95,6 @@ MainMenuDialog::MainMenuDialog(Engine *engine)
new GUI::ButtonWidget(this, "GlobalMenu.Options", "Options", kOptionsCmd, 'O');
- // The help button is disabled by default.
- // To enable "Help", an engine needs to use a subclass of MainMenuDialog
- // (at least for now, we might change how this works in the future).
- _helpButton = new GUI::ButtonWidget(this, "GlobalMenu.Help", "Help", kHelpCmd, 'H');
- _helpButton->setEnabled(false);
-
new GUI::ButtonWidget(this, "GlobalMenu.About", "About", kAboutCmd, 'A');
_rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", "Return to Launcher", kRTLCmd, 'R');
@@ -143,9 +135,6 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
case kAboutCmd:
_aboutDialog->runModal();
break;
- case kHelpCmd:
- // Not handled here -- needs to be handled by a subclass (for now)
- break;
case kRTLCmd: {
Common::Event eventRTL;
eventRTL.type = Common::EVENT_RTL;
@@ -274,13 +263,13 @@ enum {
// "" as value for the domain, and in fact provide a somewhat better user
// experience at the same time.
ConfigDialog::ConfigDialog(bool subtitleControls)
- : GUI::OptionsDialog("", "GlobalConfig") {
+ : GUI::OptionsDialog("", "ScummConfig") {
//
// Sound controllers
//
- addVolumeControls(this, "GlobalConfig.");
+ addVolumeControls(this, "ScummConfig.");
setVolumeSettingsState(true); // could disable controls by GUI options
//
@@ -289,7 +278,7 @@ ConfigDialog::ConfigDialog(bool subtitleControls)
if (subtitleControls) {
// Global talkspeed range of 0-255
- addSubtitleControls(this, "GlobalConfig.", 255);
+ addSubtitleControls(this, "ScummConfig.", 255);
setSubtitleSettingsState(true); // could disable controls by GUI options
}
@@ -297,11 +286,11 @@ ConfigDialog::ConfigDialog(bool subtitleControls)
// Add the buttons
//
- new GUI::ButtonWidget(this, "GlobalConfig.Ok", "OK", GUI::kOKCmd, 'O');
- new GUI::ButtonWidget(this, "GlobalConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
+ new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
#ifdef SMALL_SCREEN_DEVICE
- new GUI::ButtonWidget(this, "GlobalConfig.Keys", "Keys", kKeysCmd, 'K');
+ new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
_keysDialog = NULL;
#endif
}
diff --git a/engines/dialogs.h b/engines/dialogs.h
index 6e5338b317..6bee7c5fb1 100644
--- a/engines/dialogs.h
+++ b/engines/dialogs.h
@@ -27,6 +27,7 @@
#include "common/str.h"
#include "gui/dialog.h"
+#include "gui/options.h"
class Engine;
@@ -38,19 +39,6 @@ namespace GUI {
class MainMenuDialog : public GUI::Dialog {
public:
- enum {
- kSaveCmd = 'SAVE',
- kLoadCmd = 'LOAD',
- kPlayCmd = 'PLAY',
- kOptionsCmd = 'OPTN',
- kHelpCmd = 'HELP',
- kAboutCmd = 'ABOU',
- kQuitCmd = 'QUIT',
- kRTLCmd = 'RTL ',
- kChooseCmd = 'CHOS'
- };
-
-public:
MainMenuDialog(Engine *engine);
~MainMenuDialog();
@@ -63,20 +51,29 @@ protected:
void load();
protected:
- Engine *_engine;
+ Engine *_engine;
- GUI::GraphicsWidget *_logo;
+ GUI::GraphicsWidget *_logo;
+ GUI::ButtonWidget *_rtlButton;
+ GUI::ButtonWidget *_loadButton;
+ GUI::ButtonWidget *_saveButton;
+ GUI::Dialog *_aboutDialog;
+ GUI::Dialog *_optionsDialog;
+ GUI::SaveLoadChooser *_loadDialog;
+ GUI::SaveLoadChooser *_saveDialog;
+};
- GUI::ButtonWidget *_rtlButton;
- GUI::ButtonWidget *_loadButton;
- GUI::ButtonWidget *_saveButton;
- GUI::ButtonWidget *_helpButton;
+class ConfigDialog : public GUI::OptionsDialog {
+protected:
+#ifdef SMALL_SCREEN_DEVICE
+ GUI::Dialog *_keysDialog;
+#endif
- GUI::Dialog *_aboutDialog;
- GUI::Dialog *_optionsDialog;
+public:
+ ConfigDialog(bool subtitleControls);
+ ~ConfigDialog();
- GUI::SaveLoadChooser *_loadDialog;
- GUI::SaveLoadChooser *_saveDialog;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
};
#endif
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index e4bd844d75..4a0b82d746 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -1602,7 +1602,7 @@ void DrasculaEngine::animation_9_6() {
// We set the room number to -1 for the same purpose.
// Also check animation_2_1(), where the same hack was used
// by the original
- roomNumber = -2;
+ roomNumber = -1;
loadPic("nota2.alg", bgSurface, HALF_PAL);
black();
trackProtagonist = 1;
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 2c3ca63600..276554a24c 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -87,7 +87,6 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
_textverbs = 0;
_textmisc = 0;
_textd1 = 0;
- _talkSequences = 0;
_color = 0;
blinking = 0;
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index 13c8a742ca..c4dc3df1f6 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -89,8 +89,7 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) {
updateRoom();
updateScreen();
- // roomNumber -2 is end credits. Do not show cursor there
- if (cursorVisible && roomNumber != -2)
+ if (cursorVisible)
showCursor();
}
diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp
index 55566aad7e..fe46e121f0 100644
--- a/engines/m4/animation.cpp
+++ b/engines/m4/animation.cpp
@@ -26,448 +26,181 @@
#include "m4/assets.h"
#include "m4/animation.h"
#include "m4/compression.h"
-#include "m4/mads_scene.h"
namespace M4 {
// TODO: this code needs cleanup
-MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) {
- _font = NULL;
- _freeFlag = false;
- _skipLoad = false;
- _unkIndex = -1;
- _messageCtr= 0;
+Animation::Animation(MadsM4Engine *vm) {
+ _vm = vm;
+ _playing = false;
}
-MadsAnimation::~MadsAnimation() {
- for (uint i = 0; i < _messages.size(); ++i) {
- if (_messages[i].kernelMsgIndex >= 0)
- _view->_kernelMessages.remove(_messages[i].kernelMsgIndex);
- }
-
- // Further deletion logic
- if (_field12) {
- _view->_spriteSlots.deleteSprites(_spriteListIndexes[_spriteListIndex]);
- }
-
- delete _font;
+void Animation::loadFullScreen(const char *filename) {
+ _vm->_palette->deleteAllRanges();
+ load(filename);
}
-/**
- * Initialises and loads the data of an animation
- */
-void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface) {
- MadsPack anim(filename.c_str(), _vm);
- bool madsRes = filename[0] == '*';
+void Animation::load(const char *filename) {
+ MadsPack anim(filename, _vm);
char buffer[20];
- int streamIndex = 1;
// Chunk 1: header
// header
-
+ // TODO: there are some unknown fields here, plus we don't read
+ // the entire chunk
Common::SeekableReadStream *animStream = anim.getItemStream(0);
+ Common::SeekableReadStream *spriteSeriesStream;
+ //printf("Chunk 0, size %i\n", animStream->size());
+ _seriesCount = animStream->readUint16LE();
+ _frameCount = animStream->readUint16LE();
+ _frameEntryCount = animStream->readUint16LE();
- int spriteListCount = animStream->readUint16LE();
- int miscEntriesCount = animStream->readUint16LE();
- int frameEntryCount = animStream->readUint16LE();
- int messagesCount = animStream->readUint16LE();
- animStream->skip(1);
- _flags = animStream->readByte();
-
- animStream->skip(2);
- _animMode = animStream->readUint16LE();
- _roomNumber = animStream->readUint16LE();
- animStream->skip(2);
- _field12 = animStream->readUint16LE() != 0;
- _spriteListIndex = animStream->readUint16LE();
- _scrollX = animStream->readUint16LE();
- _scrollY = animStream->readSint16LE();
- animStream->skip(10);
-
- animStream->read(buffer, 13);
- _interfaceFile = Common::String(buffer, 13);
-
- for (int i = 0; i < 10; ++i) {
- animStream->read(buffer, 13);
- _spriteSetNames[i] = Common::String(buffer, 13);
- }
-
- animStream->skip(81);
- animStream->read(buffer, 13);
- _lbmFilename = Common::String(buffer, 13);
- animStream->read(buffer, 13);
- _spritesFilename = Common::String(buffer, 13);
- animStream->skip(48);
- animStream->read(buffer, 13);
- _soundName = Common::String(buffer, 13);
- animStream->skip(26);
- animStream->read(buffer, 13);
- Common::String fontResource(buffer, 13);
-
- if (_animMode == 4)
- flags |= 0x4000;
- if (flags & 0x100)
- loadInterface(interfaceSurface, sceneSurface);
-
- // Initialise the reference list
- for (int i = 0; i < spriteListCount; ++i)
- _spriteListIndexes.push_back(-1);
-
- delete animStream;
-
- if (messagesCount > 0) {
- // Chunk 2
- // Following is a list of any messages for the animation
-
- animStream = anim.getItemStream(streamIndex++);
-
- for (int i = 0; i < messagesCount; ++i) {
- AnimMessage rec;
- animStream->read(rec.msg, 70);
- rec.pos.x = animStream->readUint16LE();
- rec.pos.y = animStream->readUint16LE();
- animStream->readUint16LE();
- rec.rgb1.r = animStream->readByte();
- rec.rgb1.g = animStream->readByte();
- rec.rgb1.b = animStream->readByte();
- rec.rgb2.r = animStream->readByte();
- rec.rgb2.g = animStream->readByte();
- rec.rgb2.b = animStream->readByte();
- rec.kernelMsgIndex = animStream->readUint16LE();
- animStream->skip(6);
- rec.startFrame = animStream->readUint16LE();
- rec.endFrame = animStream->readUint16LE();
- animStream->readUint16LE();
-
- _messages.push_back(rec);
- }
-
- delete animStream;
- }
-
- if (frameEntryCount > 0) {
- // Chunk 3: animation frame info
- animStream = anim.getItemStream(streamIndex++);
-
- for (int i = 0; i < frameEntryCount; i++) {
- AnimFrameEntry rec;
- rec.frameNumber = animStream->readUint16LE();
- rec.seqIndex = animStream->readByte();
- rec.spriteSlot.spriteListIndex = animStream->readByte();
- rec.spriteSlot.frameNumber = animStream->readUint16LE();
- rec.spriteSlot.xp = animStream->readUint16LE();
- rec.spriteSlot.yp = animStream->readUint16LE();
- rec.spriteSlot.depth = animStream->readByte();
- rec.spriteSlot.scale = animStream->readByte();
-
- _frameEntries.push_back(rec);
- }
-
- delete animStream;
- }
+ // Unknown
+ for (int i = 0; i < 43; i++)
+ animStream->readByte();
- if (miscEntriesCount > 0) {
- // Chunk 4: Misc Data
- animStream = anim.getItemStream(streamIndex);
+ _spriteSeriesNames = new Common::String[_seriesCount];
+ printf("%i sprite series\n", _seriesCount);
- for (int i = 0; i < miscEntriesCount; ++i) {
- AnimMiscEntry rec;
- rec.soundNum = animStream->readByte();
- animStream->skip(1);
- rec.numTicks = animStream->readUint16LE();
- rec.posAdjust.x = animStream->readUint16LE();
- rec.posAdjust.y = animStream->readUint16LE();
- animStream->readUint16LE();
+ // TODO: for now, we only load the first sprite series
+ if (_seriesCount > 1)
+ printf("TODO: Anim has %i sprite series, for now, we only load the first one\n", _seriesCount);
+ _seriesCount = 1; // TODO
- _miscEntries.push_back(rec);
+ for (int i = 0; i < _seriesCount; i++) {
+ animStream->read(buffer, 13);
+ _spriteSeriesNames[i] = Common::String(buffer);
+ //printf("%03d: %s\n", i, _spriteSeriesNames[i].c_str());
+
+ spriteSeriesStream = _vm->res()->get(_spriteSeriesNames[i].c_str());
+ _spriteSeries = new SpriteAsset(_vm, spriteSeriesStream,
+ spriteSeriesStream->size(), _spriteSeriesNames[i].c_str());
+ _vm->res()->toss(_spriteSeriesNames[i].c_str());
+
+ // Adjust the palette of the sprites in the sprite series
+ // so that they can be displayed on screen correctly
+ RGBList *palData = new RGBList(_spriteSeries->getColorCount(), _spriteSeries->getPalette(), true);
+ _vm->_palette->addRange(palData);
+
+ for (int k = 0; k < _spriteSeries->getCount(); k++) {
+ M4Sprite *spr = _spriteSeries->getFrame(k);
+ spr->translate(palData); // sprite pixel translation
}
-
- delete animStream;
}
- // If the animation specifies a font, then load it for access
- if (_flags & ANIM_CUSTOM_FONT) {
- Common::String fontName;
- if (madsRes)
- fontName += "*";
- fontName += fontResource;
-
- _font = _vm->_font->getFont(fontName);
- }
-
- // Load all the sprite sets for the animation
- for (int i = 0; i < spriteListCount; ++i) {
- _spriteListIndexes[i] = _view->_spriteSlots.addSprites(_spriteSetNames[i].c_str());
- }
+ //printf("End pos: %i\n", animStream->pos());
+ delete animStream;
- if (_field12) {
- Common::String resName;
- if (madsRes)
- resName += "*";
- resName += _spriteSetNames[_spriteListIndex];
-
- _spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str());
- }
+ // ------------------
+
+ // Chunk 2: anim info
+ AnimationFrame frame;
+ animStream = anim.getItemStream(1);
+ //printf("Chunk 1, size %i\n", animStream->size());
+
+ _frameEntries = new AnimationFrame[_frameEntryCount];
+
+ for (int i = 0; i < _frameEntryCount; i++) {
+
+ frame.animFrameIndex = animStream->readUint16LE();
+ frame.u = animStream->readByte();
+ frame.seriesIndex = animStream->readByte();
+ frame.seriesFrameIndex = animStream->readUint16LE();
+ frame.x = animStream->readUint16LE();
+ frame.y = animStream->readUint16LE();
+ frame.v = animStream->readByte();
+ frame.w = animStream->readByte();
+
+ _frameEntries[i] = frame;
+
+ /*
+ printf(
+ "animFrameIndex = %4d, "
+ "u = %3d, "
+ "seriesIndex = %3d, "
+ "seriesFrameIndex = %6d, "
+ "x = %3d, "
+ "y = %3d, "
+ "v = %3d, "
+ "w = %3d\n",
+
+ frame.animFrameIndex,
+ frame.u,
+ frame.seriesIndex,
+ frame.seriesFrameIndex,
+ frame.x,
+ frame.y,
+ frame.v,
+ frame.w
+ );
+ */
+ }
+ //printf("End pos: %i\n", animStream->pos());
- // TODO: Unknown section about handling palette entries - I think it's adjusting sprite sets
- // to the palette of the game screen
+ delete animStream;
- // Process the sprite list indexes to remap them to the actual sprite list indexes
-
+ // Chunk 3: unknown (seems to be sound data?)
+ // TODO
}
-/**
- * Loads an animation file for display
- */
-void MadsAnimation::load(const Common::String &filename, int abortTimers) {
- initialise(filename, 0, NULL, NULL);
- _messageCtr = 0;
- _skipLoad = true;
-
- if (_field12) {
- _unkIndex = -1;
- int listIndex = _spriteListIndexes[_spriteListIndex];
- SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex);
-warning("%d", spriteSet.getCount());
- }
-
- // Initialise miscellaneous fields
- _currentFrame = 0;
- _oldFrameEntry = 0;
- _nextFrameTimer = _madsVm->_currentTimer;
- _abortTimers = abortTimers;
- _abortMode = _madsVm->scene()->_abortTimersMode2;
-
- for (int i = 0; i < 3; ++i)
- _actionNouns[i] = _madsVm->scene()->actionNouns[i];
+Animation::~Animation() {
+ //delete[] _spriteSeriesNames;
+ //delete[] _spriteSeries;
+ //delete[] _frameEntries;
+}
- // Initialise kernel message list
- for (uint i = 0; i < _messages.size(); ++i)
- _messages[i].kernelMsgIndex = -1;
+void Animation::start() {
+ _curFrame = 0;
+ _curFrameEntry = 0;
+ //for (int i = 0; i < _seriesCount; i++) {
+ //_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str());
+ //}
+ _playing = true;
+ updateAnim();
}
-void MadsAnimation::update() {
- if (_field12) {
- int spriteListIndex = _spriteListIndexes[_spriteListIndex];
- int newIndex = -1;
-
- for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
- if (_frameEntries[idx].frameNumber > _currentFrame)
- break;
- if (_frameEntries[idx].spriteSlot.spriteListIndex == spriteListIndex)
- newIndex = _frameEntries[idx].spriteSlot.frameNumber;
- }
+bool Animation::updateAnim() {
+ if (!_playing)
+ return true;
- if (newIndex >= 0)
- load1(newIndex);
- }
+ // Get the scene background surface
+ M4Surface *bg = _vm->_scene->getBackgroundSurface();
- // If it's not time for the next frame, then exit
- if (_madsVm->_currentTimer < _nextFrameTimer)
- return;
+ while (_frameEntries[_curFrameEntry].animFrameIndex == _curFrame) {
+ AnimationFrame *frame = &_frameEntries[_curFrameEntry];
+ int seriesFrameIndex = (frame->seriesFrameIndex & 0x7FFF) - 1;
- // Loop checks for any prior animation sprite slots to be expired
- for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) {
- if ((_view->_spriteSlots[slotIndex].seqIndex >= 0x80) &&
- (_view->_spriteSlots[slotIndex].seqIndex <= 0xFD)) {
- // Flag the frame as animation sprite slot
- _view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE;
- }
- }
+ // Write the sprite onto the screen
+ M4Sprite *spr = _spriteSeries->getFrame(seriesFrameIndex);
- // Validate the current frame
- if (_currentFrame > (int)_miscEntries.size()) {
- // Is the animation allowed to be repeated?
- if (_resetFlag) {
- _currentFrame = 0;
- _oldFrameEntry = 0;
- } else {
- _freeFlag = true;
- return;
- }
- }
-
- // Handle starting any sound for this frame
- AnimMiscEntry &misc = _miscEntries[_currentFrame];
- if (misc.soundNum)
- _vm->_sound->playSound(misc.soundNum);
+ // FIXME: correct x, y
+ spr->copyTo(bg, frame->x, frame->y, (int)spr->getTransparentColor());
- bool screenChanged = false;
+ // HACK: wait a bit
+ g_system->delayMillis(100);
- // Handle any scrolling of the screen surface
- if ((_scrollX != 0) || (_scrollY != 0)) {
- _view->_bgSurface->scrollX(_scrollX);
- _view->_bgSurface->scrollY(_scrollY);
-
- screenChanged = true;
+ //printf("_curFrameEntry = %d\n", _curFrameEntry);
+ _curFrameEntry++;
}
- // Handle any offset adjustment for sprites as of this frame
- if (_view->_posAdjust.x != misc.posAdjust.x) {
- misc.posAdjust.x = _view->_posAdjust.x;
- screenChanged = true;
- }
- if (_view->_posAdjust.y != misc.posAdjust.y) {
- misc.posAdjust.y = _view->_posAdjust.y;
- screenChanged = true;
- }
- if (screenChanged) {
- // Signal the entire screen needs refreshing
- _view->_spriteSlots.fullRefresh();
- }
+ //printf("_curFrame = %d\n", _curFrame);
- int spriteSlotsMax = _view->_spriteSlots.startIndex;
-
- // Main frame animation loop - frames get animated by being placed, as necessary, into the
- // main sprite slot array
- while ((uint)_oldFrameEntry < _frameEntries.size()) {
- if (_frameEntries[_oldFrameEntry].frameNumber > _currentFrame)
- break;
- else if (_frameEntries[_oldFrameEntry].frameNumber == _currentFrame) {
- // Found the correct frame
- int spriteSlotIndex = 0;
- int index = 0;
-
- for (;;) {
- if ((spriteSlotIndex == 0) && (index < spriteSlotsMax)) {
- int seqIndex = _frameEntries[_oldFrameEntry].seqIndex - _view->_spriteSlots[index].seqIndex;
- if (seqIndex == 0x80) {
- if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot)
- _view->_spriteSlots[index].spriteType = SPRITE_ZERO;
- }
- ++index;
- continue;
- }
-
- if (spriteSlotIndex == 0) {
- int slotIndex = _view->_spriteSlots.getIndex();
- _view->_spriteSlots[slotIndex].copy(_frameEntries[_oldFrameEntry].spriteSlot);
- _view->_spriteSlots[slotIndex].seqIndex += 0x80;
-
- SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(
- _view->_spriteSlots[slotIndex].spriteListIndex);
-
- _view->_spriteSlots[slotIndex].spriteType = (spriteSet.getAssetType() == 0) ?
- SPRITE_FOUR : SPRITE_ZERO;
- }
- break;
- }
- }
-
- ++_oldFrameEntry;
- }
-
- // Handle the display of any messages
- for (uint idx = 0; idx < _messages.size(); ++idx) {
- if (_messages[idx].kernelMsgIndex >= 0) {
- // Handle currently active message
- if ((_currentFrame < _messages[idx].startFrame) || (_currentFrame > _messages[idx].endFrame)) {
- _view->_kernelMessages.remove(_messages[idx].kernelMsgIndex);
- _messages[idx].kernelMsgIndex = -1;
- --_messageCtr;
- }
- } else if ((_currentFrame >= _messages[idx].startFrame) && (_currentFrame <= _messages[idx].endFrame)) {
- // Start displaying the message
- AnimMessage &me = _messages[idx];
-
- // The colour index to use is dependant on how many messages are currently on-screen
- uint8 colIndex;
- switch (_messageCtr) {
- case 1:
- colIndex = 252;
- break;
- case 2:
- colIndex = 16;
- break;
- default:
- colIndex = 250;
- break;
- }
-
- _vm->_palette->setEntry(colIndex, me.rgb1.r, me.rgb1.g, me.rgb1.b);
- _vm->_palette->setEntry(colIndex + 1, me.rgb2.r, me.rgb2.g, me.rgb2.b);
-
- // Add a kernel message to display the given text
- me.kernelMsgIndex = _view->_kernelMessages.add(me.pos, colIndex * 101, 0, 0, INDEFINITE_TIMEOUT, me.msg);
- ++_messageCtr;
- }
- }
-
- // Move to the next frame
- _currentFrame++;
- if (_currentFrame >= (int)_miscEntries.size()) {
- // Animation is complete
- if (_abortTimers != 0) {
- _view->_abortTimers = _abortTimers;
- _view->_abortTimersMode = _abortMode;
-
- if (_abortMode != ABORTMODE_1) {
- // Copy the noun list
- for (int i = 0; i < 3; ++i)
- _madsVm->scene()->actionNouns[i] = _actionNouns[i];
- }
- }
- }
+ _curFrame++;
+ if (_curFrame >= _frameCount) // anim done
+ stop();
- int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
- _nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks;
+ return _curFrame >= _frameCount;
}
-void MadsAnimation::setCurrentFrame(int frameNumber) {
- _currentFrame = frameNumber;
- _oldFrameEntry = 0;
- _freeFlag = false;
-}
-
-void MadsAnimation::load1(int frameNumber) {
- if (_skipLoad)
- return;
-
- Common::Point pt;
- int listIndex = _spriteListIndexes[_spriteListIndex];
- SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex);
-
- if (_unkIndex < 0) {
- M4Surface *frame = spriteSet.getFrame(0);
- pt.x = frame->bounds().left;
- pt.y = frame->bounds().top;
- } else {
- pt.x = _unkList[_unkIndex].x;
- pt.y = _unkList[_unkIndex].y;
- _unkIndex = 1 - _unkIndex;
- }
-
- if (proc1(spriteSet, pt, frameNumber))
- error("proc1 failure");
-}
-
-bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) {
- return 0;
-}
+void Animation::stop() {
+ _playing = false;
-void MadsAnimation::loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface) {
- if (_animMode <= 2) {
- MadsSceneResources sceneResources;
- sceneResources.load(_roomNumber, _interfaceFile.c_str(), 0, depthSurface, interfaceSurface);
-
- // Rex only supports a single dialog draw style
- assert(sceneResources.drawStyle == 2);
-
- } else if (_animMode == 4) {
- // Load a scene interface
- interfaceSurface->madsLoadInterface(_interfaceFile);
- } else {
- // This mode allocates two large surfaces for the animation
- // TODO: Are these ever properly freed?
-error("Anim mode %d - need to check free logic", _animMode);
- assert(!interfaceSurface);
- assert(!depthSurface);
- depthSurface = new M4Surface(MADS_SURFACE_WIDTH, MADS_SCREEN_HEIGHT);
- interfaceSurface = new M4Surface(MADS_SURFACE_WIDTH, MADS_SCREEN_HEIGHT);
- depthSurface->clear();
- interfaceSurface->clear();
+ for (int i = 0; i < _seriesCount; i++) {
+ // TODO: cleanup
+ //delete _spriteSeries[i];
+ //_spriteSeries[i] = NULL;
}
}
diff --git a/engines/m4/animation.h b/engines/m4/animation.h
index 883d3f2de6..2dfe0d887e 100644
--- a/engines/m4/animation.h
+++ b/engines/m4/animation.h
@@ -29,89 +29,39 @@
#include "m4/m4.h"
#include "m4/graphics.h"
#include "m4/assets.h"
-#include "m4/mads_views.h"
-#include "common/array.h"
namespace M4 {
-class MadsView;
-class SpriteSlotSubset;
-
-class AnimMessage {
-public:
- char msg[70];
- Common::Point pos;
- RGB8 rgb1, rgb2;
- int kernelMsgIndex;
-
- int startFrame, endFrame;
-};
-
-class AnimFrameEntry {
-public:
- int frameNumber;
- int seqIndex;
- SpriteSlotSubset spriteSlot;
+struct AnimationFrame {
+ uint16 animFrameIndex;
+ byte u;
+ byte seriesIndex;
+ uint16 seriesFrameIndex;
+ uint16 x, y;
+ byte v, w;
};
-class AnimMiscEntry {
-public:
- int soundNum;
- int numTicks;
- Common::Point posAdjust;
-};
-
-#define ANIM_SPRITE_SET_SIZE 50
-
-enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20};
-
-class MadsAnimation: public Animation {
-private:
- MadsView *_view;
-
- int _spriteListCount;
- Common::Array<AnimMessage> _messages;
- Common::Array<AnimFrameEntry> _frameEntries;
- Common::Array<AnimMiscEntry> _miscEntries;
- Font *_font;
-
- uint8 _flags;
- int _animMode;
- int _roomNumber;
- bool _field12;
- int _spriteListIndex;
- int _scrollX;
- int _scrollY;
- Common::String _interfaceFile;
- Common::String _spriteSetNames[10];
- Common::String _lbmFilename;
- Common::String _spritesFilename;
- Common::String _soundName;
- Common::Array<int> _spriteListIndexes;
-
- int _currentFrame, _oldFrameEntry;
- bool _resetFlag;
- bool _freeFlag;
- bool _skipLoad;
- int _unkIndex;
- Common::Point _unkList[2];
- uint32 _nextFrameTimer;
- int _messageCtr;
- int _abortTimers;
- AbortTimerMode _abortMode;
- uint16 _actionNouns[3];
-
- void load1(int frameNumber);
- bool proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber);
- void loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface);
-public:
- MadsAnimation(MadsM4Engine *vm, MadsView *view);
- virtual ~MadsAnimation();
-
- virtual void initialise(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface);
- virtual void load(const Common::String &filename, int abortTimers);
- virtual void update();
- virtual void setCurrentFrame(int frameNumber);
+class Animation {
+ public:
+ Animation(MadsM4Engine *vm);
+ ~Animation();
+
+ void load(const char *filename);
+ void loadFullScreen(const char *filename);
+ void start();
+ bool updateAnim();
+ void stop();
+
+ private:
+ bool _playing;
+ MadsM4Engine *_vm;
+ int _seriesCount;
+ int _frameCount;
+ int _frameEntryCount;
+ AnimationFrame *_frameEntries;
+ Common::String *_spriteSeriesNames;
+ SpriteAsset *_spriteSeries;
+ int _curFrame, _curFrameEntry;
bool freeFlag() const { return _freeFlag; }
};
diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp
index 91c371dec5..e604019901 100644
--- a/engines/m4/assets.cpp
+++ b/engines/m4/assets.cpp
@@ -30,13 +30,13 @@
namespace M4 {
-BaseAsset::BaseAsset(MadsM4Engine *vm) : _vm(vm) {
+BaseAsset::BaseAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : _vm(vm) {
}
BaseAsset::~BaseAsset() {
}
-MachineAsset::MachineAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
+MachineAsset::MachineAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
uint32 stateCount = stream->readUint32LE();
for (uint32 curState = 0; curState < stateCount; curState++) {
uint32 stateOffset = stream->readUint32LE();
@@ -61,7 +61,7 @@ uint32 MachineAsset::getStateOffset(uint32 state) {
return _stateTable[state];
}
-SequenceAsset::SequenceAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
+SequenceAsset::SequenceAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
_localVarCount = stream->readUint32LE();
_codeSize = size - 4;
_code = new byte[_codeSize];
@@ -78,7 +78,7 @@ void SequenceAsset::getCode(byte *&code, uint32 &codeSize) {
}
-DataAsset::DataAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
+DataAsset::DataAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
_recCount = stream->readUint32LE();
_recSize = stream->readUint32LE();
@@ -98,8 +98,7 @@ long *DataAsset::getRow(int index) {
return &_data[_recSize * index];
}
-SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) :
- BaseAsset(vm) {
+SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) : BaseAsset(vm, stream, size, name) {
_stream = stream;
_palInterface = NULL;
_paletteData = NULL;
@@ -111,20 +110,6 @@ SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, i
}
}
-SpriteAsset::SpriteAsset(MadsM4Engine *vm, const char *name): BaseAsset(vm) {
- _stream = vm->res()->get(name);
- _palInterface = NULL;
- _paletteData = NULL;
-
- if (_vm->isM4()) {
- loadM4SpriteAsset(vm, _stream, true);
- } else {
- loadMadsSpriteAsset(vm, _stream);
- }
-
- vm->res()->toss(name);
-}
-
SpriteAsset::~SpriteAsset() {
if (_palInterface) {
// Internally stored palette translation data, so release it
@@ -210,9 +195,7 @@ void SpriteAsset::loadMadsSpriteAsset(MadsM4Engine *vm, Common::SeekableReadStre
_maxHeight = 0;
Common::SeekableReadStream *spriteStream = sprite.getItemStream(0);
-
- _assetType = spriteStream->readUint16LE();
- for (int i = 0; i < 18; i++) {
+ for (int i = 0; i < 19; i++) {
spriteStream->readUint16LE();
}
_frameCount = spriteStream->readUint16LE();
diff --git a/engines/m4/assets.h b/engines/m4/assets.h
index 816a8dcff0..7b0ce24dc4 100644
--- a/engines/m4/assets.h
+++ b/engines/m4/assets.h
@@ -49,7 +49,7 @@ class Palette;
class BaseAsset {
public:
- BaseAsset(MadsM4Engine *vm);
+ BaseAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
~BaseAsset();
const Common::String getName() const { return _name; }
protected:
@@ -103,7 +103,6 @@ struct SpriteAssetFrame {
class SpriteAsset : public BaseAsset {
public:
SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream = false);
- SpriteAsset(MadsM4Engine *vm, const char *name);
~SpriteAsset();
void loadM4SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, bool asStream);
void loadMadsSpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream);
@@ -114,7 +113,6 @@ public:
int32 getFrameHeight(int index);
int32 getMaxFrameWidth() const { return _maxWidth; }
int32 getMaxFrameHeight() const { return _maxHeight; }
- uint16 getAssetType() const { return _assetType; }
M4Sprite *getFrame(int frameIndex);
void loadStreamingFrame(M4Sprite *frame, int frameIndex, int destX, int destY);
RGB8* getPalette() { return _palette; }
@@ -125,7 +123,6 @@ public:
int32 getFrameSize(int index);
M4Sprite *operator[](int index) { return getFrame(index); }
protected:
- Common::SeekableReadStream *_stream;
RGB8 _palette[256];
uint32 _colorCount;
uint32 _srcSize;
@@ -135,10 +132,7 @@ protected:
Common::Array<uint32> _frameOffsets;
Common::Array<SpriteAssetFrame> _frames;
uint32 _frameStartOffset;
-
- // MADS sprite set fields
- uint16 _assetType;
-
+ Common::SeekableReadStream *_stream;
int32 parseSprite(bool isBigEndian = false);
void loadFrameHeader(SpriteAssetFrame &frameHeader, bool isBigEndian = false);
private:
diff --git a/engines/m4/compression.h b/engines/m4/compression.h
index 00e3d1f927..74fed357ff 100644
--- a/engines/m4/compression.h
+++ b/engines/m4/compression.h
@@ -66,8 +66,8 @@ public:
class FabDecompressor {
private:
- int _bitsLeft;
- uint32 _bitBuffer;
+ int _bitsLeft;
+ uint32 _bitBuffer;
const byte *_srcData, *_srcP;
int _srcSize;
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 4e14afdfaf..0c2e80df0e 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -47,6 +47,7 @@ Console::Console(MadsM4Engine *vm) : GUI::Debugger() {
DCmd_Register("start_conv", WRAP_METHOD(Console, cmdStartConversation));
DCmd_Register("textview", WRAP_METHOD(Console, cmdShowTextview));
DCmd_Register("animview", WRAP_METHOD(Console, cmdShowAnimview));
+ DCmd_Register("anim", WRAP_METHOD(Console, cmdPlayAnimation));
}
Console::~Console() {
@@ -246,6 +247,33 @@ bool Console::cmdShowAnimview(int argc, const char **argv) {
return false;
}
+bool Console::cmdPlayAnimation(int argc, const char **argv) {
+ View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+ if (view == NULL) {
+ DebugPrintf("The scene view isn't currently active\n");
+ } else if (argc != 2 && argc != 3) {
+ DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
+ DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
+ } else {
+ char resourceName[20];
+ strncpy(resourceName, argv[1], 15);
+ resourceName[15] = '\0';
+ if (!strchr(resourceName, '.'))
+ strcat(resourceName, ".AA");
+
+ _vm->_viewManager->moveToFront(view);
+ if (argc == 3 && atoi(argv[2]) == 1)
+ _vm->_animation->loadFullScreen(resourceName);
+ else
+ _vm->_animation->load(resourceName);
+ _vm->_animation->start();
+ view->restore(0, 0, view->width(), view->height());
+ return false;
+ }
+
+ return true;
+}
+
/*--------------------------------------------------------------------------*/
MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
@@ -254,7 +282,6 @@ MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
DCmd_Register("object", WRAP_METHOD(MadsConsole, cmdObject));
DCmd_Register("message", WRAP_METHOD(MadsConsole, cmdMessage));
DCmd_Register("scene_info", WRAP_METHOD(MadsConsole, cmdSceneInfo));
- DCmd_Register("anim", WRAP_METHOD(MadsConsole, cmdPlayAnimation));
}
bool MadsConsole::cmdObject(int argc, const char **argv) {
@@ -359,33 +386,6 @@ bool MadsConsole::cmdSceneInfo(int argc, const char **argv) {
return true;
}
-bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) {
- View *view = _vm->_viewManager->getView(VIEWID_SCENE);
- if (view == NULL) {
- DebugPrintf("The scene view isn't currently active\n");
- } else if (argc != 2 && argc != 3) {
- DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
- DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
- } else {
- char resourceName[20];
- strncpy(resourceName, argv[1], 15);
- resourceName[15] = '\0';
- if (!strchr(resourceName, '.'))
- strcat(resourceName, ".AA");
-
- _vm->_viewManager->moveToFront(view);
- if (argc == 3 && atoi(argv[2]) == 1)
- _madsVm->_palette->deleteAllRanges();
-
- _madsVm->scene()->_sceneAnimation->load(resourceName, 0);
-
- view->restore(0, 0, view->width(), view->height());
- return false;
- }
-
- return true;
-}
-
/*--------------------------------------------------------------------------*/
M4Console::M4Console(M4Engine *vm): Console(vm) {
diff --git a/engines/m4/console.h b/engines/m4/console.h
index 53a47dada9..b592f041cf 100644
--- a/engines/m4/console.h
+++ b/engines/m4/console.h
@@ -50,6 +50,7 @@ private:
bool cmdStartConversation(int argc, const char **argv);
bool cmdShowTextview(int argc, const char **argv);
bool cmdShowAnimview(int argc, const char **argv);
+ bool cmdPlayAnimation(int argc, const char **argv);
public:
Console(MadsM4Engine *vm);
@@ -63,8 +64,6 @@ private:
bool cmdObject(int argc, const char **argv);
bool cmdMessage(int argc, const char **argv);
bool cmdSceneInfo(int argc, const char **argv);
- bool cmdPlayAnimation(int argc, const char **argv);
-
public:
MadsConsole(MadsEngine *vm);
virtual ~MadsConsole() {}
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index 11bc165811..746ced5d11 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -96,7 +96,7 @@ void ConversationView::setNode(int32 nodeIndex) {
_vm->_font->setFont(FONT_CONVERSATION);
// TODO: Conversation styles and colors
- _vm->_font->current()->setColours(2, 1, 3);
+ _vm->_font->setColors(2, 1, 3);
_currentNodeIndex = nodeIndex;
@@ -124,7 +124,7 @@ void ConversationView::setNode(int32 nodeIndex) {
}
// Figure out the longest string to determine where option highlighting ends
- int tempX = _vm->_font->current()->getWidth(node->entries[i]->text, 0) +
+ int tempX = _vm->_font->getWidth(node->entries[i]->text, 0) +
CONV_ENTRIES_X_OFFSET + 10;
_xEnd = MAX(_xEnd, tempX);
}
@@ -163,10 +163,10 @@ void ConversationView::onRefresh(RectList *rects, M4Surface *destSurface) {
if (i > CONV_MAX_SHOWN_ENTRIES - 1)
break;
- _vm->_font->current()->setColour((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
+ _vm->_font->setColor((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
CONVERSATION_ENTRY_NORMAL);
- _vm->_font->current()->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
+ _vm->_font->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
CONV_ENTRIES_Y_OFFSET + CONV_ENTRIES_HEIGHT * i, 0, 0);
}
}
diff --git a/engines/m4/dialogs.cpp b/engines/m4/dialogs.cpp
index a7104537f5..3af94af262 100644
--- a/engines/m4/dialogs.cpp
+++ b/engines/m4/dialogs.cpp
@@ -127,7 +127,7 @@ void Dialog::writeChars(const char *srcLine) {
strcat(line, wordStr);
lineLen = strlen(line);
- lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
+ lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
if (((_lineX + lineLen) > _widthChars) || ((_widthX + lineWidth) > _dialogWidth)) {
incLine();
@@ -146,7 +146,7 @@ void Dialog::writeChars(const char *srcLine) {
*/
void Dialog::appendText(const char *line) {
_lineX += strlen(line);
- _widthX += _vm->_font->current()->getWidth(line, DIALOG_SPACING);
+ _widthX += _vm->_font->getWidth(line, DIALOG_SPACING);
strcat(_lines[_lines.size() - 1].data, line);
}
@@ -158,7 +158,7 @@ void Dialog::addLine(const char *line, bool underlineP) {
if ((_widthX > 0) || (_lineX > 0))
incLine();
- int lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
+ int lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
int lineLen = strlen(line);
if ((lineWidth > _dialogWidth) || (lineLen >= _widthChars))
@@ -383,7 +383,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
if (id > 0) {
// Suffix provided - specifies the dialog width in number of chars
_widthChars = id * 2;
- _dialogWidth = id * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = id * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
}
} else if (matchCommand(cmdText, "UNDER")) {
@@ -416,7 +416,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
Dialog::Dialog(MadsM4Engine *vm, int widthChars): View(vm, Common::Rect(0, 0, 0, 0)) {
_vm->_font->setFont(FONT_INTERFACE_MADS);
_widthChars = widthChars * 2;
- _dialogWidth = widthChars * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = widthChars * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
_screenType = LAYER_DIALOG;
_lineX = 0;
_widthX = 0;
@@ -439,7 +439,7 @@ void Dialog::draw() {
// Calculate bounds
int dlgWidth = _dialogWidth;
- int dlgHeight = _lines.size() * (_vm->_font->current()->getHeight() + 1) + 10;
+ int dlgHeight = _lines.size() * (_vm->_font->getHeight() + 1) + 10;
int dialogX = (_vm->_screen->width() - dlgWidth) / 2;
int dialogY = (_vm->_screen->height() - dlgHeight) / 2;
@@ -480,26 +480,26 @@ void Dialog::draw() {
}
// Handle drawing the text contents
- _vm->_font->current()->setColours(7, 7, 7);
+ _vm->_font->setColours(7, 7, 7);
setColour(7);
- for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->current()->getHeight() + 1) {
+ for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->getHeight() + 1) {
if (_lines[lineCtr].barLine) {
// Bar separation line
- hLine(5, width() - 6, ((_vm->_font->current()->getHeight() + 1) >> 1) + yp);
+ hLine(5, width() - 6, ((_vm->_font->getHeight() + 1) >> 1) + yp);
} else {
// Standard line
Common::Point pt(_lines[lineCtr].xp + 5, yp);
if (_lines[lineCtr].xp & 0x40)
++pt.y;
- _vm->_font->current()->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
+ _vm->_font->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
if (_lines[lineCtr].underline)
// Underline needed
- hLine(pt.x, pt.x + _vm->_font->current()->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
- pt.y + _vm->_font->current()->getHeight());
+ hLine(pt.x, pt.x + _vm->_font->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
+ pt.y + _vm->_font->getHeight());
}
}
@@ -528,7 +528,7 @@ void Dialog::display(MadsM4Engine *vm, int widthChars, const char **descEntries)
dlg->incLine();
dlg->writeChars(*descEntries);
- int lineWidth = vm->_font->current()->getWidth(*descEntries, DIALOG_SPACING);
+ int lineWidth = vm->_font->getWidth(*descEntries, DIALOG_SPACING);
dlg->_lines[dlg->_lines.size() - 1].xp = (dlg->_dialogWidth - 10 - lineWidth) / 2;
++descEntries;
}
diff --git a/engines/m4/font.cpp b/engines/m4/font.cpp
index 4afa158976..f8dec65412 100644
--- a/engines/m4/font.cpp
+++ b/engines/m4/font.cpp
@@ -29,46 +29,28 @@
namespace M4 {
-FontManager::~FontManager() {
- for (uint i = 0; i < _entries.size(); ++i)
- delete _entries[i];
- _entries.clear();
-}
-
-Font *FontManager::getFont(const Common::String &filename) {
- // Check if the font is already loaded
- for (uint i = 0; i < _entries.size(); ++i)
- {
- if (_entries[i]->_filename.equals(filename))
- return _entries[i];
- }
-
- Font *f = new Font(_vm, filename);
- _entries.push_back(f);
- return f;
-}
-
-void FontManager::setFont(const Common::String &filename) {
- _currentFont = getFont(filename);
-}
-
-//--------------------------------------------------------------------------
-
-Font::Font(MadsM4Engine *vm, const Common::String &filename) : _vm(vm), _filename(filename) {
+Font::Font(MadsM4Engine *vm) : _vm(vm) {
_sysFont = true;
-
+ _filename = NULL;
//TODO: System font
_fontColors[0] = _vm->_palette->BLACK;
_fontColors[1] = _vm->_palette->WHITE;
_fontColors[2] = _vm->_palette->BLACK;
_fontColors[3] = _vm->_palette->DARK_GRAY;
+}
+
+void Font::setFont(const char *filename) {
+ if ((_filename != NULL) && (strcmp(filename, _filename) == 0))
+ // Already using specified font, so don't bother reloading
+ return;
_sysFont = false;
+ _filename = filename;
if (_vm->isM4())
- setFontM4(filename.c_str());
+ setFontM4(filename);
else
- setFontMads(filename.c_str());
+ setFontMads(filename);
}
void Font::setFontM4(const char *filename) {
@@ -152,21 +134,20 @@ Font::~Font() {
}
}
-void Font::setColour(uint8 colour) {
+void Font::setColor(uint8 color) {
if (_sysFont)
- _fontColors[1] = colour;
+ _fontColors[1] = color;
else
- _fontColors[3] = colour;
+ _fontColors[3] = color;
}
-void Font::setColours(uint8 col1, uint8 col2, uint8 col3) {
+void Font::setColors(uint8 alt1, uint8 alt2, uint8 foreground) {
if (_sysFont)
- _fontColors[1] = col3;
+ _fontColors[1] = foreground;
else {
- _fontColors[0] = 0xFF;
- _fontColors[1] = col1;
- _fontColors[2] = col2;
- _fontColors[3] = col3;
+ _fontColors[1] = alt1;
+ _fontColors[2] = alt2;
+ _fontColors[3] = foreground;
}
}
diff --git a/engines/m4/font.h b/engines/m4/font.h
index ca47848c61..e64f80b70d 100644
--- a/engines/m4/font.h
+++ b/engines/m4/font.h
@@ -59,11 +59,19 @@ namespace M4 {
class Font {
public:
- Font(MadsM4Engine *vm, const Common::String &filename);
+ Font(MadsM4Engine *vm);
~Font();
- void setColour(uint8 colour);
- void setColours(uint8 col1, uint8 col2, uint8 col3);
+ Font *getFont(const char *filename) {
+ // TODO: Proper separation of font instances
+ setFont(filename);
+ return this;
+ }
+ void setFont(const char *filename);
+ void setColor(uint8 color);
+ void setColors(uint8 alt1, uint8 alt2, uint8 foreground);
+ void setColour(uint8 colour) { setColor(colour); }
+ void setColours(uint8 alt1, uint8 alt2, uint8 foreground) { setColors(alt1, alt2, foreground); }
int32 getWidth(const char *text, int spaceWidth = -1);
int32 getHeight() const { return _maxHeight; }
@@ -72,8 +80,7 @@ public:
int32 writeString(M4Surface *surface, const char *text, int x, int y, int width = 0, int spaceWidth = -1) {
return write(surface, text, x, y, width, spaceWidth, _fontColors);
}
-public:
- const Common::String _filename;
+
private:
void setFontM4(const char *filename);
void setFontMads(const char *filename);
@@ -84,39 +91,10 @@ private:
uint16 *_charOffs;
uint8 *_charData;
bool _sysFont;
+ const char *_filename;
uint8 _fontColors[4];
};
-class FontEntry {
-public:
- Font *_font;
-
- FontEntry() {
- _font = NULL;
- }
- ~FontEntry() {
- delete _font;
- }
-};
-
-class FontManager {
-private:
- MadsM4Engine *_vm;
- Common::Array<Font *> _entries;
- Font *_currentFont;
-public:
- FontManager(MadsM4Engine *vm): _vm(vm) { _currentFont = NULL; }
- ~FontManager();
-
- Font *getFont(const Common::String &filename);
- void setFont(const Common::String &filename);
-
- Font *current() {
- assert(_currentFont);
- return _currentFont;
- }
-};
-
} // End of namespace M4
#endif
diff --git a/engines/m4/globals.h b/engines/m4/globals.h
index de6e716ece..a052a4c868 100644
--- a/engines/m4/globals.h
+++ b/engines/m4/globals.h
@@ -264,7 +264,6 @@ public:
// DEPRECATED: ScummVM re-implementation keeps all the quotes loaded, so the methods below are stubs
void clearQuotes() {}
void loadQuoteRange(int startNum, int endNum) {}
- void loadQuoteSet(...) {}
void loadQuote(int quoteNum) {}
void loadMadsMessagesInfo();
diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp
index 29aaa184a3..893c415576 100644
--- a/engines/m4/graphics.cpp
+++ b/engines/m4/graphics.cpp
@@ -69,13 +69,6 @@ void RGBList::setRange(int start, int count, const RGB8 *src) {
#define VGA_COLOR_TRANS(x) (x == 0x3f ? 255 : x << 2)
-M4Surface::~M4Surface() {
- if (_rgbList) {
- _madsVm->_palette->deleteRange(_rgbList);
- delete _rgbList;
- }
-}
-
void M4Surface::loadCodesM4(Common::SeekableReadStream *source) {
if (!source) {
free();
@@ -340,7 +333,7 @@ void M4Surface::fillRect(const Common::Rect &r, uint8 color) {
}
void M4Surface::copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY,
- int transparentColour) {
+ int transparentColor) {
// Validation of the rectangle and position
if ((destX >= w) || (destY >= h))
return;
@@ -369,13 +362,13 @@ void M4Surface::copyFrom(M4Surface *src, const Common::Rect &srcBounds, int dest
byte *destPtr = (byte *)pixels + (destY * width()) + destX;
for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
- if (transparentColour == -1)
+ if (transparentColor == -1)
// No transparency, so copy line over
Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr);
else {
// Copy each byte one at a time checking for the transparency color
for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr)
- if (srcPtr[xCtr] != transparentColour) destPtr[xCtr] = srcPtr[xCtr];
+ if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr];
}
srcPtr += src->width();
@@ -385,81 +378,6 @@ void M4Surface::copyFrom(M4Surface *src, const Common::Rect &srcBounds, int dest
src->freeData();
}
-/**
- * Copies a given image onto a destination surface with scaling, transferring only pixels that meet
- * the specified depth requirement on a secondary surface contain depth information
- */
-void M4Surface::copyFrom(M4Surface *src, int destX, int destY, int depth, M4Surface *depthsSurface,
- int scale, int transparentColour) {
- /* TODO: This isn't a straight re-implementation of the original draw routine. Double check in future
- * whether this implementation provides equivalent functionality
- */
- Common::Rect copyRect(0, 0, src->width(), src->height());
-
- if (destX < 0) {
- copyRect.left += -destX;
- destX = 0;
- } else if (destX + copyRect.width() > w) {
- copyRect.right -= destX + copyRect.width() - w;
- }
- if (destY < 0) {
- copyRect.top += -destY;
- destY = 0;
- } else if (destY + copyRect.height() > h) {
- copyRect.bottom -= destY + copyRect.height() - h;
- }
-
- if (!copyRect.isValidRect())
- return;
-
- // Copy the specified area
-
- byte *data = src->getBasePtr();
- byte *srcPtr = data + (src->width() * copyRect.top + copyRect.left);
- byte *depthsData = depthsSurface->getBasePtr();
- byte *depthsPtr = depthsData + (src->width() * copyRect.top + copyRect.left);
- byte *destPtr = (byte *)pixels + (destY * width()) + destX;
-
- if (scale == 100) {
- // 100% scaling variation
- for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
- // Copy each byte one at a time checking against the depth
- for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) {
- if ((depthsPtr[xCtr] > depth) && (srcPtr[xCtr] != transparentColour))
- destPtr[xCtr] = srcPtr[xCtr];
- }
-
- srcPtr += src->width();
- depthsPtr += depthsSurface->width();
- destPtr += width();
- }
- } else {
- // Scaled variation
- for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
- int currX = -1;
-
- // Loop through the source pixels
- for (int xCtr = 0, xTotal = 0; xCtr < copyRect.width(); ++xCtr, xTotal += (100 - scale)) {
- int srcX = xTotal / 100;
-
- if (srcX != currX) {
- currX = srcX;
-
- if ((depthsPtr[currX] > depth) && (srcPtr[xCtr] != transparentColour))
- destPtr[currX] = srcPtr[xCtr];
- }
- }
-
- srcPtr += src->width();
- depthsPtr += depthsSurface->width();
- destPtr += width();
- }
- }
-
- src->freeData();
- depthsSurface->freeData();
-}
-
void M4Surface::loadBackgroundRiddle(const char *sceneName) {
char resourceName[20];
Common::SeekableReadStream *stream;
@@ -479,18 +397,9 @@ void M4Surface::loadBackground(int sceneNumber, RGBList **palData) {
if (_vm->getGameType() == GType_RexNebular) {
// Load Rex Nebular screen
- bool hasPalette = palData != NULL;
- if (!hasPalette)
- palData = &_rgbList;
-
sprintf(resourceName, "rm%d.art", sceneNumber);
stream = _vm->_resourceManager->get(resourceName);
rexLoadBackground(stream, palData);
-
- if (!hasPalette) {
- _vm->_palette->addRange(_rgbList);
- this->translate(_rgbList);
- }
} else {
// Loads M4 game scene
if (palData)
@@ -727,8 +636,10 @@ void M4Surface::m4LoadBackground(Common::SeekableReadStream *source) {
delete tileBuffer;
}
-void M4Surface::madsLoadInterface(const Common::String &filename) {
- MadsPack intFile(filename.c_str(), _vm);
+void M4Surface::madsloadInterface(int index, RGBList **palData) {
+ char resourceName[20];
+ sprintf(resourceName, "i%d.int", index);
+ MadsPack intFile(resourceName, _vm);
RGB8 *palette = new RGB8[16];
// Chunk 0, palette
@@ -742,7 +653,7 @@ void M4Surface::madsLoadInterface(const Common::String &filename) {
intStream->readByte();
intStream->readByte();
}
- _rgbList = new RGBList(16, palette, true);
+ *palData = new RGBList(16, palette, true);
delete intStream;
// Chunk 1, data
@@ -750,77 +661,8 @@ void M4Surface::madsLoadInterface(const Common::String &filename) {
create(320, 44, 1);
intStream->read(pixels, 320 * 44);
delete intStream;
-
- // Translate the interface palette
- _vm->_palette->addRange(_rgbList);
- this->translate(_rgbList);
}
-void M4Surface::scrollX(int xAmount) {
- if (xAmount == 0)
- return;
-
- byte buffer[80];
- int direction = (xAmount > 0) ? 1 : -1;
- int xSize = ABS(xAmount);
- assert(xSize <= 80);
-
- byte *srcP = (byte *)getBasePtr(0, 0);
-
- for (int y = 0; y < height(); ++y, srcP += pitch) {
- if (direction < 0) {
- // Copy area to be overwritten
- Common::copy(srcP, srcP + xSize, &buffer[0]);
- // Shift the remainder of the line over the given area
- Common::copy(srcP + xSize, srcP + width(), srcP);
- // Move buffered area to the end of the line
- Common::copy(&buffer[0], &buffer[xSize], srcP + width() - xSize);
- } else {
- // Copy area to be overwritten
- Common::copy_backward(srcP + width() - xSize, srcP + width(), &buffer[80]);
- // Shift the remainder of the line over the given area
- Common::copy_backward(srcP, srcP + width() - xSize, srcP + width());
- // Move buffered area to the start of the line
- Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize);
- }
- }
-}
-
-void M4Surface::scrollY(int yAmount) {
- if (yAmount == 0)
- return;
-
- int direction = (yAmount > 0) ? 1 : -1;
- int ySize = ABS(yAmount);
- assert(ySize < (height() / 2));
- assert(width() == pitch);
-
- int blockSize = ySize * width();
- byte *tempData = (byte *)malloc(blockSize);
- byte *pixelsP = (byte *)getBasePtr(0, 0);
-
- if (direction > 0) {
- // Buffer the lines to be overwritten
- byte *srcP = (byte *)getBasePtr(0, height() - ySize);
- Common::copy(srcP, srcP + (pitch * ySize), tempData);
- // Vertically shift all the lines
- Common::copy_backward(pixelsP, pixelsP + (pitch * (height() - ySize)),
- pixelsP + (pitch * height()));
- // Transfer the buffered lines top the top of the screen
- Common::copy(tempData, tempData + blockSize, pixelsP);
- } else {
- // Buffer the lines to be overwritten
- Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData);
- // Vertically shift all the lines
- Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * height()), pixelsP);
- // Transfer the buffered lines to the bottom of the screen
- Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (height() - ySize)));
- }
-
- ::free(tempData);
-}
-
-
void M4Surface::translate(RGBList *list, bool isTransparent) {
byte *p = getBasePtr(0, 0);
byte *palIndexes = list->palIndexes();
diff --git a/engines/m4/graphics.h b/engines/m4/graphics.h
index 8c4b9ac072..4c89c50b8a 100644
--- a/engines/m4/graphics.h
+++ b/engines/m4/graphics.h
@@ -35,12 +35,6 @@
namespace M4 {
-#define MADS_SURFACE_WIDTH 320
-#define MADS_SURFACE_HEIGHT 156
-#define MADS_SCREEN_HEIGHT 200
-#define MADS_Y_OFFSET ((MADS_SCREEN_HEIGHT - MADS_SURFACE_HEIGHT) / 2)
-
-
struct BGR8 {
uint8 b, g, r;
};
@@ -95,23 +89,19 @@ class M4Surface : protected Graphics::Surface {
private:
byte _color;
bool _isScreen;
- RGBList *_rgbList;
void rexLoadBackground(Common::SeekableReadStream *source, RGBList **palData = NULL);
void madsLoadBackground(int roomNumber, RGBList **palData = NULL);
void m4LoadBackground(Common::SeekableReadStream *source);
public:
M4Surface(bool isScreen = false) {
- create(g_system->getWidth(), isScreen ? g_system->getHeight() : MADS_SURFACE_HEIGHT, 1);
+ create(g_system->getWidth(), g_system->getHeight(), 1);
_isScreen = isScreen;
- _rgbList = NULL;
}
M4Surface(int width_, int height_) {
create(width_, height_, 1);
_isScreen = false;
- _rgbList = NULL;
}
- virtual ~M4Surface();
// loads a .COD file into the M4Surface
// TODO: maybe move this to the rail system? check where it makes sense
@@ -122,8 +112,7 @@ public:
// loads the specified background
void loadBackground(int sceneNumber, RGBList **palData = NULL);
void loadBackgroundRiddle(const char *sceneName);
- void madsLoadInterface(int index, RGBList **palData = NULL);
- void madsLoadInterface(const Common::String &filename);
+ void madsloadInterface(int index, RGBList **palData);
void setColor(byte value) { _color = value; }
void setColour(byte value) { _color = value; }
@@ -156,10 +145,8 @@ public:
void clear();
void frameRect(const Common::Rect &r, uint8 color);
void fillRect(const Common::Rect &r, uint8 color);
- void copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY,
- int transparentColour = -1);
- void copyFrom(M4Surface *src, int destX, int destY, int depth, M4Surface *depthSurface, int scale,
- int transparentColour = -1);
+ void copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY,
+ int transparentColor = -1);
void update() {
if (_isScreen) {
@@ -169,23 +156,16 @@ public:
}
// copyTo methods
- inline void copyTo(M4Surface *dest, int transparentColour = -1) {
- dest->copyFrom(this, Common::Rect(width(), height()), 0, 0, transparentColour);
+ inline void copyTo(M4Surface *dest, int transparentColor = -1) {
+ dest->copyFrom(this, Common::Rect(width(), height()), 0, 0, transparentColor);
}
- inline void copyTo(M4Surface *dest, int x, int y, int transparentColour = -1) {
- dest->copyFrom(this, Common::Rect(width(), height()), x, y, transparentColour);
+ inline void copyTo(M4Surface *dest, int x, int y, int transparentColor = -1) {
+ dest->copyFrom(this, Common::Rect(width(), height()), x, y, transparentColor);
}
inline void copyTo(M4Surface *dest, const Common::Rect &srcBounds, int destX, int destY,
- int transparentColour = -1) {
- dest->copyFrom(this, srcBounds, destX, destY, transparentColour);
+ int transparentColor = -1) {
+ dest->copyFrom(this, srcBounds, destX, destY, transparentColor);
}
- inline void copyTo(M4Surface *dest, int destX, int destY, int depth, M4Surface *depthsSurface, int scale,
- int transparentColour = -1) {
- dest->copyFrom(this, destX, destY, depth, depthsSurface, scale, transparentColour);
- }
-
- void scrollX(int xAmount);
- void scrollY(int yAmount);
void translate(RGBList *list, bool isTransparent = false);
};
diff --git a/engines/m4/gui.cpp b/engines/m4/gui.cpp
index 8665b4e767..8f949de9c5 100644
--- a/engines/m4/gui.cpp
+++ b/engines/m4/gui.cpp
@@ -290,26 +290,26 @@ void MenuButton::onRefresh() {
case OBJTYPE_SL_TEXT:
switch (_objectState) {
case OS_MOUSEOVER:
- _vm->_font->current()->setColours(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
TEXT_COLOR_MOUSEOVER_HILIGHT);
sprite = sprites[SL_LINE_MOUSEOVER];
break;
case OS_PRESSED:
- _vm->_font->current()->setColours(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
TEXT_COLOR_PRESSED_HILIGHT);
sprite = sprites[SL_LINE_PRESSED];
break;
case OS_GREYED:
- _vm->_font->current()->setColours(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
TEXT_COLOR_GREYED_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
default:
case OS_NORMAL:
- _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
@@ -849,11 +849,11 @@ void MenuSaveLoadText::onRefresh() {
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
}
}
@@ -955,18 +955,18 @@ void MenuTextField::onRefresh() {
// Draw the text
_vm->_font->setFont(FONT_MENU);
- _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
int xp = _bounds.left + 4;
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
if (focused) {
// Draw in the cursor
@@ -975,7 +975,7 @@ void MenuTextField::onRefresh() {
// Get the width of the string up to the cursor position
char tempCh = *_cursor;
*_cursor = '\0';
- int stringWidth = _vm->_font->current()->getWidth(_displayText);
+ int stringWidth = _vm->_font->getWidth(_displayText);
*_cursor = tempCh;
parent()->setColor(TEXT_COLOR_MOUSEOVER_FOREGROUND);
@@ -1015,10 +1015,10 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
tempP = &tempStr[tempLen];
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->current()->getWidth(tempStr);
+ tempLen = _vm->_font->getWidth(tempStr);
while ((tempP != &tempStr[0]) && (tempLen > x - _bounds.left - 26)) {
*--tempP = '\0';
- tempLen = _vm->_font->current()->getWidth(tempStr);
+ tempLen = _vm->_font->getWidth(tempStr);
}
_cursor = &_displayText[tempP - &tempStr[0]];
@@ -1098,7 +1098,7 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
parent()->_deleteSaveDesc = false;
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->current()->getWidth(_displayText);
+ tempLen = _vm->_font->getWidth(_displayText);
if ((strlen(_displayText) < MAX_SAVEGAME_NAME - 1) &&
(tempLen < _pixelWidth - 12) && (param >= 32) && (param <= 127)) {
@@ -1140,9 +1140,9 @@ GUITextField::GUITextField(View *owner, const Common::Rect &bounds): GUIRect(own
void GUITextField::onRefresh() {
_parent->fillRect(_bounds, _vm->_palette->BLACK);
- _vm->_font->current()->setColours(3, 3, 3);
+ _vm->_font->setColors(3, 3, 3);
_vm->_font->setFont(FONT_INTERFACE);
- _vm->_font->current()->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
+ _vm->_font->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
}
//--------------------------------------------------------------------------
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index da271b10c9..897fb468cd 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -145,6 +145,7 @@ MadsM4Engine::~MadsM4Engine() {
delete _script;
delete _ws;
delete _random;
+ delete _animation;
delete _palette;
}
@@ -169,7 +170,7 @@ Common::Error MadsM4Engine::run() {
_events = new Events(this);
_kernel = new Kernel(this);
_player = new Player(this);
- _font = new FontManager(this);
+ _font = new Font(this);
if (getGameType() == GType_Burger) {
_actor = new Actor(this);
_conversationView = new ConversationView(this);
@@ -183,6 +184,7 @@ Common::Error MadsM4Engine::run() {
_sound = new Sound(this, _mixer, 255);
_script = new ScriptInterpreter(this);
_ws = new WoodScript(this);
+ _animation = new Animation(this);
//_callbacks = new Callbacks(this);
_random = new Common::RandomSource();
g_eventRec.registerRandomSource(*_random, "m4");
@@ -552,9 +554,9 @@ Common::Error MadsEngine::run() {
_scene->show();
_font->setFont(FONT_MAIN_MADS);
- _font->current()->setColours(2, 1, 3);
- _font->current()->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
- _font->current()->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
+ _font->setColors(2, 1, 3);
+ _font->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
+ _font->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
if (getGameType() == GType_DragonSphere) {
//_scene->showMADSV2TextBox("Test", 10, 10, NULL);
@@ -579,6 +581,8 @@ Common::Error MadsEngine::run() {
while (!_events->quitFlag) {
eventHandler();
+ _animation->updateAnim();
+
if (g_system->getMillis() >= nextFrame) {
nextFrame = g_system->getMillis() + GAME_FRAME_DELAY;
++_currentTimer;
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index 9937107668..1f34bd3685 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -189,7 +189,7 @@ public:
Player *_player;
Mouse *_mouse;
Events *_events;
- FontManager *_font;
+ Font *_font;
Actor *_actor;
Scene *_scene;
Dialogs *_dialogs;
@@ -200,6 +200,7 @@ public:
Rails *_rails;
ScriptInterpreter *_script;
WoodScript *_ws;
+ Animation *_animation;
Common::RandomSource *_random;
Scene *scene() { return _scene; }
diff --git a/engines/m4/m4_views.cpp b/engines/m4/m4_views.cpp
index f4345787df..3d633cef0d 100644
--- a/engines/m4/m4_views.cpp
+++ b/engines/m4/m4_views.cpp
@@ -34,7 +34,7 @@ namespace M4 {
GUIInventory::GUIInventory(View *owner, MadsM4Engine *vm, const Common::Rect &bounds, int horizCells,
int vertCells, int cellWidth, int cellHeight, int tag): GUIRect(owner, bounds, tag) {
- _vm = vm;
+ _vm = vm;
_cellCount.x = horizCells;
_cellCount.y = vertCells;
_cellSize.x = cellWidth;
diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp
index 24a041e04d..954916700c 100644
--- a/engines/m4/mads_anim.cpp
+++ b/engines/m4/mads_anim.cpp
@@ -37,7 +37,7 @@ namespace M4 {
TextviewView::TextviewView(MadsM4Engine *vm):
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
_bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT),
- _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->current()->getHeight() +
+ _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->getHeight() +
TEXTVIEW_LINE_SPACING) {
_screenType = VIEWID_TEXTVIEW;
@@ -60,7 +60,7 @@ TextviewView::TextviewView(MadsM4Engine *vm):
_vm->_palette->setPalette(&palData[0], 4, 3);
_vm->_palette->blockRange(4, 3);
- _vm->_font->current()->setColours(5, 6, 4);
+ _vm->_font->setColors(5, 6, 4);
clear();
_bgSurface.clear();
@@ -222,7 +222,7 @@ void TextviewView::updateState() {
}
} else {
// Handling a text row
- if (++_lineY == (_vm->_font->current()->getHeight() + TEXTVIEW_LINE_SPACING))
+ if (++_lineY == (_vm->_font->getHeight() + TEXTVIEW_LINE_SPACING))
processLines();
}
@@ -404,7 +404,7 @@ void TextviewView::processText() {
if (!strcmp(_currentLine, "***")) {
// Special signifier for end of script
- _scrollCount = _vm->_font->current()->getHeight() * 13;
+ _scrollCount = _vm->_font->getHeight() * 13;
_lineY = -1;
return;
}
@@ -416,7 +416,7 @@ void TextviewView::processText() {
char *centerP = strchr(_currentLine, '@');
if (centerP) {
*centerP = '\0';
- xStart = (width() / 2) - _vm->_font->current()->getWidth(_currentLine);
+ xStart = (width() / 2) - _vm->_font->getWidth(_currentLine);
// Delete the @ character and shift back the remainder of the string
char *p = centerP + 1;
@@ -424,16 +424,16 @@ void TextviewView::processText() {
strcpy(centerP, p);
} else {
- lineWidth = _vm->_font->current()->getWidth(_currentLine);
+ lineWidth = _vm->_font->getWidth(_currentLine);
xStart = (width() - lineWidth) / 2;
}
// Copy the text line onto the bottom of the textSurface surface, which will allow it
// to gradually scroll onto the screen
- int yp = _textSurface.height() - _vm->_font->current()->getHeight() - TEXTVIEW_LINE_SPACING;
+ int yp = _textSurface.height() - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING;
_textSurface.fillRect(Common::Rect(0, yp, _textSurface.width(), _textSurface.height()),
_vm->_palette->BLACK);
- _vm->_font->current()->writeString(&_textSurface, _currentLine, xStart, yp);
+ _vm->_font->writeString(&_textSurface, _currentLine, xStart, yp);
}
diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp
index 9cb053a876..d0b7021f38 100644
--- a/engines/m4/mads_logic.cpp
+++ b/engines/m4/mads_logic.cpp
@@ -59,8 +59,8 @@ void MadsSceneLogic::getSceneSpriteSet() {
// if ((_sceneNumber == 105) ((_sceneNumber == 109) && (word_84800 != 0)))
// _madsVm->globals()->playerSpriteChanged = true;
- _vm->_palette->setEntry(16, 0x38, 0xFF, 0xFF);
- _vm->_palette->setEntry(17, 0x38, 0xb4, 0xb4);
+// _vm->_palette->setEntry(16, 0x38, 0xFF, 0xFF);
+// _vm->_palette->setEntry(17, 0x38, 0xb4, 0xb4);
}
void MadsSceneLogic::getAnimName() {
@@ -78,30 +78,31 @@ uint16 MadsSceneLogic::loadSpriteSet(uint16 suffixNum, uint16 sepChar) {
}
uint16 MadsSceneLogic::startReversibleSpriteSequence(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
- M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(0);
+ M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(1);
uint8 depth = _madsVm->_rails->getDepth(Common::Point(spriteFrame->x + (spriteFrame->width() / 2),
spriteFrame->y + (spriteFrame->height() / 2)));
return _madsVm->scene()->_sequenceList.add(srcSpriteIdx, v0, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
- true, 100, depth - 1, 1, ANIMTYPE_REVERSIBLE, 0, 0);
+ -1, 100, depth - 1, 1, ANIMTYPE_REVERSIBLE, 0, 0);
}
uint16 MadsSceneLogic::startCycledSpriteSequence(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
- M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(0);
+ M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(1);
+warning("%d %dx%d %d/%d", srcSpriteIdx, spriteFrame->x, spriteFrame->y, spriteFrame->width(), spriteFrame->height());
uint8 depth = _madsVm->_rails->getDepth(Common::Point(spriteFrame->x + (spriteFrame->width() / 2),
spriteFrame->y + (spriteFrame->height() / 2)));
return _madsVm->scene()->_sequenceList.add(srcSpriteIdx, v0, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
- true, 100, depth - 1, 1, ANIMTYPE_CYCLED, 0, 0);
+ -1, 100, depth - 1, 1, ANIMTYPE_CYCLED, 0, 0);
}
uint16 MadsSceneLogic::startSpriteSequence3(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
- M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(0);
+ M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(1);
uint8 depth = _madsVm->_rails->getDepth(Common::Point(spriteFrame->x + (spriteFrame->width() / 2),
spriteFrame->y + (spriteFrame->height() / 2)));
return _madsVm->scene()->_sequenceList.add(srcSpriteIdx, v0, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
- true, 100, depth - 1, -1, ANIMTYPE_CYCLED, 0, 0);
+ -1, 100, depth - 1, -1, ANIMTYPE_CYCLED, 0, 0);
}
void MadsSceneLogic::activateHotspot(int idx, bool active) {
@@ -146,7 +147,6 @@ void MadsSceneLogic::lowRoomsEntrySound() {
}
}
-
/*--------------------------------------------------------------------------*/
/**
@@ -160,7 +160,7 @@ void MadsSceneLogic::selectScene(int sceneNum) {
assert(sceneNum == 101);
_sceneNumber = sceneNum;
- Common::set_to(&_spriteIndexes[0], &_spriteIndexes[50], 0);
+
}
void MadsSceneLogic::setupScene() {
@@ -170,9 +170,7 @@ void MadsSceneLogic::setupScene() {
// sub_1e754(animName, 3);
- if ((_sceneNumber >= 101) && (_sceneNumber <= 112))
- getSceneSpriteSet();
-
+ getSceneSpriteSet();
getAnimName();
}
@@ -208,39 +206,10 @@ void MadsSceneLogic::enterScene() {
if (_madsVm->globals()->previousScene != -1)
_madsVm->globals()->_globals[10] = 0;
if (_madsVm->globals()->previousScene != -2) {
- _madsVm->scene()->getSceneResources().playerPos = Common::Point(100, 152);
+ //playerPos = (100, 152);
}
- if ((_madsVm->globals()->previousScene == 112) ||
- ((_madsVm->globals()->previousScene != -2) && (_spriteIndexes[29] != 0))) {
- // Returning from probe cutscene?
- _spriteIndexes[29] = -1;
- _madsVm->scene()->getSceneResources().playerPos = Common::Point(161, 123);
- _madsVm->scene()->getSceneResources().playerDir = 9;
-
- // TODO: Extra flags setting
- _spriteIndexes[25] = startCycledSpriteSequence(_spriteIndexes[10], 0, 3, 0, 0, 0);
- _madsVm->scene()->_sequenceList.setAnimRange(_spriteIndexes[25], 17, 17);
- activateHotspot(0x47, false); // CHAIR
- /*timer_unk1 = */_madsVm->scene()->_dynamicHotspots.add(0x47, 0x13F /*SIT_IN*/, -1,
- Common::Rect(159, 84, 159+33, 84+36));
-
- //if (_madsVm->globals()->previousScene == 112)
- // room101Check();
- } else {
- _spriteIndexes[26] = startCycledSpriteSequence(_spriteIndexes[11], 0, 6, 0, 0, 0);
- }
-
- _madsVm->globals()->loadQuoteSet(0x31, 0x32, 0x37, 0x38, 0x39, -1);
-
- if (_madsVm->globals()->_globals[10]) {
- const char *animName = MADSResourceManager::getResourceName('S', 'e', EXTTYPE_AA, NULL, -1);
- _madsVm->scene()->loadAnimation(animName, 0x47);
-
- _madsVm->scene()->getSceneResources().playerPos = Common::Point(68, 140);
- _madsVm->scene()->getSceneResources().playerDir = 4;
- // TODO: Flags setting
- }
+ // TODO: EXTRA STUFF
lowRoomsEntrySound();
}
@@ -249,15 +218,4 @@ void MadsSceneLogic::doAction() {
}
-void MadsSceneLogic::sceneStep() {
- // FIXME: Temporary code to display a message on-screen
- static bool tempBool = false;
- if (!tempBool) {
- tempBool = true;
-
- _madsVm->scene()->_kernelMessages.add(Common::Point(63, 100), 0x1110, 0, 0, 240,
- _madsVm->globals()->getQuote(49));
- }
-}
-
}
diff --git a/engines/m4/mads_logic.h b/engines/m4/mads_logic.h
index 8c3f41d08b..a589556a21 100644
--- a/engines/m4/mads_logic.h
+++ b/engines/m4/mads_logic.h
@@ -29,8 +29,6 @@
#ifndef M4_MADS_LOGIC_H
#define M4_MADS_LOGIC_H
-#include "m4/mads_views.h"
-
namespace M4 {
class MadsSceneLogic {
@@ -56,7 +54,6 @@ public:
void setupScene();
void enterScene();
void doAction();
- void sceneStep();
};
}
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp
index d00272d31e..64f18fa11d 100644
--- a/engines/m4/mads_menus.cpp
+++ b/engines/m4/mads_menus.cpp
@@ -616,10 +616,10 @@ void RexDialogView::initialiseLines() {
}
_totalTextEntries = 0;
- // Set up a default sprite slot entry for a full screen refresh
+ // Set up a default sprite slot entry
_spriteSlots.startIndex = 1;
- _spriteSlots[0].spriteType = FULL_SCREEN_REFRESH;
- _spriteSlots[0].seqIndex = -1;
+ _spriteSlots[0].spriteId = -2;
+ _spriteSlots[0].timerIndex = -1;
}
void RexDialogView::initialiseGraphics() {
@@ -795,8 +795,8 @@ bool RexDialogView::onEvent(M4EventType eventType, int32 param1, int x, int y, b
void RexDialogView::setFrame(int frameNumber, int depth) {
int slotIndex = _spriteSlots.getIndex();
- _spriteSlots[slotIndex].spriteType = FOREGROUND_SPRITE;
- _spriteSlots[slotIndex].seqIndex = 1;
+ _spriteSlots[slotIndex].spriteId = 1;
+ _spriteSlots[slotIndex].timerIndex = 1;
_spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex;
_spriteSlots[slotIndex].frameNumber = frameNumber;
@@ -985,15 +985,15 @@ RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() {
void RexGameMenuDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 2) * 6) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 2) * 6) >> 1) - 78);
- addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 10);
+ addQuote(_vm->_font, ALIGN_CENTER, 0, top, 10);
// Loop for adding the option lines of the dialog
top += 6;
for (int idx = 0; idx < 5; ++idx) {
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 11 + idx);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CENTER, 0, top, 11 + idx);
}
}
@@ -1069,42 +1069,42 @@ void RexOptionsDialog::reload() {
void RexOptionsDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 1) * 9 + 12) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 1) * 9 + 12) >> 1) - 78);
- addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 16);
+ addQuote(_vm->_font, ALIGN_CENTER, 0, top, 16);
// Music state line
- top += _vm->_font->current()->getHeight() + 1 + 6;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
+ top += _vm->_font->getHeight() + 1 + 6;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
// Sound state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
// Interface easy state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
// Inventory sppinng state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
// Text window state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
// Screen fade state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
// Storyline mode line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
// Add Done and Cancel button texts
- top += _vm->_font->current()->getHeight() + 1 + 6;
- addQuote(_vm->_font->current(), ALIGN_CENTER, -54, top, 1, 0);
- addQuote(_vm->_font->current(), ALIGN_CENTER, 54, top, 2, 0);
+ top += _vm->_font->getHeight() + 1 + 6;
+ addQuote(_vm->_font, ALIGN_CENTER, -54, top, 1, 0);
+ addQuote(_vm->_font, ALIGN_CENTER, 54, top, 2, 0);
}
bool RexOptionsDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp
index a65224c722..8073db32db 100644
--- a/engines/m4/mads_scene.cpp
+++ b/engines/m4/mads_scene.cpp
@@ -37,31 +37,18 @@
#include "m4/mads_views.h"
#include "m4/compression.h"
#include "m4/staticres.h"
-#include "m4/animation.h"
namespace M4 {
-static const int INV_ANIM_FRAME_SPEED = 2;
-static const int INVENTORY_X = 160;
-static const int INVENTORY_Y = 159;
-static const int SCROLLER_DELAY = 200;
-
-//--------------------------------------------------------------------------
-
MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResources), MadsView(this) {
_vm = vm;
- _activeAnimation = NULL;
- MadsView::_bgSurface = Scene::_backgroundSurface;
- MadsView::_depthSurface = Scene::_walkSurface;
_interfaceSurface = new MadsInterfaceView(vm);
for (int i = 0; i < 3; ++i)
actionNouns[i] = 0;
}
MadsScene::~MadsScene() {
- delete _activeAnimation;
- _activeAnimation = NULL;
leaveScene();
_vm->_viewManager->deleteView(_interfaceSurface);
}
@@ -81,13 +68,6 @@ void MadsScene::loadScene2(const char *aaName) {
// Load scene walk paths
loadSceneCodes(_currentScene);
-
- // Initialise the scene animation
- uint16 flags = 0x4100;
- if (_madsVm->globals()->_config.textWindowStill)
- flags |= 0x200;
-
- _sceneAnimation->initialise(aaName, flags, _interfaceSurface, NULL);
}
/**
@@ -96,12 +76,27 @@ void MadsScene::loadScene2(const char *aaName) {
void MadsScene::loadSceneTemporary() {
/* Existing code that eventually needs to be replaced with the proper MADS code */
// Set system palette entries
- _vm->_palette->blockRange(0, 18);
+ _vm->_palette->blockRange(0, 7);
RGB8 sysColors[3] = { {0x1f<<2, 0x2d<<2, 0x31<<2, 0}, {0x24<<2, 0x37<<2, 0x3a<<2, 0},
{0x00<<2, 0x10<<2, 0x16<<2, 0}};
_vm->_palette->setPalette(&sysColors[0], 4, 3);
- _interfaceSurface->initialise();
+ _backgroundSurface->loadBackground(_currentScene, &_palData);
+ _vm->_palette->addRange(_palData);
+ _backgroundSurface->translate(_palData);
+
+ if (_currentScene < 900) {
+ _interfaceSurface->madsloadInterface(0, &_interfacePal);
+ _vm->_palette->addRange(_interfacePal);
+ _interfaceSurface->translate(_interfacePal);
+ _backgroundSurface->copyFrom(_interfaceSurface, Common::Rect(0, 0, 320, 44), 0, 200 - 44);
+
+ _interfaceSurface->initialise();
+ }
+
+ // Don't load other screen resources for system screens
+ if (_currentScene >= 900)
+ return;
loadSceneHotspots(_currentScene);
@@ -170,11 +165,6 @@ void MadsScene::leaveScene() {
delete _sceneResources.props;
delete _walkSurface;
- if (_activeAnimation) {
- delete _activeAnimation;
- _activeAnimation = NULL;
- }
-
Scene::leaveScene();
}
@@ -193,6 +183,15 @@ void MadsScene::loadSceneCodes(int sceneNumber, int index) {
sceneS = walkData.getItemStream(0);
_walkSurface->loadCodesMads(sceneS);
_vm->res()->toss(filename);
+ } else if (_vm->getGameType() == GType_RexNebular) {
+ // For Rex Nebular, the walk areas are part of the scene info
+ byte *destP = _walkSurface->getBasePtr(0, 0);
+ const byte *srcP = _sceneResources.walkData;
+ byte runLength;
+ while ((runLength = *srcP++) != 0) {
+ Common::set_to(destP, destP + runLength, *srcP++);
+ destP += runLength;
+ }
}
}
@@ -278,6 +277,9 @@ void MadsScene::drawElements() {
void MadsScene::update() {
+ // Copy the bare scene in
+ _backgroundSurface->copyTo(this);
+
// Draw all the various elements
drawElements();
@@ -288,17 +290,19 @@ void MadsScene::update() {
if (sStatusText[0]) {
// Text colors are inverted in Dragonsphere
if (_vm->getGameType() == GType_DragonSphere)
- _vm->_font->current()->setColours(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK);
+ _vm->_font->setColors(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK);
else
- _vm->_font->current()->setColours(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK);
+ _vm->_font->setColors(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK);
_vm->_font->setFont(FONT_MAIN_MADS);
- _vm->_font->current()->writeString(this, sStatusText, (width() - _vm->_font->current()->getWidth(sStatusText)) / 2, 142, 0);
+ _vm->_font->writeString(this, sStatusText, (width() - _vm->_font->getWidth(sStatusText)) / 2, 142, 0);
}
+
+ //***DEBUG***
+ _spriteSlots.getSprite(0).getFrame(1)->copyTo(this, 120, 90, 0);
}
void MadsScene::updateState() {
- _sceneLogic.sceneStep();
_sequenceList.tick();
if ((_activeAnimation) && !_abortTimers) {
@@ -442,15 +446,6 @@ void MadsScene::showMADSV2TextBox(char *text, int x, int y, char *faceName) {
boxSprites->getFrame(bottomRight)->copyTo(_backgroundSurface, curX, curY + 1);
}
-void MadsScene::loadAnimation(const Common::String &animName, int v0) {
- if (_activeAnimation)
- error("Multiple active animations are not allowed");
-
- MadsAnimation *anim = new MadsAnimation(_vm, this);
- anim->load(animName.c_str(), 0);
- _activeAnimation = anim;
-}
-
/*--------------------------------------------------------------------------*/
MadsAction::MadsAction() {
@@ -628,531 +623,97 @@ void MadsAction::set() {
/*--------------------------------------------------------------------------*/
-void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface) {
- char buffer1[80];
- const char *sceneName;
-
- // TODO: Initialise spriteSet / xp_list
-
- if (sceneNumber > 0) {
- sceneName = MADSResourceManager::getResourceName(RESPREFIX_RM, sceneNumber, ".DAT");
- } else {
- strcat(buffer1, "*");
- strcat(buffer1, resName);
- sceneName = buffer1; // TODO: Check whether this needs to be converted to 'HAG form'
- }
-
- Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneName);
+void MadsSceneResources::load(int sId) {
+ const char *sceneInfoStr = MADSResourceManager::getResourceName(RESPREFIX_RM, sId, ".DAT");
+ Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneInfoStr);
MadsPack sceneInfo(rawStream);
- // Chunk 0:
// Basic scene info
Common::SeekableReadStream *stream = sceneInfo.getItemStream(0);
int resSceneId = stream->readUint16LE();
- assert(resSceneId == sceneNumber);
+ assert(resSceneId == sId);
+
artFileNum = stream->readUint16LE();
- drawStyle = stream->readUint16LE();
+ field_4 = stream->readUint16LE();
width = stream->readUint16LE();
height = stream->readUint16LE();
assert((width == 320) && (height == 156));
stream->skip(24);
- int objectCount = stream->readUint16LE();
+ objectCount = stream->readUint16LE();
stream->skip(40);
- // Load in any scene objects
for (int i = 0; i < objectCount; ++i) {
- MadsObject rec;
- rec.load(stream);
- objects.push_back(rec);
- }
- for (int i = 0; i < 20 - objectCount; ++i)
- stream->skip(48);
-
- int setCount = stream->readUint16LE();
- stream->readUint16LE();
- for (int i = 0; i < setCount; ++i) {
- char buffer2[64];
- Common::String s(buffer2, 64);
- setNames.push_back(s);
- }
-
- // Initialise a copy of the surfaces if they weren't provided
- bool dsFlag = false, ssFlag = false;
- int gfxSize = width * height;
- if (!surface) {
- surface = new M4Surface(width, height);
- ssFlag = true;
- }
- int walkSize = gfxSize;
- if (drawStyle == 2) {
- width >>= 2;
- walkSize = width * height;
- }
- if (!depthSurface) {
- depthSurface = new M4Surface(width, height);
- dsFlag = true;
+ objects[i].load(stream);
}
// For Rex Nebular, read in the scene's compressed walk surface information
if (_vm->getGameType() == GType_RexNebular) {
- assert(depthSurface);
+ delete walkData;
+
stream = sceneInfo.getItemStream(1);
- byte *walkData = (byte *)malloc(stream->size());
+ walkData = (byte *)malloc(stream->size());
stream->read(walkData, stream->size());
-
- // For Rex Nebular, the walk areas are part of the scene info
- byte *destP = depthSurface->getBasePtr(0, 0);
- const byte *srcP = walkData;
- byte runLength;
- while ((runLength = *srcP++) != 0) {
- Common::set_to(destP, destP + runLength, *srcP++);
- destP += runLength;
- }
-
- delete walkData;
- delete stream;
}
- _vm->_resourceManager->toss(sceneName);
-
- // Load the surface artwork
- surface->loadBackground(sceneNumber);
-
- // Final cleanup
- if (ssFlag)
- delete surface;
- if (dsFlag)
- delete depthSurface;
+ _vm->_resourceManager->toss(sceneInfoStr);
}
-
/*--------------------------------------------------------------------------*/
-/*--------------------------------------------------------------------------
- * MadsInterfaceView handles the user interface section at the bottom of
- * game screens in MADS games
- *--------------------------------------------------------------------------
+/**
+ * Adds a new entry to the timed on-screen text display list
*/
-
-MadsInterfaceView::MadsInterfaceView(MadsM4Engine *vm): GameInterfaceView(vm,
- Common::Rect(0, MADS_SURFACE_HEIGHT, vm->_screen->width(), vm->_screen->height())) {
- _screenType = VIEWID_INTERFACE;
- _highlightedElement = -1;
- _topIndex = 0;
- _selectedObject = -1;
- _cheatKeyCtr = 0;
-
- _objectSprites = NULL;
- _objectPalData = NULL;
-
- /* Set up the rect list for screen elements */
- // Actions
- for (int i = 0; i < 10; ++i)
- _screenObjects.addRect((i / 5) * 32 + 1, (i % 5) * 8 + MADS_SURFACE_HEIGHT + 2,
- ((i / 5) + 1) * 32 + 3, ((i % 5) + 1) * 8 + MADS_SURFACE_HEIGHT + 2);
-
- // Scroller elements (up arrow, scroller, down arrow)
- _screenObjects.addRect(73, 160, 82, 167);
- _screenObjects.addRect(73, 168, 82, 190);
- _screenObjects.addRect(73, 191, 82, 198);
-
- // Inventory object names
- for (int i = 0; i < 5; ++i)
- _screenObjects.addRect(89, 158 + i * 8, 160, 166 + i * 8);
-
- // Full rectangle area for all vocab actions
- for (int i = 0; i < 5; ++i)
- _screenObjects.addRect(239, 158 + i * 8, 320, 166 + i * 8);
-}
-
-MadsInterfaceView::~MadsInterfaceView() {
- delete _objectSprites;
-}
-
-void MadsInterfaceView::setFontMode(InterfaceFontMode newMode) {
- switch (newMode) {
- case ITEM_NORMAL:
- _vm->_font->current()->setColours(4, 4, 0xff);
- break;
- case ITEM_HIGHLIGHTED:
- _vm->_font->current()->setColours(5, 5, 0xff);
- break;
- case ITEM_SELECTED:
- _vm->_font->current()->setColours(6, 6, 0xff);
- break;
- }
+/*
+void MadsScreenText::draw(M4Surface *surface) {
}
-void MadsInterfaceView::initialise() {
- // Build up the inventory list
- _inventoryList.clear();
-
- for (uint i = 0; i < _madsVm->globals()->getObjectsSize(); ++i) {
- MadsObject *obj = _madsVm->globals()->getObject(i);
- if (obj->roomNumber == PLAYER_INVENTORY)
- _inventoryList.push_back(i);
+void MadsScreenText::timedDisplay() {
+ for (int idx = 0; !_abortTimedText && (idx < OLD_TEXT_DISPLAY_SIZE); ++idx) {
+ if (((_timedText[idx].flags & TEXTFLAG_ACTIVE) != 0) &&
+ (_timedText[idx].frameTimer <= g_system->getMillis()))
+ // Add the specified entry
+ addTimedText(&_timedText[idx]);
}
-
- // If the inventory has at least one object, select it
- if (_inventoryList.size() > 0)
- setSelectedObject(_inventoryList[0]);
}
-void MadsInterfaceView::setSelectedObject(int objectNumber) {
- char resName[80];
-
- // Load inventory resource
- if (_objectSprites) {
- _vm->_palette->deleteRange(_objectPalData);
- delete _objectSprites;
- }
-
- // Check to make sure the object is in the inventory, and also visible on-screen
- int idx = _inventoryList.indexOf(objectNumber);
- if (idx == -1) {
- // Object wasn't found, so return
- _selectedObject = -1;
+void MadsScreenText::addTimedText(TimedText *entry) {
+ if ((entry->flags & TEXTFLAG_40) != 0) {
+ this->setActive2(entry->textDisplayIndex);
+ entry->flags &= 0x7F;
return;
}
- // Found the object
- if (idx < _topIndex)
- _topIndex = idx;
- else if (idx >= (_topIndex + 5))
- _topIndex = MAX(0, idx - 4);
-
- _selectedObject = objectNumber;
- sprintf(resName, "*OB%.3dI.SS", objectNumber);
-
- Common::SeekableReadStream *data = _vm->res()->get(resName);
- _objectSprites = new SpriteAsset(_vm, data, data->size(), resName);
- _vm->res()->toss(resName);
-
- // Slot it into available palette space
- _objectPalData = _objectSprites->getRgbList();
- _vm->_palette->addRange(_objectPalData);
- _objectSprites->translate(_objectPalData, true);
-
- _objectFrameNumber = 0;
-}
-
-void MadsInterfaceView::addObjectToInventory(int objectNumber) {
- if (_inventoryList.indexOf(objectNumber) == -1) {
- _madsVm->globals()->getObject(objectNumber)->roomNumber = PLAYER_INVENTORY;
- _inventoryList.push_back(objectNumber);
- }
-
- setSelectedObject(objectNumber);
-}
-
-void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) {
- _vm->_font->setFont(FONT_INTERFACE_MADS);
- char buffer[100];
-
- // Check to see if any dialog is currently active
- bool dialogVisible = _vm->_viewManager->getView(LAYER_DIALOG) != NULL;
-
- // Highlighting logic for action list
- int actionIndex = 0;
- for (int x = 0; x < 2; ++x) {
- for (int y = 0; y < 5; ++y, ++actionIndex) {
- // Determine the font colour depending on whether an item is selected. Note that the first action,
- // 'Look', is always 'selected', even when another action is clicked on
- setFontMode((_highlightedElement == actionIndex) ? ITEM_HIGHLIGHTED :
- ((actionIndex == 0) ? ITEM_SELECTED : ITEM_NORMAL));
-
- // Get the verb action and capitalise it
- const char *verbStr = _madsVm->globals()->getVocab(kVerbLook + actionIndex);
- strcpy(buffer, verbStr);
- if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
-
- // Display the verb
- const Common::Rect r(_screenObjects[actionIndex]);
- _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
- }
- }
+ if ((entry->flags & TEXTFLAG_8) == 0)
+ // FIXME: Adjust timeouts for ScumVM's milli counter
+ entry->timeout -= 3;
- // Check for highlighting of the scrollbar controls
- if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_SCROLLER) || (_highlightedElement == SCROLL_DOWN)) {
- // Highlight the control's borders
- const Common::Rect r(_screenObjects[_highlightedElement]);
- destSurface->frameRect(r, 5);
+ if ((entry->flags & TEXTFLAG_4) != 0) {
+ Text4A &rec = _text4A[entry->unk4AIndex];
+ if ((rec.field25 != 0) || (rec.active == 0))
+ entry->timeout = 0;
}
- // Draw the horizontal line in the scroller representing the current top selected
- const Common::Rect scroller(_screenObjects[SCROLL_SCROLLER]);
- int yP = (_inventoryList.size() < 2) ? 0 : (scroller.height() - 5) * _topIndex / (_inventoryList.size() - 1);
- destSurface->setColor(4);
- destSurface->hLine(scroller.left + 2, scroller.right - 3, scroller.top + 2 + yP);
-
- // List inventory items
- for (uint i = 0; i < 5; ++i) {
- if ((_topIndex + i) >= _inventoryList.size())
- break;
+ if ((entry->timeout == 0) && !_abortTimedText) {
+ entry->flags |= TEXTFLAG_40;
- const char *descStr = _madsVm->globals()->getVocab(_madsVm->globals()->getObject(
- _inventoryList[_topIndex + i])->descId);
- strcpy(buffer, descStr);
- if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
-
- const Common::Rect r(_screenObjects[INVLIST_START + i]);
-
- // Set the highlighting of the inventory item
- if (_highlightedElement == (int)(INVLIST_START + i)) setFontMode(ITEM_HIGHLIGHTED);
- else if (_selectedObject == _inventoryList[_topIndex + i]) setFontMode(ITEM_SELECTED);
- else setFontMode(ITEM_NORMAL);
-
- // Write out it's description
- _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
- }
-
- // Handle the display of any currently selected object
- if (_objectSprites) {
- // Display object sprite. Note that the frame number isn't used directly, because it would result
- // in too fast an animation
- M4Sprite *spr = _objectSprites->getFrame(_objectFrameNumber / INV_ANIM_FRAME_SPEED);
- spr->copyTo(destSurface, INVENTORY_X, INVENTORY_Y, 0);
-
- if (!_madsVm->globals()->_config.invObjectsStill && !dialogVisible) {
- // If objects need to be animated, move to the next frame
- if (++_objectFrameNumber >= (_objectSprites->getCount() * INV_ANIM_FRAME_SPEED))
- _objectFrameNumber = 0;
- }
-
- // List the vocab actions for the currently selected object
- MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
- int yIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
-
- for (int i = 0; i < obj->vocabCount; ++i) {
- const Common::Rect r(_screenObjects[VOCAB_START + i]);
-
- // Get the vocab description and capitalise it
- const char *descStr = _madsVm->globals()->getVocab(obj->vocabList[i].vocabId);
- strcpy(buffer, descStr);
- if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
-
- // Set the highlighting and display the entry
- setFontMode((i == yIndex) ? ITEM_HIGHLIGHTED : ITEM_NORMAL);
- _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
- }
- }
-}
-
-bool MadsInterfaceView::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
- MadsAction &act = _madsVm->scene()->getAction();
-
- // If the mouse isn't being held down, then reset the repeated scroll timer
- if (eventType != MEVENT_LEFT_HOLD)
- _nextScrollerTicks = 0;
-
- // Handle various event types
- switch (eventType) {
- case MEVENT_MOVE:
- // If the cursor isn't in "wait mode", don't do any processing
- if (_vm->_mouse->getCursorNum() == CURSOR_WAIT)
- return true;
-
- // Ensure the cursor is the standard arrow
- _vm->_mouse->setCursorNum(CURSOR_ARROW);
-
- // Check if any interface element is currently highlighted
- _highlightedElement = _screenObjects.find(Common::Point(x, y));
-
- return true;
-
- case MEVENT_LEFT_CLICK:
- // Left mouse click
- {
- // Check if an inventory object was selected
- if ((_highlightedElement >= INVLIST_START) && (_highlightedElement < (INVLIST_START + 5))) {
- // Ensure there is an inventory item listed in that cell
- uint idx = _highlightedElement - INVLIST_START;
- if ((_topIndex + idx) < _inventoryList.size()) {
- // Set the selected object
- setSelectedObject(_inventoryList[_topIndex + idx]);
- }
- } else if ((_highlightedElement >= ACTIONS_START) && (_highlightedElement < (ACTIONS_START + 10))) {
- // A standard action was selected
- int verbId = kVerbLook + (_highlightedElement - ACTIONS_START);
- warning("Selected action #%d", verbId);
-
- } else if ((_highlightedElement >= VOCAB_START) && (_highlightedElement < (VOCAB_START + 5))) {
- // A vocab action was selected
- MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
- int vocabIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
- if (vocabIndex >= 0) {
- act._actionMode = ACTMODE_OBJECT;
- act._actionMode2 = ACTMODE2_2;
- act._flags1 = obj->vocabList[1].flags1;
- act._flags2 = obj->vocabList[1].flags2;
-
- act._currentHotspot = _selectedObject;
- act._articleNumber = act._flags2;
- }
- }
- }
- return true;
-
- case MEVENT_LEFT_HOLD:
- // Left mouse hold
- // Handle the scroller - the up/down buttons allow for multiple actions whilst the mouse is held down
- if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_DOWN)) {
- if ((_nextScrollerTicks == 0) || (g_system->getMillis() >= _nextScrollerTicks)) {
- // Handle scroll up/down action
- _nextScrollerTicks = g_system->getMillis() + SCROLLER_DELAY;
-
- if ((_highlightedElement == SCROLL_UP) && (_topIndex > 0))
- --_topIndex;
- if ((_highlightedElement == SCROLL_DOWN) && (_topIndex < (int)(_inventoryList.size() - 1)))
- ++_topIndex;
+ if (entry->field_1C) {
+ _abortTimedText = entry->field_1C;
+ //word_84208 = entry->field_1D;
+
+ if (entry->field_1D != 1) {
+ // Restore the action list
+ for (int i = 0; i < 3; ++i)
+ _madsVm->scene()->actionNouns[i] = entry->actionNouns[i];
}
}
- return true;
-
- case MEVENT_LEFT_DRAG:
- // Left mouse drag
- // Handle the the the scroller area that can be dragged to adjust the top displayed index
- if (_highlightedElement == SCROLL_SCROLLER) {
- // Calculate the new top index based on the Y position
- const Common::Rect r(_screenObjects[SCROLL_SCROLLER]);
- _topIndex = CLIP((int)(_inventoryList.size() - 1) * (y - r.top - 2) / (r.height() - 5),
- 0, (int)_inventoryList.size() - 1);
- }
- return true;
-
- case KEVENT_KEY:
- if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
- handleCheatKey(param1);
- handleKeypress(param1);
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-bool MadsInterfaceView::handleCheatKey(int32 keycode) {
- switch (keycode) {
- case Common::KEYCODE_SPACE:
- // TODO: Move player to current destination
- return true;
-
- case Common::KEYCODE_t | (Common::KEYCODE_LALT):
- case Common::KEYCODE_t | (Common::KEYCODE_RALT):
- {
- // Teleport to room
- //Scene *sceneView = (Scene *)vm->_viewManager->getView(VIEWID_SCENE);
-
-
- return true;
- }
-
- default:
- break;
- }
-
- return false;
-}
-
-const char *CHEAT_SEQUENCE = "widepipe";
-
-bool MadsInterfaceView::handleKeypress(int32 keycode) {
- int flags = keycode >> 24;
- int kc = keycode & 0xffff;
-
- // Capitalise the letter if necessary
- if (_cheatKeyCtr < CHEAT_SEQUENCE_MAX) {
- if ((flags & Common::KBD_CTRL) && (kc == CHEAT_SEQUENCE[_cheatKeyCtr])) {
- ++_cheatKeyCtr;
- if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
- Dialog::display(_vm, 22, cheatingEnabledDesc);
- return true;
- } else {
- _cheatKeyCtr = 0;
- }
}
- // Handle the various keys
- if ((keycode == Common::KEYCODE_ESCAPE) || (keycode == Common::KEYCODE_F1)) {
- // Game menu
- _madsVm->globals()->dialogType = DIALOG_GAME_MENU;
- leaveScene();
- return false;
- } else if (flags & Common::KBD_CTRL) {
- // Handling of the different control key combinations
- switch (kc) {
- case Common::KEYCODE_i:
- // Mouse to inventory
- warning("TODO: Mouse to inventory");
- break;
-
- case Common::KEYCODE_k:
- // Toggle hotspots
- warning("TODO: Toggle hotspots");
- break;
-
- case Common::KEYCODE_p:
- // Player stats
- warning("TODO: Player stats");
- break;
-
- case Common::KEYCODE_q:
- // Quit game
- break;
-
- case Common::KEYCODE_s:
- // Activate sound
- warning("TODO: Activate sound");
- break;
-
- case Common::KEYCODE_u:
- // Rotate player
- warning("TODO: Rotate player");
- break;
-
- case Common::KEYCODE_v: {
- // Release version
- Dialog *dlg = new Dialog(_vm, GameReleaseInfoStr, GameReleaseTitleStr);
- _vm->_viewManager->addView(dlg);
- _vm->_viewManager->moveToFront(dlg);
- return false;
- }
-
- default:
- break;
- }
- } else if ((flags & Common::KBD_ALT) && (kc == Common::KEYCODE_q)) {
- // Quit Game
-
- } else {
- // Standard keypresses
- switch (kc) {
- case Common::KEYCODE_F2:
- // Save game
- _madsVm->globals()->dialogType = DIALOG_SAVE;
- leaveScene();
- break;
- case Common::KEYCODE_F3:
- // Restore game
- _madsVm->globals()->dialogType = DIALOG_RESTORE;
- leaveScene();
- break;
- }
- }
-//DIALOG_OPTIONS
- return false;
-}
-
-void MadsInterfaceView::leaveScene() {
- // Close the scene
- View *view = _madsVm->_viewManager->getView(VIEWID_SCENE);
- _madsVm->_viewManager->deleteView(view);
+ // TODO: code from 'loc_244ec' onwards
}
+*/
} // End of namespace M4
diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h
index 0269de75c8..f7625bb761 100644
--- a/engines/m4/mads_scene.h
+++ b/engines/m4/mads_scene.h
@@ -33,24 +33,37 @@
namespace M4 {
#define INTERFACE_HEIGHT 106
-class MadsInterfaceView;
+
+struct SpriteSlot {
+ int16 spriteId;
+ int16 scale;
+ uint16 spriteListIndex;
+};
+
+struct DirtyArea {
+ bool active;
+ bool active2;
+ Common::Rect bounds;
+};
+
class MadsSceneResources: public SceneResources {
public:
int sceneId;
int artFileNum;
- int drawStyle;
+ int field_4;
int width;
int height;
- Common::Array<MadsObject> objects;
- Common::Array<Common::String> setNames;
+
+ int objectCount;
+ MadsObject objects[32];
- Common::Point playerPos;
- int playerDir;
+ int walkSize;
+ byte *walkData;
- MadsSceneResources() { playerDir = 0; }
- ~MadsSceneResources() {}
- void load(int sceneId, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface);
+ MadsSceneResources() { walkSize = 0; walkData = NULL; }
+ ~MadsSceneResources() { delete walkData; }
+ void load(int sceneId);
};
enum MadsActionMode {ACTMODE_NONE = 0, ACTMODE_VERB = 1, ACTMODE_OBJECT = 3, ACTMODE_TALK = 6};
@@ -88,15 +101,17 @@ public:
const char *statusText() const { return _statusText; }
};
+#define DIRTY_AREA_SIZE 90
+
class MadsScene : public Scene, public MadsView {
private:
MadsEngine *_vm;
MadsSceneResources _sceneResources;
MadsAction _action;
- Animation *_activeAnimation;
MadsSceneLogic _sceneLogic;
SpriteAsset *_playerSprites;
+ DirtyArea _dirtyAreas[DIRTY_AREA_SIZE];
void drawElements();
void loadScene2(const char *aaName);
@@ -128,7 +143,6 @@ public:
int loadSceneSpriteSet(const char *setName);
void loadPlayerSprites(const char *prefix);
void showMADSV2TextBox(char *text, int x, int y, char *faceName);
- void loadAnimation(const Common::String &animName, int v0);
MadsInterfaceView *getInterface() { return (MadsInterfaceView *)_interfaceSurface; }
MadsSceneResources &getSceneResources() { return _sceneResources; }
@@ -136,56 +150,6 @@ public:
void setStatusText(const char *text) {}//***DEPRECATED***
};
-#define CHEAT_SEQUENCE_MAX 8
-
-class IntegerList : public Common::Array<int> {
-public:
- int indexOf(int v) {
- for (uint i = 0; i < size(); ++i)
- if (operator [](i) == v)
- return i;
- return -1;
- }
-};
-
-enum InterfaceFontMode {ITEM_NORMAL, ITEM_HIGHLIGHTED, ITEM_SELECTED};
-
-enum InterfaceObjects {ACTIONS_START = 0, SCROLL_UP = 10, SCROLL_SCROLLER = 11, SCROLL_DOWN = 12,
- INVLIST_START = 13, VOCAB_START = 18};
-
-class MadsInterfaceView : public GameInterfaceView {
-private:
- IntegerList _inventoryList;
- RectList _screenObjects;
- int _highlightedElement;
- int _topIndex;
- uint32 _nextScrollerTicks;
- int _cheatKeyCtr;
-
- // Object display fields
- int _selectedObject;
- SpriteAsset *_objectSprites;
- RGBList *_objectPalData;
- int _objectFrameNumber;
-
- void setFontMode(InterfaceFontMode newMode);
- bool handleCheatKey(int32 keycode);
- bool handleKeypress(int32 keycode);
- void leaveScene();
-public:
- MadsInterfaceView(MadsM4Engine *vm);
- ~MadsInterfaceView();
-
- virtual void initialise();
- virtual void setSelectedObject(int objectNumber);
- virtual void addObjectToInventory(int objectNumber);
- int getSelectedObject() { return _selectedObject; }
- int getInventoryObject(int objectIndex) { return _inventoryList[objectIndex]; }
-
- void onRefresh(RectList *rects, M4Surface *destSurface);
- bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents);
-};
-
} // End of namespace M4
#endif
diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp
index c656db83f1..e50c35bc04 100644
--- a/engines/m4/mads_views.cpp
+++ b/engines/m4/mads_views.cpp
@@ -24,7 +24,6 @@
*/
#include "m4/m4_views.h"
-#include "m4/animation.h"
#include "m4/dialogs.h"
#include "m4/events.h"
#include "m4/font.h"
@@ -37,23 +36,14 @@
namespace M4 {
-bool MadsSpriteSlot::operator==(const SpriteSlotSubset &other) const {
- return (spriteListIndex == other.spriteListIndex) && (frameNumber == other.frameNumber) &&
- (xp == other.xp) && (yp == other.yp) && (depth == other.depth) && (scale == other.scale);
-}
-
-void MadsSpriteSlot::copy(const SpriteSlotSubset &other) {
- spriteListIndex = other.spriteListIndex;
- frameNumber = other.frameNumber;
- xp = other.xp;
- yp = other.yp;
- depth = other.depth;
- scale = other.scale;
-}
+static const int INV_ANIM_FRAME_SPEED = 2;
+static const int INVENTORY_X = 160;
+static const int INVENTORY_Y = 159;
+static const int SCROLLER_DELAY = 200;
//--------------------------------------------------------------------------
-MadsSpriteSlots::MadsSpriteSlots(MadsView &owner): _owner(owner) {
+MadsSpriteSlots::MadsSpriteSlots() {
for (int i = 0; i < SPRITE_SLOTS_SIZE; ++i) {
MadsSpriteSlot rec;
_entries.push_back(rec);
@@ -62,23 +52,6 @@ MadsSpriteSlots::MadsSpriteSlots(MadsView &owner): _owner(owner) {
startIndex = 0;
}
-MadsSpriteSlots::~MadsSpriteSlots() {
- for (uint i = 0; i < _sprites.size(); ++i)
- delete _sprites[i];
-}
-
-void MadsSpriteSlots::clear() {
- _owner._textDisplay.clear();
- for (uint i = 0; i < _sprites.size(); ++i)
- delete _sprites[i];
- _sprites.clear();
-
- // Reset the sprite slots list back to a single entry for a full screen refresh
- startIndex = 1;
- _entries[0].spriteType = FULL_SCREEN_REFRESH;
- _entries[0].seqIndex = -1;
-}
-
int MadsSpriteSlots::getIndex() {
if (startIndex == SPRITE_SLOTS_SIZE)
error("Run out of sprite slots");
@@ -91,31 +64,20 @@ int MadsSpriteSlots::addSprites(const char *resName) {
Common::SeekableReadStream *data = _vm->res()->get(resName);
SpriteAsset *spriteSet = new SpriteAsset(_vm, data, data->size(), resName);
spriteSet->translate(_madsVm->_palette);
- assert(spriteSet != NULL);
- _sprites.push_back(spriteSet);
+ _sprites.push_back(SpriteList::value_type(spriteSet));
_vm->res()->toss(resName);
return _sprites.size() - 1;
}
-void MadsSpriteSlots::deleteSprites(int listIndex) {
- if (listIndex < 0)
- return;
-
- delete _sprites[listIndex];
- _sprites[listIndex] = NULL;
- if (listIndex == ((int)_sprites.size() - 1))
- _sprites.remove_at(listIndex);
-}
-
/*
* Deletes the sprite slot with the given timer entry
*/
-void MadsSpriteSlots::deleteTimer(int seqIndex) {
+void MadsSpriteSlots::deleteTimer(int timerIndex) {
for (int idx = 0; idx < startIndex; ++idx) {
- if (_entries[idx].seqIndex == seqIndex)
- _entries[idx].spriteType = EXPIRED_SPRITE;
+ if (_entries[idx].timerIndex == timerIndex)
+ _entries[idx].spriteId = -1;
}
}
@@ -133,49 +95,12 @@ bool sortHelper(const DepthEntry &entry1, const DepthEntry &entry2) {
typedef Common::List<DepthEntry> DepthList;
-void MadsSpriteSlots::drawBackground() {
- // Draw all active sprites onto the background surface
- for (int i = 0; i < startIndex; ++i) {
- if (_entries[i].spriteType >= 0) {
- _owner._dirtyAreas[i].active = false;
- } else {
- _owner._dirtyAreas[i].textActive = true;
- _owner._dirtyAreas.setSpriteSlot(i, _entries[i]);
-
- if (_entries[i].spriteType == BACKGROUND_SPRITE) {
- SpriteAsset &spriteSet = getSprite(_entries[i].spriteListIndex);
- M4Sprite *frame = spriteSet.getFrame((_entries[i].frameNumber & 0x7fff) - 1);
- int xp = _entries[i].xp;
- int yp = _entries[i].yp;
-
- if (_entries[i].scale != -1) {
- // Adjust position based on frame size
- xp -= frame->width() / 2;
- yp -= frame->height() / 2;
- }
-
- if (_entries[i].depth <= 1) {
- // No depth, so simply copy the frame onto the background
- frame->copyTo(_owner._bgSurface, xp, yp);
- } else {
- // Depth was specified, so draw frame using scene's depth information
- frame->copyTo(_owner._bgSurface, xp, yp, _entries[i].depth, _owner._depthSurface, 100);
- }
- }
- }
- }
-
- // Flag any remaining dirty areas as inactive
- for (uint i = startIndex; i < DIRTY_AREAS_TEXT_DISPLAY_IDX; ++i)
- _owner._dirtyAreas[i].active = false;
-}
-
-void MadsSpriteSlots::drawForeground(View *view) {
+void MadsSpriteSlots::draw(View *view) {
DepthList depthList;
// Get a list of sprite object depths for active objects
for (int i = 0; i < startIndex; ++i) {
- if (_entries[i].spriteType >= 0) {
+ if (_entries[i].spriteId >= 0) {
DepthEntry rec(_entries[i].depth, i);
depthList.push_back(rec);
}
@@ -190,57 +115,34 @@ void MadsSpriteSlots::drawForeground(View *view) {
DepthEntry &de = *i;
MadsSpriteSlot &slot = _entries[de.index];
assert(slot.spriteListIndex < (int)_sprites.size());
- SpriteAsset &spriteSet = *_sprites[slot.spriteListIndex];
+ SpriteAsset &spriteSet = *_sprites[slot.spriteListIndex].get();
if (slot.scale < 100) {
// Minimalised drawing
assert(slot.spriteListIndex < (int)_sprites.size());
M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1);
- spr->copyTo(view, slot.xp, slot.yp, slot.depth, _owner._depthSurface, slot.scale, 0);
+ spr->draw1(view, slot.scale, slot.depth, slot.xp, slot.yp);
} else {
int xp, yp;
M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1);
if (slot.scale == -1) {
- xp = slot.xp - _owner._posAdjust.x;
- yp = slot.yp - _owner._posAdjust.y;
+ xp = slot.xp; // - widthAdjust;
+ yp = slot.yp; // - heightAdjust;
} else {
- xp = slot.xp - (spr->width() / 2) - _owner._posAdjust.x;
- yp = slot.yp - spr->height() - _owner._posAdjust.y + 1;
+ xp = slot.xp - (spr->width() / 2); // - widthAdjust;
+ yp = slot.yp - spr->height() + 1; // - heightAdjust;
}
if (slot.depth > 1) {
- // Draw the frame with depth processing
- spr->copyTo(view, xp, yp, slot.depth, _owner._depthSurface, 100, 0);
+ spr->draw2(view, slot.depth, xp, yp);
} else {
- // No depth, so simply draw the image
- spr->copyTo(view, xp, yp, 0);
+ spr->draw3(view, xp, yp);
}
}
}
}
-void MadsSpriteSlots::setDirtyAreas() {
- for (int i = 0; i < startIndex; ++i) {
- if (_entries[i].spriteType >= 0) {
- _owner._dirtyAreas.setSpriteSlot(i, _entries[i]);
-
- _owner._dirtyAreas[i].textActive = (_entries[i].spriteType <= 0) ? 0 : 1;
- _entries[i].spriteType = 0;
- }
- }
-}
-
-/**
- * Flags the entire screen to be redrawn during the next drawing cycle
- */
-void MadsSpriteSlots::fullRefresh() {
- int idx = getIndex();
-
- _entries[idx].spriteType = FULL_SCREEN_REFRESH;
- _entries[idx].seqIndex = -1;
-}
-
/**
* Removes any sprite slots that are no longer needed
*/
@@ -248,7 +150,7 @@ void MadsSpriteSlots::cleanUp() {
// Delete any entries that aren't needed
int idx = 0;
while (idx < startIndex) {
- if (_entries[idx].spriteType < 0) {
+ if (_entries[idx].spriteId >= 0) {
_entries.remove_at(idx);
--startIndex;
} else {
@@ -266,7 +168,7 @@ void MadsSpriteSlots::cleanUp() {
//--------------------------------------------------------------------------
-MadsTextDisplay::MadsTextDisplay(MadsView &owner): _owner(owner) {
+MadsTextDisplay::MadsTextDisplay() {
for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) {
MadsTextDisplayEntry rec;
rec.active = false;
@@ -304,32 +206,11 @@ int MadsTextDisplay::add(int xp, int yp, uint fontColour, int charSpacing, const
return usedSlot;
}
-void MadsTextDisplay::setDirtyAreas() {
- // Determine dirty areas for active text areas
- for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) {
- if ((_entries[idx].expire < 0) || !_entries[idx].active)
- _owner._dirtyAreas[dirtyIdx].active = false;
- else {
- _owner._dirtyAreas[dirtyIdx].textActive = true;
- _owner._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]);
- }
- }
-}
-
-void MadsTextDisplay::setDirtyAreas2() {
- // Determine dirty areas for active text areas
- for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) {
- if (_entries[idx].active && (_entries[idx].expire >= 0)) {
- _owner._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]);
- _owner._dirtyAreas[dirtyIdx].textActive = (_entries[idx].expire <= 0) ? 0 : 1;
- }
- }
-}
-
void MadsTextDisplay::draw(View *view) {
for (uint idx = 0; idx < _entries.size(); ++idx) {
if (_entries[idx].active && (_entries[idx].expire >= 0)) {
- _entries[idx].font->setColours(_entries[idx].colour1, _entries[idx].colour2, 0);
+ _entries[idx].font->setColours(_entries[idx].colour1,
+ (_entries[idx].colour2 == 0) ? _entries[idx].colour1 : _entries[idx].colour2, 0xff);
_entries[idx].font->writeString(view, _entries[idx].msg,
_entries[idx].bounds.left, _entries[idx].bounds.top, _entries[idx].bounds.width(),
_entries[idx].spacing);
@@ -361,13 +242,12 @@ void MadsTextDisplay::cleanUp() {
MadsKernelMessageList::MadsKernelMessageList(MadsView &owner): _owner(owner) {
for (int i = 0; i < TIMED_TEXT_SIZE; ++i) {
- MadsKernelMessageEntry rec;
+ MadsKernelMessageListEntry rec;
_entries.push_back(rec);
}
_owner._textSpacing = -1;
_talkFont = _vm->_font->getFont(FONT_CONVERSATION_MADS);
- word_8469E = 0;
}
void MadsKernelMessageList::clear() {
@@ -378,20 +258,20 @@ void MadsKernelMessageList::clear() {
_talkFont = _vm->_font->getFont(FONT_CONVERSATION_MADS);
}
-int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 abortTimers, uint32 timeout, const char *msg) {
+int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 v2, uint32 timeout, const char *msg) {
// Find a free slot
uint idx = 0;
while ((idx < _entries.size()) && ((_entries[idx].flags & KMSG_ACTIVE) != 0))
++idx;
if (idx == _entries.size()) {
- if (abortTimers == 0)
+ if (v2 == 0)
return -1;
error("MadsKernelList overflow");
}
- MadsKernelMessageEntry &rec = _entries[idx];
- strcpy(rec.msg, msg);
+ MadsKernelMessageListEntry &rec = _entries[idx];
+ rec.msg = msg;
rec.flags = flags | KMSG_ACTIVE;
rec.colour1 = fontColour & 0xff;
rec.colour2 = fontColour >> 8;
@@ -399,37 +279,37 @@ int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 f
rec.textDisplayIndex = -1;
rec.timeout = timeout;
rec.frameTimer = _madsVm->_currentTimer;
- rec.abortTimers = abortTimers;
+ rec.field_1C = v2;
rec.abortMode = _owner._abortTimersMode2;
for (int i = 0; i < 3; ++i)
rec.actionNouns[i] = _madsVm->scene()->actionNouns[i];
- if (flags & KMSG_OWNER_TIMEOUT)
+ if (flags & KMSG_2)
rec.frameTimer = _owner._ticksAmount + _owner._newTimeout;
return idx;
}
-int MadsKernelMessageList::addQuote(int quoteId, int abortTimers, uint32 timeout) {
+int MadsKernelMessageList::addQuote(int quoteId, int v2, uint32 timeout) {
const char *quoteStr = _madsVm->globals()->getQuote(quoteId);
- return add(Common::Point(0, 0), 0x1110, KMSG_OWNER_TIMEOUT | KMSG_CENTER_ALIGN, abortTimers, timeout, quoteStr);
+ return add(Common::Point(0, 0), 0x1110, KMSG_2 | KMSG_20, v2, timeout, quoteStr);
}
-void MadsKernelMessageList::scrollMessage(int msgIndex, int numTicks, bool quoted) {
+void MadsKernelMessageList::unk1(int msgIndex, int v1, int v2) {
if (msgIndex < 0)
return;
- _entries[msgIndex].flags |= quoted ? (KMSG_SCROLL | KMSG_QUOTED) : KMSG_SCROLL;
+ _entries[msgIndex].flags |= (v2 == 0) ? KMSG_8 : (KMSG_8 | KMSG_1);
_entries[msgIndex].msgOffset = 0;
- _entries[msgIndex].numTicks = numTicks;
+ _entries[msgIndex].field_E = v1;
_entries[msgIndex].frameTimer2 = _madsVm->_currentTimer;
const char *msgP = _entries[msgIndex].msg;
_entries[msgIndex].asciiChar = *msgP;
_entries[msgIndex].asciiChar2 = *(msgP + 1);
- if (_entries[msgIndex].flags & KMSG_OWNER_TIMEOUT)
+ if (_entries[msgIndex].flags & KMSG_2)
_entries[msgIndex].frameTimer2 = _owner._ticksAmount + _owner._newTimeout;
_entries[msgIndex].frameTimer = _entries[msgIndex].frameTimer2;
@@ -437,18 +317,18 @@ void MadsKernelMessageList::scrollMessage(int msgIndex, int numTicks, bool quote
void MadsKernelMessageList::setSeqIndex(int msgIndex, int seqIndex) {
if (msgIndex >= 0) {
- _entries[msgIndex].flags |= KMSG_SEQ_ENTRY;
+ _entries[msgIndex].flags |= KMSG_4;
_entries[msgIndex].sequenceIndex = seqIndex;
}
}
void MadsKernelMessageList::remove(int msgIndex) {
- MadsKernelMessageEntry &rec = _entries[msgIndex];
+ MadsKernelMessageListEntry &rec = _entries[msgIndex];
if (rec.flags & KMSG_ACTIVE) {
- if (rec.flags & KMSG_SCROLL) {
- *(rec.msg + rec.msgOffset) = rec.asciiChar;
- *(rec.msg + rec.msgOffset + 1) = rec.asciiChar2;
+ if (rec.flags & KMSG_8) {
+ //*(rec.msg + rec.msgOffset) = rec.asciiChar;
+ //*(rec.msg + rec.msgOffset + 1) = rec.asciiChar2;
}
if (rec.textDisplayIndex >= 0)
@@ -465,136 +345,6 @@ void MadsKernelMessageList::reset() {
// sub_20454
}
-void MadsKernelMessageList::update() {
- uint32 currentTimer = _madsVm->_currentTimer;
-
- for (uint i = 0; i < _entries.size(); ++i) {
- if (((_entries[i].flags & KMSG_ACTIVE) != 0) && (currentTimer >= _entries[i].frameTimer))
- processText(i);
- }
-}
-
-void MadsKernelMessageList::processText(int msgIndex) {
- MadsKernelMessageEntry &msg = _entries[msgIndex];
- uint32 currentTimer = _madsVm->_currentTimer;
- bool flag = false;
-
- if ((msg.flags & KMSG_EXPIRE) != 0) {
- _owner._textDisplay.expire(msg.textDisplayIndex);
- msg.flags &= !KMSG_ACTIVE;
- return;
- }
-
- if ((msg.flags & KMSG_SCROLL) == 0) {
- msg.timeout -= 3;
- }
-
- if (msg.flags & KMSG_SEQ_ENTRY) {
- MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex];
- if (seqEntry.doneFlag || !seqEntry.active)
- msg.timeout = 0;
- }
-
- if ((msg.timeout <= 0) && (_owner._abortTimers == 0)) {
- msg.flags |= KMSG_EXPIRE;
- if (msg.abortTimers != 0) {
- _owner._abortTimers = msg.abortTimers;
- _owner._abortTimersMode = msg.abortMode;
-
- if (_owner._abortTimersMode != ABORTMODE_1) {
- for (int i = 0; i < 3; ++i)
- _madsVm->scene()->actionNouns[i] = msg.actionNouns[i];
- }
- }
- }
-
- msg.frameTimer = currentTimer + 3;
- int x1 = 0, y1 = 0;
-
- if (msg.flags & KMSG_SEQ_ENTRY) {
- MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex];
- if (!seqEntry.nonFixed) {
- SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex);
- M4Sprite *frame = spriteSet.getFrame(seqEntry.frameIndex - 1);
- x1 = frame->bounds().left;
- y1 = frame->bounds().top;
- } else {
- x1 = seqEntry.msgPos.x;
- y1 = seqEntry.msgPos.y;
- }
- }
-
- if (msg.flags & KMSG_OWNER_TIMEOUT) {
- if (word_8469E != 0) {
- // TODO: Figure out various flags
- } else {
- x1 = 160;
- y1 = 78;
- }
- }
-
- x1 += msg.position.x;
- y1 += msg.position.y;
-
- if ((msg.flags & KMSG_SCROLL) && (msg.frameTimer >= currentTimer)) {
- msg.msg[msg.msgOffset] = msg.asciiChar;
- char *msgP = &msg.msg[++msg.msgOffset];
- *msgP = msg.asciiChar2;
-
- msg.asciiChar = *msgP;
- msg.asciiChar2 = *(msgP + 1);
-
- if (!msg.asciiChar) {
- // End of message
- *msgP = '\0';
- msg.flags &= ~KMSG_SCROLL;
- } else if (msg.flags & KMSG_QUOTED) {
- *msgP = '"';
- *(msgP + 1) = '\0';
- }
-
- msg.frameTimer = msg.frameTimer2 = currentTimer + msg.numTicks;
- flag = true;
- }
-
- int strWidth = _talkFont->getWidth(msg.msg, _owner._textSpacing);
-
- if (msg.flags & (KMSG_RIGHT_ALIGN | KMSG_CENTER_ALIGN)) {
- x1 -= (msg.flags & KMSG_CENTER_ALIGN) ? strWidth / 2 : strWidth;
- }
-
- // Make sure text appears entirely on-screen
- int x2 = x1 + strWidth;
- if (x2 > MADS_SURFACE_WIDTH)
- x1 -= x2 - MADS_SURFACE_WIDTH;
- if (x1 > (MADS_SURFACE_WIDTH - 1))
- x1 = MADS_SURFACE_WIDTH - 1;
- if (x1 < 0)
- x1 = 0;
-
- if (y1 > (MADS_SURFACE_HEIGHT - 1))
- y1 = MADS_SURFACE_HEIGHT - 1;
- if (y1 < 0)
- y1 = 0;
-
- if (msg.textDisplayIndex >= 0) {
- MadsTextDisplayEntry textEntry = _owner._textDisplay[msg.textDisplayIndex];
-
- if (flag || (textEntry.bounds.left != x1) || (textEntry.bounds.top != y1)) {
- // Mark the associated text entry as deleted, so it can be re-created
- _owner._textDisplay.expire(msg.textDisplayIndex);
- msg.textDisplayIndex = -1;
- }
- }
-
- if (msg.textDisplayIndex < 0) {
- // Need to create a new text display entry for this message
- int idx = _owner._textDisplay.add(x1, y1, msg.colour1 | (msg.colour2 << 8), _owner._textSpacing, msg.msg, _talkFont);
- if (idx >= 0)
- msg.textDisplayIndex = idx;
- }
-}
-
//--------------------------------------------------------------------------
/**
@@ -655,23 +405,21 @@ MadsDynamicHotspots::MadsDynamicHotspots(MadsView &owner): _owner(owner) {
for (int i = 0; i < DYNAMIC_HOTSPOTS_SIZE; ++i) {
DynamicHotspot rec;
rec.active = false;
- _entries.push_back(rec);
}
_flag = true;
_count = 0;
}
-int MadsDynamicHotspots::add(int descId, int field14, int seqIndex, const Common::Rect &bounds) {
+int MadsDynamicHotspots::add(int descId, int field14, int timerIndex, const Common::Rect &bounds) {
// Find a free slot
uint idx = 0;
- while ((idx < _entries.size()) && _entries[idx].active)
+ while ((idx < _entries.size()) && !_entries[idx].active)
++idx;
if (idx == _entries.size())
error("MadsDynamicHotspots overflow");
_entries[idx].active = true;
_entries[idx].descId = descId;
- _entries[idx].seqIndex = seqIndex;
_entries[idx].bounds = bounds;
_entries[idx].pos.x = -3;
_entries[idx].pos.y = 0;
@@ -682,9 +430,7 @@ int MadsDynamicHotspots::add(int descId, int field14, int seqIndex, const Common
++_count;
_flag = true;
-
- if (seqIndex >= 0)
- _owner._sequenceList[seqIndex].dynamicHotspotIndex = idx;
+ _owner._sequenceList[timerIndex].dynamicHotspotIndex = idx;
return idx;
}
@@ -708,8 +454,8 @@ int MadsDynamicHotspots::set17(int index, int v) {
void MadsDynamicHotspots::remove(int index) {
if (_entries[index].active) {
- if (_entries[index].seqIndex >= 0)
- _owner._sequenceList[_entries[index].seqIndex].dynamicHotspotIndex = -1;
+ if (_entries[index].timerIndex >= 0)
+ _owner._sequenceList[_entries[index].timerIndex].dynamicHotspotIndex = -1;
_entries[index].active = false;
--_count;
@@ -727,143 +473,6 @@ void MadsDynamicHotspots::reset() {
/*--------------------------------------------------------------------------*/
-void MadsDirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) {
- if (bounds.left % 2) {
- --bounds.left;
- ++width;
- }
- int right = bounds.left + width;
- if (bounds.left < 0)
- bounds.left = 0;
- if (right < 0)
- right = 0;
- if (right > maxWidth)
- right = maxWidth;
-
- bounds.right = right;
- bounds2.left = bounds.width() / 2;
- bounds2.right = bounds.left + (bounds.width() + 1) / 2 - 1;
-
- if (bounds.top < 0)
- bounds.top = 0;
- int bottom = bounds.top + height;
- if (bottom < 0)
- bottom = 0;
- if (bottom > maxHeight)
- bottom = maxHeight;
-
- bounds.bottom = bottom;
- bounds2.top = bounds.height() / 2;
- bounds2.bottom = bounds.top + (bounds.height() + 1) / 2 - 1;
-
- active = true;
-}
-
-/*--------------------------------------------------------------------------*/
-
-MadsDirtyAreas::MadsDirtyAreas(MadsView &owner): _owner(owner) {
- for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) {
- MadsDirtyArea rec;
- rec.active = false;
- _entries.push_back(rec);
- }
-}
-
-void MadsDirtyAreas::setSpriteSlot(int dirtyIdx, const MadsSpriteSlot &spriteSlot) {
- int width, height;
- MadsDirtyArea &dirtyArea = _entries[dirtyIdx];
-
- if (spriteSlot.spriteType == FULL_SCREEN_REFRESH) {
- // Special entry to refresh the entire screen
- dirtyArea.bounds.left = 0;
- dirtyArea.bounds.top = 0;
- width = MADS_SURFACE_WIDTH;
- height = MADS_SURFACE_HEIGHT;
- } else {
- // Standard sprite slots
- dirtyArea.bounds.left = spriteSlot.xp - _owner._posAdjust.x;
- dirtyArea.bounds.top = spriteSlot.yp - _owner._posAdjust.y;
-
- SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(spriteSlot.spriteListIndex);
- M4Sprite *frame = spriteSet.getFrame(((spriteSlot.frameNumber & 0x7fff) - 1) & 0x7f);
-
- if (spriteSlot.scale == -1) {
- width = frame->width();
- height = frame->height();
- } else {
- width = frame->width() * spriteSlot.scale / 100;
- height = frame->height() * spriteSlot.scale / 100;
-
- dirtyArea.bounds.left -= width / 2;
- dirtyArea.bounds.top += -(height - 1);
- }
- }
-
- dirtyArea.setArea(width, height, MADS_SURFACE_WIDTH, MADS_SURFACE_HEIGHT);
-}
-
-void MadsDirtyAreas::setTextDisplay(int dirtyIdx, const MadsTextDisplayEntry &textDisplay) {
- MadsDirtyArea &dirtyArea = _entries[dirtyIdx];
- dirtyArea.bounds.left = textDisplay.bounds.left;
- dirtyArea.bounds.top = textDisplay.bounds.top;
-
- dirtyArea.setArea(textDisplay.bounds.width(), textDisplay.bounds.height(), MADS_SURFACE_WIDTH, MADS_SURFACE_HEIGHT);
-}
-
-/**
- * Merge together any designated dirty areas that overlap
- * @param startIndex 1-based starting dirty area starting index
- * @param count Number of entries to process
- */
-void MadsDirtyAreas::merge(int startIndex, int count) {
- if (startIndex >= count)
- return;
-
- for (int outerCtr = startIndex - 1, idx = 0; idx < count; ++outerCtr, ++idx) {
- if (!_entries[outerCtr].active)
- continue;
-
- for (int innerCtr = outerCtr + 1; innerCtr < count; ++innerCtr) {
- if (!_entries[innerCtr].active || !intersects(outerCtr, innerCtr))
- continue;
-
- if (_entries[outerCtr].textActive && _entries[innerCtr].textActive)
- mergeAreas(outerCtr, innerCtr);
- }
- }
-}
-
-/**
- * Returns true if two dirty areas intersect
- */
-bool MadsDirtyAreas::intersects(int idx1, int idx2) {
- return _entries[idx1].bounds2.intersects(_entries[idx2].bounds2);
-}
-
-void MadsDirtyAreas::mergeAreas(int idx1, int idx2) {
- MadsDirtyArea &da1 = _entries[idx1];
- MadsDirtyArea &da2 = _entries[idx2];
-
- da1.bounds.extend(da2.bounds);
-
- da1.bounds2.left = da1.bounds.width() / 2;
- da1.bounds2.right = da1.bounds.left + (da1.bounds.width() + 1) / 2 - 1;
- da1.bounds2.top = da1.bounds.height() / 2;
- da1.bounds2.bottom = da1.bounds.top + (da1.bounds.height() + 1) / 2 - 1;
-
- da2.active = false;
- da1.textActive = true;
-}
-
-void MadsDirtyAreas::copy(M4Surface *dest, M4Surface *src) {
- for (uint i = 0; i < _entries.size(); ++i) {
- if (_entries[i].active && _entries[i].bounds.isValidRect())
- src->copyTo(dest, _entries[i].bounds, _entries[i].bounds.left, _entries[i].bounds.top);
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
MadsSequenceList::MadsSequenceList(MadsView &owner): _owner(owner) {
for (int i = 0; i < TIMER_LIST_SIZE; ++i) {
MadsSequenceEntry rec;
@@ -893,14 +502,14 @@ bool MadsSequenceList::addSubEntry(int index, SequenceSubEntryMode mode, int fra
}
int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int triggerCountdown, int delayTicks, int extraTicks, int numTicks,
- int msgX, int msgY, bool nonFixed, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites,
+ int height, int width, char field_12, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites,
int frameStart) {
// Find a free slot
- uint seqIndex = 0;
- while ((seqIndex < _entries.size()) && (_entries[seqIndex].active))
- ++seqIndex;
- if (seqIndex == _entries.size())
+ uint timerIndex = 0;
+ while ((timerIndex < _entries.size()) && (_entries[timerIndex].active))
+ ++timerIndex;
+ if (timerIndex == _entries.size())
error("TimerList full");
if (frameStart <= 0)
@@ -911,76 +520,77 @@ int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int trigg
frameInc = 0;
// Set the list entry fields
- _entries[seqIndex].active = true;
- _entries[seqIndex].spriteListIndex = spriteListIndex;
- _entries[seqIndex].field_2 = v0;
- _entries[seqIndex].frameIndex = frameIndex;
- _entries[seqIndex].frameStart = frameStart;
- _entries[seqIndex].numSprites = numSprites;
- _entries[seqIndex].animType = animType;
- _entries[seqIndex].frameInc = frameInc;
- _entries[seqIndex].depth = depth;
- _entries[seqIndex].scale = scale;
- _entries[seqIndex].nonFixed = nonFixed;
- _entries[seqIndex].msgPos.x = msgX;
- _entries[seqIndex].msgPos.y = msgY;
- _entries[seqIndex].numTicks = numTicks;
- _entries[seqIndex].extraTicks = extraTicks;
-
- _entries[seqIndex].timeout = _madsVm->_currentTimer + delayTicks;
-
- _entries[seqIndex].triggerCountdown = triggerCountdown;
- _entries[seqIndex].doneFlag = false;
- _entries[seqIndex].field_13 = 0;
- _entries[seqIndex].dynamicHotspotIndex = -1;
- _entries[seqIndex].entries.count = 0;
- _entries[seqIndex].abortMode = _owner._abortTimersMode2;
+ _entries[timerIndex].active = true;
+ _entries[timerIndex].spriteListIndex = spriteListIndex;
+ _entries[timerIndex].field_2 = v0;
+ _entries[timerIndex].frameIndex = frameIndex;
+ _entries[timerIndex].frameStart = frameStart;
+ _entries[timerIndex].numSprites = numSprites;
+ _entries[timerIndex].animType = animType;
+ _entries[timerIndex].frameInc = frameInc;
+ _entries[timerIndex].depth = depth;
+ _entries[timerIndex].scale = scale;
+ _entries[timerIndex].field_12 = field_12;
+ _entries[timerIndex].width = width;
+ _entries[timerIndex].height = height;
+ _entries[timerIndex].numTicks = numTicks;
+ _entries[timerIndex].extraTicks = extraTicks;
+
+ _entries[timerIndex].timeout = _madsVm->_currentTimer + delayTicks;
+
+ _entries[timerIndex].triggerCountdown = triggerCountdown;
+ _entries[timerIndex].doneFlag = false;
+ _entries[timerIndex].field_13 = 0;
+ _entries[timerIndex].dynamicHotspotIndex = -1;
+ _entries[timerIndex].entries.count = 0;
+ _entries[timerIndex].abortMode = _owner._abortTimersMode2;
for (int i = 0; i < 3; ++i)
- _entries[seqIndex].actionNouns[i] = _madsVm->scene()->actionNouns[i];
+ _entries[timerIndex].actionNouns[i] = _madsVm->scene()->actionNouns[i];
- return seqIndex;
+ return timerIndex;
}
-void MadsSequenceList::remove(int seqIndex) {
- if (_entries[seqIndex].active) {
- if (_entries[seqIndex].dynamicHotspotIndex >= 0)
- _owner._dynamicHotspots.remove(_entries[seqIndex].dynamicHotspotIndex);
+void MadsSequenceList::remove(int timerIndex) {
+ if (_entries[timerIndex].active) {
+ if (_entries[timerIndex].dynamicHotspotIndex >= 0)
+ _owner._dynamicHotspots.remove(_entries[timerIndex].dynamicHotspotIndex);
}
- _entries[seqIndex].active = false;
- _owner._spriteSlots.deleteTimer(seqIndex);
+ _entries[timerIndex].active = false;
+ _owner._spriteSlots.deleteTimer(timerIndex);
}
-void MadsSequenceList::setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot) {
- MadsSequenceEntry &timerEntry = _entries[seqIndex];
+void MadsSequenceList::setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot) {
+ MadsSequenceEntry &timerEntry = _entries[timerIndex];
SpriteAsset &sprite = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex);
- spriteSlot.spriteType = sprite.getAssetType() == 1 ? BACKGROUND_SPRITE : FOREGROUND_SPRITE;
- spriteSlot.seqIndex = seqIndex;
+ // TODO: Figure out logic for spriteId value based on SPRITE_SLOT.field_0
+ spriteSlot.spriteId = (0 /*field 0*/ == 1) ? -4 : 1;
+ spriteSlot.timerIndex = timerIndex;
spriteSlot.spriteListIndex = timerEntry.spriteListIndex;
spriteSlot.frameNumber = ((timerEntry.field_2 == 1) ? 0x8000 : 0) | timerEntry.frameIndex;
spriteSlot.depth = timerEntry.depth;
spriteSlot.scale = timerEntry.scale;
- if (!timerEntry.nonFixed) {
- spriteSlot.xp = timerEntry.msgPos.x;
- spriteSlot.yp = timerEntry.msgPos.y;
+ if (timerEntry.field_12 == 0) {
+ spriteSlot.xp = timerEntry.width;
+ spriteSlot.yp = timerEntry.height;
} else {
spriteSlot.xp = sprite.getFrame(timerEntry.frameIndex - 1)->x;
spriteSlot.yp = sprite.getFrame(timerEntry.frameIndex - 1)->y;
}
}
-bool MadsSequenceList::loadSprites(int seqIndex) {
- MadsSequenceEntry &seqEntry = _entries[seqIndex];
+bool MadsSequenceList::loadSprites(int timerIndex) {
+ MadsSequenceEntry &seqEntry = _entries[timerIndex];
int slotIndex;
bool result = false;
int idx = -1;
- _owner._spriteSlots.deleteTimer(seqIndex);
+ _owner._spriteSlots.deleteTimer(timerIndex);
if (seqEntry.doneFlag) {
- remove(seqIndex);
+ remove(timerIndex);
return false;
}
@@ -989,7 +599,7 @@ bool MadsSequenceList::loadSprites(int seqIndex) {
seqEntry.doneFlag = true;
} else if ((slotIndex = _owner._spriteSlots.getIndex()) >= 0) {
MadsSpriteSlot &spriteSlot = _owner._spriteSlots[slotIndex];
- setSpriteSlot(seqIndex, spriteSlot);
+ setSpriteSlot(timerIndex, spriteSlot);
int x2 = 0, y2 = 0;
@@ -1117,108 +727,454 @@ void MadsSequenceList::delay(uint32 v1, uint32 v2) {
}
}
-void MadsSequenceList::setAnimRange(int seqIndex, int startVal, int endVal) {
- MadsSequenceEntry &seqEntry = _entries[seqIndex];
- SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex);
- int numSprites = spriteSet.getCount();
- int tempStart = startVal, tempEnd = endVal;
+//--------------------------------------------------------------------------
- switch (startVal) {
- case -2:
- tempStart = numSprites;
- break;
- case -1:
- tempStart = 1;
- break;
- }
-
- switch (endVal) {
- case -2:
- case 0:
- tempEnd = numSprites;
+MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this),
+ _kernelMessages(*this) {
+ _textSpacing = -1;
+ _ticksAmount = 3;
+ _newTimeout = 0;
+ _abortTimers = 0;
+ _abortTimers2 = 0;
+ _abortTimersMode = ABORTMODE_0;
+ _abortTimersMode2 = ABORTMODE_0;
+}
+
+void MadsView::refresh() {
+ // Draw any sprites
+ _spriteSlots.draw(_view);
+
+ // Draw text elements onto the view
+ _textDisplay.draw(_view);
+
+ // Remove any sprite slots that are no longer needed
+ _spriteSlots.cleanUp();
+
+ // Deactivate any text display entries that are no longer needed
+ _textDisplay.cleanUp();
+}
+
+/*--------------------------------------------------------------------------
+ * MadsInterfaceView handles the user interface section at the bottom of
+ * game screens in MADS games
+ *--------------------------------------------------------------------------
+ */
+
+MadsInterfaceView::MadsInterfaceView(MadsM4Engine *vm): GameInterfaceView(vm,
+ Common::Rect(0, MADS_SURFACE_HEIGHT, vm->_screen->width(), vm->_screen->height())) {
+ _screenType = VIEWID_INTERFACE;
+ _highlightedElement = -1;
+ _topIndex = 0;
+ _selectedObject = -1;
+ _cheatKeyCtr = 0;
+
+ _objectSprites = NULL;
+ _objectPalData = NULL;
+
+ /* Set up the rect list for screen elements */
+ // Actions
+ for (int i = 0; i < 10; ++i)
+ _screenObjects.addRect((i / 5) * 32 + 1, (i % 5) * 8 + MADS_SURFACE_HEIGHT + 2,
+ ((i / 5) + 1) * 32 + 3, ((i % 5) + 1) * 8 + MADS_SURFACE_HEIGHT + 2);
+
+ // Scroller elements (up arrow, scroller, down arrow)
+ _screenObjects.addRect(73, 160, 82, 167);
+ _screenObjects.addRect(73, 168, 82, 190);
+ _screenObjects.addRect(73, 191, 82, 198);
+
+ // Inventory object names
+ for (int i = 0; i < 5; ++i)
+ _screenObjects.addRect(89, 158 + i * 8, 160, 166 + i * 8);
+
+ // Full rectangle area for all vocab actions
+ for (int i = 0; i < 5; ++i)
+ _screenObjects.addRect(239, 158 + i * 8, 320, 166 + i * 8);
+}
+
+MadsInterfaceView::~MadsInterfaceView() {
+ delete _objectSprites;
+}
+
+void MadsInterfaceView::setFontMode(InterfaceFontMode newMode) {
+ switch (newMode) {
+ case ITEM_NORMAL:
+ _vm->_font->setColors(4, 4, 0xff);
break;
- case -1:
- tempEnd = 1;
+ case ITEM_HIGHLIGHTED:
+ _vm->_font->setColors(5, 5, 0xff);
break;
- default:
- tempEnd = numSprites;
+ case ITEM_SELECTED:
+ _vm->_font->setColors(6, 6, 0xff);
break;
}
+}
- seqEntry.frameStart = tempStart;
- seqEntry.numSprites = tempEnd;
+void MadsInterfaceView::initialise() {
+ // Build up the inventory list
+ _inventoryList.clear();
+
+ for (uint i = 0; i < _madsVm->globals()->getObjectsSize(); ++i) {
+ MadsObject *obj = _madsVm->globals()->getObject(i);
+ if (obj->roomNumber == PLAYER_INVENTORY)
+ _inventoryList.push_back(i);
+ }
- seqEntry.frameIndex = (seqEntry.frameInc < 0) ? tempStart : tempEnd;
+ // If the inventory has at least one object, select it
+ if (_inventoryList.size() > 0)
+ setSelectedObject(_inventoryList[0]);
}
-void MadsSequenceList::scan() {
- for (uint i = 0; i < _entries.size(); ++i) {
- if (!_entries[i].active && (_entries[i].spriteListIndex != -1)) {
- int idx = _owner._spriteSlots.getIndex();
- setSpriteSlot(i, _owner._spriteSlots[idx]);
- }
+void MadsInterfaceView::setSelectedObject(int objectNumber) {
+ char resName[80];
+
+ // Load inventory resource
+ if (_objectSprites) {
+ _vm->_palette->deleteRange(_objectPalData);
+ delete _objectSprites;
}
+
+ // Check to make sure the object is in the inventory, and also visible on-screen
+ int idx = _inventoryList.indexOf(objectNumber);
+ if (idx == -1) {
+ // Object wasn't found, so return
+ _selectedObject = -1;
+ return;
+ }
+
+ // Found the object
+ if (idx < _topIndex)
+ _topIndex = idx;
+ else if (idx >= (_topIndex + 5))
+ _topIndex = MAX(0, idx - 4);
+
+ _selectedObject = objectNumber;
+ sprintf(resName, "*OB%.3dI.SS", objectNumber);
+
+ Common::SeekableReadStream *data = _vm->res()->get(resName);
+ _objectSprites = new SpriteAsset(_vm, data, data->size(), resName);
+ _vm->res()->toss(resName);
+
+ // Slot it into available palette space
+ _objectPalData = _objectSprites->getRgbList();
+ _vm->_palette->addRange(_objectPalData);
+ _objectSprites->translate(_objectPalData, true);
+
+ _objectFrameNumber = 0;
}
-//--------------------------------------------------------------------------
+void MadsInterfaceView::addObjectToInventory(int objectNumber) {
+ if (_inventoryList.indexOf(objectNumber) == -1) {
+ _madsVm->globals()->getObject(objectNumber)->roomNumber = PLAYER_INVENTORY;
+ _inventoryList.push_back(objectNumber);
+ }
-Animation::Animation(MadsM4Engine *vm): _vm(vm) {
+ setSelectedObject(objectNumber);
}
-Animation::~Animation() {
+void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) {
+ _vm->_font->setFont(FONT_INTERFACE_MADS);
+ char buffer[100];
+
+ // Check to see if any dialog is currently active
+ bool dialogVisible = _vm->_viewManager->getView(LAYER_DIALOG) != NULL;
+
+ // Highlighting logic for action list
+ int actionIndex = 0;
+ for (int x = 0; x < 2; ++x) {
+ for (int y = 0; y < 5; ++y, ++actionIndex) {
+ // Determine the font colour depending on whether an item is selected. Note that the first action,
+ // 'Look', is always 'selected', even when another action is clicked on
+ setFontMode((_highlightedElement == actionIndex) ? ITEM_HIGHLIGHTED :
+ ((actionIndex == 0) ? ITEM_SELECTED : ITEM_NORMAL));
+
+ // Get the verb action and capitalise it
+ const char *verbStr = _madsVm->globals()->getVocab(kVerbLook + actionIndex);
+ strcpy(buffer, verbStr);
+ if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
+
+ // Display the verb
+ const Common::Rect r(_screenObjects[actionIndex]);
+ _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
+ }
+ }
+
+ // Check for highlighting of the scrollbar controls
+ if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_SCROLLER) || (_highlightedElement == SCROLL_DOWN)) {
+ // Highlight the control's borders
+ const Common::Rect r(_screenObjects[_highlightedElement]);
+ destSurface->frameRect(r, 5);
+ }
+
+ // Draw the horizontal line in the scroller representing the current top selected
+ const Common::Rect scroller(_screenObjects[SCROLL_SCROLLER]);
+ int yP = (_inventoryList.size() < 2) ? 0 : (scroller.height() - 5) * _topIndex / (_inventoryList.size() - 1);
+ destSurface->setColor(4);
+ destSurface->hLine(scroller.left + 2, scroller.right - 3, scroller.top + 2 + yP);
+
+ // List inventory items
+ for (uint i = 0; i < 5; ++i) {
+ if ((_topIndex + i) >= _inventoryList.size())
+ break;
+
+ const char *descStr = _madsVm->globals()->getVocab(_madsVm->globals()->getObject(
+ _inventoryList[_topIndex + i])->descId);
+ strcpy(buffer, descStr);
+ if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
+
+ const Common::Rect r(_screenObjects[INVLIST_START + i]);
+
+ // Set the highlighting of the inventory item
+ if (_highlightedElement == (int)(INVLIST_START + i)) setFontMode(ITEM_HIGHLIGHTED);
+ else if (_selectedObject == _inventoryList[_topIndex + i]) setFontMode(ITEM_SELECTED);
+ else setFontMode(ITEM_NORMAL);
+
+ // Write out it's description
+ _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
+ }
+
+ // Handle the display of any currently selected object
+ if (_objectSprites) {
+ // Display object sprite. Note that the frame number isn't used directly, because it would result
+ // in too fast an animation
+ M4Sprite *spr = _objectSprites->getFrame(_objectFrameNumber / INV_ANIM_FRAME_SPEED);
+ spr->copyTo(destSurface, INVENTORY_X, INVENTORY_Y, 0);
+
+ if (!_madsVm->globals()->_config.invObjectsStill && !dialogVisible) {
+ // If objects need to be animated, move to the next frame
+ if (++_objectFrameNumber >= (_objectSprites->getCount() * INV_ANIM_FRAME_SPEED))
+ _objectFrameNumber = 0;
+ }
+
+ // List the vocab actions for the currently selected object
+ MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
+ int yIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
+
+ for (int i = 0; i < obj->vocabCount; ++i) {
+ const Common::Rect r(_screenObjects[VOCAB_START + i]);
+
+ // Get the vocab description and capitalise it
+ const char *descStr = _madsVm->globals()->getVocab(obj->vocabList[i].vocabId);
+ strcpy(buffer, descStr);
+ if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
+
+ // Set the highlighting and display the entry
+ setFontMode((i == yIndex) ? ITEM_HIGHLIGHTED : ITEM_NORMAL);
+ _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
+ }
+ }
}
-//--------------------------------------------------------------------------
+bool MadsInterfaceView::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
+ MadsAction &act = _madsVm->scene()->getAction();
-MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this),
- _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this) {
-
- _textSpacing = -1;
- _ticksAmount = 3;
- _newTimeout = 0;
- _abortTimers = 0;
- _abortTimers2 = 0;
- _abortTimersMode = ABORTMODE_0;
- _abortTimersMode2 = ABORTMODE_0;
-
- _depthSurface = NULL;
- _bgSurface = NULL;
- _sceneAnimation = new MadsAnimation(_vm, this);
+ // If the mouse isn't being held down, then reset the repeated scroll timer
+ if (eventType != MEVENT_LEFT_HOLD)
+ _nextScrollerTicks = 0;
+
+ // Handle various event types
+ switch (eventType) {
+ case MEVENT_MOVE:
+ // If the cursor isn't in "wait mode", don't do any processing
+ if (_vm->_mouse->getCursorNum() == CURSOR_WAIT)
+ return true;
+
+ // Ensure the cursor is the standard arrow
+ _vm->_mouse->setCursorNum(CURSOR_ARROW);
+
+ // Check if any interface element is currently highlighted
+ _highlightedElement = _screenObjects.find(Common::Point(x, y));
+
+ return true;
+
+ case MEVENT_LEFT_CLICK:
+ // Left mouse click
+ {
+ // Check if an inventory object was selected
+ if ((_highlightedElement >= INVLIST_START) && (_highlightedElement < (INVLIST_START + 5))) {
+ // Ensure there is an inventory item listed in that cell
+ uint idx = _highlightedElement - INVLIST_START;
+ if ((_topIndex + idx) < _inventoryList.size()) {
+ // Set the selected object
+ setSelectedObject(_inventoryList[_topIndex + idx]);
+ }
+ } else if ((_highlightedElement >= ACTIONS_START) && (_highlightedElement < (ACTIONS_START + 10))) {
+ // A standard action was selected
+ int verbId = kVerbLook + (_highlightedElement - ACTIONS_START);
+ warning("Selected action #%d", verbId);
+
+ } else if ((_highlightedElement >= VOCAB_START) && (_highlightedElement < (VOCAB_START + 5))) {
+ // A vocab action was selected
+ MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
+ int vocabIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
+ if (vocabIndex >= 0) {
+ act._actionMode = ACTMODE_OBJECT;
+ act._actionMode2 = ACTMODE2_2;
+ act._flags1 = obj->vocabList[1].flags1;
+ act._flags2 = obj->vocabList[1].flags2;
+
+ act._currentHotspot = _selectedObject;
+ act._articleNumber = act._flags2;
+ }
+ }
+ }
+ return true;
+
+ case MEVENT_LEFT_HOLD:
+ // Left mouse hold
+ // Handle the scroller - the up/down buttons allow for multiple actions whilst the mouse is held down
+ if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_DOWN)) {
+ if ((_nextScrollerTicks == 0) || (g_system->getMillis() >= _nextScrollerTicks)) {
+ // Handle scroll up/down action
+ _nextScrollerTicks = g_system->getMillis() + SCROLLER_DELAY;
+
+ if ((_highlightedElement == SCROLL_UP) && (_topIndex > 0))
+ --_topIndex;
+ if ((_highlightedElement == SCROLL_DOWN) && (_topIndex < (int)(_inventoryList.size() - 1)))
+ ++_topIndex;
+ }
+ }
+ return true;
+
+ case MEVENT_LEFT_DRAG:
+ // Left mouse drag
+ // Handle the the the scroller area that can be dragged to adjust the top displayed index
+ if (_highlightedElement == SCROLL_SCROLLER) {
+ // Calculate the new top index based on the Y position
+ const Common::Rect r(_screenObjects[SCROLL_SCROLLER]);
+ _topIndex = CLIP((int)(_inventoryList.size() - 1) * (y - r.top - 2) / (r.height() - 5),
+ 0, (int)_inventoryList.size() - 1);
+ }
+ return true;
+
+ case KEVENT_KEY:
+ if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
+ handleCheatKey(param1);
+ handleKeypress(param1);
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
}
-MadsView::~MadsView() {
- delete _sceneAnimation;
+bool MadsInterfaceView::handleCheatKey(int32 keycode) {
+ switch (keycode) {
+ case Common::KEYCODE_SPACE:
+ // TODO: Move player to current destination
+ return true;
+
+ case Common::KEYCODE_t | (Common::KEYCODE_LALT):
+ case Common::KEYCODE_t | (Common::KEYCODE_RALT):
+ {
+ // Teleport to room
+ //Scene *sceneView = (Scene *)vm->_viewManager->getView(VIEWID_SCENE);
+
+
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ return false;
}
-void MadsView::refresh() {
- // Draw any sprites
- _spriteSlots.drawBackground();
+const char *CHEAT_SEQUENCE = "widepipe";
- // Process dirty areas
- _textDisplay.setDirtyAreas();
+bool MadsInterfaceView::handleKeypress(int32 keycode) {
+ int flags = keycode >> 24;
+ int kc = keycode & 0xffff;
- // Merge any identified dirty areas
- _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
-
- // Copy dirty areas to the main display surface
- _dirtyAreas.copy(_view, _bgSurface);
+ // Capitalise the letter if necessary
+ if (_cheatKeyCtr < CHEAT_SEQUENCE_MAX) {
+ if ((flags & Common::KBD_CTRL) && (kc == CHEAT_SEQUENCE[_cheatKeyCtr])) {
+ ++_cheatKeyCtr;
+ if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
+ Dialog::display(_vm, 22, cheatingEnabledDesc);
+ return true;
+ } else {
+ _cheatKeyCtr = 0;
+ }
+ }
- // Handle dirty areas for foreground objects
- _spriteSlots.setDirtyAreas();
- _textDisplay.setDirtyAreas2();
- _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+ // Handle the various keys
+ if ((keycode == Common::KEYCODE_ESCAPE) || (keycode == Common::KEYCODE_F1)) {
+ // Game menu
+ _madsVm->globals()->dialogType = DIALOG_GAME_MENU;
+ leaveScene();
+ return false;
+ } else if (flags & Common::KBD_CTRL) {
+ // Handling of the different control key combinations
+ switch (kc) {
+ case Common::KEYCODE_i:
+ // Mouse to inventory
+ warning("TODO: Mouse to inventory");
+ break;
- // Draw foreground sprites
- _spriteSlots.drawForeground(_view);
+ case Common::KEYCODE_k:
+ // Toggle hotspots
+ warning("TODO: Toggle hotspots");
+ break;
- // Draw text elements onto the view
- _textDisplay.draw(_view);
+ case Common::KEYCODE_p:
+ // Player stats
+ warning("TODO: Player stats");
+ break;
- // Remove any sprite slots that are no longer needed
- _spriteSlots.cleanUp();
+ case Common::KEYCODE_q:
+ // Quit game
+ break;
- // Deactivate any text display entries that are no longer needed
- _textDisplay.cleanUp();
+ case Common::KEYCODE_s:
+ // Activate sound
+ warning("TODO: Activate sound");
+ break;
+
+ case Common::KEYCODE_u:
+ // Rotate player
+ warning("TODO: Rotate player");
+ break;
+
+ case Common::KEYCODE_v: {
+ // Release version
+ Dialog *dlg = new Dialog(_vm, GameReleaseInfoStr, GameReleaseTitleStr);
+ _vm->_viewManager->addView(dlg);
+ _vm->_viewManager->moveToFront(dlg);
+ return false;
+ }
+
+ default:
+ break;
+ }
+ } else if ((flags & Common::KBD_ALT) && (kc == Common::KEYCODE_q)) {
+ // Quit Game
+
+ } else {
+ // Standard keypresses
+ switch (kc) {
+ case Common::KEYCODE_F2:
+ // Save game
+ _madsVm->globals()->dialogType = DIALOG_SAVE;
+ leaveScene();
+ break;
+ case Common::KEYCODE_F3:
+ // Restore game
+ _madsVm->globals()->dialogType = DIALOG_RESTORE;
+ leaveScene();
+ break;
+ }
+ }
+//DIALOG_OPTIONS
+ return false;
+}
+
+void MadsInterfaceView::leaveScene() {
+ // Close the scene
+ View *view = _madsVm->_viewManager->getView(VIEWID_SCENE);
+ _madsVm->_viewManager->deleteView(view);
}
} // End of namespace M4
diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h
index 98944e6468..926702a80b 100644
--- a/engines/m4/mads_views.h
+++ b/engines/m4/mads_views.h
@@ -34,24 +34,18 @@
namespace M4 {
+#define MADS_SURFACE_HEIGHT 156
+#define MADS_SCREEN_HEIGHT 200
+#define MADS_Y_OFFSET ((MADS_SCREEN_HEIGHT - MADS_SURFACE_HEIGHT) / 2)
+
class MadsView;
enum AbortTimerMode {ABORTMODE_0 = 0, ABORTMODE_1 = 1, ABORTMODE_2 = 2};
-class SpriteSlotSubset {
-public:
- int spriteListIndex;
- int frameNumber;
- int xp;
- int yp;
- int depth;
- int scale;
-};
-
class MadsSpriteSlot {
public:
- int spriteType;
- int seqIndex;
+ int spriteId;
+ int timerIndex;
int spriteListIndex;
int frameNumber;
int xp;
@@ -60,28 +54,20 @@ public:
int scale;
MadsSpriteSlot() { }
-
- bool operator==(const SpriteSlotSubset &other) const;
- void copy(const SpriteSlotSubset &other);
};
#define SPRITE_SLOTS_SIZE 50
-enum SpriteIdSpecial {
- BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, EXPIRED_SPRITE = -1, SPRITE_ZERO = 0, FOREGROUND_SPRITE = 1,
- SPRITE_FOUR = 4
-};
+typedef Common::Array<Common::SharedPtr<SpriteAsset> > SpriteList;
class MadsSpriteSlots {
private:
- MadsView &_owner;
Common::Array<MadsSpriteSlot> _entries;
- Common::Array<SpriteAsset *> _sprites;
+ SpriteList _sprites;
public:
int startIndex;
- MadsSpriteSlots(MadsView &owner);
- ~MadsSpriteSlots();
+ MadsSpriteSlots();
MadsSpriteSlot &operator[](int idx) {
assert(idx < SPRITE_SLOTS_SIZE);
@@ -89,19 +75,18 @@ public:
}
SpriteAsset &getSprite(int idx) {
assert(idx < (int)_sprites.size());
- return *_sprites[idx];
+ return *_sprites[idx].get();
}
int getIndex();
int addSprites(const char *resName);
- void deleteSprites(int listIndex);
- void clear();
- void deleteTimer(int seqIndex);
+ void clear() {
+ startIndex = 0;
+ _sprites.clear();
+ }
+ void deleteTimer(int timerIndex);
- void drawBackground();
- void drawForeground(View *view);
- void setDirtyAreas();
- void fullRefresh();
+ void draw(View *view);
void cleanUp();
};
@@ -123,10 +108,9 @@ public:
class MadsTextDisplay {
private:
- MadsView &_owner;
Common::Array<MadsTextDisplayEntry> _entries;
public:
- MadsTextDisplay(MadsView &owner);
+ MadsTextDisplay();
MadsTextDisplayEntry &operator[](int idx) {
assert(idx < TEXT_DISPLAY_SIZE);
@@ -141,18 +125,15 @@ public:
int add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font);
void clear();
void draw(View *view);
- void setDirtyAreas();
- void setDirtyAreas2();
void cleanUp();
};
#define TIMED_TEXT_SIZE 10
-#define INDEFINITE_TIMEOUT 9999999
+#define TEXT_4A_SIZE 30
-enum KernelMessageFlags {KMSG_QUOTED = 1, KMSG_OWNER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8, KMSG_RIGHT_ALIGN = 0x10,
- KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40, KMSG_ACTIVE = 0x80};
+enum KernelMessageFlags {KMSG_1 = 1, KMSG_2 = 2, KMSG_4 = 4, KMSG_8 = 8, KMSG_20 = 0x20, KMSG_40 = 0x40, KMSG_ACTIVE = 0x80};
-class MadsKernelMessageEntry {
+class MadsKernelMessageListEntry {
public:
uint8 flags;
int sequenceIndex;
@@ -163,35 +144,31 @@ public:
Common::Point position;
int textDisplayIndex;
int msgOffset;
- int numTicks;
+ int field_E;
uint32 frameTimer2;
uint32 frameTimer;
uint32 timeout;
- int abortTimers;
+ bool field_1C;
AbortTimerMode abortMode;
uint16 actionNouns[3];
- char msg[100];
+ const char *msg;
};
class MadsKernelMessageList {
private:
MadsView &_owner;
- Common::Array<MadsKernelMessageEntry> _entries;
+ Common::Array<MadsKernelMessageListEntry> _entries;
Font *_talkFont;
public:
- int word_8469E;
-public:
MadsKernelMessageList(MadsView &owner);
void clear();
- int add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 abortTimers, uint32 timeout, const char *msg);
- int addQuote(int quoteId, int abortTimers, uint32 timeout);
- void scrollMessage(int msgIndex, int numTicks, bool quoted);
+ int add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 v2, uint32 timeout, const char *msg);
+ int addQuote(int quoteId, int v2, uint32 timeout);
+ void unk1(int msgIndex, int v1, int v2);
void setSeqIndex(int msgIndex, int seqIndex);
void remove(int msgIndex);
void reset();
- void update();
- void processText(int msgIndex);
};
class ScreenObjectEntry {
@@ -227,7 +204,7 @@ public:
class DynamicHotspot {
public:
bool active;
- int seqIndex;
+ int timerIndex;
Common::Rect bounds;
Common::Point pos;
int facing;
@@ -252,47 +229,13 @@ public:
MadsDynamicHotspots(MadsView &owner);
DynamicHotspot &operator[](uint idx) { return _entries[idx]; }
- int add(int descId, int field14, int seqIndex, const Common::Rect &bounds);
+ int add(int descId, int field14, int timerIndex, const Common::Rect &bounds);
int setPosition(int index, int xp, int yp, int facing);
int set17(int index, int v);
void remove(int index);
void reset();
};
-class MadsDirtyArea {
-public:
- Common::Rect bounds;
- Common::Rect bounds2;
- bool textActive;
- bool active;
-
- MadsDirtyArea() { active = false; }
- void setArea(int width, int height, int maxWidth, int maxHeight);
-};
-
-#define DIRTY_AREAS_SIZE 90
-#define DIRTY_AREAS_TEXT_DISPLAY_IDX 50
-
-class MadsDirtyAreas {
-private:
- MadsView &_owner;
- Common::Array<MadsDirtyArea> _entries;
-public:
- MadsDirtyAreas(MadsView &owner);
-
- MadsDirtyArea &operator[](uint idx) {
- assert(idx < _entries.size());
- return _entries[idx];
- }
-
- void setSpriteSlot(int dirtyIdx, const MadsSpriteSlot &spriteSlot);
- void setTextDisplay(int dirtyIdx, const MadsTextDisplayEntry &textDisplay);
- void merge(int startIndex, int count);
- bool intersects(int idx1, int idx2);
- void mergeAreas(int idx1, int idx2);
- void copy(M4Surface *dest, M4Surface *src);
-};
-
enum SpriteAnimType {ANIMTYPE_CYCLED = 1, ANIMTYPE_REVERSIBLE = 2};
enum SequenceSubEntryMode {SM_0 = 0, SM_1 = 1, SM_FRAME_INDEX = 2};
@@ -323,10 +266,12 @@ struct MadsSequenceEntry {
int scale;
int dynamicHotspotIndex;
- bool nonFixed;
+ int field_12;
int field_13;
- Common::Point msgPos;
+ int width;
+ int height;
+
int triggerCountdown;
bool doneFlag;
MadsSequenceSubEntries entries;
@@ -351,42 +296,25 @@ public:
void clear();
bool addSubEntry(int index, SequenceSubEntryMode mode, int frameIndex, int abortVal);
int add(int spriteListIndex, int v0, int v1, int triggerCountdown, int delayTicks, int extraTicks, int numTicks,
- int msgX, int msgY, bool nonFixed, char scale, uint8 depth, int frameInc, SpriteAnimType animType,
+ int height, int width, char field_12, char scale, uint8 depth, int frameInc, SpriteAnimType animType,
int numSprites, int frameStart);
- void remove(int seqIndex);
- void setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot);
- bool loadSprites(int seqIndex);
+ void remove(int timerIndex);
+ void setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot);
+ bool loadSprites(int timerIndex);
void tick();
void delay(uint32 v1, uint32 v2);
- void setAnimRange(int seqIndex, int startVal, int endVal);
- void scan();
};
-class Animation {
-protected:
- MadsM4Engine *_vm;
-public:
- Animation(MadsM4Engine *vm);
- virtual ~Animation();
- virtual void initialise(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface) = 0;
- virtual void load(const Common::String &filename, int v0) = 0;
- virtual void update() = 0;
- virtual void setCurrentFrame(int frameNumber) = 0;
-};
-
-
class MadsView {
private:
View *_view;
public:
- Animation *_sceneAnimation;
MadsSpriteSlots _spriteSlots;
MadsTextDisplay _textDisplay;
MadsKernelMessageList _kernelMessages;
ScreenObjects _screenObjects;
MadsDynamicHotspots _dynamicHotspots;
MadsSequenceList _sequenceList;
- MadsDirtyAreas _dirtyAreas;
int _textSpacing;
int _ticksAmount;
@@ -395,17 +323,62 @@ public:
int8 _abortTimers2;
AbortTimerMode _abortTimersMode;
AbortTimerMode _abortTimersMode2;
- Common::Point _posAdjust;
-
- M4Surface *_depthSurface;
- M4Surface *_bgSurface;
public:
MadsView(View *view);
- ~MadsView();
void refresh();
};
+#define CHEAT_SEQUENCE_MAX 8
+
+class IntegerList : public Common::Array<int> {
+public:
+ int indexOf(int v) {
+ for (uint i = 0; i < size(); ++i)
+ if (operator [](i) == v)
+ return i;
+ return -1;
+ }
+};
+
+enum InterfaceFontMode {ITEM_NORMAL, ITEM_HIGHLIGHTED, ITEM_SELECTED};
+
+enum InterfaceObjects {ACTIONS_START = 0, SCROLL_UP = 10, SCROLL_SCROLLER = 11, SCROLL_DOWN = 12,
+ INVLIST_START = 13, VOCAB_START = 18};
+
+class MadsInterfaceView : public GameInterfaceView {
+private:
+ IntegerList _inventoryList;
+ RectList _screenObjects;
+ int _highlightedElement;
+ int _topIndex;
+ uint32 _nextScrollerTicks;
+ int _cheatKeyCtr;
+
+ // Object display fields
+ int _selectedObject;
+ SpriteAsset *_objectSprites;
+ RGBList *_objectPalData;
+ int _objectFrameNumber;
+
+ void setFontMode(InterfaceFontMode newMode);
+ bool handleCheatKey(int32 keycode);
+ bool handleKeypress(int32 keycode);
+ void leaveScene();
+public:
+ MadsInterfaceView(MadsM4Engine *vm);
+ ~MadsInterfaceView();
+
+ virtual void initialise();
+ virtual void setSelectedObject(int objectNumber);
+ virtual void addObjectToInventory(int objectNumber);
+ int getSelectedObject() { return _selectedObject; }
+ int getInventoryObject(int objectIndex) { return _inventoryList[objectIndex]; }
+
+ void onRefresh(RectList *rects, M4Surface *destSurface);
+ bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents);
+};
+
}
#endif
diff --git a/engines/m4/sprite.h b/engines/m4/sprite.h
index 49a96a6c4a..022f3bbc4f 100644
--- a/engines/m4/sprite.h
+++ b/engines/m4/sprite.h
@@ -115,6 +115,18 @@ public:
void loadDeltaRle(Common::SeekableReadStream* rleData, int destX, int destY);
void loadMadsSprite(Common::SeekableReadStream* source);
+ void draw1(M4Surface *destSurface, int scale, int depth, int xp, int yp) {
+ // TODO: Properly implement drawing
+ copyTo(destSurface, xp, yp, 0);
+ }
+ void draw2(M4Surface *destSurface, int depth, int xp, int yp) {
+ // TODO: Properly implement drawing
+ copyTo(destSurface, xp, yp, 0);
+ }
+ void draw3(M4Surface *destSurface, int xp, int yp) {
+ // TODO: Properly implement drawing
+ copyTo(destSurface, xp, yp, 0);
+ }
byte getTransparentColor() const;
protected:
};
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index 149b6b6eba..389665db39 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -30,7 +30,7 @@
#include "mohawk/riven.h"
#include "mohawk/livingbooks.h"
#include "mohawk/sound.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
namespace Mohawk {
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 7f2e0cb312..a7b1fe7fae 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -341,24 +341,6 @@ static const MohawkGameDescription gameDescriptions[] = {
0,
},
- // Myst Masterpiece Edition
- // French Windows
- // From gamin (Included in "Myst: La Trilogie")
- {
- {
- "myst",
- "Masterpiece Edition",
- AD_ENTRY1("MYST.DAT", "aea81633b2d2ae498f09072fb87263b6"),
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- Common::GUIO_NONE
- },
- GType_MYST,
- GF_ME,
- 0,
- },
-
// Riven: The Sequel to Myst
// Version 1.0 (5CD)
// From clone2727
@@ -450,24 +432,6 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version ? (DVD, From "Myst: La Trilogie")
- // From gamin
- {
- {
- "riven",
- "",
- AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- Common::GUIO_NONE
- },
- GType_RIVEN,
- GF_DVD,
- 0,
- },
-
- // Riven: The Sequel to Myst
// Version ? (Demo, From "Prince of Persia Collector's Edition")
// From Clone2727
{
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index 2ddfb47575..35691c36aa 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -78,8 +78,9 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) {
error("Myst requires greater than 256 colors to run");
if (_vm->getFeatures() & GF_ME) {
- _jpegDecoder = new Graphics::JPEGDecoder();
- _pictDecoder = new Graphics::PictDecoder(_pixelFormat);
+ // We want to delete our own JPEG surfaces, so don't free after use.
+ _jpegDecoder = new JPEGDecoder(false);
+ _pictDecoder = new MystPICT(_jpegDecoder);
} else {
_jpegDecoder = NULL;
_pictDecoder = NULL;
@@ -151,10 +152,9 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm
if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) {
for (uint32 i = 0; i < _pictureFile.pictureCount; i++)
if (_pictureFile.entries[i].id == image) {
- if (_pictureFile.entries[i].type == 0) {
- Graphics::Surface *jpegSurface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size));
- surface->copyFrom(*jpegSurface);
- } else if (_pictureFile.entries[i].type == 1)
+ if (_pictureFile.entries[i].type == 0)
+ surface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size));
+ else if (_pictureFile.entries[i].type == 1)
surface = _pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size));
else
error ("Unknown Picture File type %d", _pictureFile.entries[i].type);
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index dd1764e6d6..8d28e1ff4b 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -27,11 +27,11 @@
#define MOHAWK_GRAPHICS_H
#include "mohawk/bitmap.h"
+#include "mohawk/jpeg.h"
#include "mohawk/livingbooks.h"
+#include "mohawk/myst_pict.h"
#include "common/file.h"
-#include "graphics/pict.h"
-#include "graphics/video/codecs/mjpeg.h"
namespace Mohawk {
@@ -96,16 +96,16 @@ public:
void loadExternalPictureFile(uint16 stack);
void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest);
void copyImageToScreen(uint16 image, Common::Rect dest);
- void showCursor();
- void hideCursor();
+ void showCursor(void);
+ void hideCursor(void);
void changeCursor(uint16);
void drawRect(Common::Rect rect, bool active);
private:
MohawkEngine_Myst *_vm;
MystBitmap *_bmpDecoder;
- Graphics::PictDecoder *_pictDecoder;
- Graphics::JPEGDecoder *_jpegDecoder;
+ MystPICT *_pictDecoder;
+ JPEGDecoder *_jpegDecoder;
Graphics::PixelFormat _pixelFormat;
struct PictureFile {
diff --git a/engines/mohawk/jpeg.cpp b/engines/mohawk/jpeg.cpp
new file mode 100644
index 0000000000..07ec54dfea
--- /dev/null
+++ b/engines/mohawk/jpeg.cpp
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/conversion.h" // For YUV2RGB
+
+#include "mohawk/jpeg.h"
+
+namespace Mohawk {
+
+JPEGDecoder::JPEGDecoder(bool freeSurfaceAfterUse) : Graphics::Codec(), _freeSurfaceAfterUse(freeSurfaceAfterUse) {
+ _jpeg = new Graphics::JPEG();
+ _pixelFormat = g_system->getScreenFormat();
+ _surface = NULL;
+}
+
+JPEGDecoder::~JPEGDecoder() {
+ delete _jpeg;
+
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ }
+}
+
+Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) {
+ _jpeg->read(stream);
+ Graphics::Surface *ySurface = _jpeg->getComponent(1);
+ Graphics::Surface *uSurface = _jpeg->getComponent(2);
+ Graphics::Surface *vSurface = _jpeg->getComponent(3);
+
+ Graphics::Surface *destSurface = NULL;
+
+ // If we should free the surface after use, use the internal _surface storage
+ // (this should be used when using as a Codec, as the Codecs should free their
+ // surfaces when deleting the Codec object). Otherwise, create a new Surface
+ // as the destination.
+ if (_freeSurfaceAfterUse) {
+ if (!_surface) {
+ _surface = new Graphics::Surface();
+ _surface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel);
+ }
+ destSurface = _surface;
+ } else {
+ destSurface = new Graphics::Surface();
+ destSurface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel);
+ }
+
+ assert(destSurface);
+
+ for (uint16 i = 0; i < destSurface->h; i++) {
+ for (uint16 j = 0; j < destSurface->w; j++) {
+ byte r = 0, g = 0, b = 0;
+ Graphics::YUV2RGB(*((byte *)ySurface->getBasePtr(j, i)), *((byte *)uSurface->getBasePtr(j, i)), *((byte *)vSurface->getBasePtr(j, i)), r, g, b);
+ if (_pixelFormat.bytesPerPixel == 2)
+ *((uint16 *)destSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)destSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+
+ return destSurface;
+}
+
+} // End of namespace Mohawk
diff --git a/graphics/video/codecs/mjpeg.h b/engines/mohawk/jpeg.h
index ab364fb5be..ec87b1e7af 100644
--- a/graphics/video/codecs/mjpeg.h
+++ b/engines/mohawk/jpeg.h
@@ -23,8 +23,8 @@
*
*/
-#ifndef GRAPHICS_MJPEG_H
-#define GRAPHICS_MJPEG_H
+#ifndef MOHAWK_JPEG_H
+#define MOHAWK_JPEG_H
#include "common/scummsys.h"
#include "common/stream.h"
@@ -33,26 +33,27 @@
#include "graphics/jpeg.h"
#include "graphics/pixelformat.h"
-namespace Graphics {
+namespace Mohawk {
-// Motion JPEG Decoder
+// Mohawk's JPEG Decoder
// Basically a wrapper around JPEG which converts to RGB and also functions
// as a Codec.
-class JPEGDecoder : public Codec {
+class JPEGDecoder : public Graphics::Codec {
public:
- JPEGDecoder();
+ JPEGDecoder(bool freeSurfaceAfterUse);
~JPEGDecoder();
- Surface *decodeImage(Common::SeekableReadStream *stream);
- PixelFormat getPixelFormat() const { return _pixelFormat; }
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
- PixelFormat _pixelFormat;
- JPEG *_jpeg;
- Surface *_surface;
+ Graphics::PixelFormat _pixelFormat;
+ Graphics::JPEG *_jpeg;
+ Graphics::Surface *_surface;
+ bool _freeSurfaceAfterUse;
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk
index bb79d4abac..b224a8b143 100644
--- a/engines/mohawk/module.mk
+++ b/engines/mohawk/module.mk
@@ -6,9 +6,11 @@ MODULE_OBJS = \
detection.o \
dialogs.o \
graphics.o \
+ jpeg.o \
livingbooks.o \
mohawk.o \
myst.o \
+ myst_pict.o \
myst_vars.o \
myst_saveload.o \
myst_scripts.o \
@@ -20,7 +22,13 @@ MODULE_OBJS = \
riven_scripts.o \
riven_vars.o \
sound.o \
- video.o
+ video/cinepak.o \
+ video/qdm2.o \
+ video/qtrle.o \
+ video/qt_player.o \
+ video/rpza.o \
+ video/smc.o \
+ video/video.o
# This module can be built as a plugin
diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp
index 6b4d8bb2d2..5bde6bbeec 100644
--- a/engines/mohawk/mohawk.cpp
+++ b/engines/mohawk/mohawk.cpp
@@ -35,7 +35,7 @@
#include "mohawk/mohawk.h"
#include "mohawk/dialogs.h"
#include "mohawk/sound.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
#include "sound/mixer.h"
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 9ff301c129..d1ef3b2137 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -33,7 +33,7 @@
#include "mohawk/dialogs.h"
#include "mohawk/resource.h"
#include "mohawk/resource_cache.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
namespace Mohawk {
diff --git a/graphics/pict.cpp b/engines/mohawk/myst_pict.cpp
index f0dd7bbc6f..794ec9b87f 100644
--- a/graphics/pict.cpp
+++ b/engines/mohawk/myst_pict.cpp
@@ -23,38 +23,26 @@
*
*/
-#include "common/stream.h"
+#include "common/system.h"
-#include "graphics/conversion.h"
-#include "graphics/jpeg.h"
-#include "graphics/pict.h"
-#include "graphics/surface.h"
+#include "mohawk/myst_pict.h"
-namespace Graphics {
+namespace Mohawk {
// The PICT code is based off of the QuickDraw specs:
-// http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-461.html
-// http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-269.html
+// http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-461.html
-PictDecoder::PictDecoder(PixelFormat pixelFormat) {
- _jpeg = new JPEG();
- _pixelFormat = pixelFormat;
+MystPICT::MystPICT(JPEGDecoder *jpegDecoder) {
+ _jpegDecoder = jpegDecoder;
+ _pixelFormat = g_system->getScreenFormat();
}
-PictDecoder::~PictDecoder() {
- delete _jpeg;
-}
-
-Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *palette) {
- assert(stream);
-
- uint16 fileSize = stream->readUint16BE();
+Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) {
+ // Skip initial 512 bytes (all 0's)
+ stream->seek(512, SEEK_CUR);
- // If we have no file size here, we probably have a PICT from a file
- // and not a resource. The other two bytes are the fileSize which we
- // don't actually need (and already read if from a resource).
- if (!fileSize)
- stream->seek(512 + 2);
+ // Read in the first part of the header
+ /* uint16 fileSize = */ stream->readUint16BE();
_imageRect.top = stream->readUint16BE();
_imageRect.left = stream->readUint16BE();
@@ -64,12 +52,11 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
Graphics::Surface *image = new Graphics::Surface();
image->create(_imageRect.width(), _imageRect.height(), _pixelFormat.bytesPerPixel);
- _isPaletted = false;
// NOTE: This is only a subset of the full PICT format.
// - Only V2 Images Supported
- // - CompressedQuickTime (JPEG) compressed data is supported
- // - DirectBitsRect/PackBitsRect compressed data is supported
+ // - JPEG Chunks are Supported
+ // - DirectBitsRect Chunks are Supported
for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size(); opNum++) {
uint16 opcode = stream->readUint16BE();
debug(2, "Found PICT opcode %04x", opcode);
@@ -95,11 +82,8 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
error ("Unknown PICT version");
} else if (opcode == 0x001E) { // DefHilite
// Ignore, Contains no Data
- } else if (opcode == 0x0098) { // PackBitsRect
- decodeDirectBitsRect(stream, image, true);
- _isPaletted = true;
} else if (opcode == 0x009A) { // DirectBitsRect
- decodeDirectBitsRect(stream, image, false);
+ decodeDirectBitsRect(stream, image);
} else if (opcode == 0x00A1) { // LongComment
stream->readUint16BE();
uint16 dataSize = stream->readUint16BE();
@@ -122,71 +106,59 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
decodeCompressedQuickTime(stream, image);
break;
} else {
- warning("Unknown PICT opcode %04x", opcode);
+ error ("Unknown PICT opcode %04x", opcode);
}
}
- // If we got a palette throughout this nonsense, go and grab it
- if (palette && _isPaletted)
- memcpy(palette, _palette, 256 * 4);
-
return image;
}
-PictDecoder::PixMap PictDecoder::readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr) {
- PixMap pixMap;
- pixMap.baseAddr = hasBaseAddr ? stream->readUint32BE() : 0;
- pixMap.rowBytes = stream->readUint16BE() & 0x3fff;
- pixMap.bounds.top = stream->readUint16BE();
- pixMap.bounds.left = stream->readUint16BE();
- pixMap.bounds.bottom = stream->readUint16BE();
- pixMap.bounds.right = stream->readUint16BE();
- pixMap.pmVersion = stream->readUint16BE();
- pixMap.packType = stream->readUint16BE();
- pixMap.packSize = stream->readUint32BE();
- pixMap.hRes = stream->readUint32BE();
- pixMap.vRes = stream->readUint32BE();
- pixMap.pixelType = stream->readUint16BE();
- pixMap.pixelSize = stream->readUint16BE();
- pixMap.cmpCount = stream->readUint16BE();
- pixMap.cmpSize = stream->readUint16BE();
- pixMap.planeBytes = stream->readUint32BE();
- pixMap.pmTable = stream->readUint32BE();
- pixMap.pmReserved = stream->readUint32BE();
- return pixMap;
-}
-
struct DirectBitsRectData {
- PictDecoder::PixMap pixMap;
+ // PixMap
+ struct {
+ uint32 baseAddr;
+ uint16 rowBytes;
+ Common::Rect bounds;
+ uint16 pmVersion;
+ uint16 packType;
+ uint32 packSize;
+ uint32 hRes;
+ uint32 vRes;
+ uint16 pixelType;
+ uint16 pixelSize;
+ uint16 cmpCount;
+ uint16 cmpSize;
+ uint32 planeBytes;
+ uint32 pmTable;
+ uint32 pmReserved;
+ } pixMap;
Common::Rect srcRect;
Common::Rect dstRect;
uint16 mode;
};
-void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette) {
- static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
-
- // Clear the palette
- memset(_palette, 0, sizeof(_palette));
+void MystPICT::decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image) {
+ static const Graphics::PixelFormat directBitsFormat16 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
DirectBitsRectData directBitsData;
- directBitsData.pixMap = readPixMap(stream, !hasPalette);
-
- // Read in the palette if there is one present
- if (hasPalette) {
- // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html
- stream->readUint32BE(); // seed
- stream->readUint16BE(); // flags
- uint16 colorCount = stream->readUint16BE() + 1;
-
- for (uint32 i = 0; i < colorCount; i++) {
- stream->readUint16BE();
- _palette[i * 4] = stream->readUint16BE() >> 8;
- _palette[i * 4 + 1] = stream->readUint16BE() >> 8;
- _palette[i * 4 + 2] = stream->readUint16BE() >> 8;
- }
- }
-
+ directBitsData.pixMap.baseAddr = stream->readUint32BE();
+ directBitsData.pixMap.rowBytes = stream->readUint16BE() & 0x3fff;
+ directBitsData.pixMap.bounds.top = stream->readUint16BE();
+ directBitsData.pixMap.bounds.left = stream->readUint16BE();
+ directBitsData.pixMap.bounds.bottom = stream->readUint16BE();
+ directBitsData.pixMap.bounds.right = stream->readUint16BE();
+ directBitsData.pixMap.pmVersion = stream->readUint16BE();
+ directBitsData.pixMap.packType = stream->readUint16BE();
+ directBitsData.pixMap.packSize = stream->readUint32BE();
+ directBitsData.pixMap.hRes = stream->readUint32BE();
+ directBitsData.pixMap.vRes = stream->readUint32BE();
+ directBitsData.pixMap.pixelType = stream->readUint16BE();
+ directBitsData.pixMap.pixelSize = stream->readUint16BE();
+ directBitsData.pixMap.cmpCount = stream->readUint16BE();
+ directBitsData.pixMap.cmpSize = stream->readUint16BE();
+ directBitsData.pixMap.planeBytes = stream->readUint32BE();
+ directBitsData.pixMap.pmTable = stream->readUint32BE();
+ directBitsData.pixMap.pmReserved = stream->readUint32BE();
directBitsData.srcRect.top = stream->readUint16BE();
directBitsData.srcRect.left = stream->readUint16BE();
directBitsData.srcRect.bottom = stream->readUint16BE();
@@ -197,44 +169,34 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surfa
directBitsData.dstRect.right = stream->readUint16BE();
directBitsData.mode = stream->readUint16BE();
- if (directBitsData.pixMap.pixelSize != 8 && directBitsData.pixMap.pixelSize != 16 && directBitsData.pixMap.pixelSize != 32)
- error("Unhandled DirectBitsRect bitsPerPixel %d", directBitsData.pixMap.pixelSize);
+ if (directBitsData.pixMap.pixelSize != 16 && directBitsData.pixMap.pixelSize != 32)
+ error("Unhandled directBitsRect bitsPerPixel %d", directBitsData.pixMap.pixelSize);
- byte bytesPerPixel = (directBitsData.pixMap.pixelSize == 32) ? 3 : directBitsData.pixMap.pixelSize / 8;
+ byte bytesPerPixel = (directBitsData.pixMap.pixelSize == 16) ? 2 : 3;
byte *buffer = new byte[image->w * image->h * bytesPerPixel];
// Read in amount of data per row
for (uint16 i = 0; i < directBitsData.pixMap.bounds.height(); i++) {
- // NOTE: Compression 0 is "default". The format in SCI games is packed when 0.
- // In the future, we may need to have something to set the "default" packing
- // format, but this is good for now.
-
- if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte (on 24-bit)
- // TODO: Finish this. Hasn't been needed (yet).
- error("Unpacked DirectBitsRect data (padded)");
- } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte (on 24-bit)
- // TODO: Finish this. Hasn't been needed (yet).
- error("Unpacked DirectBitsRect data (not padded)");
- } else if (directBitsData.pixMap.packType == 0 || directBitsData.pixMap.packType > 2) { // Packed
+ if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte
+ error("Pack Type = %d, Row Bytes = %d", directBitsData.pixMap.packType, directBitsData.pixMap.rowBytes);
+ // TODO
+ } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte
+ error("Pack Type = 2");
+ // TODO
+ } else if (directBitsData.pixMap.packType > 2) { // Packed
uint16 byteCount = (directBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte();
decodeDirectBitsLine(buffer + i * image->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), bytesPerPixel);
}
}
-
- if (bytesPerPixel == 1) {
- // Just copy to the image
- memcpy(image->pixels, buffer, image->w * image->h);
- } else if (bytesPerPixel == 2) {
+
+ if (bytesPerPixel == 2) {
// Convert from 16-bit to whatever surface we need
for (uint16 y = 0; y < image->h; y++) {
for (uint16 x = 0; x < image->w; x++) {
byte r = 0, g = 0, b = 0;
uint32 color = READ_BE_UINT16(buffer + (y * image->w + x) * bytesPerPixel);
directBitsFormat16.colorToRGB(color, r, g, b);
- if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
- else
- *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
}
}
} else {
@@ -244,10 +206,7 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surfa
byte r = *(buffer + y * image->w * 3 + x);
byte g = *(buffer + y * image->w * 3 + image->w + x);
byte b = *(buffer + y * image->w * 3 + image->w * 2 + x);
- if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
- else
- *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
}
}
}
@@ -255,7 +214,7 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surfa
delete[] buffer;
}
-void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) {
+void MystPICT::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) {
uint32 dataDecoded = 0;
byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1;
@@ -297,37 +256,17 @@ void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::Seekabl
// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html
// I'm just ignoring that because Myst ME uses none of that extra stuff. The offset is always the same.
-void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image) {
+void MystPICT::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image) {
uint32 dataSize = stream->readUint32BE();
uint32 startPos = stream->pos();
- Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize);
-
- if (!_jpeg->read(jpegStream))
- error("PictDecoder::decodeCompressedQuickTime(): Could not decode JPEG data");
-
- Surface *yComponent = _jpeg->getComponent(1);
- Surface *uComponent = _jpeg->getComponent(2);
- Surface *vComponent = _jpeg->getComponent(3);
+ Graphics::Surface *jpegImage = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize));
+ stream->seek(startPos + dataSize);
- Surface jpegImage;
- jpegImage.create(yComponent->w, yComponent->h, _pixelFormat.bytesPerPixel);
+ image->copyFrom(*jpegImage);
- for (uint16 i = 0; i < jpegImage.h; i++) {
- for (uint16 j = 0; j < jpegImage.w; j++) {
- byte r = 0, g = 0, b = 0;
- YUV2RGB(*((byte *)yComponent->getBasePtr(j, i)), *((byte *)uComponent->getBasePtr(j, i)), *((byte *)vComponent->getBasePtr(j, i)), r, g, b);
- if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
- else
- *((uint32 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
- }
- }
-
- image->copyFrom(jpegImage);
- stream->seek(startPos + dataSize);
- jpegImage.free();
- delete jpegStream;
+ jpegImage->free();
+ delete jpegImage;
}
-} // End of namespace Graphics
+} // End of namespace Mohawk
diff --git a/graphics/pict.h b/engines/mohawk/myst_pict.h
index 12681f6128..0684e3352a 100644
--- a/graphics/pict.h
+++ b/engines/mohawk/myst_pict.h
@@ -23,61 +23,35 @@
*
*/
-#ifndef GRAPHICS_PICT_H
-#define GRAPHICS_PICT_H
+#ifndef MYST_PICT_H
+#define MYST_PICT_H
#include "common/rect.h"
#include "common/scummsys.h"
-
+#include "common/stream.h"
#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Graphics {
+#include "mohawk/jpeg.h"
-class JPEG;
-struct Surface;
+namespace Mohawk {
-class PictDecoder {
+class MystPICT {
public:
- PictDecoder(Graphics::PixelFormat pixelFormat);
- ~PictDecoder();
- Surface *decodeImage(Common::SeekableReadStream *stream, byte *palette = 0);
-
- struct PixMap {
- uint32 baseAddr;
- uint16 rowBytes;
- Common::Rect bounds;
- uint16 pmVersion;
- uint16 packType;
- uint32 packSize;
- uint32 hRes;
- uint32 vRes;
- uint16 pixelType;
- uint16 pixelSize;
- uint16 cmpCount;
- uint16 cmpSize;
- uint32 planeBytes;
- uint32 pmTable;
- uint32 pmReserved;
- };
-
- static PixMap readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr = true);
+ MystPICT(JPEGDecoder *jpegDecoder);
+ ~MystPICT() {}
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
private:
+ JPEGDecoder *_jpegDecoder;
Common::Rect _imageRect;
- PixelFormat _pixelFormat;
- JPEG *_jpeg;
- byte _palette[256 * 4];
- bool _isPaletted;
+ Graphics::PixelFormat _pixelFormat;
- void decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette);
+ void decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image);
void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel);
- void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Surface *image);
+ void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image);
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index 2f6d178da8..a453bb0985 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -27,7 +27,7 @@
#include "mohawk/graphics.h"
#include "mohawk/myst_scripts.h"
#include "mohawk/sound.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
#include "gui/message.h"
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index c646855bc7..0412144034 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -33,7 +33,7 @@
#include "mohawk/riven_external.h"
#include "mohawk/riven_saveload.h"
#include "mohawk/dialogs.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
namespace Mohawk {
@@ -47,7 +47,6 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
_cardData.hasData = false;
_gameOver = false;
_activatedSLST = false;
- _ignoreNextMouseUp = false;
_extrasFile = NULL;
// Attempt to let game run from the CDs
@@ -148,15 +147,10 @@ Common::Error MohawkEngine_Riven::run() {
runHotspotScript(_curHotspot, kMouseDownScript);
break;
case Common::EVENT_LBUTTONUP:
- // See RivenScript::switchCard() for more information on why we sometimes
- // disable the next up event.
- if (!_ignoreNextMouseUp) {
- if (_curHotspot >= 0)
- runHotspotScript(_curHotspot, kMouseUpScript);
- else
- checkInventoryClick();
- }
- _ignoreNextMouseUp = false;
+ if (_curHotspot >= 0)
+ runHotspotScript(_curHotspot, kMouseUpScript);
+ else
+ checkInventoryClick();
break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
@@ -239,7 +233,6 @@ void MohawkEngine_Riven::changeToStack(uint16 n) {
// Stop any videos playing
_video->stopVideos();
- _video->clearMLST();
// Clear the old stack files out
for (uint32 i = 0; i < _mhk.size(); i++)
@@ -317,6 +310,7 @@ void MohawkEngine_Riven::refreshCard() {
_gfx->clearWaterEffects();
_gfx->_activatedPLSTs.clear();
_video->stopVideos();
+ _video->_mlstRecords.clear();
_gfx->drawPLST(1);
_activatedSLST = false;
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index 11c3a4c0cb..f014b76fb8 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -113,6 +113,7 @@ public:
Common::RandomSource *_rnd;
Card _cardData;
+ bool _gameOver;
GUI::Debugger *getDebugger();
@@ -146,10 +147,6 @@ private:
uint32 *_vars;
uint32 _varCount;
- // Miscellaneous
- bool _gameOver;
- bool _ignoreNextMouseUp;
-
public:
Common::SeekableReadStream *getExtrasResource(uint32 tag, uint16 id);
bool _activatedSLST;
@@ -183,9 +180,6 @@ public:
uint32 *getLocalVar(uint32 index);
uint32 *matchVarToString(Common::String varName);
uint32 *matchVarToString(const char *varName);
-
- void setGameOver() { _gameOver = true; }
- void ignoreNextMouseUp() { _ignoreNextMouseUp = true; }
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 4e6bba1c2a..99afacc5ce 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -27,7 +27,7 @@
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
#include "mohawk/sound.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
#include "gui/message.h"
#include "common/events.h"
@@ -210,28 +210,7 @@ void RivenExternal::runEndGame(uint16 video) {
_vm->_video->playMovieBlocking(video);
// TODO: Play until the last frame and then run the credits
- _vm->setGameOver();
-}
-
-void RivenExternal::runDomeButtonMovie() {
- // This command just plays the video of the button moving down and up.
- _vm->_video->playMovieBlocking(2);
-}
-
-void RivenExternal::runDomeCheck() {
- // Check if we clicked while the golden frame was showing
-
- VideoHandle video = _vm->_video->findVideoHandle(1);
- assert(video != NULL_VID_HANDLE);
-
- int32 curFrame = _vm->_video->getCurFrame(video);
- int32 frameCount = _vm->_video->getFrameCount(video);
-
- // The final frame of the video is the 'golden' frame (double meaning: the
- // frame that is the magic one is the one with the golden symbol) but we
- // give a 3 frame leeway in either direction.
- if (frameCount - curFrame < 3 || curFrame < 3)
- *_vm->matchVarToString("domecheck") = 1;
+ _vm->_gameOver = true;
}
// ------------------------------------------------------------------------------------
@@ -239,13 +218,11 @@ void RivenExternal::runDomeCheck() {
// ------------------------------------------------------------------------------------
void RivenExternal::xastartupbtnhide(uint16 argc, uint16 *argv) {
- // The original game hides the start/setup buttons depending on an ini entry.
- // It's safe to ignore this command.
+ // The original game hides the start/setup buttons depending on an ini entry. It's safe to ignore this command.
}
void RivenExternal::xasetupcomplete(uint16 argc, uint16 *argv) {
- // The original game sets an ini entry to disable the setup button and use the
- // start button only. It's safe to ignore this part of the command.
+ // The original game sets an ini entry to disable the setup button and use the start button only. It's safe to ignore this part of the command.
_vm->_sound->stopSound();
_vm->changeToCard(1);
}
@@ -537,14 +514,13 @@ void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) {
if (heat) {
if (platform == 0) {
_vm->_video->activateMLST(7, _vm->getCurCard());
- _vm->_video->playMovie(7);
+ // TODO: Play video (non-blocking)
} else {
_vm->_video->activateMLST(8, _vm->getCurCard());
- _vm->_video->playMovie(8);
+ // TODO: Play video (non-blocking)
}
} else {
- _vm->_video->stopMovie(7);
- _vm->_video->stopMovie(8);
+ // TODO: Stop MLST's 7 and 8
}
_vm->refreshCard();
@@ -651,11 +627,11 @@ void RivenExternal::xbisland190_slidermw(uint16 argc, uint16 *argv) {
}
void RivenExternal::xbscpbtn(uint16 argc, uint16 *argv) {
- runDomeButtonMovie();
+ // TODO: Dome related
}
void RivenExternal::xbisland_domecheck(uint16 argc, uint16 *argv) {
- runDomeCheck();
+ // TODO: Dome related
}
void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) {
@@ -747,11 +723,11 @@ void RivenExternal::xgisland25_slidermw(uint16 argc, uint16 *argv) {
}
void RivenExternal::xgscpbtn(uint16 argc, uint16 *argv) {
- runDomeButtonMovie();
+ // TODO: Dome related
}
void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) {
- runDomeCheck();
+ // TODO: Dome related
}
void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) {
@@ -1002,11 +978,11 @@ void RivenExternal::xjdome25_slidermw(uint16 argc, uint16 *argv) {
}
void RivenExternal::xjscpbtn(uint16 argc, uint16 *argv) {
- runDomeButtonMovie();
+ // TODO: Dome related
}
void RivenExternal::xjisland3500_domecheck(uint16 argc, uint16 *argv) {
- runDomeCheck();
+ // TODO: Dome related
}
int RivenExternal::jspitElevatorLoop() {
@@ -1282,11 +1258,11 @@ void RivenExternal::xpisland990_elevcombo(uint16 argc, uint16 *argv) {
}
void RivenExternal::xpscpbtn(uint16 argc, uint16 *argv) {
- runDomeButtonMovie();
+ // TODO: Dome related
}
void RivenExternal::xpisland290_domecheck(uint16 argc, uint16 *argv) {
- runDomeCheck();
+ // TODO: Dome related
}
void RivenExternal::xpisland25_opencard(uint16 argc, uint16 *argv) {
@@ -1481,11 +1457,11 @@ void RivenExternal::xtakeit(uint16 argc, uint16 *argv) {
}
void RivenExternal::xtscpbtn(uint16 argc, uint16 *argv) {
- runDomeButtonMovie();
+ // TODO: Dome related
}
void RivenExternal::xtisland4990_domecheck(uint16 argc, uint16 *argv) {
- runDomeCheck();
+ // TODO: Dome related
}
void RivenExternal::xtisland5056_opencard(uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h
index 14bb51340c..8270a00854 100644
--- a/engines/mohawk/riven_external.h
+++ b/engines/mohawk/riven_external.h
@@ -57,8 +57,6 @@ private:
int jspitElevatorLoop();
void runDemoBoundaryDialog();
void runEndGame(uint16 video);
- void runDomeCheck();
- void runDomeButtonMovie();
// -----------------------------------------------------
// aspit (Main Menu, Books, Setup) external commands
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index d574a455c6..e809ad9642 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -28,7 +28,7 @@
#include "mohawk/riven_external.h"
#include "mohawk/riven_scripts.h"
#include "mohawk/sound.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
#include "common/stream.h"
#include "graphics/cursorman.h"
@@ -298,10 +298,13 @@ void RivenScript::processCommands(bool runCommands) {
// Command 1: draw tBMP resource (tbmp_id, left, top, right, bottom, u0, u1, u2, u3)
void RivenScript::drawBitmap(uint16 op, uint16 argc, uint16 *argv) {
- if (argc < 5) // Copy the image to the whole screen, ignoring the rest of the parameters
+ if (argc < 5) {
+ // Copy the image to the whole screen, ignoring the rest of the parameters
_vm->_gfx->copyImageToScreen(argv[0], 0, 0, 608, 392);
- else // Copy the image to a certain part of the screen
+ } else {
+ // Copy the image to a certain part of the screen
_vm->_gfx->copyImageToScreen(argv[0], argv[1], argv[2], argv[3], argv[4]);
+ }
// Now, update the screen
_vm->_gfx->updateScreen();
@@ -310,12 +313,6 @@ void RivenScript::drawBitmap(uint16 op, uint16 argc, uint16 *argv) {
// Command 2: go to card (card id)
void RivenScript::switchCard(uint16 op, uint16 argc, uint16 *argv) {
_vm->changeToCard(argv[0]);
-
- // WORKAROUND: If we changed card on a mouse down event,
- // we want to ignore the next mouse up event so we don't
- // change card when lifting the mouse on the next card.
- if (_scriptType == kMouseDownScript)
- _vm->ignoreNextMouseUp();
}
// Command 3: play an SLST from the script
@@ -550,8 +547,9 @@ void RivenScript::activateSLST(uint16 op, uint16 argc, uint16 *argv) {
// Command 41: activate MLST record and play
void RivenScript::activateMLSTAndPlay(uint16 op, uint16 argc, uint16 *argv) {
+ _vm->_video->enableMovie(argv[0] - 1);
_vm->_video->activateMLST(argv[0], _vm->getCurCard());
- _vm->_video->playMovie(argv[0]);
+ // TODO: Play movie (blocking?)
}
// Command 43: activate BLST record (card hotspot enabling lists)
diff --git a/graphics/video/codecs/cinepak.cpp b/engines/mohawk/video/cinepak.cpp
index d3448bb8f7..2ffe6869ae 100644
--- a/graphics/video/codecs/cinepak.cpp
+++ b/engines/mohawk/video/cinepak.cpp
@@ -23,33 +23,32 @@
*
*/
-#include "graphics/video/codecs/cinepak.h"
+#include "mohawk/video/cinepak.h"
#include "common/system.h"
+#include "graphics/conversion.h" // For YUV2RGB
// Code here partially based off of ffmpeg ;)
-namespace Graphics {
-
-// Convert a color from YUV to RGB colorspace, Cinepak style.
-inline static void CPYUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) {
- r = CLIP<int>(y + 2 * (v - 128), 0, 255);
- g = CLIP<int>(y - (u - 128) / 2 - (v - 128), 0, 255);
- b = CLIP<int>(y + 2 * (u - 128), 0, 255);
-}
+namespace Mohawk {
#define PUT_PIXEL(offset, lum, u, v) \
- CPYUV2RGB(lum, u, v, r, g, b); \
+ Graphics::CPYUV2RGB(lum, u, v, r, g, b); \
if (_pixelFormat.bytesPerPixel == 2) \
*((uint16 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \
else \
*((uint32 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b)
-CinepakDecoder::CinepakDecoder() : Codec() {
+CinepakDecoder::CinepakDecoder() : Graphics::Codec() {
_curFrame.surface = NULL;
_curFrame.strips = NULL;
_y = 0;
_pixelFormat = g_system->getScreenFormat();
+
+ // We're going to have to dither if we're running in 8bpp.
+ // We'll take RGBA8888 for best color performance in this case.
+ if (_pixelFormat.bytesPerPixel == 1)
+ _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
}
CinepakDecoder::~CinepakDecoder() {
@@ -58,7 +57,7 @@ CinepakDecoder::~CinepakDecoder() {
delete[] _curFrame.strips;
}
-Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
+Graphics::Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
_curFrame.flags = stream->readByte();
_curFrame.length = (stream->readByte() << 16) + stream->readUint16BE();
_curFrame.width = stream->readUint16BE();
@@ -80,7 +79,7 @@ Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
#endif
if (!_curFrame.surface) {
- _curFrame.surface = new Surface();
+ _curFrame.surface = new Graphics::Surface();
_curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat.bytesPerPixel);
}
@@ -284,4 +283,4 @@ void CinepakDecoder::decodeVectors(Common::SeekableReadStream *stream, uint16 st
}
}
-} // End of namespace Graphics
+} // End of namespace Mohawk
diff --git a/graphics/video/codecs/cinepak.h b/engines/mohawk/video/cinepak.h
index 92351cdba8..3f4cbba17c 100644
--- a/graphics/video/codecs/cinepak.h
+++ b/engines/mohawk/video/cinepak.h
@@ -23,8 +23,8 @@
*
*/
-#ifndef GRAPHICS_CINEPAK_H
-#define GRAPHICS_CINEPAK_H
+#ifndef CINEPAK_H
+#define CINEPAK_H
#include "common/scummsys.h"
#include "common/stream.h"
@@ -34,7 +34,7 @@
#include "graphics/video/codecs/codec.h"
-namespace Graphics {
+namespace Mohawk {
struct CinepakCodebook {
byte y[4];
@@ -56,26 +56,26 @@ struct CinepakFrame {
uint16 stripCount;
CinepakStrip *strips;
- Surface *surface;
+ Graphics::Surface *surface;
};
-class CinepakDecoder : public Codec {
+class CinepakDecoder : public Graphics::Codec {
public:
CinepakDecoder();
~CinepakDecoder();
- Surface *decodeImage(Common::SeekableReadStream *stream);
- PixelFormat getPixelFormat() const { return _pixelFormat; }
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
CinepakFrame _curFrame;
int32 _y;
- PixelFormat _pixelFormat;
+ Graphics::PixelFormat _pixelFormat;
void loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize);
void decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize);
};
-} // End of namespace Graphics
+}
#endif
diff --git a/graphics/video/codecs/qdm2.cpp b/engines/mohawk/video/qdm2.cpp
index e12be21303..b91440f00d 100644
--- a/graphics/video/codecs/qdm2.cpp
+++ b/engines/mohawk/video/qdm2.cpp
@@ -25,270 +25,12 @@
// Based off ffmpeg's QDM2 decoder
-#include "graphics/video/codecs/qdm2.h"
+#include "mohawk/video/qdm2.h"
+#include "mohawk/video/qdm2data.h"
-#ifdef GRAPHICS_QDM2_H
-
-#include "sound/audiostream.h"
-#include "graphics/video/codecs/qdm2data.h"
-
-#include "common/array.h"
-#include "common/stream.h"
#include "common/system.h"
-namespace Graphics {
-
-enum {
- SOFTCLIP_THRESHOLD = 27600,
- HARDCLIP_THRESHOLD = 35716,
- MPA_MAX_CHANNELS = 2,
- MPA_FRAME_SIZE = 1152,
- FF_INPUT_BUFFER_PADDING_SIZE = 8
-};
-
-typedef int8 sb_int8_array[2][30][64];
-
-/* bit input */
-/* buffer, buffer_end and size_in_bits must be present and used by every reader */
-struct GetBitContext {
- const uint8 *buffer, *bufferEnd;
- int index;
- int sizeInBits;
-};
-
-struct QDM2SubPacket {
- int type;
- unsigned int size;
- const uint8 *data; // pointer to subpacket data (points to input data buffer, it's not a private copy)
-};
-
-struct QDM2SubPNode {
- QDM2SubPacket *packet;
- struct QDM2SubPNode *next; // pointer to next packet in the list, NULL if leaf node
-};
-
-struct QDM2Complex {
- float re;
- float im;
-};
-
-struct FFTTone {
- float level;
- QDM2Complex *complex;
- const float *table;
- int phase;
- int phase_shift;
- int duration;
- short time_index;
- short cutoff;
-};
-
-struct FFTCoefficient {
- int16 sub_packet;
- uint8 channel;
- int16 offset;
- int16 exp;
- uint8 phase;
-};
-
-struct VLC {
- int32 bits;
- int16 (*table)[2]; // code, bits
- int32 table_size;
- int32 table_allocated;
-};
-
-#include "common/pack-start.h"
-struct QDM2FFT {
- QDM2Complex complex[MPA_MAX_CHANNELS][256];
-} PACKED_STRUCT;
-#include "common/pack-end.h"
-
-enum RDFTransformType {
- RDFT,
- IRDFT,
- RIDFT,
- IRIDFT
-};
-
-struct FFTComplex {
- float re, im;
-};
-
-struct FFTContext {
- int nbits;
- int inverse;
- uint16 *revtab;
- FFTComplex *exptab;
- FFTComplex *tmpBuf;
- int mdctSize; // size of MDCT (i.e. number of input data * 2)
- int mdctBits; // n = 2^nbits
- // pre/post rotation tables
- float *tcos;
- float *tsin;
- void (*fftPermute)(struct FFTContext *s, FFTComplex *z);
- void (*fftCalc)(struct FFTContext *s, FFTComplex *z);
- void (*imdctCalc)(struct FFTContext *s, float *output, const float *input);
- void (*imdctHalf)(struct FFTContext *s, float *output, const float *input);
- void (*mdctCalc)(struct FFTContext *s, float *output, const float *input);
- int splitRadix;
- int permutation;
-};
-
-enum {
- FF_MDCT_PERM_NONE = 0,
- FF_MDCT_PERM_INTERLEAVE = 1
-};
-
-struct RDFTContext {
- int nbits;
- int inverse;
- int signConvention;
-
- // pre/post rotation tables
- float *tcos;
- float *tsin;
- FFTContext fft;
-};
-
-class QDM2Stream : public Audio::AudioStream {
-public:
- QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
- ~QDM2Stream();
-
- bool isStereo() const { return _channels == 2; }
- bool endOfData() const { return ((_stream->pos() == _stream->size()) && (_outputSamples.size() == 0)); }
- int getRate() const { return _sampleRate; }
- int readBuffer(int16 *buffer, const int numSamples);
-
-private:
- Common::SeekableReadStream *_stream;
-
- // Parameters from codec header, do not change during playback
- uint8 _channels;
- uint16 _sampleRate;
- uint16 _bitRate;
- uint16 _blockSize; // Group
- uint16 _frameSize; // FFT
- uint16 _packetSize; // Checksum
-
- // Parameters built from header parameters, do not change during playback
- int _groupOrder; // order of frame group
- int _fftOrder; // order of FFT (actually fft order+1)
- int _fftFrameSize; // size of fft frame, in components (1 comples = re + im)
- int _sFrameSize; // size of data frame
- int _frequencyRange;
- int _subSampling; // subsampling: 0=25%, 1=50%, 2=100% */
- int _coeffPerSbSelect; // selector for "num. of coeffs. per subband" tables. Can be 0, 1, 2
- int _cmTableSelect; // selector for "coding method" tables. Can be 0, 1 (from init: 0-4)
-
- // Packets and packet lists
- QDM2SubPacket _subPackets[16]; // the packets themselves
- QDM2SubPNode _subPacketListA[16]; // list of all packets
- QDM2SubPNode _subPacketListB[16]; // FFT packets B are on list
- int _subPacketsB; // number of packets on 'B' list
- QDM2SubPNode _subPacketListC[16]; // packets with errors?
- QDM2SubPNode _subPacketListD[16]; // DCT packets
-
- // FFT and tones
- FFTTone _fftTones[1000];
- int _fftToneStart;
- int _fftToneEnd;
- FFTCoefficient _fftCoefs[1000];
- int _fftCoefsIndex;
- int _fftCoefsMinIndex[5];
- int _fftCoefsMaxIndex[5];
- int _fftLevelExp[6];
- //RDFTContext _rdftCtx;
- QDM2FFT _fft;
-
- // I/O data
- uint8 *_compressedData;
- float _outputBuffer[1024];
- Common::Array<int16> _outputSamples;
-
- // Synthesis filter
- int16 ff_mpa_synth_window[512];
- int16 _synthBuf[MPA_MAX_CHANNELS][512*2];
- int _synthBufOffset[MPA_MAX_CHANNELS];
- int32 _sbSamples[MPA_MAX_CHANNELS][128][32];
-
- // Mixed temporary data used in decoding
- float _toneLevel[MPA_MAX_CHANNELS][30][64];
- int8 _codingMethod[MPA_MAX_CHANNELS][30][64];
- int8 _quantizedCoeffs[MPA_MAX_CHANNELS][10][8];
- int8 _toneLevelIdxBase[MPA_MAX_CHANNELS][30][8];
- int8 _toneLevelIdxHi1[MPA_MAX_CHANNELS][3][8][8];
- int8 _toneLevelIdxMid[MPA_MAX_CHANNELS][26][8];
- int8 _toneLevelIdxHi2[MPA_MAX_CHANNELS][26];
- int8 _toneLevelIdx[MPA_MAX_CHANNELS][30][64];
- int8 _toneLevelIdxTemp[MPA_MAX_CHANNELS][30][64];
-
- // Flags
- bool _hasErrors; // packet has errors
- int _superblocktype_2_3; // select fft tables and some algorithm based on superblock type
- int _doSynthFilter; // used to perform or skip synthesis filter
-
- uint8 _subPacket; // 0 to 15
- int _noiseIdx; // index for dithering noise table
-
- byte _emptyBuffer[FF_INPUT_BUFFER_PADDING_SIZE];
-
- VLC _vlcTabLevel;
- VLC _vlcTabDiff;
- VLC _vlcTabRun;
- VLC _fftLevelExpAltVlc;
- VLC _fftLevelExpVlc;
- VLC _fftStereoExpVlc;
- VLC _fftStereoPhaseVlc;
- VLC _vlcTabToneLevelIdxHi1;
- VLC _vlcTabToneLevelIdxMid;
- VLC _vlcTabToneLevelIdxHi2;
- VLC _vlcTabType30;
- VLC _vlcTabType34;
- VLC _vlcTabFftToneOffset[5];
- bool _vlcsInitialized;
- void initVlc(void);
-
- uint16 _softclipTable[HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1];
- void softclipTableInit(void);
-
- float _noiseTable[4096];
- byte _randomDequantIndex[256][5];
- byte _randomDequantType24[128][3];
- void rndTableInit(void);
-
- float _noiseSamples[128];
- void initNoiseSamples(void);
-
- RDFTContext _rdftCtx;
-
- void average_quantized_coeffs(void);
- void build_sb_samples_from_noise(int sb);
- void fix_coding_method_array(int sb, int channels, sb_int8_array coding_method);
- void fill_tone_level_array(int flag);
- void fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
- sb_int8_array coding_method, int nb_channels,
- int c, int superblocktype_2_3, int cm_table_select);
- void synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max);
- void init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length);
- void init_tone_level_dequantization(GetBitContext *gb, int length);
- void process_subpacket_9(QDM2SubPNode *node);
- void process_subpacket_10(QDM2SubPNode *node, int length);
- void process_subpacket_11(QDM2SubPNode *node, int length);
- void process_subpacket_12(QDM2SubPNode *node, int length);
- void process_synthesis_subpackets(QDM2SubPNode *list);
- void qdm2_decode_super_block(void);
- void qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
- int channel, int exp, int phase);
- void qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b);
- void qdm2_decode_fft_packets(void);
- void qdm2_fft_generate_tone(FFTTone *tone);
- void qdm2_fft_tone_synthesizer(uint8 sub_packet);
- void qdm2_calculate_fft(int channel);
- void qdm2_synthesis_filter(uint8 index);
- int qdm2_decodeFrame(Common::SeekableReadStream *in);
-};
+namespace Mohawk {
// Fix compilation for non C99-compliant compilers, like MSVC
#ifndef int64_t
@@ -3318,10 +3060,4 @@ int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) {
return decodedSamples;
}
-Audio::AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
- return new QDM2Stream(stream, extraData);
-}
-
-} // End of namespace Graphics
-
-#endif
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qdm2.h b/engines/mohawk/video/qdm2.h
new file mode 100644
index 0000000000..ffa5f77030
--- /dev/null
+++ b/engines/mohawk/video/qdm2.h
@@ -0,0 +1,289 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_VIDEO_QDM2_H
+#define MOHAWK_VIDEO_QDM2_H
+
+#include "sound/audiostream.h"
+#include "common/array.h"
+#include "common/stream.h"
+
+namespace Mohawk {
+
+enum {
+ SOFTCLIP_THRESHOLD = 27600,
+ HARDCLIP_THRESHOLD = 35716,
+ MPA_MAX_CHANNELS = 2,
+ MPA_FRAME_SIZE = 1152,
+ FF_INPUT_BUFFER_PADDING_SIZE = 8
+};
+
+typedef int8 sb_int8_array[2][30][64];
+
+/* bit input */
+/* buffer, buffer_end and size_in_bits must be present and used by every reader */
+struct GetBitContext {
+ const uint8 *buffer, *bufferEnd;
+ int index;
+ int sizeInBits;
+};
+
+struct QDM2SubPacket {
+ int type;
+ unsigned int size;
+ const uint8 *data; // pointer to subpacket data (points to input data buffer, it's not a private copy)
+};
+
+struct QDM2SubPNode {
+ QDM2SubPacket *packet;
+ struct QDM2SubPNode *next; // pointer to next packet in the list, NULL if leaf node
+};
+
+struct QDM2Complex {
+ float re;
+ float im;
+};
+
+struct FFTTone {
+ float level;
+ QDM2Complex *complex;
+ const float *table;
+ int phase;
+ int phase_shift;
+ int duration;
+ short time_index;
+ short cutoff;
+};
+
+struct FFTCoefficient {
+ int16 sub_packet;
+ uint8 channel;
+ int16 offset;
+ int16 exp;
+ uint8 phase;
+};
+
+struct VLC {
+ int32 bits;
+ int16 (*table)[2]; // code, bits
+ int32 table_size;
+ int32 table_allocated;
+};
+
+#include "common/pack-start.h"
+struct QDM2FFT {
+ QDM2Complex complex[MPA_MAX_CHANNELS][256];
+} PACKED_STRUCT;
+#include "common/pack-end.h"
+
+enum RDFTransformType {
+ RDFT,
+ IRDFT,
+ RIDFT,
+ IRIDFT
+};
+
+struct FFTComplex {
+ float re, im;
+};
+
+struct FFTContext {
+ int nbits;
+ int inverse;
+ uint16 *revtab;
+ FFTComplex *exptab;
+ FFTComplex *tmpBuf;
+ int mdctSize; // size of MDCT (i.e. number of input data * 2)
+ int mdctBits; // n = 2^nbits
+ // pre/post rotation tables
+ float *tcos;
+ float *tsin;
+ void (*fftPermute)(struct FFTContext *s, FFTComplex *z);
+ void (*fftCalc)(struct FFTContext *s, FFTComplex *z);
+ void (*imdctCalc)(struct FFTContext *s, float *output, const float *input);
+ void (*imdctHalf)(struct FFTContext *s, float *output, const float *input);
+ void (*mdctCalc)(struct FFTContext *s, float *output, const float *input);
+ int splitRadix;
+ int permutation;
+};
+
+enum {
+ FF_MDCT_PERM_NONE = 0,
+ FF_MDCT_PERM_INTERLEAVE = 1
+};
+
+struct RDFTContext {
+ int nbits;
+ int inverse;
+ int signConvention;
+
+ // pre/post rotation tables
+ float *tcos;
+ float *tsin;
+ FFTContext fft;
+};
+
+class QDM2Stream : public Audio::AudioStream {
+public:
+ QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
+ ~QDM2Stream();
+
+ bool isStereo() const { return _channels == 2; }
+ bool endOfData() const { return ((_stream->pos() == _stream->size()) && (_outputSamples.size() == 0)); }
+ int getRate() const { return _sampleRate; }
+ int readBuffer(int16 *buffer, const int numSamples);
+
+private:
+ Common::SeekableReadStream *_stream;
+
+ // Parameters from codec header, do not change during playback
+ uint8 _channels;
+ uint16 _sampleRate;
+ uint16 _bitRate;
+ uint16 _blockSize; // Group
+ uint16 _frameSize; // FFT
+ uint16 _packetSize; // Checksum
+
+ // Parameters built from header parameters, do not change during playback
+ int _groupOrder; // order of frame group
+ int _fftOrder; // order of FFT (actually fft order+1)
+ int _fftFrameSize; // size of fft frame, in components (1 comples = re + im)
+ int _sFrameSize; // size of data frame
+ int _frequencyRange;
+ int _subSampling; // subsampling: 0=25%, 1=50%, 2=100% */
+ int _coeffPerSbSelect; // selector for "num. of coeffs. per subband" tables. Can be 0, 1, 2
+ int _cmTableSelect; // selector for "coding method" tables. Can be 0, 1 (from init: 0-4)
+
+ // Packets and packet lists
+ QDM2SubPacket _subPackets[16]; // the packets themselves
+ QDM2SubPNode _subPacketListA[16]; // list of all packets
+ QDM2SubPNode _subPacketListB[16]; // FFT packets B are on list
+ int _subPacketsB; // number of packets on 'B' list
+ QDM2SubPNode _subPacketListC[16]; // packets with errors?
+ QDM2SubPNode _subPacketListD[16]; // DCT packets
+
+ // FFT and tones
+ FFTTone _fftTones[1000];
+ int _fftToneStart;
+ int _fftToneEnd;
+ FFTCoefficient _fftCoefs[1000];
+ int _fftCoefsIndex;
+ int _fftCoefsMinIndex[5];
+ int _fftCoefsMaxIndex[5];
+ int _fftLevelExp[6];
+ //RDFTContext _rdftCtx;
+ QDM2FFT _fft;
+
+ // I/O data
+ uint8 *_compressedData;
+ float _outputBuffer[1024];
+ Common::Array<int16> _outputSamples;
+
+ // Synthesis filter
+ int16 ff_mpa_synth_window[512];
+ int16 _synthBuf[MPA_MAX_CHANNELS][512*2];
+ int _synthBufOffset[MPA_MAX_CHANNELS];
+ int32 _sbSamples[MPA_MAX_CHANNELS][128][32];
+
+ // Mixed temporary data used in decoding
+ float _toneLevel[MPA_MAX_CHANNELS][30][64];
+ int8 _codingMethod[MPA_MAX_CHANNELS][30][64];
+ int8 _quantizedCoeffs[MPA_MAX_CHANNELS][10][8];
+ int8 _toneLevelIdxBase[MPA_MAX_CHANNELS][30][8];
+ int8 _toneLevelIdxHi1[MPA_MAX_CHANNELS][3][8][8];
+ int8 _toneLevelIdxMid[MPA_MAX_CHANNELS][26][8];
+ int8 _toneLevelIdxHi2[MPA_MAX_CHANNELS][26];
+ int8 _toneLevelIdx[MPA_MAX_CHANNELS][30][64];
+ int8 _toneLevelIdxTemp[MPA_MAX_CHANNELS][30][64];
+
+ // Flags
+ bool _hasErrors; // packet has errors
+ int _superblocktype_2_3; // select fft tables and some algorithm based on superblock type
+ int _doSynthFilter; // used to perform or skip synthesis filter
+
+ uint8 _subPacket; // 0 to 15
+ int _noiseIdx; // index for dithering noise table
+
+ byte _emptyBuffer[FF_INPUT_BUFFER_PADDING_SIZE];
+
+ VLC _vlcTabLevel;
+ VLC _vlcTabDiff;
+ VLC _vlcTabRun;
+ VLC _fftLevelExpAltVlc;
+ VLC _fftLevelExpVlc;
+ VLC _fftStereoExpVlc;
+ VLC _fftStereoPhaseVlc;
+ VLC _vlcTabToneLevelIdxHi1;
+ VLC _vlcTabToneLevelIdxMid;
+ VLC _vlcTabToneLevelIdxHi2;
+ VLC _vlcTabType30;
+ VLC _vlcTabType34;
+ VLC _vlcTabFftToneOffset[5];
+ bool _vlcsInitialized;
+ void initVlc(void);
+
+ uint16 _softclipTable[HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1];
+ void softclipTableInit(void);
+
+ float _noiseTable[4096];
+ byte _randomDequantIndex[256][5];
+ byte _randomDequantType24[128][3];
+ void rndTableInit(void);
+
+ float _noiseSamples[128];
+ void initNoiseSamples(void);
+
+ RDFTContext _rdftCtx;
+
+ void average_quantized_coeffs(void);
+ void build_sb_samples_from_noise(int sb);
+ void fix_coding_method_array(int sb, int channels, sb_int8_array coding_method);
+ void fill_tone_level_array(int flag);
+ void fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
+ sb_int8_array coding_method, int nb_channels,
+ int c, int superblocktype_2_3, int cm_table_select);
+ void synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max);
+ void init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length);
+ void init_tone_level_dequantization(GetBitContext *gb, int length);
+ void process_subpacket_9(QDM2SubPNode *node);
+ void process_subpacket_10(QDM2SubPNode *node, int length);
+ void process_subpacket_11(QDM2SubPNode *node, int length);
+ void process_subpacket_12(QDM2SubPNode *node, int length);
+ void process_synthesis_subpackets(QDM2SubPNode *list);
+ void qdm2_decode_super_block(void);
+ void qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
+ int channel, int exp, int phase);
+ void qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b);
+ void qdm2_decode_fft_packets(void);
+ void qdm2_fft_generate_tone(FFTTone *tone);
+ void qdm2_fft_tone_synthesizer(uint8 sub_packet);
+ void qdm2_calculate_fft(int channel);
+ void qdm2_synthesis_filter(uint8 index);
+ int qdm2_decodeFrame(Common::SeekableReadStream *in);
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/graphics/video/codecs/qdm2data.h b/engines/mohawk/video/qdm2data.h
index 25ed102c4e..f1c18db41c 100644
--- a/graphics/video/codecs/qdm2data.h
+++ b/engines/mohawk/video/qdm2data.h
@@ -23,12 +23,12 @@
*
*/
-#ifndef GRAPHICS_QDM2DATA_H
-#define GRAPHICS_QDM2DATA_H
+#ifndef MOHAWK_VIDEO_QDM2DATA_H
+#define MOHAWK_VIDEO_QDM2DATA_H
#include "common/scummsys.h"
-namespace Graphics {
+namespace Mohawk {
/// VLC TABLES
@@ -526,6 +526,6 @@ static const float type34_delta[10] = { // FIXME: covers 8 entries..
0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f,
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/graphics/video/qt_decoder.cpp b/engines/mohawk/video/qt_player.cpp
index 49d2b0aed9..0ed05bb84d 100644
--- a/graphics/video/qt_decoder.cpp
+++ b/engines/mohawk/video/qt_player.cpp
@@ -31,33 +31,32 @@
// Seek function by Gael Chardon gael.dev@4now.net
//
-#include "graphics/video/qt_decoder.h"
+#include "mohawk/video/qt_player.h"
#include "common/debug.h"
#include "common/endian.h"
-#include "common/macresman.h"
#include "common/util.h"
#include "common/zlib.h"
// Audio codecs
#include "sound/decoders/adpcm.h"
#include "sound/decoders/raw.h"
-#include "graphics/video/codecs/qdm2.h"
+#include "mohawk/video/qdm2.h"
// Video codecs
-#include "graphics/video/codecs/cinepak.h"
-#include "graphics/video/codecs/mjpeg.h"
-#include "graphics/video/codecs/qtrle.h"
-#include "graphics/video/codecs/rpza.h"
-#include "graphics/video/codecs/smc.h"
+#include "mohawk/jpeg.h"
+#include "mohawk/video/cinepak.h"
+#include "mohawk/video/qtrle.h"
+#include "mohawk/video/rpza.h"
+#include "mohawk/video/smc.h"
-namespace Graphics {
+namespace Mohawk {
////////////////////////////////////////////
-// QuickTimeDecoder
+// QTPlayer
////////////////////////////////////////////
-QuickTimeDecoder::QuickTimeDecoder() : VideoDecoder() {
+QTPlayer::QTPlayer() : Graphics::VideoDecoder() {
_audStream = NULL;
_beginOffset = 0;
_videoCodec = NULL;
@@ -68,59 +67,55 @@ QuickTimeDecoder::QuickTimeDecoder() : VideoDecoder() {
_fd = 0;
_scaledSurface = 0;
_dirtyPalette = false;
- _resFork = new Common::MacResManager();
-
- initParseTable();
}
-QuickTimeDecoder::~QuickTimeDecoder() {
+QTPlayer::~QTPlayer() {
close();
- delete _resFork;
}
-uint16 QuickTimeDecoder::getWidth() const {
+uint16 QTPlayer::getWidth() const {
if (_videoStreamIndex < 0)
return 0;
return _streams[_videoStreamIndex]->width / getScaleMode();
}
-uint16 QuickTimeDecoder::getHeight() const {
+uint16 QTPlayer::getHeight() const {
if (_videoStreamIndex < 0)
return 0;
return _streams[_videoStreamIndex]->height / getScaleMode();
}
-uint32 QuickTimeDecoder::getFrameCount() const {
+uint32 QTPlayer::getFrameCount() const {
if (_videoStreamIndex < 0)
return 0;
return _streams[_videoStreamIndex]->nb_frames;
}
-byte QuickTimeDecoder::getBitsPerPixel() {
+byte QTPlayer::getBitsPerPixel() {
if (_videoStreamIndex < 0)
return 0;
return _streams[_videoStreamIndex]->bits_per_sample & 0x1F;
}
-uint32 QuickTimeDecoder::getCodecTag() {
+uint32 QTPlayer::getCodecTag() {
if (_videoStreamIndex < 0)
return 0;
return _streams[_videoStreamIndex]->codec_tag;
}
-ScaleMode QuickTimeDecoder::getScaleMode() const {
+ScaleMode QTPlayer::getScaleMode() const {
if (_videoStreamIndex < 0)
return kScaleNormal;
return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode);
}
-uint32 QuickTimeDecoder::getFrameDuration() {
+uint32 QTPlayer::getFrameDuration() {
if (_videoStreamIndex < 0)
return 0;
@@ -138,16 +133,17 @@ uint32 QuickTimeDecoder::getFrameDuration() {
return 0;
}
-PixelFormat QuickTimeDecoder::getPixelFormat() const {
+Graphics::PixelFormat QTPlayer::getPixelFormat() const {
if (!_videoCodec)
- return PixelFormat::createFormatCLUT8();
+ return Graphics::PixelFormat::createFormatCLUT8();
return _videoCodec->getPixelFormat();
}
-void QuickTimeDecoder::rewind() {
- VideoDecoder::reset();
- _nextFrameStartTime = 0;
+void QTPlayer::rewind() {
+ delete _videoCodec; _videoCodec = NULL;
+ _curFrame = -1;
+ _startTime = _nextFrameStartTime = 0;
// Restart the audio too
stopAudio();
@@ -158,7 +154,7 @@ void QuickTimeDecoder::rewind() {
startAudio();
}
-Codec *QuickTimeDecoder::createCodec(uint32 codecTag, byte bitsPerPixel) {
+Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) {
if (codecTag == MKID_BE('cvid')) {
// Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this.
return new CinepakDecoder();
@@ -179,7 +175,7 @@ Codec *QuickTimeDecoder::createCodec(uint32 codecTag, byte bitsPerPixel) {
warning ("Sorenson Video 3 not yet supported");
} else if (codecTag == MKID_BE('jpeg')) {
// Motion JPEG: Used by some Myst ME 10th Anniversary videos.
- return new JPEGDecoder();
+ return new JPEGDecoder(true);
} else if (codecTag == MKID_BE('QkBk')) {
// CDToons: Used by most of the Broderbund games. This is an unknown format so far.
warning ("CDToons not yet supported");
@@ -190,24 +186,24 @@ Codec *QuickTimeDecoder::createCodec(uint32 codecTag, byte bitsPerPixel) {
return NULL;
}
-void QuickTimeDecoder::startAudio() {
+void QTPlayer::startAudio() {
if (_audStream) // No audio/audio not supported
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream);
}
-void QuickTimeDecoder::stopAudio() {
+void QTPlayer::stopAudio() {
if (_audStream) {
g_system->getMixer()->stopHandle(_audHandle);
_audStream = NULL; // the mixer automatically frees the stream
}
}
-void QuickTimeDecoder::pauseVideoIntern(bool pause) {
+void QTPlayer::pauseVideoIntern(bool pause) {
if (_audStream)
g_system->getMixer()->pauseHandle(_audHandle, pause);
}
-Surface *QuickTimeDecoder::decodeNextFrame() {
+Graphics::Surface *QTPlayer::decodeNextFrame() {
if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1)
return NULL;
@@ -220,7 +216,7 @@ Surface *QuickTimeDecoder::decodeNextFrame() {
Common::SeekableReadStream *frameData = getNextFramePacket();
if (frameData) {
- Surface *frame = _videoCodec->decodeImage(frameData);
+ Graphics::Surface *frame = _videoCodec->decodeImage(frameData);
delete frameData;
return scaleSurface(frame);
}
@@ -228,7 +224,7 @@ Surface *QuickTimeDecoder::decodeNextFrame() {
return NULL;
}
-Surface *QuickTimeDecoder::scaleSurface(Surface *frame) {
+Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) {
if (getScaleMode() == kScaleNormal)
return frame;
@@ -241,22 +237,26 @@ Surface *QuickTimeDecoder::scaleSurface(Surface *frame) {
return _scaledSurface;
}
-bool QuickTimeDecoder::endOfVideo() const {
- return (!_audStream || _audStream->endOfData()) && (!_videoCodec || VideoDecoder::endOfVideo());
+bool QTPlayer::endOfVideo() const {
+ return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1);
+}
+
+bool QTPlayer::needsUpdate() const {
+ return !endOfVideo() && getTimeToNextFrame() == 0;
}
-uint32 QuickTimeDecoder::getElapsedTime() const {
+uint32 QTPlayer::getElapsedTime() const {
if (_audStream)
return g_system->getMixer()->getSoundElapsedTime(_audHandle);
return g_system->getMillis() - _startTime;
}
-uint32 QuickTimeDecoder::getTimeToNextFrame() const {
+uint32 QTPlayer::getTimeToNextFrame() const {
if (endOfVideo() || _curFrame < 0)
return 0;
- // Convert from the QuickTime rate base to 1000
+ // Convert from the Sega FILM base to 1000
uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale;
uint32 elapsedTime = getElapsedTime();
@@ -266,47 +266,7 @@ uint32 QuickTimeDecoder::getTimeToNextFrame() const {
return nextFrameStartTime - elapsedTime;
}
-bool QuickTimeDecoder::loadFile(const Common::String &filename) {
- if (!_resFork->open(filename) || !_resFork->hasDataFork())
- return false;
-
- _foundMOOV = _foundMDAT = false;
- _numStreams = 0;
- _partial = 0;
- _videoStreamIndex = _audioStreamIndex = -1;
- _startTime = 0;
-
- MOVatom atom = { 0, 0, 0xffffffff };
-
- if (_resFork->hasResFork()) {
- // Search for a 'moov' resource
- Common::MacResIDArray idArray = _resFork->getResIDArray(MKID_BE('moov'));
-
- if (!idArray.empty())
- _fd = _resFork->getResource(MKID_BE('moov'), idArray[0]);
-
- if (_fd) {
- atom.size = _fd->size();
- if (readDefault(atom) < 0 || !_foundMOOV)
- return false;
- }
- delete _fd;
-
- atom.type = 0;
- atom.offset = 0;
- atom.size = 0xffffffff;
- }
-
- _fd = _resFork->getDataFork();
-
- if (readDefault(atom) < 0 || !_foundMOOV || !_foundMDAT)
- return false;
-
- init();
- return true;
-}
-
-bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) {
+bool QTPlayer::load(Common::SeekableReadStream &stream) {
_fd = &stream;
_foundMOOV = _foundMDAT = false;
_numStreams = 0;
@@ -314,22 +274,21 @@ bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) {
_videoStreamIndex = _audioStreamIndex = -1;
_startTime = 0;
+ initParseTable();
+
MOVatom atom = { 0, 0, 0xffffffff };
- if (readDefault(atom) < 0 || !_foundMOOV || !_foundMDAT) {
- _fd = 0;
+ if (readDefault(atom) < 0 || (!_foundMOOV && !_foundMDAT))
return false;
- }
- init();
- return true;
-}
+ debug(0, "on_parse_exit_offset=%d", _fd->pos());
-void QuickTimeDecoder::init() {
// some cleanup : make sure we are on the mdat atom
if((uint32)_fd->pos() != _mdatOffset)
_fd->seek(_mdatOffset, SEEK_SET);
+ _next_chunk_offset = _mdatOffset; // initialise reading
+
for (uint32 i = 0; i < _numStreams;) {
if (_streams[i]->codec_type == CODEC_TYPE_MOV_OTHER) {// not audio, not video, delete
delete _streams[i];
@@ -343,12 +302,14 @@ void QuickTimeDecoder::init() {
for (uint32 i = 0; i < _numStreams; i++) {
MOVStreamContext *sc = _streams[i];
- if (!sc->time_rate)
+ if(!sc->time_rate)
sc->time_rate = 1;
- if (!sc->time_scale)
+ if(!sc->time_scale)
sc->time_scale = _timeScale;
+ //av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale);
+
sc->duration /= sc->time_rate;
sc->ffindex = i;
@@ -376,64 +337,61 @@ void QuickTimeDecoder::init() {
if (getScaleMode() != kScaleNormal) {
// We have to initialize the scaled surface
- _scaledSurface = new Surface();
+ _scaledSurface = new Graphics::Surface();
_scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
}
}
+
+ return true;
}
-void QuickTimeDecoder::initParseTable() {
+void QTPlayer::initParseTable() {
static const ParseTable p[] = {
- { &QuickTimeDecoder::readDefault, MKID_BE('dinf') },
- { &QuickTimeDecoder::readLeaf, MKID_BE('dref') },
- { &QuickTimeDecoder::readDefault, MKID_BE('edts') },
- { &QuickTimeDecoder::readELST, MKID_BE('elst') },
- { &QuickTimeDecoder::readHDLR, MKID_BE('hdlr') },
- { &QuickTimeDecoder::readMDAT, MKID_BE('mdat') },
- { &QuickTimeDecoder::readMDHD, MKID_BE('mdhd') },
- { &QuickTimeDecoder::readDefault, MKID_BE('mdia') },
- { &QuickTimeDecoder::readDefault, MKID_BE('minf') },
- { &QuickTimeDecoder::readMOOV, MKID_BE('moov') },
- { &QuickTimeDecoder::readMVHD, MKID_BE('mvhd') },
- { &QuickTimeDecoder::readLeaf, MKID_BE('smhd') },
- { &QuickTimeDecoder::readDefault, MKID_BE('stbl') },
- { &QuickTimeDecoder::readSTCO, MKID_BE('stco') },
- { &QuickTimeDecoder::readSTSC, MKID_BE('stsc') },
- { &QuickTimeDecoder::readSTSD, MKID_BE('stsd') },
- { &QuickTimeDecoder::readSTSS, MKID_BE('stss') },
- { &QuickTimeDecoder::readSTSZ, MKID_BE('stsz') },
- { &QuickTimeDecoder::readSTTS, MKID_BE('stts') },
- { &QuickTimeDecoder::readTKHD, MKID_BE('tkhd') },
- { &QuickTimeDecoder::readTRAK, MKID_BE('trak') },
- { &QuickTimeDecoder::readLeaf, MKID_BE('udta') },
- { &QuickTimeDecoder::readLeaf, MKID_BE('vmhd') },
- { &QuickTimeDecoder::readCMOV, MKID_BE('cmov') },
- { &QuickTimeDecoder::readWAVE, MKID_BE('wave') },
+ { MKID_BE('dinf'), &QTPlayer::readDefault },
+ { MKID_BE('dref'), &QTPlayer::readLeaf },
+ { MKID_BE('edts'), &QTPlayer::readDefault },
+ { MKID_BE('elst'), &QTPlayer::readELST },
+ { MKID_BE('hdlr'), &QTPlayer::readHDLR },
+ { MKID_BE('mdat'), &QTPlayer::readMDAT },
+ { MKID_BE('mdhd'), &QTPlayer::readMDHD },
+ { MKID_BE('mdia'), &QTPlayer::readDefault },
+ { MKID_BE('minf'), &QTPlayer::readDefault },
+ { MKID_BE('moov'), &QTPlayer::readMOOV },
+ { MKID_BE('mvhd'), &QTPlayer::readMVHD },
+ { MKID_BE('smhd'), &QTPlayer::readLeaf },
+ { MKID_BE('stbl'), &QTPlayer::readDefault },
+ { MKID_BE('stco'), &QTPlayer::readSTCO },
+ { MKID_BE('stsc'), &QTPlayer::readSTSC },
+ { MKID_BE('stsd'), &QTPlayer::readSTSD },
+ { MKID_BE('stss'), &QTPlayer::readSTSS },
+ { MKID_BE('stsz'), &QTPlayer::readSTSZ },
+ { MKID_BE('stts'), &QTPlayer::readSTTS },
+ { MKID_BE('tkhd'), &QTPlayer::readTKHD },
+ { MKID_BE('trak'), &QTPlayer::readTRAK },
+ { MKID_BE('udta'), &QTPlayer::readLeaf },
+ { MKID_BE('vmhd'), &QTPlayer::readLeaf },
+ { MKID_BE('cmov'), &QTPlayer::readCMOV },
+ { MKID_BE('wave'), &QTPlayer::readWAVE },
{ 0, 0 }
};
_parseTable = p;
}
-int QuickTimeDecoder::readDefault(MOVatom atom) {
+int QTPlayer::readDefault(MOVatom atom) {
uint32 total_size = 0;
MOVatom a;
int err = 0;
a.offset = atom.offset;
- while(((total_size + 8) < atom.size) && !_fd->eos() && _fd->pos() < _fd->size() && !err) {
+ while(((total_size + 8) < atom.size) && !_fd->eos() && !err) {
a.size = atom.size;
a.type = 0;
if (atom.size >= 8) {
a.size = _fd->readUint32BE();
a.type = _fd->readUint32BE();
-
- // Some QuickTime videos with resource forks have mdat chunks
- // that are of size 0. Adjust it so it's the correct size.
- if (a.type == MKID_BE('mdat') && a.size == 0)
- a.size = _fd->size();
}
total_size += 8;
@@ -485,14 +443,14 @@ int QuickTimeDecoder::readDefault(MOVatom atom) {
return err;
}
-int QuickTimeDecoder::readLeaf(MOVatom atom) {
+int QTPlayer::readLeaf(MOVatom atom) {
if (atom.size > 1)
_fd->seek(atom.size, SEEK_SET);
return 0;
}
-int QuickTimeDecoder::readMOOV(MOVatom atom) {
+int QTPlayer::readMOOV(MOVatom atom) {
if (readDefault(atom) < 0)
return -1;
@@ -506,7 +464,7 @@ int QuickTimeDecoder::readMOOV(MOVatom atom) {
return 0; // now go for mdat
}
-int QuickTimeDecoder::readCMOV(MOVatom atom) {
+int QTPlayer::readCMOV(MOVatom atom) {
#ifdef USE_ZLIB
// Read in the dcom atom
_fd->readUint32BE();
@@ -557,7 +515,7 @@ int QuickTimeDecoder::readCMOV(MOVatom atom) {
#endif
}
-int QuickTimeDecoder::readMVHD(MOVatom atom) {
+int QTPlayer::readMVHD(MOVatom atom) {
byte version = _fd->readByte(); // version
_fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
@@ -612,7 +570,7 @@ int QuickTimeDecoder::readMVHD(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readTRAK(MOVatom atom) {
+int QTPlayer::readTRAK(MOVatom atom) {
MOVStreamContext *sc = new MOVStreamContext();
if (!sc)
@@ -627,7 +585,7 @@ int QuickTimeDecoder::readTRAK(MOVatom atom) {
}
// this atom contains actual media data
-int QuickTimeDecoder::readMDAT(MOVatom atom) {
+int QTPlayer::readMDAT(MOVatom atom) {
if (atom.size == 0) // wrong one (MP4)
return 0;
@@ -644,7 +602,7 @@ int QuickTimeDecoder::readMDAT(MOVatom atom) {
return 0; // now go for moov
}
-int QuickTimeDecoder::readTKHD(MOVatom atom) {
+int QTPlayer::readTKHD(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
byte version = _fd->readByte();
@@ -704,7 +662,7 @@ int QuickTimeDecoder::readTKHD(MOVatom atom) {
}
// edit list atom
-int QuickTimeDecoder::readELST(MOVatom atom) {
+int QTPlayer::readELST(MOVatom atom) {
_fd->readByte(); // version
_fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
uint32 editCount = _streams[_numStreams - 1]->edit_count = _fd->readUint32BE(); // entries
@@ -723,7 +681,7 @@ int QuickTimeDecoder::readELST(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readHDLR(MOVatom atom) {
+int QTPlayer::readHDLR(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
_fd->readByte(); // version
@@ -764,7 +722,7 @@ int QuickTimeDecoder::readHDLR(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readMDHD(MOVatom atom) {
+int QTPlayer::readMDHD(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
byte version = _fd->readByte();
@@ -791,7 +749,7 @@ int QuickTimeDecoder::readMDHD(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readSTSD(MOVatom atom) {
+int QTPlayer::readSTSD(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
_fd->readByte(); // version
@@ -976,7 +934,7 @@ int QuickTimeDecoder::readSTSD(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readSTSC(MOVatom atom) {
+int QTPlayer::readSTSC(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
_fd->readByte(); // version
@@ -1001,7 +959,7 @@ int QuickTimeDecoder::readSTSC(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readSTSS(MOVatom atom) {
+int QTPlayer::readSTSS(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
_fd->readByte(); // version
@@ -1024,7 +982,7 @@ int QuickTimeDecoder::readSTSS(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readSTSZ(MOVatom atom) {
+int QTPlayer::readSTSZ(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
_fd->readByte(); // version
@@ -1056,7 +1014,7 @@ static uint32 ff_gcd(uint32 a, uint32 b) {
else return a;
}
-int QuickTimeDecoder::readSTTS(MOVatom atom) {
+int QTPlayer::readSTTS(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
uint32 duration = 0;
uint32 total_sample_count = 0;
@@ -1096,7 +1054,7 @@ int QuickTimeDecoder::readSTTS(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readSTCO(MOVatom atom) {
+int QTPlayer::readSTCO(MOVatom atom) {
MOVStreamContext *st = _streams[_numStreams - 1];
_fd->readByte(); // version
@@ -1130,7 +1088,7 @@ int QuickTimeDecoder::readSTCO(MOVatom atom) {
return 0;
}
-int QuickTimeDecoder::readWAVE(MOVatom atom) {
+int QTPlayer::readWAVE(MOVatom atom) {
if (_numStreams < 1)
return 0;
@@ -1149,7 +1107,7 @@ int QuickTimeDecoder::readWAVE(MOVatom atom) {
return 0;
}
-void QuickTimeDecoder::close() {
+void QTPlayer::close() {
stopAudio();
delete _videoCodec; _videoCodec = 0;
@@ -1158,7 +1116,6 @@ void QuickTimeDecoder::close() {
delete _streams[i];
delete _fd;
- _fd = 0;
if (_scaledSurface) {
_scaledSurface->free();
@@ -1169,10 +1126,10 @@ void QuickTimeDecoder::close() {
// The audio stream is deleted automatically
_audStream = NULL;
- VideoDecoder::reset();
+ Graphics::VideoDecoder::reset();
}
-Common::SeekableReadStream *QuickTimeDecoder::getNextFramePacket() {
+Common::SeekableReadStream *QTPlayer::getNextFramePacket() {
if (_videoStreamIndex < 0)
return NULL;
@@ -1225,22 +1182,17 @@ Common::SeekableReadStream *QuickTimeDecoder::getNextFramePacket() {
return _fd->readStream(_streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
}
-bool QuickTimeDecoder::checkAudioCodecSupport(uint32 tag) {
+bool QTPlayer::checkAudioCodecSupport(uint32 tag) {
// Check if the codec is a supported codec
- if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4'))
+ if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4') || tag == MKID_BE('QDM2'))
return true;
-#ifdef GRAPHICS_QDM2_H
- if (tag == MKID_BE('QDM2'))
- return true;
-#endif
-
warning("Audio Codec Not Supported: \'%s\'", tag2str(tag));
return false;
}
-Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStream *stream) {
+Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stream) {
if (!stream || _audioStreamIndex < 0)
return NULL;
@@ -1261,11 +1213,9 @@ Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStre
} else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('ima4')) {
// Riven uses this codec (as do some Myst ME videos)
return Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMApple, _streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels, 34);
-#ifdef GRAPHICS_QDM2_H
} else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) {
// Several Myst ME videos use this codec
- return makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
-#endif
+ return new QDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
}
error("Unsupported audio codec");
@@ -1273,12 +1223,12 @@ Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStre
return NULL;
}
-void QuickTimeDecoder::updateAudioBuffer() {
+void QTPlayer::updateAudioBuffer() {
if (!_audStream)
return;
- // Keep three streams in buffer so that if/when the first two end, it goes right into the next
- for (; _audStream->numQueuedStreams() < 3 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) {
+ // Keep two streams in buffer so that when the first ends, it goes right into the next
+ for (; _audStream->numQueuedStreams() < 2 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) {
Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic();
_fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]);
@@ -1319,4 +1269,4 @@ void QuickTimeDecoder::updateAudioBuffer() {
}
}
-} // End of namespace Graphics
+} // End of namespace Mohawk
diff --git a/graphics/video/qt_decoder.h b/engines/mohawk/video/qt_player.h
index db4ff8180b..6657d3edba 100644
--- a/graphics/video/qt_decoder.h
+++ b/engines/mohawk/video/qt_player.h
@@ -31,8 +31,8 @@
// Seek function by Gael Chardon gael.dev@4now.net
//
-#ifndef GRAPHICS_QT_DECODER_H
-#define GRAPHICS_QT_DECODER_H
+#ifndef MOHAWK_QT_PLAYER_H
+#define MOHAWK_QT_PLAYER_H
#include "common/scummsys.h"
#include "common/queue.h"
@@ -45,10 +45,9 @@
namespace Common {
class File;
- class MacResManager;
}
-namespace Graphics {
+namespace Mohawk {
enum ScaleMode {
kScaleNormal = 1,
@@ -56,10 +55,10 @@ enum ScaleMode {
kScaleQuarter = 4
};
-class QuickTimeDecoder : public RewindableVideoDecoder {
+class QTPlayer : public Graphics::RewindableVideoDecoder {
public:
- QuickTimeDecoder();
- virtual ~QuickTimeDecoder();
+ QTPlayer();
+ virtual ~QTPlayer();
/**
* Returns the width of the video
@@ -80,12 +79,6 @@ public:
uint32 getFrameCount() const;
/**
- * Load a video file
- * @param filename the filename to load
- */
- bool loadFile(const Common::String &filename);
-
- /**
* Load a QuickTime video file from a SeekableReadStream
* @param stream the stream to load
*/
@@ -111,11 +104,12 @@ public:
void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; }
bool isVideoLoaded() const { return _fd != 0; }
- Surface *decodeNextFrame();
+ Graphics::Surface *decodeNextFrame();
+ bool needsUpdate() const;
bool endOfVideo() const;
uint32 getElapsedTime() const;
uint32 getTimeToNextFrame() const;
- PixelFormat getPixelFormat() const;
+ Graphics::PixelFormat getPixelFormat() const;
// RewindableVideoDecoder API
void rewind();
@@ -137,8 +131,8 @@ protected:
};
struct ParseTable {
- int (QuickTimeDecoder::*func)(MOVatom atom);
uint32 type;
+ int (QTPlayer::*func)(MOVatom atom);
};
struct MOVstts {
@@ -227,6 +221,7 @@ protected:
uint32 _duration;
uint32 _mdatOffset;
uint32 _mdatSize;
+ uint32 _next_chunk_offset;
MOVStreamContext *_partial;
uint32 _numStreams;
int _ni;
@@ -235,7 +230,6 @@ protected:
byte _palette[256 * 3];
bool _dirtyPalette;
uint32 _beginOffset;
- Common::MacResManager *_resFork;
void initParseTable();
Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
@@ -244,7 +238,6 @@ protected:
uint32 getFrameDuration();
uint32 getCodecTag();
byte getBitsPerPixel();
- void init();
Audio::QueuingAudioStream *_audStream;
void startAudio();
@@ -253,13 +246,13 @@ protected:
uint _curAudioChunk;
Audio::SoundHandle _audHandle;
- Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
- Codec *_videoCodec;
+ Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
+ Graphics::Codec *_videoCodec;
uint32 _nextFrameStartTime;
int8 _videoStreamIndex;
- Surface *_scaledSurface;
- Surface *scaleSurface(Surface *frame);
+ Graphics::Surface *_scaledSurface;
+ Graphics::Surface *scaleSurface(Graphics::Surface *frame);
ScaleMode getScaleMode() const;
void pauseVideoIntern(bool pause);
@@ -284,6 +277,6 @@ protected:
int readWAVE(MOVatom atom);
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/graphics/video/codecs/qtrle.cpp b/engines/mohawk/video/qtrle.cpp
index 3e3fd4cfce..c06dbefcb3 100644
--- a/graphics/video/codecs/qtrle.cpp
+++ b/engines/mohawk/video/qtrle.cpp
@@ -26,7 +26,7 @@
// QuickTime RLE Decoder
// Based off ffmpeg's QuickTime RLE decoder (written by Mike Melanson)
-#include "graphics/video/codecs/qtrle.h"
+#include "mohawk/video/qtrle.h"
#include "common/scummsys.h"
#include "common/stream.h"
@@ -34,9 +34,9 @@
#include "graphics/colormasks.h"
#include "graphics/surface.h"
-namespace Graphics {
+namespace Mohawk {
-QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() {
+QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Graphics::Codec() {
_bitsPerPixel = bitsPerPixel;
_pixelFormat = g_system->getScreenFormat();
@@ -47,7 +47,7 @@ QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Cod
debug(2, "QTRLE corrected width: %d", width);
- _surface = new Surface();
+ _surface = new Graphics::Surface();
_surface->create(width, height, _bitsPerPixel <= 8 ? 1 : _pixelFormat.bytesPerPixel);
}
@@ -239,7 +239,7 @@ void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, u
while (rleCode--) {
// Convert from RGB555 to the format specified by the Overlay
byte r = 0, g = 0, b = 0;
- colorToRGB<ColorMasks<555> >(rgb16, r, g, b);
+ Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
}
} else {
@@ -252,7 +252,7 @@ void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, u
// Convert from RGB555 to the format specified by the Overlay
byte r = 0, g = 0, b = 0;
- colorToRGB<ColorMasks<555> >(rgb16, r, g, b);
+ Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
}
}
@@ -354,7 +354,7 @@ void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, u
}
}
-Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) {
+Graphics::Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) {
uint16 start_line = 0;
uint16 height = _surface->h;
@@ -417,4 +417,4 @@ QTRLEDecoder::~QTRLEDecoder() {
_surface->free();
}
-} // End of namespace Graphics
+} // End of namespace Mohawk
diff --git a/graphics/video/codecs/qtrle.h b/engines/mohawk/video/qtrle.h
index efbef14411..2832bd6b24 100644
--- a/graphics/video/codecs/qtrle.h
+++ b/engines/mohawk/video/qtrle.h
@@ -23,27 +23,27 @@
*
*/
-#ifndef GRAPHICS_VIDEO_QTRLE_H
-#define GRAPHICS_VIDEO_QTRLE_H
+#ifndef MOHAWK_QTRLE_H
+#define MOHAWK_QTRLE_H
#include "graphics/pixelformat.h"
#include "graphics/video/codecs/codec.h"
-namespace Graphics {
+namespace Mohawk {
-class QTRLEDecoder : public Codec {
+class QTRLEDecoder : public Graphics::Codec {
public:
QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel);
~QTRLEDecoder();
- Surface *decodeImage(Common::SeekableReadStream *stream);
- PixelFormat getPixelFormat() const { return _pixelFormat; }
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
byte _bitsPerPixel;
- Surface *_surface;
- PixelFormat _pixelFormat;
+ Graphics::Surface *_surface;
+ Graphics::PixelFormat _pixelFormat;
void decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
void decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp);
@@ -53,6 +53,6 @@ private:
void decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/graphics/video/codecs/rpza.cpp b/engines/mohawk/video/rpza.cpp
index f0ed72e730..f48c055ae2 100644
--- a/graphics/video/codecs/rpza.cpp
+++ b/engines/mohawk/video/rpza.cpp
@@ -25,14 +25,14 @@
// Based off ffmpeg's RPZA decoder
-#include "graphics/video/codecs/rpza.h"
+#include "mohawk/video/rpza.h"
#include "common/system.h"
#include "graphics/colormasks.h"
-namespace Graphics {
+namespace Mohawk {
-RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() {
+RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() {
_pixelFormat = g_system->getScreenFormat();
// We need to increase the surface size to a multiple of 4
@@ -42,7 +42,7 @@ RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() {
debug(2, "RPZA corrected width: %d", width);
- _surface = new Surface();
+ _surface = new Graphics::Surface();
_surface->create(width, height, _pixelFormat.bytesPerPixel);
}
@@ -60,7 +60,7 @@ RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() {
#define PUT_PIXEL(color) \
if ((int32)blockPtr < _surface->w * _surface->h) { \
byte r = 0, g = 0, b = 0; \
- colorToRGB<ColorMasks<555> >(color, r, g, b); \
+ Graphics::colorToRGB<Graphics::ColorMasks<555> >(color, r, g, b); \
if (_pixelFormat.bytesPerPixel == 2) \
*((uint16 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
else \
@@ -68,7 +68,7 @@ RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() {
} \
blockPtr++
-Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
+Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
uint16 colorA = 0, colorB = 0;
uint16 color4[4];
@@ -205,4 +205,4 @@ Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
return _surface;
}
-} // End of namespace Graphics
+} // End of namespace Mohawk
diff --git a/graphics/video/codecs/rpza.h b/engines/mohawk/video/rpza.h
index e6d32feb72..c6d0ada6f5 100644
--- a/graphics/video/codecs/rpza.h
+++ b/engines/mohawk/video/rpza.h
@@ -23,27 +23,27 @@
*
*/
-#ifndef GRAPHICS_VIDEO_RPZA_H
-#define GRAPHICS_VIDEO_RPZA_H
+#ifndef MOHAWK_RPZA_H
+#define MOHAWK_RPZA_H
#include "graphics/pixelformat.h"
#include "graphics/video/codecs/codec.h"
-namespace Graphics {
+namespace Mohawk {
-class RPZADecoder : public Codec {
+class RPZADecoder : public Graphics::Codec {
public:
RPZADecoder(uint16 width, uint16 height);
~RPZADecoder() { delete _surface; }
- Surface *decodeImage(Common::SeekableReadStream *stream);
- PixelFormat getPixelFormat() const { return _pixelFormat; }
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
- Surface *_surface;
- PixelFormat _pixelFormat;
+ Graphics::Surface *_surface;
+ Graphics::PixelFormat _pixelFormat;
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/graphics/video/codecs/smc.cpp b/engines/mohawk/video/smc.cpp
index 4661e3dc84..4a0d16dfcc 100644
--- a/graphics/video/codecs/smc.cpp
+++ b/engines/mohawk/video/smc.cpp
@@ -25,9 +25,9 @@
// Based off ffmpeg's SMC decoder
-#include "graphics/video/codecs/smc.h"
+#include "mohawk/video/smc.h"
-namespace Graphics {
+namespace Mohawk {
#define GET_BLOCK_COUNT() \
(opcode & 0x10) ? (1 + stream->readByte()) : 1 + (opcode & 0x0F);
@@ -382,4 +382,4 @@ Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) {
return _surface;
}
-} // End of namespace Graphics
+} // End of namespace Mohawk
diff --git a/graphics/video/codecs/smc.h b/engines/mohawk/video/smc.h
index 2d4355a83e..c52226100e 100644
--- a/graphics/video/codecs/smc.h
+++ b/engines/mohawk/video/smc.h
@@ -23,12 +23,12 @@
*
*/
-#ifndef GRAPHICS_VIDEO_SMC_H
-#define GRAPHICS_VIDEO_SMC_H
+#ifndef MOHAWK_VIDEO_SMC_H
+#define MOHAWK_VIDEO_SMC_H
#include "graphics/video/codecs/codec.h"
-namespace Graphics {
+namespace Mohawk {
enum {
CPAIR = 2,
@@ -37,16 +37,16 @@ enum {
COLORS_PER_TABLE = 256
};
-class SMCDecoder : public Codec {
+class SMCDecoder : public Graphics::Codec {
public:
SMCDecoder(uint16 width, uint16 height);
~SMCDecoder() { delete _surface; }
- Surface *decodeImage(Common::SeekableReadStream *stream);
- PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
private:
- Surface *_surface;
+ Graphics::Surface *_surface;
// SMC color tables
byte _colorPairs[COLORS_PER_TABLE * CPAIR];
@@ -54,6 +54,6 @@ private:
byte _colorOctets[COLORS_PER_TABLE * COCTET];
};
-} // End of namespace Graphics
+} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video/video.cpp
index a45a4294c8..86ecd4dedf 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video/video.cpp
@@ -24,10 +24,10 @@
*/
#include "mohawk/resource.h"
-#include "mohawk/video.h"
+#include "mohawk/video/video.h"
+#include "mohawk/video/qt_player.h"
#include "common/events.h"
-#include "graphics/video/qt_decoder.h"
namespace Mohawk {
@@ -35,19 +35,18 @@ VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
}
VideoManager::~VideoManager() {
+ _mlstRecords.clear();
stopVideos();
}
void VideoManager::pauseVideos() {
for (uint16 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].video)
- _videoStreams[i]->pauseVideo(true);
+ _videoStreams[i]->pauseVideo(true);
}
void VideoManager::resumeVideos() {
for (uint16 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].video)
- _videoStreams[i]->pauseVideo(false);
+ _videoStreams[i]->pauseVideo(false);
}
void VideoManager::stopVideos() {
@@ -90,7 +89,7 @@ void VideoManager::playMovieCentered(Common::String filename, bool clearScreen)
void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
bool continuePlaying = true;
- while (_videoStreams[videoHandle].video && !_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
+ while (!_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
if (updateBackgroundMovies())
_vm->_system->updateScreen();
@@ -121,10 +120,8 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
_vm->_system->delayMillis(10);
}
- delete _videoStreams[videoHandle].video;
- _videoStreams[videoHandle].video = 0;
- _videoStreams[videoHandle].id = 0;
- _videoStreams[videoHandle].filename.clear();
+ _videoStreams[videoHandle]->close();
+ _videoStreams.clear();
}
void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) {
@@ -155,9 +152,8 @@ bool VideoManager::updateBackgroundMovies() {
_videoStreams[i]->rewind();
} else {
delete _videoStreams[i].video;
- _videoStreams[i].video = 0;
- _videoStreams[i].id = 0;
- _videoStreams[i].filename.clear();
+ memset(&_videoStreams[i], 0, sizeof(VideoEntry));
+ _videoStreams[i].video = NULL;
continue;
}
}
@@ -244,15 +240,7 @@ void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
if (mlstRecord.u1 != 1)
warning("mlstRecord.u1 not 1");
- // We've found a match, add it
if (mlstRecord.index == mlstId) {
- // Make sure we don't have any duplicates
- for (uint32 j = 0; j < _mlstRecords.size(); j++)
- if (_mlstRecords[j].index == mlstRecord.index || _mlstRecords[j].code == mlstRecord.code) {
- _mlstRecords.remove_at(j);
- j--;
- }
-
_mlstRecords.push_back(mlstRecord);
break;
}
@@ -261,10 +249,6 @@ void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
delete mlstStream;
}
-void VideoManager::clearMLST() {
- _mlstRecords.clear();
-}
-
void VideoManager::playMovie(uint16 id) {
for (uint16 i = 0; i < _mlstRecords.size(); i++)
if (_mlstRecords[i].code == id) {
@@ -290,10 +274,8 @@ void VideoManager::stopMovie(uint16 id) {
if (_mlstRecords[i].code == id)
for (uint16 j = 0; j < _videoStreams.size(); j++)
if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- delete _videoStreams[j].video;
- _videoStreams[j].video = 0;
- _videoStreams[j].id = 0;
- _videoStreams[j].filename.clear();
+ delete _videoStreams[i].video;
+ memset(&_videoStreams[i].video, 0, sizeof(VideoEntry));
return;
}
}
@@ -334,7 +316,7 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool
// Otherwise, create a new entry
VideoEntry entry;
- entry.video = new Graphics::QuickTimeDecoder();
+ entry.video = new QTPlayer();
entry.x = x;
entry.y = y;
entry.filename = "";
@@ -364,7 +346,7 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u
// Otherwise, create a new entry
VideoEntry entry;
- entry.video = new Graphics::QuickTimeDecoder();
+ entry.video = new QTPlayer();
entry.x = x;
entry.y = y;
entry.filename = filename;
@@ -392,24 +374,4 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u
return _videoStreams.size() - 1;
}
-VideoHandle VideoManager::findVideoHandle(uint16 id) {
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_videoStreams[j].video && _mlstRecords[i].movieID == _videoStreams[j].id)
- return j;
-
- return NULL_VID_HANDLE;
-}
-
-int32 VideoManager::getCurFrame(const VideoHandle &handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getCurFrame();
-}
-
-uint32 VideoManager::getFrameCount(const VideoHandle &handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getFrameCount();
-}
-
} // End of namespace Mohawk
diff --git a/engines/mohawk/video.h b/engines/mohawk/video/video.h
index 6aa553e26b..a5d2bde65d 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video/video.h
@@ -28,10 +28,6 @@
#include "graphics/pixelformat.h"
-namespace Graphics {
- class QuickTimeDecoder;
-}
-
namespace Mohawk {
class MohawkEngine;
@@ -48,8 +44,10 @@ struct MLSTRecord {
uint16 u1;
};
+class QTPlayer;
+
struct VideoEntry {
- Graphics::QuickTimeDecoder *video;
+ QTPlayer *video;
uint16 x;
uint16 y;
bool loop;
@@ -57,7 +55,7 @@ struct VideoEntry {
uint16 id; // Riven only
bool enabled;
- Graphics::QuickTimeDecoder *operator->() const { assert(video); return video; }
+ QTPlayer *operator->() const { assert(video); return video; }
};
typedef int32 VideoHandle;
@@ -82,7 +80,6 @@ public:
// Riven-related functions
void activateMLST(uint16 mlstId, uint16 card);
- void clearMLST();
void enableMovie(uint16 id);
void disableMovie(uint16 id);
void disableAllMovies();
@@ -90,23 +87,19 @@ public:
void stopMovie(uint16 id);
void playMovieBlocking(uint16 id);
- // Handle functions
- VideoHandle findVideoHandle(uint16 id);
- int32 getCurFrame(const VideoHandle &handle);
- uint32 getFrameCount(const VideoHandle &handle);
+ // Riven-related variables
+ Common::Array<MLSTRecord> _mlstRecords;
private:
MohawkEngine *_vm;
- // Riven-related variables
- Common::Array<MLSTRecord> _mlstRecords;
+ void waitUntilMovieEnds(VideoHandle videoHandle);
// Keep tabs on any videos playing
Common::Array<VideoEntry> _videoStreams;
VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop);
VideoHandle createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop);
- void waitUntilMovieEnds(VideoHandle videoHandle);
};
} // End of namespace Mohawk
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index b5eb82b456..8864c84e2f 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -42,7 +42,6 @@ Debugger::Debugger(Parallaction *vm)
DCmd_Register("zones", WRAP_METHOD(Debugger, Cmd_Zones));
DCmd_Register("animations", WRAP_METHOD(Debugger, Cmd_Animations));
DCmd_Register("globalflags",WRAP_METHOD(Debugger, Cmd_GlobalFlags));
- DCmd_Register("toggleglobalflag",WRAP_METHOD(Debugger, Cmd_ToggleGlobalFlag));
DCmd_Register("localflags", WRAP_METHOD(Debugger, Cmd_LocalFlags));
DCmd_Register("locations", WRAP_METHOD(Debugger, Cmd_Locations));
DCmd_Register("gfxobjects", WRAP_METHOD(Debugger, Cmd_GfxObjects));
@@ -118,32 +117,6 @@ bool Debugger::Cmd_GlobalFlags(int argc, const char **argv) {
return true;
}
-bool Debugger::Cmd_ToggleGlobalFlag(int argc, const char **argv) {
-
- int i;
-
- switch (argc) {
- case 2:
- i = _vm->_globalFlagsNames->lookup(argv[1]);
- if (i == Table::notFound) {
- DebugPrintf("invalid flag '%s'\n", argv[1]);
- } else {
- i--;
- if ((_globalFlags & (1 << i)) == 0)
- _globalFlags |= (1 << i);
- else
- _globalFlags &= ~(1 << i);
- }
- break;
-
- default:
- DebugPrintf("toggleglobalflag <flag name>\n");
-
- }
-
- return true;
-}
-
bool Debugger::Cmd_LocalFlags(int argc, const char **argv) {
uint32 flags = _vm->getLocationFlags();
diff --git a/engines/parallaction/debug.h b/engines/parallaction/debug.h
index 5267206d04..54b578e95f 100644
--- a/engines/parallaction/debug.h
+++ b/engines/parallaction/debug.h
@@ -28,7 +28,6 @@ protected:
bool Cmd_Animations(int argc, const char **argv);
bool Cmd_LocalFlags(int argc, const char **argv);
bool Cmd_GlobalFlags(int argc, const char **argv);
- bool Cmd_ToggleGlobalFlag(int argc, const char **argv);
bool Cmd_Locations(int argc, const char **argv);
bool Cmd_GfxObjects(int argc, const char **argv);
bool Cmd_Programs(int argc, const char** argv);
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 7a28d18f17..6332600226 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -461,10 +461,6 @@ public:
void Parallaction::enterDialogueMode(ZonePtr z) {
- if (!z->u._speakDialogue) {
- return;
- }
-
debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u._filename.c_str());
_dialogueMan = createDialogueManager(z);
assert(_dialogueMan);
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index e145c0da94..d5d89616d2 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -337,7 +337,7 @@ DECLARE_COMMAND_OPCODE(speak) {
return;
}
- if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak && ctxt._cmd->_zone->u._speakDialogue) {
+ if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak) {
_vm->enterDialogueMode(ctxt._cmd->_zone);
} else {
_vm->_activeZone = ctxt._cmd->_zone;
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index bc1759ecd7..a7b1f6fe32 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -536,12 +536,12 @@ GfxObj *Gfx::renderFloatingLabel(Font *font, char *text) {
setupLabelSurface(*cnv, w, h);
- font->setColor((_gameType == GType_BRA) ? 0 : 7);
+ font->setColor((_vm->getGameType() == GType_BRA) ? 0 : 7);
font->drawString((byte*)cnv->pixels + 1, cnv->w, text);
font->drawString((byte*)cnv->pixels + 1 + cnv->w * 2, cnv->w, text);
font->drawString((byte*)cnv->pixels + cnv->w, cnv->w, text);
font->drawString((byte*)cnv->pixels + 2 + cnv->w, cnv->w, text);
- font->setColor((_gameType == GType_BRA) ? 11 : 1);
+ font->setColor((_vm->getGameType() == GType_BRA) ? 11 : 1);
font->drawString((byte*)cnv->pixels + 1 + cnv->w, cnv->w, text);
} else {
w = font->getStringWidth(text);
@@ -833,7 +833,7 @@ void Gfx::setBackground(uint type, BackgroundInfo *info) {
// The PC version of BRA needs the entries 20-31 of the palette to be constant, but
// the background resource files are screwed up. The right colors come from an unused
// bitmap (pointer.bmp). Nothing is known about the Amiga version so far.
- if ((_gameType == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
+ if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
int r, g, b;
for (uint i = 16; i < 32; i++) {
_backupPal.getEntry(i, r, g, b);
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index d6dd9feb19..60cc867226 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -204,13 +204,13 @@ int Input::updateGameInput() {
return event;
}
- if (_gameType == GType_Nippon) {
+ if (_vm->getGameType() == GType_Nippon) {
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame;
if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame;
}
} else
- if (_gameType == GType_BRA) {
+ if (_vm->getGameType() == GType_BRA) {
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
if (_keyPressed.keycode == Common::KEYCODE_F5) event = kEvIngameMenu;
}
@@ -326,13 +326,8 @@ bool Input::translateGameInput() {
if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || (ACTIONTYPE(z) == kZoneCommand))) {
- bool noWalk = z->_flags & kFlagsNoWalk; // check the explicit no-walk flag
- if (_gameType == GType_BRA) {
- // action performed on object marked for self-use do not need walk in BRA
- noWalk |= ((z->_flags & kFlagsYourself) != 0);
- }
-
- if (noWalk) {
+ if (z->_flags & kFlagsNoWalk) {
+ // character doesn't need to walk to take specified action
takeAction(z);
} else {
// action delayed: if Zone defined a moveto position the character is programmed to move there,
@@ -357,7 +352,7 @@ bool Input::translateGameInput() {
void Input::enterInventoryMode() {
Common::Point mousePos;
- getAbsoluteCursorPos(mousePos);
+ getCursorPos(mousePos);
bool hitCharacter = _vm->hitZone(kZoneYou, mousePos.x, mousePos.y);
if (hitCharacter) {
diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h
index 36231cfcc5..50a789247f 100644
--- a/engines/parallaction/objects.h
+++ b/engines/parallaction/objects.h
@@ -88,9 +88,9 @@ enum ZoneFlags {
kFlagsNoWalk = 0x800, // Zone: character doesn't need to walk towards object to interact
// BRA specific
- kFlagsYourself = 0x1000, // BRA: marks zones used by the character on him/herself
+ kFlagsYourself = 0x1000,
kFlagsScaled = 0x2000,
- kFlagsSelfuse = 0x4000, // BRA: marks zones to be preserved across location changes (see Parallaction::freeZones)
+ kFlagsSelfuse = 0x4000,
kFlagsIsAnimation = 0x1000000, // BRA: used in walk code (trap check), to tell is a Zone is an Animation
kFlagsAnimLinked = 0x2000000
};
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index ce7525345a..cb208a17ff 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -102,8 +102,7 @@ Parallaction::~Parallaction() {
Common::Error Parallaction::init() {
-
- _gameType = getGameType();
+
_engineFlags = 0;
_objectsNames = NULL;
_globalFlagsNames = NULL;
@@ -409,7 +408,7 @@ void Parallaction::drawAnimation(AnimationPtr anim) {
uint16 layer = LAYER_FOREGROUND;
uint16 scale = 100;
- switch (_gameType) {
+ switch (getGameType()) {
case GType_Nippon:
if ((anim->_flags & kFlagsNoMasked) == 0) {
// Layer in NS depends on where the animation is on the screen, for each animation.
@@ -524,7 +523,7 @@ void Parallaction::enterCommentMode(ZonePtr z) {
}
// TODO: move this balloons stuff into DialogueManager and BalloonManager
- if (_gameType == GType_Nippon) {
+ if (getGameType() == GType_Nippon) {
if (!data->_filename.empty()) {
if (data->_gfxobj == 0) {
data->_gfxobj = _disk->loadStatic(data->_filename.c_str());
@@ -541,7 +540,7 @@ void Parallaction::enterCommentMode(ZonePtr z) {
_gfx->setItem(_char._talk, 190, 80);
}
} else
- if (_gameType == GType_BRA) {
+ if (getGameType() == GType_BRA) {
_balloonMan->setSingleBalloon(data->_examineText.c_str(), 0, 0, 1, BalloonManager::kNormalColor);
_gfx->setItem(_char._talk, 10, 80);
}
@@ -652,21 +651,13 @@ bool Parallaction::pickupItem(ZonePtr z) {
return (slot != -1);
}
+// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
- // check if really a special zone
- if (_gameType == GType_Nippon) {
- // so-called special zones in NS have special x coordinates
- if ((z->getX() != -2) && (z->getX() != -3)) {
- return false;
- }
- }
- if (_gameType == GType_BRA) {
- // so far, special zones in BRA are only merge zones
- if (ACTIONTYPE(z) != kZoneMerge) {
- return false;
- }
+ // not a special zone
+ if ((z->getX() != -2) && (z->getX() != -3)) {
+ return false;
}
-
+
// WORKAROUND: this huge condition is needed because we made TypeData a collection of structs
// instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine,
// but we need to check it separately here. The same workaround is applied in freeZones.
@@ -690,33 +681,7 @@ bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
return false;
}
-bool Parallaction::checkZoneType(ZonePtr z, uint32 type) {
- if (_gameType == GType_Nippon) {
- if ((type == 0) && (ITEMTYPE(z) == 0))
- return true;
- }
-
- if (_gameType == GType_BRA) {
- if (type == 0) {
- if (ITEMTYPE(z) == 0) {
- if (ACTIONTYPE(z) != kZonePath) {
- return true;
- }
- }
- if (ACTIONTYPE(z) == kZoneDoor) {
- return true;
- }
- }
- }
-
- if (z->_type == type)
- return true;
- if (ITEMTYPE(z) == type)
- return true;
-
- return false;
-}
-
+// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
if (z->_flags & kFlagsRemove)
return false;
@@ -724,30 +689,29 @@ bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y);
if (!z->hitRect(x, y)) {
+
// check for special zones (items defined in common.loc)
if (checkSpecialZoneBox(z, type, x, y))
return true;
- // check if self-use zone (nothing to do with kFlagsSelfuse)
- if (_gameType == GType_Nippon) {
- if (z->getX() != -1) { // no explicit self-use flag in NS
- return false;
- }
- }
- if (_gameType == GType_BRA) {
- if (!(z->_flags & kFlagsYourself)) {
- return false;
- }
- }
- if (!_char._ani->hitFrameRect(x, y)) {
+ if (z->getX() != -1)
+ return false;
+ if (!_char._ani->hitFrameRect(x, y))
return false;
- }
- // we get here only if (x,y) hits the character and the zone is marked as self-use
}
- return checkZoneType(z, type);
+ // normal Zone
+ if ((type == 0) && (ITEMTYPE(z) == 0))
+ return true;
+ if (z->_type == type)
+ return true;
+ if (ITEMTYPE(z) == type)
+ return true;
+
+ return false;
}
+// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
if (z->_flags & kFlagsRemove)
return false;
@@ -763,14 +727,18 @@ bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
return false;
}
- return checkZoneType(z, type);
-}
+ // NOTE: the implementation of the following lines is a different in the
+ // original... it is working so far, though
+ if ((type == 0) && (ITEMTYPE(z) == 0))
+ return true;
+ if (z->_type == type)
+ return true;
+ if (ITEMTYPE(z) == type)
+ return true;
-/* NOTE: hitZone needs to be passed absolute game coordinates to work.
+ return false;
+}
- When type is kZoneMerge, then x and y are the identifiers of the objects to merge,
- and the above requirement does not apply.
-*/
ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
uint16 _di = y;
uint16 _si = x;
@@ -784,20 +752,14 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
}
}
+
int16 _a, _b, _c, _d;
bool _ef;
for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ++ait) {
AnimationPtr a = *ait;
- _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
-
- if (!_a) {
- if (_gameType == GType_BRA && ACTIONTYPE(a) != kZoneTrap) {
- continue;
- }
- }
-
+ _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
_ef = a->hitFrameRect(_si, _di);
_b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character)
@@ -989,7 +951,7 @@ bool CharacterName::dummy() const {
}
void Parallaction::beep() {
- if (_gameType == GType_Nippon) {
+ if (getGameType() == GType_Nippon) {
_soundMan->execute(SC_SETSFXCHANNEL, 3);
_soundMan->execute(SC_SETSFXVOLUME, 127);
_soundMan->execute(SC_SETSFXLOOPING, (int32)0);
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 151bfd958d..a5769350bd 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -280,7 +280,6 @@ public:
int32 _screenWidth;
int32 _screenHeight;
int32 _screenSize;
- int _gameType;
// subsystems
Gfx *_gfx;
@@ -361,7 +360,6 @@ public:
uint32 getLocationFlags();
bool checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y);
bool checkZoneBox(ZonePtr z, uint32 type, uint x, uint y);
- bool checkZoneType(ZonePtr z, uint32 type);
bool checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y);
ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
void runZone(ZonePtr z);
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index c752c85d4f..9fd46cc9af 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -195,7 +195,7 @@ void Parallaction_br::runPendingZones() {
if (_activeZone) {
z = _activeZone; // speak Zone or sound
_activeZone.reset();
- if (ACTIONTYPE(z) == kZoneSpeak && z->u._speakDialogue) {
+ if (ACTIONTYPE(z) == kZoneSpeak) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
@@ -205,7 +205,7 @@ void Parallaction_br::runPendingZones() {
if (_activeZone2) {
z = _activeZone2; // speak Zone or sound
_activeZone2.reset();
- if (ACTIONTYPE(z) == kZoneSpeak && z->u._speakDialogue) {
+ if (ACTIONTYPE(z) == kZoneSpeak) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index df1e91e8b4..928f3f5b74 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -44,10 +44,8 @@ Script::~Script() {
/*
* readLineIntern read a text line and prepares it for
* parsing, by stripping the leading whitespace and
- * changing tabs to spaces. It will stop on a CR, LF, or
- * SUB (0x1A), which may all occur at the end of a script
- * line.
- * Returns an empty string (length = 0) when a line
+ * changing tabs to spaces. It will stop on a CR or LF,
+ * and return an empty string (length = 0) when a line
* has no printable text in it.
*/
char *Script::readLineIntern(char *buf, size_t bufSize) {
@@ -56,8 +54,7 @@ char *Script::readLineIntern(char *buf, size_t bufSize) {
char c = _input->readSByte();
if (_input->eos())
break;
- // break if EOL
- if (c == '\n' || c == '\r' || c == (char)0x1A)
+ if (c == '\n' || c == '\r')
break;
if (c == '\t')
c = ' ';
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index ff24a06ceb..be72cf73a1 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -286,7 +286,6 @@ void LocationParser_ns::parseAnimation(AnimationList &list, char *name) {
debugC(5, kDebugParser, "parseAnimation(name: %s)", name);
if (_vm->_location.findAnimation(name)) {
- _zoneProg++;
_script->skip("endanimation");
return;
}
@@ -1306,7 +1305,6 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) {
debugC(5, kDebugParser, "parseZone(name: %s)", name);
if (_vm->_location.findZone(name)) {
- _zoneProg++;
_script->skip("endzone");
return;
}
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index 407dd86ec3..1c724ddc1c 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -172,11 +172,11 @@ bool MidiParser_MSC::loadMusic(byte *data, uint32 size) {
byte *pos = data;
- if (memcmp("MSCt", pos, 4)) {
+ uint32 signature = read4high(pos);
+ if (memcmp("tCSM", &signature, 4)) {
warning("Expected header not found in music file.");
return false;
}
- pos += 4;
_beats = read1(pos);
_ppqn = read2low(pos);
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index ed8a9055ba..2911d9c451 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -330,6 +330,20 @@ Common::Error SagaEngine::run() {
syncSoundSettings();
+
+#if 0
+ // FIXME: Disabled this code for now. We want to get rid of OSystem::kFeatureAutoComputeDirtyRects
+ // and this is the last place to make use of it. We need to find out whether doing
+ // so causes any regressions. If it does, we can reenable it, if not, we can remove
+ // this code in 0.13.0.
+
+ // FIXME: This is the ugly way of reducing redraw overhead. It works
+ // well for 320x200 but it's unclear how well it will work for
+ // 640x480.
+ if (getGameId() == GID_ITE)
+ _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
+#endif
+
int msec = 0;
_previousTicks = _system->getMillis();
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index bad39d3065..16bc69115f 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -47,7 +47,6 @@
#include "sci/graphics/cursor.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint.h"
-#include "sci/graphics/paint16.h"
#include "sci/graphics/palette.h"
#include "sci/parser/vocabulary.h"
@@ -105,7 +104,6 @@ Console::Console(SciEngine *engine) : GUI::Debugger() {
DCmd_Register("resource_types", WRAP_METHOD(Console, cmdResourceTypes));
DCmd_Register("list", WRAP_METHOD(Console, cmdList));
DCmd_Register("hexgrep", WRAP_METHOD(Console, cmdHexgrep));
- DCmd_Register("verify_scripts", WRAP_METHOD(Console, cmdVerifyScripts));
// Game
DCmd_Register("save_game", WRAP_METHOD(Console, cmdSaveGame));
DCmd_Register("restore_game", WRAP_METHOD(Console, cmdRestoreGame));
@@ -278,8 +276,8 @@ void Console::postEnter() {
#if 0
// Unused
#define LOOKUP_SPECIES(species) (\
- (species >= 1000) ? species : *(s->_classTable[species].scriptposp) \
- + s->_classTable[species].class_offset)
+ (species >= 1000) ? species : *(s->_classtable[species].scriptposp) \
+ + s->_classtable[species].class_offset)
#endif
bool Console::cmdHelp(int argc, const char **argv) {
@@ -325,7 +323,6 @@ bool Console::cmdHelp(int argc, const char **argv) {
DebugPrintf(" resource_types - Shows the valid resource types\n");
DebugPrintf(" list - Lists all the resources of a given type\n");
DebugPrintf(" hexgrep - Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers\n");
- DebugPrintf(" verify_scripts - Performs sanity checks on SCI1.1-SCI2.1 game scripts (e.g. if they're up to 64KB in total)\n");
DebugPrintf("\n");
DebugPrintf("Game:\n");
DebugPrintf(" save_game - Saves the current game state to the hard disk\n");
@@ -424,9 +421,10 @@ const char *selector_name(EngineState *s, int selector) {
bool Console::cmdGetVersion(int argc, const char **argv) {
const char *viewTypeDesc[] = { "Unknown", "EGA", "VGA", "VGA SCI1.1", "Amiga" };
+ EngineState *s = _engine->_gamestate;
bool hasVocab997 = g_sci->getResMan()->testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SELECTORS)) ? true : false;
- DebugPrintf("Game ID: %s\n", _engine->getGameID());
+ DebugPrintf("Game ID: %s\n", s->_gameId.c_str());
DebugPrintf("Emulated interpreter version: %s\n", getSciVersionDesc(getSciVersion()));
DebugPrintf("\n");
DebugPrintf("Detected features:\n");
@@ -813,40 +811,6 @@ bool Console::cmdHexgrep(int argc, const char **argv) {
return true;
}
-bool Console::cmdVerifyScripts(int argc, const char **argv) {
- if (getSciVersion() < SCI_VERSION_1_1) {
- DebugPrintf("This script check is only meant for SCI1.1-SCI2.1 games\n");
- return true;
- }
-
- Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript);
- sort(resources->begin(), resources->end(), ResourceIdLess());
- Common::List<ResourceId>::iterator itr = resources->begin();
-
- DebugPrintf("%d SCI1.1-SCI2.1 scripts found, performing sanity checks...\n", resources->size());
-
- Resource *script, *heap;
- while (itr != resources->end()) {
- script = _engine->getResMan()->findResource(*itr, false);
- if (!script)
- DebugPrintf("Error: script %d couldn't be loaded\n", itr->number);
-
- heap = _engine->getResMan()->findResource(*itr, false);
- if (!heap)
- DebugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->number);
-
- if (script && heap && (script->size + heap->size > 65535))
- DebugPrintf("Error: script and heap %d together are larger than 64KB (%d bytes)\n",
- itr->number, script->size + heap->size);
-
- ++itr;
- }
-
- DebugPrintf("SCI1.1-SCI2.1 script check finished\n");
-
- return true;
-}
-
bool Console::cmdList(int argc, const char **argv) {
if (argc < 2) {
DebugPrintf("Lists all the resources of a given type\n");
@@ -957,6 +921,22 @@ bool Console::cmdRestoreGame(int argc, const char **argv) {
}
bool Console::cmdRestartGame(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Restarts the game. There are two ways to restart a SCI game:\n");
+ DebugPrintf("%s play - calls the game object's play() method\n", argv[0]);
+ DebugPrintf("%s replay - calls the replay() methody\n", argv[0]);
+ return true;
+ }
+
+ if (!scumm_stricmp(argv[1], "play")) {
+ _engine->_gamestate->restarting_flags |= SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
+ } else if (!scumm_stricmp(argv[1], "replay")) {
+ _engine->_gamestate->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
+ } else {
+ DebugPrintf("Invalid usage of %s\n", argv[0]);
+ return true;
+ }
+
_engine->_gamestate->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
script_abort_flag = 1;
@@ -965,11 +945,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 < _engine->_gamestate->_segMan->classTableSize(); i++) {
- if (_engine->_gamestate->_segMan->_classTable[i].reg.segment) {
+ for (uint i = 0; i < _engine->_gamestate->_segMan->_classtable.size(); i++) {
+ if (_engine->_gamestate->_segMan->_classtable[i].reg.segment) {
DebugPrintf(" Class 0x%x at %04x:%04x (script 0x%x)\n", i,
- PRINT_REG(_engine->_gamestate->_segMan->_classTable[i].reg),
- _engine->_gamestate->_segMan->_classTable[i].script);
+ PRINT_REG(_engine->_gamestate->_segMan->_classtable[i].reg),
+ _engine->_gamestate->_segMan->_classtable[i].script);
}
}
@@ -1149,11 +1129,7 @@ bool Console::cmdUndither(int argc, const char **argv) {
bool flag = atoi(argv[1]) ? true : false;
_engine->_gfxScreen->debugUnditherSetState(flag);
- if (flag)
- DebugPrintf("undithering ENABLED\n");
- else
- DebugPrintf("undithering DISABLED\n");
- return true;
+ return false;
}
bool Console::cmdPicVisualize(int argc, const char **argv) {
@@ -1165,16 +1141,7 @@ bool Console::cmdPicVisualize(int argc, const char **argv) {
bool state = atoi(argv[1]) ? true : false;
- if (_engine->_resMan->getViewType() == kViewEga) {
- _engine->_gfxPaint16->debugSetEGAdrawingVisualize(state);
- if (state)
- DebugPrintf("picture visualization ENABLED\n");
- else
- DebugPrintf("picture visualization DISABLED\n");
- } else {
- DebugPrintf("picture visualization only available for EGA games\n");
- }
- return true;
+ return _engine->_gui->debugEGAdrawingVisualize(state);
}
bool Console::cmdPlayVideo(int argc, const char **argv) {
@@ -1281,13 +1248,13 @@ bool Console::segmentInfo(int nr) {
case SEG_TYPE_SCRIPT: {
Script *scr = (Script *)mobj;
- DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->getBufSize(), (uint)scr->getBufSize());
- if (scr->getExportTable())
- DebugPrintf(" Exports: %4d at %d\n", scr->getExportsNr(), (int)(((const byte *)scr->getExportTable()) - ((const byte *)scr->_buf)));
+ DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->_bufSize, (uint)scr->_bufSize);
+ if (scr->_exportTable)
+ DebugPrintf(" Exports: %4d at %d\n", scr->_numExports, (int)(((byte *)scr->_exportTable) - ((byte *)scr->_buf)));
else
DebugPrintf(" Exports: none\n");
- DebugPrintf(" Synonyms: %4d\n", scr->getSynonymsNr());
+ DebugPrintf(" Synonyms: %4d\n", scr->_numSynonyms);
if (scr->_localsBlock)
DebugPrintf(" Locals : %4d in segment 0x%x\n", scr->_localsBlock->_locals.size(), scr->_localsSegment);
@@ -1301,7 +1268,7 @@ bool Console::segmentInfo(int nr) {
for (it = scr->_objects.begin(); it != end; ++it) {
DebugPrintf(" ");
// Object header
- const Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos());
+ Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos());
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(it->_value.getPos()),
_engine->_gamestate->_segMan->getObjectName(it->_value.getPos()),
@@ -1348,7 +1315,7 @@ bool Console::segmentInfo(int nr) {
objpos.segment = nr;
DebugPrintf(" [%04x] %s; copy of ", i, _engine->_gamestate->_segMan->getObjectName(objpos));
// Object header
- const Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
+ Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(ct->_table[i].getPos()),
_engine->_gamestate->_segMan->getObjectName(ct->_table[i].getPos()),
@@ -1556,12 +1523,12 @@ bool Console::cmdToggleSound(int argc, const char **argv) {
int handle = id.segment << 16 | id.offset; // frobnicate handle
if (id.segment) {
- SegManager *segMan = _engine->_gamestate->_segMan; // for writeSelectorValue
+ SegManager *segMan = _engine->_gamestate->_segMan; // for PUT_SEL32V
_engine->_gamestate->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_engine->_gamestate->_sound.sfx_remove_song(handle);
- writeSelectorValue(segMan, id, SELECTOR(signal), SIGNAL_OFFSET);
- writeSelectorValue(segMan, id, SELECTOR(nodePtr), 0);
- writeSelectorValue(segMan, id, SELECTOR(handle), 0);
+ PUT_SEL32V(segMan, id, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(segMan, id, SELECTOR(nodePtr), 0);
+ PUT_SEL32V(segMan, id, SELECTOR(handle), 0);
}
#else
@@ -1795,7 +1762,7 @@ bool Console::cmdVMVars(int argc, const char **argv) {
const char *varabbrev = "gltp";
const char *vartype_pre = strchr(varabbrev, *argv[1]);
int vartype;
- int idx;
+ int idx = atoi(argv[2]);
if (!vartype_pre) {
DebugPrintf("Invalid variable type '%c'\n", *argv[1]);
@@ -1804,26 +1771,6 @@ bool Console::cmdVMVars(int argc, const char **argv) {
vartype = vartype_pre - varabbrev;
- char *endPtr = 0;
- int idxLen = strlen(argv[2]);
- const char *lastChar = argv[2] + idxLen - (idxLen == 0 ? 0 : 1);
-
- if ((strncmp(argv[2], "0x", 2) == 0) || (*lastChar == 'h')) {
- // hexadecimal number
- idx = strtol(argv[2], &endPtr, 16);
- if ((*endPtr != 0) && (*endPtr != 'h')) {
- DebugPrintf("Invalid hexadecimal index '%s'\n", argv[2]);
- return true;
- }
- } else {
- // decimal number
- idx = strtol(argv[2], &endPtr, 10);
- if (*endPtr != 0) {
- DebugPrintf("Invalid decimal index '%s'\n", argv[2]);
- return true;
- }
- }
-
if (idx < 0) {
DebugPrintf("Invalid: negative index\n");
return true;
@@ -2262,8 +2209,8 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
return true;
}
- const Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
- int selectorId = _engine->getKernel()->findSelector(argv[2]);
+ Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
+ int selector_id = _engine->getKernel()->findSelector(argv[2]);
reg_t addr;
if (!obj) {
@@ -2271,12 +2218,12 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
return true;
}
- if (selectorId < 0) {
+ if (selector_id < 0) {
DebugPrintf("Not a valid selector name.");
return true;
}
- if (lookupSelector(_engine->_gamestate->_segMan, objAddr, selectorId, NULL, &addr) != kSelectorMethod) {
+ if (lookup_selector(_engine->_gamestate->_segMan, objAddr, selector_id, NULL, &addr) != kSelectorMethod) {
DebugPrintf("Not a method.");
return true;
}
@@ -2356,20 +2303,20 @@ bool Console::cmdSend(int argc, const char **argv) {
}
const char *selector_name = argv[2];
- int selectorId = _engine->getKernel()->findSelector(selector_name);
+ int selector_id = _engine->getKernel()->findSelector(selector_name);
- if (selectorId < 0) {
+ if (selector_id < 0) {
DebugPrintf("Unknown selector: \"%s\"\n", selector_name);
return true;
}
- const Object *o = _engine->_gamestate->_segMan->getObject(object);
+ Object *o = _engine->_gamestate->_segMan->getObject(object);
if (o == NULL) {
DebugPrintf("Address \"%04x:%04x\" is not an object\n", PRINT_REG(object));
return true;
}
- SelectorType selector_type = lookupSelector(_engine->_gamestate->_segMan, object, selectorId, 0, 0);
+ SelectorType selector_type = lookup_selector(_engine->_gamestate->_segMan, object, selector_id, 0, 0);
if (selector_type == kSelectorNone) {
DebugPrintf("Object does not support selector: \"%s\"\n", selector_name);
@@ -2382,7 +2329,7 @@ bool Console::cmdSend(int argc, const char **argv) {
// Create the data block for send_selecor() at the top of the stack:
// [selector_number][argument_counter][arguments...]
StackPtr stackframe = _engine->_gamestate->_executionStack.back().sp;
- stackframe[0] = make_reg(0, selectorId);
+ stackframe[0] = make_reg(0, selector_id);
stackframe[1] = make_reg(0, send_argc);
for (int i = 0; i < send_argc; i++) {
if (parse_reg_t(_engine->_gamestate, argv[3+i], &stackframe[2+i], false)) {
@@ -3054,8 +3001,8 @@ int Console::printNode(reg_t addr) {
int Console::printObject(reg_t pos) {
EngineState *s = _engine->_gamestate; // for the several defines in this function
- const Object *obj = s->_segMan->getObject(pos);
- const Object *var_container = obj;
+ Object *obj = s->_segMan->getObject(pos);
+ Object *var_container = obj;
uint i;
if (!obj) {
@@ -3067,7 +3014,7 @@ int Console::printObject(reg_t pos) {
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), s->_segMan->getObjectName(pos),
obj->getVarCount(), obj->getMethodCount());
- if (!obj->isClass())
+ if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS))
var_container = s->_segMan->getObject(obj->getSuperClassSelector());
DebugPrintf(" -- member variables:\n");
for (i = 0; (uint)i < obj->getVarCount(); i++) {
@@ -3084,7 +3031,7 @@ int Console::printObject(reg_t pos) {
if (!val.segment)
DebugPrintf(" (%d)", val.offset);
- const Object *ref = s->_segMan->getObject(val);
+ Object *ref = s->_segMan->getObject(val);
if (ref)
DebugPrintf(" (%s)", s->_segMan->getObjectName(val));
@@ -3096,7 +3043,7 @@ int Console::printObject(reg_t pos) {
DebugPrintf(" [%03x] %s = %04x:%04x\n", obj->getFuncSelector(i), selector_name(s, obj->getFuncSelector(i)), PRINT_REG(fptr));
}
if (s->_segMan->_heap[pos.segment]->getType() == SEG_TYPE_SCRIPT)
- DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.segment)->_nr);
+ DebugPrintf("\nOwner script:\t%d\n", s->_segMan->getScript(pos.segment)->_nr);
return 0;
}
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 2b13e03ef6..c88795ae26 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -73,7 +73,6 @@ private:
bool cmdResourceTypes(int argc, const char **argv);
bool cmdList(int argc, const char **argv);
bool cmdHexgrep(int argc, const char **argv);
- bool cmdVerifyScripts(int argc, const char **argv);
// Game
bool cmdSaveGame(int argc, const char **argv);
bool cmdRestoreGame(int argc, const char **argv);
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index aba2b0b74e..2a83c8e32a 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -120,154 +120,6 @@ static const PlainGameDescriptor SciGameTitles[] = {
{0, 0}
};
-struct OldNewIdTableEntry {
- const char *oldId;
- const char *newId;
- SciVersion version;
-};
-
-static const OldNewIdTableEntry s_oldNewTable[] = {
- { "arthur", "camelot", SCI_VERSION_NONE },
- { "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
- { "brain", "castlebrain", SCI_VERSION_1_LATE },
- { "demo", "christmas1988", SCI_VERSION_NONE },
- { "card", "christmas1990", SCI_VERSION_1_EARLY, },
- { "card", "christmas1992", SCI_VERSION_1_1 },
- { "RH Budget", "cnick-longbow", SCI_VERSION_NONE },
- // iceman is the same
- { "icedemo", "iceman", SCI_VERSION_NONE },
- // longbow is the same
- { "eco", "ecoquest", SCI_VERSION_NONE },
- { "eco2", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 demo
- { "rain", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 full
- { "tales", "fairytales", SCI_VERSION_NONE },
- { "fp", "freddypharkas", SCI_VERSION_NONE },
- { "emc", "funseeker", SCI_VERSION_NONE },
- { "gk", "gk1", SCI_VERSION_NONE },
- // gk2 is the same
- { "hoyledemo", "hoyle1", SCI_VERSION_NONE },
- { "cardgames", "hoyle1", SCI_VERSION_NONE },
- { "solitare", "hoyle2", SCI_VERSION_NONE },
- // hoyle3 is the same
- // hoyle4 is the same
- { "brain", "islandbrain", SCI_VERSION_1_1 },
- { "demo000", "kq1sci", SCI_VERSION_NONE },
- { "kq1", "kq1sci", SCI_VERSION_NONE },
- { "kq4", "kq4sci", SCI_VERSION_NONE },
- // kq5 is the same
- // kq6 is the same
- // kq7 is the same
- { "mm1", "laurabow", SCI_VERSION_NONE },
- { "cb1", "laurabow", SCI_VERSION_NONE },
- { "lb2", "laurabow2", SCI_VERSION_NONE },
- { "rh", "longbow", SCI_VERSION_NONE },
- { "ll1", "lsl1sci", SCI_VERSION_NONE },
- { "lsl1", "lsl1sci", SCI_VERSION_NONE },
- // lsl2 is the same
- { "lsl3", "lsl3", SCI_VERSION_NONE },
- { "ll5", "lsl5", SCI_VERSION_NONE },
- // lsl5 is the same
- // lsl6 is the same
- { "mg", "mothergoose", SCI_VERSION_NONE },
- { "twisty", "pepper", SCI_VERSION_NONE },
- { "scary", "phantasmagoria", SCI_VERSION_NONE },
- // TODO: distinguish the full version of Phantasmagoria from the demo
- { "pq1", "pq1sci", SCI_VERSION_NONE },
- { "pq", "pq2", SCI_VERSION_NONE },
- // pq3 is the same
- // pq4 is the same
- { "hq", "qfg1", SCI_VERSION_NONE }, // QFG1 SCI0/EGA
- { "glory", "qfg1", SCI_VERSION_0_LATE }, // QFG1 SCI0/EGA
- { "trial", "qfg2", SCI_VERSION_NONE },
- { "hq2demo", "qfg2", SCI_VERSION_NONE },
- // rama is the same
- // TODO: distinguish the full version of rama from the demo
- { "thegame", "slater", SCI_VERSION_NONE },
- { "sq1demo", "sq1sci", SCI_VERSION_NONE },
- { "sq1", "sq1sci", SCI_VERSION_NONE },
- // sq3 is the same
- // sq4 is the same
- // sq5 is the same
- // sq6 is the same
- // TODO: distinguish the full version of SQ6 from the demo
- // torin is the same
-
-
- // TODO: SCI3 IDs
-
- { "", "", SCI_VERSION_NONE }
-};
-
-Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, ResourceManager *resMan) {
- // Convert the id to lower case, so that we match all upper/lower case variants.
- sierraId.toLowercase();
-
- // If the game has less than the expected scripts, it's a demo
- uint32 demoThreshold = 100;
- // ...but there are some exceptions
- if (sierraId == "brain" || sierraId == "lsl1" ||
- sierraId == "mg" || sierraId == "pq" ||
- sierraId == "jones" ||
- sierraId == "cardgames" || sierraId == "solitare" ||
- sierraId == "hoyle3" || sierraId == "hoyle4")
- demoThreshold = 40;
- if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
- demoThreshold = 150;
-
- Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
- if (resources->size() < demoThreshold) {
- *gameFlags |= ADGF_DEMO;
-
- // Crazy Nick's Picks
- if (sierraId == "lsl1" && resources->size() == 34)
- return "cnick-lsl";
- if (sierraId == "sq4" && resources->size() == 34)
- return "cnick-sq";
-
- // TODO: cnick-kq, cnick-laurabow and cnick-longbow (their resources can't be read)
-
- // Handle Astrochicken 1 (SQ3) and 2 (SQ4)
- if (sierraId == "sq3" && resources->size() == 20)
- return "astrochicken";
- if (sierraId == "sq4")
- return "msastrochicken";
- }
-
- if (sierraId == "torin" && resources->size() == 226) // Torin's Passage demo
- *gameFlags |= ADGF_DEMO;
-
- for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) {
- if (sierraId == cur->oldId) {
- // Distinguish same IDs from the SCI version
- if (cur->version != SCI_VERSION_NONE && cur->version != getSciVersion())
- continue;
-
- return cur->newId;
- }
- }
-
- if (sierraId == "glory") {
- // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1),
- // or qfg4 full (SCI2)
- // qfg1 VGA doesn't have view 1
- if (!resMan->testResource(ResourceId(kResourceTypeView, 1)))
- return "qfg1";
-
- // qfg4 full is SCI2
- if (getSciVersion() == SCI_VERSION_2)
- return "qfg4";
-
- // qfg4 demo has less than 50 scripts
- if (resources->size() < 50)
- return "qfg4";
-
- // Otherwise it's qfg3
- return "qfg3";
- }
-
- return sierraId;
-}
-
#include "sci/detection_tables.h"
/**
@@ -353,6 +205,50 @@ Common::Language charToScummVMLanguage(const char c) {
}
}
+#define READ_UINT16(buf) (!resMan->isSci11Mac() ? READ_LE_UINT16(buf) : READ_BE_UINT16(buf))
+
+// Finds the internal ID of the current game from script 0
+Common::String getSierraGameId(ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, 0), false);
+ Script *script000 = new Script();
+ script000->init(0, resMan);
+ script000->mcpyInOut(0, script->data, script->size);
+ uint16 curOffset = (getSciVersion() == SCI_VERSION_0_EARLY) ? 2 : 0;
+ uint16 objLength = 0;
+ int objType = 0;
+ int16 exportsOffset = 0;
+ Common::String sierraId;
+
+ // Now find the export table of the script
+ do {
+ objType = READ_UINT16(script000->_buf + curOffset);
+ if (!objType)
+ break;
+
+ objLength = READ_UINT16(script000->_buf + curOffset + 2);
+ curOffset += 4; // skip header
+
+ if (objType == SCI_OBJ_EXPORTS) {
+ exportsOffset = READ_UINT16(script000->_buf + curOffset + 2);
+ break;
+ }
+ curOffset += objLength - 4;
+ } while (objType != 0 && curOffset < script->size - 2);
+
+ // The game object is the first export. Script 0 is always at segment 1
+ reg_t gameObj = make_reg(1, exportsOffset);
+
+ // TODO: stop using the segment manager and read the object name here
+ SegManager *segMan = new SegManager(resMan);
+ script_instantiate(resMan, segMan, 0);
+ sierraId = segMan->getObjectName(gameObj);
+ delete segMan;
+
+ delete script000;
+
+ return sierraId;
+}
+
const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
bool foundResMap = false;
bool foundRes000 = false;
@@ -464,16 +360,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
s_fallbackDesc.platform = Common::kPlatformAmiga;
// Determine the game id
- Common::String sierraGameId = resMan->findSierraGameId();
-
- // If we don't have a game id, the game is not SCI
- if (sierraGameId.empty()) {
- SearchMan.remove("SCI_detection");
- delete resMan;
- return 0;
- }
-
- Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
+ Common::String gameId = convertSierraGameId(getSierraGameId(resMan).c_str(), &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0; // Make sure string is NULL terminated
s_fallbackDesc.gameid = s_fallbackGameIdBuf;
@@ -548,8 +435,8 @@ bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
bool SciEngine::hasFeature(EngineFeature f) const {
return
//(f == kSupportsRTL) ||
- (f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime);
+ (f == kSupportsLoadingDuringRuntime);
+ //(f == kSupportsSavingDuringRuntime);
}
SaveStateList SciMetaEngine::listSaves(const char *target) const {
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 48f7c2d64f..e51867332a 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -56,7 +56,7 @@ reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc
}
if (methodNum == -1) {
- if (lookupSelector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) {
+ if (lookup_selector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) {
warning("getDetectionAddr: target selector is not a method of object %s", objName.c_str());
return NULL_REG;
}
@@ -87,7 +87,7 @@ bool GameFeatures::autoDetectSoundType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->getBufSize())
+ if (opcode == op_ret || offset >= script->_bufSize)
break;
// The play method of the Sound object pushes the DoSound command
@@ -189,7 +189,7 @@ SciVersion GameFeatures::detectSetCursorType() {
}
// Now we check what the number variable holds in the handCursor object.
- uint16 number = readSelectorValue(_segMan, objAddr, SELECTOR(number));
+ uint16 number = GET_SEL32V(_segMan, objAddr, SELECTOR(number));
// If the number is 0, it uses views and therefore the SCI1.1 kSetCursor semantics,
// otherwise it uses the SCI0 early kSetCursor semantics.
@@ -223,7 +223,7 @@ bool GameFeatures::autoDetectLofsType(int methodNum) {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->getBufSize())
+ if (opcode == op_ret || offset >= script->_bufSize)
break;
if (opcode == op_lofsa || opcode == op_lofss) {
@@ -231,13 +231,13 @@ bool GameFeatures::autoDetectLofsType(int methodNum) {
uint16 lofs = opparams[0];
// Check for going out of bounds when interpreting as abs/rel
- if (lofs >= script->getBufSize())
+ if (lofs >= script->_bufSize)
_lofsType = SCI_VERSION_0_EARLY;
if ((signed)offset + (int16)lofs < 0)
_lofsType = SCI_VERSION_1_MIDDLE;
- if ((signed)offset + (int16)lofs >= (signed)script->getBufSize())
+ if ((signed)offset + (int16)lofs >= (signed)script->_bufSize)
_lofsType = SCI_VERSION_1_MIDDLE;
if (_lofsType != SCI_VERSION_NONE)
@@ -266,7 +266,7 @@ SciVersion GameFeatures::detectLofsType() {
// Find a function of the game object which invokes lofsa/lofss
reg_t gameClass = _segMan->findObjectByName("Game");
- const Object *obj = _segMan->getObject(gameClass);
+ Object *obj = _segMan->getObject(gameClass);
bool found = false;
for (uint m = 0; m < obj->getMethodCount(); m++) {
@@ -309,7 +309,7 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->getBufSize())
+ if (opcode == op_ret || offset >= script->_bufSize)
break;
if (opcode == op_callk) {
@@ -332,47 +332,18 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
SciVersion GameFeatures::detectGfxFunctionsType() {
if (_gfxFunctionsType == SCI_VERSION_NONE) {
- if (getSciVersion() == SCI_VERSION_0_EARLY) {
- // Old SCI0 games always used old graphics functions
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
- } else if (getSciVersion() >= SCI_VERSION_01) {
- // SCI01 and newer games always used new graphics functions
+ // This detection only works (and is only needed) for SCI0 games
+ if (getSciVersion() >= SCI_VERSION_01) {
_gfxFunctionsType = SCI_VERSION_0_LATE;
- } else { // SCI0 late
+ } else if (getSciVersion() > SCI_VERSION_0_EARLY) {
// Check if the game is using an overlay
- bool searchRoomObj = false;
- reg_t rmObjAddr = _segMan->findObjectByName("Rm");
-
- if (_kernel->_selectorCache.overlay != -1) {
- // The game has an overlay selector, check how it calls kDrawPicto determine
- // the graphics functions type used
- if (lookupSelector(_segMan, rmObjAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) {
- if (!autoDetectGfxFunctionsType()) {
- warning("Graphics functions detection failed, taking an educated guess");
-
- // Try detecting the graphics function types from the existence of the motionCue
- // selector (which is a bit of a hack)
- if (_kernel->findSelector("motionCue") != -1)
- _gfxFunctionsType = SCI_VERSION_0_LATE;
- else
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
- }
- } else {
- // The game has an overlay selector, but it's not a method of the Rm object
- // (like in Hoyle 1 and 2), so search for other methods
- searchRoomObj = true;
- }
- } else {
- // The game doesn't have an overlay selector, so search for it manually
- searchRoomObj = true;
- }
+ bool found = false;
- if (searchRoomObj) {
- // If requested, check if any method of the Rm object is calling kDrawPic,
- // as the overlay selector might be missing in demos
- bool found = false;
+ if (_kernel->_selectorCache.overlay == -1) {
+ // No overlay selector found, check if any method of the Rm object
+ // is calling kDrawPic, as the overlay selector might be missing in demos
- const Object *obj = _segMan->getObject(rmObjAddr);
+ Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm"));
for (uint m = 0; m < obj->getMethodCount(); m++) {
found = autoDetectGfxFunctionsType(m);
if (found)
@@ -380,11 +351,30 @@ SciVersion GameFeatures::detectGfxFunctionsType() {
}
if (!found) {
- // No method of the Rm object is calling kDrawPic, thus the game
- // doesn't have overlays and is using older graphics functions
+ // No overlay selector found, therefore the game is definitely
+ // using old graphics functions
_gfxFunctionsType = SCI_VERSION_0_EARLY;
}
+ } else { // _kernel->_selectorCache.overlay != -1
+ // An in-between case: The game does not have a shiftParser
+ // selector, but it does have an overlay selector, so it uses an
+ // overlay. Therefore, check it to see how it calls kDrawPic to
+ // determine the graphics functions type used
+
+ if (!autoDetectGfxFunctionsType()) {
+ warning("Graphics functions detection failed, taking an educated guess");
+
+ // Try detecting the graphics function types from the existence of the motionCue
+ // selector (which is a bit of a hack)
+ if (_kernel->findSelector("motionCue") != -1)
+ _gfxFunctionsType = SCI_VERSION_0_LATE;
+ else
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ }
}
+ } else { // (getSciVersion() == SCI_VERSION_0_EARLY)
+ // Old SCI0 games always used old graphics functions
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
}
debugC(1, kDebugLevelVM, "Detected graphics functions type: %s", getSciVersionDesc(_gfxFunctionsType));
@@ -412,7 +402,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->getBufSize())
+ if (opcode == op_ret || offset >= script->_bufSize)
break;
if (opcode == op_callk) {
@@ -465,7 +455,7 @@ bool GameFeatures::autoDetectMoveCountType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->getBufSize())
+ if (opcode == op_ret || offset >= script->_bufSize)
break;
if (opcode == op_callk) {
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
index bc10099e52..4ac2a22531 100644
--- a/engines/sci/engine/game.cpp
+++ b/engines/sci/engine/game.cpp
@@ -41,6 +41,141 @@
namespace Sci {
+struct OldNewIdTableEntry {
+ const char *oldId;
+ const char *newId;
+ SciVersion version;
+};
+
+static const OldNewIdTableEntry s_oldNewTable[] = {
+ { "arthur", "camelot", SCI_VERSION_NONE },
+ { "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
+ { "brain", "castlebrain", SCI_VERSION_1_LATE },
+ { "demo", "christmas1988", SCI_VERSION_NONE },
+ { "card", "christmas1990", SCI_VERSION_1_EARLY, },
+ { "card", "christmas1992", SCI_VERSION_1_1 },
+ { "RH Budget", "cnick-longbow", SCI_VERSION_NONE },
+ // iceman is the same
+ { "icedemo", "iceman", SCI_VERSION_NONE },
+ // longbow is the same
+ { "eco", "ecoquest", SCI_VERSION_NONE },
+ { "eco2", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 demo
+ { "rain", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 full
+ { "fp", "freddypharkas", SCI_VERSION_NONE },
+ { "emc", "funseeker", SCI_VERSION_NONE },
+ { "gk", "gk1", SCI_VERSION_NONE },
+ { "hoyledemo", "hoyle1", SCI_VERSION_NONE },
+ { "cardgames", "hoyle1", SCI_VERSION_NONE },
+ { "solitare", "hoyle2", SCI_VERSION_NONE },
+ // hoyle3 is the same
+ // hoyle4 is the same
+ { "brain", "islandbrain", SCI_VERSION_1_1 },
+ { "demo000", "kq1sci", SCI_VERSION_NONE },
+ { "kq1", "kq1sci", SCI_VERSION_NONE },
+ { "kq4", "kq4sci", SCI_VERSION_NONE },
+ { "mm1", "laurabow", SCI_VERSION_NONE },
+ { "cb1", "laurabow", SCI_VERSION_NONE },
+ { "lb2", "laurabow2", SCI_VERSION_NONE },
+ { "rh", "longbow", SCI_VERSION_NONE },
+ { "ll1", "lsl1sci", SCI_VERSION_NONE },
+ { "lsl1", "lsl1sci", SCI_VERSION_NONE },
+ // lsl2 is the same
+ { "lsl3", "lsl3", SCI_VERSION_NONE },
+ { "ll5", "lsl5", SCI_VERSION_NONE },
+ // lsl5 is the same
+ // lsl6 is the same
+ { "mg", "mothergoose", SCI_VERSION_NONE },
+ { "twisty", "pepper", SCI_VERSION_NONE },
+ { "pq1", "pq1sci", SCI_VERSION_NONE },
+ { "pq", "pq2", SCI_VERSION_NONE },
+ // pq3 is the same
+ // pq4 is the same
+ { "tales", "fairytales", SCI_VERSION_NONE },
+ { "hq", "qfg1", SCI_VERSION_NONE }, // QFG1 SCI0/EGA
+ { "glory", "qfg1", SCI_VERSION_0_LATE }, // QFG1 SCI0/EGA
+ { "trial", "qfg2", SCI_VERSION_NONE },
+ { "hq2demo", "qfg2", SCI_VERSION_NONE },
+ { "thegame", "slater", SCI_VERSION_NONE },
+ { "sq1demo", "sq1sci", SCI_VERSION_NONE },
+ { "sq1", "sq1sci", SCI_VERSION_NONE },
+ // sq3 is the same
+ // sq4 is the same
+ // sq5 is the same
+ // torin is the same
+
+ // TODO: SCI2.1, SCI3 IDs
+
+ { "", "", SCI_VERSION_NONE }
+};
+
+Common::String convertSierraGameId(const char *gameId, uint32 *gameFlags, ResourceManager *resMan) {
+ // Convert the id to lower case, so that we match all upper/lower case variants.
+ Common::String sierraId = gameId;
+ sierraId.toLowercase();
+
+ // If the game has less than the expected scripts, it's a demo
+ uint32 demoThreshold = 100;
+ // ...but there are some exceptions
+ if (sierraId == "brain" || sierraId == "lsl1" ||
+ sierraId == "mg" || sierraId == "pq" ||
+ sierraId == "jones" ||
+ sierraId == "cardgames" || sierraId == "solitare" ||
+ sierraId == "hoyle3" || sierraId == "hoyle4")
+ demoThreshold = 40;
+ if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
+ demoThreshold = 150;
+
+ Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
+ if (resources->size() < demoThreshold) {
+ *gameFlags |= ADGF_DEMO;
+
+ // Crazy Nick's Picks
+ if (sierraId == "lsl1" && resources->size() == 34)
+ return "cnick-lsl";
+ if (sierraId == "sq4" && resources->size() == 34)
+ return "cnick-sq";
+
+ // TODO: cnick-kq, cnick-laurabow and cnick-longbow (their resources can't be read)
+
+ // Handle Astrochicken 1 (SQ3) and 2 (SQ4)
+ if (sierraId == "sq3" && resources->size() == 20)
+ return "astrochicken";
+ if (sierraId == "sq4")
+ return "msastrochicken";
+ }
+
+ for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) {
+ if (sierraId == cur->oldId) {
+ // Distinguish same IDs from the SCI version
+ if (cur->version != SCI_VERSION_NONE && cur->version != getSciVersion())
+ continue;
+
+ return cur->newId;
+ }
+ }
+
+ if (sierraId == "glory") {
+ // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1),
+ // or qfg4 full (SCI2)
+ // qfg1 VGA doesn't have view 1
+ if (!resMan->testResource(ResourceId(kResourceTypeView, 1)))
+ return "qfg1";
+
+ // qfg4 full is SCI2
+ if (getSciVersion() == SCI_VERSION_2)
+ return "qfg4";
+
+ // qfg4 demo has less than 50 scripts
+ if (resources->size() < 50)
+ return "qfg4";
+
+ // Otherwise it's qfg3
+ return "qfg3";
+ }
+
+ return sierraId;
+}
+
#ifdef USE_OLD_MUSIC_FUNCTIONS
int game_init_sound(EngineState *s, int sound_flags, SciVersion soundVersion) {
if (getSciVersion() > SCI_VERSION_0_LATE)
@@ -67,7 +202,13 @@ int script_init_engine(EngineState *s) {
s->script_000 = s->_segMan->getScript(script_000_segment);
- s->_segMan->initSysStrings();
+ s->sys_strings = s->_segMan->allocateSysStrings(&s->sys_strings_segment);
+
+ // Allocate static buffer for savegame and CWD directories
+ SystemString *str = &s->sys_strings->_strings[SYS_STRING_SAVEDIR];
+ str->_name = "savedir";
+ str->_maxSize = MAX_SAVE_DIR_SIZE;
+ str->_value = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
s->r_acc = s->r_prev = NULL_REG;
s->restAdjust = 0;
@@ -99,26 +240,35 @@ int game_init(EngineState *s) {
return 1;
}
- // Reset parser
- Vocabulary *voc = g_sci->getVocabulary();
- if (voc) {
- voc->parserIsValid = false; // Invalidate parser
- voc->parser_event = NULL_REG; // Invalidate parser event
- voc->parser_base = make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE);
+ if (s->_voc) {
+ s->_voc->parserIsValid = false; // Invalidate parser
+ s->_voc->parser_event = NULL_REG; // Invalidate parser event
+ s->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
}
// Initialize menu TODO: Actually this should be another init()
if (g_sci->_gfxMenu)
g_sci->_gfxMenu->reset();
- s->restoring = false;
+ s->successor = NULL; // No successor
+
+ SystemString *str = &s->sys_strings->_strings[SYS_STRING_PARSER_BASE];
+ str->_name = "parser-base";
+ str->_maxSize = MAX_PARSER_BASE;
+ str->_value = (char *)calloc(MAX_PARSER_BASE, sizeof(char));
s->game_start_time = g_system->getMillis();
s->last_wait_time = s->game_start_time;
srand(g_system->getMillis()); // Initialize random number generator
- s->_gameObj = g_sci->getResMan()->findGameObject();
+// script_dissect(0, s->_selectorNames);
+ // The first entry in the export table of script 0 points to the game object
+ s->_gameObj = s->_segMan->lookupScriptExport(0, 0);
+ uint32 gameFlags = 0; // unused
+ s->_gameId = convertSierraGameId(s->_segMan->getObjectName(s->_gameObj), &gameFlags, g_sci->getResMan());
+
+ debug(2, " \"%s\" at %04x:%04x", s->_gameId.c_str(), PRINT_REG(s->_gameObj));
#ifdef USE_OLD_MUSIC_FUNCTIONS
if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND)
@@ -134,8 +284,9 @@ int game_init(EngineState *s) {
}
int game_exit(EngineState *s) {
- if (!s->restoring) {
- s->_executionStack.clear();
+ s->_executionStack.clear();
+
+ if (!s->successor) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
s->_sound.sfx_exit();
// Reinit because some other code depends on having a valid state
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 0b7198d1bc..49266f3a18 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -332,12 +332,11 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("DoSync", kDoSync, ".*"),
DEFUN("MemorySegment", kMemorySegment, "iri*"),
DEFUN("Intersections", kIntersections, "iiiiriiiri"),
- DEFUN("MergePoly", kMergePoly, "rli"),
DEFUN("ResCheck", kResCheck, "iii*"),
DEFUN("SetQuitStr", kSetQuitStr, "r"),
DEFUN("ShowMovie", kShowMovie, ".*"),
DEFUN("SetVideoMode", kSetVideoMode, "i"),
- DEFUN("Platform", kPlatform, ".*"),
+ DEFUN("Platform", kPlatform, "i.*"),
DEFUN("TextColors", kTextColors, ".*"),
DEFUN("TextFonts", kTextFonts, ".*"),
DEFUN("Portrait", kPortrait, ".*"),
@@ -383,6 +382,7 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("ShiftScreen", kShiftScreen, ".*"),
DEFUN("ListOps", kListOps, ".*"),
DEFUN("ATan", kATan, ".*"),
+ DEFUN("MergePoly", kMergePoly, ".*"),
DEFUN("Record", kRecord, ".*"),
DEFUN("PlayBack", kPlayBack, ".*"),
DEFUN("DbugStr", kDbugStr, ".*"),
@@ -628,7 +628,7 @@ int Kernel::findRegType(reg_t reg) {
switch (mobj->getType()) {
case SEG_TYPE_SCRIPT:
- if (reg.offset <= (*(Script *)mobj).getBufSize() &&
+ if (reg.offset <= (*(Script *)mobj)._bufSize &&
reg.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET &&
RAW_IS_OBJECT((*(Script *)mobj)._buf + reg.offset)) {
return ((Script *)mobj)->getObject(reg.offset) ? KSIG_OBJECT : KSIG_REF;
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 8f8f34f74e..7717743e19 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -414,7 +414,6 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv);
reg_t kDoSync(EngineState *s, int argc, reg_t *argv);
reg_t kMemorySegment(EngineState *s, int argc, reg_t *argv);
reg_t kIntersections(EngineState *s, int argc, reg_t *argv);
-reg_t kMergePoly(EngineState *s, int argc, reg_t *argv);
reg_t kResCheck(EngineState *s, int argc, reg_t *argv);
reg_t kSetQuitStr(EngineState *s, int argc, reg_t *argv);
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp
index b132543206..465e0e92df 100644
--- a/engines/sci/engine/kernel32.cpp
+++ b/engines/sci/engine/kernel32.cpp
@@ -501,7 +501,7 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) {
if (!s->_segMan->isHeapObject(argv[1]))
return argv[1];
- return readSelector(s->_segMan, argv[1], SELECTOR(data));
+ return GET_SEL32(s->_segMan, argv[1], SELECTOR(data));
default:
error("Unknown kArray subop %d", argv[0].toUint16());
}
@@ -575,16 +575,16 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
uint32 count = argv[5].toSint16() == -1 ? string2.size() - index2 + 1 : argv[5].toUint16();
// We have a special case here for argv[1] being a system string
- if (argv[1].segment == s->_segMan->getSysStringsSegment()) {
+ if (argv[1].segment == s->sys_strings_segment) {
// Resize if necessary
- const uint16 sysStringId = argv[1].toUint16();
- if ((uint32)s->_segMan->sysStrings->_strings[sysStringId]._maxSize < index1 + count) {
- free(s->_segMan->sysStrings->_strings[sysStringId]._value);
- s->_segMan->sysStrings->_strings[sysStringId]._maxSize = index1 + count;
- s->_segMan->sysStrings->_strings[sysStringId]._value = (char *)calloc(index1 + count, sizeof(char));
+ if ((uint32)s->sys_strings->_strings[argv[1].toUint16()]._maxSize < index1 + count) {
+ delete[] s->sys_strings->_strings[argv[1].toUint16()]._value;
+ s->sys_strings->_strings[argv[1].toUint16()]._maxSize = index1 + count;
+ s->sys_strings->_strings[argv[1].toUint16()]._value = new char[index1 + count];
+ memset(s->sys_strings->_strings[argv[1].toUint16()]._value, 0, index1 + count);
}
- strncpy(s->_segMan->sysStrings->_strings[sysStringId]._value + index1, string2.c_str() + index2, count);
+ strncpy(s->sys_strings->_strings[argv[1].toUint16()]._value + index1, string2.c_str() + index2, count);
} else {
SciString *string1 = s->_segMan->lookupString(argv[1]);
@@ -624,7 +624,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
if (!s->_segMan->isHeapObject(argv[1]))
return argv[1];
- return readSelector(s->_segMan, argv[1], SELECTOR(data));
+ return GET_SEL32(s->_segMan, argv[1], SELECTOR(data));
case 10: // Stringlen
return make_reg(0, s->_segMan->strlen(argv[1]));
case 11: { // Printf
@@ -689,12 +689,12 @@ reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
/*
reg_t viewObj = argv[0];
- uint16 viewId = readSelectorValue(s->_segMan, viewObj, SELECTOR(view));
- int16 loopNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(loop));
- int16 celNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(cel));
+ uint16 viewId = GET_SEL32V(s->_segMan, viewObj, SELECTOR(view));
+ int16 loopNo = GET_SEL32V(s->_segMan, viewObj, SELECTOR(loop));
+ int16 celNo = GET_SEL32V(s->_segMan, viewObj, SELECTOR(cel));
//int16 leftPos = 0;
//int16 topPos = 0;
- int16 priority = readSelectorValue(s->_segMan, viewObj, SELECTOR(priority));
+ int16 priority = GET_SEL32V(s->_segMan, viewObj, SELECTOR(priority));
//int16 control = 0;
*/
@@ -761,10 +761,10 @@ reg_t kOnMe(EngineState *s, int argc, reg_t *argv) {
Common::Rect nsRect;
// Get the bounding rectangle of the object
- nsRect.left = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsLeft));
- nsRect.top = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsTop));
- nsRect.right = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsRight));
- nsRect.bottom = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsBottom));
+ nsRect.left = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsLeft));
+ nsRect.top = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsTop));
+ nsRect.right = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsRight));
+ nsRect.bottom = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsBottom));
//warning("kOnMe: (%d, %d) on object %04x:%04x, parameter %d", argv[0].toUint16(), argv[1].toUint16(), PRINT_REG(argv[2]), argv[3].toUint16());
@@ -779,7 +779,7 @@ reg_t kInPolygon(EngineState *s, int argc, reg_t *argv) {
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
// TODO: argument 0 is usually 0, and arguments 1 and 2 are usually 1
reg_t object = argv[3];
- Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text)));
+ Common::String text = s->_segMan->getString(GET_SEL32(s->_segMan, object, SELECTOR(text)));
debug("kCreateTextBitmap: %s", text.c_str());
return NULL_REG;
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index 3e096074e6..156035b30d 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -49,18 +49,16 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
Common::Point mousePos;
- // Limit the mouse cursor position, if necessary
- g_sci->_gfxCursor->refreshPosition();
mousePos = g_sci->_gfxCursor->getPosition();
// If there's a simkey pending, and the game wants a keyboard event, use the
// simkey instead of a normal event
if (g_debug_simulated_key && (mask & SCI_EVENT_KEYBOARD)) {
- writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
- writeSelectorValue(segMan, obj, SELECTOR(message), g_debug_simulated_key);
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
- writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
- writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
+ PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
+ PUT_SEL32V(segMan, obj, SELECTOR(message), g_debug_simulated_key);
+ PUT_SEL32V(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
+ PUT_SEL32V(segMan, obj, SELECTOR(x), mousePos.x);
+ PUT_SEL32V(segMan, obj, SELECTOR(y), mousePos.y);
g_debug_simulated_key = 0;
return make_reg(0, 1);
}
@@ -69,11 +67,11 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
oldy = mousePos.y;
curEvent = s->_event->get(mask);
- if (g_sci->getVocabulary())
- g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event
+ if (s->_voc)
+ s->_voc->parser_event = NULL_REG; // Invalidate parser event
- writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
- writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
+ PUT_SEL32V(segMan, obj, SELECTOR(x), mousePos.x);
+ PUT_SEL32V(segMan, obj, SELECTOR(y), mousePos.y);
//s->_gui->moveCursor(s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y);
@@ -83,12 +81,12 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
break;
case SCI_EVENT_KEYBOARD:
- writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
+ PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
s->r_acc = make_reg(0, 1);
- writeSelectorValue(segMan, obj, SELECTOR(message), curEvent.character);
+ PUT_SEL32V(segMan, obj, SELECTOR(message), curEvent.character);
// We only care about the translated character
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ PUT_SEL32V(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
break;
case SCI_EVENT_MOUSE_RELEASE:
@@ -113,9 +111,9 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
break;
}
- writeSelectorValue(segMan, obj, SELECTOR(type), curEvent.type);
- writeSelectorValue(segMan, obj, SELECTOR(message), 0);
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
+ PUT_SEL32V(segMan, obj, SELECTOR(type), curEvent.type);
+ PUT_SEL32V(segMan, obj, SELECTOR(message), 0);
+ PUT_SEL32V(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
s->r_acc = make_reg(0, 1);
}
break;
@@ -167,9 +165,9 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
SegManager *segMan = s->_segMan;
- if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
+ if (GET_SEL32V(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
int mover = -1;
- switch (readSelectorValue(segMan, obj, SELECTOR(message))) {
+ switch (GET_SEL32V(segMan, obj, SELECTOR(message))) {
case SCI_KEY_HOME:
mover = 8;
break;
@@ -203,8 +201,8 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
}
if (mover >= 0) {
- writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_JOYSTICK);
- writeSelectorValue(segMan, obj, SELECTOR(message), mover);
+ PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_JOYSTICK);
+ PUT_SEL32V(segMan, obj, SELECTOR(message), mover);
return make_reg(0, 1);
} else
return NULL_REG;
@@ -219,13 +217,13 @@ reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
if (obj.segment) {
- int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
- int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
+ int16 x = GET_SEL32V(segMan, obj, SELECTOR(x));
+ int16 y = GET_SEL32V(segMan, obj, SELECTOR(y));
g_sci->_gfxCoordAdjuster->kernelGlobalToLocal(x, y, planeObject);
- writeSelectorValue(segMan, obj, SELECTOR(x), x);
- writeSelectorValue(segMan, obj, SELECTOR(y), y);
+ PUT_SEL32V(segMan, obj, SELECTOR(x), x);
+ PUT_SEL32V(segMan, obj, SELECTOR(y), y);
}
return s->r_acc;
@@ -238,13 +236,13 @@ reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
if (obj.segment) {
- int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
- int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
+ int16 x = GET_SEL32V(segMan, obj, SELECTOR(x));
+ int16 y = GET_SEL32V(segMan, obj, SELECTOR(y));
g_sci->_gfxCoordAdjuster->kernelLocalToGlobal(x, y, planeObject);
- writeSelectorValue(segMan, obj, SELECTOR(x), x);
- writeSelectorValue(segMan, obj, SELECTOR(y), y);
+ PUT_SEL32V(segMan, obj, SELECTOR(x), x);
+ PUT_SEL32V(segMan, obj, SELECTOR(y), y);
}
return s->r_acc;
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index c48fb4035f..e6b9a5388c 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -44,8 +44,6 @@ struct SavegameDesc {
int id;
int date;
int time;
- int version;
- char name[SCI_MAX_SAVENAME_LENGTH];
};
/*
@@ -247,10 +245,13 @@ static void fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) {
debugC(2, kDebugLevelFile, "FGets'ed \"%s\"", dest);
}
-static bool _savegame_index_struct_compare(const SavegameDesc &l, const SavegameDesc &r) {
- if (l.date != r.date)
- return (l.date > r.date);
- return (l.time > r.time);
+static int _savegame_index_struct_compare(const void *a, const void *b) {
+ const SavegameDesc *A = (const SavegameDesc *)a;
+ const SavegameDesc *B = (const SavegameDesc *)b;
+
+ if (B->date != A->date)
+ return B->date - A->date;
+ return B->time - A->time;
}
void listSavegames(Common::Array<SavegameDesc> &saves) {
@@ -264,7 +265,7 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
Common::SeekableReadStream *in;
if ((in = saveFileMan->openForLoading(filename))) {
SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta) || meta.savegame_name.empty()) {
+ if (!get_savegame_metadata(in, &meta)) {
// invalid
delete in;
continue;
@@ -277,13 +278,6 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
// We need to fix date in here, because we save DDMMYYYY instead of YYYYMMDD, so sorting wouldnt work
desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24);
desc.time = meta.savegame_time;
- desc.version = meta.savegame_version;
-
- if (meta.savegame_name.lastChar() == '\n')
- meta.savegame_name.deleteLastChar();
-
- Common::strlcpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH);
-
debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);
saves.push_back(desc);
@@ -291,18 +285,35 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
}
// Sort the list by creation date of the saves
- Common::sort(saves.begin(), saves.end(), _savegame_index_struct_compare);
+ qsort(saves.begin(), saves.size(), sizeof(SavegameDesc), _savegame_index_struct_compare);
}
bool Console::cmdListSaves(int argc, const char **argv) {
Common::Array<SavegameDesc> saves;
listSavegames(saves);
+ Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+
for (uint i = 0; i < saves.size(); i++) {
Common::String filename = g_sci->getSavegameName(saves[i].id);
- DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name);
- }
+ Common::SeekableReadStream *in;
+ if ((in = saveFileMan->openForLoading(filename))) {
+ SavegameMetadata meta;
+ if (!get_savegame_metadata(in, &meta)) {
+ // invalid
+ delete in;
+ continue;
+ }
+
+ if (!meta.savegame_name.empty()) {
+ if (meta.savegame_name.lastChar() == '\n')
+ meta.savegame_name.deleteLastChar();
+ DebugPrintf("%s: '%s'\n", filename.c_str(), meta.savegame_name.c_str());
+ }
+ delete in;
+ }
+ }
return true;
}
@@ -417,7 +428,7 @@ reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) {
warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0]));
#endif
- return make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_SAVEDIR);
+ return make_reg(s->sys_strings_segment, SYS_STRING_SAVEDIR);
}
reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
@@ -438,30 +449,44 @@ reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
Common::String game_id = s->_segMan->getString(argv[0]);
- uint16 savedir_nr = argv[1].toUint16();
+ int savedir_nr = argv[1].toUint16();
debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), savedir_nr);
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- // Check for savegame slot being out of range
- if (savedir_nr >= saves.size())
- return NULL_REG;
+ savedir_nr = saves[savedir_nr].id;
- // Check for compatible savegame version
- int ver = saves[savedir_nr].version;
- if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION)
+ if (savedir_nr > MAX_SAVEGAME_NR - 1) {
return NULL_REG;
+ }
- // Otherwise we assume the savegame is OK
- return make_reg(0, 1);
+ Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+ Common::String filename = g_sci->getSavegameName(savedir_nr);
+ Common::SeekableReadStream *in;
+ if ((in = saveFileMan->openForLoading(filename))) {
+ // found a savegame file
+
+ SavegameMetadata meta;
+ if (!get_savegame_metadata(in, &meta)) {
+ // invalid
+ s->r_acc = make_reg(0, 0);
+ } else {
+ s->r_acc = make_reg(0, 1);
+ }
+ delete in;
+ } else {
+ s->r_acc = make_reg(0, 1);
+ }
+
+ return s->r_acc;
}
reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
Common::String game_id = s->_segMan->getString(argv[0]);
reg_t nametarget = argv[1];
- reg_t *slot = s->_segMan->derefRegPtr(argv[2], 0);
+ reg_t *nameoffsets = s->_segMan->derefRegPtr(argv[2], 0);
debug(3, "kGetSaveFiles(%s)", game_id.c_str());
@@ -469,17 +494,42 @@ reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
listSavegames(saves);
s->r_acc = NULL_REG;
+ Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+
+ for (uint i = 0; i < saves.size(); i++) {
+ Common::String filename = g_sci->getSavegameName(saves[i].id);
+ Common::SeekableReadStream *in;
+ if ((in = saveFileMan->openForLoading(filename))) {
+ // found a savegame file
+
+ SavegameMetadata meta;
+ if (!get_savegame_metadata(in, &meta)) {
+ // invalid
+ delete in;
+ continue;
+ }
+
+ if (!meta.savegame_name.empty()) {
+ if (meta.savegame_name.lastChar() == '\n')
+ meta.savegame_name.deleteLastChar();
- for (uint i = 0; i < MIN<uint>(saves.size(), MAX_SAVEGAME_NR); i++) {
- *slot++ = s->r_acc; // Store savegame ID
- ++s->r_acc.offset; // Increase number of files found
+ *nameoffsets = s->r_acc; // Store savegame ID
+ ++s->r_acc.offset; // Increase number of files found
- s->_segMan->strcpy(nametarget, saves[i].name);
+ nameoffsets++; // Make sure the next ID string address is written to the next pointer
+ Common::String name = meta.savegame_name;
+ if (name.size() > SCI_MAX_SAVENAME_LENGTH-1)
+ name = Common::String(meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH-1);
+ s->_segMan->strcpy(nametarget, name.c_str());
- // Increase name offset pointer accordingly
- nametarget.offset += SCI_MAX_SAVENAME_LENGTH;
+ // Increase name offset pointer accordingly
+ nametarget.offset += SCI_MAX_SAVENAME_LENGTH;
+ }
+ delete in;
+ }
}
+ //free(gfname);
s->_segMan->strcpy(nametarget, ""); // Terminate list
return s->r_acc;
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 17d2cd630e..d587790b6c 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -23,10 +23,8 @@
*
*/
-#include "engines/util.h"
#include "graphics/cursorman.h"
#include "graphics/video/avi_decoder.h"
-#include "graphics/video/qt_decoder.h"
#include "graphics/surface.h"
#include "sci/sci.h"
@@ -53,8 +51,8 @@
namespace Sci {
void _k_dirloop(reg_t object, uint16 angle, EngineState *s, int argc, reg_t *argv) {
- GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
- uint16 signal = readSelectorValue(s->_segMan, object, SELECTOR(signal));
+ GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
+ uint16 signal = GET_SEL32V(s->_segMan, object, SELECTOR(signal));
int16 loopNo;
int16 maxLoops;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
@@ -93,7 +91,7 @@ void _k_dirloop(reg_t object, uint16 angle, EngineState *s, int argc, reg_t *arg
if ((loopNo > 1) && (maxLoops < 4))
return;
- writeSelectorValue(s->_segMan, object, SELECTOR(loop), loopNo);
+ PUT_SEL32V(s->_segMan, object, SELECTOR(loop), loopNo);
}
static reg_t kSetCursorSci0(EngineState *s, int argc, reg_t *argv) {
@@ -439,7 +437,7 @@ reg_t kCelWide(EngineState *s, int argc, reg_t *argv) {
reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
reg_t object = argv[0];
- GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
+ GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
int16 loopCount;
loopCount = g_sci->_gfxCache->kernelViewGetLoopCount(viewId);
@@ -451,8 +449,8 @@ reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
reg_t kNumCels(EngineState *s, int argc, reg_t *argv) {
reg_t object = argv[0];
- GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
- int16 loopNo = readSelectorValue(s->_segMan, object, SELECTOR(loop));
+ GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
+ int16 loopNo = GET_SEL32V(s->_segMan, object, SELECTOR(loop));
int16 celCount;
celCount = g_sci->_gfxCache->kernelViewGetCelCount(viewId, loopNo);
@@ -527,9 +525,9 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) {
// WORKAROUND for a problem in LSL1VGA. This allows the casino door to be opened,
// till the actual problem is found
- if (!strcmp(g_sci->getGameID(), "lsl1sci") && s->currentRoomNumber() == 300) {
- int top = readSelectorValue(s->_segMan, object, SELECTOR(brTop));
- writeSelectorValue(s->_segMan, object, SELECTOR(brTop), top + 2);
+ if (s->_gameId == "lsl1sci" && s->currentRoomNumber() == 300) {
+ int top = GET_SEL32V(s->_segMan, object, SELECTOR(brTop));
+ PUT_SEL32V(s->_segMan, object, SELECTOR(brTop), top + 2);
}
return s->r_acc;
@@ -743,12 +741,12 @@ Common::Rect kControlCreateRect(int16 x, int16 y, int16 x1, int16 y1) {
}
void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
- int16 type = readSelectorValue(s->_segMan, controlObject, SELECTOR(type));
- int16 style = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
- int16 x = readSelectorValue(s->_segMan, controlObject, SELECTOR(nsLeft));
- int16 y = readSelectorValue(s->_segMan, controlObject, SELECTOR(nsTop));
- GuiResourceId fontId = readSelectorValue(s->_segMan, controlObject, SELECTOR(font));
- reg_t textReference = readSelector(s->_segMan, controlObject, SELECTOR(text));
+ int16 type = GET_SEL32V(s->_segMan, controlObject, SELECTOR(type));
+ int16 style = GET_SEL32V(s->_segMan, controlObject, SELECTOR(state));
+ int16 x = GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsLeft));
+ int16 y = GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsTop));
+ GuiResourceId fontId = GET_SEL32V(s->_segMan, controlObject, SELECTOR(font));
+ reg_t textReference = GET_SEL32(s->_segMan, controlObject, SELECTOR(text));
Common::String text;
Common::Rect rect;
TextAlignment alignment;
@@ -764,8 +762,8 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
bool isAlias = false;
rect = kControlCreateRect(x, y,
- readSelectorValue(s->_segMan, controlObject, SELECTOR(nsRight)),
- readSelectorValue(s->_segMan, controlObject, SELECTOR(nsBottom)));
+ GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsRight)),
+ GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsBottom)));
if (!textReference.isNull())
text = s->_segMan->getString(textReference);
@@ -777,32 +775,32 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
return;
case SCI_CONTROLS_TYPE_TEXT:
- alignment = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
+ alignment = GET_SEL32V(s->_segMan, controlObject, SELECTOR(mode));
debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x ('%s') to %d,%d, mode=%d", PRINT_REG(controlObject), text.c_str(), x, y, alignment);
g_sci->_gfxControls->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite);
return;
case SCI_CONTROLS_TYPE_TEXTEDIT:
- mode = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
- maxChars = readSelectorValue(s->_segMan, controlObject, SELECTOR(max));
- cursorPos = readSelectorValue(s->_segMan, controlObject, SELECTOR(cursor));
+ mode = GET_SEL32V(s->_segMan, controlObject, SELECTOR(mode));
+ maxChars = GET_SEL32V(s->_segMan, controlObject, SELECTOR(max));
+ cursorPos = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cursor));
debugC(2, kDebugLevelGraphics, "drawing edit control %04x:%04x (text %04x:%04x, '%s') to %d,%d", PRINT_REG(controlObject), PRINT_REG(textReference), text.c_str(), x, y);
g_sci->_gfxControls->kernelDrawTextEdit(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, mode, style, cursorPos, maxChars, hilite);
return;
case SCI_CONTROLS_TYPE_ICON:
- viewId = readSelectorValue(s->_segMan, controlObject, SELECTOR(view));
+ viewId = GET_SEL32V(s->_segMan, controlObject, SELECTOR(view));
{
- int l = readSelectorValue(s->_segMan, controlObject, SELECTOR(loop));
+ int l = GET_SEL32V(s->_segMan, controlObject, SELECTOR(loop));
loopNo = (l & 0x80) ? l - 256 : l;
- int c = readSelectorValue(s->_segMan, controlObject, SELECTOR(cel));
+ int c = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cel));
celNo = (c & 0x80) ? c - 256 : c;
// Game-specific: *ONLY* the jones EGA/VGA sierra interpreter contain code using priority selector
// ALL other games use a hardcoded -1 (madness!)
// We are detecting jones/talkie as "jones" as well, but the sierra interpreter of talkie doesnt have this
// "hack". Hopefully it wont cause regressions (the code causes regressions if used against kq5/floppy)
- if (!strcmp(g_sci->getGameID(), "jones"))
- priority = readSelectorValue(s->_segMan, controlObject, SELECTOR(priority));
+ if (s->_gameId == "jones")
+ priority = GET_SEL32V(s->_segMan, controlObject, SELECTOR(priority));
else
priority = -1;
}
@@ -815,17 +813,17 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
if (type == SCI_CONTROLS_TYPE_LIST_ALIAS)
isAlias = true;
- maxChars = readSelectorValue(s->_segMan, controlObject, SELECTOR(x)); // max chars per entry
- cursorOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(cursor));
+ maxChars = GET_SEL32V(s->_segMan, controlObject, SELECTOR(x)); // max chars per entry
+ cursorOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cursor));
if (g_sci->getKernel()->_selectorCache.topString != -1) {
// Games from early SCI1 onwards use topString
- upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(topString));
+ upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(topString));
} else {
// Earlier games use lsTop or brTop
- if (lookupSelector(s->_segMan, controlObject, g_sci->getKernel()->_selectorCache.brTop, NULL, NULL) == kSelectorVariable)
- upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(brTop));
+ if (lookup_selector(s->_segMan, controlObject, g_sci->getKernel()->_selectorCache.brTop, NULL, NULL) == kSelectorVariable)
+ upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(brTop));
else
- upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(lsTop));
+ upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(lsTop));
}
// Count string entries in NULL terminated string list
@@ -876,8 +874,8 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
// Disable the "Change Directory" button, as we don't allow the game engine to
// change the directory where saved games are placed
if (objName == "changeDirI") {
- int state = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
- writeSelectorValue(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
+ int state = GET_SEL32V(s->_segMan, controlObject, SELECTOR(state));
+ PUT_SEL32V(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
}
_k_GenericDrawControl(s, controlObject, false);
@@ -896,7 +894,7 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) {
reg_t eventObject = argv[1];
if (!controlObject.isNull()) {
- int16 controlType = readSelectorValue(s->_segMan, controlObject, SELECTOR(type));
+ int16 controlType = GET_SEL32V(s->_segMan, controlObject, SELECTOR(type));
switch (controlType) {
case SCI_CONTROLS_TYPE_TEXTEDIT:
@@ -985,7 +983,7 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {
bool hiresMode = (argc > 7) ? true : false;
reg_t upscaledHiresHandle = (argc > 7) ? argv[7] : NULL_REG;
- if (!strcmp(g_sci->getGameID(), "freddypharkas") || !strcmp(g_sci->getGameID(), "freddypharkas-demo")) {
+ if ((s->_gameId == "freddypharkas") || (s->_gameId == "freddypharkas-demo")) {
// WORKAROUND
// Script 24 contains code that draws the game menu on screen. It uses a temp variable for setting priority that
// is not set. in Sierra sci this happens to be 8250h. In our sci temporary variables are initialized thus we would
@@ -996,7 +994,7 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {
priority = 15;
}
- if (!strcmp(g_sci->getGameID(), "laurabow2")) {
+ if (s->_gameId == "laurabow2") {
// WORKAROUND
// see the one above
if ((viewId == 995) && (priority == 0))
@@ -1082,12 +1080,11 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) {
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
// Hide the cursor if it's showing and then show it again if it was
// previously visible.
- bool reshowCursor = g_sci->_gfxCursor->isVisible();
+ bool reshowCursor;
+
+ reshowCursor = g_sci->_gfxCursor->isVisible();
if (reshowCursor)
g_sci->_gfxCursor->kernelHide();
-
- uint16 screenWidth = g_system->getWidth();
- uint16 screenHeight = g_system->getHeight();
Graphics::VideoDecoder *videoDecoder = 0;
@@ -1097,18 +1094,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
// Mac QuickTime
// The only argument is the string for the video
-
- // HACK: Switch to 16bpp graphics for Cinepak.
- initGraphics(screenWidth, screenHeight, screenWidth > 320, NULL);
-
- if (g_system->getScreenFormat().bytesPerPixel == 1) {
- warning("This video requires >8bpp color to be displayed, but could not switch to RGB color mode.");
- return NULL_REG;
- }
-
- videoDecoder = new Graphics::QuickTimeDecoder();
- if (!videoDecoder->loadFile(filename))
- error("Could not open '%s'", filename.c_str());
+ warning("TODO: Play QuickTime movie '%s'", filename.c_str());
+ return s->r_acc;
} else {
// DOS SEQ
// SEQ's are called with no subops, just the string and delay
@@ -1123,7 +1110,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
}
} else {
- // Windows AVI
+ // Windows AVI (Macintosh QuickTime? Need to check KQ6 Macintosh)
// TODO: This appears to be some sort of subop. case 0 contains the string
// for the video, so we'll just play it from there for now.
@@ -1155,10 +1142,10 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
if (videoDecoder) {
- uint16 x = (screenWidth - videoDecoder->getWidth()) / 2;
- uint16 y = (screenHeight - videoDecoder->getHeight()) / 2;
+ uint16 x = (g_system->getWidth() - videoDecoder->getWidth()) / 2;
+ uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2;
- while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
if (videoDecoder->needsUpdate()) {
Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
@@ -1177,15 +1164,9 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
g_system->delayMillis(10);
}
-
- // HACK: Switch back to 8bpp if we played a QuickTime video.
- // We also won't be copying the screen to the SCI screen...
- if (g_system->getScreenFormat().bytesPerPixel != 1)
- initGraphics(screenWidth, screenHeight, screenWidth > 320);
- else
- g_sci->_gfxScreen->kernelSyncWithFramebuffer();
delete videoDecoder;
+ g_sci->_gfxScreen->kernelSyncWithFramebuffer();
}
if (reshowCursor)
diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp
index f06f3eec77..c04454ca3d 100644
--- a/engines/sci/engine/klists.cpp
+++ b/engines/sci/engine/klists.cpp
@@ -155,10 +155,28 @@ reg_t kDisposeList(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+static reg_t _k_new_node(EngineState *s, reg_t value, reg_t key) {
+ reg_t nodebase;
+ Node *n = s->_segMan->allocateNode(&nodebase);
+
+ if (!n) {
+ error("[Kernel] Out of memory while creating a node");
+ return NULL_REG;
+ }
+
+ n->pred = n->succ = NULL_REG;
+ n->key = key;
+ n->value = value;
+
+ return nodebase;
+}
+
reg_t kNewNode(EngineState *s, int argc, reg_t *argv) {
- reg_t nodeValue = argv[0];
- reg_t nodeKey = (argc == 2) ? argv[1] : NULL_REG;
- s->r_acc = s->_segMan->newNode(nodeValue, nodeKey);
+
+ if (argc == 1)
+ s->r_acc = _k_new_node(s, argv[0], argv[0]);
+ else
+ s->r_acc = _k_new_node(s, argv[0], argv[1]);
debugC(2, kDebugLevelNodes, "New nodebase at %04x:%04x", PRINT_REG(s->r_acc));
@@ -397,11 +415,11 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
reg_t dest = argv[1];
reg_t order_func = argv[2];
- int input_size = (int16)readSelectorValue(segMan, source, SELECTOR(size));
+ int input_size = (int16)GET_SEL32V(segMan, source, SELECTOR(size));
int i;
- reg_t input_data = readSelector(segMan, source, SELECTOR(elements));
- reg_t output_data = readSelector(segMan, dest, SELECTOR(elements));
+ reg_t input_data = GET_SEL32(segMan, source, SELECTOR(elements));
+ reg_t output_data = GET_SEL32(segMan, dest, SELECTOR(elements));
List *list;
Node *node;
@@ -412,10 +430,10 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
if (output_data.isNull()) {
list = s->_segMan->allocateList(&output_data);
list->first = list->last = NULL_REG;
- writeSelector(segMan, dest, SELECTOR(elements), output_data);
+ PUT_SEL32(segMan, dest, SELECTOR(elements), output_data);
}
- writeSelectorValue(segMan, dest, SELECTOR(size), input_size);
+ PUT_SEL32V(segMan, dest, SELECTOR(size), input_size);
list = s->_segMan->lookupList(input_data);
node = s->_segMan->lookupNode(list->first);
@@ -424,7 +442,7 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
i = 0;
while (node) {
- invokeSelector(INV_SEL(s, order_func, doit, kStopOnInvalidSelector), 1, node->value);
+ invoke_selector(INV_SEL(s, order_func, doit, kStopOnInvalidSelector), 1, node->value);
temp_array[i].key = node->key;
temp_array[i].value = node->value;
temp_array[i].order = s->r_acc;
@@ -435,7 +453,7 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
qsort(temp_array, input_size, sizeof(sort_temp_t), sort_temp_cmp);
for (i = 0;i < input_size;i++) {
- reg_t lNode = s->_segMan->newNode(temp_array[i].value, temp_array[i].key);
+ reg_t lNode = _k_new_node(s, temp_array[i].key, temp_array[i].value);
_k_add_to_end(s, output_data, lNode);
}
@@ -515,15 +533,15 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// This can only happen with 3 params (list, target selector, variable)
if (argc != 3) {
warning("kListEachElementDo: Attempted to modify a variable selector with %d params", argc);
} else {
- writeSelector(s->_segMan, curObject, slc, argv[2]);
+ write_selector(s->_segMan, curObject, slc, argv[2]);
}
} else {
- invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
}
curNode = s->_segMan->lookupNode(nextNode);
@@ -548,11 +566,11 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// Can this happen with variable selectors?
warning("kListFirstTrue: Attempted to access a variable selector");
} else {
- invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
// Check if the result is true
if (!s->r_acc.isNull())
@@ -582,11 +600,11 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// Can this happen with variable selectors?
warning("kListAllTrue: Attempted to access a variable selector");
} else {
- invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
// Check if the result isn't true
if (s->r_acc.isNull())
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 68dc2fbba4..450dca3770 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -32,14 +32,14 @@
#include "sci/engine/kernel.h"
#include "sci/engine/gc.h"
#include "sci/graphics/gui.h"
-#include "sci/graphics/maciconbar.h"
namespace Sci {
reg_t kRestartGame(EngineState *s, int argc, reg_t *argv) {
s->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
+ s->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE; // This appears to help
- s->shrinkStackToBase();
+ shrink_execution_stack(s, s->execution_stack_base + 1);
script_abort_flag = 1; // Force vm to abort ASAP
return NULL_REG;
@@ -62,9 +62,9 @@ reg_t kGameIsRestarting(EngineState *s, int argc, reg_t *argv) {
// LSL3 calculates a machinespeed variable during game startup (right after the filthy questions)
// This one would go through w/o throttling resulting in having to do 1000 pushups or something
// Another way of handling this would be delaying incrementing of "machineSpeed" selector
- if (!strcmp(g_sci->getGameID(), "lsl3") && s->currentRoomNumber() == 290)
+ if (s->_gameId == "lsl3" && s->currentRoomNumber() == 290)
s->_throttleTrigger = true;
- if (!strcmp(g_sci->getGameID(), "iceman") && s->currentRoomNumber() == 27) {
+ if (s->_gameId == "iceman" && s->currentRoomNumber() == 27) {
s->_throttleTrigger = true;
neededSleep = 60;
}
@@ -252,15 +252,10 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
break;
}
case K_MEMORY_PEEK : {
- if (!argv[1].segment) {
- // This occurs in KQ5CD when interacting with certain objects
- warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
- return s->r_acc;
- }
-
SegmentRef ref = s->_segMan->dereference(argv[1]);
if (!ref.isValid() || ref.maxSize < 2) {
+ // This occurs in KQ5CD when interacting with certain objects
warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
return s->r_acc;
}
@@ -303,12 +298,9 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
reg_t kIconBar(EngineState *s, int argc, reg_t *argv) {
// TODO...
- if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0) {
+ if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0)
for (int i = 0; i < argv[2].toUint16(); i++)
- g_sci->_gfxMacIconBar->addIcon(argv[i + 3]);
-
- g_sci->_gfxMacIconBar->drawIcons();
- }
+ warning("kIconBar: Icon Object %d = %04x:%04x", i, PRINT_REG(argv[i + 3]));
// Other calls seem to handle selecting/deselecting them
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index 499aeabcc6..fcaf0d7ea0 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -158,8 +158,8 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "SetJump for object at %04x:%04x", PRINT_REG(object));
debugC(2, kDebugLevelBresen, "xStep: %d, yStep: %d", vx, vy);
- writeSelectorValue(segMan, object, SELECTOR(xStep), vx);
- writeSelectorValue(segMan, object, SELECTOR(yStep), vy);
+ PUT_SEL32V(segMan, object, SELECTOR(xStep), vx);
+ PUT_SEL32V(segMan, object, SELECTOR(yStep), vy);
return s->r_acc;
}
@@ -168,9 +168,9 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
#define _K_BRESEN_AXIS_Y 1
static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t mover, int step_factor, int deltax, int deltay) {
- reg_t client = readSelector(segMan, mover, SELECTOR(client));
- int stepx = (int16)readSelectorValue(segMan, client, SELECTOR(xStep)) * step_factor;
- int stepy = (int16)readSelectorValue(segMan, client, SELECTOR(yStep)) * step_factor;
+ reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
+ int stepx = (int16)GET_SEL32V(segMan, client, SELECTOR(xStep)) * step_factor;
+ int stepy = (int16)GET_SEL32V(segMan, client, SELECTOR(yStep)) * step_factor;
int numsteps_x = stepx ? (abs(deltax) + stepx - 1) / stepx : 0;
int numsteps_y = stepy ? (abs(deltay) + stepy - 1) / stepy : 0;
int bdi, i1;
@@ -191,15 +191,15 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m
/* if (abs(deltax) > abs(deltay)) {*/ // Bresenham on y
if (numsteps_y < numsteps_x) {
- writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y);
- writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1);
//i1 = 2 * (abs(deltay) - abs(deltay_step * numsteps)) * abs(deltax_step);
//bdi = -abs(deltax);
i1 = 2 * (abs(deltay) - abs(deltay_step * (numsteps - 1))) * abs(deltax_step);
bdi = -abs(deltax);
} else { // Bresenham on x
- writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X);
- writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1);
//i1= 2 * (abs(deltax) - abs(deltax_step * numsteps)) * abs(deltay_step);
//bdi = -abs(deltay);
i1 = 2 * (abs(deltax) - abs(deltax_step * (numsteps - 1))) * abs(deltay_step);
@@ -207,26 +207,26 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m
}
- writeSelectorValue(segMan, mover, SELECTOR(dx), deltax_step);
- writeSelectorValue(segMan, mover, SELECTOR(dy), deltay_step);
+ PUT_SEL32V(segMan, mover, SELECTOR(dx), deltax_step);
+ PUT_SEL32V(segMan, mover, SELECTOR(dy), deltay_step);
debugC(2, kDebugLevelBresen, "Init bresen for mover %04x:%04x: d=(%d,%d)", PRINT_REG(mover), deltax, deltay);
debugC(2, kDebugLevelBresen, " steps=%d, mv=(%d, %d), i1= %d, i2=%d",
numsteps, deltax_step, deltay_step, i1, bdi*2);
- //writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), numsteps); // Needed for HQ1/Ogre?
- writeSelectorValue(segMan, mover, SELECTOR(b_di), bdi);
- writeSelectorValue(segMan, mover, SELECTOR(b_i1), i1);
- writeSelectorValue(segMan, mover, SELECTOR(b_i2), bdi * 2);
+ //PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), numsteps); // Needed for HQ1/Ogre?
+ PUT_SEL32V(segMan, mover, SELECTOR(b_di), bdi);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_i1), i1);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_i2), bdi * 2);
}
reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
- reg_t client = readSelector(segMan, mover, SELECTOR(client));
+ reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
- int deltax = (int16)readSelectorValue(segMan, mover, SELECTOR(x)) - (int16)readSelectorValue(segMan, client, SELECTOR(x));
- int deltay = (int16)readSelectorValue(segMan, mover, SELECTOR(y)) - (int16)readSelectorValue(segMan, client, SELECTOR(y));
+ int deltax = (int16)GET_SEL32V(segMan, mover, SELECTOR(x)) - (int16)GET_SEL32V(segMan, client, SELECTOR(x));
+ int deltay = (int16)GET_SEL32V(segMan, mover, SELECTOR(y)) - (int16)GET_SEL32V(segMan, client, SELECTOR(y));
int step_factor = (argc < 1) ? argv[1].toUint16() : 1;
initialize_bresen(s->_segMan, argc, argv, mover, step_factor, deltax, deltay);
@@ -240,42 +240,42 @@ reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
- reg_t client = readSelector(segMan, mover, SELECTOR(client));
+ reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
- int x = (int16)readSelectorValue(segMan, client, SELECTOR(x));
- int y = (int16)readSelectorValue(segMan, client, SELECTOR(y));
+ int x = (int16)GET_SEL32V(segMan, client, SELECTOR(x));
+ int y = (int16)GET_SEL32V(segMan, client, SELECTOR(y));
int oldx, oldy, destx, desty, dx, dy, bdi, bi1, bi2, movcnt, bdelta, axis;
- uint16 signal = readSelectorValue(segMan, client, SELECTOR(signal));
+ uint16 signal = GET_SEL32V(segMan, client, SELECTOR(signal));
int completed = 0;
- int max_movcnt = readSelectorValue(segMan, client, SELECTOR(moveSpeed));
+ int max_movcnt = GET_SEL32V(segMan, client, SELECTOR(moveSpeed));
if (getSciVersion() > SCI_VERSION_01)
signal &= ~kSignalHitObstacle;
- writeSelector(segMan, client, SELECTOR(signal), make_reg(0, signal)); // This is a NOP for SCI0
+ PUT_SEL32(segMan, client, SELECTOR(signal), make_reg(0, signal)); // This is a NOP for SCI0
oldx = x;
oldy = y;
- destx = (int16)readSelectorValue(segMan, mover, SELECTOR(x));
- desty = (int16)readSelectorValue(segMan, mover, SELECTOR(y));
- dx = (int16)readSelectorValue(segMan, mover, SELECTOR(dx));
- dy = (int16)readSelectorValue(segMan, mover, SELECTOR(dy));
- bdi = (int16)readSelectorValue(segMan, mover, SELECTOR(b_di));
- bi1 = (int16)readSelectorValue(segMan, mover, SELECTOR(b_i1));
- bi2 = (int16)readSelectorValue(segMan, mover, SELECTOR(b_i2));
- movcnt = readSelectorValue(segMan, mover, SELECTOR(b_movCnt));
- bdelta = (int16)readSelectorValue(segMan, mover, SELECTOR(b_incr));
- axis = (int16)readSelectorValue(segMan, mover, SELECTOR(b_xAxis));
+ destx = (int16)GET_SEL32V(segMan, mover, SELECTOR(x));
+ desty = (int16)GET_SEL32V(segMan, mover, SELECTOR(y));
+ dx = (int16)GET_SEL32V(segMan, mover, SELECTOR(dx));
+ dy = (int16)GET_SEL32V(segMan, mover, SELECTOR(dy));
+ bdi = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_di));
+ bi1 = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_i1));
+ bi2 = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_i2));
+ movcnt = GET_SEL32V(segMan, mover, SELECTOR(b_movCnt));
+ bdelta = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_incr));
+ axis = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_xAxis));
//printf("movecnt %d, move speed %d\n", movcnt, max_movcnt);
if (g_sci->_features->handleMoveCount()) {
if (max_movcnt > movcnt) {
++movcnt;
- writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
+ PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
return NULL_REG;
} else {
movcnt = 0;
- writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
+ PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
}
}
@@ -288,7 +288,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
dy += bdelta;
}
- writeSelectorValue(segMan, mover, SELECTOR(b_di), bdi);
+ PUT_SEL32V(segMan, mover, SELECTOR(b_di), bdi);
x += dx;
y += dy;
@@ -310,32 +310,33 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x", PRINT_REG(mover));
}
- writeSelectorValue(segMan, client, SELECTOR(x), x);
- writeSelectorValue(segMan, client, SELECTOR(y), y);
+ PUT_SEL32V(segMan, client, SELECTOR(x), x);
+ PUT_SEL32V(segMan, client, SELECTOR(y), y);
debugC(2, kDebugLevelBresen, "New data: (x,y)=(%d,%d), di=%d", x, y, bdi);
if (g_sci->getKernel()->_selectorCache.cantBeHere != -1) {
- invokeSelector(INV_SEL(s, client, cantBeHere, kStopOnInvalidSelector), 0);
+ invoke_selector(INV_SEL(s, client, cantBeHere, kStopOnInvalidSelector), 0);
s->r_acc = make_reg(0, !s->r_acc.offset);
} else {
- invokeSelector(INV_SEL(s, client, canBeHere, kStopOnInvalidSelector), 0);
+ invoke_selector(INV_SEL(s, client, canBeHere, kStopOnInvalidSelector), 0);
}
if (!s->r_acc.offset) { // Contains the return value
- signal = readSelectorValue(segMan, client, SELECTOR(signal));
+ signal = GET_SEL32V(segMan, client, SELECTOR(signal));
- writeSelectorValue(segMan, client, SELECTOR(x), oldx);
- writeSelectorValue(segMan, client, SELECTOR(y), oldy);
- writeSelectorValue(segMan, client, SELECTOR(signal), (signal | kSignalHitObstacle));
+ PUT_SEL32V(segMan, client, SELECTOR(x), oldx);
+ PUT_SEL32V(segMan, client, SELECTOR(y), oldy);
+ PUT_SEL32V(segMan, client, SELECTOR(signal), (signal | kSignalHitObstacle));
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x by collision", PRINT_REG(mover));
completed = 1;
}
- if ((getSciVersion() >= SCI_VERSION_1_EGA))
+ // FIXME: find out why iceman needs this and we ask for version > SCI01
+ if ((getSciVersion() > SCI_VERSION_01) || (s->_gameId == "iceman"))
if (completed)
- invokeSelector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0);
+ invoke_selector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0);
return make_reg(0, completed);
}
@@ -377,15 +378,15 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
- client = readSelector(segMan, avoider, SELECTOR(client));
+ client = GET_SEL32(segMan, avoider, SELECTOR(client));
if (!s->_segMan->isHeapObject(client)) {
warning("DoAvoider() where client %04x:%04x is not an object", PRINT_REG(client));
return NULL_REG;
}
- looper = readSelector(segMan, client, SELECTOR(looper));
- mover = readSelector(segMan, client, SELECTOR(mover));
+ looper = GET_SEL32(segMan, client, SELECTOR(looper));
+ mover = GET_SEL32(segMan, client, SELECTOR(mover));
if (!s->_segMan->isHeapObject(mover)) {
if (mover.segment) {
@@ -394,38 +395,38 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- destx = readSelectorValue(segMan, mover, SELECTOR(x));
- desty = readSelectorValue(segMan, mover, SELECTOR(y));
+ destx = GET_SEL32V(segMan, mover, SELECTOR(x));
+ desty = GET_SEL32V(segMan, mover, SELECTOR(y));
debugC(2, kDebugLevelBresen, "Doing avoider %04x:%04x (dest=%d,%d)", PRINT_REG(avoider), destx, desty);
- if (invokeSelector(INV_SEL(s, mover, doit, kContinueOnInvalidSelector) , 0)) {
+ if (invoke_selector(INV_SEL(s, mover, doit, kContinueOnInvalidSelector) , 0)) {
error("Mover %04x:%04x of avoider %04x:%04x doesn't have a doit() funcselector", PRINT_REG(mover), PRINT_REG(avoider));
return NULL_REG;
}
- mover = readSelector(segMan, client, SELECTOR(mover));
+ mover = GET_SEL32(segMan, client, SELECTOR(mover));
if (!mover.segment) // Mover has been disposed?
return s->r_acc; // Return gracefully.
- if (invokeSelector(INV_SEL(s, client, isBlocked, kContinueOnInvalidSelector) , 0)) {
+ if (invoke_selector(INV_SEL(s, client, isBlocked, kContinueOnInvalidSelector) , 0)) {
error("Client %04x:%04x of avoider %04x:%04x doesn't"
" have an isBlocked() funcselector", PRINT_REG(client), PRINT_REG(avoider));
return NULL_REG;
}
- dx = destx - readSelectorValue(segMan, client, SELECTOR(x));
- dy = desty - readSelectorValue(segMan, client, SELECTOR(y));
+ dx = destx - GET_SEL32V(segMan, client, SELECTOR(x));
+ dy = desty - GET_SEL32V(segMan, client, SELECTOR(y));
angle = getAngle(dx, dy);
debugC(2, kDebugLevelBresen, "Movement (%d,%d), angle %d is %sblocked", dx, dy, angle, (s->r_acc.offset) ? " " : "not ");
if (s->r_acc.offset) { // isBlocked() returned non-zero
int rotation = (rand() & 1) ? 45 : (360 - 45); // Clockwise/counterclockwise
- int oldx = readSelectorValue(segMan, client, SELECTOR(x));
- int oldy = readSelectorValue(segMan, client, SELECTOR(y));
- int xstep = readSelectorValue(segMan, client, SELECTOR(xStep));
- int ystep = readSelectorValue(segMan, client, SELECTOR(yStep));
+ int oldx = GET_SEL32V(segMan, client, SELECTOR(x));
+ int oldy = GET_SEL32V(segMan, client, SELECTOR(y));
+ int xstep = GET_SEL32V(segMan, client, SELECTOR(xStep));
+ int ystep = GET_SEL32V(segMan, client, SELECTOR(yStep));
int moves;
debugC(2, kDebugLevelBresen, " avoider %04x:%04x", PRINT_REG(avoider));
@@ -434,23 +435,23 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
int move_x = (int)(sin(angle * PI / 180.0) * (xstep));
int move_y = (int)(-cos(angle * PI / 180.0) * (ystep));
- writeSelectorValue(segMan, client, SELECTOR(x), oldx + move_x);
- writeSelectorValue(segMan, client, SELECTOR(y), oldy + move_y);
+ PUT_SEL32V(segMan, client, SELECTOR(x), oldx + move_x);
+ PUT_SEL32V(segMan, client, SELECTOR(y), oldy + move_y);
debugC(2, kDebugLevelBresen, "Pos (%d,%d): Trying angle %d; delta=(%d,%d)", oldx, oldy, angle, move_x, move_y);
- if (invokeSelector(INV_SEL(s, client, canBeHere, kContinueOnInvalidSelector) , 0)) {
+ if (invoke_selector(INV_SEL(s, client, canBeHere, kContinueOnInvalidSelector) , 0)) {
error("Client %04x:%04x of avoider %04x:%04x doesn't"
" have a canBeHere() funcselector", PRINT_REG(client), PRINT_REG(avoider));
return NULL_REG;
}
- writeSelectorValue(segMan, client, SELECTOR(x), oldx);
- writeSelectorValue(segMan, client, SELECTOR(y), oldy);
+ PUT_SEL32V(segMan, client, SELECTOR(x), oldx);
+ PUT_SEL32V(segMan, client, SELECTOR(y), oldy);
if (s->r_acc.offset) { // We can be here
debugC(2, kDebugLevelBresen, "Success");
- writeSelectorValue(segMan, client, SELECTOR(heading), angle);
+ PUT_SEL32V(segMan, client, SELECTOR(heading), angle);
return make_reg(0, angle);
}
@@ -463,17 +464,17 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
warning("DoAvoider failed for avoider %04x:%04x", PRINT_REG(avoider));
} else {
- int heading = readSelectorValue(segMan, client, SELECTOR(heading));
+ int heading = GET_SEL32V(segMan, client, SELECTOR(heading));
if (heading == -1)
return s->r_acc; // No change
- writeSelectorValue(segMan, client, SELECTOR(heading), angle);
+ PUT_SEL32V(segMan, client, SELECTOR(heading), angle);
s->r_acc = make_reg(0, angle);
if (looper.segment) {
- if (invokeSelector(INV_SEL(s, looper, doit, kContinueOnInvalidSelector), 2, angle, client)) {
+ if (invoke_selector(INV_SEL(s, looper, doit, kContinueOnInvalidSelector), 2, angle, client)) {
error("Looper %04x:%04x of avoider %04x:%04x doesn't"
" have a doit() funcselector", PRINT_REG(looper), PRINT_REG(avoider));
} else
diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp
index 785ff39d22..0254d21642 100644
--- a/engines/sci/engine/kparse.cpp
+++ b/engines/sci/engine/kparse.cpp
@@ -42,7 +42,6 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
reg_t heap_said_block = argv[0];
byte *said_block;
int new_lastmatch;
- Vocabulary *voc = g_sci->getVocabulary();
#ifdef DEBUG_PARSER
const int debug_parser = 1;
#else
@@ -64,7 +63,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
s->_voc->decipherSaidBlock(said_block);
#endif
- if (voc->parser_event.isNull() || (readSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed)))) {
+ if (s->_voc->parser_event.isNull() || (GET_SEL32V(s->_segMan, s->_voc->parser_event, SELECTOR(claimed)))) {
return NULL_REG;
}
@@ -78,7 +77,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
s->r_acc = make_reg(0, 1);
if (new_lastmatch != SAID_PARTIAL_MATCH)
- writeSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed), 1);
+ PUT_SEL32V(s->_segMan, s->_voc->parser_event, SELECTOR(claimed), 1);
} else {
return NULL_REG;
@@ -93,15 +92,15 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) {
char *error;
ResultWordList words;
reg_t event = argv[1];
- Vocabulary *voc = g_sci->getVocabulary();
+ Vocabulary *voc = s->_voc;
- voc->parser_event = event;
+ s->_voc->parser_event = event;
bool res = voc->tokenizeString(words, string.c_str(), &error);
- voc->parserIsValid = false; /* not valid */
+ s->_voc->parserIsValid = false; /* not valid */
if (res && !words.empty()) {
- voc->synonymizeTokens(words);
+ s->_voc->synonymizeTokens(words);
s->r_acc = make_reg(0, 1);
@@ -116,32 +115,32 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) {
if (syntax_fail) {
s->r_acc = make_reg(0, 1);
- writeSelectorValue(segMan, event, SELECTOR(claimed), 1);
+ PUT_SEL32V(segMan, event, SELECTOR(claimed), 1);
- invokeSelector(INV_SEL(s, s->_gameObj, syntaxFail, kStopOnInvalidSelector), 2, voc->parser_base, stringpos);
+ invoke_selector(INV_SEL(s, s->_gameObj, syntaxFail, kStopOnInvalidSelector), 2, s->_voc->parser_base, stringpos);
/* Issue warning */
debugC(2, kDebugLevelParser, "Tree building failed");
} else {
- voc->parserIsValid = true;
- writeSelectorValue(segMan, event, SELECTOR(claimed), 0);
+ s->_voc->parserIsValid = true;
+ PUT_SEL32V(segMan, event, SELECTOR(claimed), 0);
#ifdef DEBUG_PARSER
- voc->dumpParseTree();
+ s->_voc->dumpParseTree();
#endif
}
} else {
s->r_acc = make_reg(0, 0);
- writeSelectorValue(segMan, event, SELECTOR(claimed), 1);
+ PUT_SEL32V(segMan, event, SELECTOR(claimed), 1);
if (error) {
- s->_segMan->strcpy(voc->parser_base, error);
+ s->_segMan->strcpy(s->_voc->parser_base, error);
debugC(2, kDebugLevelParser, "Word unknown: %s", error);
/* Issue warning: */
- invokeSelector(INV_SEL(s, s->_gameObj, wordFail, kStopOnInvalidSelector), 2, voc->parser_base, stringpos);
+ invoke_selector(INV_SEL(s, s->_gameObj, wordFail, kStopOnInvalidSelector), 2, s->_voc->parser_base, stringpos);
free(error);
return make_reg(0, 1); /* Tell them that it didn't work */
}
@@ -157,29 +156,28 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
Node *node;
int script;
int numSynonyms = 0;
- Vocabulary *voc = g_sci->getVocabulary();
// Only SCI0-SCI1 EGA games had a parser. In newer versions, this is a stub
if (getSciVersion() > SCI_VERSION_1_EGA)
return s->r_acc;
- voc->clearSynonyms();
+ s->_voc->clearSynonyms();
- list = s->_segMan->lookupList(readSelector(segMan, object, SELECTOR(elements)));
+ list = s->_segMan->lookupList(GET_SEL32(segMan, object, SELECTOR(elements)));
node = s->_segMan->lookupNode(list->first);
while (node) {
reg_t objpos = node->value;
int seg;
- script = readSelectorValue(segMan, objpos, SELECTOR(number));
+ script = GET_SEL32V(segMan, objpos, SELECTOR(number));
seg = s->_segMan->getScriptSegment(script);
if (seg > 0)
numSynonyms = s->_segMan->getScript(seg)->getSynonymsNr();
if (numSynonyms) {
- const byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
+ byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
if (synonyms) {
debugC(2, kDebugLevelParser, "Setting %d synonyms for script.%d",
@@ -195,7 +193,7 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
synonym_t tmp;
tmp.replaceant = (int16)READ_LE_UINT16(synonyms + i * 4);
tmp.replacement = (int16)READ_LE_UINT16(synonyms + i * 4 + 2);
- voc->addSynonym(tmp);
+ s->_voc->addSynonym(tmp);
}
} else
warning("Synonyms of script.%03d were requested, but script is not available", script);
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 857ccc2a08..25d967c247 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -337,15 +337,15 @@ static void draw_point(EngineState *s, Common::Point p, int start, int width, in
static void draw_polygon(EngineState *s, reg_t polygon, int width, int height) {
SegManager *segMan = s->_segMan;
- reg_t points = readSelector(segMan, polygon, SELECTOR(points));
+ reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
#ifdef ENABLE_SCI32
if (segMan->isHeapObject(points))
- points = readSelector(segMan, points, SELECTOR(data));
+ points = GET_SEL32(segMan, points, SELECTOR(data));
#endif
- int size = readSelectorValue(segMan, polygon, SELECTOR(size));
- int type = readSelectorValue(segMan, polygon, SELECTOR(type));
+ int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
+ int type = GET_SEL32V(segMan, polygon, SELECTOR(type));
Common::Point first, prev;
int i;
@@ -386,15 +386,15 @@ static void draw_input(EngineState *s, reg_t poly_list, Common::Point start, Com
}
static void print_polygon(SegManager *segMan, reg_t polygon) {
- reg_t points = readSelector(segMan, polygon, SELECTOR(points));
+ reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
#ifdef ENABLE_SCI32
if (segMan->isHeapObject(points))
- points = readSelector(segMan, points, SELECTOR(data));
+ points = GET_SEL32(segMan, points, SELECTOR(data));
#endif
- int size = readSelectorValue(segMan, polygon, SELECTOR(size));
- int type = readSelectorValue(segMan, polygon, SELECTOR(type));
+ int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
+ int type = GET_SEL32V(segMan, polygon, SELECTOR(type));
int i;
Common::Point point;
@@ -1036,13 +1036,13 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
// Returns : (Polygon *) The converted polygon, or NULL on error
SegManager *segMan = s->_segMan;
int i;
- reg_t points = readSelector(segMan, polygon, SELECTOR(points));
- int size = readSelectorValue(segMan, polygon, SELECTOR(size));
+ reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
+ int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
#ifdef ENABLE_SCI32
// SCI32 stores the actual points in the data property of points (in a new array)
if (segMan->isHeapObject(points))
- points = readSelector(segMan, points, SELECTOR(data));
+ points = GET_SEL32(segMan, points, SELECTOR(data));
#endif
if (size == 0) {
@@ -1050,13 +1050,13 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
return NULL;
}
- Polygon *poly = new Polygon(readSelectorValue(segMan, polygon, SELECTOR(type)));
+ Polygon *poly = new Polygon(GET_SEL32V(segMan, polygon, SELECTOR(type)));
int skip = 0;
// WORKAROUND: broken polygon in lsl1sci, room 350, after opening elevator
// Polygon has 17 points but size is set to 19
- if ((size == 19) && !strcmp(g_sci->getGameID(), "lsl1sci")) {
+ if ((size == 19) && (s->_gameId == "lsl1sci")) {
if ((s->currentRoomNumber() == 350)
&& (read_point(segMan, points, 18) == Common::Point(108, 137))) {
debug(1, "Applying fix for broken polygon in lsl1sci, room 350");
@@ -1121,7 +1121,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
if (polygon) {
pf_s->polygons.push_back(polygon);
- count += readSelectorValue(segMan, node->value, SELECTOR(size));
+ count += GET_SEL32V(segMan, node->value, SELECTOR(size));
}
node = s->_segMan->lookupNode(node->succ);
@@ -1174,7 +1174,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
// WORKAROUND LSL5 room 660. Priority glitch due to us choosing a different path
// than SSCI. Happens when Patti walks to the control room.
- if (!strcmp(g_sci->getGameID(), "lsl5") && (s->currentRoomNumber() == 660) && (Common::Point(67, 131) == *new_start) && (Common::Point(229, 101) == *new_end)) {
+ if ((s->_gameId == "lsl5") && (s->currentRoomNumber() == 660) && (Common::Point(67, 131) == *new_start) && (Common::Point(229, 101) == *new_end)) {
debug(1, "[avoidpath] Applying fix for priority problem in LSL5, room 660");
pf_s->_prependPoint = new_start;
new_start = new Common::Point(77, 107);
@@ -1394,7 +1394,7 @@ reg_t kAvoidPath(EngineState *s, int argc, reg_t *argv) {
if (argc < 7)
error("[avoidpath] Not enough arguments");
- poly_list = (!argv[4].isNull() ? readSelector(s->_segMan, argv[4], SELECTOR(elements)) : NULL_REG);
+ poly_list = (!argv[4].isNull() ? GET_SEL32(s->_segMan, argv[4], SELECTOR(elements)) : NULL_REG);
width = argv[5].toUint16();
height = argv[6].toUint16();
if (argc > 7)
@@ -1694,38 +1694,4 @@ reg_t kIntersections(EngineState *s, int argc, reg_t *argv) {
}
}
-// This is a quite rare kernel function. An example of when it's called
-// is in QFG1VGA, after killing any monster.
-reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) {
- // 3 parameters: raw polygon data, polygon list, list size
- reg_t polygonData = argv[0];
-
- // TODO: actually merge the polygon
- // In QFG1VGA, there are no immediately visible side-effects
- // of this being a stub.
-
-#if 0
- List *list = s->_segMan->lookupList(argv[1]);
- Node *node = s->_segMan->lookupNode(list->first);
- // List size is not needed
-
- Polygon *polygon;
- int count = 0;
-
- while (node) {
- polygon = convert_polygon(s, node->value);
-
- if (polygon) {
- count += readSelectorValue(s->_segMan, node->value, SELECTOR(size));
- }
-
- node = s->_segMan->lookupNode(node->succ);
- }
-#endif
-
- warning("Stub: kMergePoly");
-
- return polygonData;
-}
-
} // End of namespace Sci
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 722d0175d1..ba29f64966 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -111,7 +111,7 @@ reg_t kResCheck(EngineState *s, int argc, reg_t *argv) {
reg_t kClone(EngineState *s, int argc, reg_t *argv) {
reg_t parent_addr = argv[0];
- const Object *parent_obj = s->_segMan->getObject(parent_addr);
+ Object *parent_obj = s->_segMan->getObject(parent_addr);
reg_t clone_addr;
Clone *clone_obj; // same as Object*
@@ -132,7 +132,7 @@ reg_t kClone(EngineState *s, int argc, reg_t *argv) {
*clone_obj = *parent_obj;
// Mark as clone
- clone_obj->markAsClone();
+ clone_obj->setInfoSelector(make_reg(0, SCRIPT_INFO_CLONE));
clone_obj->setSpeciesSelector(clone_obj->getPos());
if (parent_obj->isClass())
clone_obj->setSuperClassSelector(parent_obj->getPos());
@@ -154,14 +154,14 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- if (!victim_obj->isClone()) {
+ if (victim_obj->getInfoSelector().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
return s->r_acc;
}
// QFG3 clears clones with underbits set
- //if (readSelectorValue(victim_addr, underBits))
+ //if (GET_SEL32V(victim_addr, underBits))
// warning("Clone %04x:%04x was cleared with underBits set", PRINT_REG(victim_addr));
#if 0
@@ -181,7 +181,7 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
// Returns script dispatch address index in the supplied script
reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
int script = argv[0].toUint16();
- uint16 index = (argc > 1) ? argv[1].toUint16() : 0;
+ int index = (argc > 1) ? argv[1].toUint16() : 0;
if (argv[0].segment)
return argv[0];
@@ -193,30 +193,18 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
Script *scr = s->_segMan->getScript(scriptSeg);
- if (!scr->getExportsNr()) {
- // This is normal. Some scripts don't have a dispatch (exports) table,
- // and this call is probably used to load them in memory, ignoring
- // the return value. If only one argument is passed, this call is done
- // only to load the script in memory. Thus, don't show any warning,
- // as no return value is expected
- if (argc == 2)
- warning("Script 0x%x does not have a dispatch table and export %d "
- "was requested from it", script, index);
+ if (!scr->_numExports) {
+ // FIXME: Is this fatal? This occurs in SQ4CD
+ warning("Script 0x%x does not have a dispatch table", script);
return NULL_REG;
}
- if (index > scr->getExportsNr()) {
- error("Dispatch index too big: %d > %d", index, scr->getExportsNr());
+ if (index > scr->_numExports) {
+ error("Dispatch index too big: %d > %d", index, scr->_numExports);
return NULL_REG;
}
- uint16 address = scr->validateExportFunc(index);
-
- // Point to the heap for SCI1.1+ games
- if (getSciVersion() >= SCI_VERSION_1_1)
- address += scr->getScriptSize();
-
- return make_reg(scriptSeg, address);
+ return make_reg(scriptSeg, scr->validateExportFunc(index));
}
reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) {
@@ -256,7 +244,7 @@ reg_t kRespondsTo(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
int selector = argv[1].toUint16();
- return make_reg(0, s->_segMan->isHeapObject(obj) && lookupSelector(s->_segMan, obj, selector, NULL, NULL) != kSelectorNone);
+ return make_reg(0, s->_segMan->isHeapObject(obj) && lookup_selector(s->_segMan, obj, selector, NULL, NULL) != kSelectorNone);
}
} // End of namespace Sci
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 2681b612e9..426c682e11 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -138,36 +138,10 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
while (isspace((unsigned char)*source))
source++; /* Skip whitespace */
- int16 result = 0;
-
- if (*source == '$') {
- // hexadecimal input
- result = (int16)strtol(source + 1, NULL, 16);
- } else {
- // decimal input, we can not use strtol/atoi in here, because sierra used atoi BUT it was a non standard compliant
- // atoi, that didnt do clipping. In SQ4 we get the door code in here and that's even larger than uint32!
- if (*source == '-') {
- result = -1;
- source++;
- }
- while (*source) {
- if ((*source < '0') || (*source > '9')) {
- // Sierras atoi stopped processing at anything different than number
- // Sometimes the input has a trailing space, that's fine (example: lsl3)
- if (*source != ' ') {
- // TODO: this happens in lsl5 right in the intro -> we get '1' '3' 0xCD 0xCD 0xCD 0xCD 0xCD
- // find out why this happens and fix it
- warning("Invalid character in kReadNumber input");
- }
- break;
- }
- result *= 10;
- result += *source - 0x30;
- source++;
- }
- }
-
- return make_reg(0, result);
+ if (*source == '$') /* SCI uses this for hex numbers */
+ return make_reg(0, (int16)strtol(source + 1, NULL, 16)); /* Hex */
+ else
+ return make_reg(0, (int16)strtol(source, NULL, 10)); /* Force decimal */
}
@@ -267,7 +241,7 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
#ifdef ENABLE_SCI32
// If the string is a string object, get to the actual string in the data selector
if (s->_segMan->isObject(reg))
- reg = readSelector(s->_segMan, reg, SELECTOR(data));
+ reg = GET_SEL32(s->_segMan, reg, SELECTOR(data));
#endif
Common::String tempsource = (reg == NULL_REG) ? "" : g_sci->getKernel()->lookupText(reg,
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 798f889460..fef2b9a19e 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -383,7 +383,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
sync_SegManagerPtr(s, _segMan);
- syncArray<Class>(s, _segMan->_classTable);
+ syncArray<Class>(s, _segMan->_classtable);
#ifdef USE_OLD_MUSIC_FUNCTIONS
sync_songlib(s, _sound._songlib);
@@ -541,8 +541,8 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) {
}
}
- s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numExports
- s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numSynonyms
+ s.syncAsSint32LE(_numExports);
+ s.syncAsSint32LE(_numSynonyms);
s.syncAsSint32LE(_lockers);
// Sync _objects. This is a hashmap, and we use the following on disk format:
@@ -731,6 +731,15 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
return 1;
}
+/*
+ if (s->sound_server) {
+ if ((s->sound_server->save)(s, dirname)) {
+ warning("Saving failed for the sound subsystem");
+ //chdir("..");
+ return 1;
+ }
+ }
+*/
Common::Serializer ser(0, fh);
sync_SavegameMetadata(ser, meta);
Graphics::saveThumbnail(*fh);
@@ -739,6 +748,26 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
return 0;
}
+static byte *find_unique_script_block(EngineState *s, byte *buf, int type) {
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+
+ if (oldScriptHeader)
+ buf += 2;
+
+ do {
+ int seeker_type = READ_LE_UINT16(buf);
+
+ if (seeker_type == 0) break;
+ if (seeker_type == type) return buf;
+
+ int seeker_size = READ_LE_UINT16(buf + 2);
+ assert(seeker_size > 0);
+ buf += seeker_size;
+ } while (1);
+
+ return NULL;
+}
+
// TODO: This should probably be turned into an EngineState or DataStack method.
static void reconstruct_stack(EngineState *retval) {
SegmentId stack_seg = retval->_segMan->findSegmentByType(SEG_TYPE_STACK);
@@ -748,37 +777,99 @@ static void reconstruct_stack(EngineState *retval) {
retval->stack_top = stack->_entries + stack->_capacity;
}
+static void load_script(EngineState *s, Script *scr) {
+ scr->_buf = (byte *)malloc(scr->_bufSize);
+ assert(scr->_buf);
+
+ Resource *script = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, scr->_nr), 0);
+ assert(script != 0);
+
+ assert(scr->_bufSize >= script->size);
+ memcpy(scr->_buf, script->data, script->size);
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ Resource *heap = g_sci->getResMan()->findResource(ResourceId(kResourceTypeHeap, scr->_nr), 0);
+ assert(heap != 0);
+
+ scr->_heapStart = scr->_buf + scr->_scriptSize;
+
+ assert(scr->_bufSize - scr->_scriptSize <= heap->size);
+ memcpy(scr->_heapStart, heap->data, heap->size);
+ }
+}
+
// TODO: Move thie function to a more appropriate place, such as vm.cpp or script.cpp
void SegManager::reconstructScripts(EngineState *s) {
uint i;
+ SegmentObj *mobj;
for (i = 0; i < _heap.size(); i++) {
- if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
+ mobj = _heap[i];
+ if (!mobj || mobj->getType() != SEG_TYPE_SCRIPT)
continue;
- Script *scr = (Script *)_heap[i];
- scr->load(g_sci->getResMan());
+ Script *scr = (Script *)mobj;
+
+ // FIXME: Unify this code with script_instantiate_* ?
+ load_script(s, scr);
scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]);
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ scr->_exportTable = 0;
+ scr->_synonyms = 0;
+ if (READ_LE_UINT16(scr->_buf + 6) > 0) {
+ scr->setExportTableOffset(6);
+ s->_segMan->scriptRelocateExportsSci11(i);
+ }
+ } else {
+ scr->_exportTable = (uint16 *) find_unique_script_block(s, scr->_buf, SCI_OBJ_EXPORTS);
+ scr->_synonyms = find_unique_script_block(s, scr->_buf, SCI_OBJ_SYNONYMS);
+ scr->_exportTable += 3;
+ }
+ scr->_codeBlocks.clear();
- for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it)
- it->_value._baseObj = scr->_buf + it->_value.getPos().offset;
+ ObjMap::iterator it;
+ const ObjMap::iterator end = scr->_objects.end();
+ for (it = scr->_objects.begin(); it != end; ++it) {
+ byte *data = scr->_buf + it->_value.getPos().offset;
+ it->_value._baseObj = data;
+ }
}
for (i = 0; i < _heap.size(); i++) {
- if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
+ mobj = _heap[i];
+ if (!mobj || mobj->getType() != SEG_TYPE_SCRIPT)
continue;
- Script *scr = (Script *)_heap[i];
-
- for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) {
- reg_t addr = it->_value.getPos();
- Object *obj = scr->scriptObjInit(addr, false);
+ Script *scr = (Script *)mobj;
- if (getSciVersion() < SCI_VERSION_1_1) {
- if (!obj->initBaseObject(this, addr, false)) {
- warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
- scr->scriptObjRemove(addr);
+ // FIXME: Unify this code with Script::scriptObjInit ?
+ ObjMap::iterator it;
+ const ObjMap::iterator end = scr->_objects.end();
+ for (it = scr->_objects.begin(); it != end; ++it) {
+ byte *data = scr->_buf + it->_value.getPos().offset;
+
+ if (getSciVersion() >= 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 ));
+
+ it->_value._baseMethod = funct_area;
+ it->_value._baseVars = prop_area;
+ } else {
+ int funct_area = READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET);
+ Object *_baseObj;
+
+ _baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector());
+
+ if (!_baseObj) {
+ warning("Object without a base class: Script %d, index %d (reg address %04x:%04x",
+ scr->_nr, i, PRINT_REG(it->_value.getSpeciesSelector()));
+ continue;
}
+ it->_value.setVarCount(_baseObj->getVarCount());
+ it->_value._baseObj = _baseObj->_baseObj;
+
+ it->_value._baseMethod = (uint16 *)(data + funct_area);
+ it->_value._baseVars = (uint16 *)(data + it->_value.getVarCount() * 2 + SCRIPT_SELECTOR_OFFSET);
}
}
}
@@ -821,6 +912,7 @@ static void reconstruct_sounds(EngineState *s) {
#endif
void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
+ EngineState *retval;
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongLibrary temp;
#endif
@@ -855,68 +947,86 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
thumbnail = 0;
}
- s->reset(true);
- s->saveLoadWithSerializer(ser); // FIXME: Error handling?
+ // Create a new EngineState object
+ retval = new EngineState(s->_voc, s->_segMan);
+ retval->_event = s->_event;
+
+ // Copy some old data
+ retval->_soundCmd = s->_soundCmd;
+
+ // Copy memory segment
+ retval->_memorySegmentSize = s->_memorySegmentSize;
+ memcpy(retval->_memorySegment, s->_memorySegment, s->_memorySegmentSize);
+
+ retval->saveLoadWithSerializer(ser); // FIXME: Error handling?
#ifdef USE_OLD_MUSIC_FUNCTIONS
s->_sound.sfx_exit();
#endif
// Set exec stack base to zero
- s->execution_stack_base = 0;
+ retval->execution_stack_base = 0;
// Now copy all current state information
#ifdef USE_OLD_MUSIC_FUNCTIONS
- temp = s->_sound._songlib;
- s->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
- s->sfx_init_flags = s->sfx_init_flags;
- s->_sound._songlib.freeSounds();
- s->_sound._songlib = temp;
- s->_soundCmd->updateSfxState(&retval->_sound);
+ temp = retval->_sound._songlib;
+ retval->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
+ retval->sfx_init_flags = s->sfx_init_flags;
+ retval->_sound._songlib.freeSounds();
+ retval->_sound._songlib = temp;
+ retval->_soundCmd->updateSfxState(&retval->_sound);
#endif
- reconstruct_stack(s);
- s->_segMan->reconstructScripts(s);
- s->_segMan->reconstructClones();
- s->_gameObj = s->_gameObj;
- s->script_000 = s->_segMan->getScript(s->_segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
- s->gc_countdown = GC_INTERVAL - 1;
+ reconstruct_stack(retval);
+ retval->_segMan->reconstructScripts(retval);
+ retval->_segMan->reconstructClones();
+ retval->_gameObj = s->_gameObj;
+ retval->script_000 = retval->_segMan->getScript(retval->_segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
+ retval->gc_countdown = GC_INTERVAL - 1;
+ retval->sys_strings_segment = retval->_segMan->findSegmentByType(SEG_TYPE_SYS_STRINGS);
+ retval->sys_strings = (SystemStrings *)(retval->_segMan->_heap[retval->sys_strings_segment]);
// Time state:
- s->last_wait_time = g_system->getMillis();
- s->game_start_time = g_system->getMillis();
+ retval->last_wait_time = g_system->getMillis();
+ retval->game_start_time = g_system->getMillis();
+
+ // static parser information:
+
+ if (retval->_voc)
+ retval->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
- s->restoring = false;
+ retval->successor = NULL;
+ retval->_gameId = s->_gameId;
#ifdef USE_OLD_MUSIC_FUNCTIONS
- s->_sound._it = NULL;
- s->_sound._flags = s->_sound._flags;
- s->_sound._song = NULL;
- s->_sound._suspended = s->_sound._suspended;
- reconstruct_sounds(s);
+ retval->_sound._it = NULL;
+ retval->_sound._flags = s->_sound._flags;
+ retval->_sound._song = NULL;
+ retval->_sound._suspended = s->_sound._suspended;
+ reconstruct_sounds(retval);
#else
- s->_soundCmd->reconstructPlayList(meta.savegame_version);
+ retval->_soundCmd->reconstructPlayList(meta.savegame_version);
#endif
// Message state:
- s->_msgState = new MessageState(s->_segMan);
+ retval->_msgState = new MessageState(retval->_segMan);
#ifdef ENABLE_SCI32
if (g_sci->_gui32) {
g_sci->_gui32->init();
} else {
#endif
- g_sci->_gui->resetEngineState(s);
+ g_sci->_gui->resetEngineState(retval);
g_sci->_gui->init(g_sci->_features->usesOldGfxFunctions());
#ifdef ENABLE_SCI32
}
#endif
- s->restoring = true;
+ s->successor = retval; // Set successor
script_abort_flag = 2; // Abort current game with replay
- s->shrinkStackToBase();
+ shrink_execution_stack(s, s->execution_stack_base + 1);
}
bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) {
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 7be05381da..bad79fca27 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -36,7 +36,7 @@ namespace Sci {
struct EngineState;
enum {
- CURRENT_SAVEGAME_VERSION = 20,
+ CURRENT_SAVEGAME_VERSION = 19,
MINIMUM_SAVEGAME_VERSION = 9
};
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 1f32e50b67..85a07f0efc 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -123,13 +123,13 @@ void SegManager::createClassTable() {
error("SegManager: failed to open vocab 996");
int totalClasses = vocab996->size >> 2;
- _classTable.resize(totalClasses);
+ _classtable.resize(totalClasses);
for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2);
- _classTable[classNr].reg = NULL_REG;
- _classTable[classNr].script = scriptNr;
+ _classtable[classNr].reg = NULL_REG;
+ _classtable[classNr].script = scriptNr;
}
_resMan->unlockResource(vocab996);
@@ -139,11 +139,11 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller
if (classnr == 0xffff)
return NULL_REG;
- 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());
+ 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];
+ Class *the_class = &_classtable[classnr];
if (!the_class->reg.segment) {
getScriptSegment(the_class->script, lock);
@@ -175,7 +175,7 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
Script *scr = getScript(location.segment);
unsigned int count;
- VERIFY(location.offset + 1 < (uint16)scr->getBufSize(), "Locals beyond end of script\n");
+ VERIFY(location.offset + 1 < (uint16)scr->_bufSize, "Locals beyond end of script\n");
if (getSciVersion() >= SCI_VERSION_1_1)
count = READ_SCI11ENDIAN_UINT16(scr->_buf + location.offset - 2);
@@ -185,61 +185,81 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
scr->_localsOffset = location.offset;
- if (!(location.offset + count * 2 + 1 < scr->getBufSize())) {
- warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->getBufSize());
- count = (scr->getBufSize() - location.offset) >> 1;
+ if (!(location.offset + count * 2 + 1 < scr->_bufSize)) {
+ warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->_bufSize);
+ count = (scr->_bufSize - location.offset) >> 1;
}
LocalVariables *locals = allocLocalsSegment(scr, count);
if (locals) {
uint i;
- const byte *base = (const byte *)(scr->_buf + location.offset);
+ byte *base = (byte *)(scr->_buf + location.offset);
for (i = 0; i < count; i++)
locals->_locals[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(base + i * 2));
}
}
+void SegManager::scriptRelocateExportsSci11(SegmentId seg) {
+ Script *scr = getScript(seg);
+ for (int i = 0; i < scr->_numExports; i++) {
+ /* We are forced to use an ugly heuristic here to distinguish function
+ exports from object/class exports. The former kind points into the
+ script resource, the latter into the heap resource. */
+ uint16 location = READ_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i));
+
+ if ((location < scr->_heapSize - 1) && (READ_SCI11ENDIAN_UINT16(scr->_heapStart + location) == SCRIPT_OBJECT_MAGIC_NUMBER)) {
+ WRITE_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i), location + scr->_heapStart - scr->_buf);
+ } else {
+ // Otherwise it's probably a function export,
+ // and we don't need to do anything.
+ }
+ }
+}
+
void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
Script *scr = getScript(seg);
- const byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
+ byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- if (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass) { // -info- selector
+ if (READ_SCI11ENDIAN_UINT16(seeker + 14) & SCRIPT_INFO_CLASS) {
int classpos = seeker - scr->_buf;
int species = READ_SCI11ENDIAN_UINT16(seeker + 10);
- if (species < 0 || species >= (int)_classTable.size()) {
+ if (species < 0 || species >= (int)_classtable.size()) {
error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d",
- species, species, _classTable.size(), scr->_nr);
+ species, species, _classtable.size(), scr->_nr);
return;
}
- _classTable[species].reg.segment = seg;
- _classTable[species].reg.offset = classpos;
+ _classtable[species].reg.segment = seg;
+ _classtable[species].reg.offset = classpos;
}
seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * 2;
}
seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- reg_t reg = make_reg(seg, seeker - scr->_buf);
- Object *obj = scr->scriptObjInit(reg);
+ reg_t reg;
+ Object *obj;
+
+ reg.segment = seg;
+ reg.offset = seeker - scr->_buf;
+ obj = scr->scriptObjInit(reg);
+
+#if 0
+ if (obj->_variables[5].offset != 0xffff) {
+ obj->_variables[5] = INST_LOOKUP_CLASS(obj->_variables[5].offset);
+ baseObj = getObject(obj->_variables[5]);
+ obj->variable_names_nr = baseObj->variables_nr;
+ obj->_baseObj = baseObj->_baseObj;
+ }
+#endif
// Copy base from species class, as we need its selector IDs
obj->setSuperClassSelector(
getClassAddress(obj->getSuperClassSelector().offset, SCRIPT_GET_LOCK, NULL_REG));
- // If object is instance, get -propDict- from class and set it for this object
- // This is needed for ::isMemberOf() to work.
- // Example testcase - room 381 of sq4cd - if isMemberOf() doesn't work, talk-clicks on the robot will act like
- // clicking on ego
- if (!obj->isClass()) {
- reg_t classObject = obj->getSuperClassSelector();
- Object *classObj = getObject(classObject);
- obj->setPropDictSelector(classObj->getPropDictSelector());
- }
-
// Set the -classScript- selector to the script number.
// FIXME: As this selector is filled in at run-time, it is likely
// that it is supposed to hold a pointer. The Obj::isKindOf method
@@ -252,24 +272,90 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
}
}
-void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
+
+
+int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) {
+ *was_new = 1;
+
+ *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+
+ if (!*script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
+ warning("Script 0x%x requested but not found", script_nr);
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ if (*heap)
+ warning("Inconsistency: heap resource WAS found");
+ else if (*script)
+ warning("Inconsistency: script resource WAS found");
+ }
+ return 0;
+ }
+
+ SegmentId seg_id = segMan->getScriptSegment(script_nr);
+ Script *scr = segMan->getScriptIfLoaded(seg_id);
+ if (scr) {
+ if (!scr->isMarkedAsDeleted()) {
+ scr->incrementLockers();
+ return seg_id;
+ } else {
+ scr->freeScript();
+ }
+ } else {
+ scr = segMan->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;
+ }
+ }
+
+ scr->init(script_nr, resMan);
+
+ reg_t reg;
+ reg.segment = seg_id;
+ reg.offset = 0;
+
+ // Set heap position (beyond the size word)
+ scr->setLockers(1);
+ scr->setExportTableOffset(0);
+ scr->setSynonymsOffset(0);
+ scr->setSynonymsNr(0);
+
+ *was_new = 0;
+
+ return seg_id;
+}
+
+#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, addr))
+
+int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int script_nr) {
int objType;
uint32 objLength = 0;
+ int relocation = -1;
+ Resource *script;
+ int was_new;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+ const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, NULL, &was_new);
uint16 curOffset = oldScriptHeader ? 2 : 0;
+ if (was_new)
+ return seg_id;
+
+ Script *scr = segMan->getScript(seg_id);
+ scr->mcpyInOut(0, script->data, script->size);
+
if (oldScriptHeader) {
// Old script block
// There won't be a localvar block in this case
// Instead, the script starts with a 16 bit int specifying the
// number of locals we need; these are then allocated and zeroed.
- int localsCount = READ_LE_UINT16(scr->_buf);
- if (localsCount)
- segMan->scriptInitialiseLocalsZero(segmentId, localsCount);
+ int locals_nr = READ_LE_UINT16(script->data);
+ if (locals_nr)
+ segMan->scriptInitialiseLocalsZero(seg_id, locals_nr);
}
// Now do a first pass through the script objects to find the
- // local variable blocks
+ // export table and local variable block
do {
objType = scr->getHeap(curOffset);
@@ -277,30 +363,48 @@ void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
break;
objLength = scr->getHeap(curOffset + 2);
+
+ // This happens in some demos (e.g. the EcoQuest 1 demo). Not sure what is the
+ // actual cause of it, but the scripts of these demos can't be loaded properly
+ // and we're stuck forever in this loop, as objLength never changes
+ if (!objLength) {
+ warning("script_instantiate_sci0: objLength is 0, unable to parse script");
+ return 0;
+ }
+
curOffset += 4; // skip header
switch (objType) {
+ case SCI_OBJ_EXPORTS:
+ scr->setExportTableOffset(curOffset);
+ break;
+ case SCI_OBJ_SYNONYMS:
+ scr->setSynonymsOffset(curOffset);
+ scr->setSynonymsNr((objLength) / 4);
+ break;
case SCI_OBJ_LOCALVARS:
- segMan->scriptInitialiseLocals(make_reg(segmentId, curOffset));
+ segMan->scriptInitialiseLocals(make_reg(seg_id, curOffset));
break;
+
case SCI_OBJ_CLASS: {
int classpos = curOffset - SCRIPT_OBJECT_MAGIC_OFFSET;
int species = scr->getHeap(curOffset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET);
- if (species < 0 || species >= (int)segMan->classTableSize()) {
- if (species == (int)segMan->classTableSize()) {
+ if (species < 0 || species >= (int)segMan->_classtable.size()) {
+ if (species == (int)segMan->_classtable.size()) {
// Happens in the LSL2 demo
warning("Applying workaround for an off-by-one invalid species access");
- segMan->resizeClassTable(segMan->classTableSize() + 1);
+ segMan->_classtable.resize(segMan->_classtable.size() + 1);
} else {
- error("Invalid species %d(0x%x) not in interval "
- "[0,%d) while instantiating script at segment %d\n",
- species, species, segMan->classTableSize(),
- segmentId);
- return;
+ warning("Invalid species %d(0x%x) not in interval "
+ "[0,%d) while instantiating script %d\n",
+ species, species, segMan->_classtable.size(),
+ script_nr);
+ return 0;
}
}
- segMan->setClassOffset(species, make_reg(segmentId, classpos));
+ segMan->_classtable[species].reg.segment = seg_id;
+ segMan->_classtable[species].reg.offset = classpos;
// Set technical class position-- into the block allocated for it
}
break;
@@ -310,7 +414,7 @@ void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
}
curOffset += objLength - 4;
- } while (objType != 0 && curOffset < scr->getScriptSize() - 2);
+ } while (objType != 0 && curOffset < script->size - 2);
// And now a second pass to adjust objects and class pointers, and the general pointers
objLength = 0;
@@ -324,7 +428,7 @@ void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
objLength = scr->getHeap(curOffset + 2);
curOffset += 4; // skip header
- reg_t addr = make_reg(segmentId, curOffset);
+ reg_t addr = make_reg(seg_id, curOffset);
switch (objType) {
case SCI_OBJ_CODE:
@@ -333,61 +437,93 @@ void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
case SCI_OBJ_OBJECT:
case SCI_OBJ_CLASS: { // object or class?
Object *obj = scr->scriptObjInit(addr);
- obj->initSpecies(segMan, addr);
- if (!obj->initBaseObject(segMan, addr)) {
+ // Instantiate the superclass, if neccessary
+ obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset));
+
+ Object *baseObj = segMan->getObject(obj->getSpeciesSelector());
+
+ if (baseObj) {
+ obj->setVarCount(baseObj->getVarCount());
+ // Copy base from species class, as we need its selector IDs
+ obj->_baseObj = baseObj->_baseObj;
+
+ obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset));
+ } else {
warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
+
scr->scriptObjRemove(addr);
}
} // if object or class
break;
+ case SCI_OBJ_POINTERS: // A relocation table
+ relocation = addr.offset;
+ break;
+
default:
break;
}
curOffset += objLength - 4;
- } while (objType != 0 && curOffset < scr->getScriptSize() - 2);
+ } while (objType != 0 && curOffset < script->size - 2);
+
+ if (relocation >= 0)
+ scr->scriptRelocate(make_reg(seg_id, relocation));
+
+ return seg_id; // instantiation successful
}
-int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNum) {
- SegmentId segmentId = segMan->getScriptSegment(scriptNum);
- Script *scr = segMan->getScriptIfLoaded(segmentId);
- if (scr) {
- if (!scr->isMarkedAsDeleted()) {
- scr->incrementLockers();
- return segmentId;
- } else {
- scr->freeScript();
- }
- } else {
- scr = segMan->allocateScript(scriptNum, &segmentId);
- }
+int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) {
+ Resource *script, *heap;
+ int _heapStart;
+ reg_t reg;
+ int was_new;
- scr->init(scriptNum, resMan);
- scr->load(resMan);
+ const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new);
- if (getSciVersion() >= SCI_VERSION_1_1) {
- int heapStart = scr->getScriptSize();
- segMan->scriptInitialiseLocals(make_reg(segmentId, heapStart + 4));
- segMan->scriptInitialiseObjectsSci11(segmentId);
- scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart)));
- } else {
- script_instantiate_sci0(scr, segmentId, segMan);
- byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS);
- if (relocationBlock)
- scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4));
- }
+ if (was_new)
+ return seg_id;
+
+ Script *scr = segMan->getScript(seg_id);
+
+ _heapStart = script->size;
+ if (script->size & 2)
+ _heapStart++;
+
+ scr->mcpyInOut(0, script->data, script->size);
+ scr->mcpyInOut(_heapStart, heap->data, heap->size);
- return segmentId;
+ if (READ_SCI11ENDIAN_UINT16(script->data + 6) > 0)
+ scr->setExportTableOffset(6);
+
+ reg.segment = seg_id;
+ reg.offset = _heapStart + 4;
+ segMan->scriptInitialiseLocals(reg);
+
+ segMan->scriptRelocateExportsSci11(seg_id);
+ segMan->scriptInitialiseObjectsSci11(seg_id);
+
+ reg.offset = READ_SCI11ENDIAN_UINT16(heap->data);
+ scr->heapRelocate(reg);
+
+ return seg_id;
+}
+
+int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr) {
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ return script_instantiate_sci11(resMan, segMan, script_nr);
+ else
+ return script_instantiate_sci0(resMan, segMan, script_nr);
}
void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) {
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
reg_t reg = make_reg(seg, oldScriptHeader ? 2 : 0);
- int objType, objLength = 0;
+ int objType, objLength;
Script *scr = segMan->getScript(seg);
// Make a pass over the object in order uninstantiate all superclasses
+ objLength = 0;
do {
reg.offset += objLength; // Step over the last checked object
@@ -407,7 +543,7 @@ void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg)
superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass...
if (superclass >= 0) {
- int superclass_script = segMan->getClass(superclass).script;
+ int superclass_script = segMan->_classtable[superclass].script;
if (superclass_script == script_nr) {
if (scr->getLockers())
@@ -441,9 +577,9 @@ void script_uninstantiate(SegManager *segMan, int script_nr) {
return;
// Free all classtable references to this script
- for (uint i = 0; i < segMan->classTableSize(); i++)
- if (segMan->getClass(i).reg.segment == segment)
- segMan->setClassOffset(i, NULL_REG);
+ for (uint i = 0; i < segMan->_classtable.size(); i++)
+ if (segMan->_classtable[i].reg.segment == segment)
+ segMan->_classtable[i].reg = NULL_REG;
if (getSciVersion() < SCI_VERSION_1_1)
script_uninstantiate_sci0(segMan, script_nr, segment);
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 103a016972..4b60626b2e 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -67,6 +67,37 @@ extern const char *selector_name(EngineState *s, int selector);
DebugState g_debugState;
+int propertyOffsetToId(SegManager *segMan, int prop_ofs, reg_t objp) {
+ Object *obj = segMan->getObject(objp);
+ byte *selectoroffset;
+ int selectors;
+
+ if (!obj) {
+ warning("Applied propertyOffsetToId on non-object at %04x:%04x", PRINT_REG(objp));
+ return -1;
+ }
+
+ selectors = obj->getVarCount();
+
+ if (getSciVersion() < SCI_VERSION_1_1)
+ selectoroffset = ((byte *)(obj->_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2;
+ else {
+ if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS)) {
+ obj = segMan->getObject(obj->getSuperClassSelector());
+ selectoroffset = (byte *)obj->_baseVars;
+ } else
+ selectoroffset = (byte *)obj->_baseVars;
+ }
+
+ if (prop_ofs < 0 || (prop_ofs >> 1) >= selectors) {
+ warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d]) on object at %04x:%04x",
+ prop_ofs, prop_ofs >> 1, selectors - 1, PRINT_REG(objp));
+ return -1;
+ }
+
+ return READ_SCI11ENDIAN_UINT16(selectoroffset + prop_ofs);
+}
+
// Disassembles one command from the heap, returns address of next command or 0 if a ret was encountered.
reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecode) {
SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT);
@@ -85,7 +116,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
script_entity = (Script *)mobj;
scr = script_entity->_buf;
- scr_size = script_entity->getBufSize();
+ scr_size = script_entity->_bufSize;
if (pos.offset >= scr_size) {
warning("Trying to disassemble beyond end of script");
@@ -193,11 +224,10 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
if (pos == scriptState.xs->addr.pc) { // Extra information if debugging the current opcode
if ((opcode == op_pTos) || (opcode == op_sTop) || (opcode == op_pToa) || (opcode == op_aTop) ||
(opcode == op_dpToa) || (opcode == op_ipToa) || (opcode == op_dpTos) || (opcode == op_ipTos)) {
- const Object *obj = s->_segMan->getObject(scriptState.xs->objp);
- if (!obj)
- warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(scriptState.xs->objp));
- else
- printf(" (%s)", selector_name(s, obj->propertyOffsetToId(s->_segMan, scr[pos.offset + 1])));
+ int prop_ofs = scr[pos.offset + 1];
+ int prop_id = propertyOffsetToId(s->_segMan, prop_ofs, scriptState.xs->objp);
+
+ printf(" (%s)", selector_name(s, prop_id));
}
}
@@ -246,7 +276,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
printf(" %s::%s[", name, (selector > kernel->getSelectorNamesSize()) ? "<invalid>" : selector_name(s, selector));
- switch (lookupSelector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
+ switch (lookup_selector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
case kSelectorMethod:
printf("FUNCT");
argc += restmod;
@@ -303,7 +333,7 @@ void script_debug(EngineState *s) {
if (mobj) {
Script *scr = (Script *)mobj;
byte *code_buf = scr->_buf;
- int code_buf_size = scr->getBufSize();
+ int code_buf_size = scr->_bufSize;
int opcode = scriptState.xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset];
int op = opcode >> 1;
int paramb1 = scriptState.xs->addr.pc.offset + 1 >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset + 1];
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 4d3e6f754e..b18d76e1a7 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -54,6 +54,7 @@ SegManager::SegManager(ResourceManager *resMan) {
createClassTable();
}
+// Destroy the object, free the memorys if allocated before
SegManager::~SegManager() {
resetSegMan();
}
@@ -76,29 +77,10 @@ void SegManager::resetSegMan() {
Hunks_seg_id = 0;
// Reinitialize class table
- _classTable.clear();
+ _classtable.clear();
createClassTable();
}
-void SegManager::initSysStrings() {
- sysStrings = (SystemStrings *)allocSegment(new SystemStrings(), &sysStringsSegment);
-
- // Allocate static buffer for savegame and CWD directories
- SystemString *strSaveDir = &sysStrings->_strings[SYS_STRING_SAVEDIR];
- strSaveDir->_name = "savedir";
- strSaveDir->_maxSize = MAX_SAVE_DIR_SIZE;
- strSaveDir->_value = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
- // Set the savegame dir (actually, we set it to a fake value,
- // since we cannot let the game control where saves are stored)
- ::strcpy(strSaveDir->_value, "");
-
- // Allocate static buffer for the parser base
- SystemString *strParserBase = &sysStrings->_strings[SYS_STRING_PARSER_BASE];
- strParserBase->_name = "parser-base";
- strParserBase->_maxSize = MAX_PARSER_BASE;
- strParserBase->_value = (char *)calloc(MAX_PARSER_BASE, sizeof(char));
-}
-
SegmentId SegManager::findFreeSegment() const {
// FIXME: This is a very crude approach: We find a free segment id by scanning
// from the start. This can be slow if the number of segments becomes large.
@@ -174,7 +156,7 @@ int SegManager::deallocate(SegmentId seg, bool recursive) {
}
bool SegManager::isHeapObject(reg_t pos) {
- const Object *obj = getObject(pos);
+ Object *obj = getObject(pos);
if (obj == NULL || (obj && obj->isFreed()))
return false;
Script *scr = getScriptIfLoaded(pos.segment);
@@ -241,7 +223,7 @@ Object *SegManager::getObject(reg_t pos) {
warning("getObject(): Trying to get an invalid object");
} else if (mobj->getType() == SEG_TYPE_SCRIPT) {
Script *scr = (Script *)mobj;
- if (pos.offset <= scr->getBufSize() && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
+ if (pos.offset <= scr->_bufSize && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
&& RAW_IS_OBJECT(scr->_buf + pos.offset)) {
obj = scr->getObject(pos.offset);
}
@@ -252,7 +234,7 @@ Object *SegManager::getObject(reg_t pos) {
}
const char *SegManager::getObjectName(reg_t pos) {
- const Object *obj = getObject(pos);
+ Object *obj = getObject(pos);
if (!obj)
return "<no such object>";
@@ -293,7 +275,7 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) {
// It's a script or a clone table, scan all objects in it
for (; idx < max_index; ++idx) {
- const Object *obj = NULL;
+ Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
@@ -411,6 +393,10 @@ DataStack *SegManager::allocateStack(int size, SegmentId *segid) {
return retval;
}
+SystemStrings *SegManager::allocateSysStrings(SegmentId *segid) {
+ return (SystemStrings *)allocSegment(new SystemStrings(), segid);
+}
+
void SegManager::freeHunkEntry(reg_t addr) {
if (addr.isNull()) {
warning("Attempt to free a Hunk from a null address");
@@ -499,7 +485,7 @@ void SegManager::reconstructClones() {
continue;
CloneTable::Entry &seeker = ct->_table[j];
- const Object *baseObj = getObject(seeker.getSpeciesSelector());
+ Object *baseObj = getObject(seeker.getSpeciesSelector());
seeker.cloneFromObject(baseObj);
if (!baseObj)
warning("Clone entry without a base class: %d", j);
@@ -537,16 +523,6 @@ Node *SegManager::allocateNode(reg_t *addr) {
return &(table->_table[offset]);
}
-reg_t SegManager::newNode(reg_t value, reg_t key) {
- reg_t nodebase;
- Node *n = allocateNode(&nodebase);
- n->pred = n->succ = NULL_REG;
- n->key = key;
- n->value = value;
-
- return nodebase;
-}
-
List *SegManager::lookupList(reg_t addr) {
if (getSegmentType(addr.segment) != SEG_TYPE_LISTS) {
warning("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr));
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 9312f51f9d..e8bbdbdb3f 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -112,6 +112,12 @@ public:
SegmentId getScriptSegment(int script_nr, ScriptLoadType load);
// TODO: document this
+ reg_t lookupScriptExport(int script_nr, int export_index) {
+ SegmentId seg = getScriptSegment(script_nr, SCRIPT_GET_DONT_LOAD);
+ return make_reg(seg, getScript(seg)->validateExportFunc(export_index));
+ }
+
+ // TODO: document this
reg_t getClassAddress(int classnr, ScriptLoadType lock, reg_t caller);
/**
@@ -182,10 +188,15 @@ public:
// 5. System Strings
/**
- * Initializes the system string table.
+ * Allocates a system string table
+ * See also sys_string_acquire();
+ * @param[in] segid Segment ID of the stack
+ * @returns The physical stack
*/
- void initSysStrings();
+ SystemStrings *allocateSysStrings(SegmentId *segid);
+
+ // 5. System Strings
// 6, 7. Lists and Nodes
@@ -204,14 +215,6 @@ public:
Node *allocateNode(reg_t *addr);
/**
- * Allocate and initialize a new list node.
- * @param[in] value The value to set the node to
- * @param[in] key The key to set
- * @return Pointer to the newly initialized list node
- */
- reg_t newNode(reg_t value, reg_t key);
-
- /**
* Resolves a list pointer to a list.
* @param addr The address to resolve
* @return The list referenced, or NULL on error
@@ -429,22 +432,12 @@ public:
*/
reg_t findObjectByName(const Common::String &name, int index = -1);
+ void scriptRelocateExportsSci11(SegmentId seg);
void scriptInitialiseObjectsSci11(SegmentId seg);
- uint32 classTableSize() { return _classTable.size(); }
- Class getClass(int index) { return _classTable[index]; }
- void setClassOffset(int index, reg_t offset) { _classTable[index].reg = offset; }
- void resizeClassTable(uint32 size) { _classTable.resize(size); }
-
- /**
- * Obtains the system strings segment ID
- */
- SegmentId getSysStringsSegment() { return sysStringsSegment; }
-
public: // TODO: make private
Common::Array<SegmentObj *> _heap;
- // Only accessible from saveLoadWithSerializer()
- Common::Array<Class> _classTable; /**< Table of all classes */
+ Common::Array<Class> _classtable; /**< Table of all classes */
#ifdef ENABLE_SCI32
SciArray<reg_t> *allocateArray(reg_t *addr);
@@ -467,13 +460,6 @@ private:
SegmentId Nodes_seg_id; ///< ID of the (a) node segment
SegmentId Hunks_seg_id; ///< ID of the (a) hunk segment
- /* System strings */
- SegmentId sysStringsSegment;
-public: // TODO: make private. Only kString() needs direct access
- SystemStrings *sysStrings;
-
-private:
-
#ifdef ENABLE_SCI32
SegmentId Arrays_seg_id;
SegmentId String_seg_id;
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index 0e0a759d4b..ab1a68d165 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -27,7 +27,6 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
-#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
#include "sci/engine/segment.h"
#include "sci/engine/seg_manager.h"
#include "sci/engine/state.h"
@@ -101,7 +100,8 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) {
_localsSegment = 0;
_localsBlock = NULL;
- _markedAsDeleted = false;
+ _relocated = false;
+ _markedAsDeleted = 0;
}
Script::~Script() {
@@ -117,39 +117,54 @@ void Script::freeScript() {
_codeBlocks.clear();
}
-void Script::init(int script_nr, ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+bool Script::init(int script_nr, ResourceManager *resMan) {
+ setScriptSize(script_nr, resMan);
+
+ _buf = (byte *)malloc(_bufSize);
+
+ if (!_buf) {
+ freeScript();
+ warning("Not enough memory space for script size");
+ _bufSize = 0;
+ return false;
+ }
_localsOffset = 0;
_localsBlock = NULL;
_codeBlocks.clear();
+ _relocated = false;
_markedAsDeleted = false;
_nr = script_nr;
- _buf = 0;
- _heapStart = 0;
+
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ _heapStart = _buf + _scriptSize;
+ else
+ _heapStart = _buf;
+
+ return true;
+}
+
+void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
_scriptSize = script->size;
- _bufSize = script->size;
- _heapSize = 0;
+ _heapSize = 0; // Set later
- _lockers = 1;
-
- if (getSciVersion() == SCI_VERSION_0_EARLY) {
- _bufSize += READ_LE_UINT16(script->data) * 2;
- } else if (getSciVersion() >= SCI_VERSION_1_1) {
- /**
- * In SCI11, the heap was in a separate space from the script.
- * We append it to the end of the script, and adjust addressing accordingly.
- * However, since we address the heap with a 16-bit pointer, the combined
- * size of the stack and the heap must be 64KB. So far this has worked
- * for SCI11, SCI2 and SCI21 games. SCI3 games use a different script format,
- * and theoretically they can exceed the 64KB boundary using relocation.
- */
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
- _bufSize += heap->size;
+ if (!script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
+ error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap");
+ }
+ if (oldScriptHeader) {
+ _bufSize = script->size + READ_LE_UINT16(script->data) * 2;
+ //locals_size = READ_LE_UINT16(script->data) * 2;
+ } else if (getSciVersion() < SCI_VERSION_1_1) {
+ _bufSize = script->size;
+ } else {
+ _bufSize = script->size + heap->size;
_heapSize = heap->size;
// Ensure that the start of the heap resource can be word-aligned.
@@ -158,56 +173,12 @@ void Script::init(int script_nr, ResourceManager *resMan) {
_scriptSize++;
}
- // As mentioned above, the script and the heap together should not exceed 64KB
- if (_bufSize > 65535)
- error("Script and heap sizes combined exceed 64K. This means a fundamental "
- "design bug was made regarding SCI1.1 and newer games.\nPlease "
- "report this error to the ScummVM team");
- }
-}
-
-void Script::load(ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
- assert(script != 0);
-
- _buf = (byte *)malloc(_bufSize);
- assert(_buf);
-
- assert(_bufSize >= script->size);
- memcpy(_buf, script->data, script->size);
-
- if (getSciVersion() >= SCI_VERSION_1_1) {
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
- assert(heap != 0);
-
- _heapStart = _buf + _scriptSize;
-
- assert(_bufSize - _scriptSize <= heap->size);
- memcpy(_heapStart, heap->data, heap->size);
- }
-
- _codeBlocks.clear();
-
- _exportTable = 0;
- _numExports = 0;
- _synonyms = 0;
- _numSynonyms = 0;
-
- if (getSciVersion() >= SCI_VERSION_1_1) {
- if (READ_LE_UINT16(_buf + 1 + 5) > 0) {
- _exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
- _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
- }
- } else {
- _exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
- if (_exportTable) {
- _numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
- _exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer)
- }
- _synonyms = findBlock(SCI_OBJ_SYNONYMS);
- if (_synonyms) {
- _numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
- _synonyms += 4; // skip header
+ if (_bufSize > 65535) {
+ error("Script and heap sizes combined exceed 64K."
+ "This means a fundamental design bug was made in SCI\n"
+ "regarding SCI1.1 games.\nPlease report this so it can be"
+ "fixed in the next major version");
+ return;
}
}
}
@@ -223,26 +194,19 @@ Object *Script::getObject(uint16 offset) {
return 0;
}
-const Object *Script::getObject(uint16 offset) const {
- if (_objects.contains(offset))
- return &_objects[offset];
- else
- return 0;
-}
-
-Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
+Object *Script::scriptObjInit(reg_t obj_pos) {
Object *obj;
- if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
+ if (getSciVersion() < SCI_VERSION_1_1)
obj_pos.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
obj = allocateObject(obj_pos.offset);
- VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
+ VERIFY(obj_pos.offset + SCRIPT_FUNCTAREAPTR_OFFSET < (int)_bufSize, "Function area pointer stored beyond end of script\n");
- obj->init(_buf, obj_pos, fullObjectInit);
+ obj->init(_buf, obj_pos);
return obj;
}
@@ -254,34 +218,37 @@ void Script::scriptObjRemove(reg_t obj_pos) {
_objects.erase(obj_pos.toUint16());
}
-// This helper function is used by Script::relocateLocal and Object::relocate
-static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) {
+int Script::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) {
int rel = location - block_location;
if (rel < 0)
- return false;
+ return 0;
uint idx = rel >> 1;
if (idx >= block.size())
- return false;
+ return 0;
if (rel & 1) {
warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location);
- return false;
+ return 0;
}
block[idx].segment = segment; // Perform relocation
if (getSciVersion() >= SCI_VERSION_1_1)
- block[idx].offset += scriptSize;
+ block[idx].offset += _scriptSize;
- return true;
+ return 1;
}
-bool Script::relocateLocal(SegmentId segment, int location) {
+int Script::relocateLocal(SegmentId segment, int location) {
if (_localsBlock)
- return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
+ return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location);
else
- return false;
+ return 0; // No hands, no cookies
+}
+
+int Script::relocateObject(Object &obj, SegmentId segment, int location) {
+ return relocateBlock(obj._variables, obj.getPos().offset, segment, location);
}
void Script::scriptAddCodeBlock(reg_t location) {
@@ -291,35 +258,61 @@ void Script::scriptAddCodeBlock(reg_t location) {
_codeBlocks.push_back(cb);
}
-void Script::relocate(reg_t block) {
- byte *heap = _buf;
- uint16 heapSize = (uint16)_bufSize;
- uint16 heapOffset = 0;
+void Script::scriptRelocate(reg_t block) {
+ VERIFY(block.offset < (uint16)_bufSize && READ_SCI11ENDIAN_UINT16(_buf + block.offset) * 2 + block.offset < (uint16)_bufSize,
+ "Relocation block outside of script\n");
+
+ int count = READ_SCI11ENDIAN_UINT16(_buf + block.offset);
+
+ for (int i = 0; i <= count; i++) {
+ int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2));
+ if (!pos)
+ continue; // FIXME: A hack pending investigation
+
+ if (!relocateLocal(block.segment, pos)) {
+ bool done = false;
+ uint k;
+
+ ObjMap::iterator it;
+ const ObjMap::iterator end = _objects.end();
+ for (it = _objects.begin(); !done && it != end; ++it) {
+ if (relocateObject(it->_value, block.segment, pos))
+ done = true;
+ }
+
+ for (k = 0; !done && k < _codeBlocks.size(); k++) {
+ if (pos >= _codeBlocks[k].pos.offset &&
+ pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
+ done = true;
+ }
- if (getSciVersion() >= SCI_VERSION_1_1) {
- heap = _heapStart;
- heapSize = (uint16)_heapSize;
- heapOffset = _scriptSize;
+ if (!done) {
+ printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
+ printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
+ if (_localsBlock)
+ printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
+ else
+ printf("- No locals\n");
+ for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
+ printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
+ // SQ3 script 71 has broken relocation entries.
+ printf("Trying to continue anyway...\n");
+ }
+ }
}
+}
- VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
+void Script::heapRelocate(reg_t block) {
+ VERIFY(block.offset < (uint16)_heapSize && READ_SCI11ENDIAN_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize,
"Relocation block outside of script\n");
- int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
- int exportIndex = 0;
+ if (_relocated)
+ return;
+ _relocated = true;
+ int count = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset);
for (int i = 0; i < count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
- // This occurs in SCI01/SCI1 games where every usually one export
- // value is zero. It seems that in this situation, we should skip
- // the export and move to the next one, though the total count
- // of valid exports remains the same
- if (!pos) {
- exportIndex++;
- pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
- if (!pos)
- error("Script::relocate(): Consecutive zero exports found");
- }
+ int pos = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset + 2 + (i * 2)) + _scriptSize;
if (!relocateLocal(block.segment, pos)) {
bool done = false;
@@ -328,33 +321,22 @@ void Script::relocate(reg_t block) {
ObjMap::iterator it;
const ObjMap::iterator end = _objects.end();
for (it = _objects.begin(); !done && it != end; ++it) {
- if (it->_value.relocate(block.segment, pos, _scriptSize))
+ if (relocateObject(it->_value, block.segment, pos))
done = true;
}
- // Sanity check for SCI0-SCI1
- if (getSciVersion() < SCI_VERSION_1_1) {
- for (k = 0; !done && k < _codeBlocks.size(); k++) {
- if (pos >= _codeBlocks[k].pos.offset &&
- pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
- done = true;
- }
- }
-
if (!done) {
- debug("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- debug("Relocation failed for index %04x (%d/%d)\n", pos, exportIndex + 1, count);
+ printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
+ printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
if (_localsBlock)
- debug("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
+ printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
else
- debug("- No locals\n");
+ printf("- No locals\n");
for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- debug("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- debug("Trying to continue anyway...\n");
+ printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
+ error("Breakpoint in %s, line %d", __FILE__, __LINE__);
}
}
-
- exportIndex++;
}
}
@@ -375,6 +357,16 @@ void Script::setLockers(int lockers) {
_lockers = lockers;
}
+void Script::setExportTableOffset(int offset) {
+ if (offset) {
+ _exportTable = (uint16 *)(_buf + offset + 2);
+ _numExports = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable - 1));
+ } else {
+ _exportTable = NULL;
+ _numExports = 0;
+ }
+}
+
uint16 Script::validateExportFunc(int pubfunct) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
@@ -385,35 +377,27 @@ uint16 Script::validateExportFunc(int pubfunct) {
if (exportsAreWide)
pubfunct *= 2;
- uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
+ uint16 offset = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable + pubfunct));
VERIFY(offset < _bufSize, "invalid export function pointer");
return offset;
}
-byte *Script::findBlock(int type) {
- byte *buf = _buf;
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-
- if (oldScriptHeader)
- buf += 2;
-
- do {
- int seekerType = READ_LE_UINT16(buf);
-
- if (seekerType == 0)
- break;
- if (seekerType == type)
- return buf;
+void Script::setSynonymsOffset(int offset) {
+ _synonyms = _buf + offset;
+}
- int seekerSize = READ_LE_UINT16(buf + 2);
- assert(seekerSize > 0);
- buf += seekerSize;
- } while (1);
+byte *Script::getSynonyms() const {
+ return _synonyms;
+}
- return NULL;
+void Script::setSynonymsNr(int n) {
+ _numSynonyms = n;
}
+int Script::getSynonymsNr() const {
+ return _numSynonyms;
+}
// memory operations
@@ -527,7 +511,7 @@ SegmentRef SystemStrings::dereference(reg_t pointer) {
//-------------------- script --------------------
-reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) const {
+reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) {
addr.offset = 0;
return addr;
}
@@ -543,13 +527,13 @@ void Script::freeAtAddress(SegManager *segMan, reg_t addr) {
segMan->deallocateScript(_nr);
}
-void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
+void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
(*note)(param, make_reg(segId, 0));
}
-void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
if (addr.offset <= _bufSize && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(_buf + addr.offset)) {
- const Object *obj = getObject(addr.offset);
+ Object *obj = getObject(addr.offset);
if (obj) {
// Note all local variables, if we have a local variable environment
if (_localsSegment)
@@ -569,14 +553,16 @@ void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback not
//-------------------- clones --------------------
-void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+ Clone *clone;
+
// assert(addr.segment == _segId);
if (!isValidEntry(addr.offset)) {
error("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
}
- const Clone *clone = &(_table[addr.offset]);
+ clone = &(_table[addr.offset]);
// Emit all member variables (including references to the 'super' delegate)
for (uint i = 0; i < clone->getVarCount(); i++)
@@ -611,7 +597,7 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
//-------------------- locals --------------------
-reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
+reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
// Reference the owning script
SegmentId owner_seg = segMan->getScriptSegment(script_id);
@@ -620,7 +606,7 @@ reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
return make_reg(owner_seg, 0);
}
-void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
// assert(addr.segment == _segId);
for (uint i = 0; i < _locals.size(); i++)
@@ -629,12 +615,12 @@ void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCall
//-------------------- stack --------------------
-reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
+reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) {
addr.offset = 0;
return addr;
}
-void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
fprintf(stderr, "Emitting %d stack entries\n", _capacity);
for (int i = 0; i < _capacity; i++)
(*note)(param, _entries[i]);
@@ -647,13 +633,13 @@ void ListTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
if (!isValidEntry(addr.offset)) {
warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- const List *list = &(_table[addr.offset]);
+ List *list = &(_table[addr.offset]);
note(param, list->first);
note(param, list->last);
@@ -667,12 +653,12 @@ void NodeTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
if (!isValidEntry(addr.offset)) {
warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- const Node *node = &(_table[addr.offset]);
+ Node *node = &(_table[addr.offset]);
// We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us
// to walk around from any given node
@@ -687,43 +673,20 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
//-------------------- object ----------------------------
-void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
- byte *data = buf + obj_pos.offset;
- _baseObj = data;
- _pos = obj_pos;
-
- if (getSciVersion() < SCI_VERSION_1_1) {
- _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter));
- _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2);
- _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea));
- _methodCount = READ_LE_UINT16(_baseMethod - 1);
- } else {
- _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
- _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
- _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6));
- _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod);
- }
-
- if (initVariables) {
- for (uint i = 0; i < _variables.size(); i++)
- _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
- }
-}
-
-const Object *Object::getClass(SegManager *segMan) const {
+Object *Object::getClass(SegManager *segMan) {
return isClass() ? this : segMan->getObject(getSuperClassSelector());
}
-int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
- const byte *buf;
+int Object::locateVarSelector(SegManager *segMan, Selector slc) {
+ byte *buf;
uint varnum;
if (getSciVersion() < SCI_VERSION_1_1) {
varnum = getVarCount();
- int selector_name_offset = varnum * 2 + kOffsetSelectorSegment;
+ int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET;
buf = _baseObj + selector_name_offset;
} else {
- const Object *obj = getClass(segMan);
+ Object *obj = getClass(segMan);
varnum = obj->getVariable(1).toUint16();
buf = (byte *)obj->_baseVars;
}
@@ -735,72 +698,14 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
return -1; // Failed
}
-bool Object::relocate(SegmentId segment, int location, size_t scriptSize) {
- return relocateBlock(_variables, getPos().offset, segment, location, scriptSize);
-}
-
-int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const {
- int selectors = getVarCount();
-
- if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) {
- warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d])",
- propertyOffset, propertyOffset >> 1, selectors - 1);
- return -1;
- }
-
- if (getSciVersion() < SCI_VERSION_1_1) {
- const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2;
- return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset);
- } else {
- const Object *obj = this;
- if (!isClass())
- obj = segMan->getObject(getSuperClassSelector());
-
- return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset);
- }
-}
-
-void Object::initSpecies(SegManager *segMan, reg_t addr) {
- uint16 speciesOffset = getSpeciesSelector().offset;
-
- if (speciesOffset == 0xffff) // -1
- setSpeciesSelector(NULL_REG); // no species
- else
- setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr));
-}
-
-void Object::initSuperClass(SegManager *segMan, reg_t addr) {
- uint16 superClassOffset = getSuperClassSelector().offset;
-
- if (superClassOffset == 0xffff) // -1
- setSuperClassSelector(NULL_REG); // no superclass
- else
- setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr));
-}
-
-bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) {
- const Object *baseObj = segMan->getObject(getSpeciesSelector());
-
- if (baseObj) {
- _variables.resize(baseObj->getVarCount());
- // Copy base from species class, as we need its selector IDs
- _baseObj = baseObj->_baseObj;
- if (doInitSuperClass)
- initSuperClass(segMan, addr);
- return true;
- }
-
- return false;
-}
-
//-------------------- dynamic memory --------------------
-reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const {
+reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) {
addr.offset = 0;
return addr;
}
-void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
+void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
(*note)(param, make_reg(segId, 0));
}
@@ -819,13 +724,13 @@ void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
if (!isValidEntry(addr.offset)) {
warning("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- const SciArray<reg_t> *array = &(_table[addr.offset]);
+ SciArray<reg_t> *array = &(_table[addr.offset]);
for (uint32 i = 0; i < array->getSize(); i++) {
reg_t value = array->getValue(i);
@@ -834,7 +739,7 @@ void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
}
}
-Common::String SciString::toString() const {
+Common::String SciString::toString() {
if (_type != 3)
error("SciString::toString(): Array is not a string");
@@ -845,7 +750,7 @@ Common::String SciString::toString() const {
return string;
}
-void SciString::fromString(const Common::String &string) {
+void SciString::fromString(Common::String string) {
if (_type != 3)
error("SciString::fromString(): Array is not a string");
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index f1b6dccaa2..1089ada475 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -112,7 +112,7 @@ public:
*
* @param sub_addr base address whose canonic address is to be found
*/
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const { return sub_addr; }
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) { return sub_addr; }
/**
* Deallocates all memory associated with the specified address.
@@ -125,7 +125,7 @@ public:
* @param note Invoked for each address on which free_at_address() makes sense
* @param param parameter passed to 'note'
*/
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {}
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {}
/**
* Iterates over all references reachable from the specified object.
@@ -134,7 +134,7 @@ public:
* @param note Invoked for each outgoing reference within the object
* Note: This function may also choose to report numbers (segment 0) as adresses
*/
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const {}
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) {}
};
@@ -194,8 +194,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -205,22 +205,6 @@ enum {
OBJECT_FLAG_FREED = (1 << 0)
};
-enum infoSelectorFlags {
- kInfoFlagClone = 0x0001,
- kInfoFlagClass = 0x8000
-};
-
-enum ObjectOffsets {
- kOffsetLocalVariables = -6,
- kOffsetFunctionArea = -4,
- kOffsetSelectorCounter = -2,
- kOffsetSelectorSegment = 0,
- kOffsetInfoSelectorSci0 = 4,
- kOffsetNamePointerSci0 = 6,
- kOffsetInfoSelectorSci11 = 14,
- kOffsetNamePointerSci11 = 16
-};
-
class Object {
public:
Object() {
@@ -230,34 +214,31 @@ public:
~Object() { }
- reg_t getSpeciesSelector() const { return _variables[_offset]; }
+ reg_t getSpeciesSelector() { return _variables[_offset]; }
void setSpeciesSelector(reg_t value) { _variables[_offset] = value; }
- reg_t getSuperClassSelector() const { return _variables[_offset + 1]; }
+ reg_t getSuperClassSelector() { return _variables[_offset + 1]; }
void setSuperClassSelector(reg_t value) { _variables[_offset + 1] = value; }
- reg_t getInfoSelector() const { return _variables[_offset + 2]; }
- void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
+ reg_t getInfoSelector() { return _variables[_offset + 2]; }
+ void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
- reg_t getNameSelector() const { return _variables[_offset + 3]; }
- void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
+ reg_t getNameSelector() { return _variables[_offset + 3]; }
+ void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
- reg_t getPropDictSelector() const { return _variables[2]; }
- void setPropDictSelector(reg_t value) { _variables[2] = value; }
-
- reg_t getClassScriptSelector() const { return _variables[4]; }
+ reg_t getClassScriptSelector() { return _variables[4]; }
void setClassScriptSelector(reg_t value) { _variables[4] = value; }
- Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
+ Selector getVarSelector(uint16 i) { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
- reg_t getFunction(uint16 i) const {
+ reg_t getFunction(uint16 i) {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2;
- return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16(_baseMethod + offset));
+ return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16((byte *) (_baseMethod + offset)));
}
- Selector getFuncSelector(uint16 i) const {
+ Selector getFuncSelector(uint16 i) {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1;
- return READ_SCI11ENDIAN_UINT16(_baseMethod + offset);
+ return READ_SCI11ENDIAN_UINT16((byte *) (_baseMethod + offset));
}
/**
@@ -266,7 +247,7 @@ public:
* superclasses, i.e. failure may be returned even if one of the
* superclasses defines the funcselector
*/
- int funcSelectorPosition(Selector sel) const {
+ int funcSelectorPosition(Selector sel) {
for (uint i = 0; i < _methodCount; i++)
if (getFuncSelector(i) == sel)
return i;
@@ -275,56 +256,61 @@ public:
}
/**
- * Determines if the object explicitly defines slc as a varselector.
- * Returns -1 if not found.
+ * Determines if the object explicitly defines slc as a varselector
+ * Returns -1 if not found
*/
- int locateVarSelector(SegManager *segMan, Selector slc) const;
-
- bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); }
- const Object *getClass(SegManager *segMan) const;
+ int locateVarSelector(SegManager *segMan, Selector slc);
- void markAsClone() { setInfoSelector(make_reg(0, kInfoFlagClone)); }
- bool isClone() const { return (getInfoSelector().offset & kInfoFlagClone); }
+ bool isClass() { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); }
+ Object *getClass(SegManager *segMan);
void markAsFreed() { _flags |= OBJECT_FLAG_FREED; }
- bool isFreed() const { return _flags & OBJECT_FLAG_FREED; }
+ bool isFreed() { return _flags & OBJECT_FLAG_FREED; }
+
+ void setVarCount(uint size) { _variables.resize(size); }
+ uint getVarCount() { return _variables.size(); }
- uint getVarCount() const { return _variables.size(); }
+ void init(byte *buf, reg_t obj_pos) {
+ byte *data = (byte *)(buf + obj_pos.offset);
+ _baseObj = data;
+ _pos = obj_pos;
- void init(byte *buf, reg_t obj_pos, bool initVariables = true);
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ _variables.resize(READ_LE_UINT16(data + SCRIPT_SELECTORCTR_OFFSET));
+ _baseVars = (uint16 *)(_baseObj + _variables.size() * 2);
+ _baseMethod = (uint16 *)(data + READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET));
+ _methodCount = READ_LE_UINT16(_baseMethod - 1);
+ } else {
+ _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
+ _baseVars = (uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
+ _baseMethod = (uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6));
+ _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod);
+ }
+
+ for (uint i = 0; i < _variables.size(); i++)
+ _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
+ }
- reg_t getVariable(uint var) const { return _variables[var]; }
- reg_t &getVariableRef(uint var) { return _variables[var]; }
+ reg_t getVariable(uint var) { return _variables[var]; }
- uint16 getMethodCount() const { return _methodCount; }
- reg_t getPos() const { return _pos; }
+ uint16 getMethodCount() { return _methodCount; }
+ reg_t getPos() { return _pos; }
void saveLoadWithSerializer(Common::Serializer &ser);
- void cloneFromObject(const Object *obj) {
+ void cloneFromObject(Object *obj) {
_baseObj = obj ? obj->_baseObj : NULL;
_baseMethod = obj ? obj->_baseMethod : NULL;
_baseVars = obj ? obj->_baseVars : NULL;
}
- bool relocate(SegmentId segment, int location, size_t scriptSize);
-
- int propertyOffsetToId(SegManager *segMan, int propertyOffset) const;
-
- void initSpecies(SegManager *segMan, reg_t addr);
- void initSuperClass(SegManager *segMan, reg_t addr);
- bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true);
-
// TODO: make private
- // Only SegManager::reconstructScripts() is left needing direct access to these
-public:
- const byte *_baseObj; /**< base + object offset within base */
+ Common::Array<reg_t> _variables;
+ byte *_baseObj; /**< base + object offset within base */
+ uint16 *_baseVars; /**< Pointer to the varselector area for this object */
+ uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
private:
- const uint16 *_baseVars; /**< Pointer to the varselector area for this object */
- const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
-
- Common::Array<reg_t> _variables;
uint16 _methodCount;
int _flags;
uint16 _offset;
@@ -342,27 +328,20 @@ class Script : public SegmentObj {
public:
int _nr; /**< Script number */
byte *_buf; /**< Static data buffer, or NULL if not used */
- byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
-
- uint32 getScriptSize() { return _scriptSize; }
- uint32 getHeapSize() { return _heapSize; }
- uint32 getBufSize() { return _bufSize; }
-
-protected:
- int _lockers; /**< Number of classes and objects that require this script */
-
-private:
+ size_t _bufSize;
size_t _scriptSize;
size_t _heapSize;
- size_t _bufSize;
- const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
- uint16 _numExports; /**< Number of entries in the exports table */
+ byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
- const byte *_synonyms; /**< Synonyms block or 0 if not present*/
- uint16 _numSynonyms; /**< Number of entries in the synonyms block */
+ uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
+ int _numExports; /**< Number of entries in the exports table */
- Common::Array<CodeBlock> _codeBlocks;
+ byte *_synonyms; /**< Synonyms block or 0 if not present*/
+ int _numSynonyms; /**< Number of entries in the synonyms block */
+
+protected:
+ int _lockers; /**< Number of classes and objects that require this script */
public:
/**
@@ -375,6 +354,8 @@ public:
SegmentId _localsSegment; /**< The local variable segment */
LocalVariables *_localsBlock;
+ Common::Array<CodeBlock> _codeBlocks;
+ bool _relocated;
bool _markedAsDeleted;
public:
@@ -382,21 +363,19 @@ public:
~Script();
void freeScript();
- void init(int script_nr, ResourceManager *resMan);
- void load(ResourceManager *resMan);
+ bool init(int script_nr, ResourceManager *resMan);
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
Object *allocateObject(uint16 offset);
Object *getObject(uint16 offset);
- const Object *getObject(uint16 offset) const;
/**
* Informs the segment manager that a code block must be relocated
@@ -413,7 +392,7 @@ public:
* @returns A newly created Object describing the object,
* stored within the relevant script
*/
- Object *scriptObjInit(reg_t obj_pos, bool fullObjectInit = true);
+ Object *scriptObjInit(reg_t obj_pos);
/**
* Removes a script object
@@ -428,10 +407,14 @@ public:
* @param obj_pos Location (segment, offset) of the block
* @return Location of the relocation block
*/
- void relocate(reg_t block);
+ void scriptRelocate(reg_t block);
+
+ void heapRelocate(reg_t block);
private:
- bool relocateLocal(SegmentId segment, int location);
+ int relocateLocal(SegmentId segment, int location);
+ int relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location);
+ int relocateObject(Object &obj, SegmentId segment, int location);
public:
// script lock operations
@@ -452,28 +435,22 @@ public:
void setLockers(int lockers);
/**
- * Retrieves a pointer to the exports of this script
- * @return pointer to the exports.
- */
- const uint16 *getExportTable() const { return _exportTable; }
-
- /**
- * Retrieves the number of exports of script.
- * @return the number of exports of this script
- */
- uint16 getExportsNr() const { return _numExports; }
-
- /**
* Retrieves a pointer to the synonyms associated with this script
* @return pointer to the synonyms, in non-parsed format.
*/
- const byte *getSynonyms() const { return _synonyms; }
+ byte *getSynonyms() const;
/**
* Retrieves the number of synonyms associated with this script.
* @return the number of synonyms associated with this script
*/
- uint16 getSynonymsNr() const { return _numSynonyms; }
+ int getSynonymsNr() const;
+
+ /**
+ * Sets the script-relative offset of the exports table.
+ * @param offset script-relative exports table offset
+ */
+ void setExportTableOffset(int offset);
/**
* Validate whether the specified public function is exported by
@@ -485,6 +462,19 @@ public:
uint16 validateExportFunc(int pubfunct);
/**
+ * Sets the script-relative offset of the synonyms associated with this script.
+ * @param offset script-relative offset of the synonyms block
+ */
+ void setSynonymsOffset(int offset);
+
+ /**
+ * Sets the number of synonyms associated with this script,
+ * @param nr number of synonyms, as to be stored within the script
+ */
+ void setSynonymsNr(int nr);
+
+
+ /**
* Marks the script as deleted.
* This will not actually delete the script. If references remain present on the
* heap or the stack, the script will stay in memory in a quasi-deleted state until
@@ -518,10 +508,8 @@ public:
*/
int16 getHeap(uint16 offset) const;
- /**
- * Finds the pointer where a block of a specific type starts from
- */
- byte *findBlock(int type);
+private:
+ void setScriptSize(int script_nr, ResourceManager *resMan);
};
/** Data stack */
@@ -541,8 +529,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -630,7 +618,7 @@ public:
entries_used--;
}
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
for (uint i = 0; i < _table.size(); i++)
if (isValidEntry(i))
(*note)(param, make_reg(segId, i));
@@ -643,7 +631,7 @@ struct CloneTable : public Table<Clone> {
CloneTable() : Table<Clone>(SEG_TYPE_CLONES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -654,7 +642,7 @@ struct NodeTable : public Table<Node> {
NodeTable() : Table<Node>(SEG_TYPE_NODES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -665,7 +653,7 @@ struct ListTable : public Table<List> {
ListTable() : Table<List>(SEG_TYPE_LISTS) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -700,8 +688,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -794,7 +782,7 @@ public:
_size = _actualSize = size;
}
- T getValue(uint16 index) const {
+ T getValue(uint16 index) {
if (index >= _size)
error("SciArray::getValue(): %d is out of bounds (%d)", index, _size);
@@ -808,8 +796,8 @@ public:
_data[index] = value;
}
- byte getType() const { return _type; }
- uint32 getSize() const { return _size; }
+ byte getType() { return _type; }
+ uint32 getSize() { return _size; }
T *getRawData() { return _data; }
protected:
@@ -826,15 +814,15 @@ public:
// We overload destroy to ensure the string type is 3 after destroying
void destroy() { SciArray<char>::destroy(); _type = 3; }
- Common::String toString() const;
- void fromString(const Common::String &string);
+ Common::String toString();
+ void fromString(Common::String string);
};
struct ArrayTable : public Table<SciArray<reg_t> > {
ArrayTable() : Table<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
void saveLoadWithSerializer(Common::Serializer &ser);
SegmentRef dereference(reg_t pointer);
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index 04a1b8fbba..e226c4b574 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -153,11 +153,11 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(subtitleLang);
FIND_SELECTOR(parseLang);
FIND_SELECTOR(overlay);
+ FIND_SELECTOR(setCursor);
FIND_SELECTOR(topString);
FIND_SELECTOR(scaleSignal);
FIND_SELECTOR(scaleX);
FIND_SELECTOR(scaleY);
- FIND_SELECTOR(iconIndex);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
@@ -175,32 +175,32 @@ void Kernel::mapSelectors() {
#endif
}
-reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
+reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id) {
ObjVarRef address;
- if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
+ if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable)
return NULL_REG;
else
return *address.getPointer(segMan);
}
-void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value) {
+void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value) {
ObjVarRef address;
- if ((selectorId < 0) || (selectorId > (int)g_sci->getKernel()->getSelectorNamesSize())) {
+ if ((selector_id < 0) || (selector_id > (int)g_sci->getKernel()->getSelectorNamesSize())) {
warning("Attempt to write to invalid selector %d of"
- " object at %04x:%04x.", selectorId, PRINT_REG(object));
+ " object at %04x:%04x.", selector_id, PRINT_REG(object));
return;
}
- if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
+ if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable)
warning("Selector '%s' of object at %04x:%04x could not be"
- " written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
+ " written to", g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
else
*address.getPointer(segMan) = value;
}
-int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
+int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
int k_argc, StackPtr k_argp, int argc, const reg_t *argv) {
int i;
int framesize = 2 + 1 * argc;
@@ -208,21 +208,21 @@ int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInv
int slc_type;
StackPtr stackframe = k_argp + k_argc;
- stackframe[0] = make_reg(0, selectorId); // The selector we want to call
+ stackframe[0] = make_reg(0, selector_id); // The selector we want to call
stackframe[1] = make_reg(0, argc); // Argument count
- slc_type = lookupSelector(s->_segMan, object, selectorId, NULL, &address);
+ slc_type = lookup_selector(s->_segMan, object, selector_id, NULL, &address);
if (slc_type == kSelectorNone) {
warning("Selector '%s' of object at %04x:%04x could not be invoked",
- g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
+ g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
if (noinvalid == kStopOnInvalidSelector)
error("[Kernel] Not recoverable: VM was halted");
return 1;
}
if (slc_type == kSelectorVariable) {
warning("Attempting to invoke variable selector %s of object %04x:%04x",
- g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
+ g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
return 0;
}
@@ -242,7 +242,7 @@ int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInv
return 0;
}
-int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
+int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
int k_argc, StackPtr k_argp, int argc, ...) {
va_list argp;
reg_t *args = new reg_t[argc];
@@ -252,28 +252,28 @@ int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocat
args[i] = va_arg(argp, reg_t);
va_end(argp);
- int retval = invokeSelectorArgv(s, object, selectorId, noinvalid, k_argc, k_argp, argc, args);
+ int retval = invoke_selector_argv(s, object, selector_id, noinvalid, k_argc, k_argp, argc, args);
delete[] args;
return retval;
}
-SelectorType lookupSelector(SegManager *segMan, reg_t obj_location, Selector selectorId, ObjVarRef *varp, reg_t *fptr) {
- const Object *obj = segMan->getObject(obj_location);
+SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) {
+ Object *obj = segMan->getObject(obj_location);
int index;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
// Early SCI versions used the LSB in the selector ID as a read/write
// toggle, meaning that we must remove it for selector lookup.
if (oldScriptHeader)
- selectorId &= ~1;
+ selector_id &= ~1;
if (!obj) {
- error("lookupSelector(): Attempt to send to non-object or invalid script. Address was %04x:%04x",
+ error("lookup_selector(): Attempt to send to non-object or invalid script. Address was %04x:%04x",
PRINT_REG(obj_location));
}
- index = obj->locateVarSelector(segMan, selectorId);
+ index = obj->locateVarSelector(segMan, selector_id);
if (index >= 0) {
// Found it as a variable
@@ -285,7 +285,7 @@ SelectorType lookupSelector(SegManager *segMan, reg_t obj_location, Selector sel
} else {
// Check if it's a method, with recursive lookup in superclasses
while (obj) {
- index = obj->funcSelectorPosition(selectorId);
+ index = obj->funcSelectorPosition(selector_id);
if (index >= 0) {
if (fptr)
*fptr = obj->getFunction(index);
@@ -300,7 +300,7 @@ SelectorType lookupSelector(SegManager *segMan, reg_t obj_location, Selector sel
}
-// return _lookupSelector_function(segMan, obj, selectorId, fptr);
+// return _lookup_selector_function(segMan, obj, selector_id, fptr);
}
} // End of namespace Sci
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index f50b9ab1b3..70eeb34d93 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -34,15 +34,20 @@
namespace Sci {
+
+/******************** Selector functionality ********************/
+
enum SelectorInvocation {
kStopOnInvalidSelector = 0,
kContinueOnInvalidSelector = 1
};
+
/**
* Map a selector name to a selector id. Shortcut for accessing the selector cache.
*/
#define SELECTOR(_slc_) (g_sci->getKernel()->_selectorCache._slc_)
+//#define SELECTOR(_slc_) _slc_
/**
* Retrieves a selector from an object.
@@ -53,8 +58,8 @@ enum SelectorInvocation {
* This macro halts on error. 'selector' must be a selector name registered in vm.h's
* SelectorCache and mapped in script.cpp.
*/
-reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId);
-#define readSelectorValue(segMan, _obj_, _slc_) (readSelector(segMan, _obj_, _slc_).offset)
+#define GET_SEL32(segMan, _obj_, _slc_) read_selector(segMan, _obj_, _slc_)
+#define GET_SEL32V(segMan, _obj_, _slc_) (GET_SEL32(segMan, _obj_, _slc_).offset)
/**
* Writes a selector value to an object.
@@ -65,25 +70,27 @@ reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId);
* This macro halts on error. 'selector' must be a selector name registered in vm.h's
* SelectorCache and mapped in script.cpp.
*/
-void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value);
-#define writeSelectorValue(segMan, _obj_, _slc_, _val_) writeSelector(segMan, _obj_, _slc_, make_reg(0, _val_))
+#define PUT_SEL32(segMan, _obj_, _slc_, _val_) write_selector(segMan, _obj_, _slc_, _val_)
+#define PUT_SEL32V(segMan, _obj_, _slc_, _val_) PUT_SEL32(segMan, _obj_, _slc_, make_reg(0, _val_))
-/**
- * Invokes a selector from an object.
- */
-int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
- int k_argc, StackPtr k_argp, int argc, ...);
-int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
- int k_argc, StackPtr k_argp, int argc, const reg_t *argv);
/**
- * Kludge for use with invokeSelector(). Used for compatibility with compilers
+ * Kludge for use with invoke_selector(). Used for compatibility with compilers
* that cannot handle vararg macros.
*/
#define INV_SEL(s, _object_, _selector_, _noinvalid_) \
s, _object_, g_sci->getKernel()->_selectorCache._selector_, _noinvalid_, argc, argv
+reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id);
+void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value);
+int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
+ int k_argc, StackPtr k_argp, int argc, ...);
+int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
+ int k_argc, StackPtr k_argp, int argc, const reg_t *argv);
+
+
+
} // End of namespace Sci
#endif // SCI_ENGINE_KERNEL_H
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index b642cd8dc9..bd78639c77 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -69,52 +69,51 @@ static const uint16 s_halfWidthSJISMap[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-EngineState::EngineState(SegManager *segMan)
-: _segMan(segMan), _dirseeker() {
+EngineState::EngineState(Vocabulary *voc, SegManager *segMan)
+: _voc(voc), _segMan(segMan), _dirseeker() {
- reset(false);
-}
-
-EngineState::~EngineState() {
- delete _msgState;
-}
-
-void EngineState::reset(bool isRestoring) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
sfx_init_flags = 0;
#endif
- if (!isRestoring) {
- script_000 = 0;
- _gameObj = NULL_REG;
+ restarting_flags = 0;
- _memorySegmentSize = 0;
- _soundCmd = 0;
+ last_wait_time = 0;
- restarting_flags = 0;
+ _fileHandles.resize(5);
- execution_stack_base = 0;
- _executionStackPosChanged = false;
+ execution_stack_base = 0;
+ _executionStackPosChanged = false;
- _fileHandles.resize(5);
+ r_acc = NULL_REG;
+ restAdjust = 0;
+ r_prev = NULL_REG;
- r_acc = NULL_REG;
- restAdjust = 0;
- r_prev = NULL_REG;
+ stack_base = 0;
+ stack_top = 0;
- stack_base = 0;
- stack_top = 0;
- }
+ script_000 = 0;
- last_wait_time = 0;
+ sys_strings_segment = 0;
+ sys_strings = 0;
+
+ _gameObj = NULL_REG;
gc_countdown = 0;
+ successor = 0;
+
_throttleCounter = 0;
_throttleLastTime = 0;
_throttleTrigger = false;
- restoring = false;
+ _memorySegmentSize = 0;
+
+ _soundCmd = 0;
+}
+
+EngineState::~EngineState() {
+ delete _msgState;
}
void EngineState::wait(int16 ticks) {
@@ -136,15 +135,6 @@ void EngineState::setRoomNumber(uint16 roomNumber) {
script_000->_localsBlock->_locals[13] = make_reg(0, roomNumber);
}
-void EngineState::shrinkStackToBase() {
- uint size = execution_stack_base + 1;
- assert(_executionStack.size() >= size);
- Common::List<ExecStack>::iterator iter = _executionStack.begin();
- for (uint i = 0; i < size; ++i)
- ++iter;
- _executionStack.erase(iter, _executionStack.end());
-}
-
static kLanguage charToLanguage(const char c) {
switch (c) {
case 'F':
@@ -228,7 +218,7 @@ kLanguage SciEngine::getSciLanguage() {
lang = K_LANG_ENGLISH;
if (_kernel->_selectorCache.printLang != -1) {
- lang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));
+ lang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));
if ((getSciVersion() >= SCI_VERSION_1_1) || (lang == K_LANG_NONE)) {
// If language is set to none, we use the language from the game detector.
@@ -263,7 +253,7 @@ kLanguage SciEngine::getSciLanguage() {
}
// Store language in printLang selector
- writeSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
+ PUT_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
}
}
@@ -275,7 +265,7 @@ Common::String SciEngine::strSplit(const char *str, const char *sep) {
kLanguage subLang = K_LANG_NONE;
if (_kernel->_selectorCache.subtitleLang != -1) {
- subLang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
+ subLang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
}
kLanguage secondLang;
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 431aac884e..c4b995806f 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -76,7 +76,8 @@ enum {
enum {
SCI_GAME_IS_NOT_RESTARTING = 0,
SCI_GAME_WAS_RESTARTED = 1,
- SCI_GAME_IS_RESTARTING_NOW = 2
+ SCI_GAME_IS_RESTARTING_NOW = 2,
+ SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE = 4
};
class FileHandle {
@@ -95,13 +96,16 @@ public:
struct EngineState : public Common::Serializable {
public:
- EngineState(SegManager *segMan);
+ EngineState(Vocabulary *voc, SegManager *segMan);
virtual ~EngineState();
virtual void saveLoadWithSerializer(Common::Serializer &ser);
public:
SegManager *_segMan; /**< The segment manager */
+ Vocabulary *_voc;
+
+ Common::String _gameId; /**< Designation of the primary object (which inherits from Game) */
/* Non-VM information */
@@ -153,11 +157,9 @@ public:
uint16 currentRoomNumber() const;
void setRoomNumber(uint16 roomNumber);
- /**
- * Shrink execution stack to size.
- * Contains an assert it is not already smaller.
- */
- void shrinkStackToBase();
+ /* System strings */
+ SegmentId sys_strings_segment;
+ SystemStrings *sys_strings;
reg_t _gameObj; /**< Pointer to the game object */
@@ -174,12 +176,7 @@ public:
uint _memorySegmentSize;
byte _memorySegment[kMemorySegmentMax];
- /**
- * Resets the engine state.
- */
- void reset(bool isRestoring);
-
- bool restoring; /**< A flag to indicate if a game is being restored */
+ EngineState *successor; /**< Successor of this state: Used for restoring */
};
} // End of namespace Sci
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 36f5ec6893..e2ee2e1971 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -120,7 +120,7 @@ static reg_t &validate_property(Object *obj, int index) {
return dummyReg;
}
- return obj->getVariableRef(index);
+ return obj->_variables[index];
}
static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) {
@@ -212,7 +212,7 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
if (!stopGroopPos.isNull()) { // does the game have a stopGroop object?
// Find the "client" member variable of the stopGroop object, and update it
ObjVarRef varp;
- if (lookupSelector(segMan, stopGroopPos, kernel->_selectorCache.client, &varp, NULL) == kSelectorVariable) {
+ if (lookup_selector(segMan, stopGroopPos, kernel->_selectorCache.client, &varp, NULL) == kSelectorVariable) {
reg_t *clientVar = varp.getPointer(segMan);
*clientVar = value;
}
@@ -341,7 +341,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
int selector;
int argc;
int origin = s->_executionStack.size()-1; // Origin: Used for debugging
- bool printSendActions = false;
+ int print_send_action = 0;
// We return a pointer to the new active ExecStack
// The selector calls we catch are stored below:
@@ -370,7 +370,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
if (bp->type == BREAK_SELECTOR && !strncmp(bp->name.c_str(), method_name, cmplen)) {
Console *con = g_sci->getSciDebugger();
con->DebugPrintf("Break on %s (in [%04x:%04x])\n", method_name, PRINT_REG(send_obj));
- printSendActions = true;
+ print_send_action = 1;
g_debugState.debugging = true;
g_debugState.breakpointWasHit = true;
break;
@@ -383,7 +383,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#endif // VM_DEBUG_SEND
ObjVarRef varp;
- switch (lookupSelector(s->_segMan, send_obj, selector, &varp, &funcp)) {
+ switch (lookup_selector(s->_segMan, send_obj, selector, &varp, &funcp)) {
case kSelectorNone:
error("Send to invalid selector 0x%x of object at %04x:%04x", 0xffff & selector, PRINT_REG(send_obj));
break;
@@ -398,34 +398,22 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#endif // VM_DEBUG_SEND
// argc == 0: read selector
- // argc != 0: write selector
- if (printSendActions && !argc) { // read selector
- debug("[read selector]\n");
- printSendActions = false;
+ // argc == 1: write selector
+ // argc > 1: write selector?
+ if (print_send_action && argc == 0) { // read selector
+ printf("[read selector]\n");
+ print_send_action = 0;
}
- if (printSendActions && argc) {
+ if (print_send_action && argc > 0) {
reg_t oldReg = *varp.getPointer(s->_segMan);
reg_t newReg = argp[1];
- debug("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg));
- printSendActions = false;
+ printf("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg));
+ print_send_action = 0;
}
- if (argc > 1) {
- // argc can indeed be bigger than 1 in some cases, and it seems correct
- // (i.e. we should skip that many bytes later on)... question is, why
- // does this occur? Could such calls be used to point to data after X
- // bytes in the heap? What are the skipped bytes in this case?
- // In SQ4CD, this occurs with the returnVal selector of object
- // Sq4GlobalNarrator when the game starts, and right after the narrator
- // is heard (e.g. after he talks when examining something)
- reg_t oldReg = *varp.getPointer(s->_segMan);
- reg_t newReg = argp[1];
- warning("send_selector(): argc = %d while modifying variable selector "
- "%x (%s) of object %04x:%04x (%s) from %04x:%04x to %04x:%04x",
- argc, selector, g_sci->getKernel()->getSelectorName(selector).c_str(), PRINT_REG(send_obj),
- s->_segMan->getObjectName(send_obj), PRINT_REG(oldReg), PRINT_REG(newReg));
- }
+ if (argc > 1)
+ warning("send_selector(): more than 1 parameter (%d) while modifying a variable selector", argc);
{
CallsStruct call;
@@ -450,9 +438,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
printf(") at %04x:%04x\n", PRINT_REG(funcp));
#endif // VM_DEBUG_SEND
- if (printSendActions) {
- debug("[invoke selector]\n");
- printSendActions = false;
+ if (print_send_action) {
+ printf("[invoke selector]\n");
+ print_send_action = 0;
}
{
@@ -468,7 +456,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
break;
- } // switch (lookupSelector())
+ } // switch (lookup_selector())
framesize -= (2 + argc);
argp += argc + 1;
@@ -489,7 +477,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
_exec_varselectors(s);
- return s->_executionStack.empty() ? NULL : &(s->_executionStack.back());
+ if (s->_executionStack.empty())
+ return NULL;
+ return &(s->_executionStack.back());
}
static ExecStack *add_exec_stack_varselector(Common::List<ExecStack> &execStack, reg_t objp, int argc, StackPtr argp, Selector selector, const ObjVarRef& address, int origin) {
@@ -593,26 +583,19 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
//warning("callk %s", kernelFunc.orig_name.c_str());
- // TODO: SCI2.1 equivalent
- if (g_loadFromLauncher >= 0 && (
- (kernelFuncNum == 0x8 && getSciVersion() <= SCI_VERSION_1_1) || // DrawPic
- (kernelFuncNum == 0x3d && getSciVersion() == SCI_VERSION_2) // GetSaveDir
- //(kernelFuncNum == 0x28 && getSciVersion() == SCI_VERSION_2_1) // AddPlane
- )) {
-
- // A game is being loaded from the launcher, and the game is about to draw something on
- // screen, hence all initialization has taken place (i.e. menus have been constructed etc).
- // Therefore, inject a kRestoreGame call here, instead of the requested function.
- // The restore call is injected here mainly for games which have a menu, as the menu is
- // constructed when the game starts and is not reconstructed when a saved game is loaded.
- int saveSlot = g_loadFromLauncher;
- g_loadFromLauncher = -1; // invalidate slot, so that we don't load again
-
- if (saveSlot < 0)
- error("Requested to load invalid save slot"); // should never happen, really
-
- reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
- kRestoreGame(s, 2, restoreArgv);
+ // TODO: SCI2/SCI2.1+ equivalent, once saving/loading works in SCI2/SCI2.1+
+ if (g_loadFromLauncher >= 0 && kernelFuncNum == 0x8) {
+ // A game is being loaded from the launcher, and kDisplay is called, all initialization has taken
+ // place (i.e. menus have been constructed etc). Therefore, inject a kRestoreGame call
+ // here, instead of the requested function.
+ int saveSlot = g_loadFromLauncher;
+ g_loadFromLauncher = -1; // invalidate slot, so that we don't load again
+
+ if (saveSlot < 0)
+ error("Requested to load invalid save slot"); // should never happen, really
+
+ reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
+ kRestoreGame(s, 2, restoreArgv);
} else {
// Call kernel function
s->r_acc = kernelFunc.fun(s, argc, argv);
@@ -741,7 +724,7 @@ void run_vm(EngineState *s, bool restoring) {
}
if (!restoring)
- s->execution_stack_base = s->_executionStack.size() - 1;
+ s->execution_stack_base = s->_executionStack.size()-1;
#ifndef DISABLE_VALIDATIONS
// Initialize maximum variable count
@@ -791,7 +774,7 @@ void run_vm(EngineState *s, bool restoring) {
obj = s->_segMan->getObject(scriptState.xs->objp);
code_buf = scr->_buf;
#ifndef DISABLE_VALIDATIONS
- code_buf_size = scr->getBufSize();
+ code_buf_size = scr->_bufSize;
#endif
local_script = s->_segMan->getScriptIfLoaded(scriptState.xs->local_segment);
if (!local_script) {
@@ -839,14 +822,12 @@ void run_vm(EngineState *s, bool restoring) {
#ifndef DISABLE_VALIDATIONS
if (scriptState.xs->sp < scriptState.xs->fp)
- error("run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x",
- PRINT_REG(*scriptState.xs->sp), PRINT_REG(*scriptState.xs->fp));
+ error("run_vm(): stack underflow");
scriptState.variables_max[VAR_TEMP] = scriptState.xs->sp - scriptState.xs->fp;
if (scriptState.xs->addr.pc.offset >= code_buf_size)
- error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d",
- scriptState.xs->addr.pc.offset, code_buf_size);
+ error("run_vm(): program counter gone astray");
#endif
// Get opcode
@@ -1202,7 +1183,7 @@ void run_vm(EngineState *s, bool restoring) {
StackPtr old_fp = scriptState.xs->fp;
ExecStack *old_xs = &(s->_executionStack.back());
- if ((int)s->_executionStack.size() - 1 == s->execution_stack_base) { // Have we reached the base?
+ if ((int)s->_executionStack.size()-1 == s->execution_stack_base) { // Have we reached the base?
s->execution_stack_base = old_execution_stack_base; // Restore stack base
s->_executionStack.pop_back();
@@ -1405,7 +1386,7 @@ void run_vm(EngineState *s, bool restoring) {
switch (g_sci->_features->detectLofsType()) {
case SCI_VERSION_1_1:
- s->r_acc.offset = opparams[0] + local_script->getScriptSize();
+ s->r_acc.offset = opparams[0] + local_script->_scriptSize;
break;
case SCI_VERSION_1_MIDDLE:
s->r_acc.offset = opparams[0];
@@ -1427,7 +1408,7 @@ void run_vm(EngineState *s, bool restoring) {
switch (g_sci->_features->detectLofsType()) {
case SCI_VERSION_1_1:
- r_temp.offset = opparams[0] + local_script->getScriptSize();
+ r_temp.offset = opparams[0] + local_script->_scriptSize;
break;
case SCI_VERSION_1_MIDDLE:
r_temp.offset = opparams[0];
@@ -1695,16 +1676,17 @@ static void _init_stack_base_with_selector(EngineState *s, Selector selector) {
}
static EngineState *_game_run(EngineState *&s) {
- bool restoring = false;
+ EngineState *successor = NULL;
+ int game_is_finished = 0;
if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup))
g_sci->getSciDebugger()->attach();
do {
s->_executionStackPosChanged = false;
- run_vm(s, restoring);
+ run_vm(s, successor ? true : false);
if (s->restarting_flags & SCI_GAME_IS_RESTARTING_NOW) { // Restart was requested?
- restoring = false;
+ successor = NULL;
s->_executionStack.clear();
s->_executionStackPosChanged = false;
@@ -1719,13 +1701,15 @@ static EngineState *_game_run(EngineState *&s) {
send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base);
script_abort_flag = 0;
- s->restarting_flags = SCI_GAME_WAS_RESTARTED;
+ s->restarting_flags = SCI_GAME_WAS_RESTARTED | SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
} else {
- restoring = s->restoring;
- if (restoring) {
+ successor = s->successor;
+ if (successor) {
game_exit(s);
- s->restoring = false;
+ delete s;
+ s = successor;
+
if (script_abort_flag == 2) {
debugC(2, kDebugLevelVM, "Restarting with replay()");
s->_executionStack.clear(); // Restart with replay
@@ -1738,9 +1722,9 @@ static EngineState *_game_run(EngineState *&s) {
script_abort_flag = 0;
} else
- break; // exit loop
+ game_is_finished = 1;
}
- } while (true);
+ } while (!game_is_finished);
return s;
}
@@ -1748,7 +1732,7 @@ static EngineState *_game_run(EngineState *&s) {
int game_run(EngineState **_s) {
EngineState *s = *_s;
- debugC(2, kDebugLevelVM, "Calling %s::play()", g_sci->getGameID());
+ debugC(2, kDebugLevelVM, "Calling %s::play()", s->_gameId.c_str());
_init_stack_base_with_selector(s, g_sci->getKernel()->_selectorCache.play); // Call the play selector
// Now: Register the first element on the execution stack-
@@ -1772,12 +1756,22 @@ void quit_vm() {
g_debugState.runningStep = 0;
}
-reg_t *ObjVarRef::getPointer(SegManager *segMan) const {
+void shrink_execution_stack(EngineState *s, uint size) {
+ assert(s->_executionStack.size() >= size);
+ Common::List<ExecStack>::iterator iter;
+ iter = s->_executionStack.begin();
+ for (uint i = 0; i < size; ++i)
+ ++iter;
+ s->_executionStack.erase(iter, s->_executionStack.end());
+}
+
+reg_t* ObjVarRef::getPointer(SegManager *segMan) const {
Object *o = segMan->getObject(obj);
- return o ? &o->getVariableRef(varindex) : 0;
+ if (!o) return 0;
+ return &(o->_variables[varindex]);
}
-reg_t *ExecStack::getVarPointer(SegManager *segMan) const {
+reg_t* ExecStack::getVarPointer(SegManager *segMan) const {
assert(type == EXEC_STACK_TYPE_VARSELECTOR);
return addr.varp.getPointer(segMan);
}
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index 42ee55cd06..8e40fed818 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -43,9 +43,44 @@ class ResourceManager;
/** Number of bytes to be allocated for the stack */
#define VM_STACK_SIZE 0x1000
+/** Maximum number of calls residing on the stack */
+#define SCRIPT_MAX_EXEC_STACK 256
+/** Maximum number of entries in the class table */
+#define SCRIPT_MAX_CLASSTABLE_SIZE 256
+/** Maximum number of cloned objects on the heap */
+#define SCRIPT_MAX_CLONES 256
+
+
+/** Object-relative offset of the selector area inside a script */
+#define SCRIPT_SELECTOR_OFFSET 8 -8
+
+/** Object-relative offset of the pointer to the underlying script's local variables */
+#define SCRIPT_LOCALVARPTR_OFFSET 2 -8
+
+/** Object-relative offset of the selector counter */
+#define SCRIPT_SELECTORCTR_OFFSET 6 -8
+
+/** Object-relative offset of the offset of the function area */
+#define SCRIPT_FUNCTAREAPTR_OFFSET 4 -8
+
+/** Offset that has to be added to the function area pointer */
+#define SCRIPT_FUNCTAREAPTR_MAGIC 8 -8
+
+/** Offset of the name pointer */
+#define SCRIPT_NAME_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 14 -8 : 16)
+
+/** Object-relative offset of the -info- selector */
+#define SCRIPT_INFO_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 12 -8 : 14)
+
+/** Flag fo the -info- selector */
+#define SCRIPT_INFO_CLONE 0x0001
+
+/** Flag for the -info- selector */
+#define SCRIPT_INFO_CLASS 0x8000
+
+
/** Magical object identifier */
#define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234
-
/** Offset of this identifier */
#define SCRIPT_OBJECT_MAGIC_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? -8 : 0)
@@ -54,10 +89,13 @@ class ResourceManager;
#define SCRIPT_SUPERCLASS_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 10 -8 : 12)
+/** Magic adjustment value for lofsa and lofss */
+#define SCRIPT_LOFS_MAGIC 3
+
/** Stack pointer value: Use predecessor's value */
#define CALL_SP_CARRY NULL
-/** Types of selectors as returned by lookupSelector() below. */
+/** Types of selectors as returned by lookup_selector() below. */
enum SelectorType {
kSelectorNone = 0,
kSelectorVariable,
@@ -157,9 +195,7 @@ struct SelectorCache {
// Used for auto detection purposes
Selector overlay; ///< Used to determine if a game is using old gfx functions or not
-
- // SCI1.1 Mac icon bar selectors
- Selector iconIndex; ///< Used to index icon bar objects
+ Selector setCursor; ///< For cursor semantics autodetection
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()
@@ -340,7 +376,7 @@ int script_init_engine(EngineState *);
* kSelectorMethod if the selector represents a
* method
*/
-SelectorType lookupSelector(SegManager *segMan, reg_t obj, Selector selectorid,
+SelectorType lookup_selector(SegManager *segMan, reg_t obj, Selector selectorid,
ObjVarRef *varp, reg_t *fptr);
/**
@@ -433,6 +469,12 @@ int game_exit(EngineState *s);
void quit_vm();
/**
+ * Shrink execution stack to size.
+ * Contains an assert it is not already smaller.
+ */
+void shrink_execution_stack(EngineState *s, uint size);
+
+/**
* Read a PMachine instruction from a memory buffer and return its length.
*
* @param[in] src address from which to start parsing
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index c3be22b143..53f4675f56 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -319,6 +319,8 @@ sciEvent SciEvent::get(unsigned int mask) {
//sci_event_t error_event = { SCI_EVT_ERROR, 0, 0, 0 };
sciEvent event = { 0, 0, 0, 0 };
+ // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position
+
// Update the screen here, since it's called very often
g_system->updateScreen();
@@ -387,6 +389,7 @@ void SciEvent::sleep(uint32 msecs) {
while (true) {
// let backend process events and update the screen
get(SCI_EVENT_PEEK);
+ // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position
time = g_system->getMillis();
if (time + 10 < wakeup_time) {
g_system->delayMillis(10);
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index c201b2cfb7..71c7b7dd7f 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -92,10 +92,10 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
}
}
- signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
+ signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
if (!(signal & kSignalFrozen)) {
// Call .doit method of that object
- invokeSelector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
+ invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
// Lookup node again, since the nodetable it was in may have been reallocated
curNode = _s->_segMan->lookupNode(curAddress);
}
@@ -109,15 +109,7 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
}
bool sortHelper(const AnimateEntry* entry1, const AnimateEntry* entry2) {
- if (entry1->y == entry2->y) {
- // if both y and z are the same, use the order we were given originally
- // this is needed for special cases like iceman room 35
- if (entry1->z == entry2->z)
- return entry1->givenOrderNo < entry2->givenOrderNo;
- else
- return entry1->z < entry2->z;
- }
- return entry1->y < entry2->y;
+ return (entry1->y == entry2->y) ? (entry1->z < entry2->z) : (entry1->y < entry2->y);
}
void GfxAnimate::makeSortedList(List *list) {
@@ -164,22 +156,21 @@ void GfxAnimate::makeSortedList(List *list) {
listEntry->object = curObject;
// Get data from current object
- listEntry->givenOrderNo = listNr;
- listEntry->viewId = readSelectorValue(_s->_segMan, curObject, SELECTOR(view));
- listEntry->loopNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(loop));
- listEntry->celNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(cel));
- listEntry->paletteNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(palette));
- listEntry->x = readSelectorValue(_s->_segMan, curObject, SELECTOR(x));
- listEntry->y = readSelectorValue(_s->_segMan, curObject, SELECTOR(y));
- listEntry->z = readSelectorValue(_s->_segMan, curObject, SELECTOR(z));
- listEntry->priority = readSelectorValue(_s->_segMan, curObject, SELECTOR(priority));
- listEntry->signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
+ listEntry->viewId = GET_SEL32V(_s->_segMan, curObject, SELECTOR(view));
+ listEntry->loopNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(loop));
+ listEntry->celNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(cel));
+ listEntry->paletteNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(palette));
+ listEntry->x = GET_SEL32V(_s->_segMan, curObject, SELECTOR(x));
+ listEntry->y = GET_SEL32V(_s->_segMan, curObject, SELECTOR(y));
+ listEntry->z = GET_SEL32V(_s->_segMan, curObject, SELECTOR(z));
+ listEntry->priority = GET_SEL32V(_s->_segMan, curObject, SELECTOR(priority));
+ listEntry->signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
if (getSciVersion() >= SCI_VERSION_1_1) {
// Cel scaling
- listEntry->scaleSignal = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleSignal));
+ listEntry->scaleSignal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleSignal));
if (listEntry->scaleSignal & kScaleSignalDoScaling) {
- listEntry->scaleX = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX));
- listEntry->scaleY = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY));
+ listEntry->scaleX = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleX));
+ listEntry->scaleY = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleY));
} else {
listEntry->scaleX = 128;
listEntry->scaleY = 128;
@@ -228,11 +219,11 @@ void GfxAnimate::fill(byte &old_picNotValid) {
// adjust loop and cel, if any of those is invalid
if (listEntry->loopNo >= view->getLoopCount()) {
listEntry->loopNo = 0;
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
}
if (listEntry->celNo >= view->getCelCount(listEntry->loopNo)) {
listEntry->celNo = 0;
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
}
// Create rect according to coordinates and given cel
@@ -241,17 +232,17 @@ void GfxAnimate::fill(byte &old_picNotValid) {
} else {
view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect);
}
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
signal = listEntry->signal;
// Calculate current priority according to y-coordinate
if (!(signal & kSignalFixedPriority)) {
listEntry->priority = _ports->kernelCoordinateToPriority(listEntry->y);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
}
if (signal & kSignalNoUpdate) {
@@ -291,14 +282,14 @@ void GfxAnimate::update() {
if (signal & kSignalNoUpdate) {
if (!(signal & kSignalRemoveView)) {
- bitsHandle = readSelector(_s->_segMan, curObject, SELECTOR(underBits));
+ bitsHandle = GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits));
if (_screen->_picNotValid != 1) {
_paint16->bitsRestore(bitsHandle);
listEntry->showBitsFlag = true;
} else {
_paint16->bitsFree(bitsHandle);
}
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
signal &= 0xFFFF ^ kSignalForceUpdate;
signal &= signal & kSignalViewUpdated ? 0xFFFF ^ (kSignalViewUpdated | kSignalNoUpdate) : 0xFFFF;
@@ -348,7 +339,7 @@ void GfxAnimate::update() {
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
else
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
}
listEntry->signal = signal;
}
@@ -396,7 +387,7 @@ void GfxAnimate::drawCels() {
if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) {
// Save background
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
// draw corresponding cel
_paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo, listEntry->scaleX, listEntry->scaleY);
@@ -432,10 +423,10 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
if (listEntry->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) ||
(!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) {
- lsRect.left = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft));
- lsRect.top = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop));
- lsRect.right = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight));
- lsRect.bottom = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom));
+ lsRect.left = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft));
+ lsRect.top = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop));
+ lsRect.right = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight));
+ lsRect.bottom = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom));
workerRect = lsRect;
workerRect.clip(listEntry->celRect);
@@ -447,10 +438,10 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
_paint16->bitsShow(lsRect);
workerRect = listEntry->celRect;
}
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
_paint16->bitsShow(workerRect);
if (signal & kSignalHidden) {
@@ -481,7 +472,7 @@ void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
signal = listEntry->signal;
// Finally update signal
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(signal), signal);
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(signal), signal);
listIterator++;
}
@@ -490,16 +481,16 @@ void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
listEntry = *listIterator;
curObject = listEntry->object;
// We read out signal here again, this is not by accident but to ensure that we got an up-to-date signal
- signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
+ signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) {
- _paint16->bitsRestore(readSelector(_s->_segMan, curObject, SELECTOR(underBits)));
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ _paint16->bitsRestore(GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits)));
+ PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
if (signal & kSignalDisposeMe) {
// Call .delete_ method of that object
- invokeSelector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
+ invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
}
listIterator--;
}
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 706b7182cf..2cc59b1767 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -40,7 +40,7 @@ enum ViewSignals {
kSignalAlwaysUpdate = 0x0020,
kSignalForceUpdate = 0x0040,
kSignalRemoveView = 0x0080,
- kSignalFrozen = 0x0100, // I got frozen today!!
+ kSignalFrozen = 0x0100,
kSignalExtraActor = 0x0200, // unused by us, defines all actors that may be included into the background if speed is too slow
kSignalHitObstacle = 0x0400, // used in the actor movement code by kDoBresen()
kSignalDoesntTurn = 0x0800, // used by _k_dirloop() to determine if an actor can turn or not
@@ -57,7 +57,6 @@ enum ViewScaleSignals {
};
struct AnimateEntry {
- int16 givenOrderNo;
reg_t object;
GuiResourceId viewId;
int16 loopNo;
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 3102edc2fa..36dd2d4aed 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -79,12 +79,12 @@ bool GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect &c
while (curNode) {
curObject = curNode->value;
if (curObject != checkObject) {
- signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
+ signal = GET_SEL32V(_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate)) == 0) {
- curRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
- curRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
- curRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
- curRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
+ curRect.left = GET_SEL32V(_segMan, curObject, SELECTOR(brLeft));
+ curRect.top = GET_SEL32V(_segMan, curObject, SELECTOR(brTop));
+ curRect.right = GET_SEL32V(_segMan, curObject, SELECTOR(brRight));
+ curRect.bottom = GET_SEL32V(_segMan, curObject, SELECTOR(brBottom));
// Check if curRect is within checkRect
// TODO: This check is slightly odd, because it means that a rect is not contained
// in itself. It may very well be that the original SCI engine did it just
@@ -115,29 +115,29 @@ uint16 GfxCompare::kernelOnControl(byte screenMask, const Common::Rect &rect) {
void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
GfxView *view = NULL;
Common::Rect celRect(0, 0);
- GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view));
+ GuiResourceId viewId = (GuiResourceId)GET_SEL32V(_segMan, objectReference, SELECTOR(view));
// HACK: Ignore invalid views for now (perhaps unimplemented text views?)
if (viewId == 0xFFFF) // invalid view
return;
- int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop));
- int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel));
- int16 x = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(x));
- int16 y = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(y));
+ int16 loopNo = GET_SEL32V(_segMan, objectReference, SELECTOR(loop));
+ int16 celNo = GET_SEL32V(_segMan, objectReference, SELECTOR(cel));
+ int16 x = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(x));
+ int16 y = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(y));
int16 z = 0;
if (_kernel->_selectorCache.z > -1)
- z = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(z));
+ z = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(z));
// now get cel rectangle
view = _cache->getView(viewId);
view->getCelRect(loopNo, celNo, x, y, z, &celRect);
- if (lookupSelector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) {
- writeSelectorValue(_segMan, objectReference, SELECTOR(nsLeft), celRect.left);
- writeSelectorValue(_segMan, objectReference, SELECTOR(nsRight), celRect.right);
- writeSelectorValue(_segMan, objectReference, SELECTOR(nsTop), celRect.top);
- writeSelectorValue(_segMan, objectReference, SELECTOR(nsBottom), celRect.bottom);
+ if (lookup_selector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) {
+ PUT_SEL32V(_segMan, objectReference, SELECTOR(nsLeft), celRect.left);
+ PUT_SEL32V(_segMan, objectReference, SELECTOR(nsRight), celRect.right);
+ PUT_SEL32V(_segMan, objectReference, SELECTOR(nsTop), celRect.top);
+ PUT_SEL32V(_segMan, objectReference, SELECTOR(nsBottom), celRect.bottom);
}
}
@@ -147,10 +147,10 @@ bool GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
uint16 signal, controlMask;
bool result;
- checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
- checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
- checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
- checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
+ checkRect.left = GET_SEL32V(_segMan, curObject, SELECTOR(brLeft));
+ checkRect.top = GET_SEL32V(_segMan, curObject, SELECTOR(brTop));
+ checkRect.right = GET_SEL32V(_segMan, curObject, SELECTOR(brRight));
+ checkRect.bottom = GET_SEL32V(_segMan, curObject, SELECTOR(brBottom));
if (!checkRect.isValidRect()) { // can occur in Iceman - HACK? TODO: is this really occuring in sierra sci? check this
warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom);
@@ -159,8 +159,8 @@ bool GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
adjustedRect = _coordAdjuster->onControl(checkRect);
- signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
- controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits));
+ signal = GET_SEL32V(_segMan, curObject, SELECTOR(signal));
+ controlMask = GET_SEL32V(_segMan, curObject, SELECTOR(illegalBits));
result = (isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask) ? false : true;
if ((result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) {
List *list = _segMan->lookupList(listReference);
@@ -183,14 +183,14 @@ bool GfxCompare::kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo,
}
void GfxCompare::kernelBaseSetter(reg_t object) {
- if (lookupSelector(_segMan, object, _kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
- int16 x = readSelectorValue(_segMan, object, SELECTOR(x));
- int16 y = readSelectorValue(_segMan, object, SELECTOR(y));
- int16 z = (_kernel->_selectorCache.z > -1) ? readSelectorValue(_segMan, object, SELECTOR(z)) : 0;
- int16 yStep = readSelectorValue(_segMan, object, SELECTOR(yStep));
- GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view));
- int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop));
- int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel));
+ if (lookup_selector(_segMan, object, _kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
+ int16 x = GET_SEL32V(_segMan, object, SELECTOR(x));
+ int16 y = GET_SEL32V(_segMan, object, SELECTOR(y));
+ int16 z = (_kernel->_selectorCache.z > -1) ? GET_SEL32V(_segMan, object, SELECTOR(z)) : 0;
+ int16 yStep = GET_SEL32V(_segMan, object, SELECTOR(yStep));
+ GuiResourceId viewId = GET_SEL32V(_segMan, object, SELECTOR(view));
+ int16 loopNo = GET_SEL32V(_segMan, object, SELECTOR(loop));
+ int16 celNo = GET_SEL32V(_segMan, object, SELECTOR(cel));
// HACK: Ignore invalid views for now (perhaps unimplemented text views?)
if (viewId == 0xFFFF) // invalid view
@@ -203,10 +203,10 @@ void GfxCompare::kernelBaseSetter(reg_t object) {
celRect.bottom = y + 1;
celRect.top = celRect.bottom - yStep;
- writeSelectorValue(_segMan, object, SELECTOR(brLeft), celRect.left);
- writeSelectorValue(_segMan, object, SELECTOR(brRight), celRect.right);
- writeSelectorValue(_segMan, object, SELECTOR(brTop), celRect.top);
- writeSelectorValue(_segMan, object, SELECTOR(brBottom), celRect.bottom);
+ PUT_SEL32V(_segMan, object, SELECTOR(brLeft), celRect.left);
+ PUT_SEL32V(_segMan, object, SELECTOR(brRight), celRect.right);
+ PUT_SEL32V(_segMan, object, SELECTOR(brTop), celRect.top);
+ PUT_SEL32V(_segMan, object, SELECTOR(brBottom), celRect.bottom);
}
}
diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls.cpp
index 26af9741c2..f744d6e7f1 100644
--- a/engines/sci/graphics/controls.cpp
+++ b/engines/sci/graphics/controls.cpp
@@ -143,9 +143,9 @@ void GfxControls::texteditSetBlinkTime() {
}
void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
- uint16 cursorPos = readSelectorValue(_segMan, controlObject, SELECTOR(cursor));
- uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max));
- reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
+ uint16 cursorPos = GET_SEL32V(_segMan, controlObject, SELECTOR(cursor));
+ uint16 maxChars = GET_SEL32V(_segMan, controlObject, SELECTOR(max));
+ reg_t textReference = GET_SEL32(_segMan, controlObject, SELECTOR(text));
Common::String text;
uint16 textSize, eventType, eventKey = 0;
bool textChanged = false;
@@ -158,14 +158,14 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
if (!eventObject.isNull()) {
textSize = text.size();
- eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
+ eventType = GET_SEL32V(_segMan, eventObject, SELECTOR(type));
switch (eventType) {
case SCI_EVENT_MOUSE_PRESS:
// TODO: Implement mouse support for cursor change
break;
case SCI_EVENT_KEYBOARD:
- eventKey = readSelectorValue(_segMan, eventObject, SELECTOR(message));
+ eventKey = GET_SEL32V(_segMan, eventObject, SELECTOR(message));
switch (eventKey) {
case SCI_KEY_BACKSPACE:
if (cursorPos > 0) {
@@ -207,9 +207,9 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
if (textChanged) {
GuiResourceId oldFontId = _text16->GetFontId();
- GuiResourceId fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
- rect = Common::Rect(readSelectorValue(_segMan, controlObject, SELECTOR(nsLeft)), readSelectorValue(_segMan, controlObject, SELECTOR(nsTop)),
- readSelectorValue(_segMan, controlObject, SELECTOR(nsRight)), readSelectorValue(_segMan, controlObject, SELECTOR(nsBottom)));
+ GuiResourceId fontId = GET_SEL32V(_segMan, controlObject, SELECTOR(font));
+ rect = Common::Rect(GET_SEL32V(_segMan, controlObject, SELECTOR(nsLeft)), GET_SEL32V(_segMan, controlObject, SELECTOR(nsTop)),
+ GET_SEL32V(_segMan, controlObject, SELECTOR(nsRight)), GET_SEL32V(_segMan, controlObject, SELECTOR(nsBottom)));
_text16->SetFont(fontId);
if (textAddChar) {
// We check, if we are really able to add the new char
@@ -241,7 +241,7 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
}
}
- writeSelectorValue(_segMan, controlObject, SELECTOR(cursor), cursorPos);
+ PUT_SEL32V(_segMan, controlObject, SELECTOR(cursor), cursorPos);
}
int GfxControls::getPicNotValid() {
diff --git a/engines/sci/graphics/coordadjuster.cpp b/engines/sci/graphics/coordadjuster.cpp
index 422df52f27..40ef655be7 100644
--- a/engines/sci/graphics/coordadjuster.cpp
+++ b/engines/sci/graphics/coordadjuster.cpp
@@ -93,18 +93,18 @@ GfxCoordAdjuster32::~GfxCoordAdjuster32() {
}
void GfxCoordAdjuster32::kernelGlobalToLocal(int16 &x, int16 &y, reg_t planeObject) {
- //int16 resY = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resY));
- //int16 resX = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resX));
+ //int16 resY = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resY));
+ //int16 resX = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resX));
//*x = ( *x * _screen->getWidth()) / resX;
//*y = ( *y * _screen->getHeight()) / resY;
- x -= readSelectorValue(_segMan, planeObject, SELECTOR(left));
- y -= readSelectorValue(_segMan, planeObject, SELECTOR(top));
+ x -= GET_SEL32V(_segMan, planeObject, SELECTOR(left));
+ y -= GET_SEL32V(_segMan, planeObject, SELECTOR(top));
}
void GfxCoordAdjuster32::kernelLocalToGlobal(int16 &x, int16 &y, reg_t planeObject) {
- //int16 resY = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resY));
- //int16 resX = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resX));
- x += readSelectorValue(_segMan, planeObject, SELECTOR(left));
- y += readSelectorValue(_segMan, planeObject, SELECTOR(top));
+ //int16 resY = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resY));
+ //int16 resX = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resX));
+ x += GET_SEL32V(_segMan, planeObject, SELECTOR(left));
+ y += GET_SEL32V(_segMan, planeObject, SELECTOR(top));
//*x = ( *x * resX) / _screen->getWidth();
//*y = ( *y * resY) / _screen->getHeight();
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 3cc5ca5447..78253bd913 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -54,7 +54,7 @@ GfxFrameout::~GfxFrameout() {
void GfxFrameout::kernelAddPlane(reg_t object) {
_planes.push_back(object);
- int16 planePri = readSelectorValue(_segMan, object, SELECTOR(priority)) & 0xFFFF;
+ int16 planePri = GET_SEL32V(_segMan, object, SELECTOR(priority)) & 0xFFFF;
if (planePri > _highPlanePri)
_highPlanePri = planePri;
}
@@ -74,7 +74,7 @@ void GfxFrameout::kernelDeletePlane(reg_t object) {
_highPlanePri = 0;
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
- int16 planePri = readSelectorValue(_segMan, _planes[planeNr], SELECTOR(priority)) & 0xFFFF;
+ int16 planePri = GET_SEL32V(_segMan, _planes[planeNr], SELECTOR(priority)) & 0xFFFF;
if (planePri > _highPlanePri)
_highPlanePri = planePri;
}
@@ -126,29 +126,29 @@ void GfxFrameout::kernelFrameout() {
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
planeObject = _planes[planeNr];
- planePriority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
+ planePriority = GET_SEL32V(_segMan, planeObject, SELECTOR(priority));
if (planePriority == -1) // Plane currently not meant to be shown
continue;
- planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top));
- planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left));
- planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom));
- planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right));
- planeResY = readSelectorValue(_segMan, planeObject, SELECTOR(resY));
- planeResX = readSelectorValue(_segMan, planeObject, SELECTOR(resX));
+ planeRect.top = GET_SEL32V(_segMan, planeObject, SELECTOR(top));
+ planeRect.left = GET_SEL32V(_segMan, planeObject, SELECTOR(left));
+ planeRect.bottom = GET_SEL32V(_segMan, planeObject, SELECTOR(bottom));
+ planeRect.right = GET_SEL32V(_segMan, planeObject, SELECTOR(right));
+ planeResY = GET_SEL32V(_segMan, planeObject, SELECTOR(resY));
+ planeResX = GET_SEL32V(_segMan, planeObject, SELECTOR(resX));
planeRect.top = (planeRect.top * _screen->getHeight()) / planeResY;
planeRect.left = (planeRect.left * _screen->getWidth()) / planeResX;
planeRect.bottom = (planeRect.bottom * _screen->getHeight()) / planeResY;
planeRect.right = (planeRect.right * _screen->getWidth()) / planeResX;
- planeBack = readSelectorValue(_segMan, planeObject, SELECTOR(back));
+ planeBack = GET_SEL32V(_segMan, planeObject, SELECTOR(back));
if (planeBack) {
_paint32->fillRect(planeRect, planeBack);
}
- planePictureNr = readSelectorValue(_segMan, planeObject, SELECTOR(picture));
+ planePictureNr = GET_SEL32V(_segMan, planeObject, SELECTOR(picture));
if ((planePictureNr != 0xFFFF) && (planePictureNr != 0xFFFE)) {
planePicture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, planePictureNr, false);
planePictureCels = planePicture->getSci32celCount();
@@ -161,19 +161,19 @@ void GfxFrameout::kernelFrameout() {
itemEntry = itemData;
for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
itemObject = _screenItems[itemNr];
- itemPlane = readSelector(_segMan, itemObject, SELECTOR(plane));
+ itemPlane = GET_SEL32(_segMan, itemObject, SELECTOR(plane));
if (planeObject == itemPlane) {
// Found an item on current plane
- itemEntry->viewId = readSelectorValue(_segMan, itemObject, SELECTOR(view));
- itemEntry->loopNo = readSelectorValue(_segMan, itemObject, SELECTOR(loop));
- itemEntry->celNo = readSelectorValue(_segMan, itemObject, SELECTOR(cel));
- itemEntry->x = readSelectorValue(_segMan, itemObject, SELECTOR(x));
- itemEntry->y = readSelectorValue(_segMan, itemObject, SELECTOR(y));
- itemEntry->z = readSelectorValue(_segMan, itemObject, SELECTOR(z));
- itemEntry->priority = readSelectorValue(_segMan, itemObject, SELECTOR(priority));
- itemEntry->signal = readSelectorValue(_segMan, itemObject, SELECTOR(signal));
- itemEntry->scaleX = readSelectorValue(_segMan, itemObject, SELECTOR(scaleX));
- itemEntry->scaleY = readSelectorValue(_segMan, itemObject, SELECTOR(scaleY));
+ itemEntry->viewId = GET_SEL32V(_segMan, itemObject, SELECTOR(view));
+ itemEntry->loopNo = GET_SEL32V(_segMan, itemObject, SELECTOR(loop));
+ itemEntry->celNo = GET_SEL32V(_segMan, itemObject, SELECTOR(cel));
+ itemEntry->x = GET_SEL32V(_segMan, itemObject, SELECTOR(x));
+ itemEntry->y = GET_SEL32V(_segMan, itemObject, SELECTOR(y));
+ itemEntry->z = GET_SEL32V(_segMan, itemObject, SELECTOR(z));
+ itemEntry->priority = GET_SEL32V(_segMan, itemObject, SELECTOR(priority));
+ itemEntry->signal = GET_SEL32V(_segMan, itemObject, SELECTOR(signal));
+ itemEntry->scaleX = GET_SEL32V(_segMan, itemObject, SELECTOR(scaleX));
+ itemEntry->scaleY = GET_SEL32V(_segMan, itemObject, SELECTOR(scaleY));
itemEntry->object = itemObject;
itemEntry->y = ((itemEntry->y * _screen->getHeight()) / planeResY);
@@ -240,12 +240,12 @@ void GfxFrameout::kernelFrameout() {
// This doesn't work for SCI2.1 games...
if (getSciVersion() == SCI_VERSION_2) {
Kernel *kernel = g_sci->getKernel();
- if (lookupSelector(_segMan, itemEntry->object, kernel->_selectorCache.text, NULL, NULL) == kSelectorVariable) {
- Common::String text = _segMan->getString(readSelector(_segMan, itemEntry->object, SELECTOR(text)));
- int16 fontRes = readSelectorValue(_segMan, itemEntry->object, SELECTOR(font));
+ if (lookup_selector(_segMan, itemEntry->object, kernel->_selectorCache.text, NULL, NULL) == kSelectorVariable) {
+ Common::String text = _segMan->getString(GET_SEL32(_segMan, itemEntry->object, SELECTOR(text)));
+ int16 fontRes = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(font));
GfxFont *font = new GfxFontFromResource(_resMan, _screen, fontRes);
- bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed));
- uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore));
+ bool dimmed = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(dimmed));
+ uint16 foreColor = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(fore));
uint16 curX = itemEntry->x;
uint16 curY = itemEntry->y;
for (uint32 i = 0; i < text.size(); i++) {
diff --git a/engines/sci/graphics/gui.cpp b/engines/sci/graphics/gui.cpp
index e427edd732..46f7fcd689 100644
--- a/engines/sci/graphics/gui.cpp
+++ b/engines/sci/graphics/gui.cpp
@@ -92,7 +92,7 @@ void SciGui::resetEngineState(EngineState *s) {
}
void SciGui::init(bool usesOldGfxFunctions) {
- _ports->init(usesOldGfxFunctions, this, _paint16, _text16);
+ _ports->init(usesOldGfxFunctions, this, _paint16, _text16, _s->_gameId);
_paint16->init(_animate, _text16);
}
@@ -136,4 +136,9 @@ void SciGui::portraitShow(Common::String resourceName, Common::Point position, u
void SciGui::portraitUnload(uint16 portraitId) {
}
+bool SciGui::debugEGAdrawingVisualize(bool state) {
+ _paint16->setEGAdrawingVisualize(state);
+ return false;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/graphics/gui.h b/engines/sci/graphics/gui.h
index 7663036117..732e195026 100644
--- a/engines/sci/graphics/gui.h
+++ b/engines/sci/graphics/gui.h
@@ -61,6 +61,8 @@ public:
virtual void portraitShow(Common::String resourceName, Common::Point position, uint16 resourceNum, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
virtual void portraitUnload(uint16 portraitId);
+ virtual bool debugEGAdrawingVisualize(bool state);
+
// FIXME: Don't store EngineState
virtual void resetEngineState(EngineState *s);
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
deleted file mode 100644
index a06e98ccbf..0000000000
--- a/engines/sci/graphics/maciconbar.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sci/sci.h"
-#include "sci/engine/selector.h"
-#include "sci/engine/state.h"
-#include "sci/graphics/maciconbar.h"
-#include "sci/graphics/palette.h"
-
-#include "common/stream.h"
-#include "common/system.h"
-#include "graphics/pict.h"
-#include "graphics/surface.h"
-
-namespace Sci {
-
-void GfxMacIconBar::addIcon(reg_t obj) {
- _iconBarObjects.push_back(obj);
-}
-
-void GfxMacIconBar::drawIcons() {
- // Draw the icons to the bottom of the screen
-
- byte *pal = new byte[256 * 4];
- Graphics::PictDecoder *pict = new Graphics::PictDecoder(Graphics::PixelFormat::createFormatCLUT8());
- uint32 lastX = 0;
-
- for (uint32 i = 0; i < _iconBarObjects.size(); i++) {
- uint32 iconIndex = readSelectorValue(g_sci->getEngineState()->_segMan, _iconBarObjects[i], SELECTOR(iconIndex));
- Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMacIconBarPictN, iconIndex + 1), false);
- if (!res)
- continue;
-
- Common::MemoryReadStream *stream = new Common::MemoryReadStream(res->data, res->size);
- Graphics::Surface *surf = pict->decodeImage(stream, pal);
- remapColors(surf, pal);
-
- g_system->copyRectToScreen((byte *)surf->pixels, surf->pitch, lastX, 200, MIN<uint32>(surf->w, 320 - lastX), surf->h);
-
- lastX += surf->w;
- surf->free();
- delete surf;
- delete stream;
- }
-
- delete pict;
- delete[] pal;
-}
-
-void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) {
- byte *pixels = (byte *)surf->pixels;
-
- // Remap to the screen palette
- for (uint16 i = 0; i < surf->w * surf->h; i++) {
- byte color = *pixels;
-
- byte r = palette[color * 4];
- byte g = palette[color * 4 + 1];
- byte b = palette[color * 4 + 2];
-
- // For black, make sure the index is 0
- if (r == 0 && g == 0 && b == 0)
- *pixels++ = 0;
- else
- *pixels++ = g_sci->_gfxPalette->kernelFindColor(r, g, b);
- }
-}
-
-} // End of namespace Sci
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 880e1aba12..5e3b419fe3 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -378,7 +378,7 @@ void GfxMenu::calculateMenuAndItemWidth() {
}
reg_t GfxMenu::kernelSelect(reg_t eventObject) {
- int16 eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
+ int16 eventType = GET_SEL32V(_segMan, eventObject, SELECTOR(type));
int16 keyPress, keyModifier;
Common::Point mousePosition;
GuiMenuItemList::iterator itemIterator = _itemList.begin();
@@ -390,8 +390,8 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject) {
switch (eventType) {
case SCI_EVENT_KEYBOARD:
- keyPress = readSelectorValue(_segMan, eventObject, SELECTOR(message));
- keyModifier = readSelectorValue(_segMan, eventObject, SELECTOR(modifiers));
+ keyPress = GET_SEL32V(_segMan, eventObject, SELECTOR(message));
+ keyModifier = GET_SEL32V(_segMan, eventObject, SELECTOR(modifiers));
// If tab got pressed, handle it here as if it was Ctrl-I - at least sci0 also did it that way
if (keyPress == SCI_KEY_TAB) {
keyModifier = SCI_KEYMOD_CTRL;
@@ -465,7 +465,7 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject) {
_ports->setPort(_oldPort);
if ((itemEntry) || (forceClaimed))
- writeSelector(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
+ PUT_SEL32(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
if (itemEntry)
return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id));
return NULL_REG;
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index ff4f3bec52..d0975f3d3d 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -61,7 +61,7 @@ void GfxPaint16::init(GfxAnimate *animate, GfxText16 *text16) {
_EGAdrawingVisualize = false;
}
-void GfxPaint16::debugSetEGAdrawingVisualize(bool state) {
+void GfxPaint16::setEGAdrawingVisualize(bool state) {
_EGAdrawingVisualize = state;
}
@@ -354,8 +354,7 @@ void GfxPaint16::bitsRestore(reg_t memoryHandle) {
}
void GfxPaint16::bitsFree(reg_t memoryHandle) {
- if (!memoryHandle.isNull()) // happens in KQ5CD
- _segMan->freeHunkEntry(memoryHandle);
+ _segMan->freeHunkEntry(memoryHandle);
}
void GfxPaint16::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h
index 65f9dd0d9c..b18c879387 100644
--- a/engines/sci/graphics/paint16.h
+++ b/engines/sci/graphics/paint16.h
@@ -50,7 +50,7 @@ public:
void init(GfxAnimate *animate, GfxText16 *text16);
- void debugSetEGAdrawingVisualize(bool state);
+ void setEGAdrawingVisualize(bool state);
void drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId);
void drawCelAndShow(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, uint16 scaleX = 128, uint16 scaleY = 128);
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 3c4cf7e964..6fe472f5fa 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -30,9 +30,8 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
-#include "sci/graphics/maciconbar.h"
-#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
+#include "sci/graphics/palette.h"
namespace Sci {
@@ -312,10 +311,6 @@ void GfxPalette::setOnScreen() {
if (_resMan->isAmiga32color())
return;
_screen->setPalette(&_sysPalette);
-
- // Redraw the Mac SCI1.1 Icon bar every palette change
- if (g_sci->_gfxMacIconBar)
- g_sci->_gfxMacIconBar->drawIcons();
}
bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) {
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index a59153f116..74f651a88a 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -69,20 +69,15 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1
headerSize = READ_LE_UINT16(_resource->data);
switch (headerSize) {
case 0x26: // SCI 1.1 VGA picture
- _resourceType = SCI_PICTURE_TYPE_SCI11;
- if (_addToFlag)
- _priority = 15;
drawSci11Vga();
break;
#ifdef ENABLE_SCI32
case 0x0e: // SCI32 VGA picture
- _resourceType = SCI_PICTURE_TYPE_SCI32;
drawSci32Vga();
break;
#endif
default:
// VGA, EGA or Amiga vector data
- _resourceType = SCI_PICTURE_TYPE_REGULAR;
drawVectorData(_resource->data, _resource->size);
}
}
@@ -113,8 +108,9 @@ void GfxPicture::drawSci11Vga() {
_palette->set(&palette, true);
// display Cel-data
- if (has_cel)
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0);
+ if (has_cel) {
+ drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false);
+ }
// process vector data
drawVectorData(inbuffer + vector_dataPos, vector_size);
@@ -143,7 +139,6 @@ void GfxPicture::drawSci32Vga(int16 celNo) {
// HACK
_mirroredFlag = false;
_addToFlag = false;
- _resourceType = SCI_PICTURE_TYPE_SCI32;
if ((celNo == -1) || (celNo == 0)) {
// Create palette and set it
@@ -160,14 +155,14 @@ void GfxPicture::drawSci32Vga(int16 celNo) {
cel_LiteralPos = READ_LE_UINT32(inbuffer + cel_headerPos + 28);
cel_relXpos = READ_LE_UINT16(inbuffer + cel_headerPos + 38);
cel_relYpos = READ_LE_UINT16(inbuffer + cel_headerPos + 40);
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, cel_relXpos, cel_relYpos);
+ drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, cel_relXpos, cel_relYpos, true);
cel_headerPos += 42;
celCount--;
}
}
#endif
-void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY) {
+void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header) {
byte *celBitmap = NULL;
byte *ptr = NULL;
byte *headerPtr = inbuffer + headerPos;
@@ -184,16 +179,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
int pixelNr, pixelCount;
#ifdef ENABLE_SCI32
- if (_resourceType != SCI_PICTURE_TYPE_SCI32) {
+ if (!hasSci32Header) {
#endif
displaceX = (signed char)headerPtr[4];
displaceY = (unsigned char)headerPtr[5];
- if (_resourceType == SCI_PICTURE_TYPE_SCI11) {
- // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
- clearColor = _screen->getColorWhite();
- } else {
- clearColor = headerPtr[6];
- }
+ clearColor = headerPtr[6];
#ifdef ENABLE_SCI32
} else {
displaceX = READ_LE_UINT16(headerPtr + 4); // probably signed?!?
@@ -528,29 +518,10 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
- // Pattern opcodes are handled in sierra sci1.1+ as actual NOPs and normally they definitely should not occur
- // inside picture data for such games
case PIC_OP_SET_PATTERN:
- if (_resourceType >= SCI_PICTURE_TYPE_SCI11) {
- if (strcmp(g_sci->getGameID(), "sq4") == 0) {
- // WORKAROUND: For SQ4 / for some pictures handle this like a terminator
- // This picture includes garbage data, first a set pattern w/o parameter and then short pattern
- // I guess that garbage is a left over from the sq4-floppy (sci1) to sq4-cd (sci1.1) conversion
- switch (_resourceId) {
- case 381:
- case 376:
- return;
- default:
- break;
- }
- }
- error("pic-operation set pattern inside sci1.1+ vector data");
- }
pattern_Code = data[curPos++];
break;
case PIC_OP_SHORT_PATTERNS:
- if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
- error("pic-operation short pattern inside sci1.1+ vector data");
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture);
@@ -561,8 +532,6 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OP_MEDIUM_PATTERNS:
- if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
- error("pic-operation medium pattern inside sci1.1+ vector data");
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture);
@@ -573,8 +542,6 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OP_ABSOLUTE_PATTERN:
- if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
- error("pic-operation absolute pattern inside sci1.1+ vector data");
while (vectorIsNonOpcode(data[curPos])) {
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
@@ -618,7 +585,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
vectorGetAbsCoordsNoMirror(data, curPos, x, y);
size = READ_LE_UINT16(data + curPos); curPos += 2;
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y);
+ drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false);
curPos += size;
break;
case PIC_OPX_EGA_SET_PRIORITY_TABLE:
@@ -660,7 +627,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
if (pic_priority == 255)
_priority = 0; // if priority not set, use priority 0
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y);
+ drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false);
curPos += size;
break;
case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST:
diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h
index 5a86539b37..3374c33b52 100644
--- a/engines/sci/graphics/picture.h
+++ b/engines/sci/graphics/picture.h
@@ -32,12 +32,6 @@ namespace Sci {
#define SCI_PATTERN_CODE_USE_TEXTURE 0x20
#define SCI_PATTERN_CODE_PENSIZE 0x07
-enum {
- SCI_PICTURE_TYPE_REGULAR = 0,
- SCI_PICTURE_TYPE_SCI11 = 1,
- SCI_PICTURE_TYPE_SCI32 = 2
-};
-
class GfxPorts;
class GfxScreen;
class GfxPalette;
@@ -63,7 +57,7 @@ private:
void initData(GuiResourceId resourceId);
void reset();
void drawSci11Vga();
- void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY);
+ void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header);
void drawVectorData(byte *data, int size);
bool vectorIsNonOpcode(byte pixel);
void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y);
@@ -86,7 +80,6 @@ private:
int16 _resourceId;
Resource *_resource;
- int _resourceType;
int16 _animationNr;
bool _mirroredFlag;
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index cdb6fe4ae1..ab3291dd79 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -54,7 +54,7 @@ GfxPorts::~GfxPorts() {
delete _menuPort;
}
-void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16) {
+void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16, Common::String gameId) {
int16 offTop = 10;
_usesOldGfxFunctions = usesOldGfxFunctions;
@@ -88,7 +88,6 @@ void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16,
// Jones, Slater and Hoyle 3 were called with parameter -Nw 0 0 200 320.
// Mother Goose (SCI1) uses -Nw 0 0 159 262. The game will later use SetPort so we don't need to set the other fields.
// This actually meant not skipping the first 10 pixellines in windowMgrPort
- Common::String gameId = g_sci->getGameID();
if (gameId == "jones" || gameId == "slater" || gameId == "hoyle3" || (gameId == "mothergoose" && getSciVersion() == SCI_VERSION_1_EARLY))
offTop = 0;
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index c8ce6b3470..0876d9e442 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -45,7 +45,7 @@ public:
GfxPorts(SegManager *segMan, GfxScreen *screen);
~GfxPorts();
- void init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16);
+ void init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16, Common::String gameId);
void kernelSetActive(uint16 portId);
Common::Rect kernelGetPicWindow(int16 &picTop, int16 &picLeft);
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 0e054d5a76..7ca9e33509 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -93,18 +93,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan, int16 width, int16 height, int ups
}
// Initialize the actual screen
-
- if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) {
- // For SCI1.1 Mac, we need to expand the screen to accommodate for
- // the icon bar. Of course, both KQ6 and QFG1 VGA differ in size.
- if (!scumm_stricmp(g_sci->getGameID(), "kq6"))
- initGraphics(_displayWidth, _displayHeight + 26, _displayWidth > 320);
- else if (!scumm_stricmp(g_sci->getGameID(), "qfg1"))
- initGraphics(_displayWidth, _displayHeight + 20, _displayWidth > 320);
- else
- error("Unknown SCI1.1 Mac game");
- } else
- initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
+ initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
}
GfxScreen::~GfxScreen() {
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index a2cfd38f95..8c4d666ba7 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -6,7 +6,6 @@ MODULE_OBJS := \
detection.o \
event.o \
resource.o \
- resource_audio.o \
sci.o \
util.o \
engine/features.o \
@@ -45,7 +44,6 @@ MODULE_OBJS := \
graphics/font.o \
graphics/fontsjis.o \
graphics/gui.o \
- graphics/maciconbar.o \
graphics/menu.o \
graphics/paint.o \
graphics/paint16.o \
diff --git a/engines/sci/parser/grammar.cpp b/engines/sci/parser/grammar.cpp
index 070e6767cf..1cfe84076f 100644
--- a/engines/sci/parser/grammar.cpp
+++ b/engines/sci/parser/grammar.cpp
@@ -258,11 +258,6 @@ void Vocabulary::freeRuleList(ParseRuleList *list) {
static ParseRuleList *_vocab_add_rule(ParseRuleList *list, ParseRule *rule) {
if (!rule)
return list;
- if (!rule->_data.size()) {
- // Special case for qfg2 demo
- warning("no rule contents on _vocab_add_rule()");
- return list;
- }
ParseRuleList *new_elem = new ParseRuleList(rule);
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index f49704372a..5cd1310ad3 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -2443,14 +2443,13 @@ static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *sai
int said(EngineState *s, byte *spec, bool verbose) {
int retval;
- Vocabulary *voc = g_sci->getVocabulary();
- parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
+ parse_tree_node_t *parse_tree_ptr = s->_voc->_parserNodes;
- if (voc->parserIsValid) {
+ if (s->_voc->parserIsValid) {
if (said_parse_spec(spec)) {
printf("Offending spec was: ");
- voc->decipherSaidBlock(spec);
+ s->_voc->decipherSaidBlock(spec);
return SAID_NO_MATCH;
}
diff --git a/engines/sci/parser/said.y b/engines/sci/parser/said.y
index cbb2ff3e62..27486c5794 100644
--- a/engines/sci/parser/said.y
+++ b/engines/sci/parser/said.y
@@ -799,14 +799,13 @@ static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *sai
int said(EngineState *s, byte *spec, bool verbose) {
int retval;
- Vocabulary *voc = g_sci->getVocabulary();
- parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
+ parse_tree_node_t *parse_tree_ptr = s->_voc->_parserNodes;
- if (voc->parserIsValid) {
+ if (s->_voc->parserIsValid) {
if (said_parse_spec(spec)) {
printf("Offending spec was: ");
- voc->decipherSaidBlock(spec);
+ s->_voc->decipherSaidBlock(spec);
return SAID_NO_MATCH;
}
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 449effd737..4888dbd4cb 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -26,6 +26,7 @@
// Resource library
#include "common/file.h"
+#include "common/macresman.h"
#include "sci/resource.h"
#include "sci/util.h"
@@ -44,6 +45,18 @@ struct resource_index_t {
uint16 wSize;
};
+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;
+ uint32 audioCompressionType;
+ int32 *audioCompressionOffsetMapping;
+ Common::MacResManager macResMan;
+};
+
//////////////////////////////////////////////////////////////////////
static SciVersion s_sciVersion = SCI_VERSION_NONE; // FIXME: Move this inside a suitable class, e.g. SciEngine
@@ -183,7 +196,7 @@ ResourceSource *ResourceManager::addExternalMap(const char *file_name, int volum
return newsrc;
}
-ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile, int volume_nr) {
+ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceExtMap;
@@ -191,7 +204,7 @@ ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile, i
newsrc->resourceFile = mapFile;
newsrc->scanned = false;
newsrc->associated_map = NULL;
- newsrc->volume_number = volume_nr;
+ newsrc->volume_number = 0;
_sources.push_back(newsrc);
return newsrc;
@@ -237,7 +250,6 @@ ResourceSource *ResourceManager::addPatchDir(const char *dirname) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceDirectory;
- newsrc->resourceFile = 0;
newsrc->scanned = false;
newsrc->location_name = dirname;
@@ -258,7 +270,37 @@ ResourceSource *ResourceManager::getVolume(ResourceSource *map, int volume_nr) {
// Resource manager constructors and operations
-bool ResourceManager::loadPatch(Resource *res, Common::SeekableReadStream *file) {
+void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
+ Common::File *file = getVolumeFile(source->location_name.c_str());
+ if (!file) {
+ warning("Failed to open %s", source->location_name.c_str());
+ return;
+ }
+ file->seek(0, SEEK_SET);
+ uint32 compressionType = file->readUint32BE();
+ switch (compressionType) {
+ case MKID_BE('MP3 '):
+ case MKID_BE('OGG '):
+ case MKID_BE('FLAC'):
+ // Detected a compressed audio volume
+ source->audioCompressionType = compressionType;
+ // Now read the whole offset mapping table for later usage
+ int32 recordCount = file->readUint32LE();
+ if (!recordCount)
+ error("compressed audio volume doesn't contain any entries!");
+ int32 *offsetMapping = new int32[(recordCount + 1) * 2];
+ source->audioCompressionOffsetMapping = offsetMapping;
+ for (int recordNo = 0; recordNo < recordCount; recordNo++) {
+ *offsetMapping++ = file->readUint32LE();
+ *offsetMapping++ = file->readUint32LE();
+ }
+ // Put ending zero
+ *offsetMapping++ = 0;
+ *offsetMapping++ = file->size();
+ }
+}
+
+bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
// We assume that the resource type matches res->type
// We also assume that the current file position is right at the actual data (behind resourceid/headersize byte)
@@ -273,12 +315,12 @@ bool ResourceManager::loadPatch(Resource *res, Common::SeekableReadStream *file)
unsigned int really_read;
if (res->_headerSize > 0) {
- really_read = file->read(res->_header, res->_headerSize);
+ really_read = file.read(res->_header, res->_headerSize);
if (really_read != res->_headerSize)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->_headerSize);
}
- really_read = file->read(res->data, res->size);
+ really_read = file.read(res->data, res->size);
if (really_read != res->size)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
@@ -296,7 +338,71 @@ bool ResourceManager::loadFromPatchFile(Resource *res) {
}
// Skip resourceid and header size byte
file.seek(2, SEEK_SET);
- return loadPatch(res, &file);
+ return loadPatch(res, file);
+}
+
+bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) {
+ res->data = new byte[res->size];
+
+ uint32 really_read = file.read(res->data, res->size);
+ if (really_read != res->size)
+ error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
+
+ res->_status = kResStatusAllocated;
+ return true;
+}
+
+bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) {
+ // Check for WAVE files here
+ uint32 riffTag = file.readUint32BE();
+ if (riffTag == MKID_BE('RIFF')) {
+ res->_headerSize = 0;
+ res->size = file.readUint32LE();
+ file.seek(-8, SEEK_CUR);
+ return loadFromWaveFile(res, file);
+ }
+ file.seek(-4, SEEK_CUR);
+
+ ResourceType type = (ResourceType)(file.readByte() & 0x7f);
+ if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
+ || ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
+ warning("Resource type mismatch loading %s from %s", res->_id.toString().c_str(), file.getName());
+ res->unalloc();
+ return false;
+ }
+
+ res->_headerSize = file.readByte();
+
+ if (type == kResourceTypeAudio) {
+ if (res->_headerSize != 11 && res->_headerSize != 12) {
+ warning("Unsupported audio header");
+ res->unalloc();
+ return false;
+ }
+
+ // Load sample size
+ file.seek(7, SEEK_CUR);
+ res->size = file.readUint32LE();
+ // Adjust offset to point at the header data again
+ file.seek(-11, SEEK_CUR);
+ }
+
+ return loadPatch(res, file);
+}
+
+bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &file) {
+ res->data = new byte[res->size];
+
+ if (res->data == NULL) {
+ error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
+ }
+
+ unsigned int really_read = file.read(res->data, res->size);
+ if (really_read != res->size)
+ warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
+
+ res->_status = kResStatusAllocated;
+ return true;
}
Common::File *ResourceManager::getVolumeFile(const char *filename) {
@@ -339,10 +445,11 @@ void ResourceManager::loadResource(Resource *res) {
return;
if (res->_source->source_type == kSourceMacResourceFork) {
+ //error("ResourceManager::loadResource(): TODO: Mac resource fork ;)");
Common::SeekableReadStream *stream = res->_source->macResMan.getResource(resTypeToMacTag(res->_id.type), res->_id.number);
if (!stream)
- error("Could not get Mac resource fork resource: %d %d", res->_id.type, res->_id.number);
+ error("Could not get Mac resource fork resource");
int error = decompress(res, stream);
if (error) {
@@ -353,15 +460,10 @@ void ResourceManager::loadResource(Resource *res) {
return;
}
- Common::SeekableReadStream *fileStream;
-
+ Common::File *file;
// Either loading from volume or patch loading failed
- if (res->_source->resourceFile)
- fileStream = res->_source->resourceFile->createReadStream();
- else
- fileStream = getVolumeFile(res->_source->location_name.c_str());
-
- if (!fileStream) {
+ file = getVolumeFile(res->_source->location_name.c_str());
+ if (!file) {
warning("Failed to open %s", res->_source->location_name.c_str());
res->unalloc();
return;
@@ -369,8 +471,8 @@ void ResourceManager::loadResource(Resource *res) {
switch(res->_source->source_type) {
case kSourceWave:
- fileStream->seek(res->_fileOffset, SEEK_SET);
- loadFromWaveFile(res, fileStream);
+ file->seek(res->_fileOffset, SEEK_SET);
+ loadFromWaveFile(res, *file);
return;
case kSourceAudioVolume:
@@ -401,30 +503,30 @@ void ResourceManager::loadResource(Resource *res) {
if (!compressedOffset)
error("could not translate offset to compressed offset in audio volume");
- fileStream->seek(compressedOffset, SEEK_SET);
+ file->seek(compressedOffset, SEEK_SET);
switch (res->_id.type) {
case kResourceTypeAudio:
case kResourceTypeAudio36:
// Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
- loadFromAudioVolumeSCI1(res, fileStream);
+ loadFromAudioVolumeSCI1(res, *file);
return;
default:
break;
}
} else {
// original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
- fileStream->seek(res->_fileOffset, SEEK_SET);
+ file->seek(res->_fileOffset, SEEK_SET);
}
if (getSciVersion() < SCI_VERSION_1_1)
- loadFromAudioVolumeSCI1(res, fileStream);
+ loadFromAudioVolumeSCI1(res, *file);
else
- loadFromAudioVolumeSCI11(res, fileStream);
+ loadFromAudioVolumeSCI11(res, *file);
return;
default:
- fileStream->seek(res->_fileOffset, SEEK_SET);
- int error = decompress(res, fileStream);
+ file->seek(res->_fileOffset, SEEK_SET);
+ int error = decompress(res, file);
if (error) {
warning("Error %d occured while reading %s from resource file: %s",
error, res->_id.toString().c_str(), sci_error_types[error]);
@@ -453,11 +555,11 @@ int sci0_get_compression_method(Common::ReadStream &stream) {
int ResourceManager::addAppropriateSources() {
Common::ArchiveMemberList files;
- if (Common::File::exists("resource.map")) {
+ if (Common::File::exists("RESOURCE.MAP")) {
// SCI0-SCI2 file naming scheme
- ResourceSource *map = addExternalMap("resource.map");
+ ResourceSource *map = addExternalMap("RESOURCE.MAP");
- SearchMan.listMatchingMembers(files, "resource.0??");
+ SearchMan.listMatchingMembers(files, "RESOURCE.0??");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
const Common::String name = (*x)->getName();
@@ -468,12 +570,12 @@ int ResourceManager::addAppropriateSources() {
}
#ifdef ENABLE_SCI32
// GK1CD hires content
- if (Common::File::exists("alt.map") && Common::File::exists("resource.alt"))
- addSource(addExternalMap("alt.map", 10), kSourceVolume, "resource.alt", 10);
+ if (Common::File::exists("ALT.MAP") && Common::File::exists("RESOURCE.ALT"))
+ addSource(addExternalMap("ALT.MAP", 10), kSourceVolume, "RESOURCE.ALT", 10);
#endif
} else if (Common::File::exists("Data1")) {
// Mac SCI1.1+ file naming scheme
- SearchMan.listMatchingMembers(files, "Data?*");
+ SearchMan.listMatchingMembers(files, "Data?");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
Common::String filename = (*x)->getName();
@@ -492,8 +594,8 @@ int ResourceManager::addAppropriateSources() {
} else {
// SCI2.1-SCI3 file naming scheme
Common::ArchiveMemberList mapFiles;
- SearchMan.listMatchingMembers(mapFiles, "resmap.0??");
- SearchMan.listMatchingMembers(files, "ressci.0??");
+ SearchMan.listMatchingMembers(mapFiles, "RESMAP.0??");
+ SearchMan.listMatchingMembers(files, "RESSCI.0??");
// We need to have the same number of maps as resource archives
if (mapFiles.empty() || files.empty() || mapFiles.size() != files.size())
@@ -515,9 +617,9 @@ int ResourceManager::addAppropriateSources() {
}
// SCI2.1 resource patches
- if (Common::File::exists("resmap.pat") && Common::File::exists("ressci.pat")) {
+ if (Common::File::exists("RESMAP.PAT") && Common::File::exists("RESSCI.PAT")) {
// We add this resource with a map which surely won't exist
- addSource(addExternalMap("resmap.pat", 100), kSourceVolume, "ressci.pat", 100);
+ addSource(addExternalMap("RESMAP.PAT", 100), kSourceVolume, "RESSCI.PAT", 100);
}
}
#else
@@ -526,18 +628,14 @@ int ResourceManager::addAppropriateSources() {
#endif
addPatchDir(".");
- if (Common::File::exists("message.map"))
- addSource(addExternalMap("message.map"), kSourceVolume, "resource.msg", 0);
+ if (Common::File::exists("MESSAGE.MAP"))
+ addSource(addExternalMap("MESSAGE.MAP"), kSourceVolume, "RESOURCE.MSG", 0);
return 1;
}
int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
ResourceSource *map = 0;
-#ifdef ENABLE_SCI32
- ResourceSource *sci21PatchMap = 0;
- const Common::FSNode *sci21PatchRes = 0;
-#endif
// First, find resource.map
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
@@ -547,33 +645,17 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
Common::String filename = file->getName();
filename.toLowercase();
- if (filename.contains("resource.map"))
+ // TODO: Load the SCI2.1+ maps (resmap.*) in concurrence with the volumes to
+ // get the proper volume numbers from the maps.
+ if (filename.contains("resource.map") || filename.contains("resmap.000")) {
map = addExternalMap(file);
-
- if (filename.contains("resmap.0")) {
- const char *dot = strrchr(file->getName().c_str(), '.');
- int number = atoi(dot + 1);
- map = addExternalMap(file, number);
+ break;
}
-
-#ifdef ENABLE_SCI32
- // SCI2.1 resource patches
- if (filename.contains("resmap.pat"))
- sci21PatchMap = addExternalMap(file, 100);
-
- if (filename.contains("ressci.pat"))
- sci21PatchRes = file;
-#endif
}
if (!map)
return 0;
-#ifdef ENABLE_SCI32
- if (sci21PatchMap && sci21PatchRes)
- addSource(sci21PatchMap, kSourceVolume, sci21PatchRes, 100);
-#endif
-
// Now find all the resource.0?? files
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory())
@@ -614,6 +696,36 @@ int ResourceManager::addInternalSources() {
return 1;
}
+void ResourceManager::addNewGMPatch(const Common::String &gameId) {
+ Common::String gmPatchFile;
+
+ if (gameId == "ecoquest")
+ gmPatchFile = "ECO1GM.PAT";
+ else if (gameId == "hoyle3")
+ gmPatchFile = "HOY3GM.PAT";
+ else if (gameId == "hoyle3")
+ gmPatchFile = "HOY3GM.PAT";
+ else if (gameId == "lsl1sci")
+ gmPatchFile = "LL1_GM.PAT";
+ else if (gameId == "lsl5")
+ gmPatchFile = "LL5_GM.PAT";
+ else if (gameId == "longbow")
+ gmPatchFile = "ROBNGM.PAT";
+ else if (gameId == "sq1sci")
+ gmPatchFile = "SQ1_GM.PAT";
+ else if (gameId == "sq4")
+ gmPatchFile = "SQ4_GM.PAT";
+ else if (gameId == "fairytales")
+ gmPatchFile = "TALEGM.PAT";
+
+ if (!gmPatchFile.empty() && Common::File::exists(gmPatchFile)) {
+ ResourceSource *psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourcePatch;
+ psrcPatch->location_name = gmPatchFile;
+ processPatch(psrcPatch, kResourceTypePatch, 4);
+ }
+}
+
void ResourceManager::scanNewSources() {
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
ResourceSource *source = *it;
@@ -878,6 +990,7 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
ResourceManager::ResVersion ResourceManager::detectMapVersion() {
Common::SeekableReadStream *fileStream = 0;
+ Common::File *file = 0;
byte buff[6];
ResourceSource *rsrc= 0;
@@ -888,7 +1001,7 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- Common::File *file = new Common::File();
+ file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -968,6 +1081,7 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
ResourceManager::ResVersion ResourceManager::detectVolVersion() {
Common::SeekableReadStream *fileStream = 0;
+ Common::File *file = 0;
ResourceSource *rsrc;
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
@@ -977,7 +1091,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- Common::File *file = new Common::File();
+ file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -1067,7 +1181,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
// version-agnostic patch application
void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, int resnumber) {
- Common::SeekableReadStream *fileStream = 0;
+ Common::File file;
Resource *newrsc;
ResourceId resId = ResourceId(restype, resnumber);
byte patchtype, patch_data_offset;
@@ -1075,27 +1189,18 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
if (resnumber == -1)
return;
-
- if (source->resourceFile) {
- fileStream = source->resourceFile->createReadStream();
- } else {
- Common::File *file = new Common::File();
- if (!file->open(source->location_name)) {
- warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
- return;
- }
- fileStream = file;
+ if (!file.open(source->location_name)) {
+ warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
+ return;
}
- fsize = fileStream->size();
+ fsize = file.size();
if (fsize < 3) {
debug("Patching %s failed - file too small", source->location_name.c_str());
return;
}
- patchtype = fileStream->readByte() & 0x7F;
- patch_data_offset = fileStream->readByte();
-
- delete fileStream;
+ patchtype = file.readByte() & 0x7F;
+ patch_data_offset = file.readByte();
if (patchtype != restype) {
debug("Patching %s failed - resource type mismatch", source->location_name.c_str());
@@ -1110,12 +1215,8 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
case 1:
patch_data_offset = 2;
break;
- case 4:
- patch_data_offset = 8;
- break;
default:
- warning("Resource patch unsupported special case %X", patch_data_offset & 0x7F);
- return;
+ warning("Resource patch unsupported special case %X", patch_data_offset);
}
}
@@ -1142,17 +1243,9 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
void ResourceManager::readResourcePatches(ResourceSource *source) {
- // Note: since some SCI1 games(KQ5 floppy, SQ4) might use SCI0 naming scheme for patch files
- // this function tries to read patch file with any supported naming scheme,
- // regardless of s_sciVersion value
-
- // Note that audio36 and sync36 use a different naming scheme, because they cannot be described
- // with a single resource number, but are a result of a <number, noun, verb, cond, seq> tuple.
- // Please don't be confused with the normal audio patches (*.aud) and normal sync patches (*.syn).
- // audio36 patches can be seen for example in the AUD folder of GK1CD, and are like this file:
- // @0CS0M00.0X1. GK1CD is the first game where these have been observed. The actual audio36 and
- // sync36 resources exist in SCI1.1 as well, but the first game where external patch files for
- // them have been found is GK1CD
+// Note: since some SCI1 games(KQ5 floppy, SQ4) might use SCI0 naming scheme for patch files
+// this function tries to read patch file with any supported naming scheme,
+// regardless of s_sciVersion value
Common::String mask, name;
Common::ArchiveMemberList files;
@@ -1162,7 +1255,6 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
for (int i = kResourceTypeView; i <= kResourceTypeRobot; ++i) {
// TODO: add support for audio36 and sync36 files
- // Such patches were introduced in SCI2, and didn't exist in SCI0-SCI1.1
if (i == kResourceTypeAudio36 || i == kResourceTypeSync36)
continue;
@@ -1197,13 +1289,55 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
psrcPatch = new ResourceSource;
psrcPatch->source_type = kSourcePatch;
psrcPatch->location_name = name;
- psrcPatch->resourceFile = 0;
processPatch(psrcPatch, (ResourceType)i, number);
}
}
}
}
+void ResourceManager::readWaveAudioPatches() {
+ // Here we do check for SCI1.1+ so we can patch wav files in as audio resources
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, "*.wav");
+
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ Common::String name = (*x)->getName();
+
+ if (isdigit(name[0])) {
+ int number = atoi(name.c_str());
+ ResourceSource *psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourceWave;
+ psrcPatch->location_name = name;
+ psrcPatch->volume_number = 0;
+ psrcPatch->audioCompressionType = 0;
+
+ ResourceId resId = ResourceId(kResourceTypeAudio, number);
+
+ Resource *newrsc = NULL;
+
+ // Prepare destination, if neccessary
+ if (_resMap.contains(resId) == false) {
+ newrsc = new Resource;
+ _resMap.setVal(resId, newrsc);
+ } else
+ newrsc = _resMap.getVal(resId);
+
+ // Get the size of the file
+ Common::SeekableReadStream *stream = (*x)->createReadStream();
+ uint32 fileSize = stream->size();
+ delete stream;
+
+ // Overwrite everything, because we're patching
+ newrsc->_id = resId;
+ newrsc->_status = kResStatusNoMalloc;
+ newrsc->_source = psrcPatch;
+ newrsc->size = fileSize;
+ newrsc->_headerSize = 0;
+ debugC(1, kDebugLevelResMan, "Patching %s - OK", psrcPatch->location_name.c_str());
+ }
+ }
+}
+
int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
Common::File file;
Resource *res;
@@ -1314,7 +1448,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
res->_id = resId;
// NOTE: We add the map's volume number here to the specified volume number
- // for SCI2.1 and SCI3 maps that are not resmap.000. The resmap.* files' numbers
+ // for SCI2.1 and SCI3 maps that are not RESMAP.000. The RESMAP.* files' numbers
// need to be used in concurrence with the volume specified in the map to get
// the actual resource file.
res->_source = getVolume(map, volume_nr + map->volume_number);
@@ -1342,11 +1476,7 @@ struct {
{ MKID_BE('PAL '), kResourceTypePalette },
{ MKID_BE('snd '), kResourceTypeAudio },
{ MKID_BE('MSG '), kResourceTypeMessage },
- { MKID_BE('HEP '), kResourceTypeHeap },
- { MKID_BE('IBIN'), kResourceTypeMacIconBarPictN },
- { MKID_BE('IBIS'), kResourceTypeMacIconBarPictS },
- { MKID_BE('PICT'), kResourceTypeMacPict },
- { MKID_BE('SYN '), kResourceTypeSync }
+ { MKID_BE('HEP '), kResourceTypeHeap }
};
static uint32 resTypeToMacTag(ResourceType type) {
@@ -1379,16 +1509,6 @@ int ResourceManager::readMacResourceFork(ResourceSource *source) {
Common::MacResIDArray idArray = source->macResMan.getResIDArray(tagArray[i]);
for (uint32 j = 0; j < idArray.size(); j++) {
- // Get the size of the file
- Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);
-
- // Some IBIS resources have a size of 0, so we skip them
- if (!stream)
- continue;
-
- uint32 fileSize = stream->size();
- delete stream;
-
ResourceId resId = ResourceId(type, idArray[j]);
Resource *newrsc = NULL;
@@ -1400,6 +1520,11 @@ int ResourceManager::readMacResourceFork(ResourceSource *source) {
} else
newrsc = _resMap.getVal(resId);
+ // Get the size of the file
+ Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);
+ uint32 fileSize = stream->size();
+ delete stream;
+
// Overwrite everything
newrsc->_id = resId;
newrsc->_status = kResStatusNoMalloc;
@@ -1424,6 +1549,261 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32
}
}
+void ResourceManager::removeAudioResource(ResourceId resId) {
+ // Remove resource, unless it was loaded from a patch
+ if (_resMap.contains(resId)) {
+ Resource *res = _resMap.getVal(resId);
+
+ if (res->_source->source_type == kSourceAudioVolume) {
+ if (res->_status == kResStatusLocked) {
+ warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
+ } else {
+ if (res->_status == kResStatusEnqueued)
+ removeFromLRU(res);
+
+ _resMap.erase(resId);
+ delete res;
+ }
+ }
+ }
+}
+
+// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
+// =========
+// 6-byte entries:
+// w nEntry
+// dw offset
+
+// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
+// =========
+// 5-byte entries:
+// w nEntry
+// tb offset (cumulative)
+
+// Early SCI1.1 MAP structure:
+// ===============
+// 10-byte entries:
+// b noun
+// b verb
+// b cond
+// b seq
+// dw offset
+// w syncSize + syncAscSize
+
+// Late SCI1.1 MAP structure:
+// ===============
+// Header:
+// dw baseOffset
+// Followed by 7 or 11-byte entries:
+// b noun
+// b verb
+// b cond
+// b seq
+// tb cOffset (cumulative offset)
+// w syncSize (iff seq has bit 7 set)
+// w syncAscSize (iff seq has bit 6 set)
+
+int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
+ bool isEarly = true;
+ uint32 offset = 0;
+ Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
+
+ if (!mapRes) {
+ warning("Failed to open %i.MAP", map->volume_number);
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ ResourceSource *src = getVolume(map, 0);
+
+ if (!src)
+ return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
+
+ byte *ptr = mapRes->data;
+
+ if (map->volume_number == 65535) {
+ // Heuristic to detect late SCI1.1 map format
+ if ((mapRes->size >= 6) && (ptr[mapRes->size - 6] != 0xff))
+ isEarly = false;
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint16 n = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (n == 0xffff)
+ break;
+
+ if (isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ } else {
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+ }
+
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset);
+ }
+ } else {
+ // Heuristic to detect late SCI1.1 map format
+ if ((mapRes->size >= 11) && (ptr[mapRes->size - 11] == 0xff))
+ isEarly = false;
+
+ if (!isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ }
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint32 n = READ_BE_UINT32(ptr);
+ int syncSize = 0;
+ ptr += 4;
+
+ if (n == 0xffffffff)
+ break;
+
+ if (isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ } else {
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+ }
+
+ if (isEarly || (n & 0x80)) {
+ syncSize = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (syncSize > 0)
+ addResource(ResourceId(kResourceTypeSync36, map->volume_number, n & 0xffffff3f), src, offset, syncSize);
+ }
+
+ if (n & 0x40) {
+ syncSize += READ_LE_UINT16(ptr);
+ ptr += 2;
+ }
+
+ addResource(ResourceId(kResourceTypeAudio36, map->volume_number, n & 0xffffff3f), src, offset + syncSize);
+ }
+ }
+
+ return 0;
+}
+
+// AUDIOnnn.MAP contains 10-byte entries:
+// Early format:
+// w 5 bits resource type and 11 bits resource number
+// dw 7 bits volume number and 25 bits offset
+// dw size
+// Later format:
+// w nEntry
+// dw offset+volume (as in resource.map)
+// dw size
+// ending with 10 0xFFs
+int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
+ Common::File file;
+
+ if (!file.open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+
+ bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
+ file.seek(0);
+
+ while (1) {
+ uint16 n = file.readUint16LE();
+ uint32 offset = file.readUint32LE();
+ uint32 size = file.readUint32LE();
+
+ if (file.eos() || file.err()) {
+ warning("Error while reading %s", map->location_name.c_str());
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ if (n == 0xffff)
+ break;
+
+ byte volume_nr;
+
+ if (oldFormat) {
+ n &= 0x07ff; // Mask out resource type
+ volume_nr = offset >> 25; // most significant 7 bits
+ offset &= 0x01ffffff; // least significant 25 bits
+ } else {
+ volume_nr = offset >> 28; // most significant 4 bits
+ offset &= 0x0fffffff; // least significant 28 bits
+ }
+
+ ResourceSource *src = getVolume(map, volume_nr);
+
+ if (src) {
+ if (unload)
+ removeAudioResource(ResourceId(kResourceTypeAudio, n));
+ else
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
+ } else {
+ warning("Failed to find audio volume %i", volume_nr);
+ }
+ }
+
+ return 0;
+}
+
+void ResourceManager::setAudioLanguage(int language) {
+ if (_audioMapSCI1) {
+ if (_audioMapSCI1->volume_number == language) {
+ // This language is already loaded
+ return;
+ }
+
+ // We already have a map loaded, so we unload it first
+ readAudioMapSCI1(_audioMapSCI1, true);
+
+ // Remove all volumes that use this map from the source list
+ Common::List<ResourceSource *>::iterator it = _sources.begin();
+ while (it != _sources.end()) {
+ ResourceSource *src = *it;
+ if (src->associated_map == _audioMapSCI1) {
+ it = _sources.erase(it);
+ delete src;
+ } else {
+ ++it;
+ }
+ }
+
+ // Remove the map itself from the source list
+ _sources.remove(_audioMapSCI1);
+ delete _audioMapSCI1;
+
+ _audioMapSCI1 = NULL;
+ }
+
+ char filename[9];
+ snprintf(filename, 9, "AUDIO%03d", language);
+
+ Common::String fullname = Common::String(filename) + ".MAP";
+ if (!Common::File::exists(fullname)) {
+ warning("No audio map found for language %i", language);
+ return;
+ }
+
+ _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
+
+ // Search for audio volumes for this language and add them to the source list
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ const Common::String name = (*x)->getName();
+ const char *dot = strrchr(name.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
+ }
+
+ scanNewSources();
+}
+
+int ResourceManager::getAudioLanguage() const {
+ return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0);
+}
+
int ResourceManager::readResourceInfo(Resource *res, Common::SeekableReadStream *file,
uint32&szPacked, ResourceCompression &compression) {
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
@@ -1949,98 +2329,248 @@ bool ResourceManager::hasSci1Voc900() {
return offset == res->size;
}
-// Same function as Script::findBlock(). Slight code
-// duplication here, but this has been done to keep the resource
-// manager independent from the rest of the engine
-static byte *findSci0ExportsBlock(byte *buffer) {
- byte *buf = buffer;
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) {
+ Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true);
+ int trackNr, channelNr;
+ if (!resource)
+ return;
- if (oldScriptHeader)
- buf += 2;
+ _innerResource = resource;
- do {
- int seekerType = READ_LE_UINT16(buf);
+ byte *data, *data2;
+ byte *dataEnd;
+ Channel *channel, *sampleChannel;
- if (seekerType == 0)
- break;
- if (seekerType == 7) // exports
- return buf;
+ switch (_soundVersion) {
+ case SCI_VERSION_0_EARLY:
+ case SCI_VERSION_0_LATE:
+ // SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
+ _trackCount = 1;
+ _tracks = new Track[_trackCount];
+ _tracks->digitalChannelNr = -1;
+ _tracks->type = 0; // Not used for SCI0
+ _tracks->channelCount = 1;
+ // Digital sample data included? -> Add an additional channel
+ if (resource->data[0] == 2)
+ _tracks->channelCount++;
+ _tracks->channels = new Channel[_tracks->channelCount];
+ memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
+ channel = &_tracks->channels[0];
+ if (_soundVersion == SCI_VERSION_0_EARLY) {
+ channel->data = resource->data + 0x11;
+ channel->size = resource->size - 0x11;
+ } else {
+ channel->data = resource->data + 0x21;
+ channel->size = resource->size - 0x21;
+ }
+ if (_tracks->channelCount == 2) {
+ // Digital sample data included
+ _tracks->digitalChannelNr = 1;
+ sampleChannel = &_tracks->channels[1];
+ // we need to find 0xFC (channel terminator) within the data
+ data = channel->data;
+ dataEnd = channel->data + channel->size;
+ while ((data < dataEnd) && (*data != 0xfc))
+ data++;
+ // Skip any following 0xFCs as well
+ while ((data < dataEnd) && (*data == 0xfc))
+ data++;
+ // Now adjust channels accordingly
+ sampleChannel->data = data;
+ sampleChannel->size = channel->size - (data - channel->data);
+ channel->size = data - channel->data;
+ // Read sample header information
+ //Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
+ _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
+ _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
+ _tracks->digitalSampleStart = 0;
+ _tracks->digitalSampleEnd = 0;
+ sampleChannel->data += 44; // Skip over header
+ sampleChannel->size -= 44;
+ }
+ break;
- int seekerSize = READ_LE_UINT16(buf + 2);
- assert(seekerSize > 0);
- buf += seekerSize;
- } while (1);
+ case SCI_VERSION_1_EARLY:
+ case SCI_VERSION_1_LATE:
+ data = resource->data;
+ // Count # of tracks
+ _trackCount = 0;
+ while ((*data++) != 0xFF) {
+ _trackCount++;
+ while (*data != 0xFF)
+ data += 6;
+ data++;
+ }
+ _tracks = new Track[_trackCount];
+ data = resource->data;
+ for (trackNr = 0; trackNr < _trackCount; trackNr++) {
+ // Track info starts with track type:BYTE
+ // Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
+ // 0xFF:BYTE as terminator to end that track and begin with another track type
+ // Track type 0xFF is the marker signifying the end of the tracks
+
+ _tracks[trackNr].type = *data++;
+ // Counting # of channels used
+ data2 = data;
+ _tracks[trackNr].channelCount = 0;
+ while (*data2 != 0xFF) {
+ data2 += 6;
+ _tracks[trackNr].channelCount++;
+ }
+ _tracks[trackNr].channels = new Channel[_tracks[trackNr].channelCount];
+ _tracks[trackNr].digitalChannelNr = -1; // No digital sound associated
+ _tracks[trackNr].digitalSampleRate = 0;
+ _tracks[trackNr].digitalSampleSize = 0;
+ _tracks[trackNr].digitalSampleStart = 0;
+ _tracks[trackNr].digitalSampleEnd = 0;
+ if (_tracks[trackNr].type != 0xF0) { // Digital track marker - not supported currently
+ for (channelNr = 0; channelNr < _tracks[trackNr].channelCount; channelNr++) {
+ channel = &_tracks[trackNr].channels[channelNr];
+ channel->prio = READ_LE_UINT16(data);
+ channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
+ channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
+ channel->number = *(channel->data - 2);
+ channel->poly = *(channel->data - 1);
+ channel->time = channel->prev = 0;
+ if (channel->number == 0xFE) { // Digital channel
+ _tracks[trackNr].digitalChannelNr = channelNr;
+ _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
+ _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
+ _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
+ _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
+ channel->data += 8; // Skip over header
+ channel->size -= 8;
+ }
+ data += 6;
+ }
+ } else {
+ // Skip over digital track
+ data += 6;
+ }
+ data++; // Skipping 0xFF that closes channels list
+ }
+ break;
- return NULL;
+ default:
+ error("SoundResource: SCI version %d is unsupported", _soundVersion);
+ }
}
-reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
- Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false);
-
- if (!script)
- return NULL_REG;
+SoundResource::~SoundResource() {
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++)
+ delete[] _tracks[trackNr].channels;
+ delete[] _tracks;
- byte *offsetPtr = 0;
+ _resMan->unlockResource(_innerResource);
+}
- if (getSciVersion() < SCI_VERSION_1_1) {
- byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data;
+#if 0
+SoundResource::Track* SoundResource::getTrackByNumber(uint16 number) {
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return &_tracks[0];
- // Check if the first block is the exports block (in most cases, it is)
- bool exportsIsFirst = (READ_LE_UINT16(buf + 4) == 7);
- if (exportsIsFirst) {
- offsetPtr = buf + 4 + 2;
- } else {
- offsetPtr = findSci0ExportsBlock(script->data);
- if (!offsetPtr)
- error("Unable to find exports block from script 0");
- offsetPtr += 4 + 2;
- }
- } else {
- offsetPtr = script->data + 4 + 2 + 2;
- }
-
- int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ if (/*number >= 0 &&*/number < _trackCount)
+ return &_tracks[number];
+ return NULL;
+}
+#endif
- // In SCI1.1 and newer, the heap is appended at the end of the script,
- // so adjust the offset accordingly
- if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) {
- offset += script->size;
+SoundResource::Track *SoundResource::getTrackByType(byte type) {
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return &_tracks[0];
- // Ensure that the start of the heap is word-aligned - same as in Script::init()
- if (script->size & 2)
- offset++;
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
+ if (_tracks[trackNr].type == type)
+ return &_tracks[trackNr];
}
+ return NULL;
+}
- return make_reg(1, offset);
+SoundResource::Track *SoundResource::getDigitalTrack() {
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
+ if (_tracks[trackNr].digitalChannelNr != -1)
+ return &_tracks[trackNr];
+ }
+ return NULL;
}
-Common::String ResourceManager::findSierraGameId() {
- // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated
- Resource *heap = 0;
- int nameSelector = 3;
+// Gets the filter mask for SCI0 sound resources
+int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
+ byte *data = _innerResource->data;
+ int channelMask = 0;
- if (getSciVersion() < SCI_VERSION_1_1) {
- heap = findResource(ResourceId(kResourceTypeScript, 0), false);
- } else {
- heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
- nameSelector += 5;
+ if (_soundVersion > SCI_VERSION_0_LATE)
+ return 0;
+
+ data++; // Skip over digital sample flag
+
+ for (int channelNr = 0; channelNr < 16; channelNr++) {
+ channelMask = channelMask >> 1;
+
+ byte flags;
+
+ if (_soundVersion == SCI_VERSION_0_EARLY) {
+ // Each channel is specified by a single byte
+ // Upper 4 bits of the byte is a voices count
+ // Lower 4 bits -> bit 0 set: use for AdLib
+ // bit 1 set: use for PCjr
+ // bit 2 set: use for PC speaker
+ // bit 3 set and bit 0 clear: control channel (15)
+ // bit 3 set and bit 0 set: rhythm channel (9)
+ // Note: control channel is dynamically assigned inside the drivers,
+ // but seems to be fixed at 15 in the song data.
+ flags = *data++;
+
+ // Get device bits
+ flags &= 0x7;
+ } else {
+ // Each channel is specified by 2 bytes
+ // 1st byte is voices count
+ // 2nd byte is play mask, which specifies if the channel is supposed to be played
+ // by the corresponding hardware
+
+ // Skip voice count
+ data++;
+
+ flags = *data++;
+ }
+
+ bool play;
+ switch (channelNr) {
+ case 15:
+ // Always play control channel
+ play = true;
+ break;
+ case 9:
+ // Play rhythm channel when requested
+ play = wantsRhythm;
+ break;
+ default:
+ // Otherwise check for flag
+ play = flags & hardwareMask;
+ }
+
+ if (play) {
+ // This Channel is supposed to be played by the hardware
+ channelMask |= 0x8000;
+ }
}
- if (!heap)
- return "";
+ return channelMask;
+}
- int16 gameObjectOffset = findGameObject(false).offset;
+byte SoundResource::getInitialVoiceCount(byte channel) {
+ byte *data = _innerResource->data;
- if (!gameObjectOffset)
- return "";
+ if (_soundVersion > SCI_VERSION_0_LATE)
+ return 0; // TODO
- // Seek to the name selector of the first export
- byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2);
- Common::String sierraId;
- sierraId += (const char *)seeker;
+ data++; // Skip over digital sample flag
- return sierraId;
+ if (_soundVersion == SCI_VERSION_0_EARLY)
+ return data[channel] >> 4;
+ else
+ return data[channel * 2];
}
} // End of namespace Sci
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index bc08154fed..48b5f095b1 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -26,9 +26,8 @@
#ifndef SCI_SCICORE_RESOURCE_H
#define SCI_SCICORE_RESOURCE_H
-#include "common/fs.h"
-#include "common/macresman.h"
#include "common/str.h"
+#include "common/fs.h"
#include "sci/graphics/helpers.h" // for ViewType
#include "sci/decompressor.h"
@@ -109,31 +108,14 @@ enum ResourceType {
kResourceTypeUnknown1, // Translation, currently unsupported
kResourceTypeUnknown2,
kResourceTypeRobot,
- kResourceTypeInvalid,
-
- // Mac-only resources, these resource types are self-defined
- // Numbers subject to change
- kResourceTypeMacIconBarPictN = -1, // IBIN resources (icon bar, not selected)
- kResourceTypeMacIconBarPictS = -2, // IBIS resources (icon bar, selected)
- kResourceTypeMacPict = -3 // PICT resources (inventory)
+ kResourceTypeInvalid
};
const char *getResourceTypeName(ResourceType restype);
class ResourceManager;
-
-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;
- uint32 audioCompressionType;
- int32 *audioCompressionOffsetMapping;
- Common::MacResManager macResMan;
-};
+struct ResourceSource;
class ResourceId {
public:
@@ -145,7 +127,7 @@ public:
ResourceId(ResourceType type_, uint16 number_, uint32 tuple_ = 0)
: type(type_), number(number_), tuple(tuple_) {
- if (type < kResourceTypeMacPict || type > kResourceTypeInvalid)
+ if ((type < kResourceTypeView) || (type > kResourceTypeInvalid))
type = kResourceTypeInvalid;
}
@@ -291,19 +273,6 @@ public:
// Detects, if standard font of current game includes extended characters (>0x80)
bool detectFontExtended();
- /**
- * Finds the internal Sierra ID of the current game from script 0
- */
- Common::String findSierraGameId();
-
- /**
- * Finds the location of the game object from script 0
- * @param addSci11ScriptOffset: Adjust the return value for SCI1.1 and newer
- * games. Needs to be false when the heap is accessed directly inside
- * findSierraGameId().
- */
- reg_t findGameObject(bool addSci11ScriptOffset = true);
-
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
@@ -321,8 +290,8 @@ protected:
ResourceMap _resMap;
Common::List<Common::File *> _volumeFiles; ///< list of opened volume files
ResourceSource *_audioMapSCI1; ///< Currently loaded audio map for SCI1
- ResVersion _volVersion; ///< resource.0xx version
- ResVersion _mapVersion; ///< resource.map version
+ ResVersion _volVersion; ///< RESOURCE.0xx version
+ ResVersion _mapVersion; ///< RESOURCE.MAP version
/**
* Initializes the resource manager
@@ -358,7 +327,7 @@ protected:
*/
ResourceSource *addExternalMap(const char *file_name, int volume_nr = 0);
- ResourceSource *addExternalMap(const Common::FSNode *mapFile, int volume_nr = 0);
+ ResourceSource *addExternalMap(const Common::FSNode *mapFile);
/**
* Add an internal (i.e., resource) map to the resource manager's list of sources.
@@ -395,11 +364,11 @@ protected:
Common::File *getVolumeFile(const char *filename);
void loadResource(Resource *res);
- bool loadPatch(Resource *res, Common::SeekableReadStream *file);
+ bool loadPatch(Resource *res, Common::File &file);
bool loadFromPatchFile(Resource *res);
- bool loadFromWaveFile(Resource *res, Common::SeekableReadStream *file);
- bool loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file);
- bool loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromWaveFile(Resource *res, Common::File &file);
+ bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file);
+ bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file);
void freeOldResources();
int decompress(Resource *res, Common::SeekableReadStream *file);
int readResourceInfo(Resource *res, Common::SeekableReadStream *file, uint32&szPacked, ResourceCompression &compression);
@@ -512,7 +481,6 @@ public:
Track *getDigitalTrack();
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
byte getInitialVoiceCount(byte channel);
- bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
private:
SciVersion _soundVersion;
@@ -520,9 +488,6 @@ private:
Track *_tracks;
Resource *_innerResource;
ResourceManager *_resMan;
- uint16 _channelsUsed;
-
- void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
};
} // End of namespace Sci
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
deleted file mode 100644
index 67bac974fc..0000000000
--- a/engines/sci/resource_audio.cpp
+++ /dev/null
@@ -1,706 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// Resource library
-
-#include "common/file.h"
-
-#include "sci/resource.h"
-#include "sci/util.h"
-
-namespace Sci {
-
-void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
- Common::File *file = getVolumeFile(source->location_name.c_str());
- if (!file) {
- warning("Failed to open %s", source->location_name.c_str());
- return;
- }
- file->seek(0, SEEK_SET);
- uint32 compressionType = file->readUint32BE();
- switch (compressionType) {
- case MKID_BE('MP3 '):
- case MKID_BE('OGG '):
- case MKID_BE('FLAC'):
- // Detected a compressed audio volume
- source->audioCompressionType = compressionType;
- // Now read the whole offset mapping table for later usage
- int32 recordCount = file->readUint32LE();
- if (!recordCount)
- error("compressed audio volume doesn't contain any entries!");
- int32 *offsetMapping = new int32[(recordCount + 1) * 2];
- source->audioCompressionOffsetMapping = offsetMapping;
- for (int recordNo = 0; recordNo < recordCount; recordNo++) {
- *offsetMapping++ = file->readUint32LE();
- *offsetMapping++ = file->readUint32LE();
- }
- // Put ending zero
- *offsetMapping++ = 0;
- *offsetMapping++ = file->size();
- }
-}
-
-bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) {
- res->data = new byte[res->size];
-
- uint32 really_read = file->read(res->data, res->size);
- if (really_read != res->size)
- error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
-
- res->_status = kResStatusAllocated;
- return true;
-}
-
-bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file) {
- // Check for WAVE files here
- uint32 riffTag = file->readUint32BE();
- if (riffTag == MKID_BE('RIFF')) {
- res->_headerSize = 0;
- res->size = file->readUint32LE();
- file->seek(-8, SEEK_CUR);
- return loadFromWaveFile(res, file);
- }
- file->seek(-4, SEEK_CUR);
-
- ResourceType type = (ResourceType)(file->readByte() & 0x7f);
- if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
- || ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
- warning("Resource type mismatch loading %s", res->_id.toString().c_str());
- res->unalloc();
- return false;
- }
-
- res->_headerSize = file->readByte();
-
- if (type == kResourceTypeAudio) {
- if (res->_headerSize != 11 && res->_headerSize != 12) {
- warning("Unsupported audio header");
- res->unalloc();
- return false;
- }
-
- // Load sample size
- file->seek(7, SEEK_CUR);
- res->size = file->readUint32LE();
- // Adjust offset to point at the header data again
- file->seek(-11, SEEK_CUR);
- }
-
- return loadPatch(res, file);
-}
-
-bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file) {
- res->data = new byte[res->size];
-
- if (res->data == NULL) {
- error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
- }
-
- unsigned int really_read = file->read(res->data, res->size);
- if (really_read != res->size)
- warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
-
- res->_status = kResStatusAllocated;
- return true;
-}
-
-void ResourceManager::addNewGMPatch(const Common::String &gameId) {
- Common::String gmPatchFile;
-
- if (gameId == "ecoquest")
- gmPatchFile = "ECO1GM.PAT";
- else if (gameId == "hoyle3")
- gmPatchFile = "HOY3GM.PAT";
- else if (gameId == "hoyle3")
- gmPatchFile = "HOY3GM.PAT";
- else if (gameId == "lsl1sci")
- gmPatchFile = "LL1_GM.PAT";
- else if (gameId == "lsl5")
- gmPatchFile = "LL5_GM.PAT";
- else if (gameId == "longbow")
- gmPatchFile = "ROBNGM.PAT";
- else if (gameId == "sq1sci")
- gmPatchFile = "SQ1_GM.PAT";
- else if (gameId == "sq4")
- gmPatchFile = "SQ4_GM.PAT";
- else if (gameId == "fairytales")
- gmPatchFile = "TALEGM.PAT";
-
- if (!gmPatchFile.empty() && Common::File::exists(gmPatchFile)) {
- ResourceSource *psrcPatch = new ResourceSource;
- psrcPatch->source_type = kSourcePatch;
- psrcPatch->resourceFile = 0;
- psrcPatch->location_name = gmPatchFile;
- processPatch(psrcPatch, kResourceTypePatch, 4);
- }
-}
-
-void ResourceManager::readWaveAudioPatches() {
- // Here we do check for SCI1.1+ so we can patch wav files in as audio resources
- Common::ArchiveMemberList files;
- SearchMan.listMatchingMembers(files, "*.wav");
-
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- Common::String name = (*x)->getName();
-
- if (isdigit(name[0])) {
- int number = atoi(name.c_str());
- ResourceSource *psrcPatch = new ResourceSource;
- psrcPatch->source_type = kSourceWave;
- psrcPatch->resourceFile = 0;
- psrcPatch->location_name = name;
- psrcPatch->volume_number = 0;
- psrcPatch->audioCompressionType = 0;
-
- ResourceId resId = ResourceId(kResourceTypeAudio, number);
-
- Resource *newrsc = NULL;
-
- // Prepare destination, if neccessary
- if (_resMap.contains(resId) == false) {
- newrsc = new Resource;
- _resMap.setVal(resId, newrsc);
- } else
- newrsc = _resMap.getVal(resId);
-
- // Get the size of the file
- Common::SeekableReadStream *stream = (*x)->createReadStream();
- uint32 fileSize = stream->size();
- delete stream;
-
- // Overwrite everything, because we're patching
- newrsc->_id = resId;
- newrsc->_status = kResStatusNoMalloc;
- newrsc->_source = psrcPatch;
- newrsc->size = fileSize;
- newrsc->_headerSize = 0;
- debugC(1, kDebugLevelResMan, "Patching %s - OK", psrcPatch->location_name.c_str());
- }
- }
-}
-
-void ResourceManager::removeAudioResource(ResourceId resId) {
- // Remove resource, unless it was loaded from a patch
- if (_resMap.contains(resId)) {
- Resource *res = _resMap.getVal(resId);
-
- if (res->_source->source_type == kSourceAudioVolume) {
- if (res->_status == kResStatusLocked) {
- warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
- } else {
- if (res->_status == kResStatusEnqueued)
- removeFromLRU(res);
-
- _resMap.erase(resId);
- delete res;
- }
- }
- }
-}
-
-// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
-// =========
-// 6-byte entries:
-// w nEntry
-// dw offset
-
-// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
-// =========
-// 5-byte entries:
-// w nEntry
-// tb offset (cumulative)
-
-// Early SCI1.1 MAP structure:
-// ===============
-// 10-byte entries:
-// b noun
-// b verb
-// b cond
-// b seq
-// dw offset
-// w syncSize + syncAscSize
-
-// Late SCI1.1 MAP structure:
-// ===============
-// Header:
-// dw baseOffset
-// Followed by 7 or 11-byte entries:
-// b noun
-// b verb
-// b cond
-// b seq
-// tb cOffset (cumulative offset)
-// w syncSize (iff seq has bit 7 set)
-// w syncAscSize (iff seq has bit 6 set)
-
-int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
- bool isEarly = true;
- uint32 offset = 0;
- Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
-
- if (!mapRes) {
- warning("Failed to open %i.MAP", map->volume_number);
- return SCI_ERROR_RESMAP_NOT_FOUND;
- }
-
- ResourceSource *src = getVolume(map, 0);
-
- if (!src)
- return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
-
- byte *ptr = mapRes->data;
-
- if (map->volume_number == 65535) {
- // Heuristic to detect late SCI1.1 map format
- if ((mapRes->size >= 6) && (ptr[mapRes->size - 6] != 0xff))
- isEarly = false;
-
- while (ptr < mapRes->data + mapRes->size) {
- uint16 n = READ_LE_UINT16(ptr);
- ptr += 2;
-
- if (n == 0xffff)
- break;
-
- if (isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- } else {
- offset += READ_LE_UINT24(ptr);
- ptr += 3;
- }
-
- addResource(ResourceId(kResourceTypeAudio, n), src, offset);
- }
- } else {
- // Heuristic to detect late SCI1.1 map format
- if ((mapRes->size >= 11) && (ptr[mapRes->size - 11] == 0xff))
- isEarly = false;
-
- if (!isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- }
-
- while (ptr < mapRes->data + mapRes->size) {
- uint32 n = READ_BE_UINT32(ptr);
- int syncSize = 0;
- ptr += 4;
-
- if (n == 0xffffffff)
- break;
-
- if (isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- } else {
- offset += READ_LE_UINT24(ptr);
- ptr += 3;
- }
-
- if (isEarly || (n & 0x80)) {
- syncSize = READ_LE_UINT16(ptr);
- ptr += 2;
-
- if (syncSize > 0)
- addResource(ResourceId(kResourceTypeSync36, map->volume_number, n & 0xffffff3f), src, offset, syncSize);
- }
-
- if (n & 0x40) {
- syncSize += READ_LE_UINT16(ptr);
- ptr += 2;
- }
-
- addResource(ResourceId(kResourceTypeAudio36, map->volume_number, n & 0xffffff3f), src, offset + syncSize);
- }
- }
-
- return 0;
-}
-
-// AUDIOnnn.MAP contains 10-byte entries:
-// Early format:
-// w 5 bits resource type and 11 bits resource number
-// dw 7 bits volume number and 25 bits offset
-// dw size
-// Later format:
-// w nEntry
-// dw offset+volume (as in resource.map)
-// dw size
-// ending with 10 0xFFs
-int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
- Common::File file;
-
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
-
- bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
- file.seek(0);
-
- while (1) {
- uint16 n = file.readUint16LE();
- uint32 offset = file.readUint32LE();
- uint32 size = file.readUint32LE();
-
- if (file.eos() || file.err()) {
- warning("Error while reading %s", map->location_name.c_str());
- return SCI_ERROR_RESMAP_NOT_FOUND;
- }
-
- if (n == 0xffff)
- break;
-
- byte volume_nr;
-
- if (oldFormat) {
- n &= 0x07ff; // Mask out resource type
- volume_nr = offset >> 25; // most significant 7 bits
- offset &= 0x01ffffff; // least significant 25 bits
- } else {
- volume_nr = offset >> 28; // most significant 4 bits
- offset &= 0x0fffffff; // least significant 28 bits
- }
-
- ResourceSource *src = getVolume(map, volume_nr);
-
- if (src) {
- if (unload)
- removeAudioResource(ResourceId(kResourceTypeAudio, n));
- else
- addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
- } else {
- warning("Failed to find audio volume %i", volume_nr);
- }
- }
-
- return 0;
-}
-
-void ResourceManager::setAudioLanguage(int language) {
- if (_audioMapSCI1) {
- if (_audioMapSCI1->volume_number == language) {
- // This language is already loaded
- return;
- }
-
- // We already have a map loaded, so we unload it first
- readAudioMapSCI1(_audioMapSCI1, true);
-
- // Remove all volumes that use this map from the source list
- Common::List<ResourceSource *>::iterator it = _sources.begin();
- while (it != _sources.end()) {
- ResourceSource *src = *it;
- if (src->associated_map == _audioMapSCI1) {
- it = _sources.erase(it);
- delete src;
- } else {
- ++it;
- }
- }
-
- // Remove the map itself from the source list
- _sources.remove(_audioMapSCI1);
- delete _audioMapSCI1;
-
- _audioMapSCI1 = NULL;
- }
-
- char filename[9];
- snprintf(filename, 9, "AUDIO%03d", language);
-
- Common::String fullname = Common::String(filename) + ".MAP";
- if (!Common::File::exists(fullname)) {
- warning("No audio map found for language %i", language);
- return;
- }
-
- _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
-
- // Search for audio volumes for this language and add them to the source list
- Common::ArchiveMemberList files;
- SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- const Common::String name = (*x)->getName();
- const char *dot = strrchr(name.c_str(), '.');
- int number = atoi(dot + 1);
-
- addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
- }
-
- scanNewSources();
-}
-
-int ResourceManager::getAudioLanguage() const {
- return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0);
-}
-
-SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) {
- Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true);
- int trackNr, channelNr;
- if (!resource)
- return;
-
- _innerResource = resource;
-
- byte *data, *data2;
- byte *dataEnd;
- Channel *channel, *sampleChannel;
-
- _channelsUsed = 0;
-
- switch (_soundVersion) {
- case SCI_VERSION_0_EARLY:
- case SCI_VERSION_0_LATE:
- // SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
- _trackCount = 1;
- _tracks = new Track[_trackCount];
- _tracks->digitalChannelNr = -1;
- _tracks->type = 0; // Not used for SCI0
- _tracks->channelCount = 1;
- // Digital sample data included? -> Add an additional channel
- if (resource->data[0] == 2)
- _tracks->channelCount++;
- _tracks->channels = new Channel[_tracks->channelCount];
- memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
- channel = &_tracks->channels[0];
- if (_soundVersion == SCI_VERSION_0_EARLY) {
- channel->data = resource->data + 0x11;
- channel->size = resource->size - 0x11;
- } else {
- channel->data = resource->data + 0x21;
- channel->size = resource->size - 0x21;
- }
- if (_tracks->channelCount == 2) {
- // Digital sample data included
- _tracks->digitalChannelNr = 1;
- sampleChannel = &_tracks->channels[1];
- // we need to find 0xFC (channel terminator) within the data
- data = channel->data;
- dataEnd = channel->data + channel->size;
- while ((data < dataEnd) && (*data != 0xfc))
- data++;
- // Skip any following 0xFCs as well
- while ((data < dataEnd) && (*data == 0xfc))
- data++;
- // Now adjust channels accordingly
- sampleChannel->data = data;
- sampleChannel->size = channel->size - (data - channel->data);
- channel->size = data - channel->data;
- // Read sample header information
- //Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
- _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
- _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
- _tracks->digitalSampleStart = 0;
- _tracks->digitalSampleEnd = 0;
- sampleChannel->data += 44; // Skip over header
- sampleChannel->size -= 44;
- }
- break;
-
- case SCI_VERSION_1_EARLY:
- case SCI_VERSION_1_LATE:
- data = resource->data;
- // Count # of tracks
- _trackCount = 0;
- while ((*data++) != 0xFF) {
- _trackCount++;
- while (*data != 0xFF)
- data += 6;
- data++;
- }
- _tracks = new Track[_trackCount];
- data = resource->data;
- for (trackNr = 0; trackNr < _trackCount; trackNr++) {
- // Track info starts with track type:BYTE
- // Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
- // 0xFF:BYTE as terminator to end that track and begin with another track type
- // Track type 0xFF is the marker signifying the end of the tracks
-
- _tracks[trackNr].type = *data++;
- // Counting # of channels used
- data2 = data;
- _tracks[trackNr].channelCount = 0;
- while (*data2 != 0xFF) {
- data2 += 6;
- _tracks[trackNr].channelCount++;
- }
- _tracks[trackNr].channels = new Channel[_tracks[trackNr].channelCount];
- _tracks[trackNr].digitalChannelNr = -1; // No digital sound associated
- _tracks[trackNr].digitalSampleRate = 0;
- _tracks[trackNr].digitalSampleSize = 0;
- _tracks[trackNr].digitalSampleStart = 0;
- _tracks[trackNr].digitalSampleEnd = 0;
- if (_tracks[trackNr].type != 0xF0) { // Digital track marker - not supported currently
- for (channelNr = 0; channelNr < _tracks[trackNr].channelCount; channelNr++) {
- channel = &_tracks[trackNr].channels[channelNr];
- channel->prio = READ_LE_UINT16(data);
- channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
- channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
- channel->number = *(channel->data - 2);
- setChannelUsed(channel->number);
- channel->poly = *(channel->data - 1);
- channel->time = channel->prev = 0;
- if (channel->number == 0xFE) { // Digital channel
- _tracks[trackNr].digitalChannelNr = channelNr;
- _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
- _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
- _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
- _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
- channel->data += 8; // Skip over header
- channel->size -= 8;
- }
- data += 6;
- }
- } else {
- // Skip over digital track
- data += 6;
- }
- data++; // Skipping 0xFF that closes channels list
- }
- break;
-
- default:
- error("SoundResource: SCI version %d is unsupported", _soundVersion);
- }
-}
-
-SoundResource::~SoundResource() {
- for (int trackNr = 0; trackNr < _trackCount; trackNr++)
- delete[] _tracks[trackNr].channels;
- delete[] _tracks;
-
- _resMan->unlockResource(_innerResource);
-}
-
-#if 0
-SoundResource::Track* SoundResource::getTrackByNumber(uint16 number) {
- if (_soundVersion <= SCI_VERSION_0_LATE)
- return &_tracks[0];
-
- if (/*number >= 0 &&*/number < _trackCount)
- return &_tracks[number];
- return NULL;
-}
-#endif
-
-SoundResource::Track *SoundResource::getTrackByType(byte type) {
- if (_soundVersion <= SCI_VERSION_0_LATE)
- return &_tracks[0];
-
- for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
- if (_tracks[trackNr].type == type)
- return &_tracks[trackNr];
- }
- return NULL;
-}
-
-SoundResource::Track *SoundResource::getDigitalTrack() {
- for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
- if (_tracks[trackNr].digitalChannelNr != -1)
- return &_tracks[trackNr];
- }
- return NULL;
-}
-
-// Gets the filter mask for SCI0 sound resources
-int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
- byte *data = _innerResource->data;
- int channelMask = 0;
-
- if (_soundVersion > SCI_VERSION_0_LATE)
- return 0;
-
- data++; // Skip over digital sample flag
-
- for (int channelNr = 0; channelNr < 16; channelNr++) {
- channelMask = channelMask >> 1;
-
- byte flags;
-
- if (_soundVersion == SCI_VERSION_0_EARLY) {
- // Each channel is specified by a single byte
- // Upper 4 bits of the byte is a voices count
- // Lower 4 bits -> bit 0 set: use for AdLib
- // bit 1 set: use for PCjr
- // bit 2 set: use for PC speaker
- // bit 3 set and bit 0 clear: control channel (15)
- // bit 3 set and bit 0 set: rhythm channel (9)
- // Note: control channel is dynamically assigned inside the drivers,
- // but seems to be fixed at 15 in the song data.
- flags = *data++;
-
- // Get device bits
- flags &= 0x7;
- } else {
- // Each channel is specified by 2 bytes
- // 1st byte is voices count
- // 2nd byte is play mask, which specifies if the channel is supposed to be played
- // by the corresponding hardware
-
- // Skip voice count
- data++;
-
- flags = *data++;
- }
-
- bool play;
- switch (channelNr) {
- case 15:
- // Always play control channel
- play = true;
- break;
- case 9:
- // Play rhythm channel when requested
- play = wantsRhythm;
- break;
- default:
- // Otherwise check for flag
- play = flags & hardwareMask;
- }
-
- if (play) {
- // This Channel is supposed to be played by the hardware
- channelMask |= 0x8000;
- }
- }
-
- return channelMask;
-}
-
-byte SoundResource::getInitialVoiceCount(byte channel) {
- byte *data = _innerResource->data;
-
- if (_soundVersion > SCI_VERSION_0_LATE)
- return 0; // TODO
-
- data++; // Skip over digital sample flag
-
- if (_soundVersion == SCI_VERSION_0_EARLY)
- return data[channel] >> 4;
- else
- return data[channel * 2];
-}
-
-} // End of namespace Sci
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 1de42ab115..4862d0579a 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -43,7 +43,6 @@
#include "sci/sound/audio.h"
#include "sci/sound/soundcmd.h"
#include "sci/graphics/gui.h"
-#include "sci/graphics/maciconbar.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/cursor.h"
@@ -98,7 +97,6 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc)
DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game");
_gamestate = 0;
- _gfxMacIconBar = 0;
const Common::FSNode gameDataDir(ConfMan.get("path"));
@@ -126,7 +124,6 @@ SciEngine::~SciEngine() {
delete _console;
delete _resMan;
delete _features;
- delete _gfxMacIconBar;
g_sci = 0;
}
@@ -173,9 +170,6 @@ Common::Error SciEngine::run() {
else
screen = new GfxScreen(_resMan, 320, 200, upscaledHires);
- if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1)
- _gfxMacIconBar = new GfxMacIconBar();
-
GfxPalette *palette = new GfxPalette(_resMan, screen);
GfxCache *cache = new GfxCache(_resMan, screen, palette);
GfxCursor *cursor = new GfxCursor(_resMan, palette, screen);
@@ -190,7 +184,7 @@ Common::Error SciEngine::run() {
_features = new GameFeatures(segMan, _kernel);
- _gamestate = new EngineState(segMan);
+ _gamestate = new EngineState(_vocabulary, segMan);
_gamestate->_event = new SciEvent(_resMan);
@@ -228,11 +222,16 @@ Common::Error SciEngine::run() {
}
// Add the after market GM patches for the specified game, if they exist
- _resMan->addNewGMPatch(getGameID());
+ _resMan->addNewGMPatch(_gamestate->_gameId);
script_adjust_opcode_formats(_gamestate);
_kernel->loadKernelNames(getGameID());
+ // Set the savegame dir (actually, we set it to a fake value,
+ // since we cannot let the game control where saves are stored)
+ assert(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value != 0);
+ strcpy(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value, "");
+
SciVersion soundVersion = _features->detectDoSoundType();
_gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, soundVersion);
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 685f05e685..fdd10bcd04 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -65,7 +65,7 @@ class GfxPalette;
class GfxPorts;
class GfxScreen;
class SciGui;
-class GfxMacIconBar;
+
#ifdef ENABLE_SCI32
class SciGui32;
@@ -206,7 +206,6 @@ public:
GfxPorts *_gfxPorts; // Port managment for 16-bit gfx
GfxScreen *_gfxScreen;
SciGui *_gui; /* Currently active Gui */
- GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager
#ifdef ENABLE_SCI32
SciGui32 *_gui32; // GUI for SCI32 games
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 7748c0505b..331561eea4 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -235,7 +235,6 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
uint32 audioCompressionType = audioRes->getAudioCompressionType();
if (audioCompressionType) {
-#if (defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC))
// Compressed audio made by our tool
byte *compressedData = (byte *)malloc(audioRes->size);
assert(compressedData);
@@ -262,9 +261,6 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
#endif
break;
}
-#else
- error("Compressed audio file encountered, but no appropriate decoder is compiled in");
-#endif
} else {
// Original source file
if (audioRes->_headerSize > 0) {
@@ -336,11 +332,11 @@ void AudioPlayer::setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *seg
_syncOffset = 0;
if (_syncResource) {
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), 0);
+ PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), 0);
} else {
warning("setSoundSync: failed to find resource %s", id.toString().c_str());
// Notify the scripts to stop sound sync
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
+ PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
}
}
@@ -356,8 +352,8 @@ void AudioPlayer::doSoundSync(reg_t syncObjAddr, SegManager *segMan) {
_syncOffset += 2;
}
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
+ PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
+ PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
}
}
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 3ee8a3a83d..2068ea9a33 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -60,9 +60,6 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
_dataincToAdd = 0;
_resetOnPause = false;
_channelsUsed = 0;
-
- for (int i = 0; i < 16; i++)
- _channelRemap[i] = i;
}
MidiParser_SCI::~MidiParser_SCI() {
@@ -88,6 +85,7 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
_tracks[0] = _mixedData;
setTrack(0);
_loopTick = 0;
+ _channelsUsed = 0;
if (_soundVersion <= SCI_VERSION_0_LATE) {
// Set initial voice count
@@ -122,20 +120,17 @@ void MidiParser_SCI::unloadMusic() {
// Center the pitch wheels and hold pedal in preparation for the next piece of music
if (_driver) {
for (int i = 0; i < 16; ++i) {
- if (isChannelUsed(i)) {
+ if (_channelsUsed & (1 << i)) {
_driver->send(0xE0 | i, 0, 0x40); // Reset pitch wheel
_driver->send(0xB0 | i, 0x40, 0); // Reset hold pedal
}
}
}
-
- for (int i = 0; i < 16; i++)
- _channelRemap[i] = i;
}
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
// Monitor which channels are used by this song
- setChannelUsed(info.channel());
+ _channelsUsed |= (1 << info.channel());
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
if (_dataincAdd) {
@@ -327,7 +322,7 @@ byte MidiParser_SCI::midiGetNextChannel(long ticker) {
for (int i = 0; i < _track->channelCount; i++) {
if (_track->channels[i].time == -1) // channel ended
continue;
- next = *_track->channels[i].data; // when the next event should occur
+ next = *_track->channels[i].data; // when the next event shoudl occur
if (next == 0xF8) // 0xF8 means 240 ticks delay
next = 240;
next += _track->channels[i].time;
@@ -394,18 +389,9 @@ byte *MidiParser_SCI::midiMixChannels() {
channel->time = -1; // FIXME
break;
default: // MIDI command
- if (command & 0x80) {
+ if (command & 0x80)
par1 = *channel->data++;
-
- // TODO: Fix remapping
-
-#if 0
- // Remap channel. Keep the upper 4 bits (command code) and change
- // the lower 4 bits (channel)
- byte remappedChannel = _channelRemap[par1 & 0xF];
- par1 = (par1 & 0xF0) | (remappedChannel & 0xF);
-#endif
- } else {// running status
+ else {// running status
par1 = command;
command = channel->prev;
}
diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h
index 9d4b5a39da..f95c71ce2f 100644
--- a/engines/sci/sound/midiparser_sci.h
+++ b/engines/sci/sound/midiparser_sci.h
@@ -71,18 +71,7 @@ public:
jumpToTick(0);
}
- void remapChannel(byte channel, byte newChannel) {
- assert(channel < 0xF); // don't touch special SCI channel 15
- assert(newChannel < 0xF); // don't touch special SCI channel 15
- _channelRemap[channel] = newChannel;
- }
-
- void clearUsedChannels() { _channelsUsed = 0; }
-
protected:
- bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
- void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
-
void parseNextEvent(EventInfo &info);
byte *midiMixChannels();
byte *midiFilterChannels(int channelMask);
@@ -104,8 +93,6 @@ protected:
// A 16-bit mask, containing the channels used
// by the currently parsed song
uint16 _channelsUsed;
-
- byte _channelRemap[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index fa5716e7cc..66f5ce9710 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -37,6 +37,9 @@
namespace Sci {
+// When defined, volume fading immediately sets the final sound volume
+#define DISABLE_VOLUME_FADING
+
SciMusic::SciMusic(SciVersion soundVersion)
: _soundVersion(soundVersion), _soundOn(true), _masterVolume(0) {
@@ -112,6 +115,8 @@ void SciMusic::clearPlayList() {
}
void SciMusic::pauseAll(bool pause) {
+ Common::StackLock lock(_mutex);
+
const MusicList::iterator end = _playList.end();
for (MusicList::iterator i = _playList.begin(); i != end; ++i) {
soundToggle(*i, pause);
@@ -165,29 +170,14 @@ void SciMusic::setReverb(byte reverb) {
_pMidiDrv->setReverb(reverb);
}
-static bool musicEntryCompare(const MusicEntry *l, const MusicEntry *r) {
- return (l->priority > r->priority);
+static int f_compare(const void *arg1, const void *arg2) {
+ return ((const MusicEntry *)arg2)->priority - ((const MusicEntry *)arg1)->priority;
}
void SciMusic::sortPlayList() {
- // Sort the play list in descending priority order
- Common::sort(_playList.begin(), _playList.end(), musicEntryCompare);
+ MusicEntry ** pData = _playList.begin();
+ qsort(pData, _playList.size(), sizeof(MusicEntry *), &f_compare);
}
-
-void SciMusic::findUsedChannels() {
- // Reset list
- for (int k = 0; k < 16; k++)
- _usedChannels[k] = false;
-
- const MusicList::const_iterator end = _playList.end();
- for (MusicList::const_iterator i = _playList.begin(); i != end; ++i) {
- for (int channel = 0; channel < 16; channel++) {
- if ((*i)->soundRes && (*i)->soundRes->isChannelUsed(channel))
- _usedChannels[channel] = true;
- }
- }
-}
-
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
int channelFilterMask = 0;
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
@@ -231,27 +221,6 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
pSnd->pauseCounter = 0;
- // TODO: Fix channel remapping. This doesn't quite work... (e.g. no difference in LSL1VGA)
-#if 0
- // Remap channels
- findUsedChannels();
-
- pSnd->pMidiParser->clearUsedChannels();
-
- for (int i = 0; i < 16; i++) {
- if (_usedChannels[i] && pSnd->soundRes->isChannelUsed(i)) {
- int16 newChannel = getNextUnusedChannel();
- if (newChannel >= 0) {
- _usedChannels[newChannel] = true;
- debug("Remapping channel %d to %d\n", i, newChannel);
- pSnd->pMidiParser->remapChannel(i, newChannel);
- } else {
- warning("Attempt to remap channel %d, but no unused channels exist", i);
- }
- }
- }
-#endif
-
// Find out what channels to filter for SCI0
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
@@ -274,14 +243,14 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
uint playListCount = _playList.size();
uint playListNo = playListCount;
- MusicEntry *alreadyPlaying = NULL;
+ bool alreadyPlaying = false;
// searching if sound is already in _playList
for (uint i = 0; i < playListCount; i++) {
if (_playList[i] == pSnd)
playListNo = i;
if ((_playList[i]->status == kSoundPlaying) && (_playList[i]->pMidiParser))
- alreadyPlaying = _playList[i];
+ alreadyPlaying = true;
}
if (playListNo == playListCount) { // not found
_playList.push_back(pSnd);
@@ -292,20 +261,13 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
if (pSnd->pMidiParser) {
if ((_soundVersion <= SCI_VERSION_0_LATE) && (alreadyPlaying)) {
- // Music already playing in SCI0?
- if (pSnd->priority > alreadyPlaying->priority) {
- // And new priority higher? pause previous music and play new one immediately
- // Example of such case: lsl3, when getting points (jingle is played then)
- soundPause(alreadyPlaying);
- alreadyPlaying->isQueued = true;
- } else {
- // And new priority equal or lower? queue up music and play it afterwards done by
- // SoundCommandParser::updateSci0Cues()
- // Example of such case: iceman room 14
- pSnd->isQueued = true;
- pSnd->status = kSoundPaused;
- return;
- }
+ // if any music is already playing, SCI0 queues music and plays it after the current music has finished
+ // done by SoundCommandParser::updateSci0Cues()
+ // Example of such case: iceman room 14
+ // FIXME: this code is supposed to also take a look at priority and pause currently playing sound accordingly
+ pSnd->isQueued = true;
+ pSnd->status = kSoundPaused;
+ return;
}
}
@@ -336,8 +298,6 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
void SciMusic::soundStop(MusicEntry *pSnd) {
pSnd->status = kSoundStopped;
- if (_soundVersion <= SCI_VERSION_0_LATE)
- pSnd->isQueued = false;
if (pSnd->pStreamAud)
_pMixer->stopHandle(pSnd->hCurrentAud);
@@ -420,12 +380,7 @@ void SciMusic::soundResume(MusicEntry *pSnd) {
return;
if (pSnd->status != kSoundPaused)
return;
- if (pSnd->pStreamAud) {
- _pMixer->pauseHandle(pSnd->hCurrentAud, false);
- pSnd->status = kSoundPlaying;
- } else {
- soundPlay(pSnd);
- }
+ soundPlay(pSnd);
}
void SciMusic::soundToggle(MusicEntry *pSnd, bool pause) {
@@ -567,17 +522,15 @@ void MusicEntry::doFade() {
fadeStep = 0;
fadeCompleted = true;
}
-#ifdef ENABLE_SCI32
- // Disable fading for SCI32 - sound drivers have issues when fading in (gabriel knight 1 sierra title)
- if (getSciVersion() >= SCI_VERSION_2) {
+
+ // Only process MIDI streams in this thread, not digital sound effects
+ if (pMidiParser) {
+#ifdef DISABLE_VOLUME_FADING
+ // Signal fading to stop...
volume = fadeTo;
fadeStep = 0;
fadeCompleted = true;
- }
#endif
-
- // Only process MIDI streams in this thread, not digital sound effects
- if (pMidiParser) {
pMidiParser->setVolume(volume);
}
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index 83cd59e89b..8f08065b99 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -197,6 +197,7 @@ public:
Common::Mutex _mutex;
protected:
+ byte findAudEntry(uint16 nAud, byte&oVolume, uint32& oOffset, uint32&oSize);
void sortPlayList();
SciVersion _soundVersion;
@@ -210,20 +211,10 @@ protected:
bool _bMultiMidi;
private:
static void miditimerCallback(void *p);
- void findUsedChannels();
- int16 getNextUnusedChannel() const {
- for (int i = 0; i < 16; i++) {
- if (!_usedChannels[i])
- return i;
- }
-
- return -1;
- }
MusicList _playList;
bool _soundOn;
byte _masterVolume;
- bool _usedChannels[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index ece4c1430c..925f3b2e1a 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -50,9 +50,9 @@ namespace Sci {
#ifdef USE_OLD_MUSIC_FUNCTIONS
static void script_set_priority(ResourceManager *resMan, SegManager *segMan, SfxState *state, reg_t obj, int priority) {
- int song_nr = readSelectorValue(segMan, obj, SELECTOR(number));
+ int song_nr = GET_SEL32V(segMan, obj, SELECTOR(number));
Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0);
- int flags = readSelectorValue(segMan, obj, SELECTOR(flags));
+ int flags = GET_SEL32V(segMan, obj, SELECTOR(flags));
if (priority == -1) {
if (song->data[0] == 0xf0)
@@ -64,7 +64,7 @@ static void script_set_priority(ResourceManager *resMan, SegManager *segMan, Sfx
} else flags |= SCI1_SOUND_FLAG_SCRIPTED_PRI;
state->sfx_song_renice(FROBNICATE_HANDLE(obj), priority);
- writeSelectorValue(segMan, obj, SELECTOR(flags), flags);
+ PUT_SEL32V(segMan, obj, SELECTOR(flags), flags);
}
SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id) {
@@ -98,27 +98,27 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their
case SI_LOOP:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x looped (to %d)",
PRINT_REG(obj), cue);
- /* writeSelectorValue(segMan, obj, SELECTOR(loops), readSelectorValue(segMan, obj, SELECTOR(loop));; - 1);*/
- writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ /* PUT_SEL32V(segMan, obj, SELECTOR(loops), GET_SEL32V(segMan, obj, SELECTOR(loop));; - 1);*/
+ PUT_SEL32V(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
break;
case SI_RELATIVE_CUE:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d",
PRINT_REG(obj), cue);
- writeSelectorValue(segMan, obj, SELECTOR(signal), cue + 0x7f);
+ PUT_SEL32V(segMan, obj, SELECTOR(signal), cue + 0x7f);
break;
case SI_ABSOLUTE_CUE:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d",
PRINT_REG(obj), cue);
- writeSelectorValue(segMan, obj, SELECTOR(signal), cue);
+ PUT_SEL32V(segMan, obj, SELECTOR(signal), cue);
break;
case SI_FINISHED:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished",
PRINT_REG(obj));
- writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- writeSelectorValue(segMan, obj, SELECTOR(state), kSoundStopped);
+ PUT_SEL32V(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(segMan, obj, SELECTOR(state), kSoundStopped);
break;
default:
@@ -253,7 +253,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (!obj.segment)
return;
- int resourceId = readSelectorValue(_segMan, obj, SELECTOR(number));
+ int resourceId = GET_SEL32V(_segMan, obj, SELECTOR(number));
#ifdef USE_OLD_MUSIC_FUNCTIONS
@@ -267,7 +267,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
SongIteratorType type = (_soundVersion <= SCI_VERSION_0_LATE) ? SCI_SONG_ITERATOR_TYPE_SCI0 : SCI_SONG_ITERATOR_TYPE_SCI1;
if (_soundVersion <= SCI_VERSION_0_LATE) {
- if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr))) {
+ if (GET_SEL32V(_segMan, obj, SELECTOR(nodePtr))) {
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_state->sfx_remove_song(handle);
}
@@ -281,11 +281,11 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
- writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
#else
@@ -302,10 +302,10 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
newSound->soundRes = 0;
newSound->soundObj = obj;
- newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
- newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF;
- if (_soundVersion >= SCI_VERSION_1_EARLY)
- newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
+ newSound->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
+ newSound->priority = GET_SEL32V(_segMan, obj, SELECTOR(pri)) & 0xFF;
+ if (_soundVersion >= SCI_VERSION_1_LATE)
+ newSound->volume = CLIP<int>(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
@@ -327,11 +327,11 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (newSound->soundRes || newSound->pStreamAud) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
- writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
}
#endif
@@ -346,30 +346,30 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
+ _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundPlaying);
} else if (_soundVersion == SCI_VERSION_1_EARLY) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
- _state->sfx_song_renice(handle, readSelectorValue(_segMan, obj, SELECTOR(pri)));
+ _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
+ _state->sfx_song_renice(handle, GET_SEL32V(_segMan, obj, SELECTOR(pri)));
RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) value; /* Too lazy to look up a default value for this */
_state->_songlib.setSongRestoreBehavior(handle, rb);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
} else if (_soundVersion == SCI_VERSION_1_LATE) {
- int looping = readSelectorValue(_segMan, obj, SELECTOR(loop));
- //int vol = readSelectorValue(_segMan, obj, SELECTOR(vol));
- int pri = readSelectorValue(_segMan, obj, SELECTOR(pri));
+ int looping = GET_SEL32V(_segMan, obj, SELECTOR(loop));
+ //int vol = GET_SEL32V(_segMan, obj, SELECTOR(vol));
+ int pri = GET_SEL32V(_segMan, obj, SELECTOR(pri));
int sampleLen = 0;
Song *song = _state->_songlib.findSong(handle);
- int songNumber = readSelectorValue(_segMan, obj, SELECTOR(number));
+ int songNumber = GET_SEL32V(_segMan, obj, SELECTOR(number));
- if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
+ if (GET_SEL32V(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_state->sfx_remove_song(handle);
- writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
+ PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
}
- if (!readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
+ if (!GET_SEL32V(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
// effects. If the resource exists, play it using map 65535 (sound
@@ -387,7 +387,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
warning("Could not open song number %d", songNumber);
// Send a "stop handle" event so that the engine won't wait forever here
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
return;
}
debugC(2, kDebugLevelSound, "Initializing song number %d", songNumber);
@@ -395,15 +395,15 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
handle), 0, handle, songNumber);
}
- writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
}
if (obj.segment) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
_state->sfx_song_set_loops(handle, looping);
_state->sfx_song_renice(handle, pri);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
}
}
@@ -415,7 +415,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
return;
}
- int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1;
+ int resourceId = obj.segment ? GET_SEL32V(_segMan, obj, SELECTOR(number)) : -1;
if (musicSlot->resourceId != resourceId) { // another sound loaded into struct
cmdDisposeSound(obj, value);
@@ -423,25 +423,25 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
// Find slot again :)
musicSlot = _music->getSlot(obj);
}
- int16 loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ int16 loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
debugC(2, kDebugLevelSound, "cmdPlaySound: resource number %d, loop %d", resourceId, loop);
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
+ PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
if (_soundVersion >= SCI_VERSION_1_EARLY) {
- writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- writeSelectorValue(_segMan, obj, SELECTOR(min), 0);
- writeSelectorValue(_segMan, obj, SELECTOR(sec), 0);
- writeSelectorValue(_segMan, obj, SELECTOR(frame), 0);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
+ PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
+ PUT_SEL32V(_segMan, obj, SELECTOR(min), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(sec), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(frame), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
} else {
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundPlaying);
}
- musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
- musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
- if (_soundVersion >= SCI_VERSION_1_EARLY)
- musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol));
+ musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
+ musicSlot->priority = GET_SEL32V(_segMan, obj, SELECTOR(priority));
+ if (_soundVersion >= SCI_VERSION_1_LATE)
+ musicSlot->volume = GET_SEL32V(_segMan, obj, SELECTOR(vol));
_music->soundPlay(musicSlot);
#endif
@@ -458,7 +458,7 @@ void SoundCommandParser::changeSoundStatus(reg_t obj, int newStatus) {
if (obj.segment) {
_state->sfx_song_set_status(handle, newStatus);
if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), newStatus);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), newStatus);
}
}
#endif
@@ -475,7 +475,7 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
_state->sfx_remove_song(handle);
if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(handle), 0x0000);
+ PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0x0000);
}
#else
@@ -489,11 +489,11 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
cmdStopSound(obj, value);
_music->soundKill(musicSlot);
- writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
+ PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
else
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundStopped);
#endif
}
@@ -509,7 +509,7 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
changeSoundStatus(obj, SOUND_STATUS_STOPPED);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
@@ -518,9 +518,9 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
}
if (_soundVersion <= SCI_VERSION_0_LATE) {
- writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundStopped);
} else {
- writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
+ PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
}
// Set signal selector in sound SCI0 games only, when the sample has finished playing
@@ -530,7 +530,7 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
// sfx drivers included
// We need to set signal in sound SCI1+ games all the time
if ((_soundVersion > SCI_VERSION_0_LATE) || sampleFinishedPlaying)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
musicSlot->dataInc = 0;
musicSlot->signal = 0;
@@ -565,7 +565,7 @@ void SoundCommandParser::cmdPauseSound(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
// Always pause the sound in SCI0 games. It's resumed in cmdResumeSound()
- writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
+ PUT_SEL32V(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
_music->soundPause(musicSlot);
} else {
_music->soundToggle(musicSlot, value);
@@ -590,7 +590,7 @@ void SoundCommandParser::cmdResumeSound(reg_t obj, int16 value) {
return;
}
- writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
+ PUT_SEL32V(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
_music->soundResume(musicSlot);
#endif
}
@@ -630,12 +630,13 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongHandle handle = FROBNICATE_HANDLE(obj);
if (_soundVersion != SCI_VERSION_1_LATE) {
+ /*s->sound_server->command(s, SOUND_COMMAND_FADE_HANDLE, obj, 120);*/ /* Fade out in 2 secs */
/* FIXME: The next couple of lines actually STOP the handle, rather
** than fading it! */
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
} else {
fade_params_t fade;
fade.final_volume = _argv[2].toUint16();
@@ -650,11 +651,11 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
/* FIXME: The next couple of lines actually STOP the handle, rather
** than fading it! */
if (_argv[5].toUint16()) {
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
} else {
// FIXME: Support fade-and-continue. For now, send signal right away.
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
}
}
#else
@@ -691,7 +692,7 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
// If sound is not playing currently, set signal directly
if (musicSlot->status != kSoundPlaying) {
warning("cmdFadeSound: fading requested, but sound is currently not playing");
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
}
debugC(2, kDebugLevelSound, "cmdFadeSound: to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
@@ -713,8 +714,8 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongHandle handle = FROBNICATE_HANDLE(obj);
if (_soundVersion <= SCI_VERSION_0_LATE && obj.segment) {
- _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
- script_set_priority(_resMan, _segMan, _state, obj, readSelectorValue(_segMan, obj, SELECTOR(pri)));
+ _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
+ script_set_priority(_resMan, _segMan, _state, obj, GET_SEL32V(_segMan, obj, SELECTOR(pri)));
}
#else
MusicEntry *musicSlot = _music->getSlot(obj);
@@ -723,11 +724,11 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
return;
}
- musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
- int16 objVol = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, 255);
+ musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
+ int16 objVol = CLIP<int>(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, 255);
if (objVol != musicSlot->volume)
_music->soundSetVolume(musicSlot, objVol);
- uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(pri));
+ uint32 objPrio = GET_SEL32V(_segMan, obj, SELECTOR(pri));
if (objPrio != musicSlot->priority)
_music->soundSetPriority(musicSlot, objPrio);
@@ -754,7 +755,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Absolute Cue: %d",
PRINT_REG(obj), signal);
debugC(2, kDebugLevelSound, "abs-signal %04X", signal);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal);
break;
case SI_RELATIVE_CUE:
@@ -764,17 +765,17 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
/* FIXME to match commented-out semantics
* below, with proper storage of dataInc and
* signal in the iterator code. */
- writeSelectorValue(_segMan, obj, SELECTOR(dataInc), signal);
+ PUT_SEL32V(_segMan, obj, SELECTOR(dataInc), signal);
debugC(2, kDebugLevelSound, "rel-signal %04X", signal);
if (_soundVersion == SCI_VERSION_1_EARLY)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal);
else
- writeSelectorValue(_segMan, obj, SELECTOR(signal), signal + 127);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal + 127);
break;
case SI_FINISHED:
debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x", PRINT_REG(obj));
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
break;
case SI_LOOP:
@@ -783,30 +784,30 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
//switch (signal) {
//case 0x00:
- // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
- // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
- // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc+0x7f);
+ // if (dataInc != GET_SEL32V(segMan, obj, SELECTOR(dataInc))) {
+ // PUT_SEL32V(segMan, obj, SELECTOR(dataInc), dataInc);
+ // PUT_SEL32V(segMan, obj, SELECTOR(signal), dataInc+0x7f);
// } else {
- // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
+ // PUT_SEL32V(segMan, obj, SELECTOR(signal), signal);
// }
// break;
//case 0xFF: // May be unnecessary
// s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
// break;
//default :
- // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
- // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
- // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
+ // if (dataInc != GET_SEL32V(segMan, obj, SELECTOR(dataInc))) {
+ // PUT_SEL32V(segMan, obj, SELECTOR(dataInc), dataInc);
+ // PUT_SEL32V(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
// } else {
- // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
+ // PUT_SEL32V(segMan, obj, SELECTOR(signal), signal);
// }
// break;
//}
if (_soundVersion == SCI_VERSION_1_EARLY) {
- writeSelectorValue(_segMan, obj, SELECTOR(min), min);
- writeSelectorValue(_segMan, obj, SELECTOR(sec), sec);
- writeSelectorValue(_segMan, obj, SELECTOR(frame), frame);
+ PUT_SEL32V(_segMan, obj, SELECTOR(min), min);
+ PUT_SEL32V(_segMan, obj, SELECTOR(sec), sec);
+ PUT_SEL32V(_segMan, obj, SELECTOR(frame), frame);
}
#else
MusicEntry *musicSlot = _music->getSlot(obj);
@@ -827,7 +828,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
musicSlot->loop -= currentLoopCounter - musicSlot->sampleLoopCounter;
musicSlot->sampleLoopCounter = currentLoopCounter;
}
- if ((!_music->soundIsActive(musicSlot)) && (musicSlot->status != kSoundPaused)) {
+ if (!_music->soundIsActive(musicSlot)) {
processStopSound(obj, 0, true);
} else {
_music->updateAudioStreamTicker(musicSlot);
@@ -840,14 +841,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
} else if (musicSlot->pMidiParser) {
// Update MIDI slots
if (musicSlot->signal == 0) {
- if (musicSlot->dataInc != readSelectorValue(_segMan, obj, SELECTOR(dataInc))) {
+ if (musicSlot->dataInc != GET_SEL32V(_segMan, obj, SELECTOR(dataInc))) {
if (_kernel->_selectorCache.dataInc > -1)
- writeSelectorValue(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
- writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
+ PUT_SEL32V(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
}
} else {
// Sync the signal of the sound object
- writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->signal);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), musicSlot->signal);
// We need to do this especially because state selector needs to get updated
if (musicSlot->signal == SIGNAL_OFFSET)
cmdStopSound(obj, 0);
@@ -855,14 +856,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
} else {
// Slot actually has no data (which would mean that a sound-resource w/ unsupported data is used
// (example lsl5 - sound resource 744 - it's roland exclusive
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
// If we don't set signal here, at least the switch to the mud wrestling room in lsl5 will not work
}
if (musicSlot->fadeCompleted) {
musicSlot->fadeCompleted = false;
// We need signal for sci0 at least in iceman as well (room 14, fireworks)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
if (_soundVersion <= SCI_VERSION_0_LATE) {
cmdStopSound(obj, 0);
} else {
@@ -873,14 +874,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
// Sync loop selector for SCI0
if (_soundVersion <= SCI_VERSION_0_LATE)
- writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+ PUT_SEL32V(_segMan, obj, SELECTOR(loop), musicSlot->loop);
musicSlot->signal = 0;
if (_soundVersion >= SCI_VERSION_1_EARLY) {
- writeSelectorValue(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600);
- writeSelectorValue(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
- writeSelectorValue(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
+ PUT_SEL32V(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600);
+ PUT_SEL32V(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
+ PUT_SEL32V(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
}
#endif
@@ -926,13 +927,18 @@ void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) {
#ifndef USE_OLD_MUSIC_FUNCTIONS
Common::StackLock(_music->_mutex);
+ // FIXME: this can't be right, it's called in iceman (room 14) when the door sound has done playing
+ // stopping sounds can't be right, because music is starting afterwards in ssci. can't be resume queued
+ // song(s), because music is playing even when this call is nuked inside ssci.
+ return;
+
const MusicList::iterator end = _music->getPlayListEnd();
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
+ PUT_SEL32V(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
} else {
- writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
+ PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
+ PUT_SEL32V(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
}
(*i)->dataInc = 0;
@@ -963,7 +969,7 @@ void SoundCommandParser::cmdSetSoundVolume(reg_t obj, int16 value) {
if (musicSlot->volume != value) {
musicSlot->volume = value;
_music->soundSetVolume(musicSlot, value);
- writeSelectorValue(_segMan, obj, SELECTOR(vol), value);
+ PUT_SEL32V(_segMan, obj, SELECTOR(vol), value);
}
#endif
}
@@ -990,12 +996,12 @@ void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) {
warning("cmdSetSoundPriority: Attempt to unset song priority when there is no built-in value");
//pSnd->prio=0;field_15B=0
- writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) & 0xFD);
+ PUT_SEL32V(_segMan, obj, SELECTOR(flags), GET_SEL32V(_segMan, obj, SELECTOR(flags)) & 0xFD);
} else {
// Scripted priority
//pSnd->field_15B=1;
- writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) | 2);
+ PUT_SEL32V(_segMan, obj, SELECTOR(flags), GET_SEL32V(_segMan, obj, SELECTOR(flags)) | 2);
//DoSOund(0xF,hobj,w)
}
#endif
@@ -1006,7 +1012,7 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
return;
#ifdef USE_OLD_MUSIC_FUNCTIONS
- if (!readSelector(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
+ if (!GET_SEL32(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
SongHandle handle = FROBNICATE_HANDLE(obj);
_state->sfx_song_set_loops(handle, value);
}
@@ -1031,7 +1037,7 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
musicSlot->loop = 1; // actually plays the music once
}
- writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+ PUT_SEL32V(_segMan, obj, SELECTOR(loop), musicSlot->loop);
#endif
}
@@ -1052,11 +1058,8 @@ void SoundCommandParser::updateSci0Cues() {
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
// Is the sound stopped, and the sound object updated too? If yes, skip
// this sound, as SCI0 only allows one active song
- if ((*i)->isQueued) {
+ if (((*i)->isQueued) && (!pWaitingForPlay)) {
pWaitingForPlay = (*i);
- // FIXME (?) - in iceman 2 songs are queued when playing the door sound - if we use the first song for resuming
- // then it's the wrong one. Both songs have same priority. Maybe the new sound function in sci0
- // is somehow responsible
continue;
}
if ((*i)->signal == 0 && (*i)->status != kSoundPlaying)
@@ -1102,11 +1105,11 @@ void SoundCommandParser::reconstructPlayList(int savegame_version) {
}
if ((*i)->status == kSoundPlaying) {
if (savegame_version < 14) {
- (*i)->dataInc = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(dataInc));
- (*i)->signal = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal));
+ (*i)->dataInc = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(dataInc));
+ (*i)->signal = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(signal));
if (_soundVersion >= SCI_VERSION_1_LATE)
- (*i)->volume = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol));
+ (*i)->volume = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(vol));
}
cmdPlaySound((*i)->soundObj, 0);
@@ -1142,7 +1145,7 @@ void SoundCommandParser::startNewSound(int number) {
MusicEntry *song = *_music->getPlayListStart();
reg_t soundObj = song->soundObj;
cmdDisposeSound(soundObj, 0);
- writeSelectorValue(_segMan, soundObj, SELECTOR(number), number);
+ PUT_SEL32V(_segMan, soundObj, SELECTOR(number), number);
cmdInitSound(soundObj, 0);
cmdPlaySound(soundObj, 0);
#endif
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 0e0c0e129e..757171b24c 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -845,7 +845,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
offsX = offsY = 0;
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
- assert(charOffs < 0x14000);
+ assert(charOffs < 0x10000);
if (!charOffs)
return;
charPtr = _fontPtr + charOffs;
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index ea29e25a1f..a0975839d6 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -870,7 +870,7 @@ bool ScummDebugger::Cmd_Passcode(int argc, const char **argv) {
_detach_now = true;
} else {
- DebugPrintf("Current Passcode is %d \nUse 'passcode <SEGA CD Passcode>'\n",_vm->_scummVars[411]);
+ DebugPrintf("Use 'passcode <SEGA CD Passcode>'\n");
return true;
}
return false;
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index d9c24ddca2..1f153094c1 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -233,6 +233,19 @@ protected:
#endif
+class ConfigDialog : public GUI::OptionsDialog {
+protected:
+#ifdef SMALL_SCREEN_DEVICE
+ GUI::Dialog *_keysDialog;
+#endif
+
+public:
+ ConfigDialog();
+ ~ConfigDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+};
+
#pragma mark -
ScummDialog::ScummDialog(int x, int y, int w, int h) : GUI::Dialog(x, y, w, h) {
@@ -245,31 +258,223 @@ ScummDialog::ScummDialog(String name) : GUI::Dialog(name) {
#pragma mark -
-#ifndef DISABLE_HELP
+enum {
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kPlayCmd = 'PLAY',
+ kOptionsCmd = 'OPTN',
+ kHelpCmd = 'HELP',
+ kAboutCmd = 'ABOU',
+ kQuitCmd = 'QUIT',
+ kChooseCmd = 'CHOS'
+};
ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
- : MainMenuDialog(scumm) {
+ : ScummDialog("ScummMain"), _vm(scumm) {
+
+ new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P');
+
+ _loadButton = new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L');
+ _saveButton = new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S');
+
+ new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O');
+#ifndef DISABLE_HELP
+ new GUI::ButtonWidget(this, "ScummMain.Help", "Help", kHelpCmd, 'H');
+#endif
+ new GUI::ButtonWidget(this, "ScummMain.About", "About", kAboutCmd, 'A');
+
+ new GUI::ButtonWidget(this, "ScummMain.Quit", "Quit", kQuitCmd, 'Q');
+
+ //
+ // Create the sub dialog(s)
+ //
+ _aboutDialog = new GUI::AboutDialog();
+ _optionsDialog = new ConfigDialog();
+#ifndef DISABLE_HELP
_helpDialog = new HelpDialog(scumm->_game);
- _helpButton->setEnabled(true);
+#endif
+ _saveDialog = new GUI::SaveLoadChooser("Save game:", "Save");
+ _saveDialog->setSaveMode(true);
+ _loadDialog = new GUI::SaveLoadChooser("Load game:", "Load");
+ _loadDialog->setSaveMode(false);
}
ScummMenuDialog::~ScummMenuDialog() {
+ delete _aboutDialog;
+ delete _optionsDialog;
+#ifndef DISABLE_HELP
delete _helpDialog;
+#endif
+ delete _saveDialog;
+ delete _loadDialog;
+}
+
+int ScummMenuDialog::runModal() {
+ _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
+ _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
+ return ScummDialog::runModal();
+}
+
+void ScummMenuDialog::reflowLayout() {
+ _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
+ _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
+ Dialog::reflowLayout();
}
void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
+ case kSaveCmd:
+ save();
+ break;
+ case kLoadCmd:
+ load();
+ break;
+ case kPlayCmd:
+ close();
+ break;
+ case kOptionsCmd:
+ _optionsDialog->runModal();
+ break;
+ case kAboutCmd:
+ _aboutDialog->runModal();
+ break;
+#ifndef DISABLE_HELP
case kHelpCmd:
_helpDialog->runModal();
break;
+#endif
+ case kQuitCmd:
+ _vm->quitGame();
+ close();
+ break;
default:
- MainMenuDialog::handleCommand(sender, cmd, data);
+ ScummDialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void ScummMenuDialog::save() {
+ Common::String gameId = ConfMan.get("gameid");
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ int idx = _saveDialog->runModal(plugin, ConfMan.getActiveDomainName());
+ if (idx >= 0) {
+ String result(_saveDialog->getResultString());
+ char buffer[20];
+ const char *str;
+ if (result.empty()) {
+ // If the user was lazy and entered no save name, come up with a default name.
+ sprintf(buffer, "Save %d", idx);
+ str = buffer;
+ } else
+ str = result.c_str();
+ _vm->requestSave(idx, str);
+ close();
+ }
+}
+
+void ScummMenuDialog::load() {
+ Common::String gameId = ConfMan.get("gameid");
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ int idx = _loadDialog->runModal(plugin, ConfMan.getActiveDomainName());
+ if (idx >= 0) {
+ _vm->requestLoad(idx);
+ close();
}
}
#pragma mark -
enum {
+ kKeysCmd = 'KEYS'
+};
+
+// FIXME: We use the empty string as domain name here. This tells the
+// ConfigManager to use the 'default' domain for all its actions. We do that
+// to get as close as possible to editing the 'active' settings.
+//
+// However, that requires bad & evil hacks in the ConfigManager code,
+// and even then still doesn't work quite correctly.
+// For example, if the transient domain contains 'false' for the 'fullscreen'
+// flag, but the user used a hotkey to switch to windowed mode, then the dialog
+// will display the wrong value anyway.
+//
+// Proposed solution consisting of multiple steps:
+// 1) Add special code to the open() code that reads out everything stored
+// in the transient domain that is controlled by this dialog, and updates
+// the dialog accordingly.
+// 2) Even more code is added to query the backend for current settings, like
+// the fullscreen mode flag etc., and also updates the dialog accordingly.
+// 3) The domain being edited is set to the active game domain.
+// 4) If the dialog is closed with the "OK" button, then we remove everything
+// stored in the transient domain (or at least everything corresponding to
+// switches in this dialog.
+// If OTOH the dialog is closed with "Cancel" we do no such thing.
+//
+// These changes will achieve two things at once: Allow us to get rid of using
+// "" as value for the domain, and in fact provide a somewhat better user
+// experience at the same time.
+ConfigDialog::ConfigDialog()
+ : GUI::OptionsDialog("", "ScummConfig") {
+
+ //
+ // Sound controllers
+ //
+
+ addVolumeControls(this, "ScummConfig.");
+
+ //
+ // Some misc options
+ //
+
+ // SCUMM has a talkspeed range of 0-9
+ addSubtitleControls(this, "ScummConfig.", 9);
+
+ //
+ // Add the buttons
+ //
+
+ new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
+#ifdef SMALL_SCREEN_DEVICE
+ new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
+ _keysDialog = NULL;
+#endif
+}
+
+ConfigDialog::~ConfigDialog() {
+#ifdef SMALL_SCREEN_DEVICE
+ delete _keysDialog;
+#endif
+}
+
+void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kKeysCmd:
+#ifdef SMALL_SCREEN_DEVICE
+ //
+ // Create the sub dialog(s)
+ //
+ _keysDialog = new GUI::KeysDialog();
+ _keysDialog->runModal();
+ delete _keysDialog;
+ _keysDialog = NULL;
+#endif
+ break;
+ default:
+ GUI::OptionsDialog::handleCommand (sender, cmd, data);
+ }
+}
+
+#ifndef DISABLE_HELP
+
+#pragma mark -
+
+enum {
kNextCmd = 'NEXT',
kPrevCmd = 'PREV'
};
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 41a8ec83c1..7889027dcf 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -27,8 +27,9 @@
#include "common/str.h"
#include "gui/dialog.h"
+#include "gui/options.h"
#include "gui/widget.h"
-#include "engines/dialogs.h"
+#include "gui/saveload.h"
#include "scumm/detection.h"
@@ -51,17 +52,32 @@ protected:
typedef Common::String String;
};
-#ifndef DISABLE_HELP
-class ScummMenuDialog : public MainMenuDialog {
+class ScummMenuDialog : public ScummDialog {
public:
ScummMenuDialog(ScummEngine *scumm);
~ScummMenuDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ virtual void reflowLayout();
+
+ int runModal();
protected:
+ ScummEngine *_vm;
+
+ GUI::Dialog *_aboutDialog;
+ GUI::Dialog *_optionsDialog;
+#ifndef DISABLE_HELP
GUI::Dialog *_helpDialog;
-};
#endif
+ GUI::SaveLoadChooser *_saveDialog;
+ GUI::SaveLoadChooser *_loadDialog;
+
+ GUI::ButtonWidget *_loadButton;
+ GUI::ButtonWidget *_saveButton;
+
+ void save();
+ void load();
+};
/**
* A dialog which displays an arbitrary message to the user and returns
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index c259c3ffd2..886ee99e57 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -633,10 +633,8 @@ Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary
wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
/* fill in wr->id, wr->numeric_id */
- if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
- free(wr);
+ if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name)))
return NULL;
- }
}
return wr;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index dc3a5d26b3..8a9570f534 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -508,7 +508,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0);
- openMainMenuDialog(); // Display global main menu
+ scummMenuDialog(); // Display GUI
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0);
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index cc382d9621..9b7e0798eb 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
/*
- This file was generated by the md5table tool on Mon May 24 13:24:24 2010
+ This file was generated by the md5table tool on Sun May 9 20:53:55 2010
DO NOT EDIT MANUALLY!
*/
@@ -170,13 +170,11 @@ static const MD5Table md5table[] = {
{ "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HE_ISR, Common::kPlatformWindows },
{ "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC },
{ "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows },
- { "3c4c471342bd95505a42334367d8f127", "puttmoon", "HE 70", "", 12161, Common::RU_RUS, Common::kPlatformWindows },
{ "3cce1913a3bc586b51a75c3892ff18dd", "indy3", "VGA", "VGA", -1, Common::RU_RUS, Common::kPlatformPC },
{ "3d219e7546039543307b55a91282bf18", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC },
{ "3de99ef0523f8ca7958faa3afccd035a", "spyfox", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 62", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "3e48298920fab9b7aec5a971e1bd1fab", "pajama3", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows },
- { "3e861421f494711bc6f619d4aba60285", "airport", "", "", 93231, Common::RU_RUS, Common::kPlatformWindows },
{ "40564ec47da48a67787d1f9bd043902a", "maniac", "V2 Demo", "V2 Demo", 1988, Common::EN_ANY, Common::kPlatformPC },
{ "4167a92a1d46baa4f4127d918d561f88", "tentacle", "", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown },
{ "41958e24d03181ff9a381a66d048a581", "ft", "", "", -1, Common::PT_BRA, Common::kPlatformUnknown },
@@ -245,7 +243,6 @@ static const MD5Table md5table[] = {
{ "5bd335265a61caa3d78956ad9f88ba23", "football", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "5c21fc49aee8f46e58fef21579e614a1", "thinker1", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "5d88b9d6a88e6f8e90cded9d01b7f082", "loom", "VGA", "VGA", 8307, Common::EN_ANY, Common::kPlatformPC },
- { "5dda73606533d66a4c3f4f9ea6e842af", "farm", "", "", 87061, Common::RU_RUS, Common::kPlatformWindows },
{ "5e8fb66971a60e523e5afbc4c129c0e8", "socks", "HE 85", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "5ebb57234b2fe5c5dff641e00184ad81", "freddi", "HE 73", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "5fbe557049892eb4b709d90916ec97ca", "indy3", "EGA", "EGA", 5361, Common::EN_ANY, Common::kPlatformPC },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index bb50ce7bb2..2359d4a04f 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -108,7 +108,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_language(dr.language),
_debugger(0),
_currentScript(0xFF), // Let debug() work on init stage
- _messageDialog(0), _pauseDialog(0), _versionDialog(0) {
+ _messageDialog(0), _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) {
if (_game.platform == Common::kPlatformNES) {
_gdi = new GdiNES(this);
@@ -140,6 +140,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_fileHandle = 0;
+
// Init all vars
_v0ObjectIndex = false;
_v0ObjectInInventory = false;
@@ -151,6 +152,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_sound = NULL;
memset(&vm, 0, sizeof(vm));
_pauseDialog = NULL;
+ _scummMenuDialog = NULL;
_versionDialog = NULL;
_fastMode = 0;
_actors = NULL;
@@ -550,12 +552,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
for (int i = 0; i < ARRAYSIZE(debugChannels); ++i)
DebugMan.addDebugChannel(debugChannels[i].flag, debugChannels[i].channel, debugChannels[i].desc);
-#ifndef DISABLE_HELP
- // Create custom GMM dialog providing a help subdialog
- assert(!_mainMenuDialog);
- _mainMenuDialog = new ScummMenuDialog(this);
-#endif
-
g_eventRec.registerRandomSource(_rnd, "scumm");
}
@@ -576,6 +572,7 @@ ScummEngine::~ScummEngine() {
delete _charset;
delete _messageDialog;
delete _pauseDialog;
+ delete _scummMenuDialog;
delete _versionDialog;
delete _fileHandle;
@@ -2440,6 +2437,13 @@ void ScummEngine::versionDialog() {
runDialog(*_versionDialog);
}
+void ScummEngine::scummMenuDialog() {
+ if (!_scummMenuDialog)
+ _scummMenuDialog = new ScummMenuDialog(this);
+ runDialog(*_scummMenuDialog);
+ syncSoundSettings();
+}
+
void ScummEngine::confirmExitDialog() {
ConfirmDialog d(this, 6);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 42322ba5a2..885ab790de 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -530,6 +530,7 @@ protected:
Dialog *_pauseDialog;
Dialog *_messageDialog;
Dialog *_versionDialog;
+ Dialog *_scummMenuDialog;
virtual int runDialog(Dialog &dialog);
void confirmExitDialog();
@@ -537,6 +538,7 @@ protected:
void pauseDialog();
void messageDialog(const char *message);
void versionDialog();
+ void scummMenuDialog();
char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 441e622184..c0e7be7758 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -23,6 +23,7 @@
*
*/
+
#include "common/file.h"
#include "sword1/sword1.h"
#include "sword1/animation.h"
@@ -71,9 +72,6 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSys
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
-
- _white = 255;
- _black = 0;
}
MoviePlayer::~MoviePlayer() {
@@ -256,35 +254,9 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette()) {
+ if (_decoder->hasDirtyPalette())
_decoder->setSystemPalette();
- uint32 maxWeight = 0;
- uint32 minWeight = 0xFFFFFFFF;
- uint32 weight;
- byte r, g, b;
-
- byte *palette = _decoder->getPalette();
-
- for (int i = 0; i < 256; i++) {
- r = *palette++;
- g = *palette++;
- b = *palette++;
-
- weight = 3 * r * r + 6 * g * g + 2 * b * b;
-
- if (weight >= maxWeight) {
- maxWeight = weight;
- _white = i;
- }
-
- if (weight <= minWeight) {
- minWeight = weight;
- _black = i;
- }
- }
- }
-
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -295,19 +267,17 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
-
- _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return _black;
+ return 0;
}
byte MoviePlayer::findWhitePalIndex() {
- return _white;
+ return 0xff;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index 193d5cf7ca..82343f2800 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -85,7 +85,6 @@ protected:
OSystem *_system;
Common::Array<MovieText *> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
- byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 10895b2ec1..c3f3e796b2 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -51,9 +51,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
-
- _white = 255;
- _black = 0;
}
MoviePlayer:: ~MoviePlayer() {
@@ -283,35 +280,9 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette()) {
+ if (_decoder->hasDirtyPalette())
_decoder->setSystemPalette();
- uint32 maxWeight = 0;
- uint32 minWeight = 0xFFFFFFFF;
- uint32 weight;
- byte r, g, b;
-
- byte *palette = _decoder->getPalette();
-
- for (int i = 0; i < 256; i++) {
- r = *palette++;
- g = *palette++;
- b = *palette++;
-
- weight = 3 * r * r + 6 * g * g + 2 * b * b;
-
- if (weight >= maxWeight) {
- maxWeight = weight;
- _white = i;
- }
-
- if (weight <= minWeight) {
- minWeight = weight;
- _black = i;
- }
- }
- }
-
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -322,19 +293,17 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
-
- _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return _black;
+ return 0;
}
byte MoviePlayer::findWhitePalIndex() {
- return _white;
+ return 0xff;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index ee32b1d5f2..bbf83e264c 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -87,7 +87,6 @@ protected:
uint32 _currentMovieText;
byte *_textSurface;
int _textX, _textY;
- byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 60eb08a2dd..de573feee2 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -288,8 +288,7 @@ void LoadFile(MEMHANDLE *pH) {
}
// extract and zero terminate the filename
- memcpy(szFilename, pH->szName, sizeof(pH->szName));
- szFilename[sizeof(pH->szName)] = 0;
+ Common::strlcpy(szFilename, pH->szName, sizeof(pH->szName));
if (f.open(szFilename)) {
// read the data
diff --git a/graphics/conversion.h b/graphics/conversion.h
index b6d230612e..149d7204c6 100644
--- a/graphics/conversion.h
+++ b/graphics/conversion.h
@@ -45,6 +45,13 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) {
v = CLIP<int>( ((r * 512) >> 10) - ((g * 429) >> 10) - ((b * 83) >> 10) + 128, 0, 255);
}
+/** Converting a color from YUV to RGB colorspace, Cinepak style. */
+inline static void CPYUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) {
+ r = CLIP<int>(y + 2 * (v - 128), 0, 255);
+ g = CLIP<int>(y - (u - 128) / 2 - (v - 128), 0, 255);
+ b = CLIP<int>(y + 2 * (u - 128), 0, 255);
+}
+
// TODO: generic YUV to RGB blit
/**
diff --git a/graphics/module.mk b/graphics/module.mk
index 75e3919370..ff6d7f8f60 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -13,7 +13,6 @@ MODULE_OBJS := \
iff.o \
imagedec.o \
jpeg.o \
- pict.o \
primitives.o \
scaler.o \
scaler/thumbnail_intern.o \
@@ -26,17 +25,10 @@ MODULE_OBJS := \
video/dxa_decoder.o \
video/flic_decoder.o \
video/mpeg_player.o \
- video/qt_decoder.o \
video/smk_decoder.o \
video/video_decoder.o \
- video/codecs/cinepak.o \
- video/codecs/mjpeg.o \
video/codecs/msrle.o \
video/codecs/msvideo1.o \
- video/codecs/qdm2.o \
- video/codecs/qtrle.o \
- video/codecs/rpza.o \
- video/codecs/smc.o \
video/coktelvideo/indeo3.o \
video/coktelvideo/coktelvideo.o
diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp
index 4c3c770c60..944c9700bd 100644
--- a/graphics/video/avi_decoder.cpp
+++ b/graphics/video/avi_decoder.cpp
@@ -35,7 +35,6 @@
#include "graphics/video/avi_decoder.h"
// Codecs
-#include "graphics/video/codecs/cinepak.h"
#include "graphics/video/codecs/msvideo1.h"
#include "graphics/video/codecs/msrle.h"
@@ -154,8 +153,10 @@ void AviDecoder::handleStreamHeader() {
sHeader.bufferSize = _fileStream->readUint32LE();
sHeader.quality = _fileStream->readUint32LE();
sHeader.sampleSize = _fileStream->readUint32LE();
-
- _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame)
+ sHeader.frame.left = _fileStream->readSint16LE();
+ sHeader.frame.top = _fileStream->readSint16LE();
+ sHeader.frame.right = _fileStream->readSint16LE();
+ sHeader.frame.bottom = _fileStream->readSint16LE();
if (_fileStream->readUint32BE() != ID_STRF)
error("Could not find STRF tag");
@@ -186,14 +187,11 @@ void AviDecoder::handleStreamHeader() {
_palette[i * 3 + 2] = _fileStream->readByte();
_palette[i * 3 + 1] = _fileStream->readByte();
_palette[i * 3] = _fileStream->readByte();
- _fileStream->readByte();
+ /*_palette[i * 4 + 3] = */_fileStream->readByte();
}
_dirtyPalette = true;
}
-
- if (!_vidsHeader.streamHandler)
- _vidsHeader.streamHandler = _bmInfo.compression;
} else if (sHeader.streamType == ID_AUDS) {
_audsHeader = sHeader;
@@ -203,11 +201,6 @@ void AviDecoder::handleStreamHeader() {
_wvInfo.avgBytesPerSec = _fileStream->readUint32LE();
_wvInfo.blockAlign = _fileStream->readUint16LE();
_wvInfo.size = _fileStream->readUint16LE();
-
- // AVI seems to treat the sampleSize as including the second
- // channel as well, so divide for our sake.
- if (_wvInfo.channels == 2)
- _audsHeader.sampleSize /= 2;
}
}
@@ -331,9 +324,6 @@ Surface *AviDecoder::decodeNextFrame() {
else
flags |= Audio::FLAG_UNSIGNED;
- if (_wvInfo.channels == 2)
- flags |= Audio::FLAG_STEREO;
-
_audStream->queueBuffer(data, chunkSize, DisposeAfterUse::YES, flags);
_fileStream->skip(chunkSize & 1); // Alignment
} else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' ||
@@ -389,8 +379,6 @@ Codec *AviDecoder::createCodec() {
return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount);
case ID_RLE :
return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount);
- case ID_CVID:
- return new CinepakDecoder();
default:
warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler));
}
@@ -405,7 +393,7 @@ PixelFormat AviDecoder::getPixelFormat() const {
Audio::QueuingAudioStream *AviDecoder::createAudioStream() {
if (_wvInfo.tag == AVI_WAVE_FORMAT_PCM)
- return Audio::makeQueuingAudioStream(AUDIO_RATE, _wvInfo.channels == 2);
+ return Audio::makeQueuingAudioStream(AUDIO_RATE, false);
if (_wvInfo.tag != 0) // No sound
warning ("Unsupported AVI audio format %d", _wvInfo.tag);
diff --git a/graphics/video/codecs/mjpeg.cpp b/graphics/video/codecs/mjpeg.cpp
deleted file mode 100644
index 76363036ee..0000000000
--- a/graphics/video/codecs/mjpeg.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/system.h"
-#include "graphics/conversion.h" // For YUV2RGB
-
-#include "graphics/video/codecs/mjpeg.h"
-
-namespace Graphics {
-
-JPEGDecoder::JPEGDecoder() : Codec() {
- _jpeg = new JPEG();
- _pixelFormat = g_system->getScreenFormat();
- _surface = NULL;
-}
-
-JPEGDecoder::~JPEGDecoder() {
- delete _jpeg;
-
- if (_surface) {
- _surface->free();
- delete _surface;
- }
-}
-
-Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) {
- _jpeg->read(stream);
- Surface *ySurface = _jpeg->getComponent(1);
- Surface *uSurface = _jpeg->getComponent(2);
- Surface *vSurface = _jpeg->getComponent(3);
-
- if (!_surface) {
- _surface = new Surface();
- _surface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel);
- }
-
- for (uint16 i = 0; i < _surface->h; i++) {
- for (uint16 j = 0; j < _surface->w; j++) {
- byte r = 0, g = 0, b = 0;
- YUV2RGB(*((byte *)ySurface->getBasePtr(j, i)), *((byte *)uSurface->getBasePtr(j, i)), *((byte *)vSurface->getBasePtr(j, i)), r, g, b);
- if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)_surface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
- else
- *((uint32 *)_surface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
- }
- }
-
- return _surface;
-}
-
-} // End of namespace Graphics
diff --git a/graphics/video/codecs/qdm2.h b/graphics/video/codecs/qdm2.h
deleted file mode 100644
index c9a01a70ee..0000000000
--- a/graphics/video/codecs/qdm2.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// Only compile if Mohawk is enabled or if we're building dynamic modules
-#if defined(ENABLE_MOHAWK) || defined(DYNAMIC_MODULES)
-
-#ifndef GRAPHICS_QDM2_H
-#define GRAPHICS_QDM2_H
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Audio {
- class AudioStream;
-}
-
-namespace Graphics {
-
-/**
- * Create a new AudioStream from the QDM2 data in the given stream.
- *
- * @param stream the SeekableReadStream from which to read the FLAC data
- * @param extraData the QuickTime extra data stream
- * @return a new AudioStream, or NULL, if an error occured
- */
-Audio::AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
-
-} // End of namespace Graphics
-
-#endif // GRAPHICS_QDM2_H
-#endif // Mohawk/Plugins guard
diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp
index 0b7de774eb..3f200b5971 100644
--- a/graphics/video/smk_decoder.cpp
+++ b/graphics/video/smk_decoder.cpp
@@ -25,7 +25,7 @@
// Based on http://wiki.multimedia.cx/index.php?title=Smacker
// and the FFmpeg Smacker decoder (libavcodec/smacker.c), revision 16143
-// http://git.ffmpeg.org/?p=ffmpeg;a=blob;f=libavcodec/smacker.c;hb=b8437a00a2f14d4a437346455d624241d726128e
+// http://svn.ffmpeg.org/ffmpeg/trunk/libavcodec/smacker.c?revision=16143&view=markup
#include "graphics/video/smk_decoder.h"
@@ -361,7 +361,7 @@ SmackerDecoder::~SmackerDecoder() {
}
uint32 SmackerDecoder::getElapsedTime() const {
- if (_audioStream && _audioStarted)
+ if (_audioStream)
return _mixer->getSoundElapsedTime(_audioHandle);
return VideoDecoder::getElapsedTime();
diff --git a/gui/ListWidget.cpp b/gui/ListWidget.cpp
index 97dde29824..ad6c7e0c3a 100644
--- a/gui/ListWidget.cpp
+++ b/gui/ListWidget.cpp
@@ -36,7 +36,7 @@
namespace GUI {
-ListWidget::ListWidget(Dialog *boss, const String &name, uint32 cmd)
+ListWidget::ListWidget(GuiObject *boss, const String &name, uint32 cmd)
: EditableWidget(boss, name), _cmd(cmd) {
_scrollBar = NULL;
@@ -68,7 +68,7 @@ ListWidget::ListWidget(Dialog *boss, const String &name, uint32 cmd)
_editColor = ThemeEngine::kFontColorNormal;
}
-ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h, uint32 cmd)
+ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd)
: EditableWidget(boss, x, y, w, h), _cmd(cmd) {
_scrollBar = NULL;
@@ -472,10 +472,6 @@ void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
if (_currentPos != (int)data) {
_currentPos = data;
draw();
-
- // Scrollbar actions cause list focus (which triggers a redraw)
- // NOTE: ListWidget's boss is always GUI::Dialog
- ((GUI::Dialog *)_boss)->setFocusWidget(this);
}
break;
}
diff --git a/gui/ListWidget.h b/gui/ListWidget.h
index a3fb825761..02f2c22e7c 100644
--- a/gui/ListWidget.h
+++ b/gui/ListWidget.h
@@ -87,8 +87,8 @@ protected:
ThemeEngine::FontColor _editColor;
public:
- ListWidget(Dialog *boss, const String &name, uint32 cmd = 0);
- ListWidget(Dialog *boss, int x, int y, int w, int h, uint32 cmd = 0);
+ ListWidget(GuiObject *boss, const String &name, uint32 cmd = 0);
+ ListWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd = 0);
virtual ~ListWidget();
virtual Widget *findWidget(int x, int y);
diff --git a/gui/about.cpp b/gui/about.cpp
index 8b2f470bf6..74851caf94 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -81,10 +81,31 @@ AboutDialog::AboutDialog()
: Dialog(10, 20, 300, 174),
_scrollPos(0), _scrollTime(0), _willClose(false) {
- reflowLayout();
-
int i;
+ const int screenW = g_system->getOverlayWidth();
+ const int screenH = g_system->getOverlayHeight();
+
+ _xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5);
+ _yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5);
+ int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder");
+
+ _w = screenW - 2 * outerBorder;
+ _h = screenH - 2 * outerBorder;
+
+ _lineHeight = g_gui.getFontHeight() + 3;
+
+ // Heuristic to compute 'optimal' dialog width
+ int maxW = _w - 2*_xOff;
+ _w = 0;
+ for (i = 0; i < ARRAYSIZE(credits); i++) {
+ int tmp = g_gui.getStringWidth(credits[i] + 5);
+ if (_w < tmp && tmp <= maxW) {
+ _w = tmp;
+ }
+ }
+ _w += 2*_xOff;
+
for (i = 0; i < 1; i++)
_lines.push_back("");
@@ -130,6 +151,10 @@ AboutDialog::AboutDialog()
for (i = 0; i < ARRAYSIZE(credits); i++)
addLine(credits[i]);
+
+ // Center the dialog
+ _x = (screenW - _w) / 2;
+ _y = (screenH - _h) / 2;
}
void AboutDialog::addLine(const char *str) {
@@ -269,7 +294,6 @@ void AboutDialog::handleKeyUp(Common::KeyState state) {
void AboutDialog::reflowLayout() {
Dialog::reflowLayout();
- int i;
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
@@ -285,7 +309,7 @@ void AboutDialog::reflowLayout() {
// Heuristic to compute 'optimal' dialog width
int maxW = _w - 2*_xOff;
_w = 0;
- for (i = 0; i < ARRAYSIZE(credits); i++) {
+ for (int i = 0; i < ARRAYSIZE(credits); i++) {
int tmp = g_gui.getStringWidth(credits[i] + 5);
if (_w < tmp && tmp <= maxW) {
_w = tmp;
@@ -293,7 +317,8 @@ void AboutDialog::reflowLayout() {
}
_w += 2*_xOff;
- // Center the dialog
+ _lineHeight = g_gui.getFontHeight() + 3;
+
_x = (screenW - _w) / 2;
_y = (screenH - _h) / 2;
}
diff --git a/gui/editable.cpp b/gui/editable.cpp
index 058f08e233..723384ed44 100644
--- a/gui/editable.cpp
+++ b/gui/editable.cpp
@@ -65,7 +65,7 @@ void EditableWidget::setEditString(const String &str) {
// TODO: We probably should filter the input string here,
// e.g. using tryInsertChar.
_editString = str;
- _caretPos = 0;
+ _caretPos = _editString.size();
}
bool EditableWidget::tryInsertChar(byte c, int pos) {
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 93897a7d88..75c4fb73de 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1,397 +1,38 @@
"<?xml version = '1.0'?>"
-"<render_info> "
-"<palette> "
-"<color name='black' "
-"rgb='0,0,0' "
-"/> "
-"<color name='lightgrey' "
-"rgb='104,104,104' "
-"/> "
-"<color name='darkgrey' "
-"rgb='64,64,64' "
-"/> "
-"<color name='green' "
-"rgb='32,160,32' "
-"/> "
-"<color name='green2' "
-"rgb='0,255,0' "
-"/> "
-"</palette> "
-"<fonts> "
-"<font id='text_default' "
-"file='default' "
-"/> "
-"<font id='text_button' "
-"file='default' "
-"/> "
-"<font id='text_normal' "
-"file='default' "
-"/> "
-"<text_color id='color_normal' "
-"color='green' "
-"/> "
-"<text_color id='color_normal_inverted' "
-"color='black' "
-"/> "
-"<text_color id='color_normal_hover' "
-"color='green2' "
-"/> "
-"<text_color id='color_normal_disabled' "
-"color='lightgrey' "
-"/> "
-"<text_color id='color_alternative' "
-"color='lightgrey' "
-"/> "
-"<text_color id='color_alternative_inverted' "
-"color='255,255,255' "
-"/> "
-"<text_color id='color_alternative_hover' "
-"color='176,176,176' "
-"/> "
-"<text_color id='color_alternative_disabled' "
-"color='darkgrey' "
-"/> "
-"<text_color id='color_button' "
-"color='green' "
-"/> "
-"<text_color id='color_button_hover' "
-"color='green2' "
-"/> "
-"<text_color id='color_button_disabled' "
-"color='lightgrey' "
-"/> "
-"</fonts> "
-"<defaults fill='foreground' fg_color='darkgrey' bg_color='black' shadow='0' bevel_color='lightgrey'/> "
-"<drawdata id='text_selection' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='lightgrey' "
-"/> "
-"</drawdata> "
-"<drawdata id='text_selection_focus' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='green' "
-"/> "
-"</drawdata> "
-"<drawdata id='mainmenu_bg' cache='false'> "
-"<drawstep func='fill' "
-"fill='foreground' "
-"fg_color='black' "
-"/> "
-"</drawdata> "
-"<drawdata id='special_bg' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"/> "
-"</drawdata> "
-"<drawdata id='separator' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"height='2' "
-"ypos='center' "
-"fg_color='lightgrey' "
-"/> "
-"</drawdata> "
-"<drawdata id='scrollbar_base' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"/> "
-"</drawdata> "
-"<drawdata id='scrollbar_handle_hover' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='green2' "
-"/> "
-"</drawdata> "
-"<drawdata id='scrollbar_handle_idle' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='green' "
-"/> "
-"</drawdata> "
-"<drawdata id='scrollbar_button_idle' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"<drawstep func='triangle' "
-"fg_color='green' "
-"fill='foreground' "
-"width='auto' "
-"height='auto' "
-"xpos='center' "
-"ypos='center' "
-"orientation='top' "
-"/> "
-"</drawdata> "
-"<drawdata id='scrollbar_button_hover' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"<drawstep func='triangle' "
-"fg_color='green2' "
-"fill='foreground' "
-"width='auto' "
-"height='auto' "
-"xpos='center' "
-"ypos='center' "
-"orientation='top' "
-"/> "
-"</drawdata> "
-"<drawdata id='tab_active' cache='false'> "
-"<text font='text_default' "
-"text_color='color_normal_hover' "
-"vertical_align='center' "
-"horizontal_align='center' "
-"/> "
-"<drawstep func='tab' "
-"bevel='2' "
-"radius='0' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='tab_inactive' cache='false'> "
-"<text font='text_default' "
-"text_color='color_normal' "
-"vertical_align='center' "
-"horizontal_align='center' "
-"/> "
-"<drawstep func='tab' "
-"bevel='2' "
-"radius='0' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='tab_background' cache='false'> "
-"</drawdata> "
-"<drawdata id='widget_slider' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='slider_disabled' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='lightgrey' "
-"/> "
-"</drawdata> "
-"<drawdata id='slider_full' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='green' "
-"/> "
-"</drawdata> "
-"<drawdata id='slider_hover' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='green2' "
-"/> "
-"</drawdata> "
-"<drawdata id='widget_small' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='popup_idle' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"<drawstep func='triangle' "
-"fg_color='green' "
-"fill='foreground' "
-"width='height' "
-"height='auto' "
-"xpos='right' "
-"ypos='center' "
-"orientation='bottom' "
-"/> "
-"<text font='text_default' "
-"text_color='color_normal' "
-"vertical_align='center' "
-"horizontal_align='left' "
-"/> "
-"</drawdata> "
-"<drawdata id='popup_disabled' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"<drawstep func='triangle' "
-"fg_color='lightgrey' "
-"fill='foreground' "
-"width='height' "
-"height='auto' "
-"xpos='right' "
-"ypos='center' "
-"orientation='bottom' "
-"/> "
-"<text font='text_default' "
-"text_color='color_normal_disabled' "
-"vertical_align='center' "
-"horizontal_align='left' "
-"/> "
-"</drawdata> "
-"<drawdata id='popup_hover' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"<drawstep func='triangle' "
-"fg_color='green2' "
-"fill='foreground' "
-"width='height' "
-"height='auto' "
-"xpos='right' "
-"ypos='center' "
-"orientation='bottom' "
-"/> "
-"<text font='text_default' "
-"text_color='color_normal_hover' "
-"vertical_align='center' "
-"horizontal_align='left' "
-"/> "
-"</drawdata> "
-"<drawdata id='widget_textedit' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='plain_bg' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"/> "
-"</drawdata> "
-"<drawdata id='caret' cache='false'> "
-"<drawstep func='square' "
-"fill='foreground' "
-"fg_color='lightgrey' "
-"/> "
-"</drawdata> "
-"<drawdata id='default_bg' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"/> "
-"</drawdata> "
-"<drawdata id='button_idle' cache='false'> "
-"<text font='text_button' "
-"text_color='color_button' "
-"vertical_align='center' "
-"horizontal_align='center' "
-"/> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='button_hover' cache='false'> "
-"<text font='text_button' "
-"text_color='color_button_hover' "
-"vertical_align='center' "
-"horizontal_align='center' "
-"/> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='button_disabled' cache='false'> "
-"<text font='text_button' "
-"text_color='color_button_disabled' "
-"vertical_align='center' "
-"horizontal_align='center' "
-"/> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='checkbox_disabled' cache='false'> "
-"<text font='text_default' "
-"text_color='color_normal_disabled' "
-"vertical_align='top' "
-"horizontal_align='left' "
-"/> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='checkbox_selected' cache='false'> "
-"<text font='text_default' "
-"text_color='color_normal' "
-"vertical_align='top' "
-"horizontal_align='left' "
-"/> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"<drawstep func='cross' "
-"fill='foreground' "
-"stroke='2' "
-"fg_color='green' "
-"/> "
-"</drawdata> "
-"<drawdata id='checkbox_default' cache='false'> "
-"<text font='text_default' "
-"text_color='color_normal' "
-"vertical_align='top' "
-"horizontal_align='left' "
-"/> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"fill='none' "
-"/> "
-"</drawdata> "
-"<drawdata id='widget_default' cache='false'> "
-"<drawstep func='bevelsq' "
-"bevel='2' "
-"/> "
-"</drawdata> "
-"</render_info> "
-"<layout_info resolution='-320xY,-256x240,-Xx272'> "
+"<layout_info resolution='320xY,256x240,Xx272'> "
"<globals> "
-"<def var='Line.Height' value='16' /> "
-"<def var='Font.Height' value='16' /> "
-"<def var='About.OuterBorder' value='80'/> "
-"<def var='Layout.Spacing' value='8' /> "
+"<def var='Line.Height' value='12' /> "
+"<def var='Font.Height' value='10' /> "
+"<def var='About.OuterBorder' value='10'/> "
+"<def var='Layout.Spacing' value='8'/> "
"<def var='ShowLauncherLogo' value='0'/> "
"<def var='ShowGlobalMenuLogo' value='0'/> "
"<def var='ShowSearchPic' value='0'/> "
-"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> "
-"<def var='KeyMapper.Spacing' value='10'/> "
-"<def var='KeyMapper.LabelWidth' value='100'/> "
-"<def var='KeyMapper.ButtonWidth' value='80'/> "
+"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> "
+"<def var='KeyMapper.Spacing' value='5'/> "
+"<def var='KeyMapper.LabelWidth' value='80'/> "
+"<def var='KeyMapper.ButtonWidth' value='60'/> "
+"<widget name='Button' "
+"size='72,16' "
+"/> "
+"<widget name='Slider' "
+"size='85,12' "
+"/> "
"<widget name='OptionsLabel' "
"size='110,Globals.Line.Height' "
"textalign='right' "
"/> "
"<widget name='SmallLabel' "
-"size='24,Globals.Line.Height' "
-"/> "
-"<widget name='ShortOptionsLabel' "
-"size='60,Globals.Line.Height' "
-"/> "
-"<widget name='Button' "
-"size='108,24' "
-"/> "
-"<widget name='Slider' "
-"size='128,18' "
+"size='18,Globals.Line.Height' "
"/> "
"<widget name='PopUp' "
-"size='-1,19' "
+"size='-1,15' "
"/> "
"<widget name='Checkbox' "
-"size='-1,14' "
+"size='-1,Globals.Line.Height' "
"/> "
"<widget name='ListWidget' "
-"padding='5,0,8,0' "
+"padding='5,0,0,0' "
"/> "
"<widget name='PopUpWidget' "
"padding='7,5,0,0' "
@@ -403,25 +44,25 @@
"padding='7,5,5,5' "
"/> "
"<widget name='Scrollbar' "
-"size='15,0' "
+"size='9,0' "
"/> "
"<widget name='TabWidget.Tab' "
-"size='75,27' "
-"padding='0,0,8,0' "
+"size='45,16' "
+"padding='0,0,2,0' "
"/> "
"<widget name='TabWidget.NavButton' "
-"size='15,18' "
+"size='32,18' "
"padding='0,3,4,0' "
"/> "
"</globals> "
"<dialog name='Launcher' overlays='screen'> "
-"<layout type='vertical' center='true' padding='16,16,8,8'> "
+"<layout type='vertical' center='true' padding='8,8,4,4'> "
"<widget name='Version' "
"height='Globals.Line.Height' "
"/> "
"<layout type='horizontal' spacing='5' padding='10,0,0,0'> "
"<widget name='SearchDesc' "
-"width='60' "
+"width='50' "
"height='Globals.Line.Height' "
"textalign='right' "
"/> "
@@ -438,37 +79,36 @@
"<widget name='GameList'/> "
"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='LoadGameButton' "
-"height='20' "
+"height='12' "
"/> "
"<widget name='AddGameButton' "
-"height='20' "
+"height='12' "
"/> "
"<widget name='EditGameButton' "
-"height='20' "
+"height='12' "
"/> "
"<widget name='RemoveGameButton' "
-"height='20' "
+"height='12' "
"/> "
"</layout> "
-"<space size='4'/> "
"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='QuitButton' "
-"height='20' "
+"height='12' "
"/> "
"<widget name='AboutButton' "
-"height='20' "
+"height='12' "
"/> "
"<widget name='OptionsButton' "
-"height='20' "
+"height='12' "
"/> "
"<widget name='StartButton' "
-"height='20' "
+"height='12' "
"/> "
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'> "
-"<layout type='vertical' padding='8,8,8,8'> "
+"<dialog name='Browser' overlays='screen' inset='8' shading='dim'> "
+"<layout type='vertical' padding='8,8,0,4'> "
"<widget name='Headline' "
"height='Globals.Line.Height' "
"/> "
@@ -476,7 +116,7 @@
"height='Globals.Line.Height' "
"/> "
"<widget name='List'/> "
-"<layout type='horizontal' padding='0,0,16,0'> "
+"<layout type='horizontal' padding='0,0,8,0'> "
"<widget name='Up' "
"type='Button' "
"/> "
@@ -490,10 +130,10 @@
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'> "
+"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'> "
"<layout type='vertical' padding='0,0,0,0'> "
"<widget name='TabWidget'/> "
-"<layout type='horizontal' padding='16,16,16,16'> "
+"<layout type='horizontal' padding='8,8,8,8'> "
"<space/> "
"<widget name='Cancel' "
"type='Button' "
@@ -506,7 +146,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='grModePopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -514,7 +154,7 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='grRenderPopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -532,7 +172,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='auMidiPopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -540,7 +180,7 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='auOPLPopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -548,7 +188,7 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='auSampleRatePopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -556,16 +196,16 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='subToggleDesc' "
"type='OptionsLabel' "
"/> "
"<widget name='subToggleButton' "
-"width='150' "
+"width='128' "
"height='Globals.Slider.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='subSubtitleSpeedDesc' "
"type='OptionsLabel' "
"/> "
@@ -579,9 +219,8 @@
"</layout> "
"</dialog> "
"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='horizontal' padding='16,16,16,16' spacing='8'> "
-"<layout type='vertical' padding='0,0,0,0' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='vcMusicText' "
"type='OptionsLabel' "
"/> "
@@ -592,7 +231,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='vcSfxText' "
"type='OptionsLabel' "
"/> "
@@ -603,7 +242,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='vcSpeechText' "
"type='OptionsLabel' "
"/> "
@@ -614,8 +253,8 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"</layout> "
-"<layout type='vertical' padding='24,0,24,0' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<space size='110' /> "
"<widget name='vcMuteCheckbox' "
"type='Checkbox' "
"/> "
@@ -624,7 +263,7 @@
"</dialog> "
"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
"<widget name='mcFontButton' "
"type='Button' "
"/> "
@@ -645,7 +284,7 @@
"<widget name='mcGSCheckbox' "
"type='Checkbox' "
"/> "
-"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='mcMidiGainText' "
"type='OptionsLabel' "
"/> "
@@ -661,7 +300,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
"<widget name='SaveButton' "
"type='Button' "
"/> "
@@ -669,7 +308,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
"<widget name='ThemeButton' "
"type='Button' "
"/> "
@@ -677,7 +316,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
"<widget name='ExtraButton' "
"type='Button' "
"/> "
@@ -697,7 +336,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
"<widget name='ThemeButton' "
"type='Button' "
"/> "
@@ -705,17 +344,21 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='RendererPopupDesc' "
-"type='OptionsLabel' "
+"width='80' "
+"height='Globals.Line.Height' "
+"textalign='right' "
"/> "
"<widget name='RendererPopup' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='AutosavePeriodPopupDesc' "
-"type='OptionsLabel' "
+"width='80' "
+"height='Globals.Line.Height' "
+"textalign='right' "
"/> "
"<widget name='AutosavePeriodPopup' "
"type='PopUp' "
@@ -750,10 +393,10 @@
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'> "
+"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'> "
"<layout type='vertical' padding='0,0,0,0' spacing='16'> "
"<widget name='TabWidget'/> "
-"<layout type='horizontal' padding='16,16,16,4'> "
+"<layout type='horizontal' padding='8,8,8,8'> "
"<space/> "
"<widget name='Cancel' "
"type='Button' "
@@ -765,7 +408,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
+"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -773,7 +416,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
+"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -781,7 +424,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
+"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -789,7 +432,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
+"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -797,34 +440,43 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> "
-"<layout type='vertical' padding='16,16,16,16'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='vertical' padding='8,8,8,8'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='Id' "
-"type='OptionsLabel' "
+"width='35' "
+"height='Globals.Line.Height' "
+"textalign='right' "
"/> "
"<widget name='Domain' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='Name' "
-"type='OptionsLabel' "
+"width='35' "
+"height='Globals.Line.Height' "
+"textalign='right' "
"/> "
"<widget name='Desc' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<space size='8'/> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='LangPopupDesc' "
-"type='OptionsLabel' "
+"width='60' "
+"height='Globals.Line.Height' "
+"textalign='right' "
"/> "
"<widget name='LangPopup' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='PlatformPopupDesc' "
-"type='OptionsLabel' "
+"width='60' "
+"height='Globals.Line.Height' "
+"textalign='right' "
"/> "
"<widget name='PlatformPopup' "
"type='PopUp' "
@@ -833,8 +485,8 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> "
-"<layout type='vertical' padding='16,16,16,16'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='vertical' padding='8,8,8,8'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
"<widget name='Savepath' "
"type='Button' "
"/> "
@@ -842,7 +494,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
"<widget name='Extrapath' "
"type='Button' "
"/> "
@@ -850,7 +502,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
"<widget name='Gamepath' "
"type='Button' "
"/> "
@@ -861,57 +513,86 @@
"</layout> "
"</dialog> "
"<dialog name='GlobalMenu' overlays='screen_center'> "
-"<layout type='vertical' padding='16,16,16,16' center='true'> "
+"<layout type='vertical' padding='8,8,4,6' center='true'> "
"<widget name='Title' "
-"width='210' "
-"height='Globals.Line.Height' "
+"width='160' "
+"height='4' "
"/> "
"<widget name='Version' "
-"width='210' "
-"height='Globals.Line.Height' "
+"width='160' "
+"height='4' "
+"/> "
+"<space size='1'/> "
+"<widget name='Load' "
+"width='120' "
+"height='12' "
"/> "
+"<widget name='Save' "
+"width='120' "
+"height='12' "
+"/> "
+"<space size='1'/> "
+"<widget name='Options' "
+"width='120' "
+"height='12' "
+"/> "
+"<widget name='About' "
+"width='120' "
+"height='12' "
+"/> "
+"<space size='1'/> "
"<widget name='Resume' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='120' "
+"height='12' "
"/> "
-"<space size='10'/> "
+"<widget name='RTL' "
+"width='120' "
+"height='12' "
+"/> "
+"<widget name='Quit' "
+"width='120' "
+"height='12' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name='ScummMain' overlays='screen_center'> "
+"<layout type='vertical' padding='8,8,8,8'> "
+"<widget name='Resume' "
+"width='Globals.Button.Width' "
+"height='14' "
+"/> "
+"<space size='2'/> "
"<widget name='Load' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='Globals.Button.Width' "
+"height='14' "
"/> "
"<widget name='Save' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='Globals.Button.Width' "
+"height='14' "
"/> "
-"<space size='10'/> "
+"<space size='2'/> "
"<widget name='Options' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='Globals.Button.Width' "
+"height='14' "
"/> "
"<widget name='Help' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='Globals.Button.Width' "
+"height='14' "
"/> "
"<widget name='About' "
-"width='150' "
-"height='Globals.Button.Height' "
-"/> "
-"<space size='10'/> "
-"<widget name='RTL' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='Globals.Button.Width' "
+"height='14' "
"/> "
+"<space size='2'/> "
"<widget name='Quit' "
-"width='150' "
-"height='Globals.Button.Height' "
+"width='Globals.Button.Width' "
+"height='14' "
"/> "
"</layout> "
"</dialog> "
-"<dialog name='GlobalConfig' overlays='screen_center'> "
+"<dialog name='ScummConfig' overlays='screen_center'> "
"<layout type='vertical' padding='8,8,8,8'> "
-"<layout type='horizontal' padding='0,0,0,0'> "
-"<layout type='vertical' padding='0,0,0,0' center='true'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='vcMusicText' "
"type='OptionsLabel' "
"/> "
@@ -922,7 +603,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='vcSfxText' "
"type='OptionsLabel' "
"/> "
@@ -933,7 +614,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='vcSpeechText' "
"type='OptionsLabel' "
"/> "
@@ -944,25 +625,24 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"</layout> "
-"<layout type='vertical' padding='24,24,24,24' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<space size='110' /> "
"<widget name='vcMuteCheckbox' "
"type='Checkbox' "
-"width='80' "
+"width='80' "
"/> "
"</layout> "
-"</layout> "
-"<space size='8' /> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
+"<space size='4' /> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='subToggleDesc' "
"type='OptionsLabel' "
"/> "
"<widget name='subToggleButton' "
-"width='158' "
+"width='128' "
"height='Globals.Slider.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
"<widget name='subSubtitleSpeedDesc' "
"type='OptionsLabel' "
"/> "
@@ -973,8 +653,8 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<space size='60'/> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
+"<space size='20'/> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='4'> "
"<widget name='Keys' "
"type='Button' "
"/> "
@@ -989,23 +669,15 @@
"</layout> "
"</dialog> "
"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> "
-"<layout type='vertical' padding='8,8,8,32' center='true'> "
-"<widget name='Title' "
-"height='Globals.Line.Height' "
-"/> "
-"<layout type='horizontal' padding='0,0,0,16' spacing='16'> "
+"<layout type='vertical' padding='8,8,8,8' center='true'> "
+"<widget name='Title' height='Globals.Line.Height'/> "
"<widget name='List' /> "
-"<widget name='Thumbnail' "
-"width='180' "
-"height='200' "
-"/> "
-"</layout> "
-"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='horizontal' padding='0,0,16,0'> "
"<space/> "
"<widget name='Delete' "
"type='Button' "
"/> "
-"<space size='32'/> "
+"<space size='16'/> "
"<widget name='Cancel' "
"type='Button' "
"/> "
@@ -1015,16 +687,16 @@
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='ScummHelp' overlays='screen_center'> "
-"<layout type='vertical' padding='8,8,8,8' center='true'> "
+"<dialog name='ScummHelp' overlays='screen'> "
+"<layout type='vertical' padding='8,8,8,8'> "
"<widget name='Title' "
-"width='320' "
+"width='180' "
"height='Globals.Line.Height' "
"/> "
"<widget name='HelpText' "
-"height='200' "
+"height='140' "
"/> "
-"<layout type='horizontal' padding='0,0,16,0'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<widget name='Prev' "
"type='Button' "
"/> "
@@ -1039,20 +711,20 @@
"</layout> "
"</dialog> "
"<dialog name='MassAdd' overlays='screen_center' shading='dim'> "
-"<layout type='vertical' padding='8,8,32,8' center='true'> "
+"<layout type='vertical' padding='4,4,16,4' center='true'> "
"<widget name='DirProgressText' "
-"width='480' "
+"width='280' "
"height='Globals.Line.Height' "
"/> "
"<widget name='GameProgressText' "
-"width='480' "
+"width='280' "
"height='Globals.Line.Height' "
"/> "
"<widget name='GameList' "
-"width='480' "
-"height='250' "
+"width='280' "
+"height='100' "
"/> "
-"<layout type='horizontal' padding='8,8,8,8'> "
+"<layout type='horizontal' padding='4,4,4,4'> "
"<widget name='Ok' "
"type='Button' "
"/> "
@@ -1063,20 +735,20 @@
"</layout> "
"</dialog> "
"<dialog name='KeyMapper' overlays='screen_center' shading='dim'> "
-"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'> "
+"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'> "
"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='PopupDesc' "
"type='OptionsLabel' "
"/> "
"<widget name='Popup' "
"type='PopUp' "
-"width='400' "
+"width='150' "
"height='Globals.Line.Height' "
"/> "
"</layout> "
"<widget name='KeymapArea' "
-"width='600' "
-"height='280' "
+"width='300' "
+"height='120' "
"/> "
"<widget name='Close' "
"type='Button' "
@@ -1084,40 +756,43 @@
"</layout> "
"</dialog> "
"</layout_info> "
-"<layout_info resolution='320xY,256x240,Xx272'> "
+"<layout_info resolution='-320xY,-256x240,-Xx272'> "
"<globals> "
-"<def var='Line.Height' value='12' /> "
-"<def var='Font.Height' value='10' /> "
-"<def var='About.OuterBorder' value='10'/> "
-"<def var='Layout.Spacing' value='8'/> "
+"<def var='Line.Height' value='16' /> "
+"<def var='Font.Height' value='16' /> "
+"<def var='About.OuterBorder' value='80'/> "
+"<def var='Layout.Spacing' value='8' /> "
"<def var='ShowLauncherLogo' value='0'/> "
"<def var='ShowGlobalMenuLogo' value='0'/> "
"<def var='ShowSearchPic' value='0'/> "
-"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> "
-"<def var='KeyMapper.Spacing' value='5'/> "
-"<def var='KeyMapper.LabelWidth' value='80'/> "
-"<def var='KeyMapper.ButtonWidth' value='60'/> "
-"<widget name='Button' "
-"size='72,16' "
-"/> "
-"<widget name='Slider' "
-"size='85,12' "
-"/> "
+"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> "
+"<def var='KeyMapper.Spacing' value='10'/> "
+"<def var='KeyMapper.LabelWidth' value='100'/> "
+"<def var='KeyMapper.ButtonWidth' value='80'/> "
"<widget name='OptionsLabel' "
"size='110,Globals.Line.Height' "
"textalign='right' "
"/> "
"<widget name='SmallLabel' "
-"size='18,Globals.Line.Height' "
+"size='24,Globals.Line.Height' "
+"/> "
+"<widget name='ShortOptionsLabel' "
+"size='60,Globals.Line.Height' "
+"/> "
+"<widget name='Button' "
+"size='108,24' "
+"/> "
+"<widget name='Slider' "
+"size='128,18' "
"/> "
"<widget name='PopUp' "
-"size='-1,15' "
+"size='-1,19' "
"/> "
"<widget name='Checkbox' "
-"size='-1,Globals.Line.Height' "
+"size='-1,14' "
"/> "
"<widget name='ListWidget' "
-"padding='5,0,0,0' "
+"padding='5,0,8,0' "
"/> "
"<widget name='PopUpWidget' "
"padding='7,5,0,0' "
@@ -1129,25 +804,25 @@
"padding='7,5,5,5' "
"/> "
"<widget name='Scrollbar' "
-"size='9,0' "
+"size='15,0' "
"/> "
"<widget name='TabWidget.Tab' "
-"size='45,16' "
-"padding='0,0,2,0' "
+"size='75,27' "
+"padding='0,0,8,0' "
"/> "
"<widget name='TabWidget.NavButton' "
-"size='32,18' "
+"size='15,18' "
"padding='0,3,4,0' "
"/> "
"</globals> "
"<dialog name='Launcher' overlays='screen'> "
-"<layout type='vertical' center='true' padding='8,8,4,4'> "
+"<layout type='vertical' center='true' padding='16,16,8,8'> "
"<widget name='Version' "
"height='Globals.Line.Height' "
"/> "
"<layout type='horizontal' spacing='5' padding='10,0,0,0'> "
"<widget name='SearchDesc' "
-"width='50' "
+"width='60' "
"height='Globals.Line.Height' "
"textalign='right' "
"/> "
@@ -1164,36 +839,37 @@
"<widget name='GameList'/> "
"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='LoadGameButton' "
-"height='12' "
+"height='20' "
"/> "
"<widget name='AddGameButton' "
-"height='12' "
+"height='20' "
"/> "
"<widget name='EditGameButton' "
-"height='12' "
+"height='20' "
"/> "
"<widget name='RemoveGameButton' "
-"height='12' "
+"height='20' "
"/> "
"</layout> "
+"<space size='4'/> "
"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='QuitButton' "
-"height='12' "
+"height='20' "
"/> "
"<widget name='AboutButton' "
-"height='12' "
+"height='20' "
"/> "
"<widget name='OptionsButton' "
-"height='12' "
+"height='20' "
"/> "
"<widget name='StartButton' "
-"height='12' "
+"height='20' "
"/> "
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='Browser' overlays='screen' inset='8' shading='dim'> "
-"<layout type='vertical' padding='8,8,0,4'> "
+"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'> "
+"<layout type='vertical' padding='8,8,8,8'> "
"<widget name='Headline' "
"height='Globals.Line.Height' "
"/> "
@@ -1201,7 +877,7 @@
"height='Globals.Line.Height' "
"/> "
"<widget name='List'/> "
-"<layout type='horizontal' padding='0,0,8,0'> "
+"<layout type='horizontal' padding='0,0,16,0'> "
"<widget name='Up' "
"type='Button' "
"/> "
@@ -1215,10 +891,10 @@
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'> "
+"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'> "
"<layout type='vertical' padding='0,0,0,0'> "
"<widget name='TabWidget'/> "
-"<layout type='horizontal' padding='8,8,8,8'> "
+"<layout type='horizontal' padding='16,16,16,16'> "
"<space/> "
"<widget name='Cancel' "
"type='Button' "
@@ -1231,7 +907,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='grModePopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -1239,7 +915,7 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='grRenderPopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -1257,7 +933,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='auMidiPopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -1265,7 +941,7 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='auOPLPopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -1273,7 +949,7 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='auSampleRatePopupDesc' "
"type='OptionsLabel' "
"/> "
@@ -1281,16 +957,16 @@
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='subToggleDesc' "
"type='OptionsLabel' "
"/> "
"<widget name='subToggleButton' "
-"width='128' "
+"width='150' "
"height='Globals.Slider.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='subSubtitleSpeedDesc' "
"type='OptionsLabel' "
"/> "
@@ -1304,8 +980,9 @@
"</layout> "
"</dialog> "
"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='16,16,16,16' spacing='8'> "
+"<layout type='vertical' padding='0,0,0,0' spacing='8'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<widget name='vcMusicText' "
"type='OptionsLabel' "
"/> "
@@ -1316,7 +993,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<widget name='vcSfxText' "
"type='OptionsLabel' "
"/> "
@@ -1327,7 +1004,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<widget name='vcSpeechText' "
"type='OptionsLabel' "
"/> "
@@ -1338,8 +1015,8 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
-"<space size='110' /> "
+"</layout> "
+"<layout type='vertical' padding='24,0,24,0' center='true'> "
"<widget name='vcMuteCheckbox' "
"type='Checkbox' "
"/> "
@@ -1348,7 +1025,7 @@
"</dialog> "
"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='mcFontButton' "
"type='Button' "
"/> "
@@ -1369,7 +1046,7 @@
"<widget name='mcGSCheckbox' "
"type='Checkbox' "
"/> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<widget name='mcMidiGainText' "
"type='OptionsLabel' "
"/> "
@@ -1385,7 +1062,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='SaveButton' "
"type='Button' "
"/> "
@@ -1393,7 +1070,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='ThemeButton' "
"type='Button' "
"/> "
@@ -1401,7 +1078,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='ExtraButton' "
"type='Button' "
"/> "
@@ -1421,7 +1098,7 @@
"</dialog> "
"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> "
"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='ThemeButton' "
"type='Button' "
"/> "
@@ -1429,21 +1106,17 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='RendererPopupDesc' "
-"width='80' "
-"height='Globals.Line.Height' "
-"textalign='right' "
+"type='OptionsLabel' "
"/> "
"<widget name='RendererPopup' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='AutosavePeriodPopupDesc' "
-"width='80' "
-"height='Globals.Line.Height' "
-"textalign='right' "
+"type='OptionsLabel' "
"/> "
"<widget name='AutosavePeriodPopup' "
"type='PopUp' "
@@ -1478,10 +1151,10 @@
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'> "
+"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'> "
"<layout type='vertical' padding='0,0,0,0' spacing='16'> "
"<widget name='TabWidget'/> "
-"<layout type='horizontal' padding='8,8,8,8'> "
+"<layout type='horizontal' padding='16,16,16,4'> "
"<space/> "
"<widget name='Cancel' "
"type='Button' "
@@ -1493,7 +1166,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
+"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -1501,7 +1174,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
+"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -1509,7 +1182,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
+"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -1517,7 +1190,7 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> "
-"<layout type='vertical' padding='8,8,8,8' spacing='6'> "
+"<layout type='vertical' padding='16,16,16,16' spacing='8'> "
"<widget name='EnableTabCheckbox' "
"type='Checkbox' "
"/> "
@@ -1525,43 +1198,34 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> "
-"<layout type='vertical' padding='8,8,8,8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='vertical' padding='16,16,16,16'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='Id' "
-"width='35' "
-"height='Globals.Line.Height' "
-"textalign='right' "
+"type='OptionsLabel' "
"/> "
"<widget name='Domain' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='Name' "
-"width='35' "
-"height='Globals.Line.Height' "
-"textalign='right' "
+"type='OptionsLabel' "
"/> "
"<widget name='Desc' "
"type='PopUp' "
"/> "
"</layout> "
-"<space size='8'/> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='LangPopupDesc' "
-"width='60' "
-"height='Globals.Line.Height' "
-"textalign='right' "
+"type='OptionsLabel' "
"/> "
"<widget name='LangPopup' "
"type='PopUp' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='PlatformPopupDesc' "
-"width='60' "
-"height='Globals.Line.Height' "
-"textalign='right' "
+"type='OptionsLabel' "
"/> "
"<widget name='PlatformPopup' "
"type='PopUp' "
@@ -1570,8 +1234,8 @@
"</layout> "
"</dialog> "
"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> "
-"<layout type='vertical' padding='8,8,8,8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
+"<layout type='vertical' padding='16,16,16,16'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='Savepath' "
"type='Button' "
"/> "
@@ -1579,7 +1243,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='Extrapath' "
"type='Button' "
"/> "
@@ -1587,7 +1251,7 @@
"height='Globals.Line.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='Gamepath' "
"type='Button' "
"/> "
@@ -1598,55 +1262,81 @@
"</layout> "
"</dialog> "
"<dialog name='GlobalMenu' overlays='screen_center'> "
-"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'> "
+"<layout type='vertical' padding='16,16,16,16' center='true'> "
"<widget name='Title' "
-"width='160' "
-"height='4' "
+"width='210' "
+"height='Globals.Line.Height' "
"/> "
"<widget name='Version' "
-"width='160' "
-"height='4' "
+"width='210' "
+"height='Globals.Line.Height' "
"/> "
-"<space size='1'/> "
+"<widget name='Resume' "
+"width='150' "
+"height='Globals.Button.Height' "
+"/> "
+"<space size='10'/> "
"<widget name='Load' "
-"width='120' "
-"height='12' "
+"width='150' "
+"height='Globals.Button.Height' "
"/> "
"<widget name='Save' "
-"width='120' "
-"height='12' "
+"width='150' "
+"height='Globals.Button.Height' "
"/> "
-"<space size='1'/> "
+"<space size='10'/> "
"<widget name='Options' "
-"width='120' "
-"height='12' "
-"/> "
-"<widget name='Help' "
-"width='120' "
-"height='12' "
+"width='150' "
+"height='Globals.Button.Height' "
"/> "
"<widget name='About' "
-"width='120' "
-"height='12' "
+"width='150' "
+"height='Globals.Button.Height' "
"/> "
-"<space size='1'/> "
+"<space size='10'/> "
+"<widget name='RTL' "
+"width='150' "
+"height='Globals.Button.Height' "
+"/> "
+"<widget name='Quit' "
+"width='150' "
+"height='Globals.Button.Height' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name='ScummMain' overlays='screen_center'> "
+"<layout type='vertical' padding='8,8,8,8'> "
"<widget name='Resume' "
-"width='120' "
-"height='12' "
+"type='Button' "
"/> "
-"<widget name='RTL' "
-"width='120' "
-"height='12' "
+"<space size='15'/> "
+"<widget name='Load' "
+"type='Button' "
+"/> "
+"<widget name='Save' "
+"type='Button' "
+"/> "
+"<space size='15'/> "
+"<widget name='Options' "
+"type='Button' "
+"/> "
+"<widget name='Help' "
+"type='Button' "
+"/> "
+"<widget name='About' "
+"type='Button' "
"/> "
+"<space size='15'/> "
"<widget name='Quit' "
-"width='120' "
-"height='12' "
+"type='Button' "
"/> "
"</layout> "
"</dialog> "
-"<dialog name='GlobalConfig' overlays='screen_center'> "
+"<dialog name='ScummConfig' overlays='screen_center'> "
"<layout type='vertical' padding='8,8,8,8'> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='vertical' padding='0,0,0,0' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "
"<widget name='vcMusicText' "
"type='OptionsLabel' "
"/> "
@@ -1657,7 +1347,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "
"<widget name='vcSfxText' "
"type='OptionsLabel' "
"/> "
@@ -1668,7 +1358,7 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "
"<widget name='vcSpeechText' "
"type='OptionsLabel' "
"/> "
@@ -1679,24 +1369,25 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
-"<space size='110' /> "
+"</layout> "
+"<layout type='vertical' padding='24,24,24,24' center='true'> "
"<widget name='vcMuteCheckbox' "
"type='Checkbox' "
-"width='80' "
+"width='80' "
"/> "
"</layout> "
-"<space size='4' /> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"</layout> "
+"<space size='8' /> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='subToggleDesc' "
"type='OptionsLabel' "
"/> "
"<widget name='subToggleButton' "
-"width='128' "
+"width='158' "
"height='Globals.Slider.Height' "
"/> "
"</layout> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='subSubtitleSpeedDesc' "
"type='OptionsLabel' "
"/> "
@@ -1707,8 +1398,8 @@
"type='SmallLabel' "
"/> "
"</layout> "
-"<space size='20'/> "
-"<layout type='horizontal' padding='0,0,0,0' spacing='4'> "
+"<space size='60'/> "
+"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "
"<widget name='Keys' "
"type='Button' "
"/> "
@@ -1723,15 +1414,23 @@
"</layout> "
"</dialog> "
"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> "
-"<layout type='vertical' padding='8,8,8,8' center='true'> "
-"<widget name='Title' height='Globals.Line.Height'/> "
+"<layout type='vertical' padding='8,8,8,32' center='true'> "
+"<widget name='Title' "
+"height='Globals.Line.Height' "
+"/> "
+"<layout type='horizontal' padding='0,0,0,16' spacing='16'> "
"<widget name='List' /> "
-"<layout type='horizontal' padding='0,0,16,0'> "
+"<widget name='Thumbnail' "
+"width='180' "
+"height='200' "
+"/> "
+"</layout> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<space/> "
"<widget name='Delete' "
"type='Button' "
"/> "
-"<space size='16'/> "
+"<space size='32'/> "
"<widget name='Cancel' "
"type='Button' "
"/> "
@@ -1741,16 +1440,16 @@
"</layout> "
"</layout> "
"</dialog> "
-"<dialog name='ScummHelp' overlays='screen'> "
-"<layout type='vertical' padding='8,8,8,8'> "
+"<dialog name='ScummHelp' overlays='screen_center'> "
+"<layout type='vertical' padding='8,8,8,8' center='true'> "
"<widget name='Title' "
-"width='180' "
+"width='320' "
"height='Globals.Line.Height' "
"/> "
"<widget name='HelpText' "
-"height='140' "
+"height='200' "
"/> "
-"<layout type='horizontal' padding='0,0,0,0'> "
+"<layout type='horizontal' padding='0,0,16,0'> "
"<widget name='Prev' "
"type='Button' "
"/> "
@@ -1765,20 +1464,20 @@
"</layout> "
"</dialog> "
"<dialog name='MassAdd' overlays='screen_center' shading='dim'> "
-"<layout type='vertical' padding='4,4,16,4' center='true'> "
+"<layout type='vertical' padding='8,8,32,8' center='true'> "
"<widget name='DirProgressText' "
-"width='280' "
+"width='480' "
"height='Globals.Line.Height' "
"/> "
"<widget name='GameProgressText' "
-"width='280' "
+"width='480' "
"height='Globals.Line.Height' "
"/> "
"<widget name='GameList' "
-"width='280' "
-"height='100' "
+"width='480' "
+"height='250' "
"/> "
-"<layout type='horizontal' padding='4,4,4,4'> "
+"<layout type='horizontal' padding='8,8,8,8'> "
"<widget name='Ok' "
"type='Button' "
"/> "
@@ -1789,20 +1488,20 @@
"</layout> "
"</dialog> "
"<dialog name='KeyMapper' overlays='screen_center' shading='dim'> "
-"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'> "
+"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'> "
"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "
"<widget name='PopupDesc' "
"type='OptionsLabel' "
"/> "
"<widget name='Popup' "
"type='PopUp' "
-"width='150' "
+"width='400' "
"height='Globals.Line.Height' "
"/> "
"</layout> "
"<widget name='KeymapArea' "
-"width='300' "
-"height='120' "
+"width='600' "
+"height='280' "
"/> "
"<widget name='Close' "
"type='Button' "
@@ -1810,3 +1509,359 @@
"</layout> "
"</dialog> "
"</layout_info> "
+"<render_info> "
+"<palette> "
+"<color name='black' "
+"rgb='0,0,0' "
+"/> "
+"<color name='lightgrey' "
+"rgb='104,104,104' "
+"/> "
+"<color name='darkgrey' "
+"rgb='64,64,64' "
+"/> "
+"<color name='green' "
+"rgb='32,160,32' "
+"/> "
+"<color name='green2' "
+"rgb='0,255,0' "
+"/> "
+"</palette> "
+"<fonts> "
+"<font id='text_default' "
+"file='default' "
+"/> "
+"<font id='text_button' "
+"file='default' "
+"/> "
+"<font id='text_normal' "
+"file='default' "
+"/> "
+"<text_color id='color_normal' "
+"color='green' "
+"/> "
+"<text_color id='color_normal_inverted' "
+"color='black' "
+"/> "
+"<text_color id='color_normal_hover' "
+"color='green2' "
+"/> "
+"<text_color id='color_normal_disabled' "
+"color='lightgrey' "
+"/> "
+"<text_color id='color_alternative' "
+"color='lightgrey' "
+"/> "
+"<text_color id='color_alternative_inverted' "
+"color='255,255,255' "
+"/> "
+"<text_color id='color_alternative_hover' "
+"color='176,176,176' "
+"/> "
+"<text_color id='color_alternative_disabled' "
+"color='darkgrey' "
+"/> "
+"<text_color id='color_button' "
+"color='green' "
+"/> "
+"<text_color id='color_button_hover' "
+"color='green2' "
+"/> "
+"<text_color id='color_button_disabled' "
+"color='lightgrey' "
+"/> "
+"</fonts> "
+"<defaults fill='foreground' fg_color='darkgrey' bg_color='black' shadow='0' bevel_color='lightgrey'/> "
+"<drawdata id='text_selection' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id='text_selection_focus' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='green' "
+"/> "
+"</drawdata> "
+"<drawdata id='mainmenu_bg' cache='false'> "
+"<drawstep func='fill' "
+"fill='foreground' "
+"fg_color='black' "
+"/> "
+"</drawdata> "
+"<drawdata id='special_bg' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"/> "
+"</drawdata> "
+"<drawdata id='separator' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"height='2' "
+"ypos='center' "
+"fg_color='lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id='scrollbar_base' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"/> "
+"</drawdata> "
+"<drawdata id='scrollbar_handle_hover' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='green2' "
+"/> "
+"</drawdata> "
+"<drawdata id='scrollbar_handle_idle' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='green' "
+"/> "
+"</drawdata> "
+"<drawdata id='scrollbar_button_idle' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"<drawstep func='triangle' "
+"fg_color='green' "
+"fill='foreground' "
+"width='auto' "
+"height='auto' "
+"xpos='center' "
+"ypos='center' "
+"orientation='top' "
+"/> "
+"</drawdata> "
+"<drawdata id='scrollbar_button_hover' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"<drawstep func='triangle' "
+"fg_color='green2' "
+"fill='foreground' "
+"width='auto' "
+"height='auto' "
+"xpos='center' "
+"ypos='center' "
+"orientation='top' "
+"/> "
+"</drawdata> "
+"<drawdata id='tab_active' cache='false'> "
+"<text font='text_default' "
+"text_color='color_normal_hover' "
+"vertical_align='center' "
+"horizontal_align='center' "
+"/> "
+"<drawstep func='tab' "
+"bevel='2' "
+"radius='0' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='tab_inactive' cache='false'> "
+"<text font='text_default' "
+"text_color='color_normal' "
+"vertical_align='center' "
+"horizontal_align='center' "
+"/> "
+"<drawstep func='tab' "
+"bevel='2' "
+"radius='0' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='tab_background' cache='false'> "
+"</drawdata> "
+"<drawdata id='widget_slider' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='slider_disabled' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id='slider_full' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='green' "
+"/> "
+"</drawdata> "
+"<drawdata id='slider_hover' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='green2' "
+"/> "
+"</drawdata> "
+"<drawdata id='widget_small' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='popup_idle' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"<drawstep func='triangle' "
+"fg_color='green' "
+"fill='foreground' "
+"width='height' "
+"height='auto' "
+"xpos='right' "
+"ypos='center' "
+"orientation='bottom' "
+"/> "
+"<text font='text_default' "
+"text_color='color_normal' "
+"vertical_align='center' "
+"horizontal_align='left' "
+"/> "
+"</drawdata> "
+"<drawdata id='popup_disabled' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"<drawstep func='triangle' "
+"fg_color='lightgrey' "
+"fill='foreground' "
+"width='height' "
+"height='auto' "
+"xpos='right' "
+"ypos='center' "
+"orientation='bottom' "
+"/> "
+"<text font='text_default' "
+"text_color='color_normal_disabled' "
+"vertical_align='center' "
+"horizontal_align='left' "
+"/> "
+"</drawdata> "
+"<drawdata id='popup_hover' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"<drawstep func='triangle' "
+"fg_color='green2' "
+"fill='foreground' "
+"width='height' "
+"height='auto' "
+"xpos='right' "
+"ypos='center' "
+"orientation='bottom' "
+"/> "
+"<text font='text_default' "
+"text_color='color_normal_hover' "
+"vertical_align='center' "
+"horizontal_align='left' "
+"/> "
+"</drawdata> "
+"<drawdata id='widget_textedit' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='plain_bg' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"/> "
+"</drawdata> "
+"<drawdata id='caret' cache='false'> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id='default_bg' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"/> "
+"</drawdata> "
+"<drawdata id='button_idle' cache='false'> "
+"<text font='text_button' "
+"text_color='color_button' "
+"vertical_align='center' "
+"horizontal_align='center' "
+"/> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='button_hover' cache='false'> "
+"<text font='text_button' "
+"text_color='color_button_hover' "
+"vertical_align='center' "
+"horizontal_align='center' "
+"/> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='button_disabled' cache='false'> "
+"<text font='text_button' "
+"text_color='color_button_disabled' "
+"vertical_align='center' "
+"horizontal_align='center' "
+"/> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='checkbox_disabled' cache='false'> "
+"<text font='text_default' "
+"text_color='color_normal_disabled' "
+"vertical_align='top' "
+"horizontal_align='left' "
+"/> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='checkbox_selected' cache='false'> "
+"<text font='text_default' "
+"text_color='color_normal' "
+"vertical_align='top' "
+"horizontal_align='left' "
+"/> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"<drawstep func='cross' "
+"fill='foreground' "
+"stroke='2' "
+"fg_color='green' "
+"/> "
+"</drawdata> "
+"<drawdata id='checkbox_default' cache='false'> "
+"<text font='text_default' "
+"text_color='color_normal' "
+"vertical_align='top' "
+"horizontal_align='left' "
+"/> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"fill='none' "
+"/> "
+"</drawdata> "
+"<drawdata id='widget_default' cache='false'> "
+"<drawstep func='bevelsq' "
+"bevel='2' "
+"/> "
+"</drawdata> "
+"</render_info> "
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 67cbbf7990..9733c7a97e 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 14f19a7151..27164673b4 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -582,10 +582,6 @@
width = '150'
height = 'Globals.Button.Height'
/>
- <widget name = 'Help'
- width = '150'
- height = 'Globals.Button.Height'
- />
<widget name = 'About'
width = '150'
height = 'Globals.Button.Height'
@@ -602,7 +598,36 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0'>
<layout type = 'vertical' padding = '0, 0, 0, 0' center = 'true'>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 8a0180db3c..c8ecb1abaf 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -565,7 +565,7 @@
</dialog>
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
- <layout type = 'vertical' padding = '2, 2, 4, 6' center = 'true' spacing='6'>
+ <layout type = 'vertical' padding = '8, 8, 4, 6' center = 'true'>
<widget name = 'Title'
width = '160'
height = '4'
@@ -588,10 +588,6 @@
width = '120'
height = '12'
/>
- <widget name = 'Help'
- width = '120'
- height = '12'
- />
<widget name = 'About'
width = '120'
height = '12'
@@ -612,7 +608,43 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <space size = '2'/>
+ <widget name = 'Load'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <widget name = 'Save'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <space size = '2'/>
+ <widget name = 'Options'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <widget name = 'Help'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <widget name = 'About'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <space size = '2'/>
+ <widget name = 'Quit'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'vcMusicText'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index b3dc16b67e..e6cda4ddbb 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 25add37462..2fd14f37aa 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -595,10 +595,6 @@
width = '150'
height = 'Globals.Button.Height'
/>
- <widget name = 'Help'
- width = '150'
- height = 'Globals.Button.Height'
- />
<widget name = 'About'
width = '150'
height = 'Globals.Button.Height'
@@ -615,7 +611,36 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0'>
<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '8' center = 'true'>
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index 1c2f83a3b7..e837e41e82 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -561,7 +561,7 @@
</dialog>
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
- <layout type = 'vertical' padding = '4, 4, 4, 4' center = 'true' spacing='2'>
+ <layout type = 'vertical' padding = '4, 4, 4, 4' center = 'true'>
<widget name = 'Title'
width = '160'
height = 'Globals.Line.Height'
@@ -584,10 +584,6 @@
width = '120'
height = 'Globals.Button.Height'
/>
- <widget name = 'Help'
- width = '120'
- height = 'Globals.Button.Height'
- />
<widget name = 'About'
width = '120'
height = 'Globals.Button.Height'
@@ -608,7 +604,36 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '4, 4, 4, 4'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'vcMusicText'
diff --git a/ports.mk b/ports.mk
index 8f51ebb005..4d819f54f9 100644
--- a/ports.mk
+++ b/ports.mk
@@ -44,9 +44,7 @@ bundle: scummvm-static
cp $(srcdir)/icons/scummvm.icns $(bundle_name)/Contents/Resources/
cp $(DIST_FILES_DOCS) $(bundle_name)/
cp $(DIST_FILES_THEMES) $(bundle_name)/Contents/Resources/
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/Contents/Resources/
-endif
$(srcdir)/tools/credits.pl --rtf > $(bundle_name)/Contents/Resources/Credits.rtf
chmod 644 $(bundle_name)/Contents/Resources/*
cp scummvm-static $(bundle_name)/Contents/MacOS/scummvm
@@ -58,9 +56,7 @@ iphonebundle: iphone
cp $(srcdir)/dists/iphone/Info.plist $(bundle_name)/
cp $(DIST_FILES_DOCS) $(bundle_name)/
cp $(DIST_FILES_THEMES) $(bundle_name)/
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/
-endif
$(STRIP) scummvm
ldid -S scummvm
chmod 755 scummvm
@@ -155,9 +151,7 @@ win32dist: $(EXECUTABLE)
mkdir -p $(WIN32PATH)
$(STRIP) $(EXECUTABLE) -o $(WIN32PATH)/$(EXECUTABLE)
cp $(DIST_FILES_THEMES) $(WIN32PATH)
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(WIN32PATH)
-endif
cp $(srcdir)/AUTHORS $(WIN32PATH)/AUTHORS.txt
cp $(srcdir)/COPYING $(WIN32PATH)/COPYING.txt
cp $(srcdir)/COPYING.LGPL $(WIN32PATH)/COPYING.LGPL.txt
@@ -178,9 +172,7 @@ aos4dist: $(EXECUTABLE)
$(STRIP) $(EXECUTABLE) -o $(AOS4PATH)/$(EXECUTABLE)
cp icons/scummvm.info $(AOS4PATH)/$(EXECUTABLE).info
cp $(DIST_FILES_THEMES) $(AOS4PATH)/themes/
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(AOS4PATH)/extras/
-endif
cp $(srcdir)/AUTHORS $(AOS4PATH)/AUTHORS.txt
cp $(srcdir)/COPYING $(AOS4PATH)/COPYING.txt
cp $(srcdir)/COPYING.LGPL $(AOS4PATH)/COPYING.LGPL.txt
diff --git a/sound/decoders/adpcm.cpp b/sound/decoders/adpcm.cpp
index c8a907d13e..7a85bc24d5 100644
--- a/sound/decoders/adpcm.cpp
+++ b/sound/decoders/adpcm.cpp
@@ -724,10 +724,6 @@ int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) {
}
RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign) {
- // If size is 0, report the entire size of the stream
- if (!size)
- size = stream->size();
-
switch (type) {
case kADPCMOki:
return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
diff --git a/sound/decoders/mp3.cpp b/sound/decoders/mp3.cpp
index 732ae58b67..f66d6324ef 100644
--- a/sound/decoders/mp3.cpp
+++ b/sound/decoders/mp3.cpp
@@ -36,9 +36,7 @@
#include <mad.h>
-#if defined(__PSP__)
- #include "backends/platform/psp/mp3.h"
-#endif
+
namespace Audio {
@@ -349,18 +347,7 @@ int MP3Stream::readBuffer(int16 *buffer, const int numSamples) {
SeekableAudioStream *makeMP3Stream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse) {
-
-#if defined(__PSP__)
- SeekableAudioStream *s = 0;
-
- if (Mp3PspStream::isOkToCreateStream())
- s = new Mp3PspStream(stream, disposeAfterUse);
-
- if (!s) // go to regular MAD mp3 stream if ME fails
- s = new MP3Stream(stream, disposeAfterUse);
-#else
SeekableAudioStream *s = new MP3Stream(stream, disposeAfterUse);
-#endif
if (s && s->endOfData()) {
delete s;
return 0;
diff --git a/sound/decoders/voc.cpp b/sound/decoders/voc.cpp
index e9af7ece3f..5663861f05 100644
--- a/sound/decoders/voc.cpp
+++ b/sound/decoders/voc.cpp
@@ -384,7 +384,7 @@ AudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, uint
SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) {
#ifdef STREAM_AUDIO_FROM_DISK
- return makeVOCDiskStreamNoLoop(stream, flags, disposeAfterUse);
+ return makeVOCDiskStreamNoLoop(*stream, flags, disposeAfterUse);
#else
int size, rate;
diff --git a/sound/mods/rjp1.cpp b/sound/mods/rjp1.cpp
index be376d61a4..fc1b49e9e9 100644
--- a/sound/mods/rjp1.cpp
+++ b/sound/mods/rjp1.cpp
@@ -422,7 +422,7 @@ void Rjp1::setupNote(Rjp1Channel *channel, int16 period) {
channel->envelopeMode = 4;
channel->data = channel->waveData;
channel->pos = READ_BE_UINT16(note + 16);
- channel->len = channel->pos + READ_BE_UINT16(note + 18);
+ channel->len = READ_BE_UINT16(note + 18);
channel->setupNewNote = true;
}
}
diff --git a/test/common/str.h b/test/common/str.h
index 6581c37cdb..16fb0859db 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -118,30 +118,6 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
}
- void test_refCount5() {
- // using external storage
- Common::String foo1("HelloHelloHelloHelloAndHi");
- Common::String foo2(foo1);
-
- for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
- *i = 'h';
-
- TS_ASSERT_EQUALS(foo1, "HelloHelloHelloHelloAndHi");
- TS_ASSERT_EQUALS(foo2, "hhhhhhhhhhhhhhhhhhhhhhhhh");
- }
-
- void test_refCount6() {
- // using internal storage
- Common::String foo1("Hello");
- Common::String foo2(foo1);
-
- for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
- *i = 'h';
-
- TS_ASSERT_EQUALS(foo1, "Hello");
- TS_ASSERT_EQUALS(foo2, "hhhhh");
- }
-
void test_self_asignment() {
Common::String foo1("12345678901234567890123456789012");
foo1 = foo1.c_str() + 2;
diff --git a/tools/create_msvc/create_msvc.cpp b/tools/create_msvc/create_msvc.cpp
index f418971239..a2636dab21 100644
--- a/tools/create_msvc/create_msvc.cpp
+++ b/tools/create_msvc/create_msvc.cpp
@@ -511,6 +511,8 @@ int main(int argc, char *argv[]) {
// 4103 (alignment changed after including header, may be due to missing #pragma pack(pop))
// used by pack-start / pack-end
//
+ // 4121 (alignment of a member was sensitive to packing)
+ //
// 4127 (conditional expression is constant)
// used in a lot of engines
//
@@ -564,6 +566,7 @@ int main(int argc, char *argv[]) {
projectWarnings["lure"] = "4189;4355";
projectWarnings["kyra"] = "4355";
projectWarnings["m4"] = "4355";
+ projectWarnings["mohawk"] = "4121";
ProjectProvider *provider = NULL;
diff --git a/tools/md5table.c b/tools/md5table.c
index 6823607b27..b69f3957cd 100644
--- a/tools/md5table.c
+++ b/tools/md5table.c
@@ -221,7 +221,7 @@ int main(int argc, char *argv[])
const int entrySize = 256;
int numEntries = 0, maxEntries = 1;
- char *entriesBuffer = (char *)malloc(maxEntries * entrySize);
+ char *entriesBuffer = malloc(maxEntries * entrySize);
typedef enum {
kCPPOutput,
@@ -294,7 +294,7 @@ int main(int argc, char *argv[])
} else if (entry.md5) {
if (numEntries >= maxEntries) {
maxEntries *= 2;
- entriesBuffer = (char *)realloc(entriesBuffer, maxEntries * entrySize);
+ entriesBuffer = realloc(entriesBuffer, maxEntries * entrySize);
}
if (0 == strcmp(entry.variant, "-"))
entry.variant = "";
diff --git a/tools/module.mk b/tools/module.mk
index 896a2e504b..4117ceac77 100644
--- a/tools/module.mk
+++ b/tools/module.mk
@@ -36,15 +36,15 @@ clean-tools:
tools/convbdf$(EXEEXT): $(srcdir)/tools/convbdf.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
tools/md5table$(EXEEXT): $(srcdir)/tools/md5table.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
tools/make-scumm-fontdata$(EXEEXT): $(srcdir)/tools/make-scumm-fontdata.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
#
# Rules to explicitly rebuild the credits / MD5 tables.
diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt
index 0637c386d7..7b9918ba43 100644
--- a/tools/scumm-md5.txt
+++ b/tools/scumm-md5.txt
@@ -584,7 +584,6 @@ catalog Humongous Interactive Catalog
airport Let's Explore the Airport with Buzzy
d6334a5a9b61afe18c368540fdf522ca -1 en Mac - - - Joachim Eberhard
07433205acdca3bc553d0e731588b35f -1 en Windows - - - Kirben
- 3e861421f494711bc6f619d4aba60285 93231 ru Windows - - - sev
7ea2da67ebabea4ac20cee9f4f9d2934 -1 en Mac - Demo - khalek
8ffd618a776a4c0d8922bb28b09f8ce8 -1 en Windows - Demo - khalek
@@ -596,7 +595,6 @@ farm Let's Explore the Farm with Buzzy
a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi
a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben
a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi
- 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows - - - sev
39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard
bf8b52fdd9a69c67f34e8e9fec72661c -1 en Windows HE 71 Demo - khalek, sev
@@ -708,7 +706,6 @@ puttmoon Putt-Putt Goes to the Moon
697c9b7c55a05d8199c48b48e379d2c8 -1 he DOS - - - sev
9dc02577bf50d4cfaf3de3fbac06fbe2 -1 en Mac - - - khalek
9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek
- 3c4c471342bd95505a42334367d8f127 12161 ru Windows HE 70 - - sev
aa6a91b7f6f119d1b7b1f2a4c9e24d59 6233 en DOS - Demo -
4af4a6b248103c1fe9edef619677f540 -1 en Mac - Demo - khalek