diff options
author | Christopher Page | 2008-07-14 00:10:09 +0000 |
---|---|---|
committer | Christopher Page | 2008-07-14 00:10:09 +0000 |
commit | d2e8d4831e33f9e1c63d53c9dd615a15f67ab995 (patch) | |
tree | 308cc8bb9ab0bc80d006c84b8ff84267355cedcb | |
parent | 3ac3e84ecffa967f02eeb497e260a0de08e3d2e7 (diff) | |
parent | ef95c6ff70c1b428ab1d086a9b0b551fc82c8451 (diff) | |
download | scummvm-rg350-d2e8d4831e33f9e1c63d53c9dd615a15f67ab995.tar.gz scummvm-rg350-d2e8d4831e33f9e1c63d53c9dd615a15f67ab995.tar.bz2 scummvm-rg350-d2e8d4831e33f9e1c63d53c9dd615a15f67ab995.zip |
Merged revisions 32744-32745,32747,32750-32759,32762-32764,32769,32777,32783,32785-32786,32789-32791,32798-32799,32801-32807,32809-32812,32816-32817,32819-32821,32823-32830,32832-32836,32838-32844,32846-32850,32852-32854,32858-32859,32865-32868,32873-32874,32879,32883,32895,32899,32902-32904,32910-32912,32923-32924,32930-32931,32938,32940,32948-32949,32951,32960-32964,32966-32970,32972-32974,32976,32978,32983,32986-32990,32992,32994,33002-33004,33006-33007,33009-33010,33014,33017,33021-33023,33030,33033 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
svn-id: r33051
197 files changed, 6314 insertions, 4355 deletions
@@ -10,11 +10,13 @@ For a more comprehensive changelog for the latest experimental SVN code, see: - Added support for the PC version of Waxworks - Added support for the Macintosh version of I Have no Mouth, and I must Scream + - Added support for Drascula: The Vampire Strikes Back General: - Added CAMD MIDI driver for AmigaOS4. - Revived the PS2 port (was already in 0.11.1 but was forgotten in the release notes). + - Plugged numerous memory leaks in all engines (part of GSoC'08 task) AGOS: - Fixed palette issues in Amiga versions of Simon the Sorcerer 1. diff --git a/backends/platform/dc/Makefile b/backends/platform/dc/Makefile index 0a048c45e9..56848504e1 100644 --- a/backends/platform/dc/Makefile +++ b/backends/platform/dc/Makefile @@ -16,6 +16,7 @@ LDFLAGS = -Wl,-Ttext,0x8c010000 -nostartfiles $(ronindir)/lib/crt0.o INCLUDES= -I./ -I$(srcdir) -I$(ronindir)/include/ -I$(srcdir)/engines LIBS = -L$(ronindir)/lib -lmad -lronin -lz -lm EXECUTABLE = scummvm.elf +DEPDIR = .deps PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg PLUGIN_EXTRA_DEPS = plugin.x plugin.syms scummvm.elf @@ -32,12 +33,37 @@ ifdef DYNAMIC_MODULES DEFINES += -DDYNAMIC_MODULES PRE_OBJS_FLAGS = -Wl,--whole-archive POST_OBJS_FLAGS = -Wl,--no-whole-archive +ENABLED=DYNAMIC_PLUGIN +else +ENABLED=STATIC_PLUGIN endif +ENABLE_SCUMM = $(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_IGOR = $(ENABLED) +ENABLE_KYRA = $(ENABLED) +ENABLE_LURE = $(ENABLED) +ENABLE_M4 = $(ENABLED) +ENABLE_MADE = $(ENABLED) +ENABLE_PARALLACTION = $(ENABLED) +ENABLE_QUEEN = $(ENABLED) +ENABLE_SAGA = $(ENABLED) +ENABLE_SKY = $(ENABLED) +ENABLE_SWORD1 = $(ENABLED) +ENABLE_SWORD2 = $(ENABLED) +ENABLE_TOUCHE = $(ENABLED) + OBJS := dcmain.o time.o display.o audio.o input.o selector.o icon.o \ label.o vmsave.o softkbd.o dcloader.o cache.o dc-fs.o -MODULE_DIRS += . +MODULE_DIRS += ./ include $(srcdir)/Makefile.common diff --git a/backends/platform/dc/audio.cpp b/backends/platform/dc/audio.cpp index 5f95a836e8..b5667e74b0 100644 --- a/backends/platform/dc/audio.cpp +++ b/backends/platform/dc/audio.cpp @@ -25,17 +25,18 @@ #include <common/scummsys.h> #include "engines/engine.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "dc.h" EXTERN_C void *memcpy4s(void *s1, const void *s2, unsigned int n); -void initSound() +uint OSystem_Dreamcast::initSound() { stop_sound(); do_sound_command(CMD_SET_FREQ_EXP(FREQ_22050_EXP)); do_sound_command(CMD_SET_STEREO(1)); do_sound_command(CMD_SET_BUFFER(SOUND_BUFFER_SHIFT)); + return read_sound_int(&SOUNDSTATUS->freq); } void OSystem_Dreamcast::checkSound() @@ -61,8 +62,8 @@ void OSystem_Dreamcast::checkSound() if (n<100) return; - Audio::Mixer::mixCallback(_mixer, (byte*)temp_sound_buffer, - 2*SAMPLES_TO_BYTES(n)); + _mixer->mixCallback((byte*)temp_sound_buffer, + 2*SAMPLES_TO_BYTES(n)); if (fillpos+n > curr_ring_buffer_samples) { int r = curr_ring_buffer_samples - fillpos; @@ -77,8 +78,4 @@ void OSystem_Dreamcast::checkSound() fillpos = 0; } -int OSystem_Dreamcast::getOutputSampleRate() const -{ - return read_sound_int(&SOUNDSTATUS->freq); -} diff --git a/backends/platform/dc/dc.h b/backends/platform/dc/dc.h index b7494a77bc..9dfd4c331e 100644 --- a/backends/platform/dc/dc.h +++ b/backends/platform/dc/dc.h @@ -28,6 +28,7 @@ #include <ronin/soundcommon.h> #include "backends/timer/default/default-timer.h" #include "backends/fs/fs-factory.h" +#include "sound/mixer_intern.h" #define NUM_BUFFERS 4 #define SOUND_BUFFER_SHIFT 3 @@ -195,7 +196,7 @@ class OSystem_Dreamcast : public OSystem, public FilesystemFactory { private: Common::SaveFileManager *_savefile; - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; DefaultTimerManager *_timer; SoftKeyboard _softkbd; @@ -223,6 +224,7 @@ class OSystem_Dreamcast : public OSystem, public FilesystemFactory { int temp_sound_buffer[RING_BUFFER_SAMPLES>>SOUND_BUFFER_SHIFT]; + uint initSound(); void checkSound(); void drawMouse(int xdraw, int ydraw, int w, int h, @@ -237,6 +239,5 @@ class OSystem_Dreamcast : public OSystem, public FilesystemFactory { extern int handleInput(struct mapledev *pad, int &mouse_x, int &mouse_y, byte &shiftFlags, Interactive *inter = NULL); -extern void initSound(); extern bool selectGame(char *&, char *&, class Icon &); diff --git a/backends/platform/dc/dcmain.cpp b/backends/platform/dc/dcmain.cpp index 913bc9948e..0b114bee10 100644 --- a/backends/platform/dc/dcmain.cpp +++ b/backends/platform/dc/dcmain.cpp @@ -33,7 +33,7 @@ #include <common/config-manager.h> #include "backends/plugins/dc/dc-provider.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" Icon icon; @@ -54,8 +54,10 @@ OSystem_Dreamcast::OSystem_Dreamcast() void OSystem_Dreamcast::initBackend() { _savefile = createSavefileManager(); - _mixer = new Audio::Mixer(); + _mixer = new Audio::MixerImpl(this); _timer = new DefaultTimerManager(); + _mixer->setOutputRate(initSound()); + _mixer->setReady(true); } @@ -216,7 +218,6 @@ int main() static int argc = 1; dc_init_hardware(); - initSound(); g_system = new OSystem_Dreamcast(); assert(g_system); diff --git a/backends/platform/dc/selector.cpp b/backends/platform/dc/selector.cpp index 880fbc400f..91c851506f 100644 --- a/backends/platform/dc/selector.cpp +++ b/backends/platform/dc/selector.cpp @@ -25,7 +25,9 @@ #include <common/scummsys.h> #include <engines/engine.h> +#include <engines/metaengine.h> #include <base/plugins.h> +#include <base/game.h> #include <common/fs.h> #include <common/events.h> #include "dc.h" @@ -149,15 +151,6 @@ struct Dir static Game the_game; -static void detectGames(FSList &files, GameList &candidates) -{ - const EnginePluginList &plugins = EngineMan.getPlugins(); - EnginePluginList::const_iterator iter = plugins.begin(); - for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - candidates.push_back((*iter)->detectGames(files)); - } -} - static bool isIcon(const FilesystemNode &entry) { int l = entry.getDisplayName().size(); @@ -227,8 +220,7 @@ static int findGames(Game *games, int max) files.push_back(*entry); } - GameList candidates; - detectGames(files, candidates); + GameList candidates = EngineMan.detectGames(files); for (GameList::const_iterator ge = candidates.begin(); ge != candidates.end(); ++ge) diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index a130509e36..f4706807f7 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -168,7 +168,7 @@ bool displayModeIs8Bit = false; u8 gameID; bool snapToBorder = false; -bool consoleEnable = false; +bool consoleEnable = true; bool gameScreenSwap = false; bool isCpuScalerEnabled(); //#define HEAVY_LOGGING @@ -899,12 +899,6 @@ u16* get8BitBackBuffer() { return BG_GFX + 0x10000; // 16bit qty! } -void setSoundProc(OSystem_DS::SoundProc proc, void* param) { -// consolePrintf("Set sound callback"); - soundCallback = proc; - soundParam = param; -} - // The sound system in ScummVM seems to always return stereo interleaved samples. // Here, I'm treating an 11Khz stereo stream as a 22Khz mono stream, which works sorta ok, but is // a horrible bodge. Any advice on how to change the engine to output mono would be greatly @@ -914,7 +908,8 @@ void doSoundCallback() { consolePrintf("doSoundCallback..."); #endif - if (soundCallback) { + if (OSystem_DS::instance()) + if (OSystem_DS::instance()->getMixerImpl()) { lastCallbackFrame = frameCount; for (int r = IPC->playingSection; r < IPC->playingSection + 4; r++) { @@ -923,7 +918,7 @@ void doSoundCallback() { if (IPC->fillNeeded[chunk]) { IPC->fillNeeded[chunk] = false; DC_FlushAll(); - soundCallback(soundParam, (byte *) (soundBuffer + ((bufferSamples >> 2) * chunk)), bufferSamples >> 1); + OSystem_DS::instance()->getMixerImpl()->mixCallback((byte *) (soundBuffer + ((bufferSamples >> 2) * chunk)), bufferSamples >> 1); IPC->fillNeeded[chunk] = false; DC_FlushAll(); } diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h index f20442b11e..43258b5c5d 100644 --- a/backends/platform/ds/arm9/source/dsmain.h +++ b/backends/platform/ds/arm9/source/dsmain.h @@ -88,7 +88,6 @@ int getMillis(); // Return the current runtime in milliseconds void doTimerCallback(); // Call callback function if required // Sound -void setSoundProc(OSystem_DS::SoundProc proc, void* param); // Setup a callback function for sound void doSoundCallback(); // Call function if sound buffers need more data void playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050); // Start a sound void stopSound(int channel); diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp index 6e6b457115..79b0c5390b 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.cpp +++ b/backends/platform/ds/arm9/source/osystem_ds.cpp @@ -67,10 +67,12 @@ void OSystem_DS::initBackend() { ConfMan.setInt("autosave_period", 0); ConfMan.setBool("FM_medium_quality", true); - _mixer = new DSAudioMixer; - _timer = new DSTimerManager; - DS::setSoundProc(Audio::Mixer::mixCallback, _mixer); - DS::setTimerCallback(&OSystem_DS::timerHandler, 10); + _mixer = new DSAudioMixer(this); + _timer = new DSTimerManager(); + DS::setTimerCallback(&OSystem_DS::timerHandler, 10); + + _mixer->setOutputRate(11025 /*DS::getSoundFrequency()*/); + _mixer->setReady(true); OSystem::initBackend(); } @@ -139,7 +141,7 @@ void OSystem_DS::setPalette(const byte *colors, uint start, uint num) { green >>= 3; blue >>= 3; -// if (r != 255) + if (r != 255) { BG_PALETTE[r] = red | (green << 5) | (blue << 10); if (!DS::getKeyboardEnable()) { @@ -158,13 +160,13 @@ bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) { // Ensure we copy using 16 bit quantities due to limitation of VRAM addressing - u16* image = (u16 *) DS::get8BitBackBuffer(); + const u16* image = (const u16 *) DS::get8BitBackBuffer(); for (int y = 0; y < DS::getGameHeight(); y++) { DC_FlushRange(image + (y << 8), DS::getGameWidth()); for (int x = 0; x < DS::getGameWidth() >> 1; x++) { - *(((u16 *) (surf->pixels)) + y * (DS::getGameWidth() >> 1) + x) = image[y << 8 + x]; + *(((u16 *) (surf->pixels)) + y * (DS::getGameWidth() >> 1) + x) = image[(y << 8) + x]; } } @@ -277,7 +279,7 @@ void OSystem_DS::grabOverlay (OverlayColor *buf, int pitch) { void OSystem_DS::copyRectToOverlay (const OverlayColor *buf, int pitch, int x, int y, int w, int h) { u16* bg = (u16 *) DS::get16BitBackBuffer(); - u16* src = (u16 *) buf; + const u16* src = (const u16 *) buf; // if (x + w > 256) w = 256 - x; //if (x + h > 256) h = 256 - y; @@ -433,13 +435,7 @@ void OSystem_DS::unlockMutex(MutexRef mutex) { void OSystem_DS::deleteMutex(MutexRef mutex) { } -void OSystem_DS::clearSoundCallback() { -// consolePrintf("Clearing sound callback"); -// DS::setSoundProc(NULL, NULL); -} - -int OSystem_DS::getOutputSampleRate() const -{ +int OSystem_DS::getOutputSampleRate() const { return DS::getSoundFrequency(); } diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h index 246797188f..8c8d661ad8 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.h +++ b/backends/platform/ds/arm9/source/osystem_ds.h @@ -30,10 +30,13 @@ #include "gbampsave.h" #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "graphics/surface.h" -class DSAudioMixer : public Audio::Mixer { +class DSAudioMixer : public Audio::MixerImpl { + +public: + DSAudioMixer(OSystem* system) : Audio::MixerImpl(system) { } }; class DSTimerManager : public DefaultTimerManager { @@ -62,7 +65,7 @@ protected: Graphics::Surface* createTempFrameBuffer(); public: - typedef void (*SoundProc)(void *param, byte *buf, int len); + typedef void (*SoundProc)(byte *buf, int len); typedef int (*TimerProc)(int interval); OSystem_DS(); @@ -114,7 +117,6 @@ public: virtual void unlockMutex(MutexRef mutex); virtual void deleteMutex(MutexRef mutex); - virtual void clearSoundCallback(); virtual int getOutputSampleRate() const; virtual bool openCD(int drive); @@ -147,6 +149,8 @@ public: virtual void unlockScreen(); virtual Audio::Mixer* getMixer() { return _mixer; } + Audio::MixerImpl* getMixerImpl() { return _mixer; } + virtual Common::TimerManager* getTimerManager() { return _timer; } static int timerHandler(int t); diff --git a/backends/platform/ds/arm9/source/wordcompletion.cpp b/backends/platform/ds/arm9/source/wordcompletion.cpp index 9eeeb62410..ff52572a40 100644 --- a/backends/platform/ds/arm9/source/wordcompletion.cpp +++ b/backends/platform/ds/arm9/source/wordcompletion.cpp @@ -1,6 +1,6 @@ #include "wordcompletion.h" -#include "engines/agi/agi.h" #include "osystem_ds.h" +#include "engines/agi/agi.h" // Caution for #define for NUM_CHANNELS, causes problems in mixer_intern.h #ifdef ENABLE_AGI diff --git a/backends/platform/gp2x/build/README-GP2X b/backends/platform/gp2x/build/README-GP2X index cb1d043500..7e10fc484e 100644 --- a/backends/platform/gp2x/build/README-GP2X +++ b/backends/platform/gp2x/build/README-GP2X @@ -1,4 +1,4 @@ -ScummVM - GP2X SPECIFIC README - 0.10.0 SVN +ScummVM - GP2X SPECIFIC README - HEAD SVN ------------------------------------------------------------------------ Contents: diff --git a/backends/platform/gp2x/build/README-GP2X.html b/backends/platform/gp2x/build/README-GP2X.html index 5289d3d36c..1b5f1a4173 100644 --- a/backends/platform/gp2x/build/README-GP2X.html +++ b/backends/platform/gp2x/build/README-GP2X.html @@ -2,12 +2,15 @@ <html> <head> <title>ScummVM - GP2X SPECIFIC README</title> + + </head> <body> -<span style="font-weight: bold;">ScummVM - GP2X SPECIFIC README - 0.10.0 SVN<br> +<span style="font-weight: bold;">ScummVM - +GP2X SPECIFIC README - HEAD SVN<br> </span> <hr style="width: 100%; height: 2px;"><br> @@ -16,52 +19,65 @@ <ul> - <li><a href="#About_the_backendport">About the backend/port</a></li> + <li><a href="#About_the_backendport">About the +backend/port</a></li> - <li><a href="#Game_compatibility">Game compatability</a></li> + <li><a href="#Game_compatibility">Game +compatability</a></li> <li><a href="#Included_engines">Included engines</a></li> - <li><a href="#Supported_audio_options">Supported audio options</a></li> + <li><a href="#Supported_audio_options">Supported +audio options</a></li> - <li><a href="#Supported_cut-scene_options">Supported cut-scene options</a></li> + <li><a href="#Supported_cut-scene_options">Supported +cut-scene options</a></li> <li><a href="#Recent_changes">Recent changes</a></li> <li><a href="#How_to_save">How to save</a></li> - <li><a href="#Controller_mappings">Controller mappings</a></li> + <li><a href="#Controller_mappings">Controller +mappings</a></li> <li><a href="#Know_issues">Know issues</a></li> <li><a href="#Major_TODOs">Major TODO's</a></li> - <li><a href="#Additional_resourceslinks">Additional resources/links</a></li> + <li><a href="#Additional_resourceslinks">Additional +resources/links</a></li> <li><a href="#Credits">Credits</a></li> </ul> + <br> + <hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="About_the_backendport"></a><span style="font-weight: bold;">About the backend/port</span><br> <br> -This is the readme for the offficial GP2X ScummVM backend (also known as the GP2X port).<br> +This is the readme for the offficial GP2X ScummVM backend (also known +as the GP2X port).<br> <br> -This is an SVN test release of ScummVM for the GP2X, it would be appreciated +This is an SVN test release of ScummVM for the GP2X, it would be +appreciated if this SVN test distribution was not mirrored and that people be -directed to <a href="http://www.distant-earth.com/scummvm">http://www.distant-earth.com/scummvm</a> instead for updated SVN builds.<br> +directed to <a href="http://www.distant-earth.com/scummvm">http://www.distant-earth.com/scummvm</a> +instead for updated SVN builds.<br> <br> Full supported official releases of the GP2X ScummVM backend are made -in line with main official releases and are avalalble from the <a href="http://www.scummvm.org/downloads.php">ScummVM downloads page</a>.<br> +in line with main official releases and are avalalble from the <a href="http://www.scummvm.org/downloads.php">ScummVM +downloads page</a>.<br> <br> -This build is in an active state of development and as such no ‘expected’ behavior can be guaranteed ;).<br> +This build is in an active state of development and as such no +‘expected’ behavior can be guaranteed ;).<br> <br> @@ -69,47 +85,59 @@ SVN builds are quickly tested with firmware 2.0.0 for reference.<br> <br> -Please refer to the <a href="http://forums.scummvm.org/viewforum.php?f=14">GP2X ScummVM forum</a> and <a href="http://wiki.scummvm.org/index.php/GP2X">WiKi</a> for the latest information on the port.<br> +Please refer to the <a href="http://forums.scummvm.org/viewforum.php?f=14">GP2X +ScummVM forum</a> and <a href="http://wiki.scummvm.org/index.php/GP2X">WiKi</a> +for the latest information on the port.<br> + <br> <hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Game_compatibility"></a><span style="font-weight: bold;">Game compatibility</span><br> <br> -For information on the compatability of a specific game please refer to the <a href="http://wiki.scummvm.org/index.php/GP2X#Compatibility_List">GP2X compatability section of the ScummVM WiKi</a>.<br> +For information on the compatability of a specific game please refer to +the <a href="http://wiki.scummvm.org/index.php/GP2X#Compatibility_List">GP2X +compatability section of the ScummVM WiKi</a>.<br> <br> -Please note the version and date of the ScummVM build you are running when reviewing the above list.<br> +Please note the version and date of the ScummVM build you are running +when reviewing the above list.<br> <br> <hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Included_engines"></a><span style="font-weight: bold;">Included engines</span><br> <br> + Just because an engine is included does not mean any/all of its games are supported. Please check game compatability for more infomation.<br> + <ul> - <li> -Scumm - (All games supported by ScummVM should work to some extent, using the hardware scalar if needed)</li> + + <li>Scumm - (All games supported by ScummVM should work to some +extent, using the hardware scalar if needed)</li> + <li>AGOS (AKA Simon) - (Simon the Sorcerer one and two).</li> + <li>Sky - (Beneath a Steel Sky)</li> - <li> -Sword - (Broken Sword 1) - This engine uses the hardware scalar to + + <li>Sword - (Broken Sword 1) - This engine uses the hardware +scalar to downsize the graphics to fix on the GP2X. It is NOT very nice to look at.</li> - <li> -Sword2 - (Broken Sword 2) - This engine uses the hardware + + <li>Sword2 - (Broken Sword 2) - This engine uses the hardware scalar to downsize the graphics to fix on the GP2X. It is NOT very nice to look at.</li> - <li> -Gob - (Goblins one)</li> - <li> -Queen - (Flight of the Amazon Queen)</li> - <li> -Kyra - (The Legend of Kyrandia)</li> -</ul> + <li>Gob - (Goblins one)</li> + + <li>Queen - (Flight of the Amazon Queen)</li> + + <li>Kyra - (The Legend of Kyrandia)</li> + +</ul> All other game engines are disabled in this release.<br> @@ -155,13 +183,18 @@ DXA video support will be added as soon as it is stable.<br> Enabled hardware scalar code.<br> -Now built using SDL 1.2.9 for the parts of the port that use SDL (some parts now hit the hardware directly).<br> +Now built using SDL 1.2.9 for the parts of the port that use SDL (some +parts now hit the hardware directly).<br> -Enabled new launcher - (Ensure defaulttheme.zip is in the same folder as the executable).<br> +Enabled new launcher - (Ensure defaulttheme.zip is in the same folder +as the executable).<br> -Aspect Ratio Correction can now be disabled ‘per game’. When adding a game you can find this option on the GFX tab. <br> +Aspect Ratio Correction can now be disabled ‘per +game’. When adding a game you can find this option on the GFX +tab. <br> -Note: This will cause the game to run with a black border at the bottom as it will be rendered to a 320*200 frame.<br> +Note: This will cause the game to run with a black border at the bottom +as it will be rendered to a 320*200 frame.<br> <br> @@ -169,7 +202,9 @@ Note: This will cause the game to run with a black border at the bottom as it wi <br> -<span style="font-weight: bold;">NOTE:</span> Everything is saved to the SD card, saves are stored in the <span style="font-weight: bold;">saves</span> folder under your main ScummVM executable unless you set another save location.<br> +<span style="font-weight: bold;">NOTE:</span> +Everything is saved to the SD card, saves are stored in the <span style="font-weight: bold;">saves</span> folder under +your main ScummVM executable unless you set another save location.<br> <br> @@ -178,7 +213,8 @@ same place as the ScummVM executable.<br> <br> -The save process below is for Scumm engine games but the principle is the same for all.<br> +The save process below is for Scumm engine games but the +principle is the same for all.<br> <br> @@ -198,11 +234,13 @@ In Game.<br> <br> -Basically the emulated keys you can use are equivelent to the values buttons are mapped to, <br> +Basically the emulated keys you can use are equivelent to the values +buttons are mapped to, <br> <br> -I have a virtual keyboard like the GP32 one (left/right on the stick to pick chars) to add in at some point ;-)<br> +I have a virtual keyboard like the GP32 one (left/right on the stick to +pick chars) to add in at some point ;-)<br> <br> @@ -262,9 +300,11 @@ Select: Exit ScummVM completely (and gracefully)<br> <br> -Possible random crash (well SegFault). I have had this happen twice and have not tracked down the cause. <br> +Possible random crash (well SegFault). I have had this happen twice and +have not tracked down the cause. <br> -It happens very infrequently, both times it was in the DOTT CD intro. Saving often is never a bad idea anyhow.<br> +It happens very infrequently, both times it was in the DOTT CD intro. +Saving often is never a bad idea anyhow.<br> <br> @@ -272,11 +312,14 @@ It happens very infrequently, both times it was in the DOTT CD intro. Saving oft <br> -Fix save support when using the Sky engine (Beneath a Steel Sky) - You CAN'T save at the moment but auto save works.<br> +Fix save support when using the Sky engine (Beneath a Steel Sky) - You +CAN'T save at the moment but auto save works.<br> -Look into inconsistencies with AGOS engine and map Y key to a button combination to allow clean quitting (Simon 1/2).<br> +Look into inconsistencies with AGOS engine and map Y key to a button +combination to allow clean quitting (Simon 1/2).<br> -Add splash-screen and pre-ScummVM config menu (CPU speed, LCD timings etc.) - Partly done.<br> +Add splash-screen and pre-ScummVM config menu (CPU speed, LCD timings +etc.) - Partly done.<br> Fix TV out, maybe make it an option in the pre-ScummVM config menu.<br> @@ -284,17 +327,29 @@ Any help appreciated :).<br> <br style="font-weight: bold;"> -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Additional_resourceslinks"></a><span style="font-weight: bold;">Additional resources/links</span><br> +<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Additional_resourceslinks"></a><span style="font-weight: bold;">Additional resources/links<br> + +<br> + +</span><span style="font-weight: bold;">Note:</span> +When providing feedback, +requests, forum posts, bug reports or anything like that always include +a mention of the version of ScummVM you are using (the build version, +date and time can be seen in the main game launcher window).<br> <ul> - <li><a href="http://wiki.scummvm.org/index.php/GP2X">ScummVM WiKi GP2X page</a></li> + <li><a href="http://wiki.scummvm.org/index.php/GP2X">ScummVM +WiKi GP2X page</a></li> - <li><a href="http://forums.scummvm.org/viewforum.php?f=14">ScummVM forums GP2X forum</a></li> + <li><a href="http://forums.scummvm.org/viewforum.php?f=14">ScummVM +forums GP2X forum</a></li> - <li><a href="http://www.distant-earth.com/scummvm">My own ScummVM page</a> (for SVN/test builds)</li> + <li><a href="http://www.distant-earth.com/scummvm">My +own ScummVM page</a> (for SVN/test builds)</li> - <li><a href="http://www.scummvm.org">Main ScummVM site</a> (for official supported release builds)</li> + <li><a href="http://www.scummvm.org">Main ScummVM +site</a> (for official supported release builds)</li> </ul> diff --git a/backends/platform/gp2x/build/build.sh b/backends/platform/gp2x/build/build.sh index 1ea77f4937..1ea77f4937 100644..100755 --- a/backends/platform/gp2x/build/build.sh +++ b/backends/platform/gp2x/build/build.sh diff --git a/backends/platform/gp2x/build/bundle.sh b/backends/platform/gp2x/build/bundle.sh index 9824c9b451..9824c9b451 100644..100755 --- a/backends/platform/gp2x/build/bundle.sh +++ b/backends/platform/gp2x/build/bundle.sh diff --git a/backends/platform/gp2x/build/clean.sh b/backends/platform/gp2x/build/clean.sh index 0979f6c7d6..0979f6c7d6 100644..100755 --- a/backends/platform/gp2x/build/clean.sh +++ b/backends/platform/gp2x/build/clean.sh diff --git a/backends/platform/gp2x/build/config.sh b/backends/platform/gp2x/build/config.sh index 4a30ed4a31..17083d1ea4 100644..100755 --- a/backends/platform/gp2x/build/config.sh +++ b/backends/platform/gp2x/build/config.sh @@ -17,7 +17,7 @@ export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. -./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 -#--enable-plugins +./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-made --enable-m4 +#--enable-plugins --default-dynamic echo Generating config for GP2X complete. Check for errors. diff --git a/backends/platform/gp2x/build/scummvm.gpe b/backends/platform/gp2x/build/scummvm.gpe index 1e69c149b9..1e69c149b9 100644..100755 --- a/backends/platform/gp2x/build/scummvm.gpe +++ b/backends/platform/gp2x/build/scummvm.gpe diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h index e8e128a249..92f625bdc4 100644 --- a/backends/platform/gp2x/gp2x-common.h +++ b/backends/platform/gp2x/gp2x-common.h @@ -37,7 +37,7 @@ #include <SDL_gp2x.h> namespace Audio { - class Mixer; + class MixerImpl; } namespace Common { @@ -128,12 +128,10 @@ public: virtual bool pollEvent(Common::Event &event); // overloaded by CE backend // Set function that generates samples - typedef void (*SoundProc)(void *param, byte *buf, int len); - virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend + void setupMixer(); + static void mixCallback(void *s, byte *samples, int len); virtual Audio::Mixer *getMixer(); - void clearSoundCallback(); - // Poll CD status // Returns true if cd audio is playing bool pollCD(); @@ -181,7 +179,6 @@ public: int getGraphicsMode() const; bool openCD(int drive); - int getOutputSampleRate() const; bool hasFeature(Feature f); void setFeatureState(Feature f, bool enable); @@ -369,7 +366,7 @@ protected: Common::SaveFileManager *_savefile; FilesystemFactory *getFilesystemFactory(); - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; SDL_TimerID _timerID; Common::TimerManager *_timer; diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp index 2d2b4b8078..c138f6c54d 100644 --- a/backends/platform/gp2x/gp2x.cpp +++ b/backends/platform/gp2x/gp2x.cpp @@ -40,7 +40,7 @@ #include "backends/timer/default/default-timer.h" #include "backends/plugins/posix/posix-provider.h" #include "backends/fs/posix/posix-fs-factory.h" // for getFilesystemFactory() -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include <stdio.h> #include <stdlib.h> @@ -225,8 +225,7 @@ void OSystem_GP2X::initBackend() { // Create and hook up the mixer, if none exists yet (we check for this to // allow subclasses to provide their own). if (_mixer == 0) { - _mixer = new Audio::Mixer(); - setSoundCallback(Audio::Mixer::mixCallback, _mixer); + setupMixer(); } // Create and hook up the timer manager, if none exists yet (we check for @@ -445,45 +444,69 @@ void OSystem_GP2X::deleteMutex(MutexRef mutex) { #pragma mark --- Audio --- #pragma mark - -bool OSystem_GP2X::setSoundCallback(SoundProc proc, void *param) { +void OSystem_GP2X::mixCallback(void *sys, byte *samples, int len) { + OSystem_GP2X *this_ = (OSystem_GP2X *)sys; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(samples, len); +} + +void OSystem_GP2X::setupMixer() { SDL_AudioSpec desired; SDL_AudioSpec obtained; - memset(&desired, 0, sizeof(desired)); + //memset(&desired, 0, sizeof(desired)); + // Determine the desired output sampling frequency. _samplesPerSec = 0; - if (ConfMan.hasKey("output_rate")) _samplesPerSec = ConfMan.getInt("output_rate"); - if (_samplesPerSec <= 0) _samplesPerSec = SAMPLES_PER_SEC; + //Quick EVIL Hack - DJWillis _samplesPerSec = 11025; + // Determine the sample buffer size. We want it to store enough data for + // about 1/16th of a second. Note that it must be a power of two. + // So e.g. at 22050 Hz, we request a sample buffer size of 2048. + int samples = 8192; + while (16 * samples >= _samplesPerSec) { + samples >>= 1; + } + + memset(&desired, 0, sizeof(desired)); desired.freq = _samplesPerSec; desired.format = AUDIO_S16SYS; desired.channels = 2; //desired.samples = (uint16)samples; desired.samples = 128; // Samples hack - desired.callback = proc; - desired.userdata = param; + desired.callback = mixCallback; + desired.userdata = this; + + // Create the mixer instance + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; + _samplesPerSec = 0; + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + debug(1, "Output sample rate: %d Hz", _samplesPerSec); + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_samplesPerSec); + _mixer->setReady(true); + SDL_PauseAudio(0); } - _samplesPerSec = obtained.freq; - SDL_PauseAudio(0); - return true; -} - -void OSystem_GP2X::clearSoundCallback() { - SDL_CloseAudio(); -} - -int OSystem_GP2X::getOutputSampleRate() const { - return _samplesPerSec; } Audio::Mixer *OSystem_GP2X::getMixer() { diff --git a/backends/platform/iphone/osys_iphone.cpp b/backends/platform/iphone/osys_iphone.cpp index 3365c2da9d..4cb90d35b9 100644 --- a/backends/platform/iphone/osys_iphone.cpp +++ b/backends/platform/iphone/osys_iphone.cpp @@ -1128,10 +1128,6 @@ bool OSystem_IPHONE::setSoundCallback(SoundProc proc, void *param) { return true; } -void OSystem_IPHONE::clearSoundCallback() { - debug("clearSoundCallback()\n"); -} - int OSystem_IPHONE::getOutputSampleRate() const { return AUDIO_SAMPLE_RATE; } diff --git a/backends/platform/iphone/osys_iphone.h b/backends/platform/iphone/osys_iphone.h index 71272b73fe..a01cad480a 100644 --- a/backends/platform/iphone/osys_iphone.h +++ b/backends/platform/iphone/osys_iphone.h @@ -153,7 +153,6 @@ public: virtual void deleteMutex(MutexRef mutex); virtual bool setSoundCallback(SoundProc proc, void *param); - virtual void clearSoundCallback(); virtual int getOutputSampleRate() const; virtual void setTimerCallback(TimerProc callback, int interval); diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp index 64d429a83e..463e9d7b2d 100644 --- a/backends/platform/null/null.cpp +++ b/backends/platform/null/null.cpp @@ -28,18 +28,37 @@ #if defined(USE_NULL_DRIVER) +#ifdef UNIX +#include <unistd.h> +#include <sys/time.h> +#endif + #include "common/rect.h" #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" + +/* + * Include header files needed for the getFilesystemFactory() method. + */ +#if defined(__amigaos4__) + #include "backends/fs/amigaos4/amigaos4-fs-factory.h" +#elif defined(UNIX) + #include "backends/fs/posix/posix-fs-factory.h" +#elif defined(WIN32) + #include "backends/fs/windows/windows-fs-factory.h" +#endif + + class OSystem_NULL : public OSystem { protected: Common::SaveFileManager *_savefile; - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; Common::TimerManager *_timer; + timeval _startTime; public: OSystem_NULL(); @@ -93,8 +112,6 @@ public: typedef void (*SoundProc)(void *param, byte *buf, int len); virtual bool setSoundCallback(SoundProc proc, void *param); - virtual void clearSoundCallback(); - virtual int getOutputSampleRate() const; virtual void quit(); @@ -104,6 +121,8 @@ public: virtual Audio::Mixer *getMixer(); virtual void getTimeAndDate(struct tm &t) const; virtual Common::TimerManager *getTimerManager(); + FilesystemFactory *getFilesystemFactory(); + }; static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { @@ -124,9 +143,14 @@ OSystem_NULL::~OSystem_NULL() { void OSystem_NULL::initBackend() { _savefile = new DefaultSaveFileManager(); - _mixer = new Audio::Mixer(); + _mixer = new Audio::MixerImpl(this); _timer = new DefaultTimerManager(); + _mixer->setOutputRate(22050); + _mixer->setReady(false); + + gettimeofday(&_startTime, NULL); + // Note that both the mixer and the timer manager are useless // this way; they need to be hooked into the system somehow to // be functional. Of course, can't do that in a NULL backend :). @@ -245,10 +269,20 @@ bool OSystem_NULL::pollEvent(Common::Event &event) { } uint32 OSystem_NULL::getMillis() { +#ifdef UNIX + timeval curTime; + gettimeofday(&curTime, NULL); + return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \ + ((curTime.tv_usec - _startTime.tv_usec) / 1000)); +#else return 0; +#endif } void OSystem_NULL::delayMillis(uint msecs) { +#ifdef UNIX + usleep(msecs * 1000); +#endif } OSystem::MutexRef OSystem_NULL::createMutex(void) { @@ -268,13 +302,6 @@ bool OSystem_NULL::setSoundCallback(SoundProc proc, void *param) { return true; } -void OSystem_NULL::clearSoundCallback() { -} - -int OSystem_NULL::getOutputSampleRate() const { - return 22050; -} - void OSystem_NULL::quit() { } @@ -299,6 +326,19 @@ Common::TimerManager *OSystem_NULL::getTimerManager() { void OSystem_NULL::getTimeAndDate(struct tm &t) const { } +FilesystemFactory *OSystem_NULL::getFilesystemFactory() { + #if defined(__amigaos4__) + return &AmigaOSFilesystemFactory::instance(); + #elif defined(UNIX) + return &POSIXFilesystemFactory::instance(); + #elif defined(WIN32) + return &WindowsFilesystemFactory::instance(); + #else + #error Unknown and unsupported backend in OSystem_NULL::getFilesystemFactory + #endif +} + + OSystem *OSystem_NULL_create() { return new OSystem_NULL(); } diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index b2818ebfc0..28ced7b345 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -727,7 +727,6 @@ void OSystem_PS2::quit(void) { driveStandby(); fio.umount("pfs0:"); } - //clearSoundCallback(); //setTimerCallback(NULL, 0); _screen->wantAnim(false); _systemQuit = true; diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index aa27f388b9..ca09286c4d 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -2,10 +2,36 @@ # $URL$ # $Id$ +ENABLED=STATIC_PLUGIN + #control build DISABLE_SCALERS = true DISABLE_HQ_SCALERS = true +ENABLE_SCUMM = $(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_IGOR = $(ENABLED) +ENABLE_KYRA = $(ENABLED) +ENABLE_LURE = $(ENABLED) +#ENABLE_M4 = $(ENABLED) +#ENABLE_MADE = $(ENABLED) +#ENABLE_PARALLACTION = $(ENABLED) +#ENABLE_QUEEN = $(ENABLED) +#ENABLE_SAGA = $(ENABLED) +ENABLE_SKY = $(ENABLED) +ENABLE_SWORD1 = $(ENABLED) +ENABLE_SWORD2 = $(ENABLED) +#ENABLE_TINSEL = $(ENABLED) +#ENABLE_TOUCHE = $(ENABLED) + + srcdir = ../../.. VPATH = $(srcdir) HAVE_GCC3 = false @@ -63,6 +89,8 @@ OBJS := psp_main.o \ kbd_l_c.o \ trace.o +DEPDIR = .deps + include $(srcdir)/Makefile.common PSP_EBOOT_SFO = param.sfo diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index d5d59d4d6e..6e9b5980d4 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -34,7 +34,7 @@ #include "backends/timer/default/default-timer.h" #include "graphics/surface.h" #include "graphics/scaler.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include <pspgu.h> @@ -72,7 +72,7 @@ const OSystem::GraphicsMode OSystem_PSP::s_supportedGraphicsModes[] = { }; -OSystem_PSP::OSystem_PSP() : _screenWidth(0), _screenHeight(0), _overlayWidth(0), _overlayHeight(0), _offscreen(0), _overlayBuffer(0), _overlayVisible(false), _shakePos(0), _mouseBuf(0), _prevButtons(0), _lastPadCheck(0), _padAccel(0) { +OSystem_PSP::OSystem_PSP() : _screenWidth(0), _screenHeight(0), _overlayWidth(0), _overlayHeight(0), _offscreen(0), _overlayBuffer(0), _overlayVisible(false), _shakePos(0), _mouseBuf(0), _prevButtons(0), _lastPadCheck(0), _padAccel(0), _mixer(0) { memset(_palette, 0, sizeof(_palette)); @@ -99,11 +99,11 @@ OSystem_PSP::~OSystem_PSP() { void OSystem_PSP::initBackend() { _savefile = new DefaultSaveFileManager(); - _mixer = new Audio::Mixer(); _timer = new DefaultTimerManager(); - setSoundCallback(Audio::Mixer::mixCallback, _mixer); setTimerCallback(&timer_handler, 10); + setupMixer(); + OSystem::initBackend(); } @@ -586,7 +586,15 @@ void OSystem_PSP::deleteMutex(MutexRef mutex) { SDL_DestroyMutex((SDL_mutex *)mutex); } -bool OSystem_PSP::setSoundCallback(SoundProc proc, void *param) { +void OSystem_PSP::mixCallback(void *sys, byte *samples, int len) { + OSystem_PSP *this_ = (OSystem_PSP *)sys; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(samples, len); +} + +void OSystem_PSP::setupMixer(void) { SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -613,29 +621,33 @@ bool OSystem_PSP::setSoundCallback(SoundProc proc, void *param) { desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = samples; - desired.callback = proc; - desired.userdata = param; - if (SDL_OpenAudio(&desired, &obtained) != 0) { - return false; - } - // Note: This should be the obtained output rate, but it seems that at - // least on some platforms SDL will lie and claim it did get the rate - // even if it didn't. Probably only happens for "weird" rates, though. - _samplesPerSec = obtained.freq; - SDL_PauseAudio(0); - return true; -} + desired.callback = mixCallback; + desired.userdata = this; -void OSystem_PSP::clearSoundCallback() { - SDL_CloseAudio(); -} + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); -int OSystem_PSP::getOutputSampleRate() const { - return _samplesPerSec; + if (SDL_OpenAudio(&desired, &obtained) != 0) { + warning("Could not open audio: %s", SDL_GetError()); + _samplesPerSec = 0; + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_samplesPerSec); + _mixer->setReady(true); + + SDL_PauseAudio(0); + } } void OSystem_PSP::quit() { - clearSoundCallback(); + SDL_CloseAudio(); SDL_Quit(); sceGuTerm(); sceKernelExitGame(); diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index a59e927b97..dca6ccb036 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -26,6 +26,7 @@ #include "common/scummsys.h" #include "common/system.h" #include "graphics/surface.h" +#include "sound/mixer_intern.h" #include "backends/fs/psp/psp-fs-factory.h" @@ -71,7 +72,7 @@ protected: SceCtrlData pad; Common::SaveFileManager *_savefile; - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; Common::TimerManager *_timer; public: @@ -129,10 +130,8 @@ public: virtual void unlockMutex(MutexRef mutex); virtual void deleteMutex(MutexRef mutex); - typedef void (*SoundProc)(void *param, byte *buf, int len); - virtual bool setSoundCallback(SoundProc proc, void *param); - virtual void clearSoundCallback(); - virtual int getOutputSampleRate() const; + static void mixCallback(void *sys, byte *samples, int len); + virtual void setupMixer(void); Common::SaveFileManager *getSavefileManager() { return _savefile; } Audio::Mixer *getMixer() { return _mixer; } diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index be3aaad926..290fe63663 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -30,7 +30,7 @@ #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "icons/scummvm.xpm" @@ -131,9 +131,7 @@ void OSystem_SDL::initBackend() { // Create and hook up the mixer, if none exists yet (we check for this to // allow subclasses to provide their own). if (_mixer == 0) { - _mixer = new Audio::Mixer(); - bool result = setSoundCallback(Audio::Mixer::mixCallback, _mixer); - _mixer->setReady(result); + setupMixer(); } // Create and hook up the timer manager, if none exists yet (we check for @@ -391,7 +389,15 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) { #pragma mark --- Audio --- #pragma mark - -bool OSystem_SDL::setSoundCallback(SoundProc proc, void *param) { +void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) { + OSystem_SDL *this_ = (OSystem_SDL *)sys; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(samples, len); +} + +void OSystem_SDL::setupMixer() { SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -403,7 +409,7 @@ bool OSystem_SDL::setSoundCallback(SoundProc proc, void *param) { _samplesPerSec = SAMPLES_PER_SEC; // Determine the sample buffer size. We want it to store enough data for - // about 1/32th of a second. Note that it must be a power of two. + // about 1/16th of a second. Note that it must be a power of two. // So e.g. at 22050 Hz, we request a sample buffer size of 2048. int samples = 8192; while (16 * samples >= _samplesPerSec) { @@ -415,23 +421,30 @@ bool OSystem_SDL::setSoundCallback(SoundProc proc, void *param) { desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = (uint16)samples; - desired.callback = proc; - desired.userdata = param; + desired.callback = mixCallback; + desired.userdata = this; + + // Create the mixer instance + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; + _samplesPerSec = 0; + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + debug(1, "Output sample rate: %d Hz", _samplesPerSec); + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_samplesPerSec); + _mixer->setReady(true); + SDL_PauseAudio(0); } - // Note: This should be the obtained output rate, but it seems that at - // least on some platforms SDL will lie and claim it did get the rate - // even if it didn't. Probably only happens for "weird" rates, though. - _samplesPerSec = obtained.freq; - debug(1, "Output sample rate: %d Hz", _samplesPerSec); - SDL_PauseAudio(0); - return true; -} - -int OSystem_SDL::getOutputSampleRate() const { - return _samplesPerSec; } Audio::Mixer *OSystem_SDL::getMixer() { diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 2cbadae2f4..8a94a17b00 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -38,7 +38,7 @@ namespace Audio { - class Mixer; + class MixerImpl; } namespace Common { @@ -134,8 +134,9 @@ public: virtual bool pollEvent(Common::Event &event); // overloaded by CE backend // Set function that generates samples - typedef void (*SoundProc)(void *param, byte *buf, int len); - virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend + virtual void setupMixer(); + static void mixCallback(void *s, byte *samples, int len); + virtual Audio::Mixer *getMixer(); // Poll CD status @@ -186,7 +187,6 @@ public: virtual void setWindowCaption(const char *caption); virtual bool openCD(int drive); - virtual int getOutputSampleRate() const; virtual bool hasFeature(Feature f); virtual void setFeatureState(Feature f, bool enable); @@ -371,7 +371,7 @@ protected: Common::SaveFileManager *_savefile; - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; SDL_TimerID _timerID; Common::TimerManager *_timer; diff --git a/backends/platform/symbian/AdaptAllMMPs.pl b/backends/platform/symbian/AdaptAllMMPs.pl index 99c037379d..b576bb3993 100644 --- a/backends/platform/symbian/AdaptAllMMPs.pl +++ b/backends/platform/symbian/AdaptAllMMPs.pl @@ -6,31 +6,37 @@ chdir("../../../"); # list of project files to process @mmp_files = ( - "mmp/scummvm_scumm.mmp", - "mmp/scummvm_queen.mmp", - "mmp/scummvm_agos.mmp", - "mmp/scummvm_sky.mmp", - "mmp/scummvm_gob.mmp", - "mmp/scummvm_saga.mmp", - "mmp/scummvm_kyra.mmp", - "mmp/scummvm_sword1.mmp", - "mmp/scummvm_sword2.mmp", - "mmp/scummvm_lure.mmp", - "mmp/scummvm_cine.mmp", - "mmp/scummvm_agi.mmp", - "mmp/scummvm_touche.mmp", - "mmp/scummvm_parallaction.mmp", - "mmp/scummvm_cruise.mmp", - "mmp/scummvm_drascula.mmp", - "mmp/scummvm_igor.mmp", - "mmp/scummvm_made.mmp", + + # Engine Project files + "mmp/scummvm_agi.mmp", + "mmp/scummvm_agos.mmp", + "mmp/scummvm_cine.mmp", + "mmp/scummvm_cruise.mmp", + "mmp/scummvm_drascula.mmp", + "mmp/scummvm_gob.mmp", + "mmp/scummvm_igor.mmp", + "mmp/scummvm_kyra.mmp", + "mmp/scummvm_lure.mmp", "mmp/scummvm_m4.mmp", - "S60/ScummVM_S60.mmp", - "S60v3/ScummVM_S60v3.mmp", - "S80/ScummVM_S80.mmp", + "mmp/scummvm_made.mmp", + "mmp/scummvm_parallaction.mmp", + "mmp/scummvm_queen.mmp", + "mmp/scummvm_saga.mmp", + "mmp/scummvm_scumm.mmp", + "mmp/scummvm_sky.mmp", + "mmp/scummvm_sword1.mmp", + "mmp/scummvm_sword2.mmp", + "mmp/scummvm_touche.mmp", + + + # Target Platform Project Files + "S60/ScummVM_S60.mmp", + "S60v3/ScummVM_S60v3.mmp", + "S80/ScummVM_S80.mmp", "S90/ScummVM_S90.mmp", - "UIQ2/ScummVM_UIQ2.mmp", - "UIQ3/ScummVM_UIQ3.mmp" + "UIQ2/ScummVM_UIQ2.mmp", + "UIQ3/ScummVM_UIQ3.mmp" + ); # do this first to set all *.mmp & *.inf files to *.*.in states @@ -43,7 +49,7 @@ Updating slave MACRO settings in MMP files from master 'scummvm_base.mmp' "; -# do this first so we have @DisableDefines for correct inclusion of SOURCE files later +# do this first so we have @EnabledDefines and @DisabledDefines for correct inclusion of SOURCE files later UpdateSlaveMacros(); print " @@ -53,33 +59,40 @@ Preparing to update all the Symbian MMP project files with objects from module.m "; + +# some modules.mk files have #ifndef ENABLE_XXXX blocks: my @section_empty = (""); # section standard: no #ifdef's in module.mk files -my @sections_scumm = ("", "DISABLE_SCUMM_7_8", "DISABLE_HE"); # special sections for engine SCUMM +my @sections_scumm = ("", "ENABLE_SCUMM_7_8", "ENABLE_HE"); # special sections for engine SCUMM + # files excluded from build, case insensitive, will be matched in filename string only -my @excludes_snd = ( - "mt32", - "fluidsynth", - "i386", - "part.cpp", - "partial.cpp", - "partialmanager.cpp", +my @excludes_snd = ( + "mt32.*", + "fluidsynth.cpp", + "i386.cpp", + "part.*", "synth.cpp", "tables.cpp", - "freeverb.cpp" -); + "freeverb.cpp", + "rate.*" # not really needed, USE_ARM_SOUND_ASM currently not parsed correctly, + # "rate[_arm|_arm_asm].(cpp|s)" will be added later based on WINS/ARM build! + # These #defines for compile time are set in portdefs.h +); -my @excludes_graphics = ( -"iff.cpp" -); +my @excludes_graphics = ( + "iff.cpp" +); +# the USE_ARM_* defines not parsed correctly, exclude manually: my @excludes_scumm = ( - "codec47ARM.cpp", - "gfxARM.cpp", - "proc3arm.cpp" + ".*ARM.*", # the *ARM.s files are added in .mpp files based on WINS/ARM build! + # USE_ARM_SMUSH_ASM codec47ARM.s + # USE_ARM_GFX_ASM gfxARM.s + # USE_ARM_COSTUME_ASM proc3ARM.s compiled, linked?, but *not* used :P (portdefs.h) ); -#arseModule(mmpStr, dirStr, ifdefArray, [exclusionsArray]) + +#arseModule(mmpStr, dirStr, ifdefArray, [exclusionsArray]) ParseModule("_base", "base", \@section_empty); # now in ./TRG/ScummVM_TRG.mmp, these never change anyways... ParseModule("_base", "common", \@section_empty); ParseModule("_base", "gui", \@section_empty); @@ -98,14 +111,14 @@ ParseModule("_sword1", "sword1", \@section_empty); ParseModule("_sword2", "sword2", \@section_empty); ParseModule("_lure", "lure", \@section_empty); ParseModule("_cine", "cine", \@section_empty); -ParseModule("_agi", "agi", \@section_empty); +ParseModule("_agi", "agi", \@section_empty); ParseModule("_touche", "touche", \@section_empty); ParseModule("_parallaction","parallaction",\@section_empty); ParseModule("_cruise", "cruise", \@section_empty); ParseModule("_drascula","drascula", \@section_empty); ParseModule("_igor", "igor", \@section_empty); ParseModule("_made", "made", \@section_empty); -ParseModule("_m4", "m4", \@section_empty); +ParseModule("_m4", "m4", \@section_empty); print " ======================================================================================= Done. Enjoy :P @@ -115,7 +128,7 @@ Done. Enjoy :P ################################################################################################################## ################################################################################################################## -# parses multiple sections per mmp/module +# parses multiple sections per mmp/module sub ParseModule { my ($mmp,$module,$sections,$exclusions) = @_; @@ -140,7 +153,7 @@ sub CheckForModuleMK if (-d $item) { #print "$item\n"; - + opendir DIR, $item; #my @Files = readdir DIR; my @Files = grep s/^([^\.].*)$/$1/, readdir DIR; @@ -156,9 +169,10 @@ sub CheckForModuleMK if (-f $item and $item =~ /.*\/module.mk$/) { my $sec = ""; + my $isenable; my $ObjectsSelected = 0; my $ObjectsTotal = 0; - + print "$item for section '$section' ... "; open FILE, $item; @@ -167,14 +181,24 @@ sub CheckForModuleMK my $count = @lines; print "$count lines"; - + A: foreach $line (@lines) { - # found a section? reset + # all things we need are inside #ifdef sections, + # there is nothing we need in #ifndef sections: so ignore these for now + + # found a section? reset + if ($line =~ /^ifdef (.*)/) + { + $sec = $1; + $isenable = 1; + } if ($line =~ /^ifndef (.*)/) { $sec = $1; + $isenable = 0; } + # found an object? Not uncommented! if (!($line =~ /^#/) && $line =~ s/\.o/.cpp/) { @@ -187,27 +211,47 @@ sub CheckForModuleMK $line =~ s/ \\//; # remove possible trailing ' \' $line =~ s/\//\\/g; # replace / with \ chop($line); # remove \n - + # do we need to skip this file? According to our own @exclusions array foreach $exclusion (@exclusions) { if ($line =~ /$exclusion/i) { - print "\n ! $line (excluded, \@exclusions[$exclusion])"; + my $reason = "excluded, \@exclusions[$exclusion]"; + print "\n ! $line ($reason)"; + $output .= "//SOURCE $line ($reason)\n"; next A; } } - - # do we need to skip this file? According to MACROs in .MMPs - foreach $DisableDefine (@DisableDefines) + + # do we need to do this file? According to MACROs in .MMPs + my $found = 0; + foreach $EnableDefine (@EnabledDefines) { - if ($DisableDefine eq $section && $section ne '') + if (($EnableDefine eq $section) && ($section ne '')) { - print "\n !$line (excluded, MACRO $DisableDefine)"; - next A; + $found = 1; + last; } } - + foreach $DisableDefine (@DisabledDefines) + { + if (($DisableDefine eq $section) && ($section ne '')) + { + $found = 0; + last; + } + } + # always allow non-sections + $found = 1 if ($section eq ''); + if (!$found) + { + my $reason = "excluded, MACRO $section"; + print "\n !$line ($reason)"; + $output .= "//SOURCE $line ($reason)\n"; + next A; + } + $ObjectsSelected++; #print "\n $line"; $output .= "SOURCE $line\n"; @@ -230,7 +274,7 @@ sub UpdateProjectFile my $updated = " Updated @ ".localtime(); my $name; my @mmp_files_plus_one = @mmp_files; - unshift @mmp_files_plus_one, "mmp/scummvm_base.mmp"; + unshift @mmp_files_plus_one, "mmp/scummvm_base.mmp"; foreach $name (@mmp_files_plus_one) { @@ -239,23 +283,23 @@ sub UpdateProjectFile open FILE, "$file"; my @lines = <FILE>; close FILE; - + my $onestr = join("",@lines); - + if ($onestr =~ /$n/) { print " - $name @ $n updating ... "; - + $onestr =~ s/$a.*$b/$a$updated\n$output$b/s; open FILE, ">$file"; print FILE $onestr; close FILE; - + print "done.\n"; } } - + $output = ""; } @@ -265,7 +309,7 @@ sub UpdateSlaveMacros { my $updated = " Updated @ ".localtime(); - my $name = "mmp/scummvm_base.mmp"; + my $name = "mmp/scummvm_base.mmp"; my $file = "$buildDir/$name"; print "Reading master MACROS from backends/symbian/$name ... "; @@ -279,7 +323,7 @@ sub UpdateSlaveMacros my $b = "\/\/STOP_$n\/\/"; $onestr =~ /$a(.*)$b/s; my $macros = $1; - + my $libs_first = "\n// automagically enabled static libs from macros above\n"; my $libs_second = "STATICLIBRARY scummvm_base.lib // must be above USE_* .libs\n"; my $macro_counter = 0; @@ -292,32 +336,45 @@ sub UpdateSlaveMacros if ($line =~ /^.*MACRO\s*([0-9A-Z_]*)\s*\/\/\s*LIB\:(.*)$/) { my $macro = $1; my $lib = $2; - + # this macro enabled? then also add the .lib if ($line =~ /^\s*MACRO\s*$macro/m) { - # these are the USE_ libs + # add an USE_ lib? (these need to be added @ the beginning, before _base) $libs_second .= "STATICLIBRARY $lib\n" if ($macro =~ /^USE_/); + + # add an ENABLE_ lib? (these need to be added @ the end, after _base) + if ($macro =~ /^ENABLE_/) + { + $libs_first .= "STATICLIBRARY $lib\n"; + + # add projects for BLD.INF's + my $projectname = substr("$lib",0,-4); + $projects .= "..\\mmp\\$projectname.mmp\n"; + } } else { - # these are the non DISABLED_ libs - $libs_first .= "STATICLIBRARY $lib\n" if ($macro =~ /^DISABLE_/); - - # add projects for BLD.INF's - my $projectname = substr("$lib",0,-4); - $projects .= "..\\mmp\\$projectname.mmp\n" if ($macro =~ /^DISABLE_/); + # skip lines not beginning with "MACRO" (like "//MACRO") } $macro_counter++; } + # not commented out? then add the macro to output string if ($line =~ /^\s*MACRO\s*([0-9A-Z_]*)\s*/) { my $macro = $1; $macros2 .= "$line\n"; - push @DisableDefines, $macro; # used in CheckForModuleMK()!! + if ($macro =~ /^ENABLE_/) + { + push @EnabledDefines, $macro; # used in CheckForModuleMK()!! + } + elsif ($macro =~ /^DISABLE_/) + { + push @DisabledDefines, $macro; # used in CheckForModuleMK()!! + } } - } + } print "$macro_counter macro lines.\n"; @@ -328,23 +385,23 @@ sub UpdateSlaveMacros $m = "AUTO_PROJECTS"; $p = "\/\/START_$m\/\/"; $q = "\/\/STOP_$m\/\/"; - + foreach $name (@mmp_files) { $file = "$buildDir/$name"; $fileBLDINF = $buildDir .'/'. substr($name, 0, rindex($name, "/")) . "/BLD.INF"; print "Updating macros in $file ... "; #print "Updating macros in backends/symbian/$name ... "; - + open FILE, "$file"; @lines = <FILE>; close FILE; $onestr = join("",@lines); - + my $extralibs = ""; # output # slash in name means it's a phone specific build file: add LIBs $extralibs .= "$libs_first$libs_second" if (-e $fileBLDINF); - + $onestr =~ s/$a.*$b/$a$updated$macros2$extralibs$b/s; - + open FILE, ">$file"; print FILE $onestr; close FILE; my $count = @lines; @@ -358,13 +415,13 @@ sub UpdateSlaveMacros open FILE, "$fileBLDINF"; @lines = <FILE>; close FILE; $onestr = join("",@lines); - + $onestr =~ s/$p.*$q/$p$updated$projects$q/s; - + open FILE, ">$fileBLDINF"; print FILE $onestr; close FILE; } } -} +} ################################################################################################################## @@ -372,10 +429,10 @@ sub ResetProjectFiles() { my $onestr, @lines; my @mmp_files_plus_one = @mmp_files; -# unshift @mmp_files_plus_one, "mmp/scummvm_base.mmp"; - +# unshift @mmp_files_plus_one, "mmp/scummvm_base.mmp"; + print "Resetting project files: "; - + # we don't need to do mmp/scummvm_base.mmp", it was done in BuildPackageUpload.pl before the call to this script foreach $name (@mmp_files_plus_one) { @@ -395,7 +452,7 @@ sub ResetProjectFiles() $onestr = join("",@lines); open FILE, ">$fileBLDINF"; print FILE $onestr; close FILE; } - } + } print "... done.\n"; } diff --git a/backends/platform/symbian/BuildPackageUpload_AllVersions.pl b/backends/platform/symbian/BuildPackageUpload_AllVersions.pl index a40f8b7663..94edbf4fcf 100644 --- a/backends/platform/symbian/BuildPackageUpload_AllVersions.pl +++ b/backends/platform/symbian/BuildPackageUpload_AllVersions.pl @@ -8,6 +8,7 @@ require "BuildPackageUpload_LocalSettings.pl"; ################################################################################################################## # prep some vars +# the dir containing the build files: '.\backends\platforms\symbian\$SDK_BuildDir\' $SDK_BuildDirs{'UIQ2'} = "UIQ2"; $SDK_BuildDirs{'UIQ3'} = "UIQ3"; $SDK_BuildDirs{'S60v1'} = "S60"; @@ -16,6 +17,7 @@ $SDK_BuildDirs{'S60v3'} = "S60v3"; $SDK_BuildDirs{'S80'} = "S80"; $SDK_BuildDirs{'S90'} = "S90"; +# the target name inserted here: 'abld BUILD $SDK_TargetName UREL' $SDK_TargetName{'UIQ2'} = "armi"; $SDK_TargetName{'UIQ3'} = "gcce"; $SDK_TargetName{'S60v1'}= "armi"; @@ -24,6 +26,7 @@ $SDK_TargetName{'S60v3'}= "gcce"; $SDK_TargetName{'S80'} = "armi"; $SDK_TargetName{'S90'} = "armi"; +# Binaries are installed here: '$SDK_RootDirs\epoc32\release\$SDK_TargetDir\urel\' $SDK_TargetDir{'UIQ2'} = "armi"; $SDK_TargetDir{'UIQ3'} = "armv5"; $SDK_TargetDir{'S60v1'} = "armi"; @@ -34,11 +37,11 @@ $SDK_TargetDir{'S90'} = "armi"; $build_dir = getcwd(); $output_dir = "$build_dir/Packages"; -chdir("../../"); +chdir("../../../"); $base_dir = getcwd(); chdir($build_dir); -$build_log_out = "$build_dir/Build.out.log"; -$build_log_err = "$build_dir/Build.err.log"; +$build_log_out = "$build_dir/out.build.out.log"; # don't start these files with "Build" +$build_log_err = "$build_dir/out.build.err.log"; # so "B"+TAB completion works in 1 go :P $initial_path = $ENV{'PATH'}; # so we can start with a fresh PATH for each Build @@ -54,14 +57,27 @@ $PackagesUploaded = 0; @ErrorMessages = (); $ftp_url = "FTP://$FTP_User\@$FTP_Host/$FTP_Dir/"; -$ExtraMacros = "MACRO NONSTANDARD_PORT\n"; -$ExtraMacros .= "MACRO DISABLE_FANCY_THEMES\n"; +# these macros are always defined: +$ExtraMacros = "MACRO NONSTANDARD_PORT\n"; +$ExtraMacros .= "MACRO DISABLE_FANCY_THEMES\n"; +$ExtraMacros .= "MACRO DISABLE_SCALERS\n"; +$ExtraMacros .= "MACRO DISABLE_HQ_SCALERS\n"; # prep nice list of SDKs #while( ($SDK, $RootDir) = each(%SDK_RootDirs) ) foreach $SDK (sort keys(%SDK_RootDirs)) { - $SDKs .= "$SDK\t$SDK_RootDirs{$SDK}\n\t\t\t"; + # see if it exists! + if (-d $SDK_RootDirs{$SDK}) + { + $SDKs .= "$SDK\t$SDK_RootDirs{$SDK}\n\t\t\t"; + } + else # missing? + { + $SDKs .= "$SDK\t$SDK_RootDirs{$SDK}\t[MISSING: Skipping!]\n\t\t\t"; + # remove it from array, to prevent building! + delete $SDK_RootDirs{$SDK}; + } } # prep nice list of Libraries @@ -69,7 +85,16 @@ while( ($SDK, $Value) = each(%SDK_LibraryDirs) ) { while( ($Library, $Path) = each(%{$SDK_LibraryDirs{$SDK}}) ) { - $PresentLibs{$Library} = $Path; + # maybe it's already been built? + if (-e $SDK_RootDirs{$SDK}."\\epoc32\\release\\$SDK_TargetDir{$SDK}\\urel\\$Library") + { + $PresentLibs{$Library} = "$Path [EXISTS: Skipping!]"; + delete $SDK_LibraryDirs{$SDK}{$Library}; + } + else # make it! + { + $PresentLibs{$Library} = "$Path"; + } } } foreach $Library (sort keys(%PresentLibs)) @@ -78,10 +103,37 @@ foreach $Library (sort keys(%PresentLibs)) } # prep nice list of Variations -while( ($SDK, $Value) = each(%SDK_Variations) ) +#while( ($SDK, $Value) = each(%SDK_Variations) ) +#{ +# while( ($Variation, $Value2) = each(%{$SDK_Variations{$SDK}}) ) +# { +# $Extra = ($Variation ne '' ? "_$Variation" : ""); +# if ($SDK eq "ALL") +# { +# while( ($SDK2, $RootDir) = each(%SDK_RootDirs) ) +# { +# if ($SDK_RootDirs{$SDK2} ne '') # is this SDK listed as installed? (fails silently) +# { +# push @Packages, sprintf($file_tpl_sis, $version_tpl_sis, $SDK2, $Extra); +# $PackagesQueued++; +# } +# } +# } +# else +# { +# if ($SDK_RootDirs{$SDK} ne '') # is this SDK listed as installed? (fails silently) +# { +# push @Packages, sprintf($file_tpl_sis, $version_tpl_sis, $SDK, $Extra); +# $PackagesQueued++; +# } +# } +# } +#} +while( ($SDK, $Value) = each(%VariationSets) ) { - while( ($Variation, $Value2) = each(%{$SDK_Variations{$SDK}}) ) + while( ($Variation, $FeaturesBlock) = each(%{$VariationSets{$SDK}}) ) { +#my $MacroBlock = &MakeMppMacroDefs($FeaturesBlock); $Extra = ($Variation ne '' ? "_$Variation" : ""); if ($SDK eq "ALL") { @@ -92,7 +144,7 @@ while( ($SDK, $Value) = each(%SDK_Variations) ) push @Packages, sprintf($file_tpl_sis, $version_tpl_sis, $SDK2, $Extra); $PackagesQueued++; } - } + } } else { @@ -118,7 +170,7 @@ Preparing to Build, Package & Upload $PackagesQueued SymbianOS ScummVM variation SDKs inst'd \t$SDKs ".( %SDK_LibraryDirs ? " LIBs inst'd \t$LIBs " : "" )." - $PackagesQueued Variations \t$PackagesStr + $PackagesQueued Variations \t$PackagesStr DIR base \t$base_dir build \t$build_dir output \t$output_dir @@ -126,7 +178,7 @@ Preparing to Build, Package & Upload $PackagesQueued SymbianOS ScummVM variation FTP host \t$FTP_Host user \t$FTP_User pass \t"."*" x length($FTP_Pass)." - dir \t$FTP_Dir + dir \t$FTP_Dir " : "" )." ======================================================================================= Press Ctrl-C to abort or enter to continue Build, Package & Upload $PackagesQueued Variations... @@ -142,7 +194,7 @@ unlink($build_log_out); unlink($build_log_err); # init _base.mmp now, so we can start changing it without affecting the CVS version _base.mmp.in! -my $name = "mmp/scummvm_base.mmp"; +my $name = "mmp/scummvm_base.mmp"; my $file = "$build_dir/$name"; open FILE, "$file.in"; @lines = <FILE>; close FILE; my $onestr = join("",@lines); @@ -161,15 +213,21 @@ while( ($SDK, $Value) = each(%SDK_LibraryDirs) ) { if ($SDK_RootDirs{$SDK2} ne '') # is this SDK listed as installed? (fails silently) { + # do we already have this one? + next if (-e $SDK_RootDirs{$SDK2}."\\epoc32\\release\\$SDK_TargetDir{$SDK2}\\urel\\$Library"); + $LibrariesQueued++; DoLibrary($SDK2, $Library, $Path); } - } + } } else { if ($SDK_RootDirs{$SDK} ne '') # is this SDK listed as installed? (fails silently) { + # do we already have this one? + next if (-e $SDK_RootDirs{$SDK}."\\epoc32\\release\\$SDK_TargetDir{$SDK}\\urel\\$Library"); + $LibrariesQueued++; DoLibrary($SDK, $Library, $Path); } @@ -194,8 +252,33 @@ while( ($SDK, $VariationsHash) = each(%SDK_Variations) ) { DoVariation($SDK2, $Variation, $MacroBlock); } + } + } + else + { + if ($SDK_RootDirs{$SDK} ne '') + { + DoVariation($SDK, $Variation, $MacroBlock); } } + } +} + +while( ($SDK, $VariationsHash) = each(%VariationSets) ) +{ + while( ($Variation, $FeaturesBlock) = each(%{$VariationSets{$SDK}}) ) + { + my $MacroBlock = &MakeMppMacroDefs($FeaturesBlock); + if ($SDK eq "ALL") + { + while( ($SDK2, $RootDir) = each(%SDK_RootDirs) ) + { + if ($SDK_RootDirs{$SDK2} ne '') + { + DoVariation($SDK2, $Variation, $MacroBlock); + } + } + } else { if ($SDK_RootDirs{$SDK} ne '') @@ -248,7 +331,81 @@ print " SumthinWicked wishes you a ridiculously good and optimally happy d ################################################################################################################## ################################################################################################################## -# Build, Package & Upload a single Variation +# create a set of "MACRO xxx" definitions for use in the scummvm_base.mpp file +sub MakeMppMacroDefs +{ + my ($features) = @_; + + my %EnabledFeatures = (); + foreach (split(/\W|\r|\n/, $features)) + { + if ($_ ne "") + { + #print "FEATURE: $_\n"; + $EnabledFeatures{$_} = 1; + } + } + + my $MacroDefs = ""; + + $MacroDefs .= " // Features //\n"; + foreach my $e (sort keys %UseableFeatures) + { + my $E = uc($e); + if ($EnabledFeatures{$e}) + { + $MacroDefs .= "MACRO USE_$E // LIB:$UseableFeatures{$e}\n"; + # this one is used: remove it now + delete $EnabledFeatures{$e}; + # this will leave us with a list of unparsed options! + } + else + { + $MacroDefs .= "//MACRO USE_$E\n"; + } + } + + $MacroDefs .= " // Engines //\n"; + foreach my $e (sort @EnablableEngines) + { + my $E = uc($e); + if ($EnabledFeatures{$e}) + { + $MacroDefs .= "MACRO ENABLE_$E // LIB:scummvm_$e.lib\n"; + # this one is used: remove it now + delete $EnabledFeatures{$e}; + # this will leave us with a list of unparsed options! + } + else + { + $MacroDefs .= "//MACRO ENABLE_$E\n"; + } + } + + $MacroDefs .= " // SubEngines //\n"; + foreach my $e (sort @EnablableSubEngines) + { + my $E = uc($e); + if ($EnabledFeatures{$e}) + { + $MacroDefs .= "MACRO ENABLE_$E\n"; + # this one is used: remove it now + delete $EnabledFeatures{$e}; + # this will leave us with a list of unparsed options! + } + else + { + $MacroDefs .= "//MACRO ENABLE_$E\n"; + } + } + +#print "\n\n'$features' ==> $MacroDefs\n\n\n"; + return $MacroDefs; +} + +################################################################################################################## + +# Build, Package & Upload a single Variation sub DoLibrary { my ($SDK, $Library, $Path) = @_; @@ -278,19 +435,19 @@ my $header = " my $OK = 1; PrepSdkPaths($SDK); - + chdir($Path) or $OK=0; PrintErrorMessage("Changing to $Path failed!") if (!$OK); - return 0 if (!$OK); + return 0 if (!$OK); PrintMessage("Cleaning for $Target") if (!$ReallyQuiet); system("bldmake bldfiles > NUL 2> NUL"); PrintErrorMessage("'bldmake bldfiles' exited with value " . ($? >> 8)) if ($? >> 8); - system("abld clean $TargetName urel > NUL 2> NUL"); - PrintErrorMessage("'abld clean $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8); + system("abld CLEAN $TargetName UREL > NUL 2> NUL"); + PrintErrorMessage("'abld CLEAN $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8); # remove file so we are sure that after .lib generation we have a fresh copy! if (-e $TargetFilePath) { unlink($TargetFilePath) or PrintErrorMessage("Removing $TargetFilePath"); } - + my $Redirection = "OUT:file, ERR:".($RedirectSTDERR ? "file" : "screen"); my $Message = "Building $Target ($Redirection)"; PrintMessage($Message) if (!$ReallyQuiet); @@ -298,18 +455,18 @@ my $header = " my $OldSize = (-s $build_log_err); $Redirection = ($RedirectSTDERR ? "2>> $build_log_err" : ""); - system("abld build $TargetName urel $Redirection >> $build_log_out"); + system("abld BUILD $TargetName UREL $Redirection >> $build_log_out"); $OK = 0 if ($? >> 8); # print " STDERR: ".((-s $build_log_err)-$OldSize)." bytes output written to $build_log_err\n+--------------------------------------------------------------------------------------\n" if ($OldSize != (-s $build_log_err)); - PrintErrorMessage("'abld build $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8); - return 0 if (!$OK); # ABLD always returns ok :( grr + PrintErrorMessage("'abld BUILD $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8); + return 0 if (!$OK); # ABLD always returns ok :( grr PrintMessage("Done.") if (!$ReallyQuiet); # did it work? :) if (-e $TargetFilePath) { $LibrariesSucceeded++; - + if ($TargetIntermediatePath ne '' && $TargetIntermediatePath =~ /\\EPOC32\\BUILD\\/i) # make really sure it's a valid path! { system("del /S /Q $TargetIntermediatePath > NUL"); @@ -318,9 +475,9 @@ my $header = " } else { - PrintErrorMessage("'abld build $TargetName urel' apparently failed."); + PrintErrorMessage("'abld BUILD $TargetName UREL' apparently failed."); if ($HaltOnError) - { + { PrintErrorMessage("Halting on error as requested!"); exit 1; } @@ -330,12 +487,12 @@ my $header = " ################################################################################################################## -# Build, Package & Upload a single Variation +# Build, Package & Upload a single Variation sub DoVariation { my ($SDK, $Variation, $MacroBlock) = @_; my $Extra = ($Variation ne '' ? "_$Variation" : ""); - my $Package = sprintf($file_tpl_sis, $version_tpl_sis, $SDK, $Extra); + my $Package = sprintf($file_tpl_sis, $version_tpl_sis, $SDK, $Extra); if ($SkipExistingPackages && -f "$output_dir/$Package") { @@ -366,7 +523,7 @@ my $header = " if ($OK) { $OK = BuildVariation($SDK, $Variation, $Package, $MacroBlock); - + if ($OK && $FTP_Host ne '') { UploadVariation($SDK, $Variation, $Package); @@ -382,17 +539,17 @@ sub PrepVariation() my $OK = 1; PrepSdkPaths($SDK); - + chdir($build_dir) or $OK=0; PrintErrorMessage("Changing to $build_dir failed!") if (!$OK); - return 0 if (!$OK); + return 0 if (!$OK); # insert $MacroBlock into AUTO_MACRO_MASTER in scummvm_base.mmp PrintMessage("Setting new AUTO_MACROS_MASTER in scummvm_base.mmp for '$Variation'") if (!$ReallyQuiet); my $n = "AUTO_MACROS_MASTER"; my $a = "\/\/START_$n\/\/"; my $b = "\/\/STOP_$n\/\/"; - my $name = "scummvm_base.mmp"; + my $name = "scummvm_base.mmp"; my $file = "$build_dir/mmp/$name"; my $updated = " Updated @ ".localtime(); @@ -401,11 +558,11 @@ sub PrepVariation() return 0 if (!$OK); my @lines = <FILE>; close FILE; - + my $onestr = join("",@lines); $MacroBlock =~ s/^\s*//gm; $onestr =~ s/$a(.*)$b/$a$updated\n$ExtraMacros$MacroBlock$b/s; - + open FILE, ">$file" or $OK=0; PrintErrorMessage("Writing file '$file'") if (!$OK); return 0 if (!$OK); @@ -418,7 +575,7 @@ sub PrepVariation() $OK = 0 if ($? >> 8); PrintErrorMessage("'AdaptAllMMPs.pl' exited with value " . ($? >> 8)) if ($? >> 8); return 0 if (!$OK); - + # we are here: so all is ok :) return 1; } @@ -431,7 +588,7 @@ sub BuildVariation() my $TargetName = $SDK_TargetName{$SDK}; my $TargetDir = $SDK_TargetDir{$SDK}; my $OK = 1; - + my $dir = $build_dir."/".$SDK_BuildDirs{$SDK}; $dir =~ s#/#\\#g; chdir($dir); @@ -449,13 +606,15 @@ sub BuildVariation() if (-e $UnlinkFile) { unlink($UnlinkFile) or PrintErrorMessage("Removing $UnlinkFile"); } $UnlinkFile = $SDK_RootDirs{$SDK}."/epoc32/release/$TargetDir/urel/ScummVM.exe"; if (-e $UnlinkFile) { unlink($UnlinkFile) or PrintErrorMessage("Removing $UnlinkFile"); } + # remove all libs here, note they are in another dir! + system("del ".$SDK_RootDirs{$SDK}."/epoc32/release/$TargetName/urel/scummvm_*.lib"); system("bldmake bldfiles 2> NUL > NUL"); PrintErrorMessage("'bldmake bldfiles' exited with value " . ($? >> 8)) if ($? >> 8); - system("abld clean $TargetName urel 2> NUL > NUL"); - PrintErrorMessage("'abld clean $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8); - + system("abld CLEAN $TargetName UREL 2> NUL > NUL"); + PrintErrorMessage("'abld CLEAN $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8); + my $Redirection = "OUT:file, ERR:".($RedirectSTDERR ? "file" : "screen"); my $Message = "Building $Package ($Redirection)"; PrintMessage($Message) if (!$ReallyQuiet); @@ -463,11 +622,11 @@ sub BuildVariation() my $OldSize = (-s $build_log_err); $Redirection = ($RedirectSTDERR ? "2>> $build_log_err" : ""); - system("abld build $TargetName urel $Redirection >> $build_log_out"); + system("abld BUILD $TargetName UREL $Redirection >> $build_log_out"); $OK = 0 if ($? >> 8); print " STDERR: ".((-s $build_log_err)-$OldSize)." bytes output written to $build_log_err\n+--------------------------------------------------------------------------------------\n" if ($OldSize != (-s $build_log_err) && !$ReallyQuiet); - PrintErrorMessage("'abld build $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8); - return 0 if (!$OK); # ABLD always returns ok :( grr + PrintErrorMessage("'abld BUILD $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8); + return 0 if (!$OK); # ABLD always returns ok :( grr PrintMessage("Done.") if (!$ReallyQuiet); # do we have an override suffix for the package name? @@ -491,7 +650,7 @@ sub BuildVariation() if (-e "$output_dir/$Package") { $PackagesCreated++; - + if ($TargetIntermediatePath ne '' && $TargetIntermediatePath =~ /\\EPOC32\\BUILD\\/i) # make really sure it's a valid path! { #PrintMessage("Cleaning $TargetIntermediatePath"); @@ -514,7 +673,7 @@ sub UploadVariation() use Net::FTP; my $newerr; - + PrintMessage("Connecting to FTP $FTP_Host") if (!$ReallyQuiet); $ftp = Net::FTP->new($FTP_Host,Timeout=>240) or $newerr=1; @@ -529,7 +688,7 @@ sub UploadVariation() { PrintMessage("Changing to dir $FTP_Dir"); $ftp->cwd($FTP_Dir) or $newerr=1; - + if ($newerr) { PrintErrorMessage("Changing to dir $FTP_Dir! Aborting!"); @@ -541,20 +700,20 @@ sub UploadVariation() # leave this for possible auto-deletion of old files? # @files = $ftp->dir or $newerr=1; # push @ERRORS, "Can't get file list $!\n" if $newerr; -# print "Got file list\n"; +# print "Got file list\n"; # foreach(@files) { # print "$_\n"; # } - + PrintMessage("Uploading $Package (".(-s "$output_dir/$Package")." bytes)"); - + $ftp->binary; $ftp->put("$output_dir/$Package") or $newerr=1; PrintErrorMessage("Uploading package! Aborting!") if $newerr; $PackagesUploaded++ if (!$newerr); - } + } - $ftp->quit; + $ftp->quit; } } @@ -574,6 +733,7 @@ sub PrepSdkPaths() # set env stuff PrintMessage("Prepending $SDK specific paths to %PATH%") if (!$ReallyQuiet); + $AdditionalPathEntries .= "$SDK_ToolchainDirs{$SDK};" if ($SDK_ToolchainDirs{$SDK} ne ''); $AdditionalPathEntries .= "$ECompXL_BinDir;" if ($ECompXL_BinDir ne '' && $SDK eq 'UIQ2'); $AdditionalPathEntries .= "$EPOC32RT\\include;"; $AdditionalPathEntries .= "$EPOC32RT\\tools;"; @@ -594,7 +754,7 @@ sub CleanupPath() { $path =~ s/\"\Q$ECompXL_BinDir\E\";//g; } - + while( ($SDK, $RootDir) = each(%SDK_RootDirs) ) { if ($SDK_RootDirs{$SDK} ne '') @@ -602,8 +762,8 @@ sub CleanupPath() my $path_component = "\"".$SDK_RootDirs{$SDK}."\\epoc32\\"; $path =~ s/\Q$path_component\E.*?\";//g; } - } - + } + return $path; } @@ -634,4 +794,5 @@ sub PrintMessage() } ################################################################################################################## + diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl index 0b334c08ea..1e5e4dc0c8 100644 --- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl +++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl @@ -1,75 +1,119 @@ ################################################################################################################## - # you can use these below for speed & clarity or override with custom settings - $DefaultTopMacros = " - MACRO USE_ZLIB // LIB:zlib.lib - MACRO USE_MAD // LIB:libmad.lib - MACRO USE_TREMOR // LIB:libtremor.lib - "; - - $DefaultBottomMacros = " - MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib - MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib - "; + @WorkingEngines = qw( + scumm agos sky queen gob saga + kyra lure agi + ); + @TestingEngines = qw( + cine cruise touche parallaction + drascula igor made m4 + ); + @BrokenEngines = qw( + sword1 + sword2 + ); + + @EnablableEngines = (@WorkingEngines, @TestingEngines); + + @EnablableSubEngines = qw( + scumm_7_8 + he + ); + + %UseableFeatures = ( + 'zlib' => 'zlib.lib', + 'mad' => 'libmad.lib', + 'tremor' => 'libtremor.lib', + 'mpeg2' => 'libmpeg2.lib' + ); + + # these are normally enabled for each variation + $DefaultFeatures = qw(zlib tremor); + #$DefaultFeatures = qw(zlib mad tremor); + + # you can use these below for speed & clarity or override with custom settings + $DefaultTopMacros = " + MACRO USE_ZLIB // LIB:zlib.lib + //MACRO USE_MAD // LIB:libmad.lib + MACRO USE_TREMOR // LIB:libtremor.lib + "; + + $DefaultBottomMacros = " + MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib + MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib + "; + +################################################################################################################## ## - ## General system information: + ## General system information, based on $COMPUTERNAME, so this way + ## you can use the same LocalSettings.pl file on multiple machines! ## +################################################################################################################## - # this way you can use the same LocalSettings.pl file on multiple machines! - if ($ENV{'COMPUTERNAME'} eq "BRAAMBOOK") + if ($ENV{'COMPUTERNAME'} eq "PC-21") ######################################################################### { # might use this string for file/dir naming in the future :) $Producer = "SumthinWicked"; $RedirectSTDERR = 0; - $HaltOnError = 1; + $HaltOnError = 0; $SkipExistingPackages = 0; $ReallyQuiet = 0; - + $DevBase = "C:\\S"; + # specify an optional FTP server to upload to after each Build+Package (can leave empty) - #$FTP_Host = "host.domain"; - #$FTP_User = "test"; - #$FTP_Pass = "test"; - #$FTP_Dir = "test"; - #$FTP_Host = "host.com"; $FTP_User = "something"; $FTP_Pass = "password"; $FTP_Dir = "cvsbuilds"; - + + # What Platform SDKs are installed on this machine? # possible SDKs: ("UIQ2", UIQ3", "S60v1", "S60v2", "S60v3", "S80", "S90") # Note1: the \epoc32 directory needs to be in these rootdirs # Note2: these paths do NOT end in a backslash! - $SDK_RootDirs{'UIQ2'} = "C:\\S\\UIQ_21"; - $SDK_RootDirs{'S60v1'} = "C:\\S\\S60v1"; - $SDK_RootDirs{'S60v2'} = "C:\\S\\S60v2"; - $SDK_RootDirs{'S80'} = "C:\\S\\S80"; - $SDK_RootDirs{'S90'} = "C:\\S\\S90"; - $ECompXL_BinDir = "C:\\S\\ECompXL\\bin"; # only needed for UIQ - # you need to specify each of the SDKs used in the blocks below! + # $SDK_RootDirs{'UIQ2'} = "$DevBase\\UIQ_21"; + $SDK_RootDirs{'UIQ3'} = "$DevBase\\UIQ3"; + # $SDK_RootDirs{'S60v1'} = "$DevBase\\S60v1"; + # $SDK_RootDirs{'S60v2'} = "$DevBase\\S60v2"; + $SDK_RootDirs{'S60v3'} = "$DevBase\\S60v3"; + # $SDK_RootDirs{'S80'} = "$DevBase\\S80"; + # $SDK_RootDirs{'S90'} = "$DevBase\\S90"; + + $SDK_ToolchainDirs{'S60v3'} = "$DevBase\\arm-symbianelf\\bin"; + $SDK_ToolchainDirs{'UIQ2'} = "$DevBase\\ECompXL\\bin"; # only needed for UIQ2/UIQ3 + $SDK_ToolchainDirs{'UIQ3'} = "$DevBase\\ECompXL\\bin"; # only needed for UIQ2/UIQ3 # these supporting libraries get built first, then all the Variations # Note: the string {'xxx.lib'} is used in checking in build success: so needs to be accurate! if (0) # so we can turn them on/off easily { - #$SDK_LibraryDirs{'ALL'}{'zlib.lib'} = "C:\\S\\zlib-1.2.2\\epoc"; - #$SDK_LibraryDirs{'ALL'}{'libmad.lib'} = "C:\\S\\libmad-0.15.1b\\group"; - #$SDK_LibraryDirs{'ALL'}{'libtremor.lib'}= "C:\\S\\tremor\\epoc"; - $SDK_LibraryDirs{'UIQ2'}{'esdl.lib'} = $SDK_LibraryDirs{'UIQ3'}{'esdl.lib'} = "C:\\S\\ESDL\\epoc\\UIQ"; - #$SDK_LibraryDirs{'S60v1'}{'esdl.lib'} = $SDK_LibraryDirs{'S60v2'}{'esdl.lib'} = $SDK_LibraryDirs{'S60v3'}{'esdl.lib'} = "C:\\S\\ESDL\\epoc\\S60"; - #$SDK_LibraryDirs{'S80'}{'esdl.lib'} = "C:\\S\\ESDL\\epoc\\S80"; - #$SDK_LibraryDirs{'S90'}{'esdl.lib'} = "C:\\S\\ESDL\\epoc\\S90"; - #$SDK_LibraryDirs{'ALL'}{'libmpeg2.lib'} = "C:\\S\\mpeg2dec-0.4.0\\epoc"; + ## Standard libraries + $SDK_LibraryDirs{'ALL'}{'zlib.lib'} = "$DevBase\\zlib-1.2.2\\epoc"; + #$SDK_LibraryDirs{'ALL'}{'libmad.lib'} = "$DevBase\\libmad-0.15.1b\\group"; + $SDK_LibraryDirs{'ALL'}{'libtremor.lib'}= "$DevBase\\tremor\\epoc"; + + ## SDL 1.2.12 / AnotherGuest / Symbian version + my $SdlBase = "$DevBase\\SDL-1.2.12-ag\\Symbian"; + #$SDK_LibraryDirs{'S60v1'}{'esdl.lib'} = "$SdlBase\\S60"; // unsupported? + #$SDK_LibraryDirs{'S60v2'}{'esdl.lib'} = "$SdlBase\\S60v2"; + $SDK_LibraryDirs{'S60v3'}{'esdl.lib'} = "$SdlBase\\S60v3"; + #$SDK_LibraryDirs{'S80'}{'esdl.lib'} = "$SdlBase\\S80"; + #$SDK_LibraryDirs{'S90'}{'esdl.lib'} = "$SdlBase\\S90"; + #$SDK_LibraryDirs{'UIQ2'}{'esdl.lib'} = "$SdlBase\\UIQ2" + #$SDK_LibraryDirs{'UIQ3'}{'esdl.lib'} = "$SdlBase\\UIQ3"; + + ## HardlySupported(TM) :P + #$SDK_LibraryDirs{'ALL'}{'libmpeg2.lib'} = "$DevBase\\mpeg2dec-0.4.0\\epoc"; } + + # now you can add $VariationSets only built on this PC below this line :) + + #$VariationSets{'ALL'}{'scumm'} = "$DefaultFeatures scumm scumm_7_8 he"; + #$VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines"; - # backup :P - #Path=C:\Progra~1\Active\Python24\.;C:\Program Files\Active\Tcl\bin;C:\Progra~1\Active\Perl\bin\;C:\WINDOWS\system32;C:\W - #INDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\ATI Technologies\ATI Control Panel;C:\Program Files\GNU\cvsnt;C:\Progra - #m Files\WinSCP3\;"C:\Program Files\Common Files\Microsoft Shared\VSA\8.0\VsaEnv\";"c:\Program Files\Microsoft Visual Stu - #dio 8\VC\bin";"C:\Program Files\UltraEdit-32" } - elsif ($ENV{'COMPUTERNAME'} eq "TSSLND0106") + elsif ($ENV{'COMPUTERNAME'} eq "TSSLND0106") ################################################################# { $Producer = "AnotherGuest"; $RedirectSTDERR = 1; @@ -90,7 +134,7 @@ #$SDK_RootDirs{'S80'}= "C:\\S80"; #$SDK_RootDirs{'S90'}= "C:\\S90"; $ECompXL_BinDir= "C:\\ECompXL\\"; -if (0) # so we can turn them on/off easily + if (0) # so we can turn them on/off easily { # $SDK_LibraryDirs{'ALL'}{'zlib.lib'} = "C:\\S\\zlib-1.2.2\\epoc"; # $SDK_LibraryDirs{'ALL'}{'libmad.lib'} = "C:\\S\\libmad-0.15.1b\\group"; @@ -101,9 +145,11 @@ if (0) # so we can turn them on/off easily # $SDK_LibraryDirs{'S90'}{'esdl.lib'} = "C:\\S\\ESDL\\epoc\\S90"; #$SDK_LibraryDirs{'ALL'}{'libmpeg2.lib'} = "C:\\S\\mpeg2dec-0.4.0\\epoc"; } - # now you can add $SDK_Variations only built on this PC here :) + + # now you can add $VariationSets only built on this PC below this line :) + } -elsif ($ENV{'COMPUTERNAME'} eq "BIGMACHINE") + elsif ($ENV{'COMPUTERNAME'} eq "BIGMACHINE") ################################################################# { $Producer = "AnotherGuest"; $RedirectSTDERR = 1; @@ -116,15 +162,15 @@ elsif ($ENV{'COMPUTERNAME'} eq "BIGMACHINE") #$FTP_Pass = "password"; #$FTP_Dir = "cvsbuilds"; - #$SDK_RootDirs{'UIQ2'}= "E:\\UIQ2"; - $SDK_RootDirs{'UIQ3'}= "E:\\UIQ3"; - #$SDK_RootDirs{'S60v1'}= "E:\\S60v1"; - #$SDK_RootDirs{'S60v2'}= "E:\\S60v2"; - $SDK_RootDirs{'S60v3'}= "E:\\S60v3"; - #$SDK_RootDirs{'S80'}= "E:\\S80"; - #$SDK_RootDirs{'S90'}= "E:\\S90"; - $ECompXL_BinDir= "E:\\ECompXL\\"; -if (0) # so we can turn them on/off easily + #$SDK_RootDirs{'UIQ2'}= "D:\\UIQ2"; + $SDK_RootDirs{'UIQ3'}= "D:\\UIQ3"; + #$SDK_RootDirs{'S60v1'}= "D:\\S60v1"; + #$SDK_RootDirs{'S60v2'}= "D:\\S60v2"; + $SDK_RootDirs{'S60v3'}= "D:\\S60v3"; + #$SDK_RootDirs{'S80'}= "D:\\S80"; + #$SDK_RootDirs{'S90'}= "D:\\S90"; + $ECompXL_BinDir= "D:\\ECompXL\\"; + if (0) # so we can turn them on/off easily { # $SDK_LibraryDirs{'ALL'}{'zlib.lib'} = "C:\\S\\zlib-1.2.2\\epoc"; # $SDK_LibraryDirs{'ALL'}{'libmad.lib'} = "C:\\S\\libmad-0.15.1b\\group"; @@ -137,28 +183,32 @@ if (0) # so we can turn them on/off easily $SDK_LibraryDirs{'UIQ3'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\UIQ\\UIQ3"; #$SDK_LibraryDirs{'ALL'}{'libmpeg2.lib'} = "C:\\S\\mpeg2dec-0.4.0\\epoc"; } - # now you can add $SDK_Variations only built on this PC here :) + + # now you can add $VariationSets only built on this PC below this line :) + } - else + else ######################################################################################################### { print "ERROR: Computer name ".$ENV{'COMPUTERNAME'}." not recognized! Plz edit _LocalSettings.pl!"; exit 1; } +################################################################################################################## ## ## Variation defines: ## +################################################################################################################## # second hash index = literal string used in .sis file created. # empty string also removes the trailing '_'. Some 051101 examples: - # $SDK_Variations{'UIQ2'}{''} would produce: + # $VariationSets{'UIQ2'}{''} would produce: # scummvm-051101-SymbianUIQ2.sis - # $SDK_Variations{'S60v2'}{'agos'} would produce: + # $VariationSets{'S60v2'}{'agos'} would produce: # scummvm-051101-SymbianS60v2_agos.sis - # $SDK_Variations{'ALL'}{'queen'} with all $SDK_RootDirs defined would produce: + # $VariationSets{'ALL'}{'queen'} with all $SDK_RootDirs defined would produce: # scummvm-051101-SymbianUIQ2_queen.sis # scummvm-051101-SymbianUIQ3_queen.sis # scummvm-051101-SymbianS60v1_queen.sis @@ -167,361 +217,47 @@ if (0) # so we can turn them on/off easily # scummvm-051101-SymbianS80_queen.sis # scummvm-051101-SymbianS90_queen.sis - #$SDK_Variations{'ALL'}{'test'} = "$DefaultTopMacro - # //MACRO USE_TREMOR // LIB:libtremor.lib - # //MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - # //MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - # //MACRO DISABLE_SKY // LIB:scummvm_sky.lib - # //MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - # //MACRO DISABLE_GOB // LIB:scummvm_gob.lib - # //MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - # //MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - #$DefaultBottomMacros"; - #$SDK_Variations{'S60v1'}{'test'} = $SDK_Variations{'UIQ2'}{'test'}; - -if (1) # all regular combo's -{ - # the first one includes all SDKs & release-ready engines - - $SDK_Variations{'ALL'}{'all'} = "$DefaultTopMacros - //MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - //MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - //MACRO DISABLE_SKY // LIB:scummvm_sky.lib - //MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - //MACRO DISABLE_GOB // LIB:scummvm_gob.lib - //MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - //MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - //MACRO DISABLE_AGI // LIB:scummvm_agi.lib - //MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - //MACRO DISABLE_CINE // LIB:scummvm_cine.lib - //MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - //MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib + # NOTE: empty $VariationSets{''} string instead of 'ALL' = easy way to disable pkg! - //MACRO DISABLE_LURE // LIB:scummvm_lure.lib - //MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - //MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - //MACRO DISABLE_MADE // LIB:scummvm_made.lib - //MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - # now one for each ready-for-release engine - - $SDK_Variations{'ALL'}{'scumm'} = "$DefaultTopMacros - //MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'agos'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - //MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'sky'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - //MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'queen'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - //MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'gob'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - //MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'saga'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - //MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'kyra'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - //MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - # below here you could specify weird & experimental combinations, non-ready engines - - $SDK_Variations{'ALL'}{'saga_mini'} = " - //MACRO USE_ZLIB // LIB:zlib.lib - //MACRO USE_MAD // LIB:libmad.lib - //MACRO USE_TREMOR // LIB:libtremor.lib - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - //MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - -# $SDK_Variations{'ALL'}{'scumm_no78he'} = " -# MACRO USE_ZLIB // LIB:zlib.lib -# MACRO USE_MAD // LIB:libmad.lib -# //MACRO USE_TREMOR // LIB:libtremor.lib -# MACRO DISABLE_SCUMM_7_8 -# MACRO DISABLE_SCUMM_HE -# //MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib -# MACRO DISABLE_AGOS // LIB:scummvm_agos.lib -# MACRO DISABLE_SKY // LIB:scummvm_sky.lib -# MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib -# MACRO DISABLE_GOB // LIB:scummvm_gob.lib -# MACRO DISABLE_SAGA // LIB:scummvm_saga.lib -# MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib -# MACRO DISABLE_AGI // LIB:scummvm_agi.lib -# MACRO DISABLE_LURE // LIB:scummvm_lure.lib -# MACRO DISABLE_CINE // LIB:scummvm_cine.lib -# MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib -# $DefaultBottomMacros"; - -# $SDK_Variations{'ALL'}{'all_vorbis'} = " -# MACRO USE_ZLIB // LIB:zlib.lib -# MACRO USE_MAD // LIB:libmad.lib -# MACRO USE_TREMOR // LIB:libtremor.lib -# -# //MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib -# //MACRO DISABLE_AGOS // LIB:scummvm_agos.lib -# //MACRO DISABLE_SKY // LIB:scummvm_sky.lib -# //MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib -# //MACRO DISABLE_GOB // LIB:scummvm_gob.lib -# //MACRO DISABLE_SAGA // LIB:scummvm_saga.lib -# //MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib -# $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'lure'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - //MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_agi.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - # empty $SDK_Variations{''} string instead of 'ALL' = package disabled - $SDK_Variations{'ALL'}{'test_cine'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - //MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - $SDK_Variations{'ALL'}{'agi'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - //MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - $DefaultBottomMacros"; - - - $SDK_Variations{'ALL'}{'test_touche'} = "$DefaultTopMacros - MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - MACRO DISABLE_SKY // LIB:scummvm_sky.lib - MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - MACRO DISABLE_GOB // LIB:scummvm_gob.lib - MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - MACRO DISABLE_LURE // LIB:scummvm_lure.lib - MACRO DISABLE_CINE // LIB:scummvm_cine.lib - MACRO DISABLE_AGI // LIB:scummvm_agi.lib - MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - //MACRO DISABLE_TOUCHE // LIB:scummvm_touche.lib - MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib - MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib - MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib - MACRO DISABLE_IGOR // LIB:scummvm_igor.lib - MACRO DISABLE_MADE // LIB:scummvm_made.lib - MACRO DISABLE_M4 // LIB:scummvm_m4.lib - "; -} - -# -# $SDK_Variations{'S60v2'}{'test_sword'} = "$DefaultTopMacros -# MACRO USE_MPEG2 // LIB:libmpeg2.lib -# MACRO USE_TREMOR // LIB:libtremor.lib -# MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib -# MACRO DISABLE_AGOS // LIB:scummvm_agos.lib -# MACRO DISABLE_SKY // LIB:scummvm_sky.lib -# MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib -# MACRO DISABLE_GOB // LIB:scummvm_gob.lib -# MACRO DISABLE_SAGA // LIB:scummvm_saga.lib -# MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib -# MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib -# MACRO DISABLE_CINE // LIB:scummvm_cine.lib -# MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib -# //MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib -# //MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib -# "; -# $SDK_Variations{'UIQ2'}{'test_sword'} = $SDK_Variations{'S60v2'}{'test_sword'} -# + if (1) # all regular combo's + { + # the first one includes all SDKs & release-ready engines + + $VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines"; + + # now one for each ready-for-release engine + + foreach (@WorkingEngines) + { + $VariationSets{'ALL'}{$_} = "$DefaultFeatures $_"; + } + # for scumm, we need to add 2 features: + $VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he"; + + # now one for each not-ready-for-release-or-testing engine + + foreach (@TestingEngines) + { + $VariationSets{'ALL'}{"test_$_"} = "$DefaultFeatures $_"; + } + + # below here you could specify weird & experimental combinations, non-ready engines + + # a small version of the saga engine, because it is so big (no tremor,mad,zlib) + $VariationSets{'ALL'}{'saga_mini'} = "saga"; + + # a smaller version of scumm without support for v7, v8 and HE games + $VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm"; + + # maybe you feel lucky and want to test the sword engines? :P + #$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2"; + #$VariationSets{'UIQ2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2"; + + # for mega-fast-testing only plz! Warning: contains to engines! + #$VariationSets{'ALL'}{'fast_empty'} = ""; + + } # end quick-n-fast if (1|0) -# for mega-fast-testing only plz! -# $SDK_Variations{'ALL'}{'(fast_empty)'} = " -# //MACRO USE_ZLIB // LIB:zlib.lib -# //MACRO USE_MAD // LIB:libmad.lib -# //MACRO USE_TREMOR // LIB:libtremor.lib -# MACRO USE_UIQ_SE_VIBRA // LIB:vibration.lib -# MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib -# MACRO DISABLE_AGOS // LIB:scummvm_agos.lib -# MACRO DISABLE_SKY // LIB:scummvm_sky.lib -# //MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib -# MACRO DISABLE_GOB // LIB:scummvm_gob.lib -# MACRO DISABLE_SAGA // LIB:scummvm_saga.lib -# $DefaultBottomMacros"; ################################################################################################################## diff --git a/backends/platform/symbian/README b/backends/platform/symbian/README index 0f9df338c3..8ab729a4d0 100644 --- a/backends/platform/symbian/README +++ b/backends/platform/symbian/README @@ -38,6 +38,7 @@ Building ScummVM Lets just say the framework needs quite some time to set up and takes a while to get used to. If you choose to continue you will need the following items: + - UIQ 3.0 SDK (To build for UIQ3 devices) - UIQ 2.1 SDK (To build for UIQ2 devices); http://www.symbian.com/developer/sdks_uiq.asp @@ -58,14 +59,14 @@ Building ScummVM - zlib, a massively spiffy yet delicately unobtrusive compression library http://www.zlib.net/ - - These are probably too heavy-duty for your phone: + - latest version of active perl (included with Symbian SDK does not work with the build scripts) - libogg, the free media file container format http://www.xiph.org/ogg/ - + - libvorbis, the free audio codec http://www.vorbis.com/ + These are probably too heavy-duty for your phone: - flac, the Free Lossless Audio Codec http://flac.sourceforge.net/ diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in index ff11657b34..3fea916e43 100644 --- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in +++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in @@ -29,7 +29,7 @@ TARGET ScummVM.exe TARGETPATH sys\bin TARGETTYPE exe -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char UID 0x100039ce 0xA0000657 @@ -81,13 +81,6 @@ ALWAYS_BUILD_AS_ARM STATICLIBRARY esdl.lib -#if !defined(WINS) -staticlibrary rate_arm_asm.o -staticlibrary proc3arm.o -staticlibrary codec47ARM.o -staticlibrary gfxARM.o -#endif - // *** Include paths USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\engines diff --git a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in index a1ac965148..0013d061ca 100644 --- a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in +++ b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in @@ -30,7 +30,7 @@ TARGET ScummVM.exe TARGETPATH sys\bin TARGETTYPE exe -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char UID 0x100039ce 0xA0000657 @@ -82,13 +82,6 @@ ALWAYS_BUILD_AS_ARM STATICLIBRARY esdl.lib -#if !defined(WINS) -staticlibrary rate_arm_asm.o -staticlibrary proc3arm.o -staticlibrary codec47ARM.o -staticlibrary gfxARM.o -#endif - // *** Include paths USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\engines diff --git a/backends/platform/symbian/mmp/scummvm_agi.mmp.in b/backends/platform/symbian/mmp/scummvm_agi.mmp.in index 8432968f32..04cf068133 100644 --- a/backends/platform/symbian/mmp/scummvm_agi.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_agi.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_agi.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_agos.mmp.in b/backends/platform/symbian/mmp/scummvm_agos.mmp.in index 528349c176..d03a30d88b 100644 --- a/backends/platform/symbian/mmp/scummvm_agos.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_agos.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_agos.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in index 761d4867e7..d1c8878d4b 100644 --- a/backends/platform/symbian/mmp/scummvm_base.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in @@ -30,36 +30,15 @@ TARGET scummvm_base.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM // Note: the LIB:*.lib statements are used by AdaptAllMMPs.pl, so don't remove them! //START_AUTO_MACROS_MASTER// // empty base file, will be updated by Perl build scripts - - // list of possible MACROs: (will be replaced when generating scummvm_base.mmp) - //MACRO USE_ZLIB // LIB:zlib.lib - //MACRO USE_MAD // LIB:libmad.lib - //MACRO USE_TREMOR // LIB:libtremor.lib - //MACRO USE_UIQ_SE_VIBRA // LIB:vibration.lib - //MACRO DISABLE_SCUMM_7_8 - //MACRO DISABLE_SCUMM_HE - //MACRO DISABLE_SCUMM // LIB:scummvm_scumm.lib - //MACRO DISABLE_AGOS // LIB:scummvm_agos.lib - //MACRO DISABLE_SKY // LIB:scummvm_sky.lib - //MACRO DISABLE_QUEEN // LIB:scummvm_queen.lib - //MACRO DISABLE_GOB // LIB:scummvm_gob.lib - //MACRO DISABLE_SAGA // LIB:scummvm_saga.lib - //MACRO DISABLE_KYRA // LIB:scummvm_kyra.lib - //MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib - //MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib - //MACRO DISABLE_LURE // LIB:scummvm_lure.lib - //MACRO DISABLE_CINE // LIB:scummvm_cine.lib - //MACRO DISABLE_AGI // LIB:scummvm_agi.lib - //MACRO DISABLE_PARALLACTION // LIB:scummvm_parallaction.lib - //MACRO DISABLE_CRUISE // LIB:scummvm_cruise.lib - //MACRO DISABLE_DRASCULA // LIB:scummvm_drascula.lib + // this file will be modified first, then from here all + // MACROs will be replicated to the other MPP files. //STOP_AUTO_MACROS_MASTER// @@ -77,6 +56,7 @@ SYSTEMINCLUDE ..\src // for portdefs.h // *** SOURCE files + SOURCEPATH ..\..\..\..\common //START_AUTO_OBJECTS_COMMON_// @@ -84,6 +64,7 @@ SOURCEPATH ..\..\..\..\common //STOP_AUTO_OBJECTS_COMMON_// + SOURCEPATH ..\..\..\..\graphics //START_AUTO_OBJECTS_GRAPHICS_// @@ -91,6 +72,7 @@ SOURCEPATH ..\..\..\..\graphics //STOP_AUTO_OBJECTS_GRAPHICS_// + SOURCEPATH ..\..\..\..\gui //START_AUTO_OBJECTS_GUI_// @@ -103,6 +85,7 @@ SOURCEPATH ..\..\..\..\gui //SOURCE KeysDialog.cpp //SOURCE Actions.cpp + SOURCEPATH ..\..\..\..\sound //START_AUTO_OBJECTS_SOUND_// @@ -110,16 +93,22 @@ SOURCEPATH ..\..\..\..\sound //STOP_AUTO_OBJECTS_SOUND_// #if defined (WINS) -SOURCE rate.cpp +SOURCE rate.cpp // WINS emulator version: add regular .cpp #else -SOURCE rate_arm.cpp +SOURCE rate_arm.cpp // ARM version: add ASM .cpp wrapper +SOURCE rate_arm_asm.s // ARM version: add ASM routines #endif -sourcepath ..\..\..\.. -source backends\events\default\default-events.cpp -source backends\timer\default\default-timer.cpp -source backends\saves\savefile.cpp -source backends\saves\default\default-saves.cpp -source backends\saves\compressed\compressed-saves.cpp -source engines\engine.cpp + + +// add a few files manually, since they are not parsed from modules.mk files +SOURCEPATH ..\..\..\.. +SOURCE backends\events\default\default-events.cpp +SOURCE backends\timer\default\default-timer.cpp +SOURCE backends\saves\savefile.cpp +SOURCE backends\saves\default\default-saves.cpp +SOURCE backends\saves\compressed\compressed-saves.cpp +SOURCE engines\engine.cpp + + // backend specific includes // backend specific includes diff --git a/backends/platform/symbian/mmp/scummvm_cine.mmp.in b/backends/platform/symbian/mmp/scummvm_cine.mmp.in index 052b62759b..cc355b0318 100644 --- a/backends/platform/symbian/mmp/scummvm_cine.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_cine.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_CINE.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in index ad363984c8..718f80a95b 100644 --- a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_cruise.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in index 4c9d614446..4979cc91a6 100644 --- a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_drascula.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_gob.mmp.in b/backends/platform/symbian/mmp/scummvm_gob.mmp.in index 734f3c686c..8522a937ab 100644 --- a/backends/platform/symbian/mmp/scummvm_gob.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_gob.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_gob.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in index 6c4e9a0a97..503a54ce1f 100644 --- a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_kyra.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_lure.mmp.in b/backends/platform/symbian/mmp/scummvm_lure.mmp.in index 6b3410e95f..24173c6a57 100644 --- a/backends/platform/symbian/mmp/scummvm_lure.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_lure.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_lure.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_m4.mmp.in b/backends/platform/symbian/mmp/scummvm_m4.mmp.in index 62a00143be..4429582bd7 100644 --- a/backends/platform/symbian/mmp/scummvm_m4.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_m4.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_m4.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_made.mmp.in b/backends/platform/symbian/mmp/scummvm_made.mmp.in index 7aac818f4e..cb69cbf115 100644 --- a/backends/platform/symbian/mmp/scummvm_made.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_made.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_made.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in index 910bb42ec9..4c117fba45 100644 --- a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_parallaction.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_queen.mmp.in b/backends/platform/symbian/mmp/scummvm_queen.mmp.in index 96b827a994..6bee237f77 100644 --- a/backends/platform/symbian/mmp/scummvm_queen.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_queen.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_queen.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_saga.mmp.in b/backends/platform/symbian/mmp/scummvm_saga.mmp.in index 9e8c658a8f..c040de250c 100644 --- a/backends/platform/symbian/mmp/scummvm_saga.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_saga.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_saga.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in index 39490cfd29..7eecfd3ff6 100644 --- a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_scumm.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// @@ -43,23 +43,34 @@ ALWAYS_BUILD_AS_ARM SOURCEPATH ..\..\..\..\engines\scumm + //START_AUTO_OBJECTS_SCUMM_// // empty base file, will be updated by Perl build scripts //STOP_AUTO_OBJECTS_SCUMM_// +#if !defined (WINS) +SOURCE gfxARM.s // ARM version: add ASM routines +SOURCE proc3ARM.s // ARM version: add ASM routines +#endif + -//START_AUTO_OBJECTS_SCUMM_DISABLE_SCUMM_7_8// +//START_AUTO_OBJECTS_SCUMM_ENABLE_SCUMM_7_8// // empty base file, will be updated by Perl build scripts -//STOP_AUTO_OBJECTS_SCUMM_DISABLE_SCUMM_7_8// +//STOP_AUTO_OBJECTS_SCUMM_ENABLE_SCUMM_7_8// +#if !defined (WINS) +SOURCE smush/codec47ARM.s // ARM version: add ASM routines +#endif -//START_AUTO_OBJECTS_SCUMM_DISABLE_HE// + +//START_AUTO_OBJECTS_SCUMM_ENABLE_HE// // empty base file, will be updated by Perl build scripts -//STOP_AUTO_OBJECTS_SCUMM_DISABLE_HE// +//STOP_AUTO_OBJECTS_SCUMM_ENABLE_HE// + // *** Include paths diff --git a/backends/platform/symbian/mmp/scummvm_sky.mmp.in b/backends/platform/symbian/mmp/scummvm_sky.mmp.in index e359803194..9ae57aa2b6 100644 --- a/backends/platform/symbian/mmp/scummvm_sky.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sky.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_sky.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in index 9bc97919c5..ecf71c2d30 100644 --- a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_sword1.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in index 4d25a41e89..91029b1f8d 100644 --- a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_sword2.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/mmp/scummvm_touche.mmp.in b/backends/platform/symbian/mmp/scummvm_touche.mmp.in index 9ea7636af5..3b8a7e6105 100644 --- a/backends/platform/symbian/mmp/scummvm_touche.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_touche.mmp.in @@ -30,7 +30,7 @@ TARGET scummvm_touche.lib TARGETTYPE lib OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings -OPTION GCCE -Wno-multichar -Wno-reorder -fsigned-char +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char ALWAYS_BUILD_AS_ARM //START_AUTO_MACROS_SLAVE// diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index d3e92731db..dfeb24d825 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -173,11 +173,8 @@ void OSystem_SDL_Symbian::quit() { OSystem_SDL::quit(); } -bool OSystem_SDL_Symbian::setSoundCallback(SoundProc proc, void *param) { +void OSystem_SDL_Symbian::setupMixer() { - // First save the proc and param - _sound_proc_param = param; - _sound_proc = proc; SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -207,48 +204,53 @@ bool OSystem_SDL_Symbian::setSoundCallback(SoundProc proc, void *param) { desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = (uint16)samples; -#ifdef S60 desired.callback = symbianMixCallback; desired.userdata = this; -#else - desired.callback = proc; - desired.userdata = param; -#endif + + // Create the mixer instance + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; - } - // Note: This should be the obtained output rate, but it seems that at - // least on some platforms SDL will lie and claim it did get the rate - // even if it didn't. Probably only happens for "weird" rates, though. - _samplesPerSec = obtained.freq; - _channels = obtained.channels; - - // Need to create mixbuffer for stereo mix to downmix - if (_channels != 2) { - _stereo_mix_buffer = new byte [obtained.size*2];//*2 for stereo values + _samplesPerSec = 0; + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + _channels = obtained.channels; + + // Need to create mixbuffer for stereo mix to downmix + if (_channels != 2) { + _stereo_mix_buffer = new byte [obtained.size*2];//*2 for stereo values + } + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_samplesPerSec); + _mixer->setReady(true); + SDL_PauseAudio(0); } - - SDL_PauseAudio(0); - return true; } /** * The mixer callback function, passed on to OSystem::setSoundCallback(). * This simply calls the mix() method. */ -void OSystem_SDL_Symbian::symbianMixCallback(void *s, byte *samples, int len) { - static_cast <OSystem_SDL_Symbian*>(s)->symbianMix(samples,len); -} +void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len) { + OSystem_SDL_Symbian *this_ = (OSystem_SDL_Symbian *)sys; + assert(this_); + if (!this_->_mixer) + return; -/** - * Actual mixing implementation - */ -void OSystem_SDL_Symbian::symbianMix(byte *samples, int len) { +#ifdef S60 // If not stereo then we need to downmix if (_channels != 2) { - _sound_proc(_sound_proc_param, _stereo_mix_buffer, len * 2); + this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2); + int16 *bitmixDst = (int16 *)samples; int16 *bitmixSrc = (int16 *)_stereo_mix_buffer; @@ -258,9 +260,12 @@ void OSystem_SDL_Symbian::symbianMix(byte *samples, int len) { bitmixSrc += 2; } } else - _sound_proc(_sound_proc_param, samples, len); +#else + this_->_mixer->mixCallback(samples, len); +#endif } + /** * This is an implementation by the remapKey function * @param SDL_Event to remap diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h index 77e42cd476..71d24f6286 100644 --- a/backends/platform/symbian/src/SymbianOS.h +++ b/backends/platform/symbian/src/SymbianOS.h @@ -58,7 +58,7 @@ public: // This function is overridden by the symbian port in order to provide MONO audio // downmix is done by supplying our own audiocallback // - virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend + virtual void setupMixer(); // overloaded by CE backend // Overloaded from SDL_Commmon void quit(); @@ -70,11 +70,6 @@ protected: // static void symbianMixCallback(void *s, byte *samples, int len); - // - // Actual mixing implementation - // - void symbianMix(byte *samples, int len); - virtual FilesystemFactory *getFilesystemFactory(); public: // vibration support @@ -121,8 +116,6 @@ protected: // Audio int _channels; - SoundProc _sound_proc; - void *_sound_proc_param; byte *_stereo_mix_buffer; // Used to handle joystick navi zones diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h index 2723c0bab0..06a4cf374c 100644 --- a/backends/platform/symbian/src/portdefs.h +++ b/backends/platform/symbian/src/portdefs.h @@ -35,8 +35,8 @@ #include <e32std.h> #include <math.h> -#define DISABLE_SCALERS // we only need 1x -#define DISABLE_HQ_SCALERS +//#define DISABLE_SCALERS // we only need 1x +//#define DISABLE_HQ_SCALERS #if defined(USE_TREMOR) && !defined(USE_VORBIS) #define USE_VORBIS // make sure this one is defined together with USE_TREMOR! diff --git a/backends/platform/wii/osystem.cpp b/backends/platform/wii/osystem.cpp index 2667ecb69d..9e708345c5 100644 --- a/backends/platform/wii/osystem.cpp +++ b/backends/platform/wii/osystem.cpp @@ -91,7 +91,7 @@ void OSystem_Wii::initBackend() { _startup_time = gettime(); _savefile = new DefaultSaveFileManager(); - _mixer = new Audio::Mixer(); + _mixer = new Audio::MixerImpl(this); _timer = new DefaultTimerManager(); initGfx(); diff --git a/backends/platform/wii/osystem.h b/backends/platform/wii/osystem.h index 2a168fd0b7..7fbc560b1a 100644 --- a/backends/platform/wii/osystem.h +++ b/backends/platform/wii/osystem.h @@ -31,7 +31,7 @@ #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" #include "graphics/surface.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include <gctypes.h> #include <gccore.h> @@ -96,7 +96,7 @@ private: protected: Common::SaveFileManager *_savefile; - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; DefaultTimerManager *_timer; public: @@ -159,7 +159,6 @@ public: virtual void deleteMutex(MutexRef mutex); typedef void (*SoundProc)(void *param, byte *buf, int len); - virtual int getOutputSampleRate() const; virtual void quit(); diff --git a/backends/platform/wii/osystem_sfx.cpp b/backends/platform/wii/osystem_sfx.cpp index 16b2f3b055..0a225e80c7 100644 --- a/backends/platform/wii/osystem_sfx.cpp +++ b/backends/platform/wii/osystem_sfx.cpp @@ -36,9 +36,6 @@ static bool sfx_thread_quit = false; static u8 sb = 0; static u8 *sound_buffer[2]; -static OSystem_Wii::SoundProc sound_proc = NULL; -static void *proc_param = NULL; - static void audio_switch_buffers() { AUDIO_StopDMA(); AUDIO_InitDMA((u32) sound_buffer[sb], SFX_THREAD_FRAG_SIZE); @@ -48,6 +45,7 @@ static void audio_switch_buffers() { } static void * sfx_thread_func(void *arg) { + Audio::MixerImpl *mixer = (Audio::MixerImpl *) arg; u8 next_sb; while (true) { @@ -57,7 +55,7 @@ static void * sfx_thread_func(void *arg) { break; next_sb = sb ^ 1; - sound_proc(proc_param, sound_buffer[next_sb], SFX_THREAD_FRAG_SIZE); + mixer->mixCallback(sound_buffer[next_sb], SFX_THREAD_FRAG_SIZE); DCFlushRange(sound_buffer[next_sb], SFX_THREAD_FRAG_SIZE); sb = next_sb; @@ -75,7 +73,7 @@ void OSystem_Wii::initSfx() { LWP_InitQueue(&sfx_queue); - s32 res = LWP_CreateThread(&sfx_thread, sfx_thread_func, NULL, sfx_stack, + s32 res = LWP_CreateThread(&sfx_thread, sfx_thread_func, _mixer, sfx_stack, SFX_THREAD_STACKSIZE, SFX_THREAD_PRIO); if (res) { @@ -95,9 +93,7 @@ void OSystem_Wii::initSfx() { DCFlushRange(sound_buffer[0], SFX_THREAD_FRAG_SIZE); DCFlushRange(sound_buffer[1], SFX_THREAD_FRAG_SIZE); - sound_proc = Audio::Mixer::mixCallback; - proc_param = _mixer; - + _mixer->setOutputRate(48000); _mixer->setReady(true); AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); @@ -127,7 +123,3 @@ void OSystem_Wii::deinitSfx() { } } -int OSystem_Wii::getOutputSampleRate() const { - return 48000; -} - diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile index 734bf82eaa..176971067e 100644 --- a/backends/platform/wince/Makefile +++ b/backends/platform/wince/Makefile @@ -19,6 +19,8 @@ ## Enable whichever engines you want here ENABLE_SCUMM = STATIC_PLUGIN +ENABLE_SCUMM_7_8 = 1 +ENABLE_HE = 1 ENABLE_SKY = STATIC_PLUGIN ENABLE_QUEEN = STATIC_PLUGIN ENABLE_GOB = STATIC_PLUGIN @@ -163,7 +165,8 @@ endif EXECUTABLE = scummvm.exe CXXFLAGS := $(CFLAGS) OBJS := -MODULE_DIRS += . +MODULE_DIRS += ./ +DEPDIR = .deps OBJS += CEActionsPocket.o CEDevice.o CEScaler.o \ CEActionsSmartphone.o CELauncherDialog.o wince-sdl.o diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 8cf5fac279..3f16b4fdd1 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -35,7 +35,7 @@ #include "base/main.h" #include "base/plugins.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "sound/fmopl.h" #include "backends/timer/default/default-timer.h" @@ -94,7 +94,6 @@ static char stdout_fname[MAX_PATH], stderr_fname[MAX_PATH]; // Static member inits typedef void (*SoundProc)(void *param, byte *buf, int len); bool OSystem_WINCE3::_soundMaster = true; -SoundProc OSystem_WINCE3::_originalSoundProc = NULL; bool _isSmartphone = false; bool _hasSmartphoneResolution = false; @@ -403,9 +402,8 @@ void OSystem_WINCE3::initBackend() { // Instantiate our own sound mixer // mixer init is postponed until a game engine is selected. - if (_mixer == 0) { - _mixer = new Audio::Mixer(); - } + if (_mixer == 0) + _mixer = new Audio::MixerImpl(this); // Create the timer. CE SDL does not support multiple timers (SDL_AddTimer). // We work around this by using the SetTimer function, since we only use @@ -770,7 +768,7 @@ void OSystem_WINCE3::create_toolbar() { _toolbarHandler.setVisible(false); } -bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) { +void OSystem_WINCE3::setupMixer() { SDL_AudioSpec desired; int thread_priority; @@ -779,18 +777,20 @@ bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) { memset(&desired, 0, sizeof(desired)); - _originalSoundProc = proc; desired.freq = _sampleRate; desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = 128; desired.callback = private_sound_proc; - desired.userdata = param; + desired.userdata = this; + + // Create the mixer instance + if (_mixer == 0) + _mixer = new Audio::MixerImpl(this); // Add sound thread priority - if (!ConfMan.hasKey("sound_thread_priority")) { + if (!ConfMan.hasKey("sound_thread_priority")) thread_priority = THREAD_PRIORITY_NORMAL; - } else thread_priority = ConfMan.getInt("sound_thread_priority"); @@ -799,16 +799,26 @@ bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) { SDL_CloseAudio(); if (SDL_OpenAudio(&desired, NULL) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; - } - else + _mixer->setReady(false); + + } else { debug(1, "Sound opened OK, mixing at %d Hz", _sampleRate); - SDL_PauseAudio(0); - return true; + + // Re-create mixer to match the output rate + delete(_mixer); + _mixer = new Audio::MixerImpl(this); + _mixer->setOutputRate(_sampleRate); + _mixer->setReady(true); + SDL_PauseAudio(0); + } } void OSystem_WINCE3::private_sound_proc(void *param, byte *buf, int len) { - (*_originalSoundProc)(param, buf, len); + OSystem_WINCE3 *this_ = (OSystem_WINCE3 *)param; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(buf, len); if (!_soundMaster) memset(buf, 0, len); } @@ -838,7 +848,7 @@ bool OSystem_WINCE3::checkOggHighSampleRate() { } #endif -void OSystem_WINCE3::get_sample_rate() { +void OSystem_WINCE3::compute_sample_rate() { // Force at least medium quality FM synthesis for FOTAQ Common::String gameid(ConfMan.get("gameid")); if (gameid == "queen") { @@ -875,9 +885,8 @@ void OSystem_WINCE3::setWindowCaption(const char *caption) { //update_game_settings(); // finalize mixer init - get_sample_rate(); - bool result = setSoundCallback(Audio::Mixer::mixCallback, _mixer); - _mixer->setReady(result); + compute_sample_rate(); + setupMixer(); // handle the actual event OSystem_SDL::setWindowCaption(caption); @@ -1050,7 +1059,7 @@ void OSystem_WINCE3::update_game_settings() { } } - get_sample_rate(); + compute_sample_rate(); } void OSystem_WINCE3::initSize(uint w, uint h) { diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h index daa7e832f6..8853c156d8 100644 --- a/backends/platform/wince/wince-sdl.h +++ b/backends/platform/wince/wince-sdl.h @@ -82,7 +82,7 @@ public: // Overloaded from SDL_Commmon void quit(); // Overloaded from SDL_Commmon (master volume and sample rate subtleties) - bool setSoundCallback(SoundProc proc, void *param); + void setupMixer(); // Overloaded from OSystem //void engineInit(); void getTimeAndDate(struct tm &t) const; @@ -160,13 +160,12 @@ private: #endif static void private_sound_proc(void *param, byte *buf, int len); - static SoundProc _originalSoundProc; bool update_scalers(); void create_toolbar(); void update_game_settings(); void check_mappings(); - void get_sample_rate(); + void compute_sample_rate(); void retrieve_mouse_location(int &x, int &y); diff --git a/backends/platform/x11/module.mk b/backends/platform/x11/module.mk deleted file mode 100644 index 22015b53be..0000000000 --- a/backends/platform/x11/module.mk +++ /dev/null @@ -1,10 +0,0 @@ -MODULE := backends/platform/x11 - -MODULE_OBJS := \ - x11.o - -MODULE_DIRS += \ - backends/platform/x11/ - -# We don't use the rules.mk here on purpose -OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/platform/x11/x11.cpp b/backends/platform/x11/x11.cpp deleted file mode 100644 index 329d994335..0000000000 --- a/backends/platform/x11/x11.cpp +++ /dev/null @@ -1,1050 +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$ - * - */ - -/* The bare pure X11 port done by Lionel 'BBrox' Ulmer */ - -#include "common/scummsys.h" -#include "common/events.h" -#include "common/system.h" -#include "common/util.h" -#include "base/main.h" -#include "backends/platform/x11/x11.h" -#include "backends/plugins/posix/posix-provider.h" - -#include <stdio.h> -#include <assert.h> - -#include <sys/time.h> -#include <unistd.h> - -#include <sys/ipc.h> -#include <sys/shm.h> - -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/extensions/XShm.h> - -#ifdef __linux__ -#include <linux/soundcard.h> -#else -#include <sys/soundcard.h> -#endif - -#include <sched.h> -#include <pthread.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> - - -//#define SAMPLES_PER_SEC 11025 -#define SAMPLES_PER_SEC 22050 -//#define SAMPLES_PER_SEC 44100 - - -int main(int argc, char *argv[]) { - g_system = OSystem_X11::create(0, 0); - assert(g_system); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new POSIXPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! - return res; -} - -OSystem *OSystem_X11::create(int gfx_mode, bool full_screen) { - OSystem_X11 *syst = new OSystem_X11(); - return syst; -} - -OSystem_X11::OSystem_X11() { - /* Some members initialization */ - _fake_right_mouse = 0; - _report_presses = 1; - _current_shake_pos = 0; - _new_shake_pos = 0; - _palette_changed = false; - _num_of_dirty_rects = 0; - _overlay_visible = false; - _mouse_state_changed = true; - _mouse_visible = true; - _ms_buf = NULL; - _curMouseState.x = 0; - _curMouseState.y = 0; - _curMouseState.hot_x = 0; - _curMouseState.hot_y = 0; - _curMouseState.w = 0; - _curMouseState.h = 0; - _palette16 = 0; - _palette32 = 0; - _bytesPerPixel = 0; - _image = 0; - _local_fb = 0; - _local_fb_overlay = 0; -} - -OSystem_X11::~OSystem_X11() { - XFree(_image); - if (_palette16) - free(_palette16); - - if (_palette32) - free(_palette32); - - if (_ms_buf) - free(_ms_buf); - - free(_local_fb_overlay); - free(_local_fb); -} - -void OSystem_X11::initBackend() { - char buf[512]; - XWMHints *wm_hints; - XGCValues values; - XTextProperty window_name; - char *name = (char *)&buf; - /* For the_window title */ - sprintf(buf, "ScummVM"); - - _display = XOpenDisplay(NULL); - if (_display == NULL) { - error("Could not open display !\n"); - exit(1); - } - - if (XShmQueryExtension(_display)!=True) - error("No Shared Memory Extension present"); - - _screen = DefaultScreen(_display); - _depth = DefaultDepth(_display, _screen); - switch (_depth) { - case 16 : - _bytesPerPixel = 2; - break; - case 24 : - case 32 : - _bytesPerPixel = 4; - break; - } - - if (!_bytesPerPixel) - error("Your screen depth is %ibit. Values other than 16, 24 and 32bit are currently not supported", _depth); - - _window_width = 320; - _window_height = 200; - _scumm_x = 0; - _scumm_y = 0; - _window = XCreateSimpleWindow(_display, XRootWindow(_display, _screen), 0, 0, 320, 200, 0, 0, 0); - wm_hints = XAllocWMHints(); - if (wm_hints == NULL) { - error("Not enough memory to allocate Hints !\n"); - exit(1); - } - wm_hints->flags = InputHint | StateHint; - wm_hints->input = True; - wm_hints->initial_state = NormalState; - XStringListToTextProperty(&name, 1, &window_name); - XSetWMProperties(_display, _window, &window_name, &window_name, - NULL /* argv */ , 0 /* argc */ , NULL /* size hints */ , - wm_hints, NULL /* class hints */ ); - XFree(wm_hints); - - XSelectInput(_display, _window, - ExposureMask | KeyPressMask | KeyReleaseMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); - - values.foreground = BlackPixel(_display, _screen); - _black_gc = XCreateGC(_display, _window, GCForeground, &values); - - XMapWindow(_display, _window); - XFlush(_display); - - _fb_width = 0; - _fb_height = 0; - - if (!_palette16) - _palette16 = (uint16 *)calloc(256, sizeof(uint16)); - if (!_palette32 && _bytesPerPixel == 4) - _palette32 = (uint32 *)calloc(256, sizeof(uint32)); - - while (1) { - XEvent event; - XNextEvent(_display, &event); - switch (event.type) { - case Expose: - goto out_of_loop; - } - } -out_of_loop: - create_empty_cursor(); - - /* Initialize the timer routines */ - _timer_active = false; - - /* And finally start the local timer */ - gettimeofday(&_start_time, NULL); - - OSystem::initBackend(); -} - -#undef CAPTURE_SOUND -#define FRAG_SIZE 4096 - -static void *sound_and_music_thread(void *params) { - /* Init sound */ - int sound_fd, param, frag_size; - uint8 sound_buffer[FRAG_SIZE]; - OSystem::SoundProc sound_proc = ((THREAD_PARAM *)params)->sound_proc; - void *proc_param = ((THREAD_PARAM *)params)->param; - -#ifdef CAPTURE_SOUND - FILE *f = fopen("sound.raw", "wb"); -#endif - - sound_fd = open("/dev/dsp", O_WRONLY); - audio_buf_info info; - if (sound_fd < 0) { - warning("Error opening sound device!\n"); - return NULL; - } - param = 0; - frag_size = FRAG_SIZE /* audio fragment size */ ; - while (frag_size) { - frag_size >>= 1; - param++; - } - param--; - param |= /* audio_fragment_num */ 3 << 16; - if (ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, ¶m) != 0) { - warning("Error in the SNDCTL_DSP_SETFRAGMENT ioctl!\n"); - return NULL; - } - param = AFMT_S16_LE; - if (ioctl(sound_fd, SNDCTL_DSP_SETFMT, ¶m) == -1) { - warning("Error in the SNDCTL_DSP_SETFMT ioctl!\n"); - return NULL; - } - if (param != AFMT_S16_LE) { - warning("AFMT_S16_LE not supported!\n"); - return NULL; - } - param = 2; - if (ioctl(sound_fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { - warning("Error in the SNDCTL_DSP_CHANNELS ioctl!\n"); - return NULL; - } - if (param != 2) { - warning("Stereo mode not supported!\n"); - return NULL; - } - param = SAMPLES_PER_SEC; - if (ioctl(sound_fd, SNDCTL_DSP_SPEED, ¶m) == -1) { - warning("Error in the SNDCTL_DSP_SPEED ioctl!\n"); - return NULL; - } - if (param != SAMPLES_PER_SEC) { - warning("%d kHz not supported!\n", SAMPLES_PER_SEC); - return NULL; - } - if (ioctl(sound_fd, SNDCTL_DSP_GETOSPACE, &info) != 0) { - warning("SNDCTL_DSP_GETOSPACE"); - return NULL; - } - - sched_yield(); - while (1) { - uint8 *buf = (uint8 *)sound_buffer; - int size, written; - - sound_proc(proc_param, (byte *)sound_buffer, FRAG_SIZE); -#ifdef CAPTURE_SOUND - fwrite(buf, 2, FRAG_SIZE >> 1, f); - fflush(f); -#endif - size = FRAG_SIZE; - while (size > 0) { - written = write(sound_fd, buf, size); - buf += written; - size -= written; - } - } - - return NULL; -} - -/* Function used to hide the mouse cursor */ -void OSystem_X11::create_empty_cursor() { - XColor bg; - Pixmap pixmapBits; - Cursor cursor = None; - static const char data[] = { 0 }; - - bg.red = bg.green = bg.blue = 0x0000; - pixmapBits = XCreateBitmapFromData(_display, XRootWindow(_display, _screen), data, 1, 1); - if (pixmapBits) { - cursor = XCreatePixmapCursor(_display, pixmapBits, pixmapBits, &bg, &bg, 0, 0); - XFreePixmap(_display, pixmapBits); - } - XDefineCursor(_display, _window, cursor); -} - -bool OSystem_X11::hasFeature(Feature f) { - return false; -} - -void OSystem_X11::setFeatureState(Feature f, bool enable) { -} - -bool OSystem_X11::getFeatureState(Feature f) { - return false; -} - -const OSystem::GraphicsMode *OSystem_X11::getSupportedGraphicsModes() const { - static const OSystem::GraphicsMode mode = {"1x", "Normal mode", 0}; - return &mode; -} - -int OSystem_X11::getDefaultGraphicsMode() const { - return 0; -} - -bool OSystem_X11::setGraphicsMode(int mode) { - return (mode == 0); -} - -int OSystem_X11::getGraphicsMode() const { - return 0; -} - - -uint32 OSystem_X11::getMillis() { - struct timeval current_time; - gettimeofday(¤t_time, NULL); - return (uint32)(((current_time.tv_sec - _start_time.tv_sec) * 1000) + - ((current_time.tv_usec - _start_time.tv_usec) / 1000)); -} - -void OSystem_X11::initSize(uint w, uint h) { - //debug("initSize(%i, %i)", w, h); - static XShmSegmentInfo shminfo; - - if (((uint)_fb_width != w) || ((uint)_fb_height != w)) { - _fb_width = w; - _fb_height = h; - - /* We need to change the size of the X11_window */ - XWindowChanges new_values; - - new_values.width = _fb_width; - new_values.height = _fb_height; - - XConfigureWindow(_display,_window, CWWidth | CWHeight, &new_values); - - if (_image) - XFree(_image); - _image = XShmCreateImage(_display, DefaultVisual(_display, _screen), _depth, ZPixmap, NULL, &shminfo,_fb_width,_fb_height); - if (!_image) - error("Couldn't get image by XShmCreateImage()"); - - shminfo.shmid = shmget(IPC_PRIVATE, _image->bytes_per_line * _image->height, IPC_CREAT | 0700); - if (shminfo.shmid < 0) - error("Couldn't allocate image data by shmget()"); - - _image->data = shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0); - shminfo.readOnly = False; - if (XShmAttach(_display, &shminfo) == 0) { - error("Could not attach shared memory segment !\n"); - exit(1); - } - shmctl(shminfo.shmid, IPC_RMID, 0); - - if (_local_fb) - free(_local_fb); - if (_local_fb_overlay) - free(_local_fb_overlay); - /* Initialize the 'local' frame buffer and the palette */ - _local_fb = (uint8 *)calloc(_fb_width * _fb_height, sizeof(uint8)); - _local_fb_overlay = (uint16 *)calloc(_fb_width * _fb_height, sizeof(uint16)); - - } -} - -bool OSystem_X11::setSoundCallback(SoundProc proc, void *param) { - static THREAD_PARAM thread_param; - - /* And finally start the music thread */ - thread_param.param = param; - thread_param.sound_proc = proc; - - pthread_create(&_sound_thread, NULL, sound_and_music_thread, (void *)&thread_param); - - return true; -} - -void OSystem_X11::clearSoundCallback() { - // TODO implement this... - // The sound_thread has to be stopped in a nice way. In particular, - // using pthread_kill would be a bad idea. Rather, use pthread_cancel, - // or maybe a global variable, to achieve this. - // This method shouldn't return until the sound thread really has stopped. -} - - -void OSystem_X11::setPalette(const byte *colors, uint start, uint num) { - uint16 *pal = &(_palette16[start]); - const byte *data = colors; - - if (_bytesPerPixel == 4) { - for (uint i = start; i < start+num; i++) { - //_palette32[i] = ((uint32 *)colors)[i]; - _palette32[i] = (colors[i * 4 + 0] << 16) | (colors[i * 4 + 1] << 8) | (colors[i * 4 + 2] << 0); - } - } - - do { - *pal++ = ((data[0] & 0xF8) << 8) | ((data[1] & 0xFC) << 3) | (data[2] >> 3); - data += 4; - num--; - } while (num > 0); - - _palette_changed = true; -} - -#define AddDirtyRec(xi,yi,wi,hi) \ - if (_num_of_dirty_rects < MAX_NUMBER_OF_DIRTY_RECTS) { \ - _ds[_num_of_dirty_rects].x = xi; \ - _ds[_num_of_dirty_rects].y = yi; \ - _ds[_num_of_dirty_rects].w = wi; \ - _ds[_num_of_dirty_rects].h = hi; \ - _num_of_dirty_rects++; \ - } - -void OSystem_X11::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { - uint8 *dst; - - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - if (h > (_fb_height - y)) { - h = _fb_height - y; - } - - dst = _local_fb + _fb_width * y + x; - - if (h <= 0) - return; - - AddDirtyRec(x, y, w, h); - while (h-- > 0) { - memcpy(dst, buf, w); - dst +=_fb_width; - buf += pitch; - } -} - -void OSystem_X11::blit(const DirtyRect *d, uint16 *dst, int pitch) { - uint8 *ptr_src = _local_fb + (_fb_width * d->y) + d->x; - uint16 *ptr_dst = dst + ((_fb_width * d->y) + d->x); - int x, y; - - for (y = 0; y < d->h; y++) { - for (x = 0; x < d->w; x++) { - *ptr_dst++ = _palette16[*ptr_src++]; - } - ptr_dst += pitch - d->w; - ptr_src +=_fb_width - d->w; - } -} - -void OSystem_X11::blit_convert(const DirtyRect *d, uint8 *dst, int pitch) { - uint8 *ptr_src = _local_fb + (_fb_width * d->y) + d->x; - uint8 *ptr_dst = dst + ((_fb_width * d->y) + d->x) * _bytesPerPixel; - int x, y; - - switch (_bytesPerPixel) { - case 2: - for (y = 0; y < d->h; y++) { - for (x = 0; x < d->w; x++) { - *ptr_dst = _palette16[*ptr_src++]; - ptr_dst += _bytesPerPixel; - } - ptr_dst += (pitch - d->w) * _bytesPerPixel; - ptr_src +=_fb_width - d->w; - } - break; - case 4: - for (y = 0; y < d->h; y++) { - for (x = 0; x < d->w; x++) { - *(uint32 *)ptr_dst = _palette32[*ptr_src]; - ptr_dst += _bytesPerPixel; - ptr_src++; - } - ptr_dst += (pitch - d->w) * _bytesPerPixel; - ptr_src += _fb_width - d->w; - } - } -} - -void OSystem_X11::updateScreen_helper(const DirtyRect *d, DirtyRect *dout) { - - if (_overlay_visible == false) { - blit_convert(d, (uint8 *)_image->data, _fb_width); - } else { - uint16 *ptr_src = _local_fb_overlay + (_fb_width * d->y) + d->x; - uint8 *ptr_dst = (uint8 *)_image->data + ((_fb_width * d->y) + d->x) * _bytesPerPixel; - - int y; - - switch (_bytesPerPixel) { - case 2: - for (y = 0; y < d->h; y++) { - memcpy(ptr_dst, ptr_src, d->w * sizeof(uint16)); - ptr_dst += _fb_width * sizeof(uint16); - ptr_src += _fb_width; - } - break; - case 4: - uint16 currLine, x; - register uint16 currPixel; - for (y = d->y; y < d->y + d->h; y++) { - currLine = y * _fb_width; - for (x = d->x; x < d->x + d->w; x++) { - currPixel = _local_fb_overlay[(currLine + x)]; - *(uint32 *)ptr_dst = ((currPixel & 0xF800) << 8) + ((currPixel & 0x07E0) << 5) + - ((currPixel & 0x001F) << 3); - ptr_dst += sizeof(uint32); - } - ptr_dst += (_fb_width - d->w) * _bytesPerPixel; - } - - } - } - if (d->x < dout->x) - dout->x = d->x; - if (d->y < dout->y) - dout->y = d->y; - if ((d->x + d->w) > dout->w) - dout->w = d->x + d->w; - if ((d->y + d->h) > dout->h) - dout->h = d->y + d->h; -} - -void OSystem_X11::updateScreen() { - bool full_redraw = false; - bool need_redraw = false; - static const DirtyRect ds_full = { 0, 0, _fb_width, _fb_height }; - DirtyRect dout = {_fb_width, _fb_height, 0, 0 }; - - if (_palette_changed) { - full_redraw = true; - _num_of_dirty_rects = 0; - _palette_changed = false; - } else if (_num_of_dirty_rects >= MAX_NUMBER_OF_DIRTY_RECTS) { - full_redraw = true; - _num_of_dirty_rects = 0; - } - - if (full_redraw) { - updateScreen_helper(&ds_full, &dout); - need_redraw = true; - } else if ((_num_of_dirty_rects > 0) || (_mouse_state_changed == true)) { - need_redraw = true; - while (_num_of_dirty_rects > 0) { - _num_of_dirty_rects--; - updateScreen_helper(&(_ds[_num_of_dirty_rects]), &dout); - } - } - - /* Then 'overlay' the mouse on the image */ - draw_mouse(&dout); - - if (_current_shake_pos != _new_shake_pos) { - /* Redraw first the 'black borders' in case of resize */ - if (_current_shake_pos < _new_shake_pos) - XFillRectangle(_display,_window, _black_gc, 0, _current_shake_pos, _window_width, _new_shake_pos); - else - XFillRectangle(_display,_window, _black_gc, 0, _window_height - _current_shake_pos, - _window_width,_window_height - _new_shake_pos); - XShmPutImage(_display, _window, DefaultGC(_display, _screen), _image, - 0, 0, _scumm_x, _scumm_y + _new_shake_pos, _fb_width, _fb_height, 0); - _current_shake_pos = _new_shake_pos; - } else if (need_redraw == true) { - XShmPutImage(_display, _window, DefaultGC(_display, _screen), _image, - dout.x, dout.y, _scumm_x + dout.x, _scumm_y + dout.y + _current_shake_pos, - dout.w - dout.x, dout.h - dout.y, 0); - XFlush(_display); - } -} - -bool OSystem_X11::showMouse(bool visible) -{ - if (_mouse_visible == visible) - return visible; - - bool last = _mouse_visible; - _mouse_visible = visible; - - if ((visible == false) && (_mouse_state_changed == false)) { - undraw_mouse(); - } - _mouse_state_changed = true; - - return last; -} - -void OSystem_X11::quit() { - exit(0); -} - -void OSystem_X11::setWindowCaption(const char *caption) { - //debug("setWindowCaption('%s')", caption); -} - -void OSystem_X11::undraw_mouse() { - AddDirtyRec(_oldMouseState.x, _oldMouseState.y, _oldMouseState.w, _oldMouseState.h); -} - -void OSystem_X11::draw_mouse(DirtyRect *dout) { - //debug("draw_mouse()"); - _mouse_state_changed = false; - - if (_mouse_visible == false) - return; - - int xdraw = _curMouseState.x - _curMouseState.hot_x; - int ydraw = _curMouseState.y - _curMouseState.hot_y; - int w = _curMouseState.w; - int h = _curMouseState.h; - int real_w; - int real_h; - - uint8 *dst; - const byte *buf = _ms_buf; - - if (ydraw < 0) { - real_h = h + ydraw; - buf += (-ydraw) * w; - ydraw = 0; - } else { - real_h = (ydraw + h) > _fb_height ? (_fb_height - ydraw) : h; - } - if (xdraw < 0) { - real_w = w + xdraw; - buf += (-xdraw); - xdraw = 0; - } else { - real_w = (xdraw + w) > _fb_width ? (_fb_width - xdraw) : w; - } - - dst = (uint8 *)_image->data + ((ydraw *_fb_width) + xdraw) * _bytesPerPixel; - - if ((real_h == 0) || (real_w == 0)) { - return; - } - - - if (xdraw < dout->x) - dout->x = xdraw; - if (ydraw < dout->y) - dout->y = ydraw; - if ((xdraw + real_w) > dout->w) - dout->w = xdraw + real_w; - if ((ydraw + real_h) > dout->h) - dout->h = ydraw + real_h; - - _oldMouseState.x = xdraw; - _oldMouseState.y = ydraw; - _oldMouseState.w = real_w; - _oldMouseState.h = real_h; - - while (real_h > 0) { - int width = real_w; - while (width > 0) { - byte color = *buf; - if (color != _mouseKeycolor) { - if (_depth == 16) - *(uint16 *)dst = _palette16[color]; - else { - *(uint32 *)dst = _palette32[color]; - } - } - buf++; - dst += _bytesPerPixel; - width--; - } - buf += w - real_w; - dst += (_fb_width - real_w) * _bytesPerPixel; - real_h--; - } -} - -void OSystem_X11::set_mouse_pos(int x, int y) { - if ((x != _curMouseState.x) || (y != _curMouseState.y)) { - _curMouseState.x = x; - _curMouseState.y = y; - if (_mouse_state_changed == false) { - undraw_mouse(); - } - _mouse_state_changed = true; - } -} - -void OSystem_X11::warpMouse(int x, int y) { - set_mouse_pos(x, y); -} - -void OSystem_X11::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) { - _curMouseState.w = w; - _curMouseState.h = h; - _curMouseState.hot_x = hotspot_x; - _curMouseState.hot_y = hotspot_y; - - if (_ms_buf) - free(_ms_buf); - _ms_buf = (byte *) malloc(w * h); - memcpy(_ms_buf, buf, w * h); - - if (_mouse_state_changed == false) { - undraw_mouse(); - } - _mouseKeycolor = keycolor; - _mouse_state_changed = true; -} - -void OSystem_X11::setShakePos(int shake_pos) { - if (_new_shake_pos != shake_pos) { - if (_mouse_state_changed == false) { - undraw_mouse(); - } - _mouse_state_changed = true; - } - _new_shake_pos = shake_pos; -} - -int OSystem_X11::getOutputSampleRate() const { - return SAMPLES_PER_SEC; -} - -void OSystem_X11::delayMillis(uint msecs) { - usleep(msecs * 1000); -} - -bool OSystem_X11::pollEvent(Common::Event &scumm_event) { - /* First, handle timers */ - uint32 current_msecs = getMillis(); - - if (_timer_active && (current_msecs >= _timer_next_expiry)) { - _timer_duration = _timer_callback(_timer_duration); - _timer_next_expiry = current_msecs + _timer_duration; - } - - while (XPending(_display)) { - XEvent event; - - XNextEvent(_display, &event); - switch (event.type) { - case Expose:{ - int real_w, real_h; - int real_x, real_y; - real_x = event.xexpose.x; - real_y = event.xexpose.y; - real_w = event.xexpose.width; - real_h = event.xexpose.height; - if (real_x < _scumm_x) { - real_w -= _scumm_x - real_x; - real_x = 0; - } else { - real_x -= _scumm_x; - } - if (real_y < _scumm_y) { - real_h -= _scumm_y - real_y; - real_y = 0; - } else { - real_y -= _scumm_y; - } - if ((real_h <= 0) || (real_w <= 0)) - break; - if ((real_x >=_fb_width) || (real_y >=_fb_height)) - break; - - if ((real_x + real_w) >=_fb_width) { - real_w =_fb_width - real_x; - } - if ((real_y + real_h) >=_fb_height) { - real_h =_fb_height - real_y; - } - - /* Compute the intersection of the expose event with the real ScummVM display zone */ - AddDirtyRec(real_x, real_y, real_w, real_h); - } - break; - - case KeyPress:{ - /* I am using keycodes here and NOT keysyms to be sure that even if the user - remaps his iPAQ's keyboard, it will still work. - */ - int keycode = -1; - int ascii = -1; - byte mode = 0; - - if (event.xkey.state & 0x01) - mode |= Common::KBD_SHIFT; - if (event.xkey.state & 0x04) - mode |= Common::KBD_CTRL; - if (event.xkey.state & 0x08) - mode |= Common::KBD_ALT; - switch (event.xkey.keycode) { - - case 9: /* Escape on my PC */ - case 130: /* Calendar on the iPAQ */ - keycode = 27; - break; - - case 71: /* F5 on my PC */ - case 128: /* Record on the iPAQ */ - keycode = 319; - break; - - case 65: /* Space on my PC */ - case 131: /* Schedule on the iPAQ */ - keycode = 32; - break; - - case 132: - _report_presses = 0; - break; - - case 133: - _fake_right_mouse = 1; - break; - - default:{ - KeySym xsym; - xsym = XKeycodeToKeysym(_display, event.xkey.keycode, 0); - keycode = xsym; - if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01)) - xsym &= ~0x20; /* Handle shifted keys */ - ascii = xsym; - } - } - if (keycode != -1) { - scumm_event.type = Common::EVENT_KEYDOWN; - scumm_event.kbd.keycode = keycode; - scumm_event.kbd.ascii = (ascii != -1 ? ascii : keycode); - scumm_event.kbd.flags = mode; - return true; - } - } - break; - - case KeyRelease:{ - /* I am using keycodes here and NOT keysyms to be sure that even if the user - remaps his iPAQ's keyboard, it will still work. - */ - int keycode = -1; - int ascii = -1; - byte mode = 0; - - if (event.xkey.state & 0x01) - mode |= Common::KBD_SHIFT; - if (event.xkey.state & 0x04) - mode |= Common::KBD_CTRL; - if (event.xkey.state & 0x08) - mode |= Common::KBD_ALT; - switch (event.xkey.keycode) { - case 132: /* 'Q' on the iPAQ */ - _report_presses = 1; - break; - - case 133: /* Arrow on the iPAQ */ - _fake_right_mouse = 0; - break; - - default:{ - KeySym xsym; - xsym = XKeycodeToKeysym(_display, event.xkey.keycode, 0); - keycode = xsym; - if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01)) - xsym &= ~0x20; /* Handle shifted keys */ - ascii = xsym; - } - } - if (keycode != -1) { - scumm_event.type = Common::EVENT_KEYUP; - scumm_event.kbd.keycode = keycode; - scumm_event.kbd.ascii = (ascii != -1 ? ascii : keycode); - scumm_event.kbd.flags = mode; - return true; - } - } - break; - - case ButtonPress: - if (_report_presses != 0) { - if (event.xbutton.button == 1) { - if (_fake_right_mouse == 0) { - scumm_event.type = Common::EVENT_LBUTTONDOWN; - } else { - scumm_event.type = Common::EVENT_RBUTTONDOWN; - } - } else if (event.xbutton.button == 3) - scumm_event.type = Common::EVENT_RBUTTONDOWN; - scumm_event.mouse.x = event.xbutton.x - _scumm_x; - scumm_event.mouse.y = event.xbutton.y - _scumm_y; - return true; - } - break; - - case ButtonRelease: - if (_report_presses != 0) { - if (event.xbutton.button == 1) { - if (_fake_right_mouse == 0) { - scumm_event.type = Common::EVENT_LBUTTONUP; - } else { - scumm_event.type = Common::EVENT_RBUTTONUP; - } - } else if (event.xbutton.button == 3) - scumm_event.type = Common::EVENT_RBUTTONUP; - scumm_event.mouse.x = event.xbutton.x - _scumm_x; - scumm_event.mouse.y = event.xbutton.y - _scumm_y; - return true; - } - break; - - case MotionNotify: - scumm_event.type = Common::EVENT_MOUSEMOVE; - scumm_event.mouse.x = event.xmotion.x - _scumm_x; - scumm_event.mouse.y = event.xmotion.y - _scumm_y; - set_mouse_pos(scumm_event.mouse.x, scumm_event.mouse.y); - return true; - - case ConfigureNotify:{ - if ((_window_width != event.xconfigure.width) || (_window_height != event.xconfigure.height)) { - _window_width = event.xconfigure.width; - _window_height = event.xconfigure.height; - _scumm_x = (_window_width -_fb_width) / 2; - _scumm_y = (_window_height -_fb_height) / 2; - XFillRectangle(_display, _window, _black_gc, 0, 0, _window_width, _window_height); - } - } - break; - - default: - printf("Unhandled event : %d\n", event.type); - break; - } - } - - return false; -} - -void OSystem_X11::setTimerCallback(TimerProc callback, int interval) { - if (callback != NULL) { - _timer_duration = interval; - _timer_next_expiry = getMillis() + interval; - _timer_callback = callback; - _timer_active = true; - } else { - _timer_active = false; - } -} - -OSystem::MutexRef OSystem_X11::createMutex(void) { - pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(mutex, NULL); - return (MutexRef)mutex; -} - -void OSystem_X11::lockMutex(MutexRef mutex) { - pthread_mutex_lock((pthread_mutex_t *) mutex); -} - -void OSystem_X11::unlockMutex(MutexRef mutex) { - pthread_mutex_unlock((pthread_mutex_t *) mutex); -} - -void OSystem_X11::deleteMutex(MutexRef mutex) { - pthread_mutex_destroy((pthread_mutex_t *) mutex); - free(mutex); -} - -void OSystem_X11::showOverlay() { - _overlay_visible = true; -} - -void OSystem_X11::hideOverlay() { - _overlay_visible = false; - _palette_changed = true; // This is to force a full redraw to hide the overlay -} - -void OSystem_X11::clearOverlay() { - if (_overlay_visible == false) - return; - DirtyRect d = { 0, 0, _fb_width, _fb_height }; - AddDirtyRec(0, 0, _fb_width, _fb_height); - blit(&d, _local_fb_overlay, _fb_width); -} - -void OSystem_X11::grabOverlay(int16 *dest, int pitch) { - if (_overlay_visible == false) - return; - - DirtyRect d = { 0, 0, _fb_width, _fb_height }; - blit(&d, (uint16 *)dest, pitch); -} - -void OSystem_X11::copyRectToOverlay(const int16 *src, int pitch, int x, int y, int w, int h) { - if (_overlay_visible == false) - return; - uint16 *dst = _local_fb_overlay + x + (y * _fb_width); - AddDirtyRec(x, y, w, h); - while (h > 0) { - memcpy(dst, src, w * sizeof(*dst)); - dst +=_fb_width; - src += pitch; - h--; - } -} - -int16 OSystem_X11::getHeight() { - return _fb_height; -} - -int16 OSystem_X11::getWidth() { - return _fb_width; -} - -void OSystem_X11::grabPalette(byte *colors, uint start, uint num) { - warning("Dummy: grabPalette()"); -} diff --git a/backends/platform/x11/x11.h b/backends/platform/x11/x11.h deleted file mode 100644 index bf5da5745a..0000000000 --- a/backends/platform/x11/x11.h +++ /dev/null @@ -1,197 +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$ - * - */ - -class OSystem_X11:public OSystem { -public: - OSystem_X11(); - ~OSystem_X11(); - - void initBackend(); - - // Determine whether the backend supports the specified feature. - bool hasFeature(Feature f); - - // En-/disable the specified feature. - void setFeatureState(Feature f, bool enable); - - // Query the state of the specified feature. - bool getFeatureState(Feature f); - - // Retrieve a list of all graphics modes supported by this backend. - const GraphicsMode *getSupportedGraphicsModes() const; - - // Return the ID of the 'default' graphics mode. - int getDefaultGraphicsMode() const; - - // Switch to the specified graphics mode. - bool setGraphicsMode(int mode); - - // Determine which graphics mode is currently active. - int getGraphicsMode() const; - - // Set colors of the palette - void setPalette(const byte *colors, uint start, uint num); - - // Set the size of the video bitmap. - // Typically, 320x200 - void initSize(uint w, uint h); - - // Draw a bitmap to screen. - // The screen will not be updated to reflect the new bitmap - void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); - - // Update the dirty areas of the screen - void updateScreen(); - - // Either show or hide the mouse cursor - bool showMouse(bool visible); - - // Set the position of the mouse cursor - void set_mouse_pos(int x, int y); - - // Warp the mouse cursor. Where set_mouse_pos() only informs the - // backend of the mouse cursor's current position, this function - // actually moves the cursor to the specified position. - void warpMouse(int x, int y); - - // Set the bitmap that's used when drawing the cursor. - void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int cursorTargetScale = 1); - - // Shaking is used in SCUMM. Set current shake position. - void setShakePos(int shake_pos); - - // Get the number of milliseconds since the program was started. - uint32 getMillis(); - - // Delay for a specified amount of milliseconds - void delayMillis(uint msecs); - - // Get the next event. - // Returns true if an event was retrieved. - bool pollEvent(Common::Event &event); - - // Set function that generates samples - bool setSoundCallback(SoundProc proc, void *param); - void clearSoundCallback(); - - // Determine the output sample rate. Audio data provided by the sound - // callback will be played using this rate. - int getOutputSampleRate() const; - - // Quit - void quit(); - - // Add a callback timer - void setTimerCallback(TimerProc callback, int interval); - - // Mutex handling - MutexRef createMutex(); - void lockMutex(MutexRef mutex); - void unlockMutex(MutexRef mutex); - void deleteMutex(MutexRef mutex); - - // Overlay handling for the new menu system - void showOverlay(); - void hideOverlay(); - void clearOverlay(); - void grabOverlay(int16 *, int); - void copyRectToOverlay(const int16 *, int, int, int, int, int); - virtual int16 getHeight(); - virtual int16 getWidth(); - - virtual void grabPalette(byte *colors, uint start, uint num); - - // Set a window caption or any other comparable status display to the - // given value. - void setWindowCaption(const char *caption); - - static OSystem *create(int gfx_mode, bool full_screen); - -private: - typedef struct { - int x, y; - int w, h; - int hot_x, hot_y; - } MouseState; - - typedef struct { - int x, y, w, h; - } DirtyRect; - - enum { - MAX_NUMBER_OF_DIRTY_RECTS = 32 - }; - - void create_empty_cursor(); - void draw_mouse(DirtyRect *dout); - void undraw_mouse(); - void updateScreen_helper(const DirtyRect *d, DirtyRect *dout); - void blit_convert(const DirtyRect *d, uint8 *dst, int pitch); - void blit(const DirtyRect *d, uint16 *dst, int pitch); - - uint8 *_local_fb; - uint16 *_local_fb_overlay; - bool _overlay_visible; - - int _window_width, _window_height; - int _fb_width, _fb_height; - int _scumm_x, _scumm_y; - - uint16 *_palette16; - uint32 *_palette32; - - bool _palette_changed; - Display *_display; - int _screen, _depth; - uint8 _bytesPerPixel; - Window _window; - GC _black_gc; - XImage *_image; - pthread_t _sound_thread; - - struct timeval _start_time; - - int _fake_right_mouse; - int _report_presses; - int _current_shake_pos; - int _new_shake_pos; - DirtyRect _ds[MAX_NUMBER_OF_DIRTY_RECTS]; - int _num_of_dirty_rects; - - MouseState _oldMouseState, _curMouseState; - byte *_ms_buf; - bool _mouse_visible; - bool _mouse_state_changed; - byte _mouseKeycolor; - - uint32 _timer_duration, _timer_next_expiry; - bool _timer_active; - int (*_timer_callback) (int); -}; - -typedef struct { - OSystem::SoundProc sound_proc; - void *param; -} THREAD_PARAM; diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp index ec6d6842c0..21bc56e441 100644 --- a/backends/saves/default/default-saves.cpp +++ b/backends/saves/default/default-saves.cpp @@ -120,7 +120,7 @@ Common::StringList DefaultSaveFileManager::listSavefiles(const char *pattern) { Common::StringList results; Common::String search(pattern); - if (savePath.lookupFile(savefiles, search, false, true)) { + if (savePath.lookupFile(savefiles, search, false, true, 0)) { for (FSList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) { results.push_back(file->getName()); } diff --git a/backends/timer/default/default-timer.h b/backends/timer/default/default-timer.h index 3dbb89e24a..e7ac3d122f 100644 --- a/backends/timer/default/default-timer.h +++ b/backends/timer/default/default-timer.h @@ -38,14 +38,15 @@ private: void *_timerHandler; TimerSlot *_head; - public: DefaultTimerManager(); ~DefaultTimerManager(); bool installTimerProc(TimerProc proc, int32 interval, void *refCon); void removeTimerProc(TimerProc proc); - // Timer callback, to be invoked at regular time intervals by the backend. + /** + * Timer callback, to be invoked at regular time intervals by the backend. + */ void handler(); }; diff --git a/base/main.cpp b/base/main.cpp index b836b423a4..f91574ffc4 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -229,7 +229,6 @@ static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::St // Reset the file/directory mappings Common::File::resetDefaultDirectories(); - // If result=1 return to the launcher, else quit ScummVM return result; } @@ -279,6 +278,7 @@ extern "C" int scummvm_main(int argc, char *argv[]) { // Load the plugins. PluginManager::instance().loadPlugins(); + EngineMan.getPlugins(); // Process the remaining command line settings. Must be done after the // config file and the plugins have been loaded. diff --git a/common/scummsys.h b/common/scummsys.h index 939f34a5c3..45462a6974 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -54,6 +54,7 @@ #pragma warning( disable : 4505 ) // turn off "unreferenced local function has been removed" #pragma warning( disable : 4510 ) // turn off "default constructor could not be generated" #pragma warning( disable : 4610 ) // turn off "struct can never be instantiated - user defined constructor required" + #pragma warning( disable : 4800 ) // turn off "forcing value to bool 'true' or 'false' (performance warning)" // vsnprintf is already defined in Visual Studio 2008 #if (_MSC_VER < 1500) diff --git a/common/system.cpp b/common/system.cpp index 327b7246e2..8d528258f4 100644 --- a/common/system.cpp +++ b/common/system.cpp @@ -121,28 +121,3 @@ void OSystem::clearScreen() { memset(screen->pixels, 0, screen->h * screen->pitch); unlockScreen(); } - -/* - * Include header files needed for the getFilesystemFactory() method. - * - * TODO: Remove these gradually and move the getFilesystemFactory() implementations - * to the respective backends. Then turn it into a pure virtual method of OSystem. - */ -#if defined(PALMOS_MODE) - #include "backends/fs/palmos/palmos-fs-factory.h" -#elif defined(__PLAYSTATION2__) - #include "backends/fs/ps2/ps2-fs-factory.h" -#endif - -FilesystemFactory *OSystem::getFilesystemFactory() { - #if defined(__amigaos4__) || defined(__DC__) || defined(__SYMBIAN32__) || defined(UNIX) || defined(WIN32) || defined(__WII__) || defined(__PSP__) || defined(__DS__) - // These ports already implement this function, so it should never be called. - return 0; - #elif defined(PALMOS_MODE) - return &PalmOSFilesystemFactory::instance(); - #elif defined(__PLAYSTATION2__) - return &Ps2FilesystemFactory::instance(); - #else - #error Unknown and unsupported backend in OSystem::getFilesystemFactory - #endif -} diff --git a/common/system.h b/common/system.h index 204ea9383a..b895a5cfba 100644 --- a/common/system.h +++ b/common/system.h @@ -814,15 +814,6 @@ public: */ virtual Audio::Mixer *getMixer() = 0; - /** - * Determine the output sample rate. Audio data provided by the sound - * callback will be played using this rate. - * @note Client code other than the sound mixer should _not_ use this - * method. Instead, call Mixer::getOutputRate()! - * @return the output sample rate - */ - virtual int getOutputSampleRate() const = 0; - //@} @@ -911,7 +902,7 @@ public: * * @return FilesystemFactory* The specific factory for the current architecture. */ - virtual FilesystemFactory *getFilesystemFactory(); + virtual FilesystemFactory *getFilesystemFactory() = 0; /** @@ -127,7 +127,7 @@ _srcdir=`dirname $0` # Determine a tmp file name, using mktemp(1) when available. if type mktemp > /dev/null 2>&1 ; then - TMPO=`mktemp` + TMPO=`mktemp /tmp/scummvm-conf.XXXXXXXXXX` else TMPO=${_srcdir}/scummvm-conf fi @@ -741,6 +741,10 @@ for ac_option in $@; do --enable-release) DEBFLAGS="-O2 -Wuninitialized" ;; + --enable-profiling) + CXXFLAGS="$CXXFLAGS -pg" + LDFLAGS="$LDFLAGS -pg" + ;; --with-sdl-prefix=*) arg=`echo $ac_option | cut -d '=' -f 2` _sdlpath="$arg:$arg/bin" diff --git a/dists/engine-data/lure.dat b/dists/engine-data/lure.dat Binary files differindex dbbfc45c47..26afd45d79 100644 --- a/dists/engine-data/lure.dat +++ b/dists/engine-data/lure.dat diff --git a/dists/msvc7/parallaction.vcproj b/dists/msvc7/parallaction.vcproj index 79ac169995..9dfb575c6b 100644 --- a/dists/msvc7/parallaction.vcproj +++ b/dists/msvc7/parallaction.vcproj @@ -97,6 +97,9 @@ </Configurations> <Files> <File + RelativePath="..\..\engines\parallaction\balloons.cpp"> + </File> + <File RelativePath="..\..\engines\parallaction\callables_br.cpp"> </File> <File @@ -124,6 +127,9 @@ RelativePath="..\..\engines\parallaction\disk_ns.cpp"> </File> <File + RelativePath="..\..\engines\parallaction\exec.h"> + </File> + <File RelativePath="..\..\engines\parallaction\exec_br.cpp"> </File> <File diff --git a/dists/msvc7/scummvm.vcproj b/dists/msvc7/scummvm.vcproj index befbdd8e31..1d195fd938 100644 --- a/dists/msvc7/scummvm.vcproj +++ b/dists/msvc7/scummvm.vcproj @@ -396,18 +396,15 @@ RelativePath="..\..\sound\midiparser_xmidi.cpp"> </File> <File - RelativePath="..\..\sound\musicplugin.cpp"> - </File> - <File - RelativePath="..\..\sound\musicplugin.h"> - </File> - <File RelativePath="..\..\sound\mixer.cpp"> </File> <File RelativePath="..\..\sound\mixer.h"> </File> <File + RelativePath="..\..\sound\mixer_intern.h"> + </File> + <File RelativePath="..\..\sound\mp3.cpp"> </File> <File @@ -420,6 +417,12 @@ RelativePath="..\..\sound\mpu401.h"> </File> <File + RelativePath="..\..\sound\musicplugin.cpp"> + </File> + <File + RelativePath="..\..\sound\musicplugin.h"> + </File> + <File RelativePath="..\..\sound\null.cpp"> </File> <File diff --git a/dists/msvc71/parallaction.vcproj b/dists/msvc71/parallaction.vcproj index 440e7123e8..6030b030a8 100644 --- a/dists/msvc71/parallaction.vcproj +++ b/dists/msvc71/parallaction.vcproj @@ -111,6 +111,9 @@ </References> <Files> <File + RelativePath="..\..\engines\parallaction\balloons.cpp"> + </File> + <File RelativePath="..\..\engines\parallaction\callables_br.cpp"> </File> <File @@ -138,6 +141,9 @@ RelativePath="..\..\engines\parallaction\disk_ns.cpp"> </File> <File + RelativePath="..\..\engines\parallaction\exec.h"> + </File> + <File RelativePath="..\..\engines\parallaction\exec_br.cpp"> </File> <File diff --git a/dists/msvc71/scummvm.vcproj b/dists/msvc71/scummvm.vcproj index bc363a67fd..5817c91d45 100644 --- a/dists/msvc71/scummvm.vcproj +++ b/dists/msvc71/scummvm.vcproj @@ -410,18 +410,15 @@ RelativePath="..\..\sound\midiparser_xmidi.cpp"> </File> <File - RelativePath="..\..\sound\musicplugin.cpp"> - </File> - <File - RelativePath="..\..\sound\musicplugin.h"> - </File> - <File RelativePath="..\..\sound\mixer.cpp"> </File> <File RelativePath="..\..\sound\mixer.h"> </File> <File + RelativePath="..\..\sound\mixer_intern.h"> + </File> + <File RelativePath="..\..\sound\mp3.cpp"> </File> <File @@ -434,6 +431,12 @@ RelativePath="..\..\sound\mpu401.h"> </File> <File + RelativePath="..\..\sound\musicplugin.cpp"> + </File> + <File + RelativePath="..\..\sound\musicplugin.h"> + </File> + <File RelativePath="..\..\sound\null.cpp"> </File> <File diff --git a/dists/msvc8/parallaction.vcproj b/dists/msvc8/parallaction.vcproj index 21a6d3bab3..c5721bd30f 100644 --- a/dists/msvc8/parallaction.vcproj +++ b/dists/msvc8/parallaction.vcproj @@ -161,6 +161,10 @@ </References> <Files> <File + RelativePath="..\..\engines\parallaction\balloons.cpp" + > + </File> + <File RelativePath="..\..\engines\parallaction\callables_br.cpp" > </File> @@ -197,6 +201,10 @@ > </File> <File + RelativePath="..\..\engines\parallaction\exec.h" + > + </File> + <File RelativePath="..\..\engines\parallaction\exec_br.cpp" > </File> diff --git a/dists/msvc8/scummvm.vcproj b/dists/msvc8/scummvm.vcproj index 2d047bbd1b..b144dc0b79 100644 --- a/dists/msvc8/scummvm.vcproj +++ b/dists/msvc8/scummvm.vcproj @@ -565,19 +565,15 @@ > </File> <File - RelativePath="..\..\sound\musicplugin.cpp" - > - </File> - <File - RelativePath="..\..\sound\musicplugin.h" + RelativePath="..\..\sound\mixer.cpp" > </File> <File - RelativePath="..\..\sound\mixer.cpp" + RelativePath="..\..\sound\mixer.h" > </File> <File - RelativePath="..\..\sound\mixer.h" + RelativePath="..\..\sound\mixer_intern.h" > </File> <File @@ -597,6 +593,14 @@ > </File> <File + RelativePath="..\..\sound\musicplugin.cpp" + > + </File> + <File + RelativePath="..\..\sound\musicplugin.h" + > + </File> + <File RelativePath="..\..\sound\null.cpp" > </File> diff --git a/dists/msvc9/parallaction.vcproj b/dists/msvc9/parallaction.vcproj index bdc93860f9..d3117b6b0c 100644 --- a/dists/msvc9/parallaction.vcproj +++ b/dists/msvc9/parallaction.vcproj @@ -162,6 +162,10 @@ </References> <Files> <File + RelativePath="..\..\engines\parallaction\balloons.cpp" + > + </File> + <File RelativePath="..\..\engines\parallaction\callables_br.cpp" > </File> @@ -198,6 +202,10 @@ > </File> <File + RelativePath="..\..\engines\parallaction\exec.h" + > + </File> + <File RelativePath="..\..\engines\parallaction\exec_br.cpp" > </File> diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj index bd6b5af75c..0c10158fdc 100644 --- a/dists/msvc9/scummvm.vcproj +++ b/dists/msvc9/scummvm.vcproj @@ -570,19 +570,15 @@ > </File> <File - RelativePath="..\..\sound\musicplugin.cpp" - > - </File> - <File - RelativePath="..\..\sound\musicplugin.h" + RelativePath="..\..\sound\mixer.cpp" > </File> <File - RelativePath="..\..\sound\mixer.cpp" + RelativePath="..\..\sound\mixer.h" > </File> <File - RelativePath="..\..\sound\mixer.h" + RelativePath="..\..\sound\mixer_intern.h" > </File> <File @@ -602,6 +598,14 @@ > </File> <File + RelativePath="..\..\sound\musicplugin.cpp" + > + </File> + <File + RelativePath="..\..\sound\musicplugin.h" + > + </File> + <File RelativePath="..\..\sound\null.cpp" > </File> diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index cf25f1d355..b10211282f 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -63,6 +63,7 @@ void addSpriteFilledToBGList(int16 objIdx) { void createBgIncrustListElement(int16 objIdx, int16 param) { BGIncrust tmp; + tmp.unkPtr = 0; tmp.objIdx = objIdx; tmp.param = param; tmp.x = objectTable[objIdx].x; @@ -90,6 +91,7 @@ void loadBgIncrustFromSave(Common::InSaveFile &fHandle) { fHandle.readUint32BE(); fHandle.readUint32BE(); + tmp.unkPtr = 0; tmp.objIdx = fHandle.readUint16BE(); tmp.param = fHandle.readUint16BE(); tmp.x = fHandle.readUint16BE(); diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 47446f2410..2b7f3b8890 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -969,6 +969,7 @@ void OSRenderer::drawBackground() { /*! \brief Draw one overlay * \param it Overlay info + * \todo Add handling of type 22 overlays */ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { int len; @@ -979,6 +980,9 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { switch (it->type) { // color sprite case 0: + if (objectTable[it->objIdx].frame < 0) { + break; + } sprite = animDataTable + objectTable[it->objIdx].frame; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; @@ -988,6 +992,13 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { delete[] mask; break; + // bitmap + case 4: + if (objectTable[it->objIdx].frame >= 0) { + FWRenderer::renderOverlay(it); + } + break; + // masked background case 20: assert(it->objIdx < NUM_MAX_OBJECT); diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 7830f4d8f8..547379f02d 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -227,6 +227,13 @@ void CineEngine::mainLoop(int bootScriptIdx) { do { stopMusicAfterFadeOut(); di = executePlayerInput(); + + // Clear the zoneQuery table (Operation Stealth specific) + if (g_cine->getGameType() == Cine::GType_OS) { + for (uint i = 0; i < NUM_MAX_ZONE; i++) { + zoneQuery[i] = 0; + } + } processSeqList(); executeList1(); diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index 7666f05352..c02e01c8ce 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -99,21 +99,36 @@ int removeOverlay(uint16 objIdx, uint16 param) { /*! \brief Add new overlay sprite to the list * \param objIdx Associate the overlay with this object - * \param param Type of new overlay + * \param type Type of new overlay * \todo Why are x, y, width and color left uninitialized? */ -void addOverlay(uint16 objIdx, uint16 param) { +void addOverlay(uint16 objIdx, uint16 type) { Common::List<overlay>::iterator it; overlay tmp; for (it = overlayList.begin(); it != overlayList.end(); ++it) { + // This is done for both Future Wars and Operation Stealth if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask) { break; } + + // There are additional checks in Operation Stealth's implementation + if (g_cine->getGameType() == Cine::GType_OS && (it->type == 2 || it->type == 3)) { + break; + } + } + + // In Operation Stealth's implementation we might bail out early + if (g_cine->getGameType() == Cine::GType_OS && it != overlayList.end() && it->objIdx == objIdx && it->type == type) { + return; } tmp.objIdx = objIdx; - tmp.type = param; + tmp.type = type; + tmp.x = 0; + tmp.y = 0; + tmp.width = 0; + tmp.color = 0; overlayList.insert(it, tmp); } @@ -122,24 +137,22 @@ void addOverlay(uint16 objIdx, uint16 param) { * \param objIdx Associate the overlay with this object * \param param source background index */ -void addGfxElementA0(int16 objIdx, int16 param) { +void addGfxElement(int16 objIdx, int16 param, int16 type) { Common::List<overlay>::iterator it; overlay tmp; for (it = overlayList.begin(); it != overlayList.end(); ++it) { - // wtf?! - if (objectTable[it->objIdx].mask == objectTable[objIdx].mask && - (it->type == 2 || it->type == 3)) { + if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask || it->type == 2 || it->type == 3) { break; } } - if (it != overlayList.end() && it->objIdx == objIdx && it->type == 20 && it->x == param) { + if (it != overlayList.end() && it->objIdx == objIdx && it->type == type && it->x == param) { return; } tmp.objIdx = objIdx; - tmp.type = 20; + tmp.type = type; tmp.x = param; tmp.y = 0; tmp.width = 0; @@ -153,11 +166,11 @@ void addGfxElementA0(int16 objIdx, int16 param) { * \param param Remove overlay using this background * \todo Check that it works */ -void removeGfxElementA0(int16 objIdx, int16 param) { +void removeGfxElement(int16 objIdx, int16 param, int16 type) { Common::List<overlay>::iterator it; for (it = overlayList.begin(); it != overlayList.end(); ++it) { - if (it->objIdx == objIdx && it->type == 20 && it->x == param) { + if (it->objIdx == objIdx && it->type == type && it->x == param) { overlayList.erase(it); return; } @@ -170,8 +183,12 @@ void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint1 objectTable[objIdx].mask = param3; objectTable[objIdx].frame = param4; - if (removeOverlay(objIdx, 0)) { - addOverlay(objIdx, 0); + if (g_cine->getGameType() == Cine::GType_OS) { + resetGfxEntityEntry(objIdx); + } else { // Future Wars + if (removeOverlay(objIdx, 0)) { + addOverlay(objIdx, 0); + } } } @@ -199,9 +216,12 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { case 3: objectTable[objIdx].mask = newValue; - // TODO: Check this part against disassembly - if (removeOverlay(objIdx, 0)) { - addOverlay(objIdx, 0); + if (g_cine->getGameType() == Cine::GType_OS) { // Operation Stealth specific + resetGfxEntityEntry(objIdx); + } else { // Future Wars specific + if (removeOverlay(objIdx, 0)) { + addOverlay(objIdx, 0); + } } break; case 4: @@ -221,6 +241,29 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { } } +/** + * Check if at least one of the range B's endpoints is inside range A, + * not counting the starting and ending points of range A. + * Used at least by Operation Stealth's opcode 0x8D i.e. 141. + */ +bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd) { + return (bStart > aStart && bStart < aEnd) || (bEnd > aStart && bEnd < aEnd); +} + +uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2) { + assert(objIdx1 < NUM_MAX_OBJECT && objIdx2 < NUM_MAX_OBJECT); + const objectStruct &obj1 = objectTable[objIdx1]; + const objectStruct &obj2 = objectTable[objIdx2]; + + if (compareRanges(obj1.x, obj1.x + xAdd1, obj2.x, obj2.x + xAdd2) && + compareRanges(obj1.y, obj1.y + yAdd1, obj2.y, obj2.y + yAdd2) && + compareRanges(obj1.mask, obj1.mask + maskAdd1, obj2.mask, obj2.mask + maskAdd2)) { + return kCmpEQ; + } else { + return 0; + } +} + uint16 compareObjectParam(byte objIdx, byte type, int16 value) { uint16 compareResult = 0; int16 objectParam = getObjectParam(objIdx, type); diff --git a/engines/cine/object.h b/engines/cine/object.h index e7de39649d..103b2f50ba 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -60,15 +60,17 @@ void loadObject(char *pObjectName); void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4); void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue); -void addOverlay(uint16 objIdx, uint16 param); +void addOverlay(uint16 objIdx, uint16 type); int removeOverlay(uint16 objIdx, uint16 param); -void addGfxElementA0(int16 objIdx, int16 param); -void removeGfxElementA0(int16 objIdx, int16 param); +void addGfxElement(int16 objIdx, int16 param, int16 type); +void removeGfxElement(int16 objIdx, int16 param, int16 type); int16 getObjectParam(uint16 objIdx, uint16 paramIdx); void addObjectParam(byte objIdx, byte paramIdx, int16 newValue); void subObjectParam(byte objIdx, byte paramIdx, int16 newValue); +bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd); +uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2); uint16 compareObjectParam(byte objIdx, byte param1, int16 param2); } // End of namespace Cine diff --git a/engines/cine/script.h b/engines/cine/script.h index eeac0e8809..fcd21990fa 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -237,7 +237,7 @@ protected: int o2_playSample(); int o2_playSampleAlt(); int o2_op81(); - int o2_op82(); + int o2_modifySeqListElement(); int o2_isSeqRunning(); int o2_gotoIfSupNearest(); int o2_gotoIfSupEquNearest(); @@ -258,10 +258,10 @@ protected: int o2_useBgScroll(); int o2_setAdditionalBgVScroll(); int o2_op9F(); - int o2_addGfxElementA0(); - int o2_removeGfxElementA0(); - int o2_opA2(); - int o2_opA3(); + int o2_addGfxElementType20(); + int o2_removeGfxElementType20(); + int o2_addGfxElementType21(); + int o2_removeGfxElementType21(); int o2_loadMask22(); int o2_unloadMask22(); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 845120c99e..148e673095 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1764,18 +1764,32 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI int16 lx = objectTable[objIdx].x + x; int16 ly = objectTable[objIdx].y + y; int16 idx; + int16 result = 0; for (int16 i = 0; i < numZones; i++) { idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320); - assert(idx >= 0 && idx <= NUM_MAX_ZONE); + assert(idx >= 0 && idx < NUM_MAX_ZONE); + + // The zoneQuery table is updated here only in Operation Stealth + if (g_cine->getGameType() == Cine::GType_OS) { + if (zoneData[idx] < NUM_MAX_ZONE) { + zoneQuery[zoneData[idx]]++; + } + } if (zoneData[idx] == zoneIdx) { - return 1; + result = 1; + // Future Wars breaks out early on the first match, but + // Operation Stealth doesn't because it needs to update + // the zoneQuery table for the whole loop's period. + if (g_cine->getGameType() == Cine::GType_FW) { + break; + } } } - return 0; + return result; } uint16 compareVars(int16 a, int16 b) { diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index 319fca5d3c..78b6c55564 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -202,7 +202,7 @@ const Opcode OSScript::_opcodeTable[] = { /* 80 */ { &FWScript::o2_removeSeq, "bb" }, { &FWScript::o2_op81, "" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_op82, "bbwwb" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_modifySeqListElement, "bbwwb" }, { &FWScript::o2_isSeqRunning, "bb" }, /* 84 */ { &FWScript::o2_gotoIfSupNearest, "b" }, @@ -240,10 +240,10 @@ const Opcode OSScript::_opcodeTable[] = { { &FWScript::o2_setAdditionalBgVScroll, "c" }, { &FWScript::o2_op9F, "ww" }, /* TODO: Name this opcode properly. */ /* A0 */ - { &FWScript::o2_addGfxElementA0, "ww" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_removeGfxElementA0, "ww" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_opA2, "ww" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_opA3, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_addGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_removeGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_addGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_removeGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */ /* A4 */ { &FWScript::o2_loadMask22, "b" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_unloadMask22, "b" }, /* TODO: Name this opcode properly. */ @@ -442,6 +442,7 @@ int FWScript::o2_removeSeq() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op81() { warning("STUB: o2_op81()"); @@ -449,23 +450,25 @@ int FWScript::o2_op81() { return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_op82() { +int FWScript::o2_modifySeqListElement() { byte a = getNextByte(); byte b = getNextByte(); uint16 c = getNextWord(); uint16 d = getNextWord(); byte e = getNextByte(); - warning("STUB: o2_op82(%x, %x, %x, %x, %x)", a, b, c, d, e); + debugC(5, kCineDebugScript, "Line: %d: o2_modifySeqListElement(%d,%d,%d,%d,%d)", _line, a, b, c, d, e); + + modifySeqListElement(a, 0, b, c, d, e); return 0; } +/*! \todo Check whether this opcode's name is backwards (i.e. should it be o2_isSeqNotRunning?) + */ int FWScript::o2_isSeqRunning() { byte a = getNextByte(); byte b = getNextByte(); - debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b); + debugC(5, kCineDebugScript, "Line: %d: o2_isSeqRunning(%d,%d)", _line, a, b); if (isSeqRunning(a, 0, b)) { _compare = 1; @@ -593,19 +596,18 @@ int FWScript::o2_stopObjectScript() { return 0; } -/*! \todo Implement this instruction - */ int FWScript::o2_op8D() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - uint16 c = getNextWord(); - uint16 d = getNextWord(); - uint16 e = getNextWord(); - uint16 f = getNextWord(); - uint16 g = getNextWord(); - uint16 h = getNextWord(); - warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h); - // _currentScriptElement->compareResult = ... + uint16 objIdx1 = getNextWord(); + uint16 xAdd1 = getNextWord(); + uint16 yAdd1 = getNextWord(); + uint16 maskAdd1 = getNextWord(); + uint16 objIdx2 = getNextWord(); + uint16 xAdd2 = getNextWord(); + uint16 yAdd2 = getNextWord(); + uint16 maskAdd2 = getNextWord(); + debugC(5, kCineDebugScript, "Line: %d: o2_op8D(%d, %d, %d, %d, %d, %d, %d, %d)", _line, objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2); + + _compare = compareObjectParamRanges(objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2); return 0; } @@ -649,16 +651,15 @@ int FWScript::o2_loadBg() { return 0; } -/*! \todo Check the current implementation for correctness - */ int FWScript::o2_wasZoneChecked() { byte param = getNextByte(); - _compare = (param < 16 && zoneData[param]); + _compare = (param < NUM_MAX_ZONE && zoneQuery[param]) ? 1 : 0; debugC(5, kCineDebugScript, "Line: %d: o2_wasZoneChecked(%d)", _line, param); return 0; } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9B() { uint16 a = getNextWord(); @@ -674,6 +675,7 @@ int FWScript::o2_op9B() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9C() { uint16 a = getNextWord(); @@ -713,6 +715,7 @@ int FWScript::o2_setAdditionalBgVScroll() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9F() { warning("o2_op9F()"); @@ -721,42 +724,36 @@ int FWScript::o2_op9F() { return 0; } -int FWScript::o2_addGfxElementA0() { +int FWScript::o2_addGfxElementType20() { uint16 param1 = getNextWord(); uint16 param2 = getNextWord(); - debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2); - addGfxElementA0(param1, param2); + debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType20(%d,%d)", _line, param1, param2); + addGfxElement(param1, param2, 20); return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_removeGfxElementA0() { +int FWScript::o2_removeGfxElementType20() { uint16 idx = getNextWord(); uint16 param = getNextWord(); - warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param); - removeGfxElementA0(idx, param); + debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType20(%d,%d)", _line, idx, param); + removeGfxElement(idx, param, 20); return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_opA2() { +int FWScript::o2_addGfxElementType21() { uint16 a = getNextWord(); uint16 b = getNextWord(); - warning("STUB: o2_opA2(%x, %x)", a, b); - // addGfxElementA2(); + debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType21(%d,%d)", _line, a, b); + addGfxElement(a, b, 21); return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_opA3() { +int FWScript::o2_removeGfxElementType21() { uint16 a = getNextWord(); uint16 b = getNextWord(); - warning("STUB: o2_opA3(%x, %x)", a, b); - // removeGfxElementA2(); + debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType21(%d,%d)", _line, a, b); + removeGfxElement(a, b, 21); return 0; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index bdad805785..46168b306c 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -94,6 +94,9 @@ int16 saveVar2; byte isInPause = 0; +// TODO: Implement inputVar0's changes in the program +// Currently inputVar0 isn't updated anywhere even though it's used at least in processSeqListElement. +uint16 inputVar0 = 0; byte inputVar1 = 0; uint16 inputVar2 = 0, inputVar3 = 0; @@ -110,6 +113,7 @@ CommandeType objectListCommand[20]; int16 objListTab[20]; uint16 zoneData[NUM_MAX_ZONE]; +uint16 zoneQuery[NUM_MAX_ZONE]; //!< Only exists in Operation Stealth void stopMusicAfterFadeOut(void) { @@ -130,6 +134,7 @@ void runObjectScript(int16 entryIdx) { */ void addPlayerCommandMessage(int16 cmd) { overlay tmp; + memset(&tmp, 0, sizeof(tmp)); tmp.objIdx = cmd; tmp.type = 3; @@ -389,6 +394,7 @@ bool brokenSave(Common::InSaveFile &fHandle) { } /*! \todo Implement Operation Stealth loading, this is obviously Future Wars only + * \todo Add support for loading the zoneQuery table (Operation Stealth specific) */ bool CineEngine::makeLoad(char *saveName) { int16 i; @@ -586,6 +592,8 @@ bool CineEngine::makeLoad(char *saveName) { return true; } +/*! \todo Add support for saving the zoneQuery table (Operation Stealth specific) + */ void makeSave(char *saveFileName) { int16 i; Common::OutSaveFile *fHandle; @@ -1580,16 +1588,19 @@ void removeSeq(uint16 param1, uint16 param2, uint16 param3) { } } -uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { +bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { Common::List<SeqListElement>::iterator it; for (it = seqList.begin(); it != seqList.end(); ++it) { if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) { - return 1; + // Just to be on the safe side there's a restriction of the + // addition's result to 16-bit arithmetic here like in the + // original. It's possible that it's not strictly needed. + return ((it->var14 + it->var16) & 0xFFFF) == 0; } } - return 0; + return true; } void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) { @@ -1616,6 +1627,19 @@ void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, i seqList.insert(it, tmp); } +void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4) { + // Find a suitable list element and modify it + for (Common::List<SeqListElement>::iterator it = seqList.begin(); it != seqList.end(); ++it) { + if (it->objIdx == objIdx && it->var4 == var4Test) { + it->varC = param1; + it->var18 = param2; + it->var1A = param3; + it->var10 = it->var12 = param4; + break; + } + } +} + void computeMove1(SeqListElement &element, int16 x, int16 y, int16 param1, int16 param2, int16 x2, int16 y2) { element.var16 = 0; @@ -1660,105 +1684,48 @@ uint16 computeMove2(SeqListElement &element) { return returnVar; } -// sort all the gfx stuff... - -void resetGfxEntityEntry(uint16 objIdx) { -#if 0 - overlayHeadElement* tempHead = &overlayHead; - byte* var_16 = NULL; - uint16 var_10 = 0; - uint16 var_12 = 0; - overlayHeadElement* currentHead = tempHead->next; - byte* var_1A = NULL; - overlayHeadElement* var1E = &overlayHead; - - while (currentHead) { - tempHead2 = currentHead->next; - - if (currentHead->objIdx == objIdx && currentHead->type!=2 && currentHead->type!=3 && currentHead->type!=0x14) { - tempHead->next = tempHead2; - - if (tempHead2) { - tempHead2->previous = currentHead->previous; - } else { - seqVar0 = currentHead->previous; - } - - var_22 = var_16; - - if (!var_22) { - // todo: goto? - } - - var_22->previous = currentHead; - } else { - } - - if (currentHead->type == 0x14) { - } else { - } - - if (currentHead->type == 0x2 || currentHead->type == 0x3) { - si = 10000; - } else { - si = objectTable[currentHead->objIdx]; - } - - if (objectTable[objIdx]>si) { - var1E = currentHead; - } - - tempHead = tempHead->next; - - } - - if (var_1A) { - currentHead = var_16; - var_22 = var_1E->next; - var_1E->next = currentHead; - var_1A->next = var_22; - - if (var_1E != &gfxEntityHead) { - currentHead->previous = var_1E; - } - - if (!var_22) { - seqVar0 = var_1A; - } else { - var_22->previous = var_1A; - } - - } -#endif -} - -uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &element, uint16 param3, int16 *param4) { - const byte *currentPtr = ptr; - const byte *ptrData; - const byte *ptr2; +uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &element, uint16 param3, int16 *param4) { + const int8 *ptrData; + const int8 *ptr2; int16 di; + // In the original an error string is set and 0 is returned if the following doesn't hold assert(ptr); - assert(param4); - - dummyU16 = READ_BE_UINT16((currentPtr + param1 * 2) + 8); + // We probably could just use a local variable here instead of the dummyU16 but + // haven't checked if this has any side-effects so keeping it this way still. + dummyU16 = READ_BE_UINT16(ptr + param1 * 2 + 8); ptrData = ptr + dummyU16; + // In the original an error string is set and 0 is returned if the following doesn't hold assert(*ptrData); di = (objectTable[objIdx].costume + 1) % (*ptrData); - ptr2 = (ptrData + (di * 8)) + 1; - + ++ptrData; // Jump over the just read byte + // Here ptr2 seems to be indexing a table of structs (8 bytes per struct): + // struct { + // int8 x; // 0 (Used with checkCollision) + // int8 y; // 1 (Used with checkCollision) + // int8 numZones; // 2 (Used with checkCollision) + // int8 var3; // 3 (Not used in this function) + // int8 xAdd; // 4 (Used with an object) + // int8 yAdd; // 5 (Used with an object) + // int8 maskAdd; // 6 (Used with an object) + // int8 frameAdd; // 7 (Used with an object) + // }; + ptr2 = ptrData + di * 8; + + // We might probably safely discard the AND by 1 here because + // at least in the original checkCollision returns always 0 or 1. if ((checkCollision(objIdx, ptr2[0], ptr2[1], ptr2[2], ptr[0]) & 1)) { return 0; } - objectTable[objIdx].x += (int8)ptr2[4]; - objectTable[objIdx].y += (int8)ptr2[5]; - objectTable[objIdx].mask += (int8)ptr2[6]; + objectTable[objIdx].x += ptr2[4]; + objectTable[objIdx].y += ptr2[5]; + objectTable[objIdx].mask += ptr2[6]; - if (objectTable[objIdx].frame) { + if (ptr2[6]) { resetGfxEntityEntry(objIdx); } @@ -1767,16 +1734,63 @@ uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &ele if (param3 || !element.var14) { objectTable[objIdx].costume = di; } else { + assert(param4); *param4 = di; } return 1; } +/*! + * Permutates the overlay list into a different order according to some logic. + * \todo Check this function for correctness (Wasn't very easy to reverse engineer so there may be errors) + */ +void resetGfxEntityEntry(uint16 objIdx) { + Common::List<overlay>::iterator it, bObjsCutPoint; + Common::List<overlay> aReverseObjs, bObjs; + bool foundCutPoint = false; + + // Go through the overlay list and partition the whole list into two categories (Type A and type B objects) + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + if (it->objIdx == objIdx && it->type != 2 && it->type != 3) { // Type A object + aReverseObjs.push_front(*it); + } else { // Type B object + bObjs.push_back(*it); + uint16 objectMask; + if (it->type == 2 || it->type == 3) { + objectMask = 10000; + } else { + objectMask = objectTable[it->objIdx].mask; + } + + if (objectTable[objIdx].mask > objectMask) { // Check for B objects' cut point + bObjsCutPoint = bObjs.reverse_begin(); + foundCutPoint = true; + } + } + } + + // Recreate the overlay list in a different order. + overlayList.clear(); + if (foundCutPoint) { + // If a cut point was found the order is: + // B objects before the cut point, the cut point, A objects in reverse order, B objects after cut point. + ++bObjsCutPoint; // Include the cut point in the first list insertion + overlayList.insert(overlayList.end(), bObjs.begin(), bObjsCutPoint); + overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); + overlayList.insert(overlayList.end(), bObjsCutPoint, bObjs.end()); + } else { + // If no cut point was found the order is: + // A objects in reverse order, B objects. + overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); + overlayList.insert(overlayList.end(), bObjs.begin(), bObjs.end()); + } +} + void processSeqListElement(SeqListElement &element) { int16 x = objectTable[element.objIdx].x; int16 y = objectTable[element.objIdx].y; - const byte *ptr1 = animDataTable[element.frame].data(); + const int8 *ptr1 = (const int8 *) animDataTable[element.frame].data(); int16 var_10; int16 var_4; int16 var_2; @@ -1789,22 +1803,44 @@ void processSeqListElement(SeqListElement &element) { element.var12 = 0; if (ptr1) { - uint16 param1 = ptr1[1]; - uint16 param2 = ptr1[2]; + int16 param1 = ptr1[1]; + int16 param2 = ptr1[2]; if (element.varC != 255) { - // FIXME: Why is this here? Fingolfin gets lots of these - // in his copy of Operation Stealth (value 0 or 236) under - // Mac OS X. Maybe it's a endian issue? At least the graphics - // in the copy protection screen are partially messed up. - warning("processSeqListElement: varC = %d", element.varC); - } - - if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) { - computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]); + int16 x2 = element.var18; + int16 y2 = element.var1A; + if (element.varC) { + x2 += objectTable[element.varC].x; + y2 += objectTable[element.varC].y; + } + computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, x2, y2); } else { - element.var16 = 0; - element.var14 = 0; + if (inputVar0 && allowPlayerInput) { + int16 adder = param1 + 1; + if (inputVar0 != 1) { + adder = -adder; + } + // FIXME: In Operation Stealth's disassembly global variable 251 is used here + // but it's named as VAR_MOUSE_Y_MODE in ScummVM. Is it correct or a + // left over from Future Wars's reverse engineering? + globalVars[VAR_MOUSE_X_POS] = globalVars[251] = ptr1[4] + x + adder; + } + + if (inputVar1 && allowPlayerInput) { + int16 adder = param2 + 1; + if (inputVar1 != 1) { + adder = -adder; + } + // TODO: Name currently unnamed global variable 252 + globalVars[VAR_MOUSE_Y_POS] = globalVars[252] = ptr1[5] + y + adder; + } + + if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) { + computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]); + } else { + element.var16 = 0; + element.var14 = 0; + } } var_10 = computeMove2(element); @@ -1845,14 +1881,14 @@ void processSeqListElement(SeqListElement &element) { } } - if (element.var16 + element.var14) { + if (element.var16 + element.var14 == 0) { if (element.var1C) { if (element.var1E) { objectTable[element.objIdx].costume = 0; element.var1E = 0; } - addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, (int16 *) & var2); + addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, &var_2); } } diff --git a/engines/cine/various.h b/engines/cine/various.h index f4d1649aab..3befde7eb8 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -128,16 +128,20 @@ struct SelectedObjStruct { #define NUM_MAX_ZONE 16 extern uint16 zoneData[NUM_MAX_ZONE]; +extern uint16 zoneQuery[NUM_MAX_ZONE]; void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5); void removeMessages(); void removeSeq(uint16 param1, uint16 param2, uint16 param3); -uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3); +bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3); void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8); +void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4); void processSeqList(void); +void resetGfxEntityEntry(uint16 objIdx); + bool makeTextEntryMenu(const char *caption, char *string, int strLen, int y); } // End of namespace Cine diff --git a/engines/cruise/cruise_main.h b/engines/cruise/cruise_main.h index 60afe5fa4c..c9c27ada49 100644 --- a/engines/cruise/cruise_main.h +++ b/engines/cruise/cruise_main.h @@ -28,7 +28,7 @@ #include <string.h> #include <stdlib.h> -#include <assert.h> +#include <assert.h> // FIXME: WINCE: this is not needed/not portable (probably applies to all above includes) #include "common/scummsys.h" diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index b0877a2e3e..06868494b5 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -372,7 +372,11 @@ void DrasculaEngine::animation_1_1() { break; clearRoom(); - playMusic(2); + if (_lang == kSpanish) + playMusic(31); + else + playMusic(2); + pause(5); playFLI("intro.bin", 12); term_int = 1; diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index 567d894b75..8bb73d8dd1 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -328,7 +328,7 @@ public: int curHeight, curWidth, feetHeight; int talkHeight, talkWidth; int floorX1, floorY1, floorX2, floorY2; - int near, far; + int lowerLimit, upperLimit; int trackFinal, walkToObject; int objExit; int timeDiff, startTime; diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 6fe28bdbdc..37dddf4b7e 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -1672,8 +1672,8 @@ void DrasculaEngine::enterRoom(int roomIndex) { getIntFromLine(buffer, size, &floorY2); if (currentChapter != 2) { - getIntFromLine(buffer, size, &far); - getIntFromLine(buffer, size, &near); + getIntFromLine(buffer, size, &upperLimit); + getIntFromLine(buffer, size, &lowerLimit); } _arj.close(); @@ -1732,27 +1732,27 @@ void DrasculaEngine::enterRoom(int roomIndex) { if (currentChapter != 2) { for (l = 0; l <= floorY1; l++) - factor_red[l] = far; + factor_red[l] = upperLimit; for (l = floorY1; l <= 201; l++) - factor_red[l] = near; + factor_red[l] = lowerLimit; - chiquez = (float)(near - far) / (float)(floorY2 - floorY1); + chiquez = (float)(lowerLimit - upperLimit) / (float)(floorY2 - floorY1); for (l = floorY1; l <= floorY2; l++) { - factor_red[l] = (int)(far + pequegnez); + factor_red[l] = (int)(upperLimit + pequegnez); pequegnez = pequegnez + chiquez; } } if (roomNumber == 24) { for (l = floorY1 - 1; l > 74; l--) { - factor_red[l] = (int)(far - pequegnez); + factor_red[l] = (int)(upperLimit - pequegnez); pequegnez = pequegnez + chiquez; } } if (currentChapter == 5 && roomNumber == 54) { for (l = floorY1 - 1; l > 84; l--) { - factor_red[l] = (int)(far - pequegnez); + factor_red[l] = (int)(upperLimit - pequegnez); pequegnez = pequegnez + chiquez; } } diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index 4d3187a0fd..a89c5ff734 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -60,7 +60,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { int x_talk1[8] = { 56, 86, 116, 146, 176, 206, 236, 266 }; int x_talk3[4] = { 80, 102, 124, 146 }; int x_talk4[4] = { 119, 158, 197, 236 }; - int face; + int face = 0; int length = strlen(said); color_abc(kColorWhite); diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 8351f2ecfb..63a0f8f45b 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -277,6 +277,19 @@ static const GOBGameDescription gameDescriptions[] = { kFeaturesNone, "intro" }, + { // Supplied by raina in the forums + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "6d837c6380d8f4d984c9f6cc0026df4f", 192712), + EN_ANY, + kPlatformMacintosh, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob1, + kFeaturesNone, + "intro" + }, { // Supplied by paul66 in bug report #1652352 { "gob1", diff --git a/engines/gob/driver_vga.cpp b/engines/gob/driver_vga.cpp index f68ce47783..2d3a10b570 100644 --- a/engines/gob/driver_vga.cpp +++ b/engines/gob/driver_vga.cpp @@ -112,7 +112,7 @@ void VGAVideoDriver::drawSprite(SurfaceDesc *source, SurfaceDesc *dest, if ((width < 1) || (height < 1)) return; - byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left; + const byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left; byte *destPos = dest->getVidMem() + (y * dest->getWidth()) + x; uint32 size = width * height; diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index e7aed0790e..5add0b9cea 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -78,58 +78,6 @@ Goblin::Goblin(GobEngine *vm) : _vm(vm) { _pressedMapY = 0; _pathExistence = 0; - _some0ValPtr = 0; - - _gobRetVarPtr = 0; - _curGobVarPtr = 0; - _curGobXPosVarPtr = 0; - _curGobYPosVarPtr = 0; - _itemInPocketVarPtr = 0; - - _curGobStateVarPtr = 0; - _curGobFrameVarPtr = 0; - _curGobMultStateVarPtr = 0; - _curGobNextStateVarPtr = 0; - _curGobScrXVarPtr = 0; - _curGobScrYVarPtr = 0; - _curGobLeftVarPtr = 0; - _curGobTopVarPtr = 0; - _curGobRightVarPtr = 0; - _curGobBottomVarPtr = 0; - _curGobDoAnimVarPtr = 0; - _curGobOrderVarPtr = 0; - _curGobNoTickVarPtr = 0; - _curGobTypeVarPtr = 0; - _curGobMaxTickVarPtr = 0; - _curGobTickVarPtr = 0; - _curGobActStartStateVarPtr = 0; - _curGobLookDirVarPtr = 0; - _curGobPickableVarPtr = 0; - _curGobRelaxVarPtr = 0; - _curGobMaxFrameVarPtr = 0; - - _destItemStateVarPtr = 0; - _destItemFrameVarPtr = 0; - _destItemMultStateVarPtr = 0; - _destItemNextStateVarPtr = 0; - _destItemScrXVarPtr = 0; - _destItemScrYVarPtr = 0; - _destItemLeftVarPtr = 0; - _destItemTopVarPtr = 0; - _destItemRightVarPtr = 0; - _destItemBottomVarPtr = 0; - _destItemDoAnimVarPtr = 0; - _destItemOrderVarPtr = 0; - _destItemNoTickVarPtr = 0; - _destItemTypeVarPtr = 0; - _destItemMaxTickVarPtr = 0; - _destItemTickVarPtr = 0; - _destItemActStartStVarPtr = 0; - _destItemLookDirVarPtr = 0; - _destItemPickableVarPtr = 0; - _destItemRelaxVarPtr = 0; - _destItemMaxFrameVarPtr = 0; - _destItemType = 0; _destItemState = 0; for (int i = 0; i < 20; i++) { @@ -690,7 +638,7 @@ void Goblin::switchGoblin(int16 index) { _gobDestY = tmp; _vm->_map->_curGoblinY = tmp; - *_curGobVarPtr = _currentGoblin; + _curGobVarPtr = (uint32) _currentGoblin; _pathExistence = 0; _readyToAct = 0; } @@ -1250,172 +1198,172 @@ void Goblin::loadObjects(const char *source) { void Goblin::saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal) { Gob_Object *obj; - *_some0ValPtr = someVal; - *_curGobXPosVarPtr = xPos; - *_curGobYPosVarPtr = yPos; - *_itemInPocketVarPtr = _itemIndInPocket; + _some0ValPtr = (uint32) someVal; + _curGobXPosVarPtr = (uint32) xPos; + _curGobYPosVarPtr = (uint32) yPos; + _itemInPocketVarPtr = (uint32) _itemIndInPocket; obj = _goblins[_currentGoblin]; - *_curGobStateVarPtr = obj->state; - *_curGobFrameVarPtr = obj->curFrame; - *_curGobMultStateVarPtr = obj->multState; - *_curGobNextStateVarPtr = obj->nextState; - *_curGobScrXVarPtr = obj->xPos; - *_curGobScrYVarPtr = obj->yPos; - *_curGobLeftVarPtr = obj->left; - *_curGobTopVarPtr = obj->top; - *_curGobRightVarPtr = obj->right; - *_curGobBottomVarPtr = obj->bottom; - *_curGobDoAnimVarPtr = obj->doAnim; - *_curGobOrderVarPtr = obj->order; - *_curGobNoTickVarPtr = obj->noTick; - *_curGobTypeVarPtr = obj->type; - *_curGobMaxTickVarPtr = obj->maxTick; - *_curGobTickVarPtr = obj->tick; - *_curGobActStartStateVarPtr = obj->actionStartState; - *_curGobLookDirVarPtr = obj->curLookDir; - *_curGobPickableVarPtr = obj->pickable; - *_curGobRelaxVarPtr = obj->relaxTime; - *_curGobMaxFrameVarPtr = getObjMaxFrame(obj); + _curGobStateVarPtr = (uint32) obj->state; + _curGobFrameVarPtr = (uint32) obj->curFrame; + _curGobMultStateVarPtr = (uint32) obj->multState; + _curGobNextStateVarPtr = (uint32) obj->nextState; + _curGobScrXVarPtr = (uint32) obj->xPos; + _curGobScrYVarPtr = (uint32) obj->yPos; + _curGobLeftVarPtr = (uint32) obj->left; + _curGobTopVarPtr = (uint32) obj->top; + _curGobRightVarPtr = (uint32) obj->right; + _curGobBottomVarPtr = (uint32) obj->bottom; + _curGobDoAnimVarPtr = (uint32) obj->doAnim; + _curGobOrderVarPtr = (uint32) obj->order; + _curGobNoTickVarPtr = (uint32) obj->noTick; + _curGobTypeVarPtr = (uint32) obj->type; + _curGobMaxTickVarPtr = (uint32) obj->maxTick; + _curGobTickVarPtr = (uint32) obj->tick; + _curGobActStartStateVarPtr = (uint32) obj->actionStartState; + _curGobLookDirVarPtr = (uint32) obj->curLookDir; + _curGobPickableVarPtr = (uint32) obj->pickable; + _curGobRelaxVarPtr = (uint32) obj->relaxTime; + _curGobMaxFrameVarPtr = (uint32) getObjMaxFrame(obj); if (_actDestItemDesc == 0) return; obj = _actDestItemDesc; - *_destItemStateVarPtr = obj->state; - *_destItemFrameVarPtr = obj->curFrame; - *_destItemMultStateVarPtr = obj->multState; - *_destItemNextStateVarPtr = obj->nextState; - *_destItemScrXVarPtr = obj->xPos; - *_destItemScrYVarPtr = obj->yPos; - *_destItemLeftVarPtr = obj->left; - *_destItemTopVarPtr = obj->top; - *_destItemRightVarPtr = obj->right; - *_destItemBottomVarPtr = obj->bottom; - *_destItemDoAnimVarPtr = obj->doAnim; - *_destItemOrderVarPtr = obj->order; - *_destItemNoTickVarPtr = obj->noTick; - *_destItemTypeVarPtr = obj->type; - *_destItemMaxTickVarPtr = obj->maxTick; - *_destItemTickVarPtr = obj->tick; - *_destItemActStartStVarPtr = obj->actionStartState; - *_destItemLookDirVarPtr = obj->curLookDir; - *_destItemPickableVarPtr = obj->pickable; - *_destItemRelaxVarPtr = obj->relaxTime; - *_destItemMaxFrameVarPtr = getObjMaxFrame(obj); + _destItemStateVarPtr = (uint32) obj->state; + _destItemFrameVarPtr = (uint32) obj->curFrame; + _destItemMultStateVarPtr = (uint32) obj->multState; + _destItemNextStateVarPtr = (uint32) obj->nextState; + _destItemScrXVarPtr = (uint32) obj->xPos; + _destItemScrYVarPtr = (uint32) obj->yPos; + _destItemLeftVarPtr = (uint32) obj->left; + _destItemTopVarPtr = (uint32) obj->top; + _destItemRightVarPtr = (uint32) obj->right; + _destItemBottomVarPtr = (uint32) obj->bottom; + _destItemDoAnimVarPtr = (uint32) obj->doAnim; + _destItemOrderVarPtr = (uint32) obj->order; + _destItemNoTickVarPtr = (uint32) obj->noTick; + _destItemTypeVarPtr = (uint32) obj->type; + _destItemMaxTickVarPtr = (uint32) obj->maxTick; + _destItemTickVarPtr = (uint32) obj->tick; + _destItemActStartStVarPtr = (uint32) obj->actionStartState; + _destItemLookDirVarPtr = (uint32) obj->curLookDir; + _destItemPickableVarPtr = (uint32) obj->pickable; + _destItemRelaxVarPtr = (uint32) obj->relaxTime; + _destItemMaxFrameVarPtr = (uint32) getObjMaxFrame(obj); _destItemState = obj->state; _destItemType = obj->type; } void Goblin::initVarPointers(void) { - _gobRetVarPtr = (int32 *)VAR_ADDRESS(59); - _curGobStateVarPtr = (int32 *)VAR_ADDRESS(60); - _curGobFrameVarPtr = (int32 *)VAR_ADDRESS(61); - _curGobMultStateVarPtr = (int32 *)VAR_ADDRESS(62); - _curGobNextStateVarPtr = (int32 *)VAR_ADDRESS(63); - _curGobScrXVarPtr = (int32 *)VAR_ADDRESS(64); - _curGobScrYVarPtr = (int32 *)VAR_ADDRESS(65); - _curGobLeftVarPtr = (int32 *)VAR_ADDRESS(66); - _curGobTopVarPtr = (int32 *)VAR_ADDRESS(67); - _curGobRightVarPtr = (int32 *)VAR_ADDRESS(68); - _curGobBottomVarPtr = (int32 *)VAR_ADDRESS(69); - _curGobDoAnimVarPtr = (int32 *)VAR_ADDRESS(70); - _curGobOrderVarPtr = (int32 *)VAR_ADDRESS(71); - _curGobNoTickVarPtr = (int32 *)VAR_ADDRESS(72); - _curGobTypeVarPtr = (int32 *)VAR_ADDRESS(73); - _curGobMaxTickVarPtr = (int32 *)VAR_ADDRESS(74); - _curGobTickVarPtr = (int32 *)VAR_ADDRESS(75); - _curGobActStartStateVarPtr = (int32 *)VAR_ADDRESS(76); - _curGobLookDirVarPtr = (int32 *)VAR_ADDRESS(77); - _curGobPickableVarPtr = (int32 *)VAR_ADDRESS(80); - _curGobRelaxVarPtr = (int32 *)VAR_ADDRESS(81); - _destItemStateVarPtr = (int32 *)VAR_ADDRESS(82); - _destItemFrameVarPtr = (int32 *)VAR_ADDRESS(83); - _destItemMultStateVarPtr = (int32 *)VAR_ADDRESS(84); - _destItemNextStateVarPtr = (int32 *)VAR_ADDRESS(85); - _destItemScrXVarPtr = (int32 *)VAR_ADDRESS(86); - _destItemScrYVarPtr = (int32 *)VAR_ADDRESS(87); - _destItemLeftVarPtr = (int32 *)VAR_ADDRESS(88); - _destItemTopVarPtr = (int32 *)VAR_ADDRESS(89); - _destItemRightVarPtr = (int32 *)VAR_ADDRESS(90); - _destItemBottomVarPtr = (int32 *)VAR_ADDRESS(91); - _destItemDoAnimVarPtr = (int32 *)VAR_ADDRESS(92); - _destItemOrderVarPtr = (int32 *)VAR_ADDRESS(93); - _destItemNoTickVarPtr = (int32 *)VAR_ADDRESS(94); - _destItemTypeVarPtr = (int32 *)VAR_ADDRESS(95); - _destItemMaxTickVarPtr = (int32 *)VAR_ADDRESS(96); - _destItemTickVarPtr = (int32 *)VAR_ADDRESS(97); - _destItemActStartStVarPtr = (int32 *)VAR_ADDRESS(98); - _destItemLookDirVarPtr = (int32 *)VAR_ADDRESS(99); - _destItemPickableVarPtr = (int32 *)VAR_ADDRESS(102); - _destItemRelaxVarPtr = (int32 *)VAR_ADDRESS(103); - _destItemMaxFrameVarPtr = (int32 *)VAR_ADDRESS(105); - _curGobVarPtr = (int32 *)VAR_ADDRESS(106); - _some0ValPtr = (int32 *)VAR_ADDRESS(107); - _curGobXPosVarPtr = (int32 *)VAR_ADDRESS(108); - _curGobYPosVarPtr = (int32 *)VAR_ADDRESS(109); - _curGobMaxFrameVarPtr = (int32 *)VAR_ADDRESS(110); - - _itemInPocketVarPtr = (int32 *)VAR_ADDRESS(114); - - *_itemInPocketVarPtr = -2; + _gobRetVarPtr.set(*_vm->_inter->_variables, 236); + _curGobStateVarPtr.set(*_vm->_inter->_variables, 240); + _curGobFrameVarPtr.set(*_vm->_inter->_variables, 244); + _curGobMultStateVarPtr.set(*_vm->_inter->_variables, 248); + _curGobNextStateVarPtr.set(*_vm->_inter->_variables, 252); + _curGobScrXVarPtr.set(*_vm->_inter->_variables, 256); + _curGobScrYVarPtr.set(*_vm->_inter->_variables, 260); + _curGobLeftVarPtr.set(*_vm->_inter->_variables, 264); + _curGobTopVarPtr.set(*_vm->_inter->_variables, 268); + _curGobRightVarPtr.set(*_vm->_inter->_variables, 272); + _curGobBottomVarPtr.set(*_vm->_inter->_variables, 276); + _curGobDoAnimVarPtr.set(*_vm->_inter->_variables, 280); + _curGobOrderVarPtr.set(*_vm->_inter->_variables, 284); + _curGobNoTickVarPtr.set(*_vm->_inter->_variables, 288); + _curGobTypeVarPtr.set(*_vm->_inter->_variables, 292); + _curGobMaxTickVarPtr.set(*_vm->_inter->_variables, 296); + _curGobTickVarPtr.set(*_vm->_inter->_variables, 300); + _curGobActStartStateVarPtr.set(*_vm->_inter->_variables, 304); + _curGobLookDirVarPtr.set(*_vm->_inter->_variables, 308); + _curGobPickableVarPtr.set(*_vm->_inter->_variables, 320); + _curGobRelaxVarPtr.set(*_vm->_inter->_variables, 324); + _destItemStateVarPtr.set(*_vm->_inter->_variables, 328); + _destItemFrameVarPtr.set(*_vm->_inter->_variables, 332); + _destItemMultStateVarPtr.set(*_vm->_inter->_variables, 336); + _destItemNextStateVarPtr.set(*_vm->_inter->_variables, 340); + _destItemScrXVarPtr.set(*_vm->_inter->_variables, 344); + _destItemScrYVarPtr.set(*_vm->_inter->_variables, 348); + _destItemLeftVarPtr.set(*_vm->_inter->_variables, 352); + _destItemTopVarPtr.set(*_vm->_inter->_variables, 356); + _destItemRightVarPtr.set(*_vm->_inter->_variables, 360); + _destItemBottomVarPtr.set(*_vm->_inter->_variables, 364); + _destItemDoAnimVarPtr.set(*_vm->_inter->_variables, 368); + _destItemOrderVarPtr.set(*_vm->_inter->_variables, 372); + _destItemNoTickVarPtr.set(*_vm->_inter->_variables, 376); + _destItemTypeVarPtr.set(*_vm->_inter->_variables, 380); + _destItemMaxTickVarPtr.set(*_vm->_inter->_variables, 384); + _destItemTickVarPtr.set(*_vm->_inter->_variables, 388); + _destItemActStartStVarPtr.set(*_vm->_inter->_variables, 392); + _destItemLookDirVarPtr.set(*_vm->_inter->_variables, 396); + _destItemPickableVarPtr.set(*_vm->_inter->_variables, 408); + _destItemRelaxVarPtr.set(*_vm->_inter->_variables, 412); + _destItemMaxFrameVarPtr.set(*_vm->_inter->_variables, 420); + _curGobVarPtr.set(*_vm->_inter->_variables, 424); + _some0ValPtr.set(*_vm->_inter->_variables, 428); + _curGobXPosVarPtr.set(*_vm->_inter->_variables, 432); + _curGobYPosVarPtr.set(*_vm->_inter->_variables, 436); + _curGobMaxFrameVarPtr.set(*_vm->_inter->_variables, 440); + + _itemInPocketVarPtr.set(*_vm->_inter->_variables, 456); + + _itemInPocketVarPtr = (uint32) -2; } void Goblin::loadGobDataFromVars(void) { Gob_Object *obj; - _itemIndInPocket = *_itemInPocketVarPtr; + _itemIndInPocket = (int32) _itemInPocketVarPtr; obj = _goblins[_currentGoblin]; - obj->state = *_curGobStateVarPtr; - obj->curFrame = *_curGobFrameVarPtr; - obj->multState = *_curGobMultStateVarPtr; - obj->nextState = *_curGobNextStateVarPtr; - obj->xPos = *_curGobScrXVarPtr; - obj->yPos = *_curGobScrYVarPtr; - obj->left = *_curGobLeftVarPtr; - obj->top = *_curGobTopVarPtr; - obj->right = *_curGobRightVarPtr; - obj->bottom = *_curGobBottomVarPtr; - obj->doAnim = *_curGobDoAnimVarPtr; - obj->order = *_curGobOrderVarPtr; - obj->noTick = *_curGobNoTickVarPtr; - obj->type = *_curGobTypeVarPtr; - obj->maxTick = *_curGobMaxTickVarPtr; - obj->tick = *_curGobTickVarPtr; - obj->actionStartState = *_curGobActStartStateVarPtr; - obj->curLookDir = *_curGobLookDirVarPtr; - obj->pickable = *_curGobPickableVarPtr; - obj->relaxTime = *_curGobRelaxVarPtr; + obj->state = (int32) _curGobStateVarPtr; + obj->curFrame = (int32) _curGobFrameVarPtr; + obj->multState = (int32) _curGobMultStateVarPtr; + obj->nextState = (int32) _curGobNextStateVarPtr; + obj->xPos = (int32) _curGobScrXVarPtr; + obj->yPos = (int32) _curGobScrYVarPtr; + obj->left = (int32) _curGobLeftVarPtr; + obj->top = (int32) _curGobTopVarPtr; + obj->right = (int32) _curGobRightVarPtr; + obj->bottom = (int32) _curGobBottomVarPtr; + obj->doAnim = (int32) _curGobDoAnimVarPtr; + obj->order = (int32) _curGobOrderVarPtr; + obj->noTick = (int32) _curGobNoTickVarPtr; + obj->type = (int32) _curGobTypeVarPtr; + obj->maxTick = (int32) _curGobMaxTickVarPtr; + obj->tick = (int32) _curGobTickVarPtr; + obj->actionStartState = (int32) _curGobActStartStateVarPtr; + obj->curLookDir = (int32) _curGobLookDirVarPtr; + obj->pickable = (int32) _curGobPickableVarPtr; + obj->relaxTime = (int32) _curGobRelaxVarPtr; if (_actDestItemDesc == 0) return; obj = _actDestItemDesc; - obj->state = *_destItemStateVarPtr; - obj->curFrame = *_destItemFrameVarPtr; - obj->multState = *_destItemMultStateVarPtr; - obj->nextState = *_destItemNextStateVarPtr; - obj->xPos = *_destItemScrXVarPtr; - obj->yPos = *_destItemScrYVarPtr; - obj->left = *_destItemLeftVarPtr; - obj->top = *_destItemTopVarPtr; - obj->right = *_destItemRightVarPtr; - obj->bottom = *_destItemBottomVarPtr; - obj->doAnim = *_destItemDoAnimVarPtr; - obj->order = *_destItemOrderVarPtr; - obj->noTick = *_destItemNoTickVarPtr; - obj->type = *_destItemTypeVarPtr; - obj->maxTick = *_destItemMaxTickVarPtr; - obj->tick = *_destItemTickVarPtr; - obj->actionStartState = *_destItemActStartStVarPtr; - obj->curLookDir = *_destItemLookDirVarPtr; - obj->pickable = *_destItemPickableVarPtr; - obj->relaxTime = *_destItemRelaxVarPtr; + obj->state = (int32) _destItemStateVarPtr; + obj->curFrame = (int32) _destItemFrameVarPtr; + obj->multState = (int32) _destItemMultStateVarPtr; + obj->nextState = (int32) _destItemNextStateVarPtr; + obj->xPos = (int32) _destItemScrXVarPtr; + obj->yPos = (int32) _destItemScrYVarPtr; + obj->left = (int32) _destItemLeftVarPtr; + obj->top = (int32) _destItemTopVarPtr; + obj->right = (int32) _destItemRightVarPtr; + obj->bottom = (int32) _destItemBottomVarPtr; + obj->doAnim = (int32) _destItemDoAnimVarPtr; + obj->order = (int32) _destItemOrderVarPtr; + obj->noTick = (int32) _destItemNoTickVarPtr; + obj->type = (int32) _destItemTypeVarPtr; + obj->maxTick = (int32) _destItemMaxTickVarPtr; + obj->tick = (int32) _destItemTickVarPtr; + obj->actionStartState = (int32) _destItemActStartStVarPtr; + obj->curLookDir = (int32) _destItemLookDirVarPtr; + obj->pickable = (int32) _destItemPickableVarPtr; + obj->relaxTime = (int32) _destItemRelaxVarPtr; if (obj->type != _destItemType) obj->toRedraw = 1; diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h index 3fd8a9f93b..2100bcbdac 100644 --- a/engines/gob/goblin.h +++ b/engines/gob/goblin.h @@ -28,6 +28,7 @@ #include "gob/util.h" #include "gob/mult.h" +#include "gob/variables.h" #include "gob/sound/sounddesc.h" namespace Gob { @@ -115,57 +116,57 @@ public: char _pathExistence; // Pointers to interpreter variables - int32 *_some0ValPtr; - - int32 *_gobRetVarPtr; - int32 *_curGobVarPtr; - int32 *_curGobXPosVarPtr; - int32 *_curGobYPosVarPtr; - int32 *_itemInPocketVarPtr; - - int32 *_curGobStateVarPtr; - int32 *_curGobFrameVarPtr; - int32 *_curGobMultStateVarPtr; - int32 *_curGobNextStateVarPtr; - int32 *_curGobScrXVarPtr; - int32 *_curGobScrYVarPtr; - int32 *_curGobLeftVarPtr; - int32 *_curGobTopVarPtr; - int32 *_curGobRightVarPtr; - int32 *_curGobBottomVarPtr; - int32 *_curGobDoAnimVarPtr; - int32 *_curGobOrderVarPtr; - int32 *_curGobNoTickVarPtr; - int32 *_curGobTypeVarPtr; - int32 *_curGobMaxTickVarPtr; - int32 *_curGobTickVarPtr; - int32 *_curGobActStartStateVarPtr; - int32 *_curGobLookDirVarPtr; - int32 *_curGobPickableVarPtr; - int32 *_curGobRelaxVarPtr; - int32 *_curGobMaxFrameVarPtr; - - int32 *_destItemStateVarPtr; - int32 *_destItemFrameVarPtr; - int32 *_destItemMultStateVarPtr; - int32 *_destItemNextStateVarPtr; - int32 *_destItemScrXVarPtr; - int32 *_destItemScrYVarPtr; - int32 *_destItemLeftVarPtr; - int32 *_destItemTopVarPtr; - int32 *_destItemRightVarPtr; - int32 *_destItemBottomVarPtr; - int32 *_destItemDoAnimVarPtr; - int32 *_destItemOrderVarPtr; - int32 *_destItemNoTickVarPtr; - int32 *_destItemTypeVarPtr; - int32 *_destItemMaxTickVarPtr; - int32 *_destItemTickVarPtr; - int32 *_destItemActStartStVarPtr; - int32 *_destItemLookDirVarPtr; - int32 *_destItemPickableVarPtr; - int32 *_destItemRelaxVarPtr; - int32 *_destItemMaxFrameVarPtr; + VariableReference _some0ValPtr; + + VariableReference _gobRetVarPtr; + VariableReference _curGobVarPtr; + VariableReference _curGobXPosVarPtr; + VariableReference _curGobYPosVarPtr; + VariableReference _itemInPocketVarPtr; + + VariableReference _curGobStateVarPtr; + VariableReference _curGobFrameVarPtr; + VariableReference _curGobMultStateVarPtr; + VariableReference _curGobNextStateVarPtr; + VariableReference _curGobScrXVarPtr; + VariableReference _curGobScrYVarPtr; + VariableReference _curGobLeftVarPtr; + VariableReference _curGobTopVarPtr; + VariableReference _curGobRightVarPtr; + VariableReference _curGobBottomVarPtr; + VariableReference _curGobDoAnimVarPtr; + VariableReference _curGobOrderVarPtr; + VariableReference _curGobNoTickVarPtr; + VariableReference _curGobTypeVarPtr; + VariableReference _curGobMaxTickVarPtr; + VariableReference _curGobTickVarPtr; + VariableReference _curGobActStartStateVarPtr; + VariableReference _curGobLookDirVarPtr; + VariableReference _curGobPickableVarPtr; + VariableReference _curGobRelaxVarPtr; + VariableReference _curGobMaxFrameVarPtr; + + VariableReference _destItemStateVarPtr; + VariableReference _destItemFrameVarPtr; + VariableReference _destItemMultStateVarPtr; + VariableReference _destItemNextStateVarPtr; + VariableReference _destItemScrXVarPtr; + VariableReference _destItemScrYVarPtr; + VariableReference _destItemLeftVarPtr; + VariableReference _destItemTopVarPtr; + VariableReference _destItemRightVarPtr; + VariableReference _destItemBottomVarPtr; + VariableReference _destItemDoAnimVarPtr; + VariableReference _destItemOrderVarPtr; + VariableReference _destItemNoTickVarPtr; + VariableReference _destItemTypeVarPtr; + VariableReference _destItemMaxTickVarPtr; + VariableReference _destItemTickVarPtr; + VariableReference _destItemActStartStVarPtr; + VariableReference _destItemLookDirVarPtr; + VariableReference _destItemPickableVarPtr; + VariableReference _destItemRelaxVarPtr; + VariableReference _destItemMaxFrameVarPtr; int16 _destItemType; int16 _destItemState; diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp index 9144e35070..d763aeb01c 100644 --- a/engines/gob/goblin_v2.cpp +++ b/engines/gob/goblin_v2.cpp @@ -88,7 +88,7 @@ void Goblin_v2::placeObject(Gob_Object *objDesc, char animated, (_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (y + 1) / 2; *obj->pPosX = x * _vm->_map->_tilesWidth; } else { - if (obj->goblinStates[state] != 0) { + if ((obj->goblinStates != 0) && (obj->goblinStates[state] != 0)) { layer = obj->goblinStates[state][0].layer; animation = obj->goblinStates[state][0].animation; objAnim->state = state; diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index ecba1c1a20..c0a1bfc21a 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -212,25 +212,35 @@ void Inter::funcBlock(int16 retFlag) { break; // WORKAROUND: - // The EGA version of gob1 doesn't add a delay after showing + // The EGA and Mac versions of gob1 doesn't add a delay after showing // images between levels. We manually add it here. - if ((_vm->getGameType() == kGameTypeGob1) && _vm->isEGA()) { + if ((_vm->getGameType() == kGameTypeGob1) && + (_vm->isEGA() || (_vm->getPlatform() == Common::kPlatformMacintosh))) { + int addr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData; - if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie + + if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie, EGA + !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || + (startaddr == 0x188D && addr == 0x1A58 && // Zombie, Mac !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || (startaddr == 0x1299 && addr == 0x139A && // Dungeon !strncmp(_vm->_game->_curTotFile, "avt006.tot", 10)) || - (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron + (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron, EGA + !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) || + (startaddr == 0x11C8 && addr == 0x1341 && // Cauldron, Mac !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) || (startaddr == 0x09F2 && addr == 0x0AF3 && // Statue !strncmp(_vm->_game->_curTotFile, "avt016.tot", 10)) || (startaddr == 0x0B92 && addr == 0x0C93 && // Castle !strncmp(_vm->_game->_curTotFile, "avt019.tot", 10)) || - (startaddr == 0x17D9 && addr == 0x18DA && // Finale + (startaddr == 0x17D9 && addr == 0x18DA && // Finale, EGA + !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10)) || + (startaddr == 0x17E9 && addr == 0x19A8 && // Finale, Mac !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10))) { _vm->_util->longDelay(5000); } + } // End of workaround cmd = *_vm->_global->_inter_execPtr; diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 60b3974d6d..b684be6c07 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -79,7 +79,7 @@ protected: }; struct OpGobParams { int16 extraData; - int32 *retVarPtr; + VariableReference retVarPtr; Goblin::Gob_Object *objDesc; }; diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 6a52770ad1..cc114f0afc 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -912,12 +912,21 @@ void Inter_v1::o1_initMult() { animDataVar = _vm->_parse->parseVarIndex(); if (_vm->_mult->_objects && (oldObjCount != _vm->_mult->_objCount)) { + warning("Initializing new objects without having " "cleaned up the old ones at first"); + + for (int i = 0; i < _vm->_mult->_objCount; i++) { + delete _vm->_mult->_objects[i].pPosX; + delete _vm->_mult->_objects[i].pPosY; + } + delete[] _vm->_mult->_objects; delete[] _vm->_mult->_renderData; + _vm->_mult->_objects = 0; _vm->_mult->_renderObjs = 0; + } if (_vm->_mult->_objects == 0) { @@ -933,8 +942,8 @@ void Inter_v1::o1_initMult() { uint32 offPosY = i * 4 + (posYVar / 4) * 4; uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; - _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX); - _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY); + _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX); + _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); _vm->_mult->_objects[i].pAnimData = (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, @@ -1774,7 +1783,7 @@ bool Inter_v1::o1_goblinFunc(OpFuncParams ¶ms) { gobParams.extraData = 0; gobParams.objDesc = 0; - gobParams.retVarPtr = (int32 *) VAR_ADDRESS(59); + gobParams.retVarPtr.set(*_vm->_inter->_variables, 236); cmd = load16(); _vm->_global->_inter_execPtr += 2; @@ -2268,49 +2277,49 @@ bool Inter_v1::o1_manageDataFile(OpFuncParams ¶ms) { void Inter_v1::o1_setState(OpGobParams ¶ms) { params.objDesc->state = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemStateVarPtr = params.extraData; + _vm->_goblin->_destItemStateVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setCurFrame(OpGobParams ¶ms) { params.objDesc->curFrame = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemFrameVarPtr = params.extraData; + _vm->_goblin->_destItemFrameVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setNextState(OpGobParams ¶ms) { params.objDesc->nextState = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemNextStateVarPtr = params.extraData; + _vm->_goblin->_destItemNextStateVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setMultState(OpGobParams ¶ms) { params.objDesc->multState = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemMultStateVarPtr = params.extraData; + _vm->_goblin->_destItemMultStateVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setOrder(OpGobParams ¶ms) { params.objDesc->order = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemOrderVarPtr = params.extraData; + _vm->_goblin->_destItemOrderVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setActionStartState(OpGobParams ¶ms) { params.objDesc->actionStartState = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemActStartStVarPtr = params.extraData; + _vm->_goblin->_destItemActStartStVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setCurLookDir(OpGobParams ¶ms) { params.objDesc->curLookDir = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemLookDirVarPtr = params.extraData; + _vm->_goblin->_destItemLookDirVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setType(OpGobParams ¶ms) { params.objDesc->type = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemTypeVarPtr = params.extraData; + _vm->_goblin->_destItemTypeVarPtr = (uint32) params.extraData; if (params.extraData == 0) params.objDesc->toRedraw = 1; @@ -2319,107 +2328,107 @@ void Inter_v1::o1_setType(OpGobParams ¶ms) { void Inter_v1::o1_setNoTick(OpGobParams ¶ms) { params.objDesc->noTick = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemNoTickVarPtr = params.extraData; + _vm->_goblin->_destItemNoTickVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setPickable(OpGobParams ¶ms) { params.objDesc->pickable = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemPickableVarPtr = params.extraData; + _vm->_goblin->_destItemPickableVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setXPos(OpGobParams ¶ms) { params.objDesc->xPos = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemScrXVarPtr = params.extraData; + _vm->_goblin->_destItemScrXVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setYPos(OpGobParams ¶ms) { params.objDesc->yPos = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemScrYVarPtr = params.extraData; + _vm->_goblin->_destItemScrYVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setDoAnim(OpGobParams ¶ms) { params.objDesc->doAnim = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemDoAnimVarPtr = params.extraData; + _vm->_goblin->_destItemDoAnimVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setRelaxTime(OpGobParams ¶ms) { params.objDesc->relaxTime = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemRelaxVarPtr = params.extraData; + _vm->_goblin->_destItemRelaxVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setMaxTick(OpGobParams ¶ms) { params.objDesc->maxTick = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemMaxTickVarPtr = params.extraData; + _vm->_goblin->_destItemMaxTickVarPtr = (uint32) params.extraData; } void Inter_v1::o1_getState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->state; + params.retVarPtr = (uint32) params.objDesc->state; } void Inter_v1::o1_getCurFrame(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->curFrame; + params.retVarPtr = (uint32) params.objDesc->curFrame; } void Inter_v1::o1_getNextState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->nextState; + params.retVarPtr = (uint32) params.objDesc->nextState; } void Inter_v1::o1_getMultState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->multState; + params.retVarPtr = (uint32) params.objDesc->multState; } void Inter_v1::o1_getOrder(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->order; + params.retVarPtr = (uint32) params.objDesc->order; } void Inter_v1::o1_getActionStartState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->actionStartState; + params.retVarPtr = (uint32) params.objDesc->actionStartState; } void Inter_v1::o1_getCurLookDir(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->curLookDir; + params.retVarPtr = (uint32) params.objDesc->curLookDir; } void Inter_v1::o1_getType(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->type; + params.retVarPtr = (uint32) params.objDesc->type; } void Inter_v1::o1_getNoTick(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->noTick; + params.retVarPtr = (uint32) params.objDesc->noTick; } void Inter_v1::o1_getPickable(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->pickable; + params.retVarPtr = (uint32) params.objDesc->pickable; } void Inter_v1::o1_getObjMaxFrame(OpGobParams ¶ms) { - *params.retVarPtr = _vm->_goblin->getObjMaxFrame(params.objDesc); + params.retVarPtr = (uint32) _vm->_goblin->getObjMaxFrame(params.objDesc); } void Inter_v1::o1_getXPos(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->xPos; + params.retVarPtr = (uint32) params.objDesc->xPos; } void Inter_v1::o1_getYPos(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->yPos; + params.retVarPtr = (uint32) params.objDesc->yPos; } void Inter_v1::o1_getDoAnim(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->doAnim; + params.retVarPtr = (uint32) params.objDesc->doAnim; } void Inter_v1::o1_getRelaxTime(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->relaxTime; + params.retVarPtr = (uint32) params.objDesc->relaxTime; } void Inter_v1::o1_getMaxTick(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->maxTick; + params.retVarPtr = (uint32) params.objDesc->maxTick; } void Inter_v1::o1_manipulateMap(OpGobParams ¶ms) { @@ -2435,9 +2444,9 @@ void Inter_v1::o1_getItem(OpGobParams ¶ms) { int16 yPos = load16(); if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - *params.retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8; + params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); else - *params.retVarPtr = _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; } void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { @@ -2460,9 +2469,9 @@ void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) { yPos = VAR(yPos); if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - *params.retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8; + params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); else - *params.retVarPtr = _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; } void Inter_v1::o1_setPassMap(OpGobParams ¶ms) { @@ -2500,11 +2509,11 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams ¶ms) { params.objDesc->curFrame = 0; params.objDesc->state = 21; if (_vm->_goblin->_currentGoblin == item) { - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = 18; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = 18; _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x; _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y; } @@ -2512,12 +2521,12 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams ¶ms) { void Inter_v1::o1_getGoblinPosXH(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].x >> 1; + params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].x >> 1); } void Inter_v1::o1_getGoblinPosYH(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].y >> 1; + params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].y >> 1); } void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { @@ -2539,14 +2548,14 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { params.objDesc->xPos = animLayer->posX; params.objDesc->yPos = animLayer->posY; - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = params.objDesc->state; - *_vm->_goblin->_curGobNextStateVarPtr = params.objDesc->nextState; - *_vm->_goblin->_curGobMultStateVarPtr = params.objDesc->multState; - *_vm->_goblin->_curGobMaxFrameVarPtr = - _vm->_goblin->getObjMaxFrame(params.objDesc); + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = (uint32) params.objDesc->state; + _vm->_goblin->_curGobNextStateVarPtr = (uint32) params.objDesc->nextState; + _vm->_goblin->_curGobMultStateVarPtr = (uint32) params.objDesc->multState; + _vm->_goblin->_curGobMaxFrameVarPtr = + (uint32) _vm->_goblin->getObjMaxFrame(params.objDesc); _vm->_goblin->_noPick = 1; return; } @@ -2573,12 +2582,12 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { _vm->_goblin->_pressedMapY = yPos; _vm->_map->_curGoblinY = yPos; - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = 21; - *_vm->_goblin->_curGobNextStateVarPtr = 21; - *_vm->_goblin->_curGobMultStateVarPtr = -1; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = 21; + _vm->_goblin->_curGobNextStateVarPtr = 21; + _vm->_goblin->_curGobMultStateVarPtr = (uint32) -1; _vm->_goblin->_noPick = 0; } @@ -2598,11 +2607,11 @@ void Inter_v1::o1_setItemIndInPocket(OpGobParams ¶ms) { } void Inter_v1::o1_getItemIdInPocket(OpGobParams ¶ms) { - *params.retVarPtr = _vm->_goblin->_itemIdInPocket; + params.retVarPtr = (uint32) _vm->_goblin->_itemIdInPocket; } void Inter_v1::o1_getItemIndInPocket(OpGobParams ¶ms) { - *params.retVarPtr = _vm->_goblin->_itemIndInPocket; + params.retVarPtr = (uint32) _vm->_goblin->_itemIndInPocket; } void Inter_v1::o1_setGoblinPos(OpGobParams ¶ms) { @@ -2632,10 +2641,10 @@ void Inter_v1::o1_setGoblinPos(OpGobParams ¶ms) { params.objDesc->state = 21; if (_vm->_goblin->_currentGoblin == item) { - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = 18; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = 18; _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x; _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y; @@ -2659,11 +2668,11 @@ void Inter_v1::o1_setGoblinState(OpGobParams ¶ms) { params.objDesc->yPos = animLayer->posY; if (item == _vm->_goblin->_currentGoblin) { - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = params.objDesc->state; - *_vm->_goblin->_curGobMultStateVarPtr = params.objDesc->multState; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = (uint32) params.objDesc->state; + _vm->_goblin->_curGobMultStateVarPtr = (uint32) params.objDesc->multState; } } @@ -2686,13 +2695,13 @@ void Inter_v1::o1_setGoblinStateRedraw(OpGobParams ¶ms) { params.objDesc->toRedraw = 1; params.objDesc->type = 0; if (params.objDesc == _vm->_goblin->_actDestItemDesc) { - *_vm->_goblin->_destItemScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_destItemScrYVarPtr = params.objDesc->yPos; + _vm->_goblin->_destItemScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_destItemScrYVarPtr = (uint32) params.objDesc->yPos; - *_vm->_goblin->_destItemStateVarPtr = params.objDesc->state; - *_vm->_goblin->_destItemNextStateVarPtr = -1; - *_vm->_goblin->_destItemMultStateVarPtr = -1; - *_vm->_goblin->_destItemFrameVarPtr = 0; + _vm->_goblin->_destItemStateVarPtr = (uint32) params.objDesc->state; + _vm->_goblin->_destItemNextStateVarPtr = (uint32) -1; + _vm->_goblin->_destItemMultStateVarPtr = (uint32) -1; + _vm->_goblin->_destItemFrameVarPtr = 0; } } @@ -2712,12 +2721,12 @@ void Inter_v1::o1_decRelaxTime(OpGobParams ¶ms) { void Inter_v1::o1_getGoblinPosX(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].x; + params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].x; } void Inter_v1::o1_getGoblinPosY(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].y; + params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].y; } void Inter_v1::o1_clearPathExistence(OpGobParams ¶ms) { @@ -2741,9 +2750,9 @@ void Inter_v1::o1_getObjectIntersect(OpGobParams ¶ms) { params.objDesc = _vm->_goblin->_objects[params.extraData]; if (_vm->_goblin->objIntersected(params.objDesc, _vm->_goblin->_goblins[item])) - *params.retVarPtr = 1; + params.retVarPtr = 1; else - *params.retVarPtr = 0; + params.retVarPtr = 0; } void Inter_v1::o1_getGoblinIntersect(OpGobParams ¶ms) { @@ -2753,9 +2762,9 @@ void Inter_v1::o1_getGoblinIntersect(OpGobParams ¶ms) { params.objDesc = _vm->_goblin->_goblins[params.extraData]; if (_vm->_goblin->objIntersected(params.objDesc, _vm->_goblin->_goblins[item])) - *params.retVarPtr = 1; + params.retVarPtr = 1; else - *params.retVarPtr = 0; + params.retVarPtr = 0; } void Inter_v1::o1_setItemPos(OpGobParams ¶ms) { @@ -2886,7 +2895,7 @@ void Inter_v1::o1_initGoblin(OpGobParams ¶ms) { _vm->_map->_destY = _vm->_goblin->_gobPositions[0].y; _vm->_goblin->_gobDestY = _vm->_goblin->_gobPositions[0].y; - *_vm->_goblin->_curGobVarPtr = 0; + _vm->_goblin->_curGobVarPtr = 0; _vm->_goblin->_pathExistence = 0; _vm->_goblin->_readyToAct = 0; } diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index ae7aaa662d..b245001653 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -881,9 +881,15 @@ void Inter_v2::o2_initMult() { _vm->_mult->clearObjectVideos(); + for (int i = 0; i < _vm->_mult->_objCount; i++) { + delete _vm->_mult->_objects[i].pPosX; + delete _vm->_mult->_objects[i].pPosY; + } + delete[] _vm->_mult->_objects; delete[] _vm->_mult->_renderObjs; delete[] _vm->_mult->_orderArray; + _vm->_mult->_objects = 0; _vm->_mult->_renderObjs = 0; _vm->_mult->_orderArray = 0; @@ -908,8 +914,8 @@ void Inter_v2::o2_initMult() { uint32 offPosY = i * 4 + (posYVar / 4) * 4; uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; - _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX); - _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY); + _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX); + _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); _vm->_mult->_objects[i].pAnimData = (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, @@ -1047,7 +1053,7 @@ void Inter_v2::o2_loadMultObject() { } else if ((objAnim.animType != 100) && (objAnim.animType != 101)) { - if ((*(obj.pPosX) == -1234) && (*(obj.pPosY) == -4321)) { + if ((((int32) *(obj.pPosX)) == -1234) && (((int32) *(obj.pPosY)) == -4321)) { if (obj.videoSlot > 0) _vm->_vidPlayer->slotClose(obj.videoSlot - 1); diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index 46a903fd34..a502e92188 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -93,12 +93,18 @@ Mult::Mult(GobEngine *vm) : _vm(vm) { } Mult::~Mult() { + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _orderArray; delete[] _renderData; delete[] _renderObjs; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; delete _multData; } @@ -123,6 +129,12 @@ void Mult::freeAll(void) { void Mult::freeMult() { clearObjectVideos(); + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _renderData; delete[] _renderObjs; @@ -203,11 +215,17 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, if (_animDataAllocated) { clearObjectVideos(); + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _renderData; delete[] _renderObjs; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; delete[] _orderArray; diff --git a/engines/gob/mult.h b/engines/gob/mult.h index aaf2e2826c..3bb3af17b3 100644 --- a/engines/gob/mult.h +++ b/engines/gob/mult.h @@ -27,6 +27,7 @@ #define GOB_MULT_H #include "gob/video.h" +#include "gob/variables.h" namespace Gob { @@ -77,8 +78,8 @@ public: } PACKED_STRUCT; struct Mult_Object { - int32 *pPosX; - int32 *pPosY; + VariableReference *pPosX; + VariableReference *pPosY; Mult_AnimData *pAnimData; int16 tick; int16 lastLeft; @@ -267,8 +268,8 @@ protected: bool _doPalSubst; - int32 *_animArrayX; - int32 *_animArrayY; + Variables *_animArrayX; + Variables *_animArrayY; Mult_AnimData *_animArrayData; int16 _palKeyIndex; diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp index 22683437e7..a369e7d297 100644 --- a/engines/gob/mult_v1.cpp +++ b/engines/gob/mult_v1.cpp @@ -216,10 +216,16 @@ void Mult_v1::freeMultKeys() { if (_animDataAllocated) { clearObjectVideos(); + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _renderData; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _objects = 0; @@ -263,6 +269,14 @@ void Mult_v1::playMultInit() { _oldPalette = _vm->_global->_pPaletteDesc->vgaPal; if (!_animSurf) { + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + + delete[] _objects; + _vm->_util->setFrameRate(_multData->frameRate); _animTop = 0; _animLeft = 0; @@ -270,30 +284,27 @@ void Mult_v1::playMultInit() { _animHeight = 200; _objCount = 4; - delete[] _objects; delete[] _renderData; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _objects = new Mult_Object[_objCount]; _renderData = new int16[9 * _objCount]; - _animArrayX = new int32[_objCount]; - _animArrayY = new int32[_objCount]; + _animArrayX = new VariablesLE(_objCount * 4); + _animArrayY = new VariablesLE(_objCount * 4); _animArrayData = new Mult_AnimData[_objCount]; memset(_objects, 0, _objCount * sizeof(Mult_Object)); memset(_renderData, 0, _objCount * 9 * sizeof(int16)); - memset(_animArrayX, 0, _objCount * sizeof(int32)); - memset(_animArrayY, 0, _objCount * sizeof(int32)); memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData)); for (_counter = 0; _counter < _objCount; _counter++) { Mult_Object &multObj = _objects[_counter]; Mult_AnimData &animData = _animArrayData[_counter]; - multObj.pPosX = (int32 *) &_animArrayX[_counter]; - multObj.pPosY = (int32 *) &_animArrayY[_counter]; + multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4); + multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4); multObj.pAnimData = &animData; animData.isStatic = 1; diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 3a83ac1867..20a81174e5 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -329,8 +329,8 @@ void Mult_v2::freeMultKeys() { if (_animDataAllocated) { freeMult(); - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _animArrayX = 0; @@ -510,6 +510,13 @@ void Mult_v2::playMultInit() { if (!_animSurf) { int16 width, height; + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + + delete[] _objects; + _vm->_util->setFrameRate(_multData->frameRate); _animTop = 0; _animLeft = 0; @@ -517,33 +524,30 @@ void Mult_v2::playMultInit() { _animHeight = _vm->_video->_surfHeight; _objCount = 4; - delete[] _objects; delete[] _orderArray; delete[] _renderObjs; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _objects = new Mult_Object[_objCount]; _orderArray = new int8[_objCount]; _renderObjs = new Mult_Object*[_objCount]; - _animArrayX = new int32[_objCount]; - _animArrayY = new int32[_objCount]; + _animArrayX = new VariablesLE(_objCount * 4); + _animArrayY = new VariablesLE(_objCount * 4); _animArrayData = new Mult_AnimData[_objCount]; memset(_objects, 0, _objCount * sizeof(Mult_Object)); memset(_orderArray, 0, _objCount * sizeof(int8)); memset(_renderObjs, 0, _objCount * sizeof(Mult_Object *)); - memset(_animArrayX, 0, _objCount * sizeof(int32)); - memset(_animArrayY, 0, _objCount * sizeof(int32)); memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData)); for (_counter = 0; _counter < _objCount; _counter++) { Mult_Object &multObj = _objects[_counter]; Mult_AnimData &animData = _animArrayData[_counter]; - multObj.pPosX = (int32 *) &_animArrayX[_counter]; - multObj.pPosY = (int32 *) &_animArrayY[_counter]; + multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4); + multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4); multObj.pAnimData = &animData; animData.isStatic = 1; diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h index b59510e4bb..07b5a737db 100644 --- a/engines/gob/sound/sound.h +++ b/engines/gob/sound/sound.h @@ -144,4 +144,4 @@ private: } // End of namespace Gob -#endif // GOB_SOUND_H +#endif // GOB_SOUND_SOUND_H diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h index 5789885a99..3e8e6b5c1b 100644 --- a/engines/gob/sound/soundmixer.h +++ b/engines/gob/sound/soundmixer.h @@ -37,7 +37,7 @@ namespace Gob { class SoundMixer : public Audio::AudioStream { public: - SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType); + SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type); ~SoundMixer(); virtual void play(SoundDesc &sndDesc, int16 repCount, diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp index 0eea2f6547..805aaeb839 100644 --- a/engines/gob/variables.cpp +++ b/engines/gob/variables.cpp @@ -308,4 +308,62 @@ uint32 VariablesBE::read32(const byte *buf) const { return READ_BE_UINT32(buf); } +VariableReference::VariableReference() { + _vars = 0; + _offset = 0; +} + +VariableReference::VariableReference(Variables &vars, uint32 offset, Variables::Type type) { + set(vars, offset, type); +} + +VariableReference::~VariableReference() { +} + +void VariableReference::set(Variables &vars, uint32 offset, Variables::Type type) { + _vars = &vars; + _offset = offset; + _type = type; +} + +VariableReference &VariableReference::operator=(uint32 value) { + if (_vars) { + switch (_type) { + case Variables::kVariableType8: + _vars->writeOff8(_offset, (uint8) value); + break; + case Variables::kVariableType16: + _vars->writeOff16(_offset, (uint16) value); + break; + case Variables::kVariableType32: + _vars->writeOff32(_offset, value); + break; + } + } + return *this; +} + +VariableReference::operator uint32() { + if (_vars) { + switch (_type) { + case Variables::kVariableType8: + return (uint32) _vars->readOff8(_offset); + case Variables::kVariableType16: + return (uint32) _vars->readOff16(_offset); + case Variables::kVariableType32: + return _vars->readOff32(_offset); + } + } + + return 0; +} + +VariableReference &VariableReference::operator+=(uint32 value) { + return (*this = (*this + value)); +} + +VariableReference &VariableReference::operator*=(uint32 value) { + return (*this = (*this * value)); +} + } // End of namespace Gob diff --git a/engines/gob/variables.h b/engines/gob/variables.h index 5989ed38ee..32f160a6bd 100644 --- a/engines/gob/variables.h +++ b/engines/gob/variables.h @@ -30,6 +30,12 @@ namespace Gob { class Variables { public: + enum Type { + kVariableType8, + kVariableType16, + kVariableType32 + }; + Variables(uint32 size); virtual ~Variables(); @@ -142,6 +148,26 @@ protected: uint32 read32(const byte *buf) const; }; +class VariableReference { + public: + VariableReference(); + VariableReference(Variables &vars, uint32 offset, + Variables::Type type = Variables::kVariableType32); + ~VariableReference(); + + void set(Variables &vars, uint32 offset, Variables::Type type = Variables::kVariableType32); + + VariableReference &operator=(uint32 value); + VariableReference &operator+=(uint32 value); + VariableReference &operator*=(uint32 value); + operator uint32(); + + private: + Variables *_vars; + uint32 _offset; + Variables::Type _type; +}; + } // End of namespace Gob #endif // GOB_VARIABLES_H diff --git a/engines/igor/igor.cpp b/engines/igor/igor.cpp index 018709f34f..4d4fb97762 100644 --- a/engines/igor/igor.cpp +++ b/engines/igor/igor.cpp @@ -404,7 +404,7 @@ void IgorEngine::playSound(int num, int type) { debugC(9, kDebugEngine, "playSound() %d", num); --num; int soundOffset = -1; - Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType; + Audio::Mixer::SoundType soundType; Audio::SoundHandle *soundHandle = 0; if (type == 1) { if (_mixer->isSoundHandleActive(_sfxHandle)) { diff --git a/engines/kyra/animator_lok.cpp b/engines/kyra/animator_lok.cpp index 1baa78b203..75d5537e4a 100644 --- a/engines/kyra/animator_lok.cpp +++ b/engines/kyra/animator_lok.cpp @@ -665,7 +665,7 @@ void Animator_LoK::animRefreshNPC(int character) { void Animator_LoK::setCharacterDefaultFrame(int character) { debugC(9, kDebugLevelAnimator, "Animator_LoK::setCharacterDefaultFrame()"); - static uint16 initFrameTable[] = { + static const uint16 initFrameTable[] = { 7, 41, 77, 0, 0 }; assert(character < ARRAYSIZE(initFrameTable)); @@ -678,7 +678,7 @@ void Animator_LoK::setCharacterDefaultFrame(int character) { void Animator_LoK::setCharactersHeight() { debugC(9, kDebugLevelAnimator, "Animator_LoK::setCharactersHeight()"); - static int8 initHeightTable[] = { + static const int8 initHeightTable[] = { 48, 40, 48, 47, 56, 44, 42, 47, 38, 35, 40 diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 344121b503..fce1e93bc2 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -41,9 +41,11 @@ struct KYRAGameDescription { namespace { -#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } +#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } +#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, id } #define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA1) #define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) #define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, Kyra::GI_KYRA1) #define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, Kyra::GI_KYRA1) @@ -59,13 +61,36 @@ namespace { #define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_KYRA2) #define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) -#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3) +#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3) const KYRAGameDescription adGameDescs[] = { { { "kyra1", 0, + AD_ENTRY1("DISK1.EXE", "c8641d0414d6c966d0a3dad79db07bf4"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_CMP_FLAGS + }, + { + { + "kyra1", + 0, + AD_ENTRY1("DISK1.EXE", "5d5cee4c3d0b68d586788b74243d254a"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_CMP_FLAGS + }, + { + { + "kyra1", + "Extracted", AD_ENTRY1("GEMCUT.EMC", "3c244298395520bb62b5edfe41688879"), Common::EN_ANY, Common::kPlatformPC, @@ -76,7 +101,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "796e44863dd22fa635b042df1bf16673"), Common::EN_ANY, Common::kPlatformPC, @@ -87,7 +112,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "abf8eb360e79a6c2a837751fbd4d3d24"), Common::FR_FRA, Common::kPlatformPC, @@ -98,7 +123,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "6018e1dfeaca7fe83f8d0b00eb0dd049"), Common::DE_DEU, Common::kPlatformPC, @@ -109,7 +134,7 @@ const KYRAGameDescription adGameDescs[] = { { // from Arne.F { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "f0b276781f47c130f423ec9679fe9ed9"), Common::DE_DEU, Common::kPlatformPC, @@ -120,7 +145,7 @@ const KYRAGameDescription adGameDescs[] = { { // from VooD { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "8909b41596913b3f5deaf3c9f1017b01"), Common::ES_ESP, Common::kPlatformPC, @@ -131,7 +156,7 @@ const KYRAGameDescription adGameDescs[] = { { // floppy 1.8 from clemmy { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "747861d2a9c643c59fdab570df5b9093"), Common::ES_ESP, Common::kPlatformPC, @@ -142,7 +167,7 @@ const KYRAGameDescription adGameDescs[] = { { // from gourry { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "ef08c8c237ee1473fd52578303fc36df"), Common::IT_ITA, Common::kPlatformPC, @@ -323,7 +348,7 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_FLOPPY_CMP_FLAGS }, - { // // Floppy version extracted + { // Floppy version extracted { "kyra2", "Extracted", @@ -463,6 +488,28 @@ const KYRAGameDescription adGameDescs[] = { }, KYRA2_TOWNS_SJIS_FLAGS }, + { // PC-9821 + { + "kyra2", + 0, + AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), + Common::EN_ANY, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + KYRA2_TOWNS_FLAGS + }, + { + { + "kyra2", + 0, + AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), + Common::JA_JPN, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + KYRA2_TOWNS_SJIS_FLAGS + }, // Kyra3 @@ -480,7 +527,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, { { @@ -495,7 +542,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, { { @@ -510,7 +557,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, // installed version @@ -527,7 +574,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -542,7 +589,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -557,9 +604,102 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, + // Spanish fan translation, see fr#1994040 "KYRA3: Add support for Spanish fan translation" + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::ES_ESP, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) + }, + + // Itlian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3" + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) + }, { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } }; diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 032c28d44d..cb3cef2fb3 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -454,14 +454,26 @@ void KyraEngine_HoF::loadBookBkgd() { void KyraEngine_HoF::showBookPage() { char filename[16]; - sprintf(filename, "PAGE%.01X.", _bookCurPage); - strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); + sprintf(filename, "PAGE%.01X.%s", _bookCurPage, _languageExtension[_lang]); uint8 *leftPage = _res->fileData(filename, 0); + if (!leftPage) { + // some floppy version use a TXT extension + sprintf(filename, "PAGE%.01X.TXT", _bookCurPage); + leftPage = _res->fileData(filename, 0); + } + int leftPageY = _bookPageYOffset[_bookCurPage]; - sprintf(filename, "PAGE%.01X.", _bookCurPage+1); - strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); - uint8 *rightPage = (_bookCurPage != _bookMaxPage) ? _res->fileData(filename, 0) : 0; + sprintf(filename, "PAGE%.01X.%s", _bookCurPage+1, _languageExtension[_lang]); + uint8 *rightPage = 0; + if (_bookCurPage != _bookMaxPage) { + rightPage = _res->fileData(filename, 0); + if (!rightPage) { + sprintf(filename, "PAGE%.01X.TXT", _bookCurPage); + rightPage = _res->fileData(filename, 0); + } + } + int rightPageY = _bookPageYOffset[_bookCurPage+1]; _screen->hideMouse(); diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index db9d61ce5e..092aaedb23 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -187,6 +187,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) { #pragma mark - GUI_LoK::GUI_LoK(KyraEngine_LoK *vm, Screen_LoK *screen) : GUI(vm), _vm(vm), _screen(screen) { + _lastScreenUpdate = 0; _menu = 0; initStaticResource(); _scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::scrollUp); @@ -478,7 +479,6 @@ int GUI_LoK::buttonMenuCallback(Button *caller) { void GUI_LoK::getInput() { Common::Event event; - static uint32 lastScreenUpdate = 0; uint32 now = _vm->_system->getMillis(); _mouseWheel = 0; @@ -492,7 +492,7 @@ void GUI_LoK::getInput() { break; case Common::EVENT_MOUSEMOVE: _vm->_system->updateScreen(); - lastScreenUpdate = now; + _lastScreenUpdate = now; break; case Common::EVENT_WHEELUP: _mouseWheel = -1; @@ -508,9 +508,9 @@ void GUI_LoK::getInput() { } } - if (now - lastScreenUpdate > 50) { + if (now - _lastScreenUpdate > 50) { _vm->_system->updateScreen(); - lastScreenUpdate = now; + _lastScreenUpdate = now; } _vm->_system->delayMillis(3); @@ -1052,7 +1052,7 @@ void GUI_LoK::fadePalette() { if (_vm->gameFlags().platform == Common::kPlatformAmiga) return; - static int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; + static const int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; int index = 0; memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 607ef0b605..49081c7ae2 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -157,6 +157,8 @@ private: KyraEngine_LoK *_vm; Screen_LoK *_screen; + uint32 _lastScreenUpdate; + bool _menuRestoreScreen; uint8 _toplevelMenu; int _savegameOffset; diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp index 8eb62c20c2..2c2903d0b3 100644 --- a/engines/kyra/items_lok.cpp +++ b/engines/kyra/items_lok.cpp @@ -39,7 +39,7 @@ namespace Kyra { int KyraEngine_LoK::findDuplicateItemShape(int shape) { - static uint8 dupTable[] = { + static const uint8 dupTable[] = { 0x48, 0x46, 0x49, 0x47, 0x4a, 0x46, 0x4b, 0x47, 0x4c, 0x46, 0x4d, 0x47, 0x5b, 0x5a, 0x5c, 0x5a, 0x5d, 0x5a, 0x5e, 0x5a, 0xFF, 0xFF diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 470e5f0343..ac69272ef4 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -296,6 +296,9 @@ int KyraEngine_HoF::go() { _res->loadFileList("FILEDATA.FDT"); else _res->loadFileList(_ingamePakList, _ingamePakListSize); + + if (_flags.platform == Common::kPlatformPC98) + _res->loadPakFile("AUDIO.PAK"); } _menuDirectlyToLoad = (_menuChoice == 3) ? true : false; @@ -1560,7 +1563,7 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) { int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]); if (vocIndex != -1) _sound->voicePlay(_ingameSoundList[vocIndex], true); - else if (_flags.platform == Common::kPlatformPC) + else if (_flags.platform != Common::kPlatformFMTowns) // TODO ?? Maybe there is a way to let users select whether they want // voc, midi or adl sfx (even though it makes no sense to choose anything but voc). KyraEngine_v1::snd_playSoundEffect(track); @@ -2020,6 +2023,9 @@ void KyraEngine_HoF::writeSettings() { break; } + if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG) + _flags.lang = _flags.fanLang; + ConfMan.set("language", Common::getLanguageCode(_flags.lang)); KyraEngine_v1::writeSettings(); diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 700bec10b7..7097543750 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -343,6 +343,14 @@ void KyraEngine_MR::initMainMenu() { 0x80, 0xFF }; + if (_flags.lang == Common::ES_ESP) { + for (int i = 0; i < 4; ++i) + data.strings[i] = _mainMenuSpanishFan[i]; + } else if (_flags.lang == Common::IT_ITA) { + for (int i = 0; i < 4; ++i) + data.strings[i] = _mainMenuItalianFan[i]; + } + MainMenu::Animation anim; anim.anim = _menuAnim; anim.startFrame = 29; @@ -1543,6 +1551,9 @@ void KyraEngine_MR::writeSettings() { break; } + if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG) + _flags.lang = _flags.fanLang; + ConfMan.set("language", Common::getLanguageCode(_flags.lang)); ConfMan.setBool("studio_audience", _configStudio); diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 5af138373c..5f9f6f91a3 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -184,9 +184,12 @@ private: private: // main menu - const char *const *_mainMenuStrings; + const char * const *_mainMenuStrings; int _mainMenuStringsSize; + static const char * const _mainMenuSpanishFan[]; + static const char * const _mainMenuItalianFan[]; + // animator uint8 *_gamePlayBuffer; void restorePage3(); diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index accf5ab57e..cc97f43a05 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -105,14 +105,16 @@ int KyraEngine_v1::init() { // "KYRA1: Crash on exceeded polyphony" for more information). int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/); - if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { - // TODO: currently we don't support the PC98 sound data, - // but since it has the FM-Towns data files, we just use the - // FM-Towns driver + if (_flags.platform == Common::kPlatformFMTowns) { if (_flags.gameID == GI_KYRA1) _sound = new SoundTowns(this, _mixer); else - _sound = new SoundTowns_v2(this, _mixer); + _sound = new SoundTownsPC98_v2(this, _mixer); + } else if (_flags.platform == Common::kPlatformPC98) { + if (_flags.gameID == GI_KYRA1) + _sound = new SoundPC98(this, _mixer); + else + _sound = new SoundTownsPC98_v2(this, _mixer); } else if (midiDriver == MD_ADLIB) { _sound = new SoundAdlibPC(this, _mixer); assert(_sound); @@ -169,36 +171,6 @@ int KyraEngine_v1::init() { _gameToLoad = -1; } - _lang = 0; - Common::Language lang = Common::parseLanguage(ConfMan.get("language")); - - if (_flags.gameID == GI_KYRA2 || _flags.gameID == GI_KYRA3) { - switch (lang) { - case Common::EN_ANY: - case Common::EN_USA: - case Common::EN_GRB: - _lang = 0; - break; - - case Common::FR_FRA: - _lang = 1; - break; - - case Common::DE_DEU: - _lang = 2; - break; - - case Common::JA_JPN: - _lang = 3; - break; - - default: - warning("unsupported language, switching back to English"); - _lang = 0; - break; - } - } - return 0; } @@ -276,6 +248,14 @@ void KyraEngine_v1::delayWithTicks(int ticks) { void KyraEngine_v1::registerDefaultSettings() { if (_flags.gameID != GI_KYRA3) ConfMan.registerDefault("cdaudio", (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)); + if (_flags.fanLang != Common::UNK_LANG) { + // HACK/WORKAROUND: Since we can't use registerDefault here to overwrite + // the global subtitles settings, we're using this hack to enable subtitles + // for fan translations + const Common::ConfigManager::Domain *cur = ConfMan.getActiveDomain(); + if (!cur || (cur && cur->get("subtitles").empty())) + ConfMan.setBool("subtitles", true); + } } void KyraEngine_v1::readSettings() { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 921d5ba033..8dd95c79b9 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -44,6 +44,11 @@ namespace Kyra { struct GameFlags { Common::Language lang; + + // language overwrites of fan translations (only needed for multilingual games) + Common::Language fanLang; + Common::Language replacedLang; + Common::Platform platform; bool isDemo : 1; @@ -207,7 +212,6 @@ protected: // detection GameFlags _flags; - int _lang; // opcode virtual void setupOpcodeTable() = 0; diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 20875202e5..08a4e9f4c5 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -23,6 +23,8 @@ * */ +#include "common/config-manager.h" + #include "kyra/kyra_v2.h" #include "kyra/screen_v2.h" #include "kyra/debugger.h" @@ -70,6 +72,36 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi memset(&_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory)); _pauseStart = 0; + + _lang = 0; + Common::Language lang = Common::parseLanguage(ConfMan.get("language")); + if (lang == _flags.fanLang && _flags.replacedLang != Common::UNK_LANG) + lang = _flags.replacedLang; + + switch (lang) { + case Common::EN_ANY: + case Common::EN_USA: + case Common::EN_GRB: + _lang = 0; + break; + + case Common::FR_FRA: + _lang = 1; + break; + + case Common::DE_DEU: + _lang = 2; + break; + + case Common::JA_JPN: + _lang = 3; + break; + + default: + warning("unsupported language, switching back to English"); + _lang = 0; + break; + } } KyraEngine_v2::~KyraEngine_v2() { diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 24f7aad614..6fdf30fff8 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -94,6 +94,9 @@ protected: virtual void update() = 0; virtual void updateWithText() = 0; + // detection + int _lang; + // MainMenu MainMenu *_menu; diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp index dbf54e1fcd..08df7b064e 100644 --- a/engines/kyra/scene_hof.cpp +++ b/engines/kyra/scene_hof.cpp @@ -723,7 +723,7 @@ void KyraEngine_HoF::fadeScenePal(int srcIndex, int delayTime) { bool KyraEngine_HoF::lineIsPassable(int x, int y) { debugC(9, kDebugLevelMain, "KyraEngine_HoF::lineIsPassable(%d, %d)", x, y); - static int unkTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 }; + static const int widthTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 }; if (_pathfinderFlag & 2) { if (x >= 320) @@ -743,7 +743,7 @@ bool KyraEngine_HoF::lineIsPassable(int x, int y) { if (y > 143) return false; - int unk1 = unkTable[getScale(x, y) >> 5]; + int unk1 = widthTable[getScale(x, y) >> 5]; if (y < 0) y = 0; diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp index e4ae67f751..53c269a926 100644 --- a/engines/kyra/scene_lok.cpp +++ b/engines/kyra/scene_lok.cpp @@ -1144,11 +1144,11 @@ void KyraEngine_LoK::setCharactersInDefaultScene() { } void KyraEngine_LoK::setCharactersPositions(int character) { - static uint16 initXPosTable[] = { + static const uint16 initXPosTable[] = { 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B, 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042 }; - static uint8 initYPosTable[] = { + static const uint8 initYPosTable[] = { 0x00, 0xA2, 0x00, 0x42, 0x00, 0x67, 0x67, 0x60, 0x5A, 0x71, 0x76 diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index f00c47ceea..6e7a88b1a3 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -92,9 +92,19 @@ bool Screen::init() { if (_useSJIS) { if (!_sjisFontData) { - _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0); - if (!_sjisFontData) - error("missing font rom ('FMT_FNT.ROM') required for this version"); + // we use the FM-Towns font rom for PC-98, too, until we feel + // like adding support for the PC-98 font + //if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + // FM-Towns + _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0); + if (!_sjisFontData) + error("missing font rom ('FMT_FNT.ROM') required for this version"); + /*} else { + // PC-98 + _sjisFontData = _vm->resource()->fileData("FONT.ROM", 0); + if (!_sjisFontData) + error("missing font rom ('FONT.ROM') required for this version"); + }*/ } if (!_sjisTempPage) { diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index ef3e259cfa..b10a4b32bf 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -35,7 +35,7 @@ namespace Kyra { EMCInterpreter::EMCInterpreter(KyraEngine_v1 *vm) : _vm(vm) { #define COMMAND(x) { &EMCInterpreter::x, #x } - static CommandEntry commandProcs[] = { + static const CommandEntry commandProcs[] = { // 0x00 COMMAND(cmd_jmpTo), COMMAND(cmd_setRetValue), @@ -132,6 +132,8 @@ bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Commo scriptData->opcodes = opcodes; + strncpy(scriptData->filename, filename, 13); + return true; } @@ -205,7 +207,7 @@ bool EMCInterpreter::run(EMCState *script) { } if (opcode > 18) { - error("Script unknown command: %d", opcode); + error("Script unknown command: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset); } else { debugC(5, kDebugLevelScript, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _commands[opcode].desc, _parameter, (uint)_parameter); (this->*(_commands[opcode].proc))(script); @@ -388,7 +390,7 @@ void EMCInterpreter::cmd_execOpcode(EMCState* script) { script->retValue = (*(*script->dataPtr->opcodes)[opcode])(script); } else { script->retValue = 0; - warning("calling unimplemented opcode(0x%.02X/%d)", opcode, opcode); + warning("Calling unimplemented opcode(0x%.02X/%d) from file '%s'", opcode, opcode, script->dataPtr->filename); } } diff --git a/engines/kyra/script.h b/engines/kyra/script.h index de52093f66..2b97a83289 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -36,6 +36,8 @@ struct EMCState; typedef Common::Functor1<EMCState*, int> Opcode; struct EMCData { + char filename[13]; + byte *text; uint16 *data; uint16 *ordr; diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index 91fbfb3e49..94f160d11f 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -799,10 +799,14 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) { _screen->fadeToBlack(0x14); - sprintf(filename, "LETTER%.1d.", letter); - strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); - + sprintf(filename, "LETTER%.1d.%s", letter, _languageExtension[_lang]); uint8 *letterBuffer = _res->fileData(filename, 0); + if (!letterBuffer) { + // some floppy versions use a TXT extension + sprintf(filename, "LETTER%.1d.TXT", letter); + letterBuffer = _res->fileData(filename, 0); + } + if (letterBuffer) { bookDecodeText(letterBuffer); bookPrintText(2, letterBuffer, 0xC, 0xA, 0x20); diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 4ad6464424..4b82232049 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -34,7 +34,8 @@ namespace Kyra { TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) { #define COMMAND(x) { &TIMInterpreter::x, #x } #define COMMAND_UNIMPL() { 0, 0 } - static CommandEntry commandProcs[] = { +#define cmd_return(n) cmd_return_##n + static const CommandEntry commandProcs[] = { // 0x00 COMMAND(cmd_initFunc0), COMMAND(cmd_stopCurFunc), @@ -66,15 +67,16 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s COMMAND_UNIMPL(), COMMAND(cmd_resetAllRuntimes), // 0x18 - COMMAND(cmd_return<1>), + COMMAND(cmd_return(1)), COMMAND(cmd_execOpcode), COMMAND(cmd_initFuncNow), COMMAND(cmd_stopFuncNow), // 0x1C - COMMAND(cmd_return<1>), - COMMAND(cmd_return<1>), - COMMAND(cmd_return<-1>) + COMMAND(cmd_return(1)), + COMMAND(cmd_return(1)), + COMMAND(cmd_return(n1)) }; +#undef cmd_return _commands = commandProcs; _commandsSize = ARRAYSIZE(commandProcs); @@ -122,6 +124,8 @@ TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpc for (int i = 0; i < num; ++i) tim->func[i].avtl = tim->avtl + tim->avtl[i]; + strncpy(tim->filename, filename, 13); + return tim; } @@ -199,12 +203,12 @@ void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) { int TIMInterpreter::execCommand(int cmd, const uint16 *param) { if (cmd < 0 || cmd >= _commandsSize) { - warning("Calling unimplemented TIM command %d", cmd); + warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename); return 0; } if (_commands[cmd].proc == 0) { - warning("Calling unimplemented TIM command %d", cmd); + warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename); return 0; } @@ -259,7 +263,7 @@ int TIMInterpreter::cmd_execOpcode(const uint16 *param) { uint16 opcode = *param++; if (opcode > _currentTim->opcodes->size()) { - warning("Calling unimplemented TIM opcode(0x%.02X/%d)", opcode, opcode); + warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename); return 0; } diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index cd715ff4ef..39a1d90a44 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -37,6 +37,8 @@ struct TIM; typedef Common::Functor2<const TIM*, const uint16*, int> TIMOpcode; struct TIM { + char filename[13]; + int16 procFunc; uint16 procParam; @@ -102,8 +104,12 @@ private: int cmd_execOpcode(const uint16 *param); int cmd_initFuncNow(const uint16 *param); int cmd_stopFuncNow(const uint16 *param); - template<int T> - int cmd_return(const uint16 *) { return T; } +#define cmd_return(n, v) \ + int cmd_return_##n(const uint16 *) { return v; } + + cmd_return( 1, 1); + cmd_return(n1, -1); +#undef cmd_return }; } // end of namespace Kyra diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp index 73d69ef10c..dfda5bf859 100644 --- a/engines/kyra/seqplayer.cpp +++ b/engines/kyra/seqplayer.cpp @@ -500,7 +500,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { debugC(9, kDebugLevelSequence, "SeqPlayer::seq_playSequence(%p, %d)", (const void *)seqData, skipSeq); assert(seqData); - static SeqEntry floppySeqProcs[] = { + static const SeqEntry floppySeqProcs[] = { // 0x00 SEQOP(3, s1_wsaOpen), SEQOP(2, s1_wsaClose), @@ -541,7 +541,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { SEQOP(1, s1_endOfScript) }; - static SeqEntry cdromSeqProcs[] = { + static const SeqEntry cdromSeqProcs[] = { // 0x00 SEQOP(3, s1_wsaOpen), SEQOP(2, s1_wsaClose), diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index 1940acbf7f..577dcd827b 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -1082,7 +1082,7 @@ void KyraEngine_LoK::seq_playCredits() { _screen->_charWidth = -1; // we only need this for the fm-towns version - if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) + if (_flags.platform == Common::kPlatformFMTowns && _configMusic == 1) snd_playWanderScoreViaMap(53, 1); uint8 *buffer = 0; diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index f56c43aabd..5068268d99 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -243,27 +243,14 @@ int SoundMidiPC::open() { } void SoundMidiPC::close() { - if (_driver) + if (_driver) { _driver->close(); + delete _driver; + } _driver = 0; } void SoundMidiPC::send(uint32 b) { - // HACK: For Kyrandia, we make the simplifying assumption that a song - // either loops in its entirety, or not at all. So if we see a FOR_LOOP - // controller event, we turn on looping even if there isn't any - // corresponding NEXT_BREAK event. - // - // This is a gross over-simplification of how XMIDI handles loops. If - // anyone feels like doing a proper implementation, please refer to - // the Exult project, and do it in midiparser_xmidi.cpp - - if ((b & 0xFFF0) == 0x74B0 && _eventFromMusic) { - debugC(9, kDebugLevelMain | kDebugLevelSound, "SoundMidiPC: Looping song"); - _musicParser->property(MidiParser::mpAutoLoop, true); - return; - } - if (_passThrough) { if ((b & 0xFFF0) == 0x007BB0) return; diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 1baeb3064a..cebfdf491f 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -73,7 +73,8 @@ public: kAdlib, kMidiMT32, kMidiGM, - kTowns + kTowns, + kPC98 }; virtual kType getMusicType() const = 0; @@ -382,7 +383,9 @@ private: Common::Mutex _mutex; }; -class SoundTowns_EuphonyDriver; +class Towns_EuphonyDriver; +class TownsPC98_OpnDriver; + class SoundTowns : public MidiDriver, public Sound { public: SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer); @@ -417,6 +420,7 @@ public: static float semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, uint32 sampleRate, uint32 outputRate, int32 pitchWheel); + private: bool loadInstruments(); void playEuphonyTrack(uint32 offset, int loop); @@ -430,7 +434,7 @@ private: uint _sfxFileIndex; uint8 *_sfxFileData; - SoundTowns_EuphonyDriver * _driver; + Towns_EuphonyDriver * _driver; MidiParser * _parser; Common::Mutex _mutex; @@ -439,13 +443,38 @@ private: const uint8 *_sfxWDTable; }; -//class SoundTowns_v2_TwnDriver; -class SoundTowns_v2 : public Sound { +class SoundPC98 : public Sound { public: - SoundTowns_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer); - ~SoundTowns_v2(); + SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer); + ~SoundPC98(); - kType getMusicType() const { return kTowns; } + virtual kType getMusicType() const { return kPC98; } + + bool init(); + + void process() {} + void loadSoundFile(uint file) {} + + void playTrack(uint8 track); + void haltTrack(); + void beginFadeOut(); + + int32 voicePlay(const char *file, bool isSfx = false) { return -1; } + void playSoundEffect(uint8); + +protected: + int _lastTrack; + uint8 *_musicTrackData; + uint8 *_sfxTrackData; + TownsPC98_OpnDriver *_driver; +}; + +class SoundTownsPC98_v2 : public Sound { +public: + SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer); + ~SoundTownsPC98_v2(); + + kType getMusicType() const { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; } bool init(); void process(); @@ -457,15 +486,15 @@ public: void beginFadeOut(); int32 voicePlay(const char *file, bool isSfx = false); - void playSoundEffect(uint8) {} - -private: - int _lastTrack; + void playSoundEffect(uint8 track); +protected: Audio::AudioStream *_currentSFX; + int _lastTrack; + bool _useFmSfx; - //SoundTowns_v2_TwnDriver *_driver; - uint8 *_twnTrackData; + uint8 *_musicTrackData; + TownsPC98_OpnDriver *_driver; }; class MixedSoundDriver : public Sound { diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp index 8a1d16a6b1..b43d72ebce 100644 --- a/engines/kyra/sound_lok.cpp +++ b/engines/kyra/sound_lok.cpp @@ -43,19 +43,29 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) { if (restart) _lastMusicCommand = -1; - if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { + if (_flags.platform == Common::kPlatformFMTowns) { if (command == 1) { _sound->beginFadeOut(); } else if (command >= 35 && command <= 38) { snd_playSoundEffect(command-20); } else if (command >= 2) { - if (_lastMusicCommand != command) { + if (_lastMusicCommand != command) // the original does -2 here we handle this inside _sound->playTrack() _sound->playTrack(command); - } } else { _sound->haltTrack(); } + _lastMusicCommand = command; + } else if (_flags.platform == Common::kPlatformPC98) { + if (command == 1) { + _sound->beginFadeOut(); + } else if (command >= 2) { + if (_lastMusicCommand != command) + _sound->playTrack(command); + } else { + _sound->haltTrack(); + } + _lastMusicCommand = command; } else { KyraEngine_v1::snd_playWanderScoreViaMap(command, restart); } diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 4265533507..e96cef735c 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -34,18 +34,16 @@ #include "common/util.h" -#include <math.h> - #define EUPHONY_FADEOUT_TICKS 600 namespace Kyra { -enum ChannelState { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing }; +enum EnvelopeState { s_ready, s_attacking, s_decaying, s_sustaining, s_releasing }; -class MidiChannel_EuD : public MidiChannel { +class Towns_EuphonyChannel : public MidiChannel { public: - MidiChannel_EuD() {} - ~MidiChannel_EuD() {} + Towns_EuphonyChannel() {} + ~Towns_EuphonyChannel() {} virtual void nextTick(int32 *outbuf, int buflen) = 0; virtual void rate(uint16 r) = 0; @@ -54,10 +52,10 @@ protected: uint16 _rate; }; -class MidiChannel_EuD_FM : public MidiChannel_EuD { +class Towns_EuphonyFmChannel : public Towns_EuphonyChannel { public: - MidiChannel_EuD_FM(); - virtual ~MidiChannel_EuD_FM(); + Towns_EuphonyFmChannel(); + virtual ~Towns_EuphonyFmChannel(); void nextTick(int32 *outbuf, int buflen); void rate(uint16 r); @@ -79,13 +77,13 @@ protected: Voice2612 *_voice; }; -class MidiChannel_EuD_WAVE : public MidiChannel_EuD { +class Towns_EuphonyPcmChannel : public Towns_EuphonyChannel { public: void nextTick(int32 *outbuf, int buflen); void rate(uint16 r); - MidiChannel_EuD_WAVE(); - virtual ~MidiChannel_EuD_WAVE(); + Towns_EuphonyPcmChannel(); + virtual ~Towns_EuphonyPcmChannel(); // MidiChannel interface MidiDriver *device() { return 0; } @@ -126,9 +124,9 @@ protected: int32 keyOffset; int32 keyNote; const int8 *_samples; - } * _snd[8]; + } *_snd[8]; struct Env { - ChannelState state; + EnvelopeState state; int32 currentLevel; int32 rate; int32 tickCount; @@ -141,40 +139,39 @@ protected: int32 releaseRate; int32 rootKeyOffset; int32 size; - } * _env[8]; - } * _voice; + } *_env[8]; + } *_voice; }; -class SoundTowns_EuphonyTrackQueue { +class Towns_EuphonyTrackQueue { public: - SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver *driver, SoundTowns_EuphonyTrackQueue *last); - ~SoundTowns_EuphonyTrackQueue() {} + Towns_EuphonyTrackQueue(Towns_EuphonyDriver *driver, Towns_EuphonyTrackQueue *last); + ~Towns_EuphonyTrackQueue() {} - void release(); + Towns_EuphonyTrackQueue *release(); void initDriver(); - void loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop = 0); - void loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop = 0); + void loadDataToCurrentPosition(uint8 *trackdata, uint32 size, bool loop = 0); + void loadDataToEndOfQueue(uint8 *trackdata, uint32 size, bool loop = 0); void setPlayBackStatus(bool playing); - SoundTowns_EuphonyTrackQueue * reset(); bool isPlaying() {return _playing; } - uint8 * trackData() {return _trackData; } + uint8 *trackData() {return _trackData; } bool _loop; - SoundTowns_EuphonyTrackQueue * _next; + Towns_EuphonyTrackQueue *_next; private: - uint8 * _trackData; - uint8 * _used; - uint8 * _fchan; - uint8 * _wchan; + uint8 *_trackData; + uint8 *_used; + uint8 *_fchan; + uint8 *_wchan; bool _playing; - SoundTowns_EuphonyDriver * _driver; - SoundTowns_EuphonyTrackQueue * _last; + Towns_EuphonyDriver *_driver; + Towns_EuphonyTrackQueue *_last; }; -class MidiParser_EuD : public MidiParser { +class Towns_EuphonyParser : public MidiParser { public: - MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue); + Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue); bool loadMusic (byte *data, uint32 size); int32 calculateTempo(int16 val); @@ -183,11 +180,11 @@ protected: void resetTracking(); void setup(); - byte * _enable; - byte * _mode; - byte * _channel; - byte * _adjVelo; - int8 * _adjNote; + byte *_enable; + byte *_mode; + byte *_channel; + byte *_adjVelo; + int8 *_adjNote; uint8 _firstBaseTickStep; uint8 _nextBaseTickStep; @@ -195,13 +192,13 @@ protected: uint32 _baseTick; byte _tempo[3]; - SoundTowns_EuphonyTrackQueue * _queue; + Towns_EuphonyTrackQueue *_queue; }; -class SoundTowns_EuphonyDriver : public MidiDriver_Emulated { +class Towns_EuphonyDriver : public MidiDriver_Emulated { public: - SoundTowns_EuphonyDriver(Audio::Mixer *mixer); - virtual ~SoundTowns_EuphonyDriver(); + Towns_EuphonyDriver(Audio::Mixer *mixer); + virtual ~Towns_EuphonyDriver(); int open(); void close(); @@ -213,7 +210,7 @@ public: void loadFmInstruments(const byte *instr); void loadWaveInstruments(const byte *instr); - SoundTowns_EuphonyTrackQueue * queue() { return _queue; } + Towns_EuphonyTrackQueue *queue() { return _queue; } MidiChannel *allocateChannel() { return 0; } MidiChannel *getPercussionChannel() { return 0; } @@ -237,10 +234,10 @@ protected: void generateSamples(int16 *buf, int len); - MidiChannel_EuD_FM *_fChannel[6]; - MidiChannel_EuD_WAVE *_wChannel[8]; - MidiChannel_EuD * _channel[16]; - SoundTowns_EuphonyTrackQueue * _queue; + Towns_EuphonyFmChannel *_fChannel[6]; + Towns_EuphonyPcmChannel *_wChannel[8]; + Towns_EuphonyChannel *_channel[16]; + Towns_EuphonyTrackQueue *_queue; int _volume; bool _fading; @@ -251,23 +248,23 @@ protected: int8 * _waveSounds[10]; }; -MidiChannel_EuD_FM::MidiChannel_EuD_FM() { +Towns_EuphonyFmChannel::Towns_EuphonyFmChannel() { _voice = new Voice2612; } -MidiChannel_EuD_FM::~MidiChannel_EuD_FM() { +Towns_EuphonyFmChannel::~Towns_EuphonyFmChannel() { delete _voice; } -void MidiChannel_EuD_FM::noteOn(byte note, byte onVelo) { +void Towns_EuphonyFmChannel::noteOn(byte note, byte onVelo) { _voice->noteOn(note, onVelo); } -void MidiChannel_EuD_FM::noteOff(byte note) { +void Towns_EuphonyFmChannel::noteOff(byte note) { _voice->noteOff(note); } -void MidiChannel_EuD_FM::controlChange(byte control, byte value) { +void Towns_EuphonyFmChannel::controlChange(byte control, byte value) { if (control == 121) { // Reset controller delete _voice; @@ -279,25 +276,25 @@ void MidiChannel_EuD_FM::controlChange(byte control, byte value) { } } -void MidiChannel_EuD_FM::sysEx_customInstrument(uint32, const byte *fmInst) { +void Towns_EuphonyFmChannel::sysEx_customInstrument(uint32, const byte *fmInst) { _voice->_rate = _rate; _voice->setInstrument(fmInst); } -void MidiChannel_EuD_FM::pitchBend(int16 value) { +void Towns_EuphonyFmChannel::pitchBend(int16 value) { _voice->pitchBend(value); } -void MidiChannel_EuD_FM::nextTick(int32 *outbuf, int buflen) { +void Towns_EuphonyFmChannel::nextTick(int32 *outbuf, int buflen) { _voice->nextTick((int*) outbuf, buflen); } -void MidiChannel_EuD_FM::rate(uint16 r) { +void Towns_EuphonyFmChannel::rate(uint16 r) { _rate = r; _voice->_rate = r; } -MidiChannel_EuD_WAVE::MidiChannel_EuD_WAVE() { +Towns_EuphonyPcmChannel::Towns_EuphonyPcmChannel() { _voice = new Voice; for (uint8 i = 0; i < 8; i++) { _voice->_env[i] = new Voice::Env; @@ -310,7 +307,7 @@ MidiChannel_EuD_WAVE::MidiChannel_EuD_WAVE() { _current = -1; } -MidiChannel_EuD_WAVE::~MidiChannel_EuD_WAVE() { +Towns_EuphonyPcmChannel::~Towns_EuphonyPcmChannel() { for (uint8 i = 0; i < 8; i++) { if (_voice->_snd[i]) delete _voice->_snd[i]; @@ -319,7 +316,7 @@ MidiChannel_EuD_WAVE::~MidiChannel_EuD_WAVE() { delete _voice; } -void MidiChannel_EuD_WAVE::noteOn(byte note, byte onVelo) { +void Towns_EuphonyPcmChannel::noteOn(byte note, byte onVelo) { _note = note; velocity(onVelo); _phase = 0; @@ -329,24 +326,24 @@ void MidiChannel_EuD_WAVE::noteOn(byte note, byte onVelo) { break; } - _voice->_env[_current]->state = _s_attacking; + _voice->_env[_current]->state = s_attacking; _voice->_env[_current]->currentLevel = 0; _voice->_env[_current]->rate = _rate; _voice->_env[_current]->tickCount = 0; } -void MidiChannel_EuD_WAVE::noteOff(byte note) { +void Towns_EuphonyPcmChannel::noteOff(byte note) { if (_current == -1) return; - if (_voice->_env[_current]->state == _s_ready) + if (_voice->_env[_current]->state == s_ready) return; - _voice->_env[_current]->state = _s_releasing; + _voice->_env[_current]->state = s_releasing; _voice->_env[_current]->releaseLevel = _voice->_env[_current]->currentLevel; _voice->_env[_current]->tickCount = 0; } -void MidiChannel_EuD_WAVE::controlChange(byte control, byte value) { +void Towns_EuphonyPcmChannel::controlChange(byte control, byte value) { switch (control) { case 0x07: // volume @@ -377,7 +374,7 @@ void MidiChannel_EuD_WAVE::controlChange(byte control, byte value) { } } -void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmInst) { +void Towns_EuphonyPcmChannel::sysEx_customInstrument(uint32 type, const byte *fmInst) { if (type == 0x80) { for (uint8 i = 0; i < 8; i++) { const byte * const* pos = (const byte * const*) fmInst; @@ -406,7 +403,7 @@ void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmIns _voice->split[i] = READ_LE_UINT16(fmInst + 16 + 2 * i); _voice->id[i] = READ_LE_UINT32(fmInst + 32 + 4 * i); _voice->_snd[i] = 0; - _voice->_env[i]->state = _s_ready; + _voice->_env[i]->state = s_ready; _voice->_env[i]->currentLevel = 0; _voice->_env[i]->totalLevel = *(fmInst + 64 + 8 * i); _voice->_env[i]->attackRate = *(fmInst + 65 + 8 * i) * 10; @@ -419,11 +416,11 @@ void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmIns } } -void MidiChannel_EuD_WAVE::pitchBend(int16 value) { +void Towns_EuphonyPcmChannel::pitchBend(int16 value) { _frequencyOffs = value; } -void MidiChannel_EuD_WAVE::nextTick(int32 *outbuf, int buflen) { +void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) { if (_current == -1 || !_voice->_snd[_current] || !_voice->_env[_current]->state || !_velocity) { velocity(0); _current = -1; @@ -475,13 +472,13 @@ void MidiChannel_EuD_WAVE::nextTick(int32 *outbuf, int buflen) { } } -void MidiChannel_EuD_WAVE::evpNextTick() { +void Towns_EuphonyPcmChannel::evpNextTick() { switch (_voice->_env[_current]->state) { - case _s_ready: + case s_ready: _voice->_env[_current]->currentLevel = 0; return; - case _s_attacking: + case s_attacking: if (_voice->_env[_current]->attackRate == 0) _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; else if (_voice->_env[_current]->attackRate >= 1270) @@ -493,12 +490,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel >= _voice->_env[_current]->totalLevel) { _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; - _voice->_env[_current]->state = _s_decaying; + _voice->_env[_current]->state = s_decaying; _voice->_env[_current]->tickCount = 0; } break; - case _s_decaying: + case s_decaying: if (_voice->_env[_current]->decayRate == 0) _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; else if (_voice->_env[_current]->decayRate >= 1270) @@ -512,12 +509,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel <= _voice->_env[_current]->sustainLevel) { _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; - _voice->_env[_current]->state = _s_sustaining; + _voice->_env[_current]->state = s_sustaining; _voice->_env[_current]->tickCount = 0; } break; - case _s_sustaining: + case s_sustaining: if (_voice->_env[_current]->sustainRate == 0) _voice->_env[_current]->currentLevel = 0; else if (_voice->_env[_current]->sustainRate >= 2540) @@ -531,12 +528,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel <= 0) { _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->state = _s_ready; + _voice->_env[_current]->state = s_ready; _voice->_env[_current]->tickCount = 0; } break; - case _s_releasing: + case s_releasing: if (_voice->_env[_current]->releaseRate == 0) _voice->_env[_current]->currentLevel = 0; else if (_voice->_env[_current]->releaseRate >= 1270) @@ -550,7 +547,7 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel <= 0) { _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->state = _s_ready; + _voice->_env[_current]->state = s_ready; } break; @@ -559,15 +556,15 @@ void MidiChannel_EuD_WAVE::evpNextTick() { } } -void MidiChannel_EuD_WAVE::rate(uint16 r) { +void Towns_EuphonyPcmChannel::rate(uint16 r) { _rate = r; } -void MidiChannel_EuD_WAVE::velocity(int velo) { +void Towns_EuphonyPcmChannel::velocity(int velo) { _velocity = velo; } -SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer) +Towns_EuphonyDriver::Towns_EuphonyDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) { _volume = 255; _fadestate = EUPHONY_FADEOUT_TICKS; @@ -576,9 +573,9 @@ SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer) MidiDriver_YM2612::createLookupTables(); for (uint8 i = 0; i < 6; i++) - _channel[i] = _fChannel[i] = new MidiChannel_EuD_FM; + _channel[i] = _fChannel[i] = new Towns_EuphonyFmChannel; for (uint8 i = 0; i < 8; i++) - _channel[i + 6] = _wChannel[i] = new MidiChannel_EuD_WAVE; + _channel[i + 6] = _wChannel[i] = new Towns_EuphonyPcmChannel; _channel[14] = _channel[15] = 0; _fmInstruments = _waveInstruments = 0; @@ -587,10 +584,10 @@ SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer) rate(getRate()); fading(0); - _queue = new SoundTowns_EuphonyTrackQueue(this, 0); + _queue = new Towns_EuphonyTrackQueue(this, 0); } -SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() { +Towns_EuphonyDriver::~Towns_EuphonyDriver() { for (int i = 0; i < 6; i++) delete _fChannel[i]; for (int i = 0; i < 8; i++) @@ -622,7 +619,7 @@ SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() { } } -int SoundTowns_EuphonyDriver::open() { +int Towns_EuphonyDriver::open() { if (_isOpen) return MERR_ALREADY_OPEN; MidiDriver_Emulated::open(); @@ -633,18 +630,18 @@ int SoundTowns_EuphonyDriver::open() { return 0; } -void SoundTowns_EuphonyDriver::close() { +void Towns_EuphonyDriver::close() { if (!_isOpen) return; _isOpen = false; _mixer->stopHandle(_mixerSoundHandle); } -void SoundTowns_EuphonyDriver::send(uint32 b) { +void Towns_EuphonyDriver::send(uint32 b) { send(b & 0xF, b & 0xFFFFFFF0); } -void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) { +void Towns_EuphonyDriver::send(byte chan, uint32 b) { byte param2 = (byte) ((b >> 16) & 0xFF); byte param1 = (byte) ((b >> 8) & 0xFF); byte cmd = (byte) (b & 0xF0); @@ -703,18 +700,18 @@ void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) { _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000); break; default: - warning("SoundTowns_EuphonyDriver: Unknown send() command 0x%02X", cmd); + warning("Towns_EuphonyDriver: Unknown send() command 0x%02X", cmd); } } -void SoundTowns_EuphonyDriver::loadFmInstruments(const byte *instr) { +void Towns_EuphonyDriver::loadFmInstruments(const byte *instr) { if (_fmInstruments) delete[] _fmInstruments; _fmInstruments = new uint8[0x1800]; memcpy(_fmInstruments, instr, 0x1800); } -void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) { +void Towns_EuphonyDriver::loadWaveInstruments(const byte *instr) { if (_waveInstruments) delete[] _waveInstruments; _waveInstruments = new uint8[0x1000]; @@ -739,24 +736,24 @@ void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) { } -void SoundTowns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) { +void Towns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) { _channel[midiChannelNumber] = _fChannel[fmChannelNumber]; } -void SoundTowns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) { +void Towns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) { _channel[midiChannelNumber] = _wChannel[waveChannelNumber]; } -void SoundTowns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) { +void Towns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) { _channel[midiChannelNumber] = 0; } -void SoundTowns_EuphonyDriver::generateSamples(int16 *data, int len) { +void Towns_EuphonyDriver::generateSamples(int16 *data, int len) { memset(data, 0, 2 * sizeof(int16) * len); nextTick(data, len); } -void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { +void Towns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { int32 *buf0 = (int32 *)buf1; for (int i = 0; i < ARRAYSIZE(_channel); i++) { @@ -779,26 +776,26 @@ void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { } } -void SoundTowns_EuphonyDriver::rate(uint16 r) { +void Towns_EuphonyDriver::rate(uint16 r) { for (uint8 i = 0; i < 16; i++) { if (_channel[i]) _channel[i]->rate(r); } } -void SoundTowns_EuphonyDriver::fading(bool status) { +void Towns_EuphonyDriver::fading(bool status) { _fading = status; if (!_fading) _fadestate = EUPHONY_FADEOUT_TICKS; } -MidiParser_EuD::MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue) : MidiParser(), +Towns_EuphonyParser::Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue) : MidiParser(), _firstBaseTickStep(0x33), _nextBaseTickStep(0x33) { _initialTempo = calculateTempo(0x5a); _queue = queue; } -void MidiParser_EuD::parseNextEvent(EventInfo &info) { +void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { byte *pos = _position._play_pos; if (_queue->_next) { @@ -878,7 +875,7 @@ void MidiParser_EuD::parseNextEvent(EventInfo &info) { pos += 6; } } else if (cmd == 0xF2) { - static uint16 tickTable [] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; + static const uint16 tickTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; _baseTick += tickTable[_nextBaseTickStep >> 4] * ((_nextBaseTickStep & 0x0f) + 1); _nextBaseTickStep = pos[1]; pos += 6; @@ -920,15 +917,14 @@ void MidiParser_EuD::parseNextEvent(EventInfo &info) { _position._play_pos = pos; } -bool MidiParser_EuD::loadMusic(byte *data, uint32 size) { +bool Towns_EuphonyParser::loadMusic(byte *data, uint32 size) { bool loop = _autoLoop; if (_queue->isPlaying() && !_queue->_loop) { _queue->loadDataToEndOfQueue(data, size, loop); } else { unloadMusic(); - _queue = _queue->reset(); - _queue->release(); + _queue = _queue->release(); _queue->loadDataToCurrentPosition(data, size, loop); setup(); setTrack(0); @@ -937,7 +933,7 @@ bool MidiParser_EuD::loadMusic(byte *data, uint32 size) { return true; } -int32 MidiParser_EuD::calculateTempo(int16 val) { +int32 Towns_EuphonyParser::calculateTempo(int16 val) { int32 tempo = val; if (tempo < 0) @@ -953,7 +949,7 @@ int32 MidiParser_EuD::calculateTempo(int16 val) { return tempo; } -void MidiParser_EuD::resetTracking() { +void Towns_EuphonyParser::resetTracking() { MidiParser::resetTracking(); _nextBaseTickStep = _firstBaseTickStep; @@ -962,7 +958,7 @@ void MidiParser_EuD::resetTracking() { _queue->setPlayBackStatus(false); } -void MidiParser_EuD::setup() { +void Towns_EuphonyParser::setup() { uint8 *data = _queue->trackData(); if (!data) return; @@ -984,7 +980,7 @@ void MidiParser_EuD::setup() { _tracks[0] = data + 0x806; } -SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver * driver, SoundTowns_EuphonyTrackQueue * last) { +Towns_EuphonyTrackQueue::Towns_EuphonyTrackQueue(Towns_EuphonyDriver * driver, Towns_EuphonyTrackQueue * last) { _trackData = 0; _next = 0; _driver = driver; @@ -993,22 +989,15 @@ SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDri _playing = false; } -void SoundTowns_EuphonyTrackQueue::setPlayBackStatus(bool playing) { - SoundTowns_EuphonyTrackQueue * i = this; +void Towns_EuphonyTrackQueue::setPlayBackStatus(bool playing) { + Towns_EuphonyTrackQueue * i = this; do { i->_playing = playing; i = i->_next; } while (i); } -SoundTowns_EuphonyTrackQueue * SoundTowns_EuphonyTrackQueue::reset() { - SoundTowns_EuphonyTrackQueue * i = this; - while (i->_last) - i = i->_last; - return i; -} - -void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) { +void Towns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) { if (_trackData) delete[] _trackData; _trackData = new uint8[0xC58A]; @@ -1022,17 +1011,17 @@ void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, _playing = false; } -void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) { +void Towns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) { if (!_trackData) { loadDataToCurrentPosition(trackdata, size, loop); return; } - SoundTowns_EuphonyTrackQueue * i = this; + Towns_EuphonyTrackQueue * i = this; while (i->_next) i = i->_next; - i = i->_next = new SoundTowns_EuphonyTrackQueue(_driver, i); + i = i->_next = new Towns_EuphonyTrackQueue(_driver, i); i->_trackData = new uint8[0xC58A]; memset(i->_trackData, 0, 0xC58A); Screen::decodeFrame4(trackdata, i->_trackData, size); @@ -1044,29 +1033,39 @@ void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint3 i->_playing = _playing; } -void SoundTowns_EuphonyTrackQueue::release() { - SoundTowns_EuphonyTrackQueue * i = _next; - _next = 0; - _playing = false; - _used = _fchan = _wchan = 0; +Towns_EuphonyTrackQueue *Towns_EuphonyTrackQueue::release() { + Towns_EuphonyTrackQueue *i = this; + while (i->_next) + i = i->_next; - if (_trackData) { - delete[] _trackData; - _trackData = 0; - } + Towns_EuphonyTrackQueue *res = i; while (i) { + i->_playing = false; + i->_used = i->_fchan = i->_wchan = 0; if (i->_trackData) { delete[] i->_trackData; i->_trackData = 0; } - i = i->_next; - if (i) - delete i->_last; + i = i->_last; + if (i) { + res = i; + if (i->_next) { + delete i->_next; + i->_next = 0; + } + } } + + if (res->_trackData) { + delete[] res->_trackData; + res->_trackData = 0; + } + + return res; } -void SoundTowns_EuphonyTrackQueue::initDriver() { +void Towns_EuphonyTrackQueue::initDriver() { for (uint8 i = 0; i < 6; i++) { if (_used[_fchan[i]]) _driver->assignFmChannel(_fchan[i], i); @@ -1084,11 +1083,1685 @@ void SoundTowns_EuphonyTrackQueue::initDriver() { _driver->send(0x79B0); } +class TownsPC98_OpnOperator { +public: + TownsPC98_OpnOperator(double rate, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); + ~TownsPC98_OpnOperator() {} + + void keyOn(); + void keyOff(); + void frequency(int freq); + void updatePhaseIncrement(); + void recalculateRates(); + void generateOutput(int phasebuf, int *_feedbuf, int &out); + + void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } + void detune(int value) { _detn = &_detnTbl[value << 5]; } + void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } + void attackRate(uint32 value) { _specifiedAttackRate = value; } + bool scaleRate(uint8 value); + void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } + void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } + void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } + void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } + void totalLevel(uint32 value) { _totalLevel = value << 3; } + void reset(); + +protected: + EnvelopeState _state; + uint32 _feedbackLevel; + uint32 _multiple; + uint32 _totalLevel; + uint8 _keyScale1; + uint8 _keyScale2; + uint32 _specifiedAttackRate; + uint32 _specifiedDecayRate; + uint32 _specifiedSustainRate; + uint32 _specifiedReleaseRate; + uint32 _tickCount; + uint32 _sustainLevel; + + uint32 _frequency; + uint8 _kcode; + uint32 _phase; + uint32 _phaseIncrement; + const int32 *_detn; + + const uint8 *_rateTbl; + const uint8 *_rshiftTbl; + const uint8 *_adTbl; + const uint32 *_fTbl; + const uint32 *_sinTbl; + const int32 *_tLvlTbl; + const int32 *_detnTbl; + + const double _tickLength; + double _tick; + int32 _currentLevel; + + struct EvpState { + uint8 rate; + uint8 shift; + } fs_a, fs_d, fs_s, fs_r; +}; + +TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : + _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), + _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0), + _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), + _phase(0), _state(s_ready) { + + reset(); +} + +void TownsPC98_OpnOperator::keyOn() { + _state = s_attacking; + _phase = 0; +} + +void TownsPC98_OpnOperator::keyOff() { + if (_state != s_ready) + _state = s_releasing; +} + +void TownsPC98_OpnOperator::frequency(int freq) { + uint8 block = (freq >> 11); + uint16 pos = (freq & 0x7ff); + uint8 c = pos >> 7; + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); + _frequency = _fTbl[pos << 1] >> (7 - block); +} + +void TownsPC98_OpnOperator::updatePhaseIncrement() { + _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1; + uint8 keyscale = _kcode >> _keyScale1; + if (_keyScale2 != keyscale) { + _keyScale2 = keyscale; + recalculateRates(); + } +} + +void TownsPC98_OpnOperator::recalculateRates() { + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + + r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0; + fs_d.rate = _rateTbl[r + k]; + fs_d.shift = _rshiftTbl[r + k]; + + r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0; + fs_s.rate = _rateTbl[r + k]; + fs_s.shift = _rshiftTbl[r + k]; + + r = (_specifiedReleaseRate << 2) + 0x22; + fs_r.rate = _rateTbl[r + k]; + fs_r.shift = _rshiftTbl[r + k]; +} + +void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) { + if (_state == s_ready) + return; + + _tick += _tickLength; + while (_tick > 0x30000) { + _tick -= 0x30000; + ++_tickCount; + + int32 levelIncrement = 0; + uint32 targetTime = 0; + int32 targetLevel = 0; + EnvelopeState next_state = s_ready; + + switch (_state) { + case s_ready: + return; + case s_attacking: + next_state = s_decaying; + targetTime = (1 << fs_a.shift) - 1; + targetLevel = 0; + levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; + break; + case s_decaying: + targetTime = (1 << fs_d.shift) - 1; + next_state = s_sustaining; + targetLevel = _sustainLevel; + levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; + break; + case s_sustaining: + targetTime = (1 << fs_s.shift) - 1; + next_state = s_ready; + targetLevel = 1023; + levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; + break; + case s_releasing: + targetTime = (1 << fs_r.shift) - 1; + next_state = s_ready; + targetLevel = 1023; + levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; + break; + } + + if (!(_tickCount & targetTime)) { + _currentLevel += levelIncrement; + if ((!targetLevel && _currentLevel <= targetLevel) || (targetLevel && _currentLevel >= targetLevel)) { + if (_state != s_decaying) + _currentLevel = targetLevel; + if (_state != s_sustaining) + _state = next_state; + } + } + } + + uint32 lvlout = _totalLevel + (uint32) _currentLevel; + + int outp = 0; + int *i = &outp, *o = &outp; + int phaseShift = 0; + + if (_feedbuf) { + o = &_feedbuf[0]; + i = &_feedbuf[1]; + phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0; + if (phasebuf == -1) + *i = 0; + *o = *i; + } else { + phaseShift = phasebuf << 15; + } + + if (lvlout < 832) { + uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) + + phaseShift)) >> 16) & 0x3ff]; + *i = ((index < 6656) ? _tLvlTbl[index] : 0); + } else { + *i = 0; + } + + _phase += _phaseIncrement; + out += *o; + if (out > 32767) + out = 32767; + if (out < -32767) + out = -32767; +} + +void TownsPC98_OpnOperator::reset(){ + keyOff(); + _tick = 0; + _keyScale2 = 0; + _currentLevel = 1023; + + frequency(0); + detune(0); + scaleRate(0); + multiple(0); + updatePhaseIncrement(); + attackRate(0); + decayRate(0); + releaseRate(0); + sustainRate(0); + feedbackLevel(0); + totalLevel(127); +} + +bool TownsPC98_OpnOperator::scaleRate(uint8 value) { + value = 3 - value; + if (_keyScale1 != value) { + _keyScale1 = value; + return true; + } + + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + return false; +} + +class TownsPC98_OpnDriver; +class TownsPC98_OpnChannel { +public: + TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, + uint8 key, uint8 prt, uint8 id); + virtual ~TownsPC98_OpnChannel(); + virtual void init(); + + typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); + + typedef enum channelState { + CHS_RECALCFREQ = 0x01, + CHS_KEYOFF = 0x02, + CHS_SSG = 0x04, + CHS_PITCHWHEELOFF = 0x08, + CHS_ALL_BUT_EOT = 0x0f, + CHS_EOT = 0x80 + } ChannelState; + + virtual void loadData(uint8 *data); + virtual void processEvents(); + virtual void processFrequency(); + bool processControlEvent(uint8 cmd); + void writeReg(uint8 regAdress, uint8 value); + + virtual void keyOn(); + virtual void keyOff(); + + void setOutputLevel(); + void fadeStep(); + void reset(); + + void updateEnv(); + void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed); + + bool _enableLeft; + bool _enableRight; + bool _updateEnvelopes; + const uint8 _idFlag; + int _feedbuf[3]; + +protected: + bool control_dummy(uint8 para); + bool control_f0_setPatch(uint8 para); + bool control_f1_presetOutputLevel(uint8 para); + bool control_f2_setKeyOffTime(uint8 para); + bool control_f3_setFreqLSB(uint8 para); + bool control_f4_setOutputLevel(uint8 para); + bool control_f5_setTempo(uint8 para); + bool control_f6_repeatSection(uint8 para); + bool control_f7_setupPitchWheel(uint8 para); + bool control_f8_togglePitchWheel(uint8 para); + bool control_fa_writeReg(uint8 para); + bool control_fb_incOutLevel(uint8 para); + bool control_fc_decOutLevel(uint8 para); + bool control_fd_jump(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + bool control_f0_setPatchSSG(uint8 para); + bool control_f1_setTotalLevel(uint8 para); + bool control_f4_setAlgorithm(uint8 para); + bool control_f9_unkSSG(uint8 para); + bool control_fb_incOutLevelSSG(uint8 para); + bool control_fc_decOutLevelSSG(uint8 para); + bool control_ff_endOfTrackSSG(uint8 para); + + uint8 _ticksLeft; + uint8 _algorithm; + uint8 _instrID; + uint8 _totalLevel; + uint8 _frqBlockMSB; + int8 _frqLSB; + uint8 _keyOffTime; + bool _protect; + uint8 *_dataPtr; + uint8 _ptchWhlInitDelayLo; + uint8 _ptchWhlInitDelayHi; + int16 _ptchWhlModInitVal; + uint8 _ptchWhlDuration; + uint8 _ptchWhlCurDelay; + int16 _ptchWhlModCurVal; + uint8 _ptchWhlDurLeft; + uint16 frequency; + uint8 _regOffset; + uint8 _flags; + uint8 _ssg1; + uint8 _ssg2; + + const uint8 _chanNum; + const uint8 _keyNum; + const uint8 _part; + + TownsPC98_OpnDriver *_drv; + TownsPC98_OpnOperator **_opr; + uint16 _frqTemp; + + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel { +public: + TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + ~TownsPC98_OpnChannelSSG() {} + void init(); + + void processEvents(); + void processFrequency(); + + void keyOn(); + void keyOff(); + void loadData(uint8 *data); + +private: + void opn_SSG_UNK(uint8 a); +}; + + +class TownsPC98_OpnDriver : public Audio::AudioStream { +friend class TownsPC98_OpnChannel; +friend class TownsPC98_OpnChannelSSG; +public: + enum OpnType { + OD_TOWNS, + OD_TYPE26, + OD_TYPE86 + }; + + TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type); + ~TownsPC98_OpnDriver(); + + bool init(); + void loadData(uint8 *data, bool loadPaused = false); + void reset(); + void fadeOut(); + + void pause() { _playing = false; } + void cont() { _playing = true; } + + void callback(); + void nextTick(int16 *buffer, uint32 bufferSize); + + bool looping() { return _looping == _updateChannelsFlag ? true : false; } + + // AudioStream interface + int inline readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return true; } + bool endOfData() const { return false; } + int getRate() const { return _mixer->getOutputRate(); } + +protected: + void generateTables(); + + TownsPC98_OpnChannel **_channels; + TownsPC98_OpnChannelSSG **_ssgChannels; + //TownsPC98_OpnChannel *_adpcmChannel; + + void setTempo(uint8 tempo); + + void lock() { _mutex.lock(); } + void unlock() { _mutex.unlock(); } + + Audio::Mixer *_mixer; + Common::Mutex _mutex; + Audio::SoundHandle _soundHandle; + + const uint8 *_opnCarrier; + const uint8 *_opnFreqTable; + const uint8 *_opnFxCmdLen; + const uint8 *_opnLvlPresets; + + uint8 *_oprRates; + uint8 *_oprRateshift; + uint8 *_oprAttackDecay; + uint32 *_oprFrq; + uint32 *_oprSinTbl; + int32 *_oprLevelOut; + int32 *_oprDetune; + + uint8 *_trackData; + uint8 *_patches; + + uint8 _cbCounter; + uint8 _updateChannelsFlag; + uint8 _finishedChannelsFlag; + uint16 _tempo; + bool _playing; + bool _fading; + uint8 _looping; + uint32 _tickCounter; + + bool _updateEnvelopes; + int _ssgFlag; + + int32 _samplesTillCallback; + int32 _samplesTillCallbackRemainder; + int32 _samplesPerCallback; + int32 _samplesPerCallbackRemainder; + + const int _numChan; + const int _numSSG; + const bool _hasADPCM; + const bool _hasStereo; + + double _baserate; + static const uint8 _drvTables[]; + static const uint32 _adtStat[]; + bool _ready; +}; + +TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, + uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), + _part(prt), _idFlag(id) { + + _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _ssg1 = _ssg2 = 0; + _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0; + _frqLSB = 0; + _protect = _updateEnvelopes = false; + _enableLeft = _enableRight = true; + _dataPtr = 0; + _ptchWhlModInitVal = _ptchWhlModCurVal = 0; + frequency = _frqTemp = 0; + memset(&_feedbuf, 0, sizeof(int) * 3); + _opr = 0; +} + +TownsPC98_OpnChannel::~TownsPC98_OpnChannel() { + if (_opr) { + for (int i = 0; i < 4; i++) + delete _opr[i]; + delete [] _opr; + } +} + +void TownsPC98_OpnChannel::init() { + + _opr = new TownsPC98_OpnOperator*[4]; + for (int i = 0; i < 4; i++) + _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, + _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); + + #define Control(x) &TownsPC98_OpnChannel::control_##x + static const ControlEventFunc ctrlEvents[] = { + Control(f0_setPatch), + Control(f1_presetOutputLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setOutputLevel), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupPitchWheel), + Control(f8_togglePitchWheel), + Control(dummy), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control + + controlEvents = ctrlEvents; +} + +void TownsPC98_OpnChannel::keyOff() { + // all operators off + uint8 value = _keyNum & 0x0f; + uint8 regAdress = 0x28; + writeReg(regAdress, value); + _flags |= CHS_KEYOFF; +} + +void TownsPC98_OpnChannel::keyOn() { + // all operators on + uint8 value = _keyNum | 0xf0; + uint8 regAdress = 0x28; + writeReg(regAdress, value); +} + +void TownsPC98_OpnChannel::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; + + uint8 *src_b = _dataPtr; + int loop = 1; + uint8 cmd = 0; + while (loop) { + if (loop == 1) { + cmd = *src_b++; + if (cmd < 0xf0) { + src_b++; + loop = 1; + } else { + if (cmd == 0xff) { + loop = *src_b ? 2 : 0; + if (READ_LE_UINT16(src_b)) + _drv->_looping |= _idFlag; + } else if (cmd == 0xf6) { + loop = 3; + } else { + loop = 2; + } + } + } else if (loop == 2) { + src_b += _drv->_opnFxCmdLen[cmd - 240]; + loop = 1; + } else if (loop == 3) { + src_b[0] = src_b[1]; + src_b += 4; + loop = 1; + } + } +} + +void TownsPC98_OpnChannel::processEvents() { + if (_flags & CHS_EOT) + return; + + if (_protect == false && _ticksLeft == _keyOffTime) + keyOff(); + + if (--_ticksLeft) + return; + + if (_protect == false) + keyOff(); + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + keyOff(); + _protect = false; + } else { + keyOn(); + + if (_protect == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _protect = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; +} + +void TownsPC98_OpnChannel::processFrequency() { + if (_flags & CHS_RECALCFREQ) { + uint8 block = (_frqBlockMSB & 0x70) >> 1; + uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; + frequency = (bfreq + _frqLSB) | (block << 8); + + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); + + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + if (_flags & CHS_KEYOFF) { + _ptchWhlModCurVal = _ptchWhlModInitVal; + _ptchWhlCurDelay += _ptchWhlInitDelayLo; + } + + _ptchWhlDurLeft = (_ptchWhlDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + } + + if (!(_flags & CHS_PITCHWHEELOFF)) { + if (--_ptchWhlCurDelay) + return; + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + frequency += _ptchWhlModCurVal; + + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); + + if(!--_ptchWhlDurLeft) { + _ptchWhlDurLeft = _ptchWhlDuration; + _ptchWhlModCurVal = -_ptchWhlModCurVal; + } + } +} + +bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +void TownsPC98_OpnChannel::setOutputLevel() { + uint8 outopr = _drv->_opnCarrier[_algorithm]; + uint8 reg = 0x40 + _regOffset; + + for (int i = 0; i < 4; i++) { + if (outopr & 1) + writeReg(reg, _totalLevel); + outopr >>= 1; + reg += 4; + } +} + +void TownsPC98_OpnChannel::fadeStep() { + _totalLevel += 3; + if (_totalLevel > 0x7f) + _totalLevel = 0x7f; + setOutputLevel(); +} + +void TownsPC98_OpnChannel::reset() { + for (int i = 0; i < 4; i++) + _opr[i]->reset(); + + _updateEnvelopes = false; + _enableLeft = _enableRight = true; + memset(&_feedbuf, 0, sizeof(int) * 3); +} + +void TownsPC98_OpnChannel::updateEnv() { + for (int i = 0; i < 4 ; i++) + _opr[i]->updatePhaseIncrement(); +} + +void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) { + int phbuf1, phbuf2, output; + phbuf1 = phbuf2 = output = 0; + + switch (_algorithm) { + case 0: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(*del, 0, phbuf2); + *del = 0; + _opr[1]->generateOutput(phbuf1, 0, *del); + _opr[3]->generateOutput(phbuf2, 0, output); + break; + case 1: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(*del, 0, phbuf2); + _opr[1]->generateOutput(0, 0, phbuf1); + _opr[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 2: + _opr[0]->generateOutput(0, feed, phbuf2); + _opr[2]->generateOutput(*del, 0, phbuf2); + _opr[1]->generateOutput(0, 0, phbuf1); + _opr[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 3: + _opr[0]->generateOutput(0, feed, phbuf2); + _opr[2]->generateOutput(0, 0, *del); + _opr[1]->generateOutput(phbuf2, 0, phbuf1); + _opr[3]->generateOutput(*del, 0, output); + *del = phbuf1; + break; + case 4: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(0, 0, phbuf2); + _opr[1]->generateOutput(phbuf1, 0, output); + _opr[3]->generateOutput(phbuf2, 0, output); + *del = 0; + break; + case 5: + *del = feed[1]; + _opr[0]->generateOutput(-1, feed, phbuf1); + _opr[2]->generateOutput(*del, 0, output); + _opr[1]->generateOutput(*del, 0, output); + _opr[3]->generateOutput(*del, 0, output); + break; + case 6: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(0, 0, output); + _opr[1]->generateOutput(phbuf1, 0, output); + _opr[3]->generateOutput(0, 0, output); + *del = 0; + break; + case 7: + _opr[0]->generateOutput(0, feed, output); + _opr[2]->generateOutput(0, 0, output); + _opr[1]->generateOutput(0, 0, output); + _opr[3]->generateOutput(0, 0, output); + *del = 0; + break; + }; + + if (_enableLeft) { + int l = output + leftSample; + if (l > 32767) + l = 32767; + if (l < -32767) + l = -32767; + leftSample = (int16) l; + } + + if (_enableRight) { + int r = output + rightSample; + if (r > 32767) + r = 32767; + if (r < -32767) + r = -32767; + rightSample = (int16) r; + } +} + +void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { + uint8 h = regAdress & 0xf0; + uint8 l = (regAdress & 0x0f); + static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; + uint8 o = oprOrdr[(l - _regOffset) >> 2]; + + switch (h) { + case 0x00: + // ssg + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + case 0x10: + // adpcm + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + case 0x20: + if (l == 8) { + // Key on/off + for (int i = 0; i < 4; i++) { + if ((value >> (4 + i)) & 1) + _opr[i]->keyOn(); + else + _opr[i]->keyOff(); + } + } else if (l == 2) { + // LFO + warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); + } else if (l == 7) { + // Timers; Ch 3/6 special mode + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)"); + } else if (l == 4 || l == 5) { + // Timer A + warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)"); + } else if (l == 6) { + // Timer B + warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)"); + } else if (l == 10 || l == 11) { + // DAC + warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); + } + break; + + case 0x30: + // detune, multiple + _opr[o]->detune((value >> 4) & 7); + _opr[o]->multiple(value & 0x0f); + _updateEnvelopes = true; + break; + + case 0x40: + // total level + _opr[o]->totalLevel(value & 0x7f); + break; + + case 0x50: + // rate scaling, attack rate + _opr[o]->attackRate(value & 0x1f); + if (_opr[o]->scaleRate(value >> 6)) + _updateEnvelopes = true; + break; + + case 0x60: + // first decay rate, amplitude modulation + _opr[o]->decayRate(value & 0x1f); + if (value & 0x80) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); + + break; + + case 0x70: + // secondary decay rate + _opr[o]->sustainRate(value & 0x1f); + break; + + case 0x80: + // secondary amplitude, release rate; + _opr[o]->sustainLevel(value >> 4); + _opr[o]->releaseRate(value & 0x0f); + break; + + case 0x90: + // ssg + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + + case 0xa0: + // frequency + l -= _regOffset; + if (l == 0) { + _frqTemp = (_frqTemp & 0xff00) | value; + _updateEnvelopes = true; + for (int i = 0; i < 4; i++) + _opr[i]->frequency(_frqTemp); + } else if (l == 4) { + _frqTemp = (_frqTemp & 0xff) | (value << 8); + } else if (l == 8) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } else if (l == 12) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } + break; + + case 0xb0: + l -= _regOffset; + if (l == 0) { + // feedback, _algorithm + _opr[0]->feedbackLevel((value >> 3) & 7); + _opr[1]->feedbackLevel(0); + _opr[2]->feedbackLevel(0); + _opr[3]->feedbackLevel(0); + } else if (l == 4) { + // stereo, LFO sensitivity + _enableLeft = value & 0x80 ? true : false; + _enableRight = value & 0x40 ? true : false; + uint8 ams = (value & 0x3F) >> 3; + if (ams) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); + uint8 fms = value & 3; + if (fms) + warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); + } + break; + + default: + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + } +} + +bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { + _instrID = para; + uint8 reg = _regOffset + 0x80; + + for (int i = 0; i < 4; i++) { + // set release rate for each operator + writeReg(reg, 0x0f); + reg += 4; + } + + const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5); + reg = _regOffset + 0x30; + + // write registers 0x30 to 0x8f + for (int i = 0; i < 6; i++) { + writeReg(reg, tptr[0]); + reg += 4; + writeReg(reg, tptr[2]); + reg += 4; + writeReg(reg, tptr[1]); + reg += 4; + writeReg(reg, tptr[3]); + reg += 4; + tptr += 4; + } + + reg = _regOffset + 0xB0; + _algorithm = tptr[0] & 7; + // set feedback and algorithm + writeReg(reg, tptr[0]); + + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) { + if (_drv->_fading) + return true; + + _totalLevel = _drv->_opnLvlPresets[para]; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_f2_setKeyOffTime(uint8 para) { + _keyOffTime = para; + return true; +} + +bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) { + _frqLSB = (int8) para; + return true; +} + +bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) { + if (_drv->_fading) + return true; + + _totalLevel = para; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) { + _drv->setTempo(para); + return true; +} + +bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { + _dataPtr--; + _dataPtr[0]--; + + if (*_dataPtr) { + // repeat section until counter has reached zero + _dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2); + } else { + // reset counter, advance to next section + _dataPtr[0] = _dataPtr[1]; + _dataPtr += 4; + } + return true; +} + +bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) { + _ptchWhlInitDelayLo = _dataPtr[0]; + _ptchWhlInitDelayHi = para; + _ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); + _ptchWhlDuration = _dataPtr[3]; + _dataPtr += 4; + _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ; + return true; +} + +bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) { + if (para == 0x10) { + if (*_dataPtr++) { + _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF; + } else { + _flags |= CHS_PITCHWHEELOFF; + } + } else { + //uint8 skipChannels = para / 36; + //uint8 entry = para % 36; + //TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; + ////// NOT IMPLEMENTED + //t->unnamedEntries[entry] = *_dataPtr++; + } + return true; +} + +bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) { + writeReg(para, *_dataPtr++); + return true; +} + +bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + uint8 val = (_totalLevel + 3); + if (val > 0x7f) + val = 0x7f; + + _totalLevel = val; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + int8 val = (int8) (_totalLevel - 3); + if (val < 0) + val = 0; + + _totalLevel = (uint8) val; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) { + uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1); + _dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr; + return true; +} + +bool TownsPC98_OpnChannel::control_dummy(uint8 para) { + _dataPtr--; + return true; +} + +bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackData + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedChannelsFlag |= _idFlag; + keyOff(); + return false; + } +} + +bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) { + _instrID = para << 4; + para = (para >> 3) & 0x1e; + if (para) + return control_f4_setAlgorithm(para | 0x40); + return true; +} + +bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) { + if (!_drv->_fading) + _totalLevel = para; + return true; +} + +bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) { + _algorithm = para; + return true; +} + +bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) { + _dataPtr += 5; + return true; +} + +bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + + return true; +} + +bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + if(_totalLevel + 1 < 0x10) + _totalLevel++; + + return true; +} + +bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackData + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + //_finishedChannelsFlag |= _idFlag; + keyOff(); + return false; + } +} + +TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { +} + +void TownsPC98_OpnChannelSSG::init() { + _algorithm = 0x80; + + _opr = new TownsPC98_OpnOperator*[4]; + for (int i = 0; i < 4; i++) + _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, + _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); + + #define Control(x) &TownsPC98_OpnChannelSSG::control_##x + static const ControlEventFunc ctrlEventsSSG[] = { + Control(f0_setPatchSSG), + Control(f1_setTotalLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setOutputLevel), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupPitchWheel), + Control(f8_togglePitchWheel), + Control(f9_unkSSG), + Control(fa_writeReg), + Control(fb_incOutLevelSSG), + Control(fc_decOutLevelSSG), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrackSSG) + }; + #undef Control + + controlEvents = ctrlEventsSSG; +} + +void TownsPC98_OpnChannelSSG::processEvents() { + if (_flags & CHS_EOT) + return; + + _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; + + if (_protect == false && _ticksLeft == _keyOffTime) + keyOff(); + + if (--_ticksLeft) + return; + + if (_protect == false) + keyOff(); + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + keyOff(); + _protect = false; + } else { + keyOn(); + + if (_protect == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _protect = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; + + if (!(_flags & CHS_SSG)) { + + } +} + +void TownsPC98_OpnChannelSSG::processFrequency() { + if (_flags & CHS_RECALCFREQ) { + uint8 block = (_frqBlockMSB & 0x70) >> 1; + uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; + frequency = (bfreq + _frqLSB) | (block << 8); + + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); + + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + if (_flags & CHS_KEYOFF) { + _ptchWhlModCurVal = _ptchWhlModInitVal; + _ptchWhlCurDelay += _ptchWhlInitDelayLo; + } + + _ptchWhlDurLeft = (_ptchWhlDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + } + + if (!(_flags & CHS_PITCHWHEELOFF)) { + if (--_ptchWhlCurDelay) + return; + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + frequency += _ptchWhlModCurVal; + + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); + + if(!--_ptchWhlDurLeft) { + _ptchWhlDurLeft = _ptchWhlDuration; + _ptchWhlModCurVal = -_ptchWhlModCurVal; + } + } +} + +void TownsPC98_OpnChannelSSG::keyOff() { + // all operators off + uint8 value = _keyNum & 0x0f; + uint8 regAdress = 0x28; + writeReg(regAdress, value); + _flags |= CHS_KEYOFF; +} + +void TownsPC98_OpnChannelSSG::keyOn() { + // all operators on + uint8 value = _keyNum | 0xf0; + uint8 regAdress = 0x28; + writeReg(regAdress, value); +} + +void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { + _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; + opn_SSG_UNK(0); + TownsPC98_OpnChannel::loadData(data); + _algorithm = 0x80; +} + +void TownsPC98_OpnChannelSSG::opn_SSG_UNK(uint8 a) { + _ssg1 = a; + uint16 h = (_totalLevel + 1) * a; + if ((h >> 8) == _ssg2) + return; + _ssg2 = (h >> 8); + writeReg(8 + _regOffset, _ssg2); +} + +TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : + _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0), + _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), + _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), + _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), + _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false), + _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), + _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { + setTempo(84); + _baserate = (3579545.0 / (double)getRate()) / 144.0; +} + +TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { + _mixer->stopHandle(_soundHandle); + + if (_channels) { + for (int i = 0; i < _numChan; i++) + delete _channels[i]; + delete [] _channels; + } + + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) + delete _ssgChannels[i]; + delete [] _ssgChannels; + } + + delete [] _oprRates; + delete [] _oprRateshift; + delete [] _oprFrq; + delete [] _oprAttackDecay; + delete [] _oprSinTbl; + delete [] _oprLevelOut; + delete [] _oprDetune; +} + +bool TownsPC98_OpnDriver::init() { + if (_ready) { + reset(); + return true; + } + + generateTables(); + + if (_channels) { + for (int i = 0; i < _numChan; i++) { + if (_channels[i]) + delete _channels[i]; + } + delete [] _channels; + } + _channels = new TownsPC98_OpnChannel*[_numChan]; + for (int i = 0; i < _numChan; i++) { + int ii = i * 6; + _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _channels[i]->init(); + } + + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) { + if (_ssgChannels[i]) + delete _ssgChannels[i]; + } + delete [] _ssgChannels; + } + if (_numSSG) { + _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG]; + for (int i = 0; i < _numSSG; i++) { + int ii = i * 6; + _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _ssgChannels[i]->init(); + } + } + + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, + &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); + + _ready = true; + return true; +} + +int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) { + memset(buffer, 0, sizeof(int16) * numSamples); + int32 samplesLeft = numSamples >> 1; + while (samplesLeft) { + if (!_samplesTillCallback) { + callback(); + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= _tempo) { + _samplesTillCallback++; + _samplesTillCallbackRemainder -= _tempo; + } + } + + int32 render = MIN(samplesLeft, _samplesTillCallback); + samplesLeft -= render; + _samplesTillCallback -= render; + + nextTick(buffer, render); + + for (int i = 0; i < render; ++i) { + buffer[i << 1] <<= 2; + buffer[(i << 1) + 1] <<= 2; + } + + buffer += (render << 1); + } + + return numSamples; +} + +void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { + if (!_ready) { + warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); + return; + } + + if (!data) { + warning("TownsPC98_OpnDriver: Invalid music file data"); + return; + } + + lock(); + _trackData = data; + + reset(); + + uint8 *src_a = data; + + for (uint8 i = 0; i < 3; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (uint8 i = 3; i < _numChan; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + if (_hasADPCM) { + //_adpcmChannel->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + _ssgFlag = 0; + + _patches = src_a + 4; + _cbCounter = 4; + _finishedChannelsFlag = 0; + + // AH 0x17 + unlock(); + _playing = (loadPaused ? false : true); +} + +void TownsPC98_OpnDriver::reset() { + for (int i = 0; i < (_numChan); i++) + _channels[i]->reset(); + for (int i = 0; i < (_numSSG); i++) + _ssgChannels[i]->reset(); + + _playing = _fading = false; + _looping = 0; + _tickCounter = 0; +} + +void TownsPC98_OpnDriver::fadeOut() { + if (!_playing) + return; + + _fading = true; + + for (int i = 0; i < 20; i++) { + lock(); + uint32 dTime = _tickCounter + 2; + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->_idFlag) + _channels[j]->fadeStep(); + } + for (int j = 0; j < _numSSG; j++) + _ssgChannels[j]->fadeStep(); + + unlock(); + + while (_playing) { + if (_tickCounter >= dTime) + break; + } + } + + _fading = false; + + reset(); +} + +void TownsPC98_OpnDriver::callback() { + if (!_playing || --_cbCounter) + return; + + _cbCounter = 4; + _tickCounter++; + + lock(); + + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } + + if (_numSSG) { + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } + + _ssgFlag = 0; + + unlock(); + + if (_finishedChannelsFlag == _updateChannelsFlag) + reset(); +} + +void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { + if (!_playing) + return; + + for (int i = 0; i < _numChan ; i++) { + if (_channels[i]->_updateEnvelopes) { + _channels[i]->_updateEnvelopes = false; + _channels[i]->updateEnv(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) + _channels[i]->generateOutput(buffer[ii * 2], + buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf); + } + + for (int i = 0; i < _numSSG ; i++) { + if (_ssgChannels[i]->_updateEnvelopes) { + _ssgChannels[i]->_updateEnvelopes = false; + _ssgChannels[i]->updateEnv(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) + _ssgChannels[i]->generateOutput(buffer[ii * 2], + buffer[ii * 2 + 1], &_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf); + } +} + +void TownsPC98_OpnDriver::generateTables() { + delete [] _oprRates; + _oprRates = new uint8[128]; + memset(_oprRates, 0x90, 32); + uint8 *dst = (uint8*) _oprRates + 32; + for (int i = 0; i < 48; i += 4) + WRITE_BE_UINT32(dst + i, 0x00081018); + dst += 48; + for (uint8 i = 0; i < 16; i ++) { + uint8 v = (i < 12) ? i : 12; + *dst++ = ((4 + v) << 3); + } + memset(dst, 0x80, 32); + + delete [] _oprRateshift; + _oprRateshift = new uint8[128]; + memset(_oprRateshift, 0, 128); + dst = (uint8*) _oprRateshift + 32; + for (int i = 11; i; i--) { + memset(dst, i, 4); + dst += 4; + } + + delete [] _oprFrq; + _oprFrq = new uint32[0x1000]; + for (uint32 i = 0; i < 0x1000; i++) + _oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); + + delete [] _oprAttackDecay; + _oprAttackDecay = new uint8[152]; + memset(_oprAttackDecay, 0, 152); + for (int i = 0; i < 36; i++) + WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); + + delete [] _oprSinTbl; + _oprSinTbl = new uint32[1024]; + for (int i = 0; i < 1024; i++) { + double val = sin((double) (((i << 1) + 1) * PI / 1024.0)); + double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; + int32 i_dcb = (int32)(2.0 * d_dcb); + i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); + _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); + } + + delete [] _oprLevelOut; + _oprLevelOut = new int32[0x1a00]; + for (int i = 0; i < 256; i++) { + double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); + int32 val_int = ((int32) val) >> 4; + _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; + _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; + for (int ii = 1; ii < 13; ii++) { + _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; + _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; + } + } + + uint8 *dtt = new uint8[128]; + memset(dtt, 0, 36); + memset(dtt + 36, 1, 8); + memcpy(dtt + 44, _drvTables + 144, 84); + + delete [] _oprDetune; + _oprDetune = new int32[256]; + for (int i = 0; i < 128; i++) { + _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); + _oprDetune[i + 128] = -_oprDetune[i]; + } + + delete [] dtt; +} + +void TownsPC98_OpnDriver::setTempo(uint8 tempo) { + _tempo = tempo; + _samplesPerCallback = getRate() / _tempo; + _samplesPerCallbackRemainder = getRate() % _tempo; +} + +const uint8 TownsPC98_OpnDriver::_drvTables[] = { + // channel presets + 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, + 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, + 0x00, 0x80, 0x03, 0x04, 0x01, 0x08, + 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, + 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, + + // control event size + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, + 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, + + // fmt level presets + 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, + 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, + 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, + + // carriers + 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, + + // frequencies + 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, + 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, + 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, + 0x00, 0x00, 0x00, 0x00, + + // unused + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // detune + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x16, 0x16, 0x16, 0x16, + + // pc98 level presets + 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, + 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, + 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90 +}; + +const uint32 TownsPC98_OpnDriver::_adtStat[] = { + 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010101, 0x00010101, 0x00010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010102, 0x01010102, + 0x01020102, 0x01020102, 0x01020202, 0x01020202, + 0x02020202, 0x02020202, 0x02020204, 0x02020204, + 0x02040204, 0x02040204, 0x02040404, 0x02040404, + 0x04040404, 0x04040404, 0x04040408, 0x04040408, + 0x04080408, 0x04080408, 0x04080808, 0x04080808, + 0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; + SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0), _sfxFileIndex((uint)-1), _sfxWDTable(0), _sfxBTTable(0), _parser(0) { - _driver = new SoundTowns_EuphonyDriver(_mixer); + _driver = new Towns_EuphonyDriver(_mixer); int ret = open(); if (ret != MERR_ALREADY_OPEN && ret != 0) error("couldn't open midi driver"); @@ -1124,7 +2797,7 @@ void SoundTowns::playTrack(uint8 track) { return; track -= 2; - const int32 * const tTable = (const int32 * const) cdaData(); + const int32 *const tTable = (const int32 *const) cdaData(); int tTableIndex = 3 * track; int trackNum = (int) READ_LE_UINT32(&tTable[tTableIndex + 2]); @@ -1195,12 +2868,12 @@ void SoundTowns::playSoundEffect(uint8 track) { } } - uint8 * fileBody = _sfxFileData + 0x01b8; + uint8 *fileBody = _sfxFileData + 0x01b8; int32 offset = (int32)READ_LE_UINT32(_sfxFileData + (track - 0x0b) * 4); if (offset == -1) return; - uint32 * sfxHeader = (uint32*)(fileBody + offset); + uint32 *sfxHeader = (uint32*)(fileBody + offset); uint32 sfxHeaderID = READ_LE_UINT32(sfxHeader); uint32 sfxHeaderInBufferSize = READ_LE_UINT32(&sfxHeader[1]); @@ -1220,7 +2893,7 @@ void SoundTowns::playSoundEffect(uint8 track) { } else if (sfxHeaderID == 1) { Screen::decodeFrame4(sfxBody, sfxPlaybackBuffer, playbackBufferSize); } else if (_sfxWDTable) { - uint8 * tgt = sfxPlaybackBuffer; + uint8 *tgt = sfxPlaybackBuffer; uint32 sfx_BtTable_Offset = 0; uint32 sfx_WdTable_Offset = 0; uint32 sfx_WdTable_Number = 5; @@ -1285,7 +2958,7 @@ uint32 SoundTowns::getBaseTempo(void) { } bool SoundTowns::loadInstruments() { - uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0); + uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); if (!twm) return false; _driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0); @@ -1300,11 +2973,11 @@ bool SoundTowns::loadInstruments() { } void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { - uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0); + uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); Common::StackLock lock(_mutex); if (!_parser) { - _parser = new MidiParser_EuD(_driver->queue()); + _parser = new Towns_EuphonyParser(_driver->queue()); _parser->setMidiDriver(this); _parser->setTimerRate(getBaseTempo()); } @@ -1315,7 +2988,7 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { delete[] twm; } -void SoundTowns::onTimer(void * data) { +void SoundTowns::onTimer(void *data) { SoundTowns *music = (SoundTowns *)data; Common::StackLock lock(music->_mutex); if (music->_parser) @@ -1356,22 +3029,75 @@ float SoundTowns::semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiTo return (float) sampleRate * 10.0f * rateshift / outputRate; } +SoundPC98::SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer) : + Sound(vm, mixer), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0) { +} + +SoundPC98::~SoundPC98() { + delete[] _musicTrackData; + delete[] _sfxTrackData; + delete _driver; +} + +bool SoundPC98::init() { + _driver = new TownsPC98_OpnDriver(_mixer, TownsPC98_OpnDriver::OD_TYPE26); + _sfxTrackData = _vm->resource()->fileData("se.dat", 0); + if (!_sfxTrackData) + return false; + return _driver->init(); +} + +void SoundPC98::playTrack(uint8 track) { + if (--track >= 56) + track -= 55; + + if (track == _lastTrack && _musicEnabled) + return; + + haltTrack(); + + char musicfile[13]; + sprintf(musicfile, fileListEntry(0), track); + delete[] _musicTrackData; + _musicTrackData = _vm->resource()->fileData(musicfile, 0); + if (_musicEnabled) + _driver->loadData(_musicTrackData); + + _lastTrack = track; +} + +void SoundPC98::haltTrack() { + _lastTrack = -1; + AudioCD.stop(); + AudioCD.updateCD(); + _driver->reset(); +} + +void SoundPC98::beginFadeOut() { + _driver->fadeOut(); + haltTrack(); +} + +void SoundPC98::playSoundEffect(uint8) { + /// TODO /// +} + + // KYRA 2 -SoundTowns_v2::SoundTowns_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) - : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), /*_driver(0),*/ - _twnTrackData(0) { +SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) : + Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { } -SoundTowns_v2::~SoundTowns_v2() { - /*if (_driver) - delete _driver;*/ - if (_twnTrackData) - delete[] _twnTrackData; +SoundTownsPC98_v2::~SoundTownsPC98_v2() { + delete[] _musicTrackData; + delete _driver; } -bool SoundTowns_v2::init() { - //_driver = new SoundTowns_v2_TwnDriver(_mixer); +bool SoundTownsPC98_v2::init() { + _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); + _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like // a good idea, we should definitely not be doing this @@ -1384,55 +3110,61 @@ bool SoundTowns_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; - return true;//_driver->init(); + return _driver->init(); } -void SoundTowns_v2::process() { +void SoundTownsPC98_v2::process() { AudioCD.updateCD(); } -void SoundTowns_v2::playTrack(uint8 track) { +void SoundTownsPC98_v2::playTrack(uint8 track) { if (track == _lastTrack && _musicEnabled) return; - const uint16 * const cdaTracks = (const uint16 * const) cdaData(); + const uint16 *const cdaTracks = (const uint16 *const) cdaData(); int trackNum = -1; - for (int i = 0; i < cdaTrackNum(); i++) { - if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) { - trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1; - break; + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + for (int i = 0; i < cdaTrackNum(); i++) { + if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) { + trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1; + break; + } } } - haltTrack(); + beginFadeOut(); - // TODO: figure out when to loop and when not for CD Audio - bool loop = false; + char musicfile[13]; + sprintf(musicfile, fileListEntry(0), track); + delete[] _musicTrackData; + + _musicTrackData = _vm->resource()->fileData(musicfile, 0); + _driver->loadData(_musicTrackData, true); if (_musicEnabled == 2 && trackNum != -1) { - AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0); + AudioCD.play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0); AudioCD.updateCD(); } else if (_musicEnabled) { - char musicfile[13]; - sprintf(musicfile, fileListEntry(0), track); - if (_twnTrackData) - delete[] _twnTrackData; - _twnTrackData = _vm->resource()->fileData(musicfile, 0); - //_driver->loadData(_twnTrackData); + _driver->cont(); } _lastTrack = track; } -void SoundTowns_v2::haltTrack() { +void SoundTownsPC98_v2::haltTrack() { _lastTrack = -1; AudioCD.stop(); AudioCD.updateCD(); - //_driver->reset(); + _driver->reset(); } -int32 SoundTowns_v2::voicePlay(const char *file, bool) { +void SoundTownsPC98_v2::beginFadeOut() { + _driver->fadeOut(); + haltTrack(); +} + +int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 }; int h = 0; @@ -1443,11 +3175,11 @@ int32 SoundTowns_v2::voicePlay(const char *file, bool) { return 0; } - char filename [13]; + char filename[13]; sprintf(filename, "%s.PCM", file); - uint8 * data = _vm->resource()->fileData(filename, 0); - uint8 * src = data; + uint8 *data = _vm->resource()->fileData(filename, 0); + uint8 *src = data; uint16 sfxRate = rates[READ_LE_UINT16(src)]; src += 2; @@ -1500,9 +3232,16 @@ int32 SoundTowns_v2::voicePlay(const char *file, bool) { return 1; } -void SoundTowns_v2::beginFadeOut() { - //_driver->fadeOut(); - haltTrack(); +void SoundTownsPC98_v2::playSoundEffect(uint8 track) { + if (!_useFmSfx) + return; + + uint8 *sd = _vm->resource()->fileData("sound.dat", 0); + + + //TODO + + delete [] sd; } } // end of namespace Kyra diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index abdf115c1e..4f577c1d1e 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1034,6 +1034,9 @@ void KyraEngine_LoK::initStaticResource() { } // audio data tables + static const char *tIntro98[] = { "intro%d.dat" }; + static const char *tIngame98[] = { "kyram%d.dat" }; + static const AudioDataStruct soundData_PC[] = { { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, { _soundFiles, _soundFilesSize, 0, 0 }, @@ -1045,7 +1048,20 @@ void KyraEngine_LoK::initStaticResource() { { _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize }, { 0, 0, 0, 0} }; - _soundData = (_flags.platform == Common::kPlatformPC) ? soundData_PC : soundData_TOWNS; + + static const AudioDataStruct soundData_PC98[] = { + { tIntro98, 1, 0, 0 }, + { tIngame98, 1, 0, 0 }, + { 0, 0, 0, 0} + }; + + if (_flags.platform == Common::kPlatformPC) + _soundData = soundData_PC; + else if (_flags.platform == Common::kPlatformFMTowns) + _soundData = soundData_TOWNS; + else if (_flags.platform == Common::kPlatformPC98) + _soundData = soundData_PC98; + } void KyraEngine_LoK::loadMouseShapes() { @@ -1243,6 +1259,10 @@ void KyraEngine_HoF::initStaticResource() { static const char *fmtMusicFileListFinale[] = { "finale%d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; + static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; + static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; + static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; + static const AudioDataStruct soundData_PC[] = { { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, { _musicFileListIngame, _musicFileListIngameSize, 0, 0}, @@ -1254,7 +1274,19 @@ void KyraEngine_HoF::initStaticResource() { { fmtMusicFileListIngame, 1, _cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1 }, { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } }; - _soundData = (_flags.platform == Common::kPlatformPC) ? soundData_PC : soundData_TOWNS; + + static const AudioDataStruct soundData_PC98[] = { + { pc98MusicFileListIntro, 1, 0, 0 }, + { pc98MusicFileListIngame, 1, 0, 0 }, + { pc98MusicFileListFinale, 1, 0, 0 } + }; + + if (_flags.platform == Common::kPlatformPC) + _soundData = soundData_PC; + else if (_flags.platform == Common::kPlatformFMTowns) + _soundData = soundData_TOWNS; + else if (_flags.platform == Common::kPlatformPC98) + _soundData = soundData_PC98; // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); @@ -1944,12 +1976,26 @@ const char *KyraEngine_MR::_languageExtension[] = { "TRE", "TRF", "TRG"/*, - "TRI", Italian and Spanish were never included - "TRS"*/ + "TRI", Italian and Spanish were never included, the supported fan translations are using + "TRS" English/French extensions thus overwriting these languages */ }; const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension); +const char * const KyraEngine_MR::_mainMenuSpanishFan[] = { + "Nueva Partida", + "Ver Intro", + "Restaurar", + "Finalizar" +}; + +const char * const KyraEngine_MR::_mainMenuItalianFan[] = { + "Nuova Partita", + "Introduzione", + "Carica una partita", + "Esci dal gioco" +}; + const KyraEngine_MR::ShapeDesc KyraEngine_MR::_shapeDescs[] = { { 57, 91, -31, -82 }, { 57, 91, -31, -82 }, diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp index 80b21119ff..0488f17d8f 100644 --- a/engines/m4/assets.cpp +++ b/engines/m4/assets.cpp @@ -201,6 +201,7 @@ void SpriteAsset::loadMadsSpriteAsset(M4Engine *vm, Common::SeekableReadStream* Common::SeekableReadStream *spriteDataStream = sprite.getItemStream(3); SpriteAssetFrame frame; for (curFrame = 0; curFrame < _frameCount; curFrame++) { + frame.stream = 0; frame.comp = 0; frameOffset = spriteStream->readUint32LE(); _frameOffsets.push_back(frameOffset); diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index a07a175066..5b8bdab9d6 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -379,8 +379,8 @@ void Converse::loadConversation(const char *convName) { uint32 header = convS->readUint32LE(); uint32 size; uint32 chunk; - uint32 data; - uint32 i; + uint32 data = 0; + uint32 i = 0; ConvEntry* curEntry = NULL; ConvEntry* replyEntry = NULL; int32 currentWeightedEntry = -1; diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp index 12d9a24d37..58c68979d1 100644 --- a/engines/m4/globals.cpp +++ b/engines/m4/globals.cpp @@ -75,7 +75,7 @@ bool Kernel::sendTrigger(int32 triggerNum) { bool Kernel::handleTrigger(int32 triggerNum) { - printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, triggerNum); + printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, (uint)triggerNum); if (betweenRooms) return true; @@ -271,11 +271,13 @@ Globals::Globals(M4Engine *vm): _vm(vm) { } Globals::~Globals() { - for(uint32 i = 0; i < _madsVocab.size(); i++) + uint32 i; + + for(i = 0; i < _madsVocab.size(); i++) free(_madsVocab[i]); _madsVocab.clear(); - for(uint32 i = 0; i < _madsQuotes.size(); i++) + for(i = 0; i < _madsQuotes.size(); i++) free(_madsQuotes[i]); _madsQuotes.clear(); @@ -351,7 +353,7 @@ void Globals::loadMadsMessagesInfo() { _vm->res()->toss("messages.dat"); } -char* Globals::loadMessage(uint32 index) { +char* Globals::loadMessage(uint index) { if (index > _madsMessages.size() - 1) { warning("Invalid message index: %i", index); return NULL; diff --git a/engines/m4/globals.h b/engines/m4/globals.h index a0133db2d6..a80e8bf710 100644 --- a/engines/m4/globals.h +++ b/engines/m4/globals.h @@ -177,7 +177,7 @@ public: void loadMadsMessagesInfo(); uint32 getMessagesSize() { return _madsMessages.size(); } - char* loadMessage(uint32 index); + char* loadMessage(uint index); }; #define PLAYER_FIELD_LENGTH 40 diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp index 57816b6600..5070a2b79c 100644 --- a/engines/m4/resource.cpp +++ b/engines/m4/resource.cpp @@ -310,7 +310,7 @@ const char *MADSResourceManager::getResourceFilename(const char *resourceName) { Common::SeekableReadStream *MADSResourceManager::loadResource(const char *resourceName, bool loadFlag) { Common::File hagFile; - uint32 offset, size; + uint32 offset = 0, size = 0; // If the first character is a '@' then look for an external file diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp index 1a8ca9c50a..831f1fab8e 100644 --- a/engines/made/pmvplayer.cpp +++ b/engines/made/pmvplayer.cpp @@ -40,7 +40,10 @@ void PmvPlayer::play(const char *filename) { _surface = NULL; _fd = new Common::File(); - _fd->open(filename); + if (!_fd->open(filename)) { + delete _fd; + return; + } uint32 chunkType, chunkSize; diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index cecd0c8968..0c22d40259 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -688,7 +688,7 @@ void Screen::printText(const char *text) { for (int textPos = 0; textPos < textLen; textPos++) { - uint c = text[textPos]; + uint c = ((byte*)text)[textPos]; int charWidth = _font->getCharWidth(c); if (c == 9) { @@ -822,6 +822,8 @@ SpriteListItem Screen::getFromSpriteList(int16 index) { if (((uint) index) > _spriteList.size()) { SpriteListItem emptyItem; emptyItem.index = 0; + emptyItem.xofs = 0; + emptyItem.yofs = 0; return emptyItem; } else { return _spriteList[index - 1]; diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp new file mode 100644 index 0000000000..fab92dada9 --- /dev/null +++ b/engines/parallaction/balloons.cpp @@ -0,0 +1,456 @@ +/* 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 "parallaction/graphics.h" +#include "parallaction/parallaction.h" + +namespace Parallaction { + + +#define BALLOON_TRANSPARENT_COLOR_NS 2 +#define BALLOON_TRANSPARENT_COLOR_BR 0 + +#define BALLOON_TAIL_WIDTH 12 +#define BALLOON_TAIL_HEIGHT 10 + + +byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = { + { + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, + 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + }, + { + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02 + } +}; + +class BalloonManager_ns : public BalloonManager { + + static int16 _dialogueBalloonX[5]; + + struct Balloon { + Common::Rect outerBox; + Common::Rect innerBox; + Graphics::Surface *surface; + GfxObj *obj; + } _intBalloons[5]; + + uint _numBalloons; + + void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); + int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); + Balloon *getBalloon(uint id); + + Gfx *_gfx; + +public: + BalloonManager_ns(Gfx *gfx); + ~BalloonManager_ns(); + + void freeBalloons(); + int setLocationBalloon(char *text, bool endGame); + int setDialogueBalloon(char *text, uint16 winding, byte textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); + void setBalloonText(uint id, char *text, byte textColor); + int hitTestDialogueBalloon(int x, int y); +}; + +int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 }; + +BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) { + +} + +BalloonManager_ns::~BalloonManager_ns() { + +} + + +BalloonManager_ns::Balloon* BalloonManager_ns::getBalloon(uint id) { + assert(id < _numBalloons); + return &_intBalloons[id]; +} + +int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) { + assert(_numBalloons < 5); + + int id = _numBalloons; + + Balloon *balloon = &_intBalloons[id]; + + int16 real_h = (winding == -1) ? h : h + 9; + balloon->surface = new Graphics::Surface; + balloon->surface->create(w, real_h, 1); + balloon->surface->fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR_NS); + + Common::Rect r(w, h); + balloon->surface->fillRect(r, 0); + balloon->outerBox = r; + + r.grow(-borderThickness); + balloon->surface->fillRect(r, 1); + balloon->innerBox = r; + + if (winding != -1) { + // draws tail + // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill. + winding = (winding == 0 ? 1 : 0); + Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); + s.moveTo(r.width()/2 - 5, r.bottom - 1); + _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS); + } + + _numBalloons++; + + return id; +} + + +int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { + + int16 w, h; + + _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+5, h, winding, 1); + Balloon *balloon = &_intBalloons[id]; + + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = x; + balloon->obj->y = y; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS; + + return id; +} + +int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) { + + int16 w, h; + + _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+5, h, winding, 1); + Balloon *balloon = &_intBalloons[id]; + + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = _dialogueBalloonX[id]; + balloon->obj->y = 10; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS; + + if (id > 0) { + balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].outerBox.height(); + } + + + return id; +} + +void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) { + Balloon *balloon = getBalloon(id); + balloon->surface->fillRect(balloon->innerBox, 1); + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); +} + + +int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) { + + int16 w, h; + + _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS); + Balloon *balloon = &_intBalloons[id]; + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 5; + balloon->obj->y = 5; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS; + + return id; +} + +int BalloonManager_ns::hitTestDialogueBalloon(int x, int y) { + + Common::Point p; + + for (uint i = 0; i < _numBalloons; i++) { + p.x = x - _intBalloons[i].obj->x; + p.y = y - _intBalloons[i].obj->y; + + if (_intBalloons[i].innerBox.contains(p)) + return i; + } + + return -1; +} + +void BalloonManager_ns::freeBalloons() { + _gfx->destroyBalloons(); + + for (uint i = 0; i < _numBalloons; i++) { + _intBalloons[i].obj = 0; + _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons + } + + _numBalloons = 0; +} + + + + + + + + +class BalloonManager_br : public BalloonManager { + + struct Balloon { + Common::Rect box; + Graphics::Surface *surface; + GfxObj *obj; + } _intBalloons[3]; + + uint _numBalloons; + + Frames *_leftBalloon; + Frames *_rightBalloon; + Disk *_disk; + Gfx *_gfx; + + void cacheAnims(); + void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); + int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); + Balloon *getBalloon(uint id); + Graphics::Surface *expandBalloon(Frames *data, int frameNum); + + +public: + BalloonManager_br(Disk *disk, Gfx *gfx); + ~BalloonManager_br(); + + void freeBalloons(); + int setLocationBalloon(char *text, bool endGame); + int setDialogueBalloon(char *text, uint16 winding, byte textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); + void setBalloonText(uint id, char *text, byte textColor); + int hitTestDialogueBalloon(int x, int y); +}; + + + +BalloonManager_br::Balloon* BalloonManager_br::getBalloon(uint id) { + assert(id < _numBalloons); + return &_intBalloons[id]; +} + +Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum) { + + Common::Rect rect; + data->getRect(frameNum, rect); + + rect.translate(-rect.left, -rect.top); + + Graphics::Surface *surf = new Graphics::Surface; + surf->create(rect.width(), rect.height(), 1); + + _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR); + + return surf; +} + +int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { + cacheAnims(); + + int id = _numBalloons; + Frames *src = 0; + int srcFrame = 0; + + Balloon *balloon = &_intBalloons[id]; + + if (winding == 0) { + src = _leftBalloon; + srcFrame = 0; + } else + if (winding == 1) { + src = _rightBalloon; + srcFrame = 0; + } + + assert(src); + + balloon->surface = expandBalloon(src, srcFrame); + src->getRect(srcFrame, balloon->box); + +// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = x; + balloon->obj->y = y; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; + + _numBalloons++; + + return id; +} + +int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) { + cacheAnims(); + + int id = _numBalloons; + Frames *src = 0; + int srcFrame = 0; + + Balloon *balloon = &_intBalloons[id]; + + if (winding == 0) { + src = _leftBalloon; + srcFrame = id; + } else + if (winding == 1) { + src = _rightBalloon; + srcFrame = 0; + } + + assert(src); + + balloon->surface = expandBalloon(src, srcFrame); + src->getRect(srcFrame, balloon->box); + +// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 0; + balloon->obj->y = 10; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; + + if (id > 0) { + balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height(); + } + + _numBalloons++; + + return id; +} + +void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { } + +int BalloonManager_br::setLocationBalloon(char *text, bool endGame) { +/* + int16 w, h; + + getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); + Balloon *balloon = &_intBalloons[id]; + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 5; + balloon->obj->y = 5; +*/ + return 0; +} + +int BalloonManager_br::hitTestDialogueBalloon(int x, int y) { + + Common::Point p; + + for (uint i = 0; i < _numBalloons; i++) { + p.x = x - _intBalloons[i].obj->x; + p.y = y - _intBalloons[i].obj->y; + + if (_intBalloons[i].box.contains(p)) + return i; + } + + return -1; +} + +void BalloonManager_br::freeBalloons() { + _gfx->destroyBalloons(); + + for (uint i = 0; i < _numBalloons; i++) { + _intBalloons[i].obj = 0; + _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons + } + + _numBalloons = 0; +} + +void BalloonManager_br::cacheAnims() { + if (!_leftBalloon) { + _leftBalloon = _disk->loadFrames("fumetto.ani"); + _rightBalloon = _disk->loadFrames("fumdx.ani"); + } +} + +BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) { +} + +BalloonManager_br::~BalloonManager_br() { + delete _leftBalloon; + delete _rightBalloon; +} + +void Parallaction::setupBalloonManager() { + if (_vm->getGameType() == GType_Nippon) { + _balloonMan = new BalloonManager_ns(_vm->_gfx); + } else + if (_vm->getGameType() == GType_BRA) { + _balloonMan = new BalloonManager_br(_vm->_disk, _vm->_gfx); + } else { + error("Unknown game type"); + } +} + +} // namespace Parallaction diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 68e6a70ffb..7c053715f6 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -341,7 +341,7 @@ void Parallaction_ns::_c_endComment(void *param) { } _input->waitUntilLeftClick(); - _gfx->freeBalloons(); + _balloonMan->freeBalloons(); return; } @@ -417,6 +417,13 @@ void Parallaction_ns::_c_ridux(void *parm) { } void Parallaction_ns::_c_testResult(void *parm) { + if (_inTestResult) { // NOTE: _inTestResult has been added because the scripts call _c_testResult multiple times to cope with + // the multiple buffering that was used in the original engine. _inTestResult now prevents the engine + // from crashing when the scripts are executed. + return; + } + _inTestResult = true; + _gfx->updateScreen(); _disk->selectArchive("disk1"); diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp index 3c90a76f61..f57976594e 100644 --- a/engines/parallaction/debug.cpp +++ b/engines/parallaction/debug.cpp @@ -188,17 +188,15 @@ bool Debugger::Cmd_GfxObjects(int argc, const char **argv) { const char *objType[] = { "DOOR", "GET", "ANIM" }; DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n" - "| name | x | y | z | f | type | flag |\n" + "| name | x | y | z | f | type | visi |\n" "+--------------------+-----+-----+-----+-----+--------+--------+\n"); - for (uint i = 0; i < 3; i++) { - GfxObjList::iterator b = _vm->_gfx->_gfxobjList[i].begin(); - GfxObjList::iterator e = _vm->_gfx->_gfxobjList[i].end(); + GfxObjList::iterator b = _vm->_gfx->_gfxobjList.begin(); + GfxObjList::iterator e = _vm->_gfx->_gfxobjList.end(); - for ( ; b != e; b++) { - GfxObj *obj = *b; - DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], 6 ); - } + for ( ; b != e; b++) { + GfxObj *obj = *b; + DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], obj->isVisible() ); } DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n"); diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index eb2254cd80..a771f960a9 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -51,8 +51,8 @@ class DialogueManager { bool _askPassword; bool isNpc; - Frames *_questioner; - Frames *_answerer; + GfxObj *_questioner; + GfxObj *_answerer; Question *_q; @@ -93,7 +93,7 @@ uint16 DialogueManager::askPassword() { uint16 passwordLen = 0; _password[0] = '\0'; - _vm->_gfx->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); + _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); _vm->_gfx->setItemFrame(id, 0); @@ -113,7 +113,7 @@ uint16 DialogueManager::askPassword() { } if (changed) { - _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 3); + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); _vm->_gfx->updateScreen(); changed = false; } @@ -138,7 +138,7 @@ uint16 DialogueManager::askPassword() { } - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return 0; @@ -157,7 +157,7 @@ bool DialogueManager::displayAnswer(uint16 i) { // display suitable answers if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) { - int id = _vm->_gfx->setDialogueBalloon(a->_text, 1, 3); + int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3); assert(id >= 0); _visAnswers[id] = i; @@ -185,13 +185,13 @@ void DialogueManager::displayQuestion() { if (!scumm_stricmp(_q->_text, "NULL")) return; - _vm->_gfx->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); + _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); _vm->_gfx->updateScreen(); _vm->_input->waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return; } @@ -224,7 +224,7 @@ void DialogueManager::run() { answer = 0; displayQuestion(); - + if (_vm->quit()) return; @@ -244,7 +244,7 @@ void DialogueManager::run() { } if (cmdlist) - _vm->runCommands(*cmdlist); + _vm->_cmdExec->run(*cmdlist); } @@ -256,31 +256,31 @@ int16 DialogueManager::selectAnswer() { _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); if (numAvailableAnswers == 1) { - _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 0); + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 0); _vm->_input->waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return 0; } int oldSelection = -1; - int selection; + int selection = 0; uint32 event; Common::Point p; while (!_vm->quit()) { - + _vm->_input->readInput(); _vm->_input->getCursorPos(p); event = _vm->_input->getLastButtonEvent(); - selection = _vm->_gfx->hitTestDialogueBalloon(p.x, p.y); + selection = _vm->_balloonMan->hitTestDialogueBalloon(p.x, p.y); if (selection != oldSelection) { if (oldSelection != -1) { - _vm->_gfx->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); + _vm->_balloonMan->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); } if (selection != -1) { - _vm->_gfx->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); + _vm->_balloonMan->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF); } } @@ -295,7 +295,7 @@ int16 DialogueManager::selectAnswer() { oldSelection = selection; } - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return _visAnswers[selection]; } diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index b76c66aead..694d4efa6d 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -55,12 +55,12 @@ public: virtual Script* loadLocation(const char *name) = 0; virtual Script* loadScript(const char* name) = 0; - virtual Frames* loadTalk(const char *name) = 0; - virtual Frames* loadObjects(const char *name) = 0; + virtual GfxObj* loadTalk(const char *name) = 0; + virtual GfxObj* loadObjects(const char *name) = 0; virtual Frames* loadPointer(const char *name) = 0; - virtual Frames* loadHead(const char* name) = 0; + virtual GfxObj* loadHead(const char* name) = 0; virtual Font* loadFont(const char* name) = 0; - virtual Frames* loadStatic(const char* name) = 0; + virtual GfxObj* loadStatic(const char* name) = 0; virtual Frames* loadFrames(const char* name) = 0; virtual void loadSlide(BackgroundInfo& info, const char *filename) = 0; virtual void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) = 0; @@ -147,12 +147,12 @@ public: Script* loadLocation(const char *name); Script* loadScript(const char* name); - Frames* loadTalk(const char *name); - Frames* loadObjects(const char *name); + GfxObj* loadTalk(const char *name); + GfxObj* loadObjects(const char *name); Frames* loadPointer(const char *name); - Frames* loadHead(const char* name); + GfxObj* loadHead(const char* name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); + GfxObj* loadStatic(const char* name); Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path); @@ -181,12 +181,12 @@ public: Script* loadLocation(const char *name); Script* loadScript(const char* name); - Frames* loadTalk(const char *name); - Frames* loadObjects(const char *name); + GfxObj* loadTalk(const char *name); + GfxObj* loadObjects(const char *name); Frames* loadPointer(const char *name); - Frames* loadHead(const char* name); + GfxObj* loadHead(const char* name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); + GfxObj* loadStatic(const char* name); Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path); @@ -220,12 +220,12 @@ public: void setLanguage(uint16 language); Script* loadLocation(const char *name); Script* loadScript(const char* name); - Frames* loadTalk(const char *name); - Frames* loadObjects(const char *name); + GfxObj* loadTalk(const char *name); + GfxObj* loadObjects(const char *name); Frames* loadPointer(const char *name); - Frames* loadHead(const char* name); + GfxObj* loadHead(const char* name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); + GfxObj* loadStatic(const char* name); Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); @@ -248,9 +248,9 @@ public: AmigaDisk_br(Parallaction *vm); virtual ~AmigaDisk_br(); - Frames* loadTalk(const char *name); + GfxObj* loadTalk(const char *name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); + GfxObj* loadStatic(const char* name); Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 5e88327879..ee1e111139 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -58,7 +58,7 @@ struct Sprites : public Frames { } ~Sprites() { - delete _sprites; + delete[] _sprites; } uint16 getNum() { @@ -138,7 +138,7 @@ DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) { DosDisk_br::~DosDisk_br() { } -Frames* DosDisk_br::loadTalk(const char *name) { +GfxObj* DosDisk_br::loadTalk(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name); Common::File stream; @@ -151,7 +151,7 @@ Frames* DosDisk_br::loadTalk(const char *name) { errorFileNotFound(path); } - return createSprites(stream); + return new GfxObj(0, createSprites(stream), name); } Script* DosDisk_br::loadLocation(const char *name) { @@ -184,7 +184,7 @@ Script* DosDisk_br::loadScript(const char* name) { } // there are no Head resources in Big Red Adventure -Frames* DosDisk_br::loadHead(const char* name) { +GfxObj* DosDisk_br::loadHead(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadHead"); return 0; } @@ -235,7 +235,7 @@ Font* DosDisk_br::loadFont(const char* name) { } -Frames* DosDisk_br::loadObjects(const char *name) { +GfxObj* DosDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); return 0; } @@ -244,7 +244,7 @@ void genSlidePath(char *path, const char* name) { sprintf(path, "%s.bmp", name); } -Frames* DosDisk_br::loadStatic(const char* name) { +GfxObj* DosDisk_br::loadStatic(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadStatic"); char path[PATH_LEN]; @@ -256,7 +256,7 @@ Frames* DosDisk_br::loadStatic(const char* name) { Graphics::Surface *surf = new Graphics::Surface; loadBitmap(stream, *surf, 0); - return new SurfaceToFrames(surf); + return new GfxObj(0, new SurfaceToFrames(surf), name); } Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) { @@ -287,9 +287,12 @@ Frames* DosDisk_br::loadFrames(const char* name) { sprintf(path, "%s/ani/%s", _partPath, name); Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); - + if (!stream.open(path)) { + sprintf(path, "%s/ani/%s.ani", _partPath, name); + if (!stream.open(path)) { + errorFileNotFound(path); + } + } return createSprites(stream); } @@ -552,7 +555,7 @@ void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) { return; } -Frames* AmigaDisk_br::loadStatic(const char* name) { +GfxObj* AmigaDisk_br::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name); char path[PATH_LEN]; @@ -570,7 +573,7 @@ Frames* AmigaDisk_br::loadStatic(const char* name) { free(pal); - return new SurfaceToFrames(surf); + return new GfxObj(0, new SurfaceToFrames(surf)); } Sprites* AmigaDisk_br::createSprites(const char *path) { @@ -609,13 +612,13 @@ Frames* AmigaDisk_br::loadFrames(const char* name) { return createSprites(path); } -Frames* AmigaDisk_br::loadTalk(const char *name) { +GfxObj* AmigaDisk_br::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name); char path[PATH_LEN]; sprintf(path, "%s/talks/%s.tal", _partPath, name); - return createSprites(path); + return new GfxObj(0, createSprites(path)); } Font* AmigaDisk_br::loadFont(const char* name) { diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index cdbe3458a7..55e6fc5e77 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -385,12 +385,12 @@ Cnv* DosDisk_ns::loadCnv(const char *filename) { return new Cnv(numFrames, width, height, data); } -Frames* DosDisk_ns::loadTalk(const char *name) { +GfxObj* DosDisk_ns::loadTalk(const char *name) { const char *ext = strstr(name, ".talk"); if (ext != NULL) { // npc talk - return loadCnv(name); + return new GfxObj(0, loadCnv(name), name); } @@ -401,7 +401,7 @@ Frames* DosDisk_ns::loadTalk(const char *name) { sprintf(v20, "%stal", name); } - return loadExternalCnv(v20); + return new GfxObj(0, loadExternalCnv(v20), name); } Script* DosDisk_ns::loadLocation(const char *name) { @@ -434,14 +434,14 @@ Script* DosDisk_ns::loadScript(const char* name) { return new Script(new DummyArchiveStream(_resArchive), true); } -Frames* DosDisk_ns::loadHead(const char* name) { +GfxObj* DosDisk_ns::loadHead(const char* name) { char path[PATH_LEN]; sprintf(path, "%shead", name); path[8] = '\0'; - return loadExternalStaticCnv(path); + return new GfxObj(0, loadExternalStaticCnv(path)); } @@ -457,15 +457,15 @@ Font* DosDisk_ns::loadFont(const char* name) { } -Frames* DosDisk_ns::loadObjects(const char *name) { +GfxObj* DosDisk_ns::loadObjects(const char *name) { char path[PATH_LEN]; sprintf(path, "%sobj", name); - return loadExternalCnv(path); + return new GfxObj(0, loadExternalCnv(path), name); } -Frames* DosDisk_ns::loadStatic(const char* name) { +GfxObj* DosDisk_ns::loadStatic(const char* name) { char path[PATH_LEN]; @@ -487,7 +487,7 @@ Frames* DosDisk_ns::loadStatic(const char* name) { Graphics::PackBitsReadStream decoder(_resArchive); decoder.read(cnv->pixels, w*h); - return new SurfaceToFrames(cnv); + return new GfxObj(0, new SurfaceToFrames(cnv), name); } Frames* DosDisk_ns::loadFrames(const char* name) { @@ -1025,7 +1025,7 @@ Frames* AmigaDisk_ns::loadPointer(const char* name) { return makeStaticCnv(stream); } -Frames* AmigaDisk_ns::loadStatic(const char* name) { +GfxObj* AmigaDisk_ns::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadStatic '%s'", name); Common::SeekableReadStream *s = openArchivedFile(name, true); @@ -1033,7 +1033,7 @@ Frames* AmigaDisk_ns::loadStatic(const char* name) { delete s; - return cnv; + return new GfxObj(0, cnv, name); } Common::SeekableReadStream *AmigaDisk_ns::openArchivedFile(const char* name, bool errorOnFileNotFound) { @@ -1276,7 +1276,7 @@ Frames* AmigaDisk_ns::loadFrames(const char* name) { return cnv; } -Frames* AmigaDisk_ns::loadHead(const char* name) { +GfxObj* AmigaDisk_ns::loadHead(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadHead '%s'", name); char path[PATH_LEN]; @@ -1287,11 +1287,11 @@ Frames* AmigaDisk_ns::loadHead(const char* name) { delete s; - return cnv; + return new GfxObj(0, cnv, name); } -Frames* AmigaDisk_ns::loadObjects(const char *name) { +GfxObj* AmigaDisk_ns::loadObjects(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadObjects"); char path[PATH_LEN]; @@ -1305,11 +1305,11 @@ Frames* AmigaDisk_ns::loadObjects(const char *name) { Cnv *cnv = makeCnv(*s); delete s; - return cnv; + return new GfxObj(0, cnv, name); } -Frames* AmigaDisk_ns::loadTalk(const char *name) { +GfxObj* AmigaDisk_ns::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadTalk '%s'", name); Common::SeekableReadStream *s; @@ -1328,7 +1328,7 @@ Frames* AmigaDisk_ns::loadTalk(const char *name) { Cnv *cnv = makeCnv(*s); delete s; - return cnv; + return new GfxObj(0, cnv, name); } Table* AmigaDisk_ns::loadTable(const char* name) { @@ -1395,9 +1395,7 @@ Common::ReadStream* AmigaDisk_ns::loadSound(const char* name) { char path[PATH_LEN]; sprintf(path, "%s.snd", name); - openArchivedFile(path); - - return new DummyArchiveStream(_resArchive); + return openArchivedFile(path); } } // namespace Parallaction diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h new file mode 100644 index 0000000000..887d6be526 --- /dev/null +++ b/engines/parallaction/exec.h @@ -0,0 +1,241 @@ +/* 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 PARALLACTION_EXEC_H +#define PARALLACTION_EXEC_H + +#include "common/util.h" +#include "parallaction/objects.h" + + +namespace Parallaction { + +typedef Common::Functor0<void> Opcode; +typedef Common::Array<const Opcode*> OpcodeSet; + +#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op() +#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op() + +class Parallaction_ns; +class Parallaction_br; + +class CommandExec { +protected: + struct ParallactionStruct1 { + CommandPtr cmd; + ZonePtr z; + } _ctxt; + + OpcodeSet _opcodes; + +public: + virtual void init() = 0; + virtual void run(CommandList &list, ZonePtr z = nullZonePtr); + CommandExec() { + } + virtual ~CommandExec() { + for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i) + delete *i; + _opcodes.clear(); + } +}; + +class CommandExec_ns : public CommandExec { + + Parallaction_ns *_vm; + +protected: + void updateGetZone(ZonePtr z, bool visible); + + DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(set); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(get); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); + +public: + void init(); + + CommandExec_ns(Parallaction_ns* vm); + ~CommandExec_ns(); +}; + +class CommandExec_br : public CommandExec_ns { + +protected: + Parallaction_br *_vm; + + DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(character); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(add); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(let); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(music); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(give); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(text); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(part); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave); + +public: + void init(); + + CommandExec_br(Parallaction_br* vm); + ~CommandExec_br(); +}; + + + + + +class ProgramExec { +protected: + struct ParallactionStruct2 { + AnimationPtr anim; + ProgramPtr program; + InstructionList::iterator inst; + uint16 modCounter; + bool suspend; + } _ctxt; + + OpcodeSet _opcodes; + + uint16 _modCounter; + +public: + virtual void init() = 0; + virtual void runScripts(ProgramList::iterator first, ProgramList::iterator last); + ProgramExec() : _modCounter(0) { + } + virtual ~ProgramExec() { + for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i) + delete *i; + _opcodes.clear(); + } +}; + +class ProgramExec_ns : public ProgramExec { + + Parallaction_ns *_vm; + +protected: + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); + +public: + void init(); + + ProgramExec_ns(Parallaction_ns *vm); + ~ProgramExec_ns(); +}; + +class ProgramExec_br : public ProgramExec_ns { + + Parallaction_br *_vm; + +protected: + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); + +public: + void init(); + ProgramExec_br(Parallaction_br *vm); + ~ProgramExec_br(); +}; + +} // namespace Parallaction + +#endif diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 3b67b4c370..edb832cffc 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -23,6 +23,7 @@ * */ +#include "parallaction/exec.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" @@ -64,12 +65,13 @@ namespace Parallaction { #define SetOpcodeTable(x) table = &x; -typedef Common::Functor0Mem<void, Parallaction_br> OpcodeV2; -#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::cmdOp_##op)) -#define DECLARE_COMMAND_OPCODE(op) void Parallaction_br::cmdOp_##op() +typedef Common::Functor0Mem<void, CommandExec_br> OpcodeV1; +#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_br::cmdOp_##op)) +#define DECLARE_COMMAND_OPCODE(op) void CommandExec_br::cmdOp_##op() -#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::instOp_##op)) -#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_br::instOp_##op() +typedef Common::Functor0Mem<void, ProgramExec_br> OpcodeV2; +#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_br::instOp_##op)) +#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_br::instOp_##op() void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y); @@ -100,8 +102,13 @@ void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { } void Parallaction_br::clearSubtitles() { - _gfx->freeLabels(); - _subtitle[0] = _subtitle[1] = -1; + if (_subtitle[0] != -1) { + _gfx->hideLabel(_subtitle[0]); + } + + if (_subtitle[1] != -1) { + _gfx->hideLabel(_subtitle[1]); + } } @@ -109,7 +116,7 @@ DECLARE_COMMAND_OPCODE(location) { warning("Parallaction_br::cmdOp_location command not yet implemented"); // TODO: handle startPos and startPos2 - scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); + _vm->scheduleLocationSwitch(_ctxt.cmd->u._string); } @@ -124,7 +131,7 @@ DECLARE_COMMAND_OPCODE(close) { DECLARE_COMMAND_OPCODE(on) { - CommandData *data = &_cmdRunCtxt.cmd->u; + CommandData *data = &_ctxt.cmd->u; ZonePtr z = data->_zone; if (z) { @@ -132,28 +139,28 @@ DECLARE_COMMAND_OPCODE(on) { z->_flags &= ~kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, true); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, true); } } } DECLARE_COMMAND_OPCODE(off) { - CommandData *data = &_cmdRunCtxt.cmd->u; + CommandData *data = &_ctxt.cmd->u; ZonePtr z = data->_zone; if (z) { z->_flags |= kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, false); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, false); } } } DECLARE_COMMAND_OPCODE(call) { - callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); + _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z); } @@ -167,17 +174,17 @@ DECLARE_COMMAND_OPCODE(move) { } DECLARE_COMMAND_OPCODE(start) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing; + _ctxt.cmd->u._zone->_flags |= kFlagsActing; } DECLARE_COMMAND_OPCODE(stop) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing; + _ctxt.cmd->u._zone->_flags &= ~kFlagsActing; } DECLARE_COMMAND_OPCODE(character) { - debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _cmdRunCtxt.cmd->u._string); - changeCharacter(_cmdRunCtxt.cmd->u._string); + debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _ctxt.cmd->u._string); + _vm->changeCharacter(_ctxt.cmd->u._string); } @@ -187,12 +194,12 @@ DECLARE_COMMAND_OPCODE(followme) { DECLARE_COMMAND_OPCODE(onmouse) { - _input->showCursor(true); + _vm->_input->showCursor(true); } DECLARE_COMMAND_OPCODE(offmouse) { - _input->showCursor(false); + _vm->_input->showCursor(false); } @@ -207,42 +214,42 @@ DECLARE_COMMAND_OPCODE(leave) { DECLARE_COMMAND_OPCODE(inc) { - _counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_ctxt.cmd->u._lvalue] += _ctxt.cmd->u._rvalue; } DECLARE_COMMAND_OPCODE(dec) { - _counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_ctxt.cmd->u._lvalue] -= _ctxt.cmd->u._rvalue; } DECLARE_COMMAND_OPCODE(ifeq) { - if (_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) { - setLocationFlags(kFlagsTestTrue); + if (_vm->_counters[_ctxt.cmd->u._lvalue] == _ctxt.cmd->u._rvalue) { + _vm->setLocationFlags(kFlagsTestTrue); } else { - clearLocationFlags(kFlagsTestTrue); + _vm->clearLocationFlags(kFlagsTestTrue); } } DECLARE_COMMAND_OPCODE(iflt) { - if (_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) { - setLocationFlags(kFlagsTestTrue); + if (_vm->_counters[_ctxt.cmd->u._lvalue] < _ctxt.cmd->u._rvalue) { + _vm->setLocationFlags(kFlagsTestTrue); } else { - clearLocationFlags(kFlagsTestTrue); + _vm->clearLocationFlags(kFlagsTestTrue); } } DECLARE_COMMAND_OPCODE(ifgt) { - if (_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) { - setLocationFlags(kFlagsTestTrue); + if (_vm->_counters[_ctxt.cmd->u._lvalue] > _ctxt.cmd->u._rvalue) { + _vm->setLocationFlags(kFlagsTestTrue); } else { - clearLocationFlags(kFlagsTestTrue); + _vm->clearLocationFlags(kFlagsTestTrue); } } DECLARE_COMMAND_OPCODE(let) { - _counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_ctxt.cmd->u._lvalue] = _ctxt.cmd->u._rvalue; } @@ -252,25 +259,25 @@ DECLARE_COMMAND_OPCODE(music) { DECLARE_COMMAND_OPCODE(fix) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsFixed; + _ctxt.cmd->u._zone->_flags |= kFlagsFixed; } DECLARE_COMMAND_OPCODE(unfix) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; + _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed; } DECLARE_COMMAND_OPCODE(zeta) { - _location._zeta0 = _cmdRunCtxt.cmd->u._zeta0; - _location._zeta1 = _cmdRunCtxt.cmd->u._zeta1; - _location._zeta2 = _cmdRunCtxt.cmd->u._zeta2; + _vm->_location._zeta0 = _ctxt.cmd->u._zeta0; + _vm->_location._zeta1 = _ctxt.cmd->u._zeta1; + _vm->_location._zeta2 = _ctxt.cmd->u._zeta2; } DECLARE_COMMAND_OPCODE(scroll) { warning("Parallaction_br::cmdOp_scroll not yet implemented"); - _gfx->setVar("scroll_x", _cmdRunCtxt.cmd->u._rvalue ); + _vm->_gfx->setVar("scroll_x", _ctxt.cmd->u._rvalue ); } @@ -285,8 +292,8 @@ DECLARE_COMMAND_OPCODE(give) { DECLARE_COMMAND_OPCODE(text) { - CommandData *data = &_cmdRunCtxt.cmd->u; - setupSubtitles(data->_string, data->_string2, data->_zeta0); + CommandData *data = &_ctxt.cmd->u; + _vm->setupSubtitles(data->_string, data->_string2, data->_zeta0); } @@ -297,7 +304,7 @@ DECLARE_COMMAND_OPCODE(part) { DECLARE_COMMAND_OPCODE(testsfx) { warning("Parallaction_br::cmdOp_testsfx not completely implemented"); - clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled + _vm->clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled } @@ -319,7 +326,7 @@ DECLARE_COMMAND_OPCODE(offsave) { DECLARE_INSTRUCTION_OPCODE(on) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; ZonePtr z = inst->_z; if (z) { @@ -327,28 +334,28 @@ DECLARE_INSTRUCTION_OPCODE(on) { z->_flags &= ~kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, true); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, true); } } } DECLARE_INSTRUCTION_OPCODE(off) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; ZonePtr z = inst->_z; if (z) { z->_flags |= kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, false); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, false); } } } DECLARE_INSTRUCTION_OPCODE(set) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 rvalue = inst->_opB.getRValue(); int16* lvalue = inst->_opA.getLValue(); @@ -359,21 +366,21 @@ DECLARE_INSTRUCTION_OPCODE(set) { DECLARE_INSTRUCTION_OPCODE(loop) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; - _instRunCtxt.program->_loopCounter = inst->_opB.getRValue(); - _instRunCtxt.program->_loopStart = _instRunCtxt.inst; + _ctxt.program->_loopCounter = inst->_opB.getRValue(); + _ctxt.program->_loopStart = _ctxt.inst; } DECLARE_INSTRUCTION_OPCODE(inc) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 rvalue = inst->_opB.getRValue(); if (inst->_flags & kInstMod) { // mod int16 _bx = (rvalue > 0 ? rvalue : -rvalue); - if (_instRunCtxt.modCounter % _bx != 0) return; + if (_ctxt.modCounter % _bx != 0) return; rvalue = (rvalue > 0 ? 1 : -1); } @@ -420,12 +427,12 @@ DECLARE_INSTRUCTION_OPCODE(wait) { DECLARE_INSTRUCTION_OPCODE(start) { - (*_instRunCtxt.inst)->_z->_flags |= kFlagsActing; + (*_ctxt.inst)->_z->_flags |= kFlagsActing; } DECLARE_INSTRUCTION_OPCODE(process) { - _activeZone2 = (*_instRunCtxt.inst)->_z; + _vm->_activeZone2 = (*_ctxt.inst)->_z; } @@ -435,18 +442,18 @@ DECLARE_INSTRUCTION_OPCODE(move) { DECLARE_INSTRUCTION_OPCODE(color) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 entry = inst->_opB.getRValue(); - _gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]); + _vm->_gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]); } DECLARE_INSTRUCTION_OPCODE(mask) { #if 0 - Instruction *inst = *_instRunCtxt.inst; + Instruction *inst = *_ctxt.inst; _gfx->_bgLayers[0] = inst->_opA.getRValue(); _gfx->_bgLayers[1] = inst->_opB.getRValue(); _gfx->_bgLayers[2] = inst->_opC.getRValue(); @@ -459,8 +466,8 @@ DECLARE_INSTRUCTION_OPCODE(print) { } DECLARE_INSTRUCTION_OPCODE(text) { - InstructionPtr inst = (*_instRunCtxt.inst); - setupSubtitles(inst->_text, inst->_text2, inst->_y); + InstructionPtr inst = (*_ctxt.inst); + _vm->setupSubtitles(inst->_text, inst->_text2, inst->_y); } @@ -489,21 +496,20 @@ DECLARE_INSTRUCTION_OPCODE(stop) { } DECLARE_INSTRUCTION_OPCODE(endscript) { - if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) { - _instRunCtxt.anim->_flags &= ~kFlagsActing; - runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim); - _instRunCtxt.program->_status = kProgramDone; + if ((_ctxt.anim->_flags & kFlagsLooping) == 0) { + _ctxt.anim->_flags &= ~kFlagsActing; + _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim); + _ctxt.program->_status = kProgramDone; } - _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin(); + _ctxt.program->_ip = _ctxt.program->_instructions.begin(); - _instRunCtxt.suspend = true; + _ctxt.suspend = true; } -void Parallaction_br::initOpcodes() { - +void CommandExec_br::init() { Common::Array<const Opcode*> *table = 0; - SetOpcodeTable(_commandOpcodes); + SetOpcodeTable(_opcodes); COMMAND_OPCODE(invalid); COMMAND_OPCODE(set); COMMAND_OPCODE(clear); @@ -546,8 +552,21 @@ void Parallaction_br::initOpcodes() { COMMAND_OPCODE(ret); COMMAND_OPCODE(onsave); COMMAND_OPCODE(offsave); +} + +CommandExec_br::CommandExec_br(Parallaction_br* vm) : CommandExec_ns(vm), _vm(vm) { + +} + +CommandExec_br::~CommandExec_br() { - SetOpcodeTable(_instructionOpcodes); +} + +void ProgramExec_br::init() { + + Common::Array<const Opcode*> *table = 0; + + SetOpcodeTable(_opcodes); INSTRUCTION_OPCODE(invalid); INSTRUCTION_OPCODE(on); INSTRUCTION_OPCODE(off); @@ -582,6 +601,12 @@ void Parallaction_br::initOpcodes() { INSTRUCTION_OPCODE(endscript); } +ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm) { +} + +ProgramExec_br::~ProgramExec_br() { +} + #if 0 void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 0c4addd9b7..b4578f80ad 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -23,6 +23,7 @@ * */ +#include "parallaction/exec.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" #include "parallaction/sound.h" @@ -52,18 +53,19 @@ namespace Parallaction { #define SetOpcodeTable(x) table = &x; -typedef Common::Functor0Mem<void, Parallaction_ns> OpcodeV2; -#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::cmdOp_##op)) -#define DECLARE_COMMAND_OPCODE(op) void Parallaction_ns::cmdOp_##op() +typedef Common::Functor0Mem<void, CommandExec_ns> OpcodeV1; +#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_ns::cmdOp_##op)) +#define DECLARE_COMMAND_OPCODE(op) void CommandExec_ns::cmdOp_##op() -#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::instOp_##op)) -#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_ns::instOp_##op() +typedef Common::Functor0Mem<void, ProgramExec_ns> OpcodeV2; +#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_ns::instOp_##op)) +#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_ns::instOp_##op() DECLARE_INSTRUCTION_OPCODE(on) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; inst->_a->_flags |= kFlagsActive; inst->_a->_flags &= ~kFlagsRemove; @@ -71,31 +73,31 @@ DECLARE_INSTRUCTION_OPCODE(on) { DECLARE_INSTRUCTION_OPCODE(off) { - (*_instRunCtxt.inst)->_a->_flags |= kFlagsRemove; + (*_ctxt.inst)->_a->_flags |= kFlagsRemove; } DECLARE_INSTRUCTION_OPCODE(loop) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; - _instRunCtxt.program->_loopCounter = inst->_opB.getRValue(); - _instRunCtxt.program->_loopStart = _instRunCtxt.inst; + _ctxt.program->_loopCounter = inst->_opB.getRValue(); + _ctxt.program->_loopStart = _ctxt.inst; } DECLARE_INSTRUCTION_OPCODE(endloop) { - if (--_instRunCtxt.program->_loopCounter > 0) { - _instRunCtxt.inst = _instRunCtxt.program->_loopStart; + if (--_ctxt.program->_loopCounter > 0) { + _ctxt.inst = _ctxt.program->_loopStart; } } DECLARE_INSTRUCTION_OPCODE(inc) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 _si = inst->_opB.getRValue(); if (inst->_flags & kInstMod) { // mod int16 _bx = (_si > 0 ? _si : -_si); - if (_instRunCtxt.modCounter % _bx != 0) return; + if (_modCounter % _bx != 0) return; _si = (_si > 0 ? 1 : -1); } @@ -116,7 +118,7 @@ DECLARE_INSTRUCTION_OPCODE(inc) { DECLARE_INSTRUCTION_OPCODE(set) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 _si = inst->_opB.getRValue(); int16 *lvalue = inst->_opA.getLValue(); @@ -127,7 +129,7 @@ DECLARE_INSTRUCTION_OPCODE(set) { DECLARE_INSTRUCTION_OPCODE(put) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; Graphics::Surface v18; v18.w = inst->_a->width(); v18.h = inst->_a->height(); @@ -137,7 +139,7 @@ DECLARE_INSTRUCTION_OPCODE(put) { int16 y = inst->_opB.getRValue(); bool mask = (inst->_flags & kInstMaskedPut) == kInstMaskedPut; - _gfx->patchBackground(v18, x, y, mask); + _vm->_gfx->patchBackground(v18, x, y, mask); } DECLARE_INSTRUCTION_OPCODE(null) { @@ -145,170 +147,177 @@ DECLARE_INSTRUCTION_OPCODE(null) { } DECLARE_INSTRUCTION_OPCODE(invalid) { - error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index); + error("Can't execute invalid opcode %i", (*_ctxt.inst)->_index); } DECLARE_INSTRUCTION_OPCODE(call) { - callFunction((*_instRunCtxt.inst)->_immediate, 0); + _vm->callFunction((*_ctxt.inst)->_immediate, 0); } DECLARE_INSTRUCTION_OPCODE(wait) { if (_engineFlags & kEngineWalking) - _instRunCtxt.suspend = true; + _ctxt.suspend = true; } DECLARE_INSTRUCTION_OPCODE(start) { - (*_instRunCtxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive); + (*_ctxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive); } DECLARE_INSTRUCTION_OPCODE(sound) { - _activeZone = (*_instRunCtxt.inst)->_z; + _vm->_activeZone = (*_ctxt.inst)->_z; } DECLARE_INSTRUCTION_OPCODE(move) { - InstructionPtr inst = (*_instRunCtxt.inst); + InstructionPtr inst = (*_ctxt.inst); int16 x = inst->_opA.getRValue(); int16 y = inst->_opB.getRValue(); - _char.scheduleWalk(x, y); + _vm->_char.scheduleWalk(x, y); } DECLARE_INSTRUCTION_OPCODE(endscript) { - if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) { - _instRunCtxt.anim->_flags &= ~kFlagsActing; - runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim); - _instRunCtxt.program->_status = kProgramDone; + if ((_ctxt.anim->_flags & kFlagsLooping) == 0) { + _ctxt.anim->_flags &= ~kFlagsActing; + _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim); + _ctxt.program->_status = kProgramDone; } - _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin(); + _ctxt.program->_ip = _ctxt.program->_instructions.begin(); - _instRunCtxt.suspend = true; + _ctxt.suspend = true; } DECLARE_COMMAND_OPCODE(invalid) { - error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id); + error("Can't execute invalid command '%i'", _ctxt.cmd->_id); } DECLARE_COMMAND_OPCODE(set) { - if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { - _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; - _commandFlags |= _cmdRunCtxt.cmd->u._flags; + if (_ctxt.cmd->u._flags & kFlagsGlobal) { + _ctxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags |= _ctxt.cmd->u._flags; } else { - setLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->setLocationFlags(_ctxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(clear) { - if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { - _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; - _commandFlags &= ~_cmdRunCtxt.cmd->u._flags; + if (_ctxt.cmd->u._flags & kFlagsGlobal) { + _ctxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags &= ~_ctxt.cmd->u._flags; } else { - clearLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->clearLocationFlags(_ctxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(start) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing; + _ctxt.cmd->u._zone->_flags |= kFlagsActing; } DECLARE_COMMAND_OPCODE(speak) { - _activeZone = _cmdRunCtxt.cmd->u._zone; + _vm->_activeZone = _ctxt.cmd->u._zone; } DECLARE_COMMAND_OPCODE(get) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; - runZone(_cmdRunCtxt.cmd->u._zone); + _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed; + _vm->runZone(_ctxt.cmd->u._zone); } DECLARE_COMMAND_OPCODE(location) { - scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); + _vm->scheduleLocationSwitch(_ctxt.cmd->u._string); } DECLARE_COMMAND_OPCODE(open) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed; - if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) { - updateDoor(_cmdRunCtxt.cmd->u._zone); + _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed; + if (_ctxt.cmd->u._zone->u.door->gfxobj) { + _vm->updateDoor(_ctxt.cmd->u._zone); } } DECLARE_COMMAND_OPCODE(close) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed; - if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) { - updateDoor(_cmdRunCtxt.cmd->u._zone); + _ctxt.cmd->u._zone->_flags |= kFlagsClosed; + if (_ctxt.cmd->u._zone->u.door->gfxobj) { + _vm->updateDoor(_ctxt.cmd->u._zone); } } +void CommandExec_ns::updateGetZone(ZonePtr z, bool visible) { + if (!z) { + return; + } + + if ((z->_type & 0xFFFF) == kZoneGet) { + _vm->_gfx->showGfxObj(z->u.get->gfxobj, visible); + } +} DECLARE_COMMAND_OPCODE(on) { - ZonePtr z = _cmdRunCtxt.cmd->u._zone; - // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing - // the pointer to get structure members, thus leading to crashes in systems with memory - // protection. - // As a side note, the overwritten address is the 5th entry in the DOS interrupt table - // (print screen handler): this suggests that a system would hang when the print screen - // key is pressed after playing Nippon Safes, provided that this code path is taken. + ZonePtr z = _ctxt.cmd->u._zone; + if (z) { z->_flags &= ~kFlagsRemove; z->_flags |= kFlagsActive; - if ((z->_type & 0xFFFF) == kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, true); - } + updateGetZone(z, true); } } DECLARE_COMMAND_OPCODE(off) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove; + ZonePtr z = _ctxt.cmd->u._zone; + + if (z) { + _ctxt.cmd->u._zone->_flags |= kFlagsRemove; + updateGetZone(z, false); + } } DECLARE_COMMAND_OPCODE(call) { - callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); + _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z); } DECLARE_COMMAND_OPCODE(toggle) { - if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { - _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; - _commandFlags ^= _cmdRunCtxt.cmd->u._flags; + if (_ctxt.cmd->u._flags & kFlagsGlobal) { + _ctxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags ^= _ctxt.cmd->u._flags; } else { - toggleLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->toggleLocationFlags(_ctxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(drop){ - dropItem( _cmdRunCtxt.cmd->u._object ); + _vm->dropItem( _ctxt.cmd->u._object ); } DECLARE_COMMAND_OPCODE(quit) { - _quit = true; + _vm->_quit = true; _vm->quitGame(); } DECLARE_COMMAND_OPCODE(move) { - _char.scheduleWalk(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y); + _vm->_char.scheduleWalk(_ctxt.cmd->u._move.x, _ctxt.cmd->u._move.y); } DECLARE_COMMAND_OPCODE(stop) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing; + _ctxt.cmd->u._zone->_flags &= ~kFlagsActing; } @@ -357,16 +366,14 @@ void Parallaction_ns::drawAnimations() { } -void Parallaction_ns::runScripts() { +void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) { if (_engineFlags & kEnginePauseJobs) { return; } debugC(9, kDebugExec, "runScripts"); - static uint16 modCounter = 0; - - for (ProgramList::iterator it = _location._programs.begin(); it != _location._programs.end(); it++) { + for (ProgramList::iterator it = first; it != last; it++) { AnimationPtr a = (*it)->_anim; @@ -383,17 +390,16 @@ void Parallaction_ns::runScripts() { debugC(9, kDebugExec, "Animation: %s, instruction: %i", a->_name, (*inst)->_index); //_instructionNamesRes[(*inst)->_index - 1]); - _instRunCtxt.inst = inst; - _instRunCtxt.anim = AnimationPtr(a); - _instRunCtxt.program = *it; - _instRunCtxt.modCounter = modCounter; - _instRunCtxt.suspend = false; + _ctxt.inst = inst; + _ctxt.anim = AnimationPtr(a); + _ctxt.program = *it; + _ctxt.suspend = false; - (*_instructionOpcodes[(*inst)->_index])(); + (*_opcodes[(*inst)->_index])(); - inst = _instRunCtxt.inst; // handles endloop correctly + inst = _ctxt.inst; // handles endloop correctly - if (_instRunCtxt.suspend) + if (_ctxt.suspend) goto label1; inst++; @@ -406,44 +412,54 @@ label1: a->_z = a->_top + a->height(); } - _char._ani->_z = _char._ani->height() + _char._ani->_top; - if (_char._ani->gfxobj) { - _char._ani->gfxobj->z = _char._ani->_z; - } - modCounter++; + _modCounter++; return; } -void Parallaction::runCommands(CommandList& list, ZonePtr z) { - if (list.size() == 0) +void CommandExec::run(CommandList& list, ZonePtr z) { + if (list.size() == 0) { + debugC(3, kDebugExec, "runCommands: nothing to do"); return; + } - debugC(3, kDebugExec, "runCommands"); + debugC(3, kDebugExec, "runCommands starting"); + + uint32 useFlags = 0; + bool useLocalFlags; CommandList::iterator it = list.begin(); for ( ; it != list.end(); it++) { + if (_vm->quit()) + break; + CommandPtr cmd = *it; - uint32 v8 = getLocationFlags(); if (_vm->quit()) break; - + if (cmd->_flagsOn & kFlagsGlobal) { - v8 = _commandFlags | kFlagsGlobal; + useFlags = _commandFlags | kFlagsGlobal; + useLocalFlags = false; + } else { + useFlags = _vm->getLocationFlags(); + useLocalFlags = true; } - if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue; - if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue; + bool onMatch = (cmd->_flagsOn & useFlags) == cmd->_flagsOn; + bool offMatch = (cmd->_flagsOff & ~useFlags) == cmd->_flagsOff; + + debugC(3, kDebugExec, "runCommands[%i] (on: %x, off: %x), (%s = %x)", cmd->_id, cmd->_flagsOn, cmd->_flagsOff, + useLocalFlags ? "LOCALFLAGS" : "GLOBALFLAGS", useFlags); -// debugC(3, kDebugExec, "runCommands[%i]: %s (on: %x, off: %x)", cmd->_id, _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff); + if (!onMatch || !offMatch) continue; - _cmdRunCtxt.z = z; - _cmdRunCtxt.cmd = cmd; + _ctxt.z = z; + _ctxt.cmd = cmd; - (*_commandOpcodes[cmd->_id])(); + (*_opcodes[cmd->_id])(); } debugC(3, kDebugExec, "runCommands completed"); @@ -452,6 +468,13 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) { } +CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) { + +} + +CommandExec_ns::~CommandExec_ns() { + +} // // ZONE TYPE: EXAMINE @@ -470,7 +493,7 @@ void Parallaction::displayComment(ExamineData *data) { } _gfx->setHalfbriteMode(true); - _gfx->setSingleBalloon(data->_description, 0, 90, 0, 0); + _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); Common::Rect r; data->_cnv->getRect(0, r); id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); @@ -478,7 +501,7 @@ void Parallaction::displayComment(ExamineData *data) { id = _gfx->setItem(_char._head, 100, 152); _gfx->setItemFrame(id, 0); } else { - _gfx->setSingleBalloon(data->_description, 140, 10, 0, 0); + _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); id = _gfx->setItem(_char._talk, 190, 80); _gfx->setItemFrame(id, 0); } @@ -528,7 +551,7 @@ uint16 Parallaction::runZone(ZonePtr z) { debugC(3, kDebugExec, "runZone completed"); - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); return 0; } @@ -655,11 +678,34 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { } -void Parallaction_ns::initOpcodes() { +void CommandExec_ns::init() { + Common::Array<const Opcode*> *table = 0; + + SetOpcodeTable(_opcodes); + COMMAND_OPCODE(invalid); + COMMAND_OPCODE(set); + COMMAND_OPCODE(clear); + COMMAND_OPCODE(start); + COMMAND_OPCODE(speak); + COMMAND_OPCODE(get); + COMMAND_OPCODE(location); + COMMAND_OPCODE(open); + COMMAND_OPCODE(close); + COMMAND_OPCODE(on); + COMMAND_OPCODE(off); + COMMAND_OPCODE(call); + COMMAND_OPCODE(toggle); + COMMAND_OPCODE(drop); + COMMAND_OPCODE(quit); + COMMAND_OPCODE(move); + COMMAND_OPCODE(stop); +} + +void ProgramExec_ns::init() { Common::Array<const Opcode*> *table = 0; - SetOpcodeTable(_instructionOpcodes); + SetOpcodeTable(_opcodes); INSTRUCTION_OPCODE(invalid); INSTRUCTION_OPCODE(on); INSTRUCTION_OPCODE(off); @@ -681,25 +727,12 @@ void Parallaction_ns::initOpcodes() { INSTRUCTION_OPCODE(move); INSTRUCTION_OPCODE(endscript); - SetOpcodeTable(_commandOpcodes); - COMMAND_OPCODE(invalid); - COMMAND_OPCODE(set); - COMMAND_OPCODE(clear); - COMMAND_OPCODE(start); - COMMAND_OPCODE(speak); - COMMAND_OPCODE(get); - COMMAND_OPCODE(location); - COMMAND_OPCODE(open); - COMMAND_OPCODE(close); - COMMAND_OPCODE(on); - COMMAND_OPCODE(off); - COMMAND_OPCODE(call); - COMMAND_OPCODE(toggle); - COMMAND_OPCODE(drop); - COMMAND_OPCODE(quit); - COMMAND_OPCODE(move); - COMMAND_OPCODE(stop); } +ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) { +} + +ProgramExec_ns::~ProgramExec_ns() { +} } // namespace Parallaction diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 6599a1f81c..9e7eb12ed8 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -32,7 +32,7 @@ namespace Parallaction { -GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(0), _keep(true) { +GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(kGfxObjNormal), _keep(true) { if (name) { _name = strdup(name); } else { @@ -86,93 +86,325 @@ void GfxObj::clearFlags(uint32 flags) { } GfxObj* Gfx::loadAnim(const char *name) { - Frames *frames = _disk->loadFrames(name); + Frames* frames = _disk->loadFrames(name); + assert(frames); + GfxObj *obj = new GfxObj(kGfxObjTypeAnim, frames, name); assert(obj); + // animation Z is not set here, but controlled by game scripts and user interaction. + // it is always >=0 and <screen height + obj->transparentKey = 0; + _gfxobjList.push_back(obj); return obj; } GfxObj* Gfx::loadGet(const char *name) { - Frames *frames = _disk->loadStatic(name); - GfxObj *obj = new GfxObj(kGfxObjTypeGet, frames, name); + GfxObj *obj = _disk->loadStatic(name); assert(obj); + obj->z = kGfxObjGetZ; // this preset Z value ensures that get zones are drawn after doors but before animations + obj->type = kGfxObjTypeGet; + obj->transparentKey = 0; + _gfxobjList.push_back(obj); return obj; } GfxObj* Gfx::loadDoor(const char *name) { Frames *frames = _disk->loadFrames(name); + assert(frames); + GfxObj *obj = new GfxObj(kGfxObjTypeDoor, frames, name); assert(obj); + obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first + obj->transparentKey = 0; + _gfxobjList.push_back(obj); return obj; } -void Gfx::clearGfxObjects() { - _gfxobjList[0].clear(); - _gfxobjList[1].clear(); - _gfxobjList[2].clear(); +void Gfx::clearGfxObjects(uint filter) { + + GfxObjList::iterator b = _gfxobjList.begin(); + GfxObjList::iterator e = _gfxobjList.end(); + + for ( ; b != e; ) { + if (((*b)->_flags & filter) != 0) { + b = _gfxobjList.erase(b); + } else { + b++; + } + } + } void Gfx::showGfxObj(GfxObj* obj, bool visible) { - if (!obj || obj->isVisible() == visible) { + if (!obj) { return; } if (visible) { obj->setFlags(kGfxObjVisible); - _gfxobjList[obj->type].push_back(obj); } else { obj->clearFlags(kGfxObjVisible); - _gfxobjList[obj->type].remove(obj); } - } -bool compareAnimationZ(const GfxObj* a1, const GfxObj* a2) { +bool compareZ(const GfxObj* a1, const GfxObj* a2) { return a1->z < a2->z; } void Gfx::sortAnimations() { - GfxObjList::iterator first = _gfxobjList[kGfxObjTypeAnim].begin(); - GfxObjList::iterator last = _gfxobjList[kGfxObjTypeAnim].end(); + GfxObjList::iterator first = _gfxobjList.begin(); + GfxObjList::iterator last = _gfxobjList.end(); - Common::sort(first, last, compareAnimationZ); + Common::sort(first, last, compareZ); } -void Gfx::drawGfxObjects(Graphics::Surface &surf) { + +void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) { + if (!obj->isVisible()) { + return; + } Common::Rect rect; byte *data; + uint scrollX = (scene) ? -_varScrollX : 0; + + obj->getRect(obj->frame, rect); + rect.translate(obj->x + scrollX, obj->y); + data = obj->getData(obj->frame); + + if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { + blt(rect, data, &surf, obj->layer, obj->transparentKey); + } else { + unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey); + } + +} + + +void Gfx::drawGfxObjects(Graphics::Surface &surf) { + sortAnimations(); // TODO: some zones don't appear because of wrong masking (3 or 0?) - // TODO: Dr.Ki is not visible inside the club + GfxObjList::iterator b = _gfxobjList.begin(); + GfxObjList::iterator e = _gfxobjList.end(); + + for (; b != e; b++) { + drawGfxObject(*b, surf, true); + } +} + + + +void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) { + byte *dst = (byte*)surf->getBasePtr(x, y); + font->setColor(color); + font->drawString(dst, surf->w, text); +} + +void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) { + + uint16 lines = 0; + uint16 linewidth = 0; + + uint16 rx = 10; + uint16 ry = 4; + + uint16 blankWidth = font->getStringWidth(" "); + uint16 tokenWidth = 0; + + char token[MAX_TOKEN_LEN]; + + if (wrapwidth == -1) + wrapwidth = _vm->_screenWidth; + + while (strlen(text) > 0) { + + text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); - for (uint i = 0; i < 3; i++) { + if (!scumm_stricmp(token, "%p")) { + lines++; + rx = 10; + ry = 4 + lines*10; // y - GfxObjList::iterator b = _gfxobjList[i].begin(); - GfxObjList::iterator e = _gfxobjList[i].end(); + strcpy(token, "> ......."); + strncpy(token+2, _password, strlen(_password)); + tokenWidth = font->getStringWidth(token); + } else { + tokenWidth = font->getStringWidth(token); - for (; b != e; b++) { - GfxObj *obj = *b; - if (obj->isVisible()) { - obj->getRect(obj->frame, rect); - rect.translate(obj->x - _varScrollX, obj->y); - data = obj->getData(obj->frame); - if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { - blt(rect, data, &surf, obj->layer, 0); - } else { - unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, 0); + linewidth += tokenWidth; + + if (linewidth > wrapwidth) { + // wrap line + lines++; + rx = 10; // x + ry = 4 + lines*10; // y + linewidth = tokenWidth; + } + + if (!scumm_stricmp(token, "%s")) { + sprintf(token, "%d", _score); + } + + } + + drawText(font, surf, rx, ry, token, color); + + rx += tokenWidth + blankWidth; + linewidth += blankWidth; + + text = Common::ltrim(text); + } + +} + + +// this is the maximum size of an unpacked frame in BRA +byte _unpackedBitmap[640*401]; + +#if 0 +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { + + byte *d = _unpackedBitmap; + + while (size > 0) { + + uint8 p = *data++; + size--; + uint8 color = p & 0xF; + uint8 repeat = (p & 0xF0) >> 4; + if (repeat == 0) { + repeat = *data++; + size--; + } + + memset(d, color, repeat); + d += repeat; + } + + blt(r, _unpackedBitmap, surf, z, transparentColor); +} +#endif +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { + + byte *d = _unpackedBitmap; + uint pixelsLeftInLine = r.width(); + + while (size > 0) { + uint8 p = *data++; + size--; + uint8 color = p & 0xF; + uint8 repeat = (p & 0xF0) >> 4; + if (repeat == 0) { + repeat = *data++; + size--; + } + if (repeat == 0) { + // end of line + repeat = pixelsLeftInLine; + pixelsLeftInLine = r.width(); + } else { + pixelsLeftInLine -= repeat; + } + + memset(d, color, repeat); + d += repeat; + } + + blt(r, _unpackedBitmap, surf, z, transparentColor); +} + + +void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { + + Common::Point dp; + Common::Rect q(r); + + Common::Rect clipper(surf->w, surf->h); + + q.clip(clipper); + if (!q.isValidRect()) return; + + dp.x = q.left; + dp.y = q.top; + + q.translate(-r.left, -r.top); + + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = surf->w - q.width(); + + + if (_varRenderMode == 2) { + + for (uint16 i = 0; i < q.height(); i++) { + + for (uint16 j = 0; j < q.width(); j++) { + if (*s != transparentColor) { + if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { + byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); + if (z >= v) *d = 5; + } else { + *d = 5; + } + } + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + + } else { + if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { + + for (uint16 i = 0; i < q.height(); i++) { + + for (uint16 j = 0; j < q.width(); j++) { + if (*s != transparentColor) { + byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); + if (z >= v) *d = *s; + } + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + + } else { + + for (uint16 i = q.top; i < q.bottom; i++) { + for (uint16 j = q.left; j < q.right; j++) { + if (*s != transparentColor) + *d = *s; + + s++; + d++; } + + s += sPitch; + d += dPitch; } + } } + } + } // namespace Parallaction diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 58fb02a750..32d0e303eb 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -64,10 +64,6 @@ int32 Gfx::getVar(const Common::String &name) { #define LABEL_TRANSPARENT_COLOR 0xFF -#define BALLOON_TRANSPARENT_COLOR 2 - - -int16 Gfx::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 }; void halfbritePixel(int x, int y, int color, void *data) { byte *buffer = (byte*)data; @@ -238,37 +234,6 @@ void Palette::rotate(uint first, uint last, bool forward) { } -#define BALLOON_TAIL_WIDTH 12 -#define BALLOON_TAIL_HEIGHT 10 - - -byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = { - { - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, - 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - }, - { - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02 - } -}; - void Gfx::setPalette(Palette pal) { byte sysPal[256*4]; @@ -356,21 +321,19 @@ void Gfx::drawItems() { Graphics::Surface *surf = g_system->lockScreen(); for (uint i = 0; i < _numItems; i++) { - blt(_items[i].rect, _items[i].data->getData(_items[i].frame), surf, LAYER_FOREGROUND, _items[i].transparentColor); + drawGfxObject(_items[i].data, *surf, false); } g_system->unlockScreen(); } void Gfx::drawBalloons() { - if (_numBalloons == 0) { + if (_balloons.size() == 0) { return; } Graphics::Surface *surf = g_system->lockScreen(); - for (uint i = 0; i < _numBalloons; i++) { - Common::Rect r(_balloons[i].surface.w, _balloons[i].surface.h); - r.moveTo(_balloons[i].x, _balloons[i].y); - blt(r, (byte*)_balloons[i].surface.getBasePtr(0, 0), surf, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR); + for (uint i = 0; i < _balloons.size(); i++) { + drawGfxObject(_balloons[i], *surf, false); } g_system->unlockScreen(); } @@ -521,145 +484,6 @@ void Gfx::invertBackground(const Common::Rect& r) { } -// this is the maximum size of an unpacked frame in BRA -byte _unpackedBitmap[640*401]; - -#if 0 -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { - - byte *d = _unpackedBitmap; - - while (size > 0) { - - uint8 p = *data++; - size--; - uint8 color = p & 0xF; - uint8 repeat = (p & 0xF0) >> 4; - if (repeat == 0) { - repeat = *data++; - size--; - } - - memset(d, color, repeat); - d += repeat; - } - - blt(r, _unpackedBitmap, surf, z, transparentColor); -} -#endif -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { - - byte *d = _unpackedBitmap; - uint pixelsLeftInLine = r.width(); - - while (size > 0) { - uint8 p = *data++; - size--; - uint8 color = p & 0xF; - uint8 repeat = (p & 0xF0) >> 4; - if (repeat == 0) { - repeat = *data++; - size--; - } - if (repeat == 0) { - // end of line - repeat = pixelsLeftInLine; - pixelsLeftInLine = r.width(); - } else { - pixelsLeftInLine -= repeat; - } - - memset(d, color, repeat); - d += repeat; - } - - blt(r, _unpackedBitmap, surf, z, transparentColor); -} - - -void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { - - Common::Point dp; - Common::Rect q(r); - - Common::Rect clipper(surf->w, surf->h); - - q.clip(clipper); - if (!q.isValidRect()) return; - - dp.x = q.left; - dp.y = q.top; - - q.translate(-r.left, -r.top); - - byte *s = data + q.left + q.top * r.width(); - byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); - - uint sPitch = r.width() - q.width(); - uint dPitch = surf->w - q.width(); - - - if (_varRenderMode == 2) { - - for (uint16 i = 0; i < q.height(); i++) { - - for (uint16 j = 0; j < q.width(); j++) { - if (*s != transparentColor) { - if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { - byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); - if (z >= v) *d = 5; - } else { - *d = 5; - } - } - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } else { - if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { - - for (uint16 i = 0; i < q.height(); i++) { - - for (uint16 j = 0; j < q.width(); j++) { - if (*s != transparentColor) { - byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); - if (z >= v) *d = *s; - } - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } else { - - for (uint16 i = q.top; i < q.bottom; i++) { - for (uint16 j = q.left; j < q.right; j++) { - if (*s != transparentColor) - *d = *s; - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } - } - -} - @@ -669,10 +493,9 @@ void setupLabelSurface(Graphics::Surface &surf, uint w, uint h) { surf.fillRect(Common::Rect(w,h), LABEL_TRANSPARENT_COLOR); } -Label *Gfx::renderFloatingLabel(Font *font, char *text) { +uint Gfx::renderFloatingLabel(Font *font, char *text) { - Label *label = new Label; - Graphics::Surface *cnv = &label->_cnv; + Graphics::Surface *cnv = new Graphics::Surface; uint w, h; @@ -698,14 +521,74 @@ Label *Gfx::renderFloatingLabel(Font *font, char *text) { drawText(font, cnv, 0, 0, text, 0); } - return label; + GfxObj *obj = new GfxObj(kGfxObjTypeLabel, new SurfaceToFrames(cnv), "floatingLabel"); + obj->transparentKey = LABEL_TRANSPARENT_COLOR; + obj->layer = LAYER_FOREGROUND; + + uint id = _labels.size(); + _labels.insert_at(id, obj); + + return id; +} + +void Gfx::showFloatingLabel(uint label) { + assert(label < _labels.size()); + + hideFloatingLabel(); + + _labels[label]->x = -1000; + _labels[label]->y = -1000; + _labels[label]->setFlags(kGfxObjVisible); + + _floatingLabel = label; +} + +void Gfx::hideFloatingLabel() { + if (_floatingLabel != NO_FLOATING_LABEL) { + _labels[_floatingLabel]->clearFlags(kGfxObjVisible); + } + _floatingLabel = NO_FLOATING_LABEL; +} + + +void Gfx::updateFloatingLabel() { + if (_floatingLabel == NO_FLOATING_LABEL) { + return; + } + + int16 _si, _di; + + Common::Point cursor; + _vm->_input->getCursorPos(cursor); + + Common::Rect r; + _labels[_floatingLabel]->getRect(0, r); + + if (_vm->_input->_activeItem._id != 0) { + _si = cursor.x + 16 - r.width()/2; + _di = cursor.y + 34; + } else { + _si = cursor.x + 8 - r.width()/2; + _di = cursor.y + 21; + } + + if (_si < 0) _si = 0; + if (_di > 190) _di = 190; + + if (r.width() + _si > _vm->_screenWidth) + _si = _vm->_screenWidth - r.width(); + + _labels[_floatingLabel]->x = _si; + _labels[_floatingLabel]->y = _di; } + + + uint Gfx::createLabel(Font *font, const char *text, byte color) { - assert(_numLabels < MAX_NUM_LABELS); + assert(_labels.size() < MAX_NUM_LABELS); - Label *label = new Label; - Graphics::Surface *cnv = &label->_cnv; + Graphics::Surface *cnv = new Graphics::Surface; uint w, h; @@ -726,122 +609,65 @@ uint Gfx::createLabel(Font *font, const char *text, byte color) { drawText(font, cnv, 0, 0, text, color); } - uint id = _numLabels; - _labels[id] = label; - _numLabels++; + GfxObj *obj = new GfxObj(kGfxObjTypeLabel, new SurfaceToFrames(cnv), "label"); + obj->transparentKey = LABEL_TRANSPARENT_COLOR; + obj->layer = LAYER_FOREGROUND; + + int id = _labels.size(); + + _labels.insert_at(id, obj); return id; } void Gfx::showLabel(uint id, int16 x, int16 y) { - assert(id < _numLabels); - _labels[id]->_visible = true; + assert(id < _labels.size()); + _labels[id]->setFlags(kGfxObjVisible); + + Common::Rect r; + _labels[id]->getRect(0, r); if (x == CENTER_LABEL_HORIZONTAL) { - x = CLIP<int16>((_vm->_screenWidth - _labels[id]->_cnv.w) / 2, 0, _vm->_screenWidth/2); + x = CLIP<int16>((_vm->_screenWidth - r.width()) / 2, 0, _vm->_screenWidth/2); } if (y == CENTER_LABEL_VERTICAL) { - y = CLIP<int16>((_vm->_screenHeight - _labels[id]->_cnv.h) / 2, 0, _vm->_screenHeight/2); + y = CLIP<int16>((_vm->_screenHeight - r.height()) / 2, 0, _vm->_screenHeight/2); } - _labels[id]->_pos.x = x; - _labels[id]->_pos.y = y; + _labels[id]->x = x; + _labels[id]->y = y; } void Gfx::hideLabel(uint id) { - assert(id < _numLabels); - _labels[id]->_visible = false; + assert(id < _labels.size()); + _labels[id]->clearFlags(kGfxObjVisible); } void Gfx::freeLabels() { - for (uint i = 0; i < _numLabels; i++) { + for (uint i = 0; i < _labels.size(); i++) { delete _labels[i]; } - _numLabels = 0; -} - - -void Gfx::setFloatingLabel(Label *label) { - _floatingLabel = label; - - if (_floatingLabel) { - _floatingLabel->resetPosition(); - } -} - -void Gfx::updateFloatingLabel() { - if (!_floatingLabel) { - return; - } - - int16 _si, _di; - - Common::Point cursor; - _vm->_input->getCursorPos(cursor); - - if (_vm->_input->_activeItem._id != 0) { - _si = cursor.x + 16 - _floatingLabel->_cnv.w/2; - _di = cursor.y + 34; - } else { - _si = cursor.x + 8 - _floatingLabel->_cnv.w/2; - _di = cursor.y + 21; - } - - if (_si < 0) _si = 0; - if (_di > 190) _di = 190; - - if (_floatingLabel->_cnv.w + _si > _vm->_screenWidth) - _si = _vm->_screenWidth - _floatingLabel->_cnv.w; - - _floatingLabel->_pos.x = _si; - _floatingLabel->_pos.y = _di; + _labels.clear(); + _floatingLabel = NO_FLOATING_LABEL; } void Gfx::drawLabels() { - if ((!_floatingLabel) && (_numLabels == 0)) { + if (_labels.size() == 0) { return; } + updateFloatingLabel(); Graphics::Surface* surf = g_system->lockScreen(); - for (uint i = 0; i < _numLabels; i++) { - if (_labels[i]->_visible) { - Common::Rect r(_labels[i]->_cnv.w, _labels[i]->_cnv.h); - r.moveTo(_labels[i]->_pos); - blt(r, (byte*)_labels[i]->_cnv.getBasePtr(0, 0), surf, LAYER_FOREGROUND, LABEL_TRANSPARENT_COLOR); - } - } - - if (_floatingLabel) { - Common::Rect r(_floatingLabel->_cnv.w, _floatingLabel->_cnv.h); - r.moveTo(_floatingLabel->_pos); - blt(r, (byte*)_floatingLabel->_cnv.getBasePtr(0, 0), surf, LAYER_FOREGROUND, LABEL_TRANSPARENT_COLOR); + for (uint i = 0; i < _labels.size(); i++) { + drawGfxObject(_labels[i], *surf, false); } g_system->unlockScreen(); } -Label::Label() { - resetPosition(); - _visible = false; -} - -Label::~Label() { - free(); -} - -void Label::free() { - _cnv.free(); - resetPosition(); -} - -void Label::resetPosition() { - _pos.x = -1000; - _pos.y = -1000; -} - void Gfx::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) { @@ -917,10 +743,8 @@ Gfx::Gfx(Parallaction* vm) : setPalette(_palette); - _numBalloons = 0; _numItems = 0; - _numLabels = 0; - _floatingLabel = 0; + _floatingLabel = NO_FLOATING_LABEL; _screenX = 0; _screenY = 0; @@ -943,20 +767,21 @@ Gfx::Gfx(Parallaction* vm) : Gfx::~Gfx() { freeBackground(); + freeLabels(); return; } -int Gfx::setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor) { +int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) { int id = _numItems; _items[id].data = frames; - _items[id].x = x; - _items[id].y = y; - - _items[id].transparentColor = transparentColor; + _items[id].data->x = x; + _items[id].data->y = y; + _items[id].data->layer = LAYER_FOREGROUND; + _items[id].data->transparentKey = transparentColor; _numItems++; @@ -965,206 +790,35 @@ int Gfx::setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor) { void Gfx::setItemFrame(uint item, uint16 f) { assert(item < _numItems); - _items[item].frame = f; - _items[item].data->getRect(f, _items[item].rect); - _items[item].rect.moveTo(_items[item].x, _items[item].y); -} - -Gfx::Balloon* Gfx::getBalloon(uint id) { - assert(id < _numBalloons); - return &_balloons[id]; -} - -int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) { - assert(_numBalloons < 5); - - int id = _numBalloons; - - Gfx::Balloon *balloon = &_balloons[id]; - - int16 real_h = (winding == -1) ? h : h + 9; - balloon->surface.create(w, real_h, 1); - balloon->surface.fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR); - - Common::Rect r(w, h); - balloon->surface.fillRect(r, 0); - balloon->outerBox = r; - - r.grow(-borderThickness); - balloon->surface.fillRect(r, 1); - balloon->innerBox = r; - - if (winding != -1) { - // draws tail - // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill. - winding = (winding == 0 ? 1 : 0); - Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); - s.moveTo(r.width()/2 - 5, r.bottom - 1); - blt(s, _resBalloonTail[winding], &balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR); - } - - _numBalloons++; - - return id; -} - -int Gfx::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { - - int16 w, h; - - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); - - int id = createBalloon(w+5, h, winding, 1); - Gfx::Balloon *balloon = &_balloons[id]; - - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH); - - balloon->x = x; - balloon->y = y; - - return id; -} - -int Gfx::setDialogueBalloon(char *text, uint16 winding, byte textColor) { - - int16 w, h; - - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); - - int id = createBalloon(w+5, h, winding, 1); - Gfx::Balloon *balloon = &_balloons[id]; - - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH); - - balloon->x = _dialogueBalloonX[id]; - balloon->y = 10; - - if (id > 0) { - balloon->y += _balloons[id - 1].y + _balloons[id - 1].outerBox.height(); - } - - - return id; + _items[item].data->frame = f; + _items[item].data->setFlags(kGfxObjVisible); } -void Gfx::setBalloonText(uint id, char *text, byte textColor) { - Gfx::Balloon *balloon = getBalloon(id); - balloon->surface.fillRect(balloon->innerBox, 1); - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH); -} - - -int Gfx::setLocationBalloon(char *text, bool endGame) { - - int16 w, h; - - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); - - int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); - Gfx::Balloon *balloon = &_balloons[id]; - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, 0, MAX_BALLOON_WIDTH); - - balloon->x = 5; - balloon->y = 5; - return id; -} +GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) { -int Gfx::hitTestDialogueBalloon(int x, int y) { + GfxObj *obj = new GfxObj(kGfxObjTypeBalloon, frames, text); - Common::Point p; + obj->layer = LAYER_FOREGROUND; + obj->frame = 0; + obj->setFlags(kGfxObjVisible); - for (uint i = 0; i < _numBalloons; i++) { - p.x = x - _balloons[i].x; - p.y = y - _balloons[i].y; - - if (_balloons[i].innerBox.contains(p)) - return i; - } + _balloons.push_back(obj); - return -1; + return obj; } - -void Gfx::freeBalloons() { - for (uint i = 0; i < _numBalloons; i++) { - _balloons[i].surface.free(); +void Gfx::destroyBalloons() { + for (uint i = 0; i < _balloons.size(); i++) { + delete _balloons[i]; } - _numBalloons = 0; + _balloons.clear(); } void Gfx::freeItems() { _numItems = 0; } -void Gfx::hideDialogueStuff() { - freeItems(); - freeBalloons(); -} - -void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) { - byte *dst = (byte*)surf->getBasePtr(x, y); - font->setColor(color); - font->drawString(dst, surf->w, text); -} - -void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) { - - uint16 lines = 0; - uint16 linewidth = 0; - - uint16 rx = 10; - uint16 ry = 4; - - uint16 blankWidth = font->getStringWidth(" "); - uint16 tokenWidth = 0; - - char token[MAX_TOKEN_LEN]; - - if (wrapwidth == -1) - wrapwidth = _vm->_screenWidth; - - while (strlen(text) > 0) { - - text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); - - if (!scumm_stricmp(token, "%p")) { - lines++; - rx = 10; - ry = 4 + lines*10; // y - - strcpy(token, "> ......."); - strncpy(token+2, _password, strlen(_password)); - tokenWidth = font->getStringWidth(token); - } else { - tokenWidth = font->getStringWidth(token); - - linewidth += tokenWidth; - - if (linewidth > wrapwidth) { - // wrap line - lines++; - rx = 10; // x - ry = 4 + lines*10; // y - linewidth = tokenWidth; - } - - if (!scumm_stricmp(token, "%s")) { - sprintf(token, "%d", _score); - } - - } - - drawText(font, surf, rx, ry, token, color); - - rx += tokenWidth + blankWidth; - linewidth += blankWidth; - - text = Common::ltrim(text); - } - -} - void Gfx::freeBackground() { _backgroundInfo.free(); } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index f03b8538b8..09f4b2f244 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -157,11 +157,11 @@ struct SurfaceToMultiFrames : public Frames { r.setHeight(_height); } uint getRawSize(uint16 index) { - assert(index == 0); + assert(index < _num); return getSize(index); } uint getSize(uint16 index) { - assert(index == 0); + assert(index < _num); return _width * _height; } @@ -326,20 +326,6 @@ public: #define CENTER_LABEL_HORIZONTAL -1 #define CENTER_LABEL_VERTICAL -1 -struct Label { - Graphics::Surface _cnv; - - Common::Point _pos; - bool _visible; - - Label(); - ~Label(); - - void free(); - void resetPosition(); -}; - - #define MAX_BALLOON_WIDTH 130 @@ -354,25 +340,39 @@ class Disk; enum { kGfxObjVisible = 1, + kGfxObjNormal = 2, + kGfxObjCharacter = 4, kGfxObjTypeDoor = 0, kGfxObjTypeGet = 1, - kGfxObjTypeAnim = 2 + kGfxObjTypeAnim = 2, + kGfxObjTypeLabel = 3, + kGfxObjTypeBalloon = 4, + kGfxObjTypeCharacter = 8 +}; + +enum { + kGfxObjDoorZ = -200, + kGfxObjGetZ = -100 }; class GfxObj { char *_name; Frames *_frames; - uint32 _flags; bool _keep; public: int16 x, y; - uint16 z; + + int32 z; + + uint32 _flags; + uint type; uint frame; uint layer; + uint transparentKey; GfxObj(uint type, Frames *frames, const char *name = NULL); virtual ~GfxObj(); @@ -453,6 +453,20 @@ enum { kBackgroundSlide = 2 }; + +class BalloonManager { +public: + virtual ~BalloonManager() { } + + virtual void freeBalloons() = 0; + virtual int setLocationBalloon(char *text, bool endGame) = 0; + virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0; + virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0; + virtual void setBalloonText(uint id, char *text, byte textColor) = 0; + virtual int hitTestDialogueBalloon(int x, int y) = 0; +}; + + typedef Common::HashMap<Common::String, int32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> VarMap; class Gfx { @@ -461,33 +475,33 @@ public: Disk *_disk; VarMap _vars; - GfxObjList _gfxobjList[3]; + GfxObjList _gfxobjList; GfxObj* loadAnim(const char *name); GfxObj* loadGet(const char *name); GfxObj* loadDoor(const char *name); void drawGfxObjects(Graphics::Surface &surf); void showGfxObj(GfxObj* obj, bool visible); - void clearGfxObjects(); + void clearGfxObjects(uint filter); void sortAnimations(); + // labels - void setFloatingLabel(Label *label); - Label *renderFloatingLabel(Font *font, char *text); + void showFloatingLabel(uint label); + void hideFloatingLabel(); + + uint renderFloatingLabel(Font *font, char *text); uint createLabel(Font *font, const char *text, byte color); void showLabel(uint id, int16 x, int16 y); void hideLabel(uint id); void freeLabels(); // dialogue balloons - int setLocationBalloon(char *text, bool endGame); - int setDialogueBalloon(char *text, uint16 winding, byte textColor); - int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); - void setBalloonText(uint id, char *text, byte textColor); - int hitTestDialogueBalloon(int x, int y); void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height); + GfxObj* registerBalloon(Frames *frames, const char *text); + void destroyBalloons(); // other items - int setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor = 0); + int setItem(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0); void setItemFrame(uint item, uint16 f); void hideDialogueStuff(); void freeBalloons(); @@ -549,36 +563,22 @@ protected: Graphics::Surface _bitmapMask; int32 getRenderMode(const char *type); -protected: - static int16 _dialogueBalloonX[5]; - - struct Balloon { - uint16 x; - uint16 y; - Common::Rect outerBox; - Common::Rect innerBox; - uint16 winding; - Graphics::Surface surface; - } _balloons[5]; - - uint _numBalloons; +public: struct Item { - uint16 x; - uint16 y; - uint16 frame; - Frames *data; - - byte transparentColor; - Common::Rect rect; + GfxObj *data; } _items[14]; uint _numItems; - #define MAX_NUM_LABELS 5 - Label* _labels[MAX_NUM_LABELS]; - uint _numLabels; - Label *_floatingLabel; + #define MAX_NUM_LABELS 20 + #define NO_FLOATING_LABEL 1000 + + typedef Common::Array<GfxObj*> GfxObjArray; + GfxObjArray _labels; + GfxObjArray _balloons; + + uint _floatingLabel; void drawInventory(); void updateFloatingLabel(); @@ -588,13 +588,11 @@ protected: void copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst); - int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); - Balloon *getBalloon(uint id); - // low level text and patches void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); + void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene); void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor); }; diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index e073a7c989..391459a12f 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -123,7 +123,7 @@ int Parallaction_br::guiShowMenu() { // TODO: filter menu entries according to progress in game #define NUM_MENULINES 7 - Frames *_lines[NUM_MENULINES]; + GfxObj *_lines[NUM_MENULINES]; const char *menuStrings[NUM_MENULINES] = { "SEE INTRO", @@ -158,7 +158,7 @@ int Parallaction_br::guiShowMenu() { int i; for (i = 0; i < availItems; i++) { - _lines[i] = guiRenderMenuItem(menuStrings[i]); + _lines[i] = new GfxObj(0, guiRenderMenuItem(menuStrings[i]), "MenuItem"); uint id = _gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF); _gfx->setItemFrame(id, 0); } @@ -196,7 +196,7 @@ int Parallaction_br::guiShowMenu() { } _system->showMouse(false); - _gfx->hideDialogueStuff(); + hideDialogueStuff(); for (i = 0; i < availItems; i++) { delete _lines[i]; diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 1d4d44fa46..9c48586dbc 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -166,6 +166,8 @@ void Parallaction_ns::guiStart() { } void Parallaction_ns::selectStartLocation() { + _inTestResult = false; + int character = guiSelectCharacter(); if (character == -1) error("invalid character selected from menu screen"); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 0fc00ce03b..9d5ff4ef80 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -174,7 +174,7 @@ void Input::updateGameInput() { void Input::updateCommentInput() { waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); _vm->_gfx->setHalfbriteMode(false); _inputMode = kInputModeGame; @@ -302,7 +302,7 @@ bool Input::translateInventoryInput() { _vm->dropItem(z->u.merge->_obj1); _vm->dropItem(z->u.merge->_obj2); _vm->addInventoryItem(z->u.merge->_obj3); - _vm->runCommands(z->_commands); + _vm->_cmdExec->run(z->_commands); } return true; diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 46dbb08c4e..e06fe96705 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -44,7 +44,7 @@ struct InputData { Common::Point _mousePos; int16 _inventoryIndex; ZonePtr _zone; - Label* _label; + uint _label; }; class Input { diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index 2478b4b2e1..fb867f5285 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -1,6 +1,7 @@ MODULE := engines/parallaction MODULE_OBJS := \ + balloons.o \ callables_br.o \ callables_ns.o \ debug.o \ diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index cac31911f4..66025cf0f7 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -54,6 +54,7 @@ Animation::Animation() { Animation::~Animation() { free(_scriptName); + gfxobj->release(); } uint16 Animation::width() const { @@ -182,7 +183,8 @@ Zone::~Zone() { break; } - delete _label; + + free(_linkedName); } void Zone::getRect(Common::Rect& r) const { @@ -207,6 +209,16 @@ uint16 Zone::height() const { return _bottom - _top; } +Dialogue::Dialogue() { + memset(_questions, 0, sizeof(_questions)); +} + +Dialogue::~Dialogue() { + for (int i = 0; i < NUM_QUESTIONS; i++) { + delete _questions[i]; + } +} + Answer::Answer() { _text = NULL; _mood = 0; diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index afa6cc5ed5..19835da9d0 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -181,6 +181,9 @@ struct Question { struct Dialogue { Question *_questions[NUM_QUESTIONS]; + + Dialogue(); + ~Dialogue(); }; struct GetData { // size = 24 @@ -206,7 +209,7 @@ struct SpeakData { // size = 36 } }; struct ExamineData { // size = 28 - Frames *_cnv; + GfxObj *_cnv; uint16 _opBase; // unused uint16 field_12; // unused char* _description; @@ -284,7 +287,7 @@ struct Zone { int16 _bottom; uint32 _type; uint32 _flags; - Label *_label; + uint _label; uint16 field_2C; // unused uint16 field_2E; // unused TypeData u; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index ee8e0cbcc8..2fc809977f 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -84,18 +84,20 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam Parallaction::~Parallaction() { - clearSet(_commandOpcodes); - clearSet(_instructionOpcodes); - delete _debugger; delete _globalTable; delete _callableNames; + delete _cmdExec; + delete _programExec; + _gfx->clearGfxObjects(kGfxObjCharacter | kGfxObjNormal); + hideDialogueStuff(); + delete _balloonMan; freeLocation(); freeCharacter(); destroyInventory(); - + delete _localFlagNames; delete _gfx; delete _soundMan; @@ -136,6 +138,8 @@ int Parallaction::init() { _debugger = new Debugger(this); + setupBalloonManager(); + return 0; } @@ -166,6 +170,8 @@ void Parallaction::freeCharacter() { delete _objectsNames; _objectsNames = 0; + _gfx->clearGfxObjects(kGfxObjCharacter); + _char.free(); return; @@ -195,6 +201,9 @@ AnimationPtr Parallaction::findAnimation(const char *name) { } void Parallaction::freeAnimations() { + for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { + (*it)->_commands.clear(); // See comment for freeZones(), about circular references. + } _location._animations.clear(); return; } @@ -245,7 +254,7 @@ void Parallaction::freeLocation() { _location._walkNodes.clear(); - _gfx->clearGfxObjects(); + _gfx->clearGfxObjects(kGfxObjNormal); freeBackground(); _location._programs.clear(); @@ -280,7 +289,7 @@ void Parallaction::setBackground(const char* name, const char* mask, const char* } void Parallaction::showLocationComment(const char *text, bool end) { - _gfx->setLocationBalloon(const_cast<char*>(text), end); + _balloonMan->setLocationBalloon(const_cast<char*>(text), end); } @@ -289,12 +298,12 @@ void Parallaction::processInput(InputData *data) { switch (data->_event) { case kEvEnterZone: debugC(2, kDebugInput, "processInput: kEvEnterZone"); - _gfx->setFloatingLabel(data->_label); + _gfx->showFloatingLabel(data->_label); break; case kEvExitZone: debugC(2, kDebugInput, "processInput: kEvExitZone"); - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); break; case kEvAction: @@ -307,7 +316,7 @@ void Parallaction::processInput(InputData *data) { case kEvOpenInventory: _input->stopHovering(); - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { setArrowCursor(); } @@ -379,8 +388,12 @@ void Parallaction::runGame() { _gfx->beginFrame(); if (_input->_inputMode == Input::kInputModeGame) { - runScripts(); - walk(); + _programExec->runScripts(_location._programs.begin(), _location._programs.end()); + _char._ani->_z = _char._ani->height() + _char._ani->_top; + if (_char._ani->gfxobj) { + _char._ani->gfxobj->z = _char._ani->_z; + } + walk(_char); drawAnimations(); } @@ -415,14 +428,14 @@ void Parallaction::doLocationEnterTransition() { pal.makeGrayscale(); _gfx->setPalette(pal); - runScripts(); + _programExec->runScripts(_location._programs.begin(), _location._programs.end()); drawAnimations(); _gfx->updateScreen(); showLocationComment(_location._comment, false); _input->waitUntilLeftClick(); - _gfx->freeBalloons(); + _balloonMan->freeBalloons(); // fades maximum intensity palette towards approximation of main palette for (uint16 _si = 0; _si<6; _si++) { @@ -482,6 +495,9 @@ void Parallaction::freeZones() { debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name); it++; } else { + (*it)->_commands.clear(); // Since commands may reference zones, and both commands and zones are kept stored into + // SharedPtr's, we need to kill commands explicitly to destroy any potential circular + // reference. it = _location._zones.erase(it); } } @@ -490,6 +506,34 @@ void Parallaction::freeZones() { } +enum { + WALK_LEFT = 0, + WALK_RIGHT = 1, + WALK_DOWN = 2, + WALK_UP = 3 +}; + +struct WalkFrames { + int16 stillFrame[4]; + int16 firstWalkFrame[4]; + int16 numWalkFrames[4]; + int16 frameRepeat[4]; +}; + +WalkFrames _char20WalkFrames = { + { 0, 7, 14, 17 }, + { 1, 8, 15, 18 }, + { 6, 6, 2, 2 }, + { 2, 2, 4, 4 } +}; + +WalkFrames _char24WalkFrames = { + { 0, 9, 18, 21 }, + { 1, 10, 19, 22 }, + { 8, 8, 2, 2 }, + { 2, 2, 4, 4 } +}; + const char Character::_prefixMini[] = "mini"; const char Character::_suffixTras[] = "tras"; const char Character::_empty[] = "\0"; @@ -500,6 +544,9 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder( _head = NULL; _objs = NULL; + _direction = WALK_DOWN; + _step = 0; + _dummy = false; _ani->_left = 150; @@ -564,10 +611,14 @@ void Character::setName(const char *name) { const char *end = begin + strlen(name); _prefix = _empty; + _suffix = _empty; _dummy = IS_DUMMY_CHARACTER(name); if (!_dummy) { + if (!strstr(name, "donna")) { + _engineFlags &= ~kEngineTransformedDonna; + } else if (_engineFlags & kEngineTransformedDonna) { _suffix = _suffixTras; } else { @@ -576,8 +627,6 @@ void Character::setName(const char *name) { _engineFlags |= kEngineTransformedDonna; _suffix = _suffixTras; end = s; - } else { - _suffix = _empty; } } if (IS_MINI_CHARACTER(name)) { @@ -618,4 +667,29 @@ void Parallaction::scheduleLocationSwitch(const char *location) { } + + + +void Character::updateDirection(const Common::Point& pos, const Common::Point& to) { + + Common::Point dist(to.x - pos.x, to.y - pos.y); + WalkFrames *frames = (_ani->getFrameNum() == 20) ? &_char20WalkFrames : &_char24WalkFrames; + + _step++; + + if (dist.x == 0 && dist.y == 0) { + _ani->_frame = frames->stillFrame[_direction]; + return; + } + + if (dist.x < 0) + dist.x = -dist.x; + if (dist.y < 0) + dist.y = -dist.y; + + _direction = (dist.x > dist.y) ? ((to.x > pos.x) ? WALK_LEFT : WALK_RIGHT) : ((to.y > pos.y) ? WALK_DOWN : WALK_UP); + _ani->_frame = frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction]; +} + + } // namespace Parallaction diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 9f8bbea1b0..461ddc674f 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -33,6 +33,7 @@ #include "engines/engine.h" +#include "parallaction/exec.h" #include "parallaction/input.h" #include "parallaction/inventory.h" #include "parallaction/parser.h" @@ -201,9 +202,9 @@ struct Character { AnimationPtr _ani; - Frames *_head; - Frames *_talk; - Frames *_objs; + GfxObj *_head; + GfxObj *_talk; + GfxObj *_objs; PathBuilder _builder; WalkNodeList *_walkPath; @@ -227,18 +228,19 @@ protected: static const char _suffixTras[]; static const char _empty[]; + int16 _direction, _step; + public: void setName(const char *name); const char *getName() const; const char *getBaseName() const; const char *getFullName() const; bool dummy() const; -}; + void updateDirection(const Common::Point& pos, const Common::Point& to); +}; -#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op() -#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op() #define NUM_LOCATIONS 120 @@ -263,31 +265,14 @@ public: Input *_input; - OpcodeSet _commandOpcodes; - - struct ParallactionStruct1 { - CommandPtr cmd; - ZonePtr z; - } _cmdRunCtxt; - - OpcodeSet _instructionOpcodes; - - struct ParallactionStruct2 { - AnimationPtr anim; - ProgramPtr program; - InstructionList::iterator inst; - uint16 modCounter; - bool suspend; - } _instRunCtxt; - void processInput(InputData* data); void pauseJobs(); void resumeJobs(); - void finalizeWalk(WalkNodeList *list); - int16 selectWalkFrame(const Common::Point& pos, const WalkNodePtr from); - void clipMove(Common::Point& pos, const WalkNodePtr from); + void finalizeWalk(Character &character); + int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to); + void clipMove(Common::Point& pos, const Common::Point& to); ZonePtr findZone(const char *name); ZonePtr hitZone(uint32 type, uint16 x, uint16 y); @@ -296,8 +281,6 @@ public: void runDialogue(SpeakData*); - void runCommands(CommandList& list, ZonePtr z = nullZonePtr); - AnimationPtr findAnimation(const char *name); void freeAnimations(); @@ -331,6 +314,8 @@ public: Gfx* _gfx; Disk* _disk; + CommandExec* _cmdExec; + ProgramExec* _programExec; Character _char; void setLocationFlags(uint32 flags); @@ -371,10 +356,8 @@ protected: // members void runGame(); void updateView(); - void scheduleLocationSwitch(const char *location); void doLocationEnterTransition(); virtual void changeLocation(char *location) = 0; - virtual void changeCharacter(const char *name) = 0; virtual void runPendingZones() = 0; void allocateLocationSlot(const char *name); void finalizeLocationParsing(); @@ -383,7 +366,7 @@ protected: // members void displayComment(ExamineData *data); - uint16 checkDoor(); + void checkDoor(const Common::Point &foot); void freeCharacter(); @@ -393,6 +376,9 @@ protected: // members public: + void scheduleLocationSwitch(const char *location); + virtual void changeCharacter(const char *name) = 0; + virtual void callFunction(uint index, void* parm) { } virtual void setArrowCursor() = 0; @@ -402,12 +388,12 @@ public: void updateDoor(ZonePtr z); - virtual void runScripts() = 0; - virtual void walk() = 0; + virtual void walk(Character &character) = 0; virtual void drawAnimations() = 0; void beep(); + ZonePtr _zoneTrap; public: // const char **_zoneFlagNamesRes; @@ -433,6 +419,15 @@ public: Inventory *_inventory; InventoryRenderer *_inventoryRenderer; + BalloonManager *_balloonMan; + + void setupBalloonManager(); + + void hideDialogueStuff() { + _gfx->freeItems(); + _balloonMan->freeBalloons(); + } + }; @@ -528,7 +523,6 @@ private: void initResources(); void initCursors(); - void initParsers(); static byte _resMouseArrow[256]; byte *_mouseArrow; @@ -552,6 +546,9 @@ private: ZonePtr _moveSarcExaZones[5]; AnimationPtr _rightHandAnim; + bool _inTestResult; + + // common callables void _c_play_boogie(void*); void _c_startIntro(void*); @@ -588,49 +585,12 @@ private: const Callable *_callables; protected: - void runScripts(); - void walk(); + void walk(Character &character); void drawAnimations(); void parseLocation(const char *filename); void loadProgram(AnimationPtr a, const char *filename); - void initOpcodes(); - - DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(set); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(get); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); - - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); - void selectStartLocation(); void guiStart(); @@ -663,6 +623,9 @@ public: typedef void (Parallaction_br::*Callable)(void*); virtual void callFunction(uint index, void* parm); void changeCharacter(const char *name); + void setupSubtitles(char *s, char *s2, int y); + void clearSubtitles(); + public: Table *_countersNames; @@ -690,8 +653,6 @@ private: void initResources(); void initFonts(); void freeFonts(); - void initOpcodes(); - void initParsers(); void setArrowCursor(); void setInventoryCursor(int pos); @@ -733,68 +694,6 @@ private: void parseLocation(const char* name); void loadProgram(AnimationPtr a, const char *filename); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(character); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(add); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(let); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(music); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(give); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(text); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(part); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave); - - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); - - void setupSubtitles(char *s, char *s2, int y); - void clearSubtitles(); #if 0 void jobWaitRemoveLabelJob(void *parm, Job *job); void jobPauseSfx(void *parm, Job *job); diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 72a829d7cb..090184e9fe 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -72,14 +72,21 @@ int Parallaction_br::init() { initResources(); initFonts(); initCursors(); - initOpcodes(); _locationParser = new LocationParser_br(this); _locationParser->init(); _programParser = new ProgramParser_br(this); _programParser->init(); + _cmdExec = new CommandExec_br(this); + _cmdExec->init(); + _programExec = new ProgramExec_br(this); + _programExec->init(); + _part = -1; + _subtitle[0] = -1; + _subtitle[1] = -1; + Parallaction::init(); return 0; @@ -221,10 +228,16 @@ void Parallaction_br::changeLocation(char *location) { // free open location stuff clearSubtitles(); freeBackground(); - _gfx->clearGfxObjects(); + _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter); _location._programs.clear(); + + _location._animations.remove(_char._ani); + freeZones(); freeAnimations(); + + _location._animations.push_front(_char._ani); + // free(_location._comment); // _location._comment = 0; // _location._commands.clear(); @@ -233,9 +246,9 @@ void Parallaction_br::changeLocation(char *location) { // load new location parseLocation(location); - runCommands(_location._commands); + _cmdExec->run(_location._commands); // doLocationEnterTransition(); - runCommands(_location._aCommands); + _cmdExec->run(_location._aCommands); _engineFlags &= ~kEngineChangeLocation; } @@ -284,12 +297,16 @@ void Parallaction_br::loadProgram(AnimationPtr a, const char *filename) { void Parallaction_br::changeCharacter(const char *name) { + printf("changeCharacter(%s)\n", name); + const char *charName = _char.getName(); if (!scumm_stricmp(charName, name)) { return; } _char.setName(name); + _char._ani->gfxobj = _gfx->loadAnim(name); + _char._ani->gfxobj->setFlags(kGfxObjCharacter); _char._talk = _disk->loadTalk(name); } diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 318443bb18..e5baf1864d 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -135,18 +135,24 @@ int Parallaction_ns::init() { initResources(); initFonts(); initCursors(); - initOpcodes(); _locationParser = new LocationParser_ns(this); _locationParser->init(); _programParser = new ProgramParser_ns(this); _programParser->init(); + _cmdExec = new CommandExec_ns(this); + _cmdExec->init(); + _programExec = new ProgramExec_ns(this); + _programExec->init(); + _introSarcData1 = 0; _introSarcData2 = 1; _introSarcData3 = 200; num_foglie = 0; + _inTestResult = false; + _location._animations.push_front(_char._ani); Parallaction::init(); @@ -156,7 +162,7 @@ int Parallaction_ns::init() { Parallaction_ns::~Parallaction_ns() { freeFonts(); - + delete _locationParser; delete _programParser; delete _mouseComposedArrow; @@ -185,7 +191,7 @@ void Parallaction_ns::setArrowCursor() { debugC(1, kDebugInput, "setting mouse cursor to arrow"); // this stuff is needed to avoid artifacts with labels and selected items when switching cursors - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); _input->_activeItem._id = 0; _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); @@ -235,10 +241,10 @@ int Parallaction_ns::go() { _globalTable = _disk->loadTable("global"); guiStart(); - + if (quit()) return _eventMan->shouldRTL(); - + changeLocation(_location._name); if (quit()) @@ -296,14 +302,17 @@ void Parallaction_ns::changeLocation(char *location) { _soundMan->playLocationMusic(location); - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); _gfx->freeLabels(); + _zoneTrap = nullZonePtr; + _input->stopHovering(); if (_engineFlags & kEngineBlockInput) { setArrowCursor(); } + _gfx->showGfxObj(_char._ani->gfxobj, false); _location._animations.remove(_char._ani); freeLocation(); @@ -325,6 +334,7 @@ void Parallaction_ns::changeLocation(char *location) { } _location._animations.push_front(_char._ani); + _gfx->showGfxObj(_char._ani->gfxobj, true); strcpy(_saveData1, locname.location()); parseLocation(_saveData1); @@ -349,11 +359,11 @@ void Parallaction_ns::changeLocation(char *location) { // and acommands are executed, so that it can be set again if needed. _engineFlags &= ~kEngineChangeLocation; - runCommands(_location._commands); + _cmdExec->run(_location._commands); doLocationEnterTransition(); - runCommands(_location._aCommands); + _cmdExec->run(_location._aCommands); if (_location._hasSound) _soundMan->playSfx(_location._soundFile, 0, true); @@ -409,6 +419,7 @@ void Parallaction_ns::changeCharacter(const char *name) { Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); _char._ani->gfxobj = _gfx->loadAnim(_char.getFullName()); + _char._ani->gfxobj->setFlags(kGfxObjCharacter); if (!_char.dummy()) { if (getPlatform() == Common::kPlatformAmiga) { diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 51da7eb396..defc917a72 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -390,7 +390,7 @@ DECLARE_LOCATION_PARSER(flags) { if ((_vm->getLocationFlags() & kFlagsVisited) == 0) { // only for 1st visit - _vm->clearLocationFlags(kFlagsAll); + _vm->clearLocationFlags((uint32)kFlagsAll); int _si = 1; do { diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index c654e3008e..2f4d2df776 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1059,7 +1059,7 @@ DECLARE_LOCATION_PARSER(flags) { if ((_vm->getLocationFlags() & kFlagsVisited) == 0) { // only for 1st visit - _vm->clearLocationFlags(kFlagsAll); + _vm->clearLocationFlags((uint32)kFlagsAll); int _si = 1; do { diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp index dd74e8f7aa..df6867a90c 100644 --- a/engines/parallaction/sound.cpp +++ b/engines/parallaction/sound.cpp @@ -175,6 +175,7 @@ void MidiPlayer::close() { _mutex.lock(); _driver->setTimerCallback(NULL, NULL); _driver->close(); + delete _driver; _driver = 0; _parser->setMidiDriver(NULL); delete _parser; @@ -249,6 +250,9 @@ void DosSoundMan::stopMusic() { } void DosSoundMan::playCharacterMusic(const char *character) { + if (character == NULL) { + return; + } if (!scumm_stricmp(_vm->_location._name, "night") || !scumm_stricmp(_vm->_location._name, "intsushi")) { diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 0a8ded9e29..40dfddb903 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -27,12 +27,6 @@ namespace Parallaction { -static uint16 _doorData1 = 1000; -static ZonePtr _zoneTrap; - -static uint16 walkData1 = 0; -static uint16 walkData2 = 0; // next walk frame - inline byte PathBuffer::getValue(uint16 x, uint16 y) { byte m = data[(x >> 3) + y * internalWidth]; @@ -259,172 +253,117 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) { return 1; } -void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr from) { +void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { - if ((pos.x < from->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { - pos.x = (pos.x + 2 < from->_x) ? pos.x + 2 : from->_x; + if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { + pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x; } - if ((pos.x > from->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { - pos.x = (pos.x - 2 > from->_x) ? pos.x - 2 : from->_x; + if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { + pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x; } - if ((pos.y < from->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { - pos.y = (pos.y + 2 <= from->_y) ? pos.y + 2 : from->_y; + if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { + pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y; } - if ((pos.y > from->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { - pos.y = (pos.y - 2 >= from->_y) ? pos.y - 2 :from->_y; + if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { + pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y; } return; } -int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr from) { - - Common::Point dist(from->_x - pos.x, from->_y - pos.y); - - if (dist.x < 0) - dist.x = -dist.x; - if (dist.y < 0) - dist.y = -dist.y; - walkData1++; - - // walk frame selection - int16 v16; - if (_char._ani->getFrameNum() == 20) { - - if (dist.x > dist.y) { - walkData2 = (from->_x > pos.x) ? 0 : 7; - walkData1 %= 12; - v16 = walkData1 / 2; - } else { - walkData2 = (from->_y > pos.y) ? 14 : 17; - walkData1 %= 8; - v16 = walkData1 / 4; - } - - } else { - - if (dist.x > dist.y) { - walkData2 = (from->_x > pos.x) ? 0 : 9; - walkData1 %= 16; - v16 = walkData1 / 2; - } else { - walkData2 = (from->_y > pos.y) ? 18 : 21; - walkData1 %= 8; - v16 = walkData1 / 4; - } - - } - - return v16; -} - -uint16 Parallaction::checkDoor() { -// printf("checkDoor()..."); - - if (_currentLocationIndex != _doorData1) { - _doorData1 = _currentLocationIndex; - _zoneTrap = nullZonePtr; - } - - _engineFlags &= ~kEngineWalking; - - Common::Point foot; +void Parallaction::checkDoor(const Common::Point &foot) { - _char.getFoot(foot); ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y); - if (z) { - if ((z->_flags & kFlagsClosed) == 0) { _location._startPosition = z->u.door->_startPos; _location._startFrame = z->u.door->_startFrame; - scheduleLocationSwitch(z->u.door->_location); _zoneTrap = nullZonePtr; - } else { - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); } } - _char.getFoot(foot); z = hitZone(kZoneTrap, foot.x, foot.y); - if (z) { setLocationFlags(kFlagsEnter); - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); clearLocationFlags(kFlagsEnter); _zoneTrap = z; } else if (_zoneTrap) { setLocationFlags(kFlagsExit); - runCommands(_zoneTrap->_commands, _zoneTrap); + _cmdExec->run(_zoneTrap->_commands, _zoneTrap); clearLocationFlags(kFlagsExit); _zoneTrap = nullZonePtr; } -// printf("done\n"); - - _char._ani->_frame = walkData2; - return _char._ani->_frame; } -void Parallaction::finalizeWalk(WalkNodeList *list) { - checkDoor(); - delete list; +void Parallaction::finalizeWalk(Character &character) { + _engineFlags &= ~kEngineWalking; + + Common::Point foot; + character.getFoot(foot); + checkDoor(foot); + + delete character._walkPath; + character._walkPath = 0; } -void Parallaction_ns::walk() { +void Parallaction_ns::walk(Character &character) { if ((_engineFlags & kEngineWalking) == 0) { return; } - WalkNodeList *list = _char._walkPath; - - _char._ani->_oldPos.x = _char._ani->_left; - _char._ani->_oldPos.y = _char._ani->_top; - - Common::Point pos; - _char.getFoot(pos); - - WalkNodeList::iterator it = list->begin(); + Common::Point curPos; + character.getFoot(curPos); - if (it != list->end()) { - if ((*it)->_x == pos.x && (*it)->_y == pos.y) { + // update target, if previous was reached + WalkNodeList::iterator it = character._walkPath->begin(); + if (it != character._walkPath->end()) { + if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y); - it = list->erase(it); + it = character._walkPath->erase(it); } } - if (it == list->end()) { - debugC(1, kDebugWalk, "walk reached last node"); -// j->_finished = 1; - finalizeWalk(list); - return; - } - _char._walkPath = list; - - // selectWalkFrame must be performed before position is changed by clipMove - int16 v16 = selectWalkFrame(pos, *it); - clipMove(pos, *it); - _char.setFoot(pos); + // advance character towards the target + Common::Point targetPos; + if (it == character._walkPath->end()) { + debugC(1, kDebugWalk, "walk reached last node"); + finalizeWalk(character); + targetPos = curPos; + } else { + if (*it) { + // targetPos is saved to help setting character direction + targetPos.x = (*it)->_x; + targetPos.y = (*it)->_y; + } - Common::Point newpos(_char._ani->_left, _char._ani->_top); + Common::Point newPos(curPos); + clipMove(newPos, targetPos); + character.setFoot(newPos); - if (newpos == _char._ani->_oldPos) { - debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); -// j->_finished = 1; - finalizeWalk(list); - } else { - _char._ani->_frame = v16 + walkData2 + 1; + if (newPos == curPos) { + debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); + finalizeWalk(character); + } } - return; + // targetPos is used to select the direction (and the walkFrame) of a character, + // since it doesn't cause the sudden changes in orientation that newPos would. + // Since newPos is 'adjusted' according to walkable areas, an imaginary line drawn + // from curPos to newPos is prone to abrutply change in direction, thus making the + // code select 'too different' frames when walking diagonally against obstacles, + // and yielding an annoying shaking effect in the character. + character.updateDirection(curPos, targetPos); } diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp index 5a8db74e3b..b3bd663baf 100644 --- a/engines/queen/resource.cpp +++ b/engines/queen/resource.cpp @@ -106,7 +106,7 @@ ResourceEntry *Resource::resourceEntry(const char *filename) const { re = &_resourceTable[cur]; break; } - } while (cur++ < _resourceEntries); + } while (++cur < _resourceEntries); #endif return re; } diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 9359c6610c..753ad45212 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -492,7 +492,7 @@ static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Com // Note that GF_OLD_BUNDLE is true if and only if GF_OLD256 is false. // Candidates: maniac enhanced, zak enhanced, indy3ega, loom - if (g->version != 2 && g->version != 3 || (g->features & GF_OLD256)) + if ((g->version != 2 && g->version != 3) || (g->features & GF_OLD256)) return false; /* We distinguish the games by the presence/absence of diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s index cd3e5c7dad..83aaa78927 100644 --- a/engines/scumm/gfxARM.s +++ b/engines/scumm/gfxARM.s @@ -59,7 +59,7 @@ asmDrawStripToScreen: CMP r1,#4 @ If width<4 BLT end @ return - @ Width &= ~4 ? What's that about then? Width &= ~3 I could have + @ Width &= ~4 ? What''s that about then? Width &= ~3 I could have @ understood... BIC r1,r1,#4 diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index 33e6748860..f8fb1efca2 100644 --- a/engines/scumm/he/resource_he.cpp +++ b/engines/scumm/he/resource_he.cpp @@ -522,12 +522,13 @@ int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base, /* get a list of all resources at this level */ wr = list_resources(fi, base, &rescnt); - if (wr == NULL) + if (wr == NULL) { if (size != 0) return size; else return 0; - + } + /* process each resource listed */ for (c = 0 ; c < rescnt ; c++) { /* (over)write the corresponding WinResource holder with the current */ diff --git a/engines/scumm/imuse_digi/dimuse_track.h b/engines/scumm/imuse_digi/dimuse_track.h index 33147128cb..2d4c673cf6 100644 --- a/engines/scumm/imuse_digi/dimuse_track.h +++ b/engines/scumm/imuse_digi/dimuse_track.h @@ -85,13 +85,15 @@ struct Track { int getPan() const { return (pan != 64) ? 2 * pan - 127 : 0; } int getVol() const { return vol / 1000; } Audio::Mixer::SoundType getType() const { - Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType; + Audio::Mixer::SoundType type; if (volGroupId == 1) type = Audio::Mixer::kSpeechSoundType; else if (volGroupId == 2) type = Audio::Mixer::kSFXSoundType; else if (volGroupId == 3) type = Audio::Mixer::kMusicSoundType; + else + error("Track::getType(): invalid sound type"); return type; } }; diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index f2b2a67835..5894e837aa 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -411,15 +411,15 @@ void ScummEngine::listSavegames(bool *marks, int num) { char prefix[256]; char slot[3]; int slotNum; - Common::StringList filenames; + Common::StringList files; makeSavegameName(prefix, 99, false); prefix[strlen(prefix)-2] = '*'; prefix[strlen(prefix)-1] = 0; memset(marks, false, num * sizeof(bool)); //assume no savegames for this title - filenames = _saveFileMan->listSavefiles(prefix); + files = _saveFileMan->listSavefiles(prefix); - for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++){ + for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) { //Obtain the last 2 digits of the filename, since they correspond to the save slot slot[0] = file->c_str()[file->size()-2]; slot[1] = file->c_str()[file->size()-1]; diff --git a/engines/scumm/smush/codec47ARM.s b/engines/scumm/smush/codec47ARM.s index 81bfdb2d22..73341c117f 100644 --- a/engines/scumm/smush/codec47ARM.s +++ b/engines/scumm/smush/codec47ARM.s @@ -80,7 +80,7 @@ level1codeFD: LDRB r9,[r8,#384] @ r9 = l = tmp_ptr[384] LDRB r6,[r1],#1 @ r6 = val = *_d_src++ ADD r12,r8,#384 @ r12= &tmp_ptr[384] - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 BEQ level1codeFD_over1 level1codeFD_loop1: @@ -94,7 +94,7 @@ level1codeFD_over1: LDRB r9,[r12,#1] @ r9 = l = tmp_ptr[385] LDRB r6,[r1],#1 @ r6 = val = *_d_src++ SUB r12,r12,#256 @ r12= &tmp_ptr[128] (256 = 384-128) - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 BEQ level1codeFD_over2 level1codeFD_loop2: @@ -219,7 +219,7 @@ level2codeFD: LDRB r9,[r8,#96] @ r9 = l = tmp_ptr[96] LDRB r6,[r1],#1 @ r6 = val = *_d_src++ ADD r12,r8,#32 @ r12 = tmp_ptr + 32 - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 BEQ level2codeFD_over1 level2codeFD_loop1: @@ -232,7 +232,7 @@ level2codeFD_loop1: level2codeFD_over1: LDRB r9,[r12,#65] @ r9 = l = tmp_ptr[97] (65 = 97-32) LDRB r6,[r1],#1 @ r6 = val = *_d_src++ - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 MOVEQ PC,R14 level2codeFD_loop2: diff --git a/engines/touche/midi.cpp b/engines/touche/midi.cpp index ce62849d2f..d77dbf5bfa 100644 --- a/engines/touche/midi.cpp +++ b/engines/touche/midi.cpp @@ -23,6 +23,7 @@ * */ +#include "common/config-manager.h" #include "common/stream.h" #include "sound/midiparser.h" @@ -31,9 +32,8 @@ namespace Touche { -MidiPlayer::MidiPlayer(MidiDriver *driver, bool nativeMT32) - : _driver(driver), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0), _nativeMT32(nativeMT32) { - assert(_driver); +MidiPlayer::MidiPlayer() + : _driver(0), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0) { memset(_channelsTable, 0, sizeof(_channelsTable)); memset(_channelsVolume, 0, sizeof(_channelsVolume)); open(); @@ -92,6 +92,9 @@ void MidiPlayer::setVolume(int volume) { } int MidiPlayer::open() { + int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); + _nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); + _driver = MidiDriver::createMidi(midiDriver); int ret = _driver->open(); if (ret == 0) { _parser = MidiParser::createParser_SMF(); diff --git a/engines/touche/midi.h b/engines/touche/midi.h index 3b128593db..a518a4bb29 100644 --- a/engines/touche/midi.h +++ b/engines/touche/midi.h @@ -46,7 +46,7 @@ public: NUM_CHANNELS = 16 }; - MidiPlayer(MidiDriver *driver, bool nativeMT32); + MidiPlayer(); ~MidiPlayer(); void play(Common::ReadStream &stream, int size, bool loop = false); diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp index 0fa09d5b7a..c96a28bc8e 100644 --- a/engines/touche/saveload.cpp +++ b/engines/touche/saveload.cpp @@ -200,9 +200,6 @@ static void saveOrLoad(S &s, ProgramPointData &data) { saveOrLoad(s, data.order); } -template <class S, class A> -static void saveOrLoadCommonArray(S &s, A &array); - template <class A> static void saveOrLoadCommonArray(Common::WriteStream &stream, A &array) { uint count = array.size(); diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index cb8080effd..a4a9b7df92 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -91,11 +91,7 @@ int ToucheEngine::init() { setupOpcodes(); - int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); - bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); - MidiDriver *driver = MidiDriver::createMidi(midiDriver); - _midiPlayer = new MidiPlayer(driver, native_mt32); - + _midiPlayer = new MidiPlayer; _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); diff --git a/sound/midiparser_smf.cpp b/sound/midiparser_smf.cpp index ed5007ecb7..89b7d3f525 100644 --- a/sound/midiparser_smf.cpp +++ b/sound/midiparser_smf.cpp @@ -85,16 +85,26 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { _position._running_status = info.event; switch (info.command()) { - case 0xC: case 0xD: + case 0x9: // Note On + info.basic.param1 = *(_position._play_pos++); + info.basic.param2 = *(_position._play_pos++); + if (info.basic.param2 == 0) + info.event = info.channel() | 0x80; + info.length = 0; + break; + + case 0xC: + case 0xD: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; - case 0x8: case 0x9: case 0xA: case 0xB: case 0xE: + case 0x8: + case 0xA: + case 0xB: + case 0xE: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); - if (info.command() == 0x9 && info.basic.param2 == 0) - info.event = info.channel() | 0x80; info.length = 0; break; @@ -110,7 +120,12 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { info.basic.param2 = 0; break; - case 0x6: case 0x8: case 0xA: case 0xB: case 0xC: case 0xE: + case 0x6: + case 0x8: + case 0xA: + case 0xB: + case 0xC: + case 0xE: info.basic.param1 = info.basic.param2 = 0; break; diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp index d2aac49351..7cf114dcc6 100644 --- a/sound/midiparser_xmidi.cpp +++ b/sound/midiparser_xmidi.cpp @@ -38,6 +38,14 @@ protected: NoteTimer _notes_cache[32]; uint32 _inserted_delta; // Track simulated deltas for note-off events + struct Loop { + byte *pos; + byte repeat; + }; + + Loop _loop[4]; + int _loopCount; + protected: uint32 readVLQ2(byte * &data); void resetTracking(); @@ -78,16 +86,56 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { } break; - case 0xC: case 0xD: + case 0xC: + case 0xD: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; - case 0x8: case 0xA: case 0xB: case 0xE: + case 0x8: + case 0xA: + case 0xE: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); break; + case 0xB: + info.basic.param1 = *(_position._play_pos++); + info.basic.param2 = *(_position._play_pos++); + + // Simplified XMIDI looping. + // + // I would really like to turn the loop events into some sort + // of NOP event (perhaps a dummy META event?), but for now we + // just pass them on to the MIDI driver. That has worked in the + // past, so it shouldn't cause any actual damage... + + if (info.basic.param1 == 0x74) { + // XMIDI_CONTROLLER_FOR_LOOP + byte *pos = _position._play_pos; + if (_loopCount < ARRAYSIZE(_loop) - 1) + _loopCount++; + + _loop[_loopCount].pos = pos; + _loop[_loopCount].repeat = info.basic.param2; + } else if (info.basic.param1 == 0x75) { + // XMIDI_CONTROLLER_NEXT_BREAK + if (_loopCount >= 0) { + if (info.basic.param2 < 64) { + // End the current loop. + _loopCount--; + } else { + _position._play_pos = _loop[_loopCount].pos; + // Repeat 0 means "loop forever". + if (_loop[_loopCount].repeat) { + if (--_loop[_loopCount].repeat == 0) + _loopCount--; + } + } + } + } + break; + case 0xF: // Meta or SysEx event switch (info.event & 0x0F) { case 0x2: // Song Position Pointer @@ -100,7 +148,12 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { info.basic.param2 = 0; break; - case 0x6: case 0x8: case 0xA: case 0xB: case 0xC: case 0xE: + case 0x6: + case 0x8: + case 0xA: + case 0xB: + case 0xC: + case 0xE: info.basic.param1 = info.basic.param2 = 0; break; @@ -136,6 +189,8 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { uint32 chunk_len; char buf[32]; + _loopCount = -1; + unloadMusic(); byte *pos = data; diff --git a/sound/mixer.cpp b/sound/mixer.cpp index fc5b21cf32..27e031f108 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -27,7 +27,7 @@ #include "common/util.h" #include "common/system.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "sound/rate.h" #include "sound/audiostream.h" @@ -103,32 +103,38 @@ public: #pragma mark - -Mixer::Mixer() { - _syst = g_system; +MixerImpl::MixerImpl(OSystem *system) + : _syst(system), _sampleRate(0), _mixerReady(false), _handleSeed(0) { - _handleSeed = 0; - - int i = 0; + int i; for (i = 0; i < ARRAYSIZE(_volumeForSoundType); i++) _volumeForSoundType[i] = kMaxMixerVolume; for (i = 0; i != NUM_CHANNELS; i++) _channels[i] = 0; - - _mixerReady = false; } -Mixer::~Mixer() { +MixerImpl::~MixerImpl() { for (int i = 0; i != NUM_CHANNELS; i++) delete _channels[i]; } -uint Mixer::getOutputRate() const { - return (uint)_syst->getOutputSampleRate(); +void MixerImpl::setReady(bool ready) { + _mixerReady = ready; +} + +uint MixerImpl::getOutputRate() const { + return _sampleRate; +} + +void MixerImpl::setOutputRate(uint sampleRate) { + if (_sampleRate != 0 && _sampleRate != sampleRate) + error("Changing the Audio::Mixer output sample rate is not supported"); + _sampleRate = sampleRate; } -void Mixer::insertChannel(SoundHandle *handle, Channel *chan) { +void MixerImpl::insertChannel(SoundHandle *handle, Channel *chan) { int index = -1; for (int i = 0; i != NUM_CHANNELS; i++) { @@ -138,7 +144,7 @@ void Mixer::insertChannel(SoundHandle *handle, Channel *chan) { } } if (index == -1) { - warning("Mixer::out of mixer slots"); + warning("MixerImpl::out of mixer slots"); delete chan; return; } @@ -151,7 +157,7 @@ void Mixer::insertChannel(SoundHandle *handle, Channel *chan) { } } -void Mixer::playRaw( +void MixerImpl::playRaw( SoundType type, SoundHandle *handle, void *sound, @@ -166,7 +172,7 @@ void Mixer::playRaw( playInputStream(type, handle, input, id, volume, balance, true, false, ((flags & Mixer::FLAG_REVERSE_STEREO) != 0)); } -void Mixer::playInputStream( +void MixerImpl::playInputStream( SoundType type, SoundHandle *handle, AudioStream *input, @@ -198,8 +204,13 @@ void Mixer::playInputStream( insertChannel(handle, chan); } -void Mixer::mix(int16 *buf, uint len) { +void MixerImpl::mixCallback(byte *samples, uint len) { + assert(samples); + Common::StackLock lock(_mutex); + + int16 *buf = (int16 *)samples; + len >>= 2; // Since the mixer callback has been called, the mixer must be ready... _mixerReady = true; @@ -218,15 +229,7 @@ void Mixer::mix(int16 *buf, uint len) { } } -void Mixer::mixCallback(void *s, byte *samples, int len) { - assert(s); - assert(samples); - // Len is the number of bytes in the buffer; we divide it by - // four to get the number of samples (stereo 16 bit). - ((Mixer *)s)->mix((int16 *)samples, len >> 2); -} - -void Mixer::stopAll() { +void MixerImpl::stopAll() { Common::StackLock lock(_mutex); for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] != 0 && !_channels[i]->isPermanent()) { @@ -236,7 +239,7 @@ void Mixer::stopAll() { } } -void Mixer::stopID(int id) { +void MixerImpl::stopID(int id) { Common::StackLock lock(_mutex); for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] != 0 && _channels[i]->getId() == id) { @@ -246,7 +249,7 @@ void Mixer::stopID(int id) { } } -void Mixer::stopHandle(SoundHandle handle) { +void MixerImpl::stopHandle(SoundHandle handle) { Common::StackLock lock(_mutex); // Simply ignore stop requests for handles of sounds that already terminated @@ -258,7 +261,7 @@ void Mixer::stopHandle(SoundHandle handle) { _channels[index] = 0; } -void Mixer::setChannelVolume(SoundHandle handle, byte volume) { +void MixerImpl::setChannelVolume(SoundHandle handle, byte volume) { Common::StackLock lock(_mutex); const int index = handle._val % NUM_CHANNELS; @@ -268,7 +271,7 @@ void Mixer::setChannelVolume(SoundHandle handle, byte volume) { _channels[index]->setVolume(volume); } -void Mixer::setChannelBalance(SoundHandle handle, int8 balance) { +void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) { Common::StackLock lock(_mutex); const int index = handle._val % NUM_CHANNELS; @@ -278,7 +281,7 @@ void Mixer::setChannelBalance(SoundHandle handle, int8 balance) { _channels[index]->setBalance(balance); } -uint32 Mixer::getSoundElapsedTime(SoundHandle handle) { +uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) { Common::StackLock lock(_mutex); const int index = handle._val % NUM_CHANNELS; @@ -288,7 +291,7 @@ uint32 Mixer::getSoundElapsedTime(SoundHandle handle) { return _channels[index]->getElapsedTime(); } -void Mixer::pauseAll(bool paused) { +void MixerImpl::pauseAll(bool paused) { Common::StackLock lock(_mutex); for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] != 0) { @@ -297,7 +300,7 @@ void Mixer::pauseAll(bool paused) { } } -void Mixer::pauseID(int id, bool paused) { +void MixerImpl::pauseID(int id, bool paused) { Common::StackLock lock(_mutex); for (int i = 0; i != NUM_CHANNELS; i++) { if (_channels[i] != 0 && _channels[i]->getId() == id) { @@ -307,7 +310,7 @@ void Mixer::pauseID(int id, bool paused) { } } -void Mixer::pauseHandle(SoundHandle handle, bool paused) { +void MixerImpl::pauseHandle(SoundHandle handle, bool paused) { Common::StackLock lock(_mutex); // Simply ignore (un)pause requests for sounds that already terminated @@ -318,7 +321,7 @@ void Mixer::pauseHandle(SoundHandle handle, bool paused) { _channels[index]->pause(paused); } -bool Mixer::isSoundIDActive(int id) { +bool MixerImpl::isSoundIDActive(int id) { Common::StackLock lock(_mutex); for (int i = 0; i != NUM_CHANNELS; i++) if (_channels[i] && _channels[i]->getId() == id) @@ -326,7 +329,7 @@ bool Mixer::isSoundIDActive(int id) { return false; } -int Mixer::getSoundID(SoundHandle handle) { +int MixerImpl::getSoundID(SoundHandle handle) { Common::StackLock lock(_mutex); const int index = handle._val % NUM_CHANNELS; if (_channels[index] && _channels[index]->_handle._val == handle._val) @@ -334,13 +337,13 @@ int Mixer::getSoundID(SoundHandle handle) { return 0; } -bool Mixer::isSoundHandleActive(SoundHandle handle) { +bool MixerImpl::isSoundHandleActive(SoundHandle handle) { Common::StackLock lock(_mutex); const int index = handle._val % NUM_CHANNELS; return _channels[index] && _channels[index]->_handle._val == handle._val; } -bool Mixer::hasActiveChannelOfType(SoundType type) { +bool MixerImpl::hasActiveChannelOfType(SoundType type) { Common::StackLock lock(_mutex); for (int i = 0; i != NUM_CHANNELS; i++) if (_channels[i] && _channels[i]->_type == type) @@ -348,7 +351,7 @@ bool Mixer::hasActiveChannelOfType(SoundType type) { return false; } -void Mixer::setVolumeForSoundType(SoundType type, int volume) { +void MixerImpl::setVolumeForSoundType(SoundType type, int volume) { assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType)); // Check range @@ -363,7 +366,7 @@ void Mixer::setVolumeForSoundType(SoundType type, int volume) { _volumeForSoundType[type] = volume; } -int Mixer::getVolumeForSoundType(SoundType type) const { +int MixerImpl::getVolumeForSoundType(SoundType type) const { assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType)); return _volumeForSoundType[type]; @@ -443,7 +446,7 @@ uint32 Channel::getElapsedTime() { // Convert the number of samples into a time duration. To avoid // overflow, this has to be done in a somewhat non-obvious way. - uint rate = _mixer->getOutputRate(); + uint32 rate = _mixer->getOutputRate(); uint32 seconds = _samplesConsumed / rate; uint32 milliseconds = (1000 * (_samplesConsumed % rate)) / rate; diff --git a/sound/mixer.h b/sound/mixer.h index 26ae0898fd..28988256b3 100644 --- a/sound/mixer.h +++ b/sound/mixer.h @@ -38,6 +38,7 @@ namespace Audio { class AudioStream; class Channel; class Mixer; +class MixerImpl; /** * A SoundHandle instances corresponds to a specific sound @@ -47,7 +48,7 @@ class Mixer; */ class SoundHandle { friend class Channel; - friend class Mixer; + friend class MixerImpl; uint32 _val; public: inline SoundHandle() : _val(0xFFFFFFFF) {} @@ -104,24 +105,9 @@ public: kMaxMixerVolume = 256 }; -private: - enum { - NUM_CHANNELS = 16 - }; - - OSystem *_syst; - Common::Mutex _mutex; - - int _volumeForSoundType[4]; - - uint32 _handleSeed; - Channel *_channels[NUM_CHANNELS]; - - bool _mixerReady; - public: - Mixer(); - ~Mixer(); + Mixer() {} + virtual ~Mixer() {} @@ -132,8 +118,10 @@ public: * sync with an audio stream. In particular, the Adlib MIDI emulation... * * @return whether the mixer is ready and setup + * + * @todo get rid of this? */ - bool isReady() const { return _mixerReady; } + virtual bool isReady() const = 0; @@ -143,12 +131,12 @@ public: * (using the makeLinearInputStream factory function), which is then * passed on to playInputStream. */ - void playRaw( + virtual void playRaw( SoundType type, SoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id = -1, byte volume = kMaxChannelVolume, int8 balance = 0, - uint32 loopStart = 0, uint32 loopEnd = 0); + uint32 loopStart = 0, uint32 loopEnd = 0) = 0; /** * Start playing the given audio input stream. @@ -170,35 +158,35 @@ public: * not stop this particular stream * @param reverseStereo a flag indicating whether left and right channels shall be swapped */ - void playInputStream( + virtual void playInputStream( SoundType type, SoundHandle *handle, AudioStream *input, int id = -1, byte volume = kMaxChannelVolume, int8 balance = 0, bool autofreeStream = true, bool permanent = false, - bool reverseStereo = false); + bool reverseStereo = false) = 0; /** * Stop all currently playing sounds. */ - void stopAll(); + virtual void stopAll() = 0; /** * Stop playing the sound with given ID. * * @param id the ID of the sound to affect */ - void stopID(int id); + virtual void stopID(int id) = 0; /** * Stop playing the sound corresponding to the given handle. * * @param handle the sound to affect */ - void stopHandle(SoundHandle handle); + virtual void stopHandle(SoundHandle handle) = 0; @@ -208,7 +196,7 @@ public: * * @param paused true to pause everything, false to unpause */ - void pauseAll(bool paused); + virtual void pauseAll(bool paused) = 0; /** * Pause/unpause the sound with the given ID. @@ -216,7 +204,7 @@ public: * @param id the ID of the sound to affect * @param paused true to pause the sound, false to unpause it */ - void pauseID(int id, bool paused); + virtual void pauseID(int id, bool paused) = 0; /** * Pause/unpause the sound corresponding to the given handle. @@ -224,7 +212,7 @@ public: * @param handle the sound to affect * @param paused true to pause the sound, false to unpause it */ - void pauseHandle(SoundHandle handle, bool paused); + virtual void pauseHandle(SoundHandle handle, bool paused) = 0; @@ -234,7 +222,7 @@ public: * @param id the ID of the sound to query * @return true if the sound is active */ - bool isSoundIDActive(int id); + virtual bool isSoundIDActive(int id) = 0; /** * Get the sound ID of handle sound @@ -242,7 +230,7 @@ public: * @param handle sound to query * @return sound ID if active */ - int getSoundID(SoundHandle handle); + virtual int getSoundID(SoundHandle handle) = 0; /** * Check if a sound with the given handle is active. @@ -250,7 +238,7 @@ public: * @param handle sound to query * @return true if the sound is active */ - bool isSoundHandleActive(SoundHandle handle); + virtual bool isSoundHandleActive(SoundHandle handle) = 0; @@ -260,7 +248,7 @@ public: * @param handle the sound to affect * @param volume the new channel volume (0 - kMaxChannelVolume) */ - void setChannelVolume(SoundHandle handle, byte volume); + virtual void setChannelVolume(SoundHandle handle, byte volume) = 0; /** * Set the channel balance for the given handle. @@ -269,12 +257,12 @@ public: * @param balance the new channel balance: * (-127 ... 0 ... 127) corresponds to (left ... center ... right) */ - void setChannelBalance(SoundHandle handle, int8 balance); + virtual void setChannelBalance(SoundHandle handle, int8 balance) = 0; /** * Get approximation of for how long the channel has been playing. */ - uint32 getSoundElapsedTime(SoundHandle handle); + virtual uint32 getSoundElapsedTime(SoundHandle handle) = 0; /** * Check whether any channel of the given sound type is active. @@ -284,7 +272,7 @@ public: * @param type the sound type to look for * @return true if any channels of the specified type are active. */ - bool hasActiveChannelOfType(SoundType type); + virtual bool hasActiveChannelOfType(SoundType type) = 0; /** * Set the volume for the given sound type. @@ -292,7 +280,7 @@ public: * @param type the sound type * @param volume the new global volume, 0 - kMaxMixerVolume */ - void setVolumeForSoundType(SoundType type, int volume); + virtual void setVolumeForSoundType(SoundType type, int volume) = 0; /** * Query the global volume. @@ -300,7 +288,7 @@ public: * @param type the sound type * @return the global music volume, 0 - kMaxMixerVolume */ - int getVolumeForSoundType(SoundType type) const; + virtual int getVolumeForSoundType(SoundType type) const = 0; /** * Query the system's audio output sample rate. This returns @@ -308,26 +296,7 @@ public: * * @return the output sample rate in Hz */ - uint getOutputRate() const; - -protected: - void insertChannel(SoundHandle *handle, Channel *chan); - - /** - * Internal main method -- all the actual mixing work is done from here. - */ - void mix(int16 * buf, uint len); - - // FIXME: temporary "public" to allow access to mixCallback - // from within OSystem::makeMixer() -public: - /** - * The mixer callback function, passed on to OSystem::setSoundCallback(). - * This simply calls the mix() method. - */ - static void mixCallback(void *s, byte *samples, int len); - - void setReady(bool ready) { _mixerReady = ready; } + virtual uint getOutputRate() const = 0; }; diff --git a/sound/mixer_intern.h b/sound/mixer_intern.h new file mode 100644 index 0000000000..46ba97e66c --- /dev/null +++ b/sound/mixer_intern.h @@ -0,0 +1,154 @@ +/* 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_MIXER_INTERN_H +#define SOUND_MIXER_INTERN_H + +#include "common/scummsys.h" +#include "common/mutex.h" +#include "sound/mixer.h" + +namespace Audio { + +/** + * The (default) implementation of the ScummVM audio mixing subsystem. + * + * Backends are responsible for allocating (and later releasing) an instance + * of this class, which engines can access via OSystem::getMixer(). + * + * Initialisation of instances of this class usually happens as follows: + * 1) Creat a new Audio::MixerImpl instance. + * 2) Set the hardware output sample rate via the setSampleRate() method. + * 3) Hook up the mixCallback() in a suitable audio processing thread/callback. + * 4) Change the mixer into ready mode via setReady(true). + * 5) Start audio processing (e.g. by resuming the audio thread, if applicable). + * + * In the future, we might make it possible for backends to provide + * (partial) alternative implementations of the mixer, e.g. to make + * better use of native sound mixing support on low-end devices. + * + * @see OSystem::getMixer() + */ +class MixerImpl : public Mixer { +private: + enum { + NUM_CHANNELS = 16 + }; + + OSystem *_syst; + Common::Mutex _mutex; + + uint _sampleRate; + bool _mixerReady; + uint32 _handleSeed; + + int _volumeForSoundType[4]; + Channel *_channels[NUM_CHANNELS]; + + +public: + MixerImpl(OSystem *system); + ~MixerImpl(); + + virtual bool isReady() const { return _mixerReady; } + + virtual void playRaw( + SoundType type, + SoundHandle *handle, + void *sound, uint32 size, uint rate, byte flags, + int id = -1, byte volume = 255, int8 balance = 0, + uint32 loopStart = 0, uint32 loopEnd = 0); + + virtual void playInputStream( + SoundType type, + SoundHandle *handle, + AudioStream *input, + int id = -1, byte volume = 255, int8 balance = 0, + bool autofreeStream = true, + bool permanent = false, + bool reverseStereo = false); + + + + virtual void stopAll(); + virtual void stopID(int id); + virtual void stopHandle(SoundHandle handle); + + virtual void pauseAll(bool paused); + virtual void pauseID(int id, bool paused); + virtual void pauseHandle(SoundHandle handle, bool paused); + + virtual bool isSoundIDActive(int id); + virtual int getSoundID(SoundHandle handle); + + virtual bool isSoundHandleActive(SoundHandle handle); + + virtual void setChannelVolume(SoundHandle handle, byte volume); + virtual void setChannelBalance(SoundHandle handle, int8 balance); + + virtual uint32 getSoundElapsedTime(SoundHandle handle); + + virtual bool hasActiveChannelOfType(SoundType type); + + virtual void setVolumeForSoundType(SoundType type, int volume); + virtual int getVolumeForSoundType(SoundType type) const; + + virtual uint getOutputRate() const; + +protected: + void insertChannel(SoundHandle *handle, Channel *chan); + +public: + /** + * The mixer callback function, to be called at regular intervals by + * the backend (e.g. from an audio mixing thread). All the actual mixing + * work is done from here. + */ + void mixCallback(byte *samples, uint len); + + /** + * Set the internal 'is ready' flag of the mixer. + * Backends should invoke Mixer::setReady(true) once initialisation of + * their audio system has been completed (and in particular, *after* + * setOutputRate() has been called). + */ + void setReady(bool ready); + + /** + * Set the output sample rate. + * + * @param sampleRate the new output sample rate + * + * @note Right now, this can be done exactly ONCE. That is, the mixer + * currently does not support changing the output sample rate after it + * has been set for the first time. This may change in the future. + */ + void setOutputRate(uint sampleRate); +}; + + +} // End of namespace Audio + +#endif diff --git a/sound/mp3.cpp b/sound/mp3.cpp index eea725ce3a..70467bdb39 100644 --- a/sound/mp3.cpp +++ b/sound/mp3.cpp @@ -121,7 +121,7 @@ MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispos mad_timer_add(&length, start); mad_timer_negate(&length); - if (mad_timer_sign(end) == 0) { + if (mad_timer_sign(end) != 0) { mad_timer_add(&length, end); } else { mad_stream_init(&_stream); diff --git a/tools/create_lure/create_lure_dat.cpp b/tools/create_lure/create_lure_dat.cpp index 09744fef1f..9250104349 100644 --- a/tools/create_lure/create_lure_dat.cpp +++ b/tools/create_lure/create_lure_dat.cpp @@ -1312,14 +1312,14 @@ const char *englishTextStrings[NUM_TEXT_ENTRIES] = { const char *italianTextStrings[NUM_TEXT_ENTRIES] = { "Prendi", NULL, "Spingi", "Tira", "Aziona", "Apri", "Chiudi", "Blocca", - "Sblocca", "Usa", "Dai", "Parla con", "Ordina a", "Buy", "Guarda", "Osserva", - "Guarda tra", "Chiedi", NULL, "Bevi", "Stato", "Vai a", "Ritorna", + "Sblocca", "Usa", "Dai", "Parla con", "Ordina a", "Compra", "Guarda", "Osserva", + "Guarda attraverso", "Chiedi", NULL, "Bevi", "Stato", "Vai a", "Ritorna", "Corrompi", "Esamina", - "Inform", "Reavvia", "Salva gioco", "Ripristina", "Abbandona", "Testo lento\x8B", + "Crediti", "Ricomincia", "Salva gioco", "Ripristina", "Abbandona", "Testo lento\x8B", "Testo veloce\x8B", "Sonoro acceso", "Sonoro spento", "(niente)", " per ", " a ", " su ", "e poi", "finito", "Sei sicuro (s/n)?", - "Stai portando ", "niente", "e hai ", "soldi", "soldis", + "Stai portando ", "niente", "Hai ", "soldo", "soldi", NULL, "l' ", "la ", NULL, "le ", "i ", "il ", NULL, NULL, NULL }; diff --git a/tools/svnpropset.sh b/tools/svnpropset.sh new file mode 100755 index 0000000000..46acba534e --- /dev/null +++ b/tools/svnpropset.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# This script adds common svn properties to files + +if [ $# -eq 0 ]; then + echo "Usage: $0 [FILE]..." + exit 1 +fi + +for filename in $@; do + if [ -f $filename ]; then + svn propset svn:mime-type text/plain $filename + svn propset svn:keywords "Date Rev Author URL Id" $filename + svn propset svn:eol-style native $filename + elif [ -e $filename ]; then + echo "$0: error: '$filename' is not a regular file" + else + echo "$0: error: '$filename' does not exist" + fi +done |