diff options
139 files changed, 6342 insertions, 2096 deletions
@@ -25,7 +25,7 @@ CXXFLAGS:= -Wall $(CXXFLAGS) CXXFLAGS+= -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder # Enable even more warnings... CXXFLAGS+= -pedantic -Wpointer-arith -Wcast-qual -Wcast-align -CXXFLAGS+= -Wshadow -Wimplicit -Wundef -Wnon-virtual-dtor -Wwrite-strings +CXXFLAGS+= -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings # Disable RTTI and exceptions, and enabled checking of pointers returned by "new" CXXFLAGS+= -fno-rtti -fno-exceptions -fcheck-new @@ -3,19 +3,23 @@ For a more comprehensive changelog for the latest experimental SVN code, see: 0.12.0 (????-??-??) New Games: - - Added support for The Legend of Kyrandia: Book Two: Hand of Fate - - Added support for The Legend of Kyrandia: Book Three: Malcolm's Revenge - - Added support for Lost in Time - - Added support for The Bizarre Adventures of Woodruff and the Schnibble - - Added support for the PC version of Waxworks + - Added support for The Legend of Kyrandia: Book Two: Hand of Fate. + - Added support for The Legend of Kyrandia: Book Three: Malcolm's Revenge. + - Added support for Lost in Time. + - Added support for The Bizarre Adventures of Woodruff and the Schnibble. + - 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 + 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), + - Added audio double buffering to the SDL backend, which fixes the + problems with the MT-32 emulator on Mac OS X (for now only enabled + on Mac OS X). AGOS: - Fixed palette issues in Amiga versions of Simon the Sorcerer 1. diff --git a/backends/midi/quicktime.cpp b/backends/midi/quicktime.cpp index 568adf022b..a18eadcb30 100644 --- a/backends/midi/quicktime.cpp +++ b/backends/midi/quicktime.cpp @@ -132,8 +132,7 @@ bail: return MERR_DEVICE_NOT_AVAILABLE; } -void MidiDriver_QT::close() -{ +void MidiDriver_QT::close() { MidiDriver_MPU401::close(); dispose(); } @@ -248,8 +247,7 @@ void MidiDriver_QT::setPitchBendRange (byte channel, uint range) { NASetController(qtNoteAllocator, qtNoteChannel[channel], kControllerPitchBend, theBend); } -void MidiDriver_QT::dispose() -{ +void MidiDriver_QT::dispose() { for (int i = 0; i < 16; i++) { if (qtNoteChannel[i] != 0) NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]); diff --git a/backends/platform/dc/Makefile b/backends/platform/dc/Makefile index 5c01b20b27..db5861903b 100644 --- a/backends/platform/dc/Makefile +++ b/backends/platform/dc/Makefile @@ -33,8 +33,33 @@ 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 @@ -50,7 +75,7 @@ SCUMMVM.BIN : scummvm.bin plugin_dist : for p in plugins/*.plg; do \ - sh-elf-strip -g -o "`basename \"$$p\" | tr '[:lower:]' '[:upper:]'`" "$$p"; \ + sh-elf-strip -g -o "`basename \"$$p\" | LC_CTYPE=C tr '[:lower:]' '[:upper:]'`" "$$p"; \ done dist : SCUMMVM.BIN plugins plugin_dist 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 d2c3b579bd..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; diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h index e53575a4a5..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(); @@ -146,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/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2 index 22cd4eaa1b..204f4f7a16 100644 --- a/backends/platform/ps2/Makefile.ps2 +++ b/backends/platform/ps2/Makefile.ps2 @@ -19,16 +19,17 @@ RM = rm -f srcdir = ../../.. VPATH = $(srcdir) INCDIR = ../../../ +DEPDIR = .deps DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_MPEG2 -DUSE_ZLIB -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar # PS2SDK-Ports from ps2dev.org's SVN repository for libmad, zlib and ucl -PS2SDK_PORTS = /home/robby/libStuffNew/ps2sdk-ports +PS2SDK_PORTS = /mnt/winxp/scummvm/ports PS2SDK_PORTS_INCS = /ucl /zlib/include /libmad/ee/include PS2SDK_PORTS_LIBS = /ucl /zlib/lib /libmad/ee/lib # we also need SjPcm, Tremor and libmpeg2 -MORE_LIBS_DIR = /home/robby/libStuff +MORE_LIBS_DIR = /mnt/winxp/scummvm/ports MORE_LIBS_INCS = /SjPcm/ee/src /mpeg2dec/include /tremor MORE_LIBS_LIBS = /SjPcm/ee/lib /mpeg2dec/libmpeg2 /tremor/tremor diff --git a/backends/platform/ps2/fileio.cpp b/backends/platform/ps2/fileio.cpp index bc310a43f4..b7fa8d03f1 100644 --- a/backends/platform/ps2/fileio.cpp +++ b/backends/platform/ps2/fileio.cpp @@ -340,8 +340,6 @@ FILE *ps2_fopen(const char *fname, const char *mode) { assert(cacheListSema >= 0); } - //printf("ps2_fopen: %s, %s\n", fname, mode); - if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) { printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); return NULL; @@ -363,6 +361,8 @@ FILE *ps2_fopen(const char *fname, const char *mode) { } else { // Regular access to one of the devices + printf("ps2_fopen = %s\n", fname); // romeo : temp + if (!rdOnly) return NULL; // we only provide readaccess for cd,dvd,hdd,usb @@ -378,19 +378,22 @@ FILE *ps2_fopen(const char *fname, const char *mode) { } int64 cacheId = -1; - if (rdOnly && tocManager.haveEntries()) + if (tocManager.haveEntries()) cacheId = tocManager.fileExists(fname); if (cacheId != 0) { Ps2File *file = findInCache(cacheId); - if (file) + if (file) { + printf(" findInCache(%x)\n", cacheId); // romeo : temp return (FILE*)file; + } bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun"); file = new Ps2ReadFile(cacheId, isAudioFile); if (file->open(fname)) { openFileCount++; + printf(" new cacheID = %x\n", cacheId); // romeo : temp return (FILE*)file; } else delete file; @@ -579,7 +582,7 @@ void TocManager::readEntries(const char *root) { } char readPath[256]; sprintf(readPath, "%s/", _root); - printf("readDir: %s\n", readPath); + printf("readDir: %s (root: %s )\n", readPath, root); readDir(readPath, &_rootNode, 0); } @@ -587,28 +590,62 @@ void TocManager::readDir(const char *path, TocNode **node, int level) { if (level <= 2) { // we don't scan deeper than that iox_dirent_t dirent; int fd = fio.dopen(path); + TocNode *eNode = NULL; // = *node; // entry node + bool first = true; + + printf("path=%s - level=%d fd=%d\n", path, level, fd); // romeo : temp if (fd >= 0) { - while (fio.dread(fd, &dirent) > 0) - if (dirent.name[0] != '.') { // skip '.' and '..' + while (fio.dread(fd, &dirent) > 0) { + if (dirent.name[0] != '.') { // skip '.' & '..' - romeo : check + // --- do we have them on PS2? *node = new TocNode; + if (first) { + eNode = *node; + first = false; + } (*node)->sub = (*node)->next = NULL; - (*node)->nameLen = strlen(dirent.name); memcpy((*node)->name, dirent.name, (*node)->nameLen + 1); - if (dirent.stat.mode & FIO_S_IFDIR) { // directory + if (dirent.stat.mode & FIO_S_IFDIR) { (*node)->isDir = true; - char nextPath[256]; - sprintf(nextPath, "%s%s/", path, dirent.name); - readDir(nextPath, &((*node)->sub), level + 1); - } else + printf("dirent.name = %s [DIR]\n", dirent.name); + } + else { (*node)->isDir = false; + printf("dirent.name = %s\n", dirent.name); + } + node = &((*node)->next); } + } + fio.dclose(fd); - } else - printf("Can't open path: %s\n", path); + } + + TocNode *iNode = eNode; + char nextPath[256]; + + while (iNode) { + if (iNode->isDir == true) { + sprintf(nextPath, "%s%s/", path, iNode->name); + readDir(nextPath, &(iNode->sub), level + 1); + } + iNode = iNode->next; + } + } + + /* + ** Wizard of Oz' trick (to get all games running from USB on PS2): + + 1. Make a list of files / dirs in level #0 (dclose before continuing) + + 2. Go through the dirs : dopen / dread them / mark dirs / dclose + + It's a safe recursion, cause it recurses on 'isDir' nodes + after dclosing the higher hierarchy + */ } int64 TocManager::fileExists(const char *name) { diff --git a/backends/platform/ps2/iop/rpckbd/Makefile b/backends/platform/ps2/iop/rpckbd/Makefile new file mode 100644 index 0000000000..b25efa3660 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/Makefile @@ -0,0 +1,30 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ + + +IOP_OBJS_DIR = obj/ +IOP_BIN_DIR = bin/ +IOP_SRC_DIR = src/ +IOP_INC_DIR = include/ + +IOP_BIN=bin/rpckbd.irx +IOP_OBJS=obj/ps2kbd.o obj/imports.o + +IOP_CFLAGS=-Wall +IOP_INCS += -I$(PS2SDKSRC)/iop/usb/usbd/include + +all: $(IOP_OBJS_DIR) $(IOP_BIN_DIR) $(IOP_BIN) + +clean: + rm -f -r $(IOP_OBJS_DIR) $(IOP_BIN_DIR) + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/backends/platform/ps2/iop/rpckbd/include/ps2kbd.h b/backends/platform/ps2/iop/rpckbd/include/ps2kbd.h new file mode 100644 index 0000000000..f16c7ca12b --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/include/ps2kbd.h @@ -0,0 +1,90 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# USB Keyboard Driver for PS2 +*/ + +#ifndef __PS2KBD_H__ +#define __PS2KBD_H__ + +#define PS2KBD_RPC_ID 0xb0b0b80 + +#define PS2KBD_LED_NUMLOCK 1 +#define PS2KBD_LED_CAPSLOCK 2 +#define PS2KBD_LED_SCRLOCK 4 +#define PS2KBD_LED_COMPOSE 8 +#define PS2KBD_LED_KANA 16 + +#define PS2KBD_LED_MASK 0x1F; + +#define PS2KBD_ESCAPE_KEY 0x1B + +#define PS2KBD_LEFT_CTRL (1 << 0) +#define PS2KBD_LEFT_SHIFT (1 << 1) +#define PS2KBD_LEFT_ALT (1 << 2) +#define PS2KBD_LEFT_GUI (1 << 3) +#define PS2KBD_RIGHT_CTRL (1 << 4) +#define PS2KBD_RIGHT_SHIFT (1 << 5) +#define PS2KBD_RIGHT_ALT (1 << 6) +#define PS2KBD_RIGHT_GUI (1 << 7) + +#define PS2KBD_CTRL (PS2KBD_LEFT_CTRL | PS2KBD_RIGHT_CTRL) +#define PS2KBD_SHIFT (PS2KBD_LEFT_SHIFT | PS2KBD_RIGHT_SHIFT) +#define PS2KBD_ALT (PS2KBD_LEFT_ALT | PS2KBD_RIGHT_ALT) +#define PS2KBD_GUI (PS2KBD_LEFT_GUI | PS2KBD_RIGHT_GUI) + +#define PS2KBD_RAWKEY_UP 0xF0 +#define PS2KBD_RAWKEY_DOWN 0xF1 + +typedef struct _kbd_rawkey { + u8 state; + u8 key; +} kbd_rawkey __attribute__ ((packed)); + +#define PS2KBD_READMODE_NORMAL 1 +#define PS2KBD_READMODE_RAW 2 + +/* Notes on read mode */ +/* In normal readmode (default) read multiples of 1 character off the keyboard file. These are + processed by the keymaps so that you get back ASCII data */ +/* In raw readmode must read multiples of 2. First byte indicates state (i.e. Up or Down) + Second byte is the USB key code for that key. This table is presented in the USB HID Usage Tables manaual + from usb.org */ + +#define PS2KBD_KEYMAP_SIZE 256 + +typedef struct _kbd_keymap + +{ + u8 keymap[PS2KBD_KEYMAP_SIZE]; + u8 shiftkeymap[PS2KBD_KEYMAP_SIZE]; + u8 keycap[PS2KBD_KEYMAP_SIZE]; +} kbd_keymap; + + +/* IRPC function numbers */ +#define KBD_RPC_SETREADMODE 1 /* Sets up keymapped or raw mode */ +#define KBD_RPC_SETLEDS 2 /* Sets the LED state for ALL keyboards connected */ +#define KBD_RPC_SETREPEATRATE 3 /* Sets the repeat rate of the keyboard */ +#define KBD_RPC_SETKEYMAP 4 /* Sets the keymap for the standard keys, non shifted and shifted */ +#define KBD_RPC_SETCTRLMAP 5 /* Sets the control key mapping */ +#define KBD_RPC_SETALTMAP 6 /* Sets the alt key mapping */ +#define KBD_RPC_SETSPECIALMAP 7 /* Sets the special key mapping */ +#define KBD_RPC_FLUSHBUFFER 9 /* Flush the internal buffer, probably best after a keymap change */ +#define KBD_RPC_RESETKEYMAP 10 /* Reset keymaps to default states */ +#define KBD_RPC_READKEY 11 +#define KBD_RPC_READRAW 12 + +/* Note on keymaps. In normal keymap a 0 would indicate no key */ +/* Key maps are represented by 3 256*8bit tables. First table maps USB key to a char when not shifted */ +/* Second table maps USB key to a char when shifted */ +/* Third table contains boolean values. If 1 then the key is shifted/unshifted in capslock, else capslock is ignored */ + +#endif diff --git a/backends/platform/ps2/iop/rpckbd/src/imports.lst b/backends/platform/ps2/iop/rpckbd/src/imports.lst new file mode 100644 index 0000000000..41e13e6e73 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/imports.lst @@ -0,0 +1,58 @@ + +sysclib_IMPORTS_start +I_memset +I_strcmp +I_memcpy +sysclib_IMPORTS_end + +loadcore_IMPORTS_start +I_FlushDcache +loadcore_IMPORTS_end + +sifcmd_IMPORTS_start +I_sceSifInitRpc +I_sceSifSetRpcQueue +I_sceSifRegisterRpc +I_sceSifRpcLoop +sifcmd_IMPORTS_end + +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + +thsemap_IMPORTS_start +I_CreateSema +I_SignalSema +I_WaitSema +I_PollSema +I_DeleteSema +thsemap_IMPORTS_end + +thbase_IMPORTS_start +I_StartThread +I_CreateThread +I_USec2SysClock +I_iSetAlarm +I_SetAlarm +I_CancelAlarm +thbase_IMPORTS_end + +thevent_IMPORTS_start +I_WaitEventFlag +I_iSetEventFlag +I_CreateEventFlag +thevent_IMPORTS_end + +sysmem_IMPORTS_start +I_AllocSysMemory +I_FreeSysMemory +sysmem_IMPORTS_end + +usbd_IMPORTS_start +I_UsbGetDeviceStaticDescriptor +I_UsbOpenEndpoint +I_UsbSetDevicePrivateData +I_UsbTransfer +I_UsbRegisterDriver +usbd_IMPORTS_end + diff --git a/backends/platform/ps2/iop/rpckbd/src/irx_imports.h b/backends/platform/ps2/iop/rpckbd/src/irx_imports.h new file mode 100644 index 0000000000..6ecc8e5864 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/irx_imports.h @@ -0,0 +1,35 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org> +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include "irx.h" + +/* Please keep these in alphabetical order! */ +#include "dmacman.h" +#include "intrman.h" +#include "libsd.h" +#include "loadcore.h" +#include "sifcmd.h" +#include "stdio.h" +#include "sysclib.h" +#include "sysmem.h" +#include "thbase.h" +#include "thevent.h" +#include "thmsgbx.h" +#include "thsemap.h" +#include "usbd.h" +#include "vblank.h" + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/backends/platform/ps2/iop/rpckbd/src/ps2kbd.c b/backends/platform/ps2/iop/rpckbd/src/ps2kbd.c new file mode 100644 index 0000000000..f87a47f0cb --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/ps2kbd.c @@ -0,0 +1,1199 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2005, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# USB Keyboard Driver for PS2 +*/ + +#include "types.h" +#include "ioman.h" +#include "loadcore.h" +#include "stdio.h" +#include "sifcmd.h" +#include "sifrpc.h" +#include "sysclib.h" +#include "sysmem.h" +#include "usbd.h" +#include "usbd_macro.h" +#include "thbase.h" +#include "thevent.h" +#include "thsemap.h" + +#include "ps2kbd.h" +#include "us_keymap.h" + +#define PS2KBD_VERSION 0x100 + +#define USB_SUBCLASS_BOOT 1 +#define USB_HIDPROTO_KEYBOARD 1 + +#define PS2KBD_MAXDEV 2 +#define PS2KBD_MAXKEYS 6 + +#define PS2KBD_DEFLINELEN 4096 +#define PS2KBD_DEFREPEATRATE 100 +/* Default repeat rate in milliseconds */ +#define PS2KBD_REPEATWAIT 1000 +/* Number of milliseconds to wait before starting key repeat */ +#define USB_KEYB_NUMLOCK 0x53 +#define USB_KEYB_CAPSLOCK 0x39 +#define USB_KEYB_SCRLOCK 0x47 + +#define USB_KEYB_NUMPAD_START 0x54 +#define USB_KEYB_NUMPAD_END 0x63 + +#define SEMA_ZERO -419 +#define SEMA_DELETED -425 + +int ps2kbd_init(); +void ps2kbd_config_set(int resultCode, int bytes, void *arg); +void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg); +void ps2kbd_data_recv(int resultCode, int bytes, void *arg); +int ps2kbd_probe(int devId); +int ps2kbd_connect(int devId); +int ps2kbd_disconnect(int devId); +void usb_getstring(int endp, int index, char *desc); + +typedef struct _kbd_data_recv + +{ + u8 mod_keys; + u8 reserved; + u8 keycodes[PS2KBD_MAXKEYS]; +} kbd_data_recv; + +typedef struct _keyb_dev + +{ + int configEndp; + int dataEndp; + int packetSize; + int devId; + int interfaceNo; /* Holds the interface number selected on this device */ + char repeatkeys[2]; + u32 eventmask; + u8 ledStatus; /* Maintains state on the led status */ + kbd_data_recv oldData; + kbd_data_recv data; /* Holds the data for the transfers */ +} kbd_dev; + +/* Global Variables */ + +int kbd_readmode; +u32 kbd_repeatrate; +kbd_dev *devices[PS2KBD_MAXDEV]; /* Holds a list of current devices */ +int dev_count; +UsbDriver kbd_driver = { NULL, NULL, "PS2Kbd", ps2kbd_probe, ps2kbd_connect, ps2kbd_disconnect }; +u8 *lineBuffer; +u32 lineStartP, lineEndP; +int lineSema; +int bufferSema; +u32 lineSize; +u8 keymap[PS2KBD_KEYMAP_SIZE]; /* Normal key map */ +u8 shiftkeymap[PS2KBD_KEYMAP_SIZE]; /* Shifted key map */ +u8 keycap[PS2KBD_KEYMAP_SIZE]; /* Does this key get shifted by capslock ? */ +u8 special_keys[PS2KBD_KEYMAP_SIZE]; +u8 control_map[PS2KBD_KEYMAP_SIZE]; +u8 alt_map[PS2KBD_KEYMAP_SIZE]; +//static struct fileio_driver kbd_fdriver; +iop_device_t kbd_filedrv; +u8 keyModValue[8] = { 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7 }; +int repeat_tid; +int eventid; /* Id of the repeat event */ + +int _start () +{ + FlushDcache(); + + ps2kbd_init(); + + printf("PS2KBD - USB Keyboard Library\n"); + + return 0; + +} + +int ps2kbd_probe(int devId) + +{ + UsbDeviceDescriptor *dev; + UsbConfigDescriptor *conf; + UsbInterfaceDescriptor *intf; + UsbEndpointDescriptor *endp; + //UsbStringDescriptor *str; + + if(dev_count >= PS2KBD_MAXDEV) + { + printf("ERROR: Maximum keyboard devices reached\n"); + return 0; + } + + //printf("PS2Kbd_probe devId %d\n", devId); + + dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ + if(!dev) + { + printf("ERROR: Couldn't get device descriptor\n"); + return 0; + } + + //printf("Device class %d, Size %d, Man %d, Product %d Cpnfigurations %d\n", dev->bDeviceClass, dev->bMaxPacketSize0, dev->iManufacturer, dev->iProduct, dev->bNumConfigurations); + /* Check that the device class is specified in the interfaces and it has at least one configuration */ + if((dev->bDeviceClass != USB_CLASS_PER_INTERFACE) || (dev->bNumConfigurations < 1)) + { + //printf("This is not the droid you're looking for\n"); + return 0; + } + + conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); + if(!conf) + { + printf("ERROR: Couldn't get configuration descriptor\n"); + return 0; + } + //printf("Config Length %d Total %d Interfaces %d\n", conf->bLength, conf->wTotalLength, conf->bNumInterfaces); + + if((conf->bNumInterfaces < 1) || (conf->wTotalLength < (sizeof(UsbConfigDescriptor) + sizeof(UsbInterfaceDescriptor)))) + { + printf("ERROR: No interfaces available\n"); + return 0; + } + + intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ +/* printf("Interface Length %d Endpoints %d Class %d Sub %d Proto %d\n", intf->bLength, */ +/* intf->bNumEndpoints, intf->bInterfaceClass, intf->bInterfaceSubClass, */ +/* intf->bInterfaceProtocol); */ + + if((intf->bInterfaceClass != USB_CLASS_HID) || (intf->bInterfaceSubClass != USB_SUBCLASS_BOOT) || + (intf->bInterfaceProtocol != USB_HIDPROTO_KEYBOARD) || (intf->bNumEndpoints < 1)) + + { + //printf("We came, we saw, we told it to fuck off\n"); + return 0; + } + + endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); + endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ + + //printf("Endpoint 1 Addr %d, Attr %d, MaxPacket %d\n", endp->bEndpointAddress, endp->bmAttributes, endp->wMaxPacketSizeLB); + + if(((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) || + ((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)) + { + printf("ERROR: Endpoint not interrupt type and/or an input\n"); + return 0; + } + + printf("PS2KBD: Found a keyboard device\n"); + + return 1; +} + +int ps2kbd_connect(int devId) + +{ + /* Assume we can only get here if we have already checked the device is kosher */ + + UsbDeviceDescriptor *dev; + UsbConfigDescriptor *conf; + UsbInterfaceDescriptor *intf; + UsbEndpointDescriptor *endp; + kbd_dev *currDev; + int devLoop; + + //printf("PS2Kbd_connect devId %d\n", devId); + + dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ + if(!dev) + { + printf("ERROR: Couldn't get device descriptor\n"); + return 1; + } + + conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); + if(!conf) + { + printf("ERROR: Couldn't get configuration descriptor\n"); + return 1; + } + + intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ + endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); + endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ + + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if(devices[devLoop] == NULL) + { + break; + } + } + + if(devLoop == PS2KBD_MAXDEV) + { + /* How the f*** did we end up here ??? */ + printf("ERROR: Device Weirdness!!\n"); + return 1; + } + + currDev = (kbd_dev *) AllocSysMemory(0, sizeof(kbd_dev), NULL); + if(!currDev) + { + printf("ERROR: Couldn't allocate a device point for the kbd\n"); + return 1; + } + + devices[devLoop] = currDev; + memset(currDev, 0, sizeof(kbd_dev)); + currDev->configEndp = UsbOpenEndpoint(devId, NULL); + currDev->dataEndp = UsbOpenEndpoint(devId, endp); + currDev->packetSize = endp->wMaxPacketSizeLB | ((int) endp->wMaxPacketSizeHB << 8); + currDev->eventmask = (1 << devLoop); + if(currDev->packetSize > sizeof(kbd_data_recv)) + { + currDev->packetSize = sizeof(kbd_data_recv); + } + + if(dev->iManufacturer != 0) + { + usb_getstring(currDev->configEndp, dev->iManufacturer, "Keyboard Manufacturer"); + } + + if(dev->iProduct != 0) + { + usb_getstring(currDev->configEndp, dev->iProduct, "Keyboard Product"); + } + + currDev->devId = devId; + currDev->interfaceNo = intf->bInterfaceNumber; + currDev->ledStatus = 0; + + UsbSetDevicePrivateData(devId, currDev); /* Set the index for the device data */ + + //printf("Configuration value %d\n", conf->bConfigurationValue); + UsbSetDeviceConfiguration(currDev->configEndp, conf->bConfigurationValue, ps2kbd_config_set, currDev); + + dev_count++; /* Increment device count */ + printf("PS2KBD: Connected device\n"); + + return 0; +} + +int ps2kbd_disconnect(int devId) + +{ + int devLoop; + printf("PS2Kbd_disconnect devId %d\n", devId); + + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if((devices[devLoop]) && (devices[devLoop]->devId == devId)) + { + dev_count--; + FreeSysMemory(devices[devLoop]); + devices[devLoop] = NULL; + printf("PS2KBD: Disconnected device\n"); + break; + } + } + + return 0; +} + +typedef struct _string_descriptor + +{ + u8 buf[200]; + char *desc; +} string_descriptor; + +void ps2kbd_getstring_set(int resultCode, int bytes, void *arg) + +{ + UsbStringDescriptor *str = (UsbStringDescriptor *) arg; + string_descriptor *strBuf = (string_descriptor *) arg; + char string[50]; + int strLoop; + +/* printf("=========getstring=========\n"); */ + +/* printf("PS2KEYBOARD: GET_DESCRIPTOR res %d, bytes %d, arg %p\n", resultCode, bytes, arg); */ + + if(resultCode == USB_RC_OK) + { + memset(string, 0, 50); + for(strLoop = 0; strLoop < ((bytes - 2) / 2); strLoop++) + { + string[strLoop] = str->wData[strLoop] & 0xFF; + } + printf("%s: %s\n", strBuf->desc, string); + } + + FreeSysMemory(arg); +} + +void usb_getstring(int endp, int index, char *desc) + +{ + u8 *data; + string_descriptor *str; + int ret; + + data = (u8 *) AllocSysMemory(0, sizeof(string_descriptor), NULL); + str = (string_descriptor *) data; + + if(data != NULL) + { + str->desc = desc; + ret = UsbControlTransfer(endp, 0x80, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | index, + 0, sizeof(string_descriptor) - 4, data, ps2kbd_getstring_set, data); + if(ret != USB_RC_OK) + { + printf("PS2KBD: Error sending string descriptor request\n"); + FreeSysMemory(data); + } + } +} + +void ps2kbd_config_set(int resultCode, int bytes, void *arg) + /* Called when we have finished choosing our configuration */ + +{ + kbd_dev *dev; + + if(resultCode != USB_RC_OK) + { + printf("PS2KEYBOARD: Configuration set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + //printf("PS2KEYBOARD: Configuration set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + /* Do a interrupt data transfer */ + + dev = (kbd_dev *) arg; + if(dev != NULL) + { + int ret; + + ret = UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_IDLE, 0, dev->interfaceNo, 0, NULL, ps2kbd_idlemode_set, arg); + } +} + +void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg) + +{ + kbd_dev *dev; + + + + if(resultCode != USB_RC_OK) + { + printf("PS2KBD: Idlemode set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + dev = (kbd_dev *) arg; + if(dev != NULL) + { + int ret; + + ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); + } +} + +void ps2kbd_led_set(int resultCode, int bytes, void *arg) + +{ + //printf("LED Set\n"); +} + +void ps2kbd_build_uniquekeys(u8 *res, const u8 *new, const u8 *old) + + /* Builds a list of unique keys */ + +{ + int loopNew, loopOld; + int loopRes = 0; + int foundKey; + + for(loopNew = 0; loopNew < PS2KBD_MAXKEYS; loopNew++) + { + if(new[loopNew] != 0) + { + foundKey = 0; + for(loopOld = 0; loopOld < PS2KBD_MAXKEYS; loopOld++) + { + if(new[loopNew] == old[loopOld]) + { + foundKey = 1; + break; + } + } + if(!foundKey) + { + res[loopRes++] = new[loopNew]; + } + } + } +} + +u32 ps2kbd_repeathandler(void *arg) + +{ + kbd_dev *dev = arg; + iop_sys_clock_t t; + //printf("Repeat handler\n"); + + iSetEventFlag(eventid, dev->eventmask); + + USec2SysClock(kbd_repeatrate * 1000, &t); + iSetAlarm(&t, ps2kbd_repeathandler, arg); + + return t.hi; +} + +void ps2kbd_getkeys(u8 keyMods, u8 ledStatus, const u8 *keys, kbd_dev *dev) + +{ + int loopKey; + int tempPos = 0; + int byteCount = 0; + u8 currChars[2]; + + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + u8 currKey = keys[loopKey]; + + currChars[0] = 0; + currChars[1] = 0; + + if(lineEndP == (tempPos - 1)) + { + break; + } + + if(currKey) /* If this is a valid key */ + { + if((currKey >= USB_KEYB_NUMPAD_START) && (currKey <= USB_KEYB_NUMPAD_END)) + /* Handle numpad specially */ + { + if(ledStatus & PS2KBD_LED_NUMLOCK) + { + if(keymap[currKey]) + { + currChars[0] = keymap[currKey]; + } + } + else + { + if(special_keys[currKey]) + { + currChars[0] = PS2KBD_ESCAPE_KEY; + currChars[1] = special_keys[currKey]; + } + else if(keymap[currKey] != '5') /* Make sure this isnt a 5 key :) */ + { + currChars[0] = keymap[currKey]; + } + } + } + else if(special_keys[currKey]) /* This is a special key */ + { + currChars[0] = PS2KBD_ESCAPE_KEY; + currChars[1] = special_keys[currKey]; + } + else if(keyMods & PS2KBD_CTRL) /* CTRL */ + { + if(control_map[currKey]) + { + currChars[0] = control_map[currKey]; + } + } + else if(keyMods & PS2KBD_ALT) /* ALT */ + { + if(alt_map[currKey]) + { + currChars[0] = alt_map[currKey]; + } + } + else if(keyMods & PS2KBD_SHIFT) /* SHIFT */ + { + if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) + { + currChars[0] = keymap[currKey]; + } + else + { + currChars[0] = shiftkeymap[currKey]; + } + } + else /* Normal key */ + { + if(keymap[keys[loopKey]]) + { + if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) + { + currChars[0] = shiftkeymap[currKey]; + } + else + { + currChars[0] = keymap[currKey]; + } + } + } + } + + if((currChars[0] == PS2KBD_ESCAPE_KEY) && (currChars[1] != 0)) + { + if(lineEndP != (tempPos - 2)) + { + lineBuffer[lineEndP++] = currChars[0]; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = currChars[1]; + lineEndP %= lineSize; + byteCount += 2; + } + dev->repeatkeys[0] = currChars[0]; + dev->repeatkeys[1] = currChars[1]; + } + else if(currChars[0] != 0) + { + lineBuffer[lineEndP++] = currChars[0]; + lineEndP %= lineSize; + byteCount++; + dev->repeatkeys[0] = currChars[0]; + dev->repeatkeys[1] = 0; + } + } + + if(byteCount > 0) + { + iop_sys_clock_t t; + /* Set alarm to do repeat rate */ + //printf("repeatkeys %d %d\n", kbd_repeatkeys[0], kbd_repeatkeys[1]); + USec2SysClock(PS2KBD_REPEATWAIT * 1000, &t); + SetAlarm(&t, ps2kbd_repeathandler, dev); + } + + for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema to indicate data */ + { + SignalSema(bufferSema); + } + +/* lineBuffer[PS2KBD_DEFLINELEN - 1] = 0; */ +/* printf(lineBuffer); */ + //printf("lineStart %d, lineEnd %d\n", lineStartP, lineEndP); +} + + +void ps2kbd_getkeys_raw(u8 newKeyMods, u8 oldKeyMods, u8 *new, const u8 *old) + +{ + int loopKey; + u8 currKey; + u8 keyMods = newKeyMods ^ oldKeyMods; + u8 keyModsMap = newKeyMods & keyMods; + int tempPos = 0; + int byteCount = 0; + + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + for(loopKey = 0; loopKey < 8; loopKey++) + { + int currMod = (1 << loopKey); + if(keyMods & currMod) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + currKey = keyModValue[loopKey]; + + if(keyModsMap & currMod) /* If key pressed */ + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; + //printf("Key down\n"); + } + else + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; + //printf("Key up\n"); + } + + lineEndP %= lineSize; + lineBuffer[lineEndP++] = currKey; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key %d\n", currKey); + } + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + if(new[loopKey] != 0) + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = new[loopKey]; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key down\nKey %d\n", new[loopKey]); + } + + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + if(old[loopKey] != 0) + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = old[loopKey]; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key up\nKey %d\n", old[loopKey]); + } + + } + + for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema for the number of bytes read */ + { + SignalSema(bufferSema); + } +} + +void ps2kbd_data_recv(int resultCode, int bytes, void *arg) + +{ + kbd_dev *dev; + int ret; + int phantom; + int loop; + + if(resultCode != USB_RC_OK) + { + printf("PS2KEYBOARD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + //printf("PS2KBD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + + dev = (kbd_dev *) arg; + if(dev == NULL) + { + printf("PS2KBD: dev == NULL\n"); + return; + } + +/* printf("PS2KBD Modifiers %02X, Keys ", dev->data.mod_keys); */ +/* for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) */ +/* { */ +/* printf("%02X ", dev->data.keycodes[loop]); */ +/* } */ +/* printf("\n"); */ + + CancelAlarm(ps2kbd_repeathandler, dev); /* Make sure repeat alarm is cancelled */ + + /* Check for phantom states */ + phantom = 1; + for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) + { + if(dev->data.keycodes[loop] != 1) + { + phantom = 0; + break; + } + } + + if(!phantom) /* If not in a phantom state */ + { + u8 uniqueKeys[PS2KBD_MAXKEYS]; + u8 missingKeys[PS2KBD_MAXKEYS]; + int loopKey; + + memset(uniqueKeys, 0, PS2KBD_MAXKEYS); + memset(missingKeys, 0, PS2KBD_MAXKEYS); + ps2kbd_build_uniquekeys(uniqueKeys, dev->data.keycodes, dev->oldData.keycodes); + ps2kbd_build_uniquekeys(missingKeys, dev->oldData.keycodes, dev->data.keycodes); + /* Build new and missing key lists */ + +/* printf("Unique keys : "); */ +/* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ +/* { */ +/* printf("%02X ", uniqueKeys[loopKey]); */ +/* } */ +/* printf("\n"); */ + +/* printf("Missing keys : "); */ +/* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ +/* { */ +/* printf("%02X ", missingKeys[loopKey]); */ +/* } */ +/* printf("\n"); */ + + if(kbd_readmode == PS2KBD_READMODE_NORMAL) + { + u8 ledStatus; + + ledStatus = dev->ledStatus; + //printf("ledStatus %02X\n", ledStatus); + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) /* Process key codes */ + { + switch(uniqueKeys[loopKey]) + { + case USB_KEYB_NUMLOCK : + ledStatus ^= PS2KBD_LED_NUMLOCK; + uniqueKeys[loopKey] = 0; + break; + case USB_KEYB_CAPSLOCK : + ledStatus ^= PS2KBD_LED_CAPSLOCK; + uniqueKeys[loopKey] = 0; + break; + case USB_KEYB_SCRLOCK : + ledStatus ^= PS2KBD_LED_SCRLOCK; + uniqueKeys[loopKey] = 0; + break; + } + } + + if(ledStatus != dev->ledStatus) + { + dev->ledStatus = ledStatus & PS2KBD_LED_MASK; + //printf("LEDS %02X\n", dev->ledStatus); + /* Call Set LEDS */ + UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, + dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, arg); + } + + WaitSema(lineSema); /* Make sure no other thread is going to manipulate the buffer */ + ps2kbd_getkeys(dev->data.mod_keys, dev->ledStatus, uniqueKeys, dev); /* read in remaining keys */ + SignalSema(lineSema); + } + else /* RAW Mode */ + { + WaitSema(lineSema); + ps2kbd_getkeys_raw(dev->data.mod_keys, dev->oldData.mod_keys, uniqueKeys, missingKeys); + SignalSema(lineSema); + } + + memcpy(&dev->oldData, &dev->data, sizeof(kbd_data_recv)); + } + + ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); +} + +void flushbuffer() + +{ + iop_sema_t s; + + lineStartP = 0; + lineEndP = 0; + memset(lineBuffer, 0, lineSize); + + DeleteSema(bufferSema); + s.initial = 0; + s.max = lineSize; + s.option = 0; + s.attr = 0; + bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ + + if(bufferSema <= 0) + { + printf("Error creating buffer sema\n"); + } +} + +void ps2kbd_rpc_setreadmode(u32 readmode) + +{ + int devLoop; + + if(readmode == kbd_readmode) return; + + if((readmode == PS2KBD_READMODE_NORMAL) || (readmode == PS2KBD_READMODE_RAW)) + { + /* Reset line buffer */ + //printf("ioctl_setreadmode %d\n", readmode); + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + CancelAlarm(ps2kbd_repeathandler, devices[devLoop]); + } + + WaitSema(lineSema); + kbd_readmode = readmode; + flushbuffer(); + SignalSema(lineSema); + } +} + +void ps2kbd_rpc_setkeymap(kbd_keymap *keymaps) + +{ + //printf("ioctl_setkeymap %p\n", keymaps); + WaitSema(lineSema); /* Lock the input so you dont end up with weird results */ + memcpy(keymap, keymaps->keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, keymaps->shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, keymaps->keycap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setctrlmap(u8 *ctrlmap) + +{ + //printf("ioctl_setctrlmap %p\n", ctrlmap); + WaitSema(lineSema); + memcpy(control_map, ctrlmap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setaltmap(u8 *altmap) + +{ + //printf("ioctl_setaltmap %p\n", altmap); + WaitSema(lineSema); + memcpy(alt_map, altmap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setspecialmap(u8 *special) + +{ + //printf("ioctl_setspecialmap %p\n", special); + WaitSema(lineSema); + memcpy(special_keys, special, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_resetkeymap() + /* Reset keymap to default US variety */ + +{ + //printf("ioctl_resetkeymap()\n"); + WaitSema(lineSema); + memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); + memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); + memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); + memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_flushbuffer() + /* Flush the internal buffer */ + +{ + //printf("ioctl_flushbuffer()\n"); + WaitSema(lineSema); + flushbuffer(); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setleds(u8 ledStatus) + +{ + int devLoop; + kbd_dev *dev; + + //printf("ioctl_setleds %d\n", ledStatus); + ledStatus &= PS2KBD_LED_MASK; + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + dev = devices[devLoop]; + if(dev) + { + if(ledStatus != dev->ledStatus) + { + dev->ledStatus = ledStatus & PS2KBD_LED_MASK; + UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, + dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, dev); + } + } + } +} + +void ps2kbd_rpc_setrepeatrate(u32 rate) +{ + kbd_repeatrate = rate; +} + +int kbd_read(void *buf, int size) +{ + int count = 0; + char *data = (char *) buf; + + if(kbd_readmode == PS2KBD_READMODE_RAW) + size &= ~1; /* Ensure size of a multiple of 2 */ + + if (PollSema(bufferSema) >= 0) { + SignalSema(bufferSema); + if (WaitSema(lineSema) >= 0) { + while((count < size) && (lineStartP != lineEndP)) { + data[count] = lineBuffer[lineStartP++]; + lineStartP %= lineSize; + count++; + PollSema(bufferSema); /* Take off one count from the sema */ + } + SignalSema(lineSema); + } + } + return count; +} + +void repeat_thread(void *arg) + +{ + u32 eventmask; + int devLoop; + + for(;;) + { + WaitEventFlag(eventid, 0xFFFFFFFF, 0x01 | 0x10, &eventmask); + //printf("Recieved event %08X\n", eventmask); + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if((eventmask & (1 << devLoop)) && (devices[devLoop])) + { + int tempPos = 0; + + WaitSema(lineSema); + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + if((devices[devLoop]->repeatkeys[0]) && (devices[devLoop]->repeatkeys[1])) + { + if(lineEndP != (tempPos - 2)) + { + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[1]; + lineEndP %= lineSize; + SignalSema(bufferSema); + SignalSema(bufferSema); + } + } + else if(devices[devLoop]->repeatkeys[0]) + { + if(lineEndP != (tempPos - 1)) + { + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; + lineEndP %= lineSize; + SignalSema(bufferSema); + } + } + + SignalSema(lineSema); + } + } + } +} + +int init_repeatthread() + /* Creates a thread to handle key repeats */ +{ + iop_thread_t param; + iop_event_t event; + + event.attr = 0; + event.option = 0; + event.bits = 0; + eventid = CreateEventFlag(&event); + + param.attr = TH_C; + param.thread = repeat_thread; + param.priority = 40; + param.stacksize = 0x800; + param.option = 0; + + repeat_tid = CreateThread(¶m); + if (repeat_tid > 0) { + StartThread(repeat_tid, 0); + return 0; + } + else + { + return 1; + } +} + +static unsigned long retKey; + +void *ps2kbd_rpc_server(int fno, void *data, int size) { + retKey = 0; + switch (fno) { + case KBD_RPC_SETREADMODE: + ps2kbd_rpc_setreadmode(*(u32 *)data); + break; + case KBD_RPC_SETKEYMAP: + ps2kbd_rpc_setkeymap((kbd_keymap *) data); + break; + case KBD_RPC_SETALTMAP: + ps2kbd_rpc_setaltmap((u8 *) data); + break; + case KBD_RPC_SETCTRLMAP: + ps2kbd_rpc_setctrlmap((u8 *) data); + break; + case KBD_RPC_SETSPECIALMAP: + ps2kbd_rpc_setspecialmap((u8 *) data); + break; + case KBD_RPC_FLUSHBUFFER: + ps2kbd_rpc_flushbuffer(); + break; + case KBD_RPC_SETLEDS: + ps2kbd_rpc_setleds(*(u8*) data); + break; + case KBD_RPC_RESETKEYMAP: + ps2kbd_rpc_resetkeymap(); + break; + case KBD_RPC_SETREPEATRATE: + ps2kbd_rpc_setrepeatrate(*(u32 *) data); + break; + case KBD_RPC_READRAW: + kbd_read(&retKey, 2); + return &retKey; + case KBD_RPC_READKEY: + kbd_read(&retKey, 1); + return &retKey; + default: + printf("Ps2Kbd: Unknown RPC command %d\n", fno); + break; + } + return NULL; +} + +struct t_SifRpcDataQueue qd; +struct t_SifRpcServerData sd0; +void *rpcRcvBuf; + +void ps2kbd_start_rpc(unsigned long tid) { + rpcRcvBuf = AllocSysMemory(0, 3 * PS2KBD_KEYMAP_SIZE, NULL); + printf("Ps2Kbd: starting RPC server\n"); + SifInitRpc(0); + + SifSetRpcQueue(&qd, tid); + SifRegisterRpc(&sd0, PS2KBD_RPC_ID, ps2kbd_rpc_server, rpcRcvBuf, 0, 0, &qd); + SifRpcLoop(&qd); +} + +int ps2kbd_init_rpc(void) { + struct _iop_thread param; + int th; + + param.attr = 0x02000000; + param.thread = (void*)ps2kbd_start_rpc; + param.priority = 40; + param.stacksize = 0x800; + param.option = 0; + + th = CreateThread(¶m); + + if (th > 0) { + StartThread(th, (void *)th); + return 0; + } else + return -1; +} + +int ps2kbd_init() { + int ret; + iop_sema_t s; + + s.initial = 1; + s.max = 1; + s.option = 0; + s.attr = 0; + lineSema = CreateSema(&s); + if(lineSema <= 0) + { + printf("Error creating sema\n"); + return 1; + } + + s.initial = 0; + s.max = PS2KBD_DEFLINELEN; + s.option = 0; + s.attr = 0; + bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ + if(bufferSema <= 0) + { + printf("Error creating buffer sema\n"); + return 1; + } + + lineBuffer = (u8 *) AllocSysMemory(0, PS2KBD_DEFLINELEN, NULL); + if(lineBuffer == NULL) + { + printf("Error allocating line buffer\n"); + return 1; + } + lineStartP = 0; + lineEndP = 0; + lineSize = PS2KBD_DEFLINELEN; + memset(lineBuffer, 0, PS2KBD_DEFLINELEN); + + memset(devices, 0, sizeof(kbd_dev *) * PS2KBD_MAXDEV); + dev_count = 0; + kbd_readmode = PS2KBD_READMODE_NORMAL; + kbd_repeatrate = PS2KBD_DEFREPEATRATE; + memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); + memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); + memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); + memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); + + ps2kbd_init_rpc(); + init_repeatthread(); + + ret = UsbRegisterDriver(&kbd_driver); + if(ret != USB_RC_OK) + { + printf("Error registering USB devices\n"); + return 1; + } + + printf("UsbRegisterDriver %d\n", ret); + + return 0; +} diff --git a/backends/platform/ps2/iop/rpckbd/src/us_keymap.h b/backends/platform/ps2/iop/rpckbd/src/us_keymap.h new file mode 100644 index 0000000000..57f0686cd3 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/us_keymap.h @@ -0,0 +1,1579 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# USB Keyboard Driver for PS2 +*/ + +#ifndef __US_KEYMAP_H__ +#define __US_KEYMAP_H__ + +/* Default US keymap */ + +u8 us_keymap[PS2KBD_KEYMAP_SIZE] = + { + 0, + 0, + 0, + 0, + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + 10, /* line feed */ + 0, /* Esc */ + 0x7,/* BS */ + 0x9, /* TAB */ + 0x20, + '-', + '=', + '[', + ']', + '\\', + '#', + ';', + '\'', + '`', + ',', + '.', + '/', + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + '/', // Keypad + '*', + '-', + '+', + 10, + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '.', + '\\', + 0, + 0, + '=', + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_shiftkeymap[PS2KBD_KEYMAP_SIZE] = + { + 0, + 0, + 0, + 0, + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '!', + '@', + '#', + '$', + '%', + '^', + '&', + '*', + '(', + ')', + 10, /* line feed */ + 0, /* Esc */ + 0x7,/* BS */ + 0x9, /* TAB */ + 0x20, + '_', + '+', + '{', + '}', + '|', + '~', + ':', + '"', + '~', + '<', + '>', + '?', + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + '/', // Keypad + '*', + '-', + '+', + 10, + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '.', + '\\', + 0, + 0, + '=', + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_keycap[PS2KBD_KEYMAP_SIZE] = + { + 0, + 0, + 0, + 0, + 1, //a + 1, //b + 1, //c + 1, //d + 1, //e + 1, //f + 1,//g + 1,//h + 1,//i + 1,//j + 1,//k + 1,//l + 1,//m + 1,//n + 1,//o + 1,//p + 1,//q + 1,//r + 1,//s + 1,//t + 1,//u + 1,//v + 1,//w + 1,//x + 1,//y + 1,//z + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* line feed */ + 0, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + 0, // Keypad + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_special_keys[PS2KBD_KEYMAP_SIZE] = { + + 0, + 0, + 0, + 0, + 0, //a + 0, //b + 0, //c + 0, //d + 0, //e + 0, //f + 0,//g + 0,//h + 0,//i + 0,//j + 0,//k + 0,//l + 0,//m + 0,//n + 0,//o + 0,//p + 0,//q + 0,//r + 0,//s + 0,//t + 0,//u + 0,//v + 0,//w + 0,//x + 0,//y + 0,//z + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* line feed */ + 0x1B, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 1, // F1 + 2, // F2 + 3, // F3 + 4, // F4 + 5, // F5 + 6, // F6 + 7, // F7 + 8, // F8 + 9, // F9 + 10, // F10 + 11, // F11 + 12, // F12 + 32, // PrintScr + 33, // Scroll Lock + 34, // Pause + 35, // Insert + 36, // Home + 37, // Pg Up + 38, // Delete + 39, // End + 40, // Pg Down + 41, // Right + 42, // Left + 43, // Down + 44, // Up + 0, // Numlock + 0, // Keypad / + 0, // Keypad * + 0, // Keypad - + 0, // Keypad + + 0, // Keypad Enter + 39, // Keypad 1/End + 43, // Keypad 2/Down + 40, // Keypad 3/PageDn + 42, // Keypad 4/Left + 0, // Keypad 5 + 41, // Keypad 6/Right + 36, // Keypad 7/Home + 44, // Keypad 8/Up + 37, // Keypad 9/PageUp + 35, // Keypad 0/Insert + 38, // Keypad ./Delete + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_control_map[PS2KBD_KEYMAP_SIZE] = { + + 0, + 0, + 0, + 0, + 1, //a + 2, //b + 3, //c + 4, //d + 5, //e + 6, //f + 7,//g + 8,//h + 9,//i + 10,//j + 11,//k + 12,//l + 13,//m + 14,//n + 15,//o + 16,//p + 17,//q + 18,//r + 19,//s + 20,//t + 21,//u + 22,//v + 23,//w + 24,//x + 25,//y + 26,//z + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* line feed */ + 0, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + 0, // Keypad + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +u8 us_alt_map[PS2KBD_KEYMAP_SIZE] = { + + 0, + 0, + 0, + 0, + 128, //a + 129, //b + 130, //c + 131, //d + 132, //e + 133, //f + 134,//g + 135,//h + 136,//i + 137,//j + 138,//k + 139,//l + 140,//m + 141,//n + 142,//o + 143,//p + 144,//q + 145,//r + 146,//s + 147,//t + 148,//u + 149,//v + 150,//w + 151,//x + 152,//y + 154,//z + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, /* line feed */ + 0, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + 0, // Keypad + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +#endif diff --git a/backends/platform/ps2/irxboot.cpp b/backends/platform/ps2/irxboot.cpp index 327e5bdc71..65d1e243eb 100644 --- a/backends/platform/ps2/irxboot.cpp +++ b/backends/platform/ps2/irxboot.cpp @@ -43,7 +43,7 @@ IrxFile irxFiles[] = { { "PADMAN", BIOS, NOTHING, NULL, 0 }, { "LIBSD", BIOS, NOTHING, NULL, 0 }, - { "IOMANX.IRX", SYSTEM | NOT_HOST, NOTHING, NULL, 0 }, // already loaded by ps2link + { "IOMANX.IRX", SYSTEM /*| NOT_HOST*/, NOTHING, NULL, 0 }, // already loaded by ps2link { "FILEXIO.IRX", SYSTEM, NOTHING, NULL, 0 }, { "CODYVDFS.IRX", SYSTEM, NOTHING, NULL, 0 }, { "SJPCM.IRX", SYSTEM, NOTHING, NULL, 0 }, diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 28ced7b345..d4dd9aedcf 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -54,9 +54,11 @@ #include "graphics/surface.h" #include "graphics/font.h" #include "backends/timer/default/default-timer.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "common/events.h" #include "backends/platform/ps2/ps2debug.h" +#include "backends/fs/ps2/ps2-fs-factory.h" + // asm("mfc0 %0, $9\n" : "=r"(tickStart)); extern void *_gp; @@ -309,7 +311,9 @@ OSystem_PS2::OSystem_PS2(const char *elfPath) { void OSystem_PS2::init(void) { sioprintf("Timer...\n"); _scummTimerManager = new DefaultTimerManager(); - _scummMixer = new Audio::Mixer(); + _scummMixer = new Audio::MixerImpl(this); + _scummMixer->setOutputRate(44100); + _scummMixer->setReady(true); initTimer(); sioprintf("Starting SavefileManager\n"); @@ -410,7 +414,8 @@ void OSystem_PS2::soundThread(void) { // we have to produce more samples, call sound mixer // the scratchpad at 0x70000000 is used as temporary soundbuffer //_scummSoundProc(_scummSoundParam, (uint8*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); - Audio::Mixer::mixCallback(_scummMixer, (byte*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); + // Audio::Mixer::mixCallback(_scummMixer, (byte*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); + _scummMixer->mixCallback((byte*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); // demux data into 2 buffers, L and R __asm__ ( @@ -534,10 +539,6 @@ Common::TimerManager *OSystem_PS2::getTimerManager() { return _scummTimerManager; } -int OSystem_PS2::getOutputSampleRate(void) const { - return 48000; -} - Audio::Mixer *OSystem_PS2::getMixer() { return _scummMixer; } @@ -546,6 +547,10 @@ Common::SaveFileManager *OSystem_PS2::getSavefileManager(void) { return _saveManager; } +FilesystemFactory *OSystem_PS2::getFilesystemFactory() { + return &Ps2FilesystemFactory::instance(); +} + void OSystem_PS2::setShakePos(int shakeOffset) { _screen->setShakePos(shakeOffset); } diff --git a/backends/platform/ps2/systemps2.h b/backends/platform/ps2/systemps2.h index 9dbe9be553..08975ab2c8 100644 --- a/backends/platform/ps2/systemps2.h +++ b/backends/platform/ps2/systemps2.h @@ -33,6 +33,7 @@ class DefaultTimerManager; class Gs2dScreen; class Ps2Input; class Ps2SaveFileManager; +// class Ps2FilesystemFactory; struct IrxReference; #define MAX_MUTEXES 16 @@ -48,7 +49,7 @@ namespace Common { }; namespace Audio { - class Mixer; + class MixerImpl; }; class OSystem_PS2 : public OSystem { @@ -87,7 +88,6 @@ public: virtual bool pollEvent(Common::Event &event); virtual Audio::Mixer *getMixer(); - virtual int getOutputSampleRate(void) const; virtual bool openCD(int drive); virtual bool pollCD(); @@ -112,6 +112,7 @@ public: virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); virtual Common::SaveFileManager *getSavefileManager(); + virtual FilesystemFactory *getFilesystemFactory(); virtual void getTimeAndDate(struct tm &t) const; @@ -133,7 +134,7 @@ private: void readRtcTime(void); DefaultTimerManager *_scummTimerManager; - Audio::Mixer *_scummMixer; + Audio::MixerImpl *_scummMixer; bool _mouseVisible; 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 2d18b4bfd6..6e9b5980d4 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -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::MixerImpl(this); _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,21 +621,29 @@ bool OSystem_PSP::setSoundCallback(SoundProc proc, void *param) { desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = samples; - desired.callback = proc; - desired.userdata = param; + desired.callback = mixCallback; + desired.userdata = this; + + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { - return false; + 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); } - // 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; -} - -int OSystem_PSP::getOutputSampleRate() const { - return _samplesPerSec; } void OSystem_PSP::quit() { diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 64514f6872..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,9 +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 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 290fe63663..76ac91c282 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -191,7 +191,7 @@ OSystem_SDL::OSystem_SDL() OSystem_SDL::~OSystem_SDL() { SDL_RemoveTimer(_timerID); - SDL_CloseAudio(); + closeMixer(); free(_dirtyChecksums); free(_currentPalette); @@ -199,7 +199,6 @@ OSystem_SDL::~OSystem_SDL() { free(_mouseData); delete _savefile; - delete _mixer; delete _timer; } @@ -306,7 +305,7 @@ void OSystem_SDL::quit() { SDL_ShowCursor(SDL_ENABLE); SDL_RemoveTimer(_timerID); - SDL_CloseAudio(); + closeMixer(); free(_dirtyChecksums); free(_currentPalette); @@ -314,7 +313,6 @@ void OSystem_SDL::quit() { free(_mouseData); delete _savefile; - delete _mixer; delete _timer; SDL_Quit(); @@ -389,14 +387,110 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) { #pragma mark --- Audio --- #pragma mark - +#ifdef MIXER_DOUBLE_BUFFERING + +void OSystem_SDL::mixerProducerThread() { + byte nextSoundBuffer; + + SDL_LockMutex(_soundMutex); + while (true) { + // Wait till we are allowed to produce data + SDL_CondWait(_soundCond, _soundMutex); + + if (_soundThreadShouldQuit) + break; + + // Generate samples and put them into the next buffer + nextSoundBuffer = _activeSoundBuf ^ 1; + _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize); + + // Swap buffers + _activeSoundBuf = nextSoundBuffer; + } + SDL_UnlockMutex(_soundMutex); +} + +int SDLCALL OSystem_SDL::mixerProducerThreadEntry(void *arg) { + OSystem_SDL *this_ = (OSystem_SDL *)arg; + assert(this_); + this_->mixerProducerThread(); + return 0; +} + + +void OSystem_SDL::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) { + _soundThreadIsRunning = false; + _soundThreadShouldQuit = false; + + // Create mutex and condition variable + _soundMutex = SDL_CreateMutex(); + _soundCond = SDL_CreateCond(); + + // Create two sound buffers + _activeSoundBuf = 0; + _soundBufSize = bufSize; + _soundBuffers[0] = (byte *)calloc(1, bufSize); + _soundBuffers[1] = (byte *)calloc(1, bufSize); + + _soundThreadIsRunning = true; + + // Finally start the thread + _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this); +} + +void OSystem_SDL::deinitThreadedMixer() { + // Kill thread?? _soundThread + + if (_soundThreadIsRunning) { + // Signal the producer thread to end, and wait for it to actually finish. + _soundThreadShouldQuit = true; + SDL_CondBroadcast(_soundCond); + SDL_WaitThread(_soundThread, NULL); + + // Kill the mutex & cond variables. + // Attention: AT this point, the mixer callback must not be running + // anymore, else we will crash! + SDL_DestroyMutex(_soundMutex); + SDL_DestroyCond(_soundCond); + + _soundThreadIsRunning = false; + + free(_soundBuffers[0]); + free(_soundBuffers[1]); + } +} + + +void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) { + OSystem_SDL *this_ = (OSystem_SDL *)arg; + assert(this_); + assert(this_->_mixer); + + assert((int)this_->_soundBufSize == len); + + // Lock mutex, to ensure our data is not overwritten by the producer thread + SDL_LockMutex(this_->_soundMutex); + + // Copy data from the current sound buffer + memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len); + + // Unlock mutex and wake up the produced thread + SDL_UnlockMutex(this_->_soundMutex); + SDL_CondSignal(this_->_soundCond); +} + +#else + void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) { OSystem_SDL *this_ = (OSystem_SDL *)sys; assert(this_); + assert(this_->_mixer); - if (this_->_mixer) - this_->_mixer->mixCallback(samples, len); + this_->_mixer->mixCallback(samples, len); } +#endif + void OSystem_SDL::setupMixer() { SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -443,10 +537,31 @@ void OSystem_SDL::setupMixer() { // Tell the mixer that we are ready and start the sound processing _mixer->setOutputRate(_samplesPerSec); _mixer->setReady(true); + +#ifdef MIXER_DOUBLE_BUFFERING + initThreadedMixer(_mixer, obtained.samples * 4); +#endif + + // start the sound system SDL_PauseAudio(0); } } +void OSystem_SDL::closeMixer() { + if (_mixer) + _mixer->setReady(false); + + SDL_CloseAudio(); + + delete _mixer; + _mixer = 0; + +#ifdef MIXER_DOUBLE_BUFFERING + deinitThreadedMixer(); +#endif + +} + Audio::Mixer *OSystem_SDL::getMixer() { assert(_mixer); return _mixer; diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 8a94a17b00..4ad588f5f5 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -51,6 +51,15 @@ namespace Common { #define USE_OSD 1 #endif +#if defined(MACOSX) +// On Mac OS X, we need to double buffer the audio buffer, else anything +// which produces sampled data with high latency (like the MT-32 emulator) +// will sound terribly. +// This could be enabled for more / most ports in the future, but needs some +// testing. +#define MIXER_DOUBLE_BUFFERING 1 +#endif + enum { GFX_NORMAL = 0, @@ -137,6 +146,8 @@ public: virtual void setupMixer(); static void mixCallback(void *s, byte *samples, int len); + virtual void closeMixer(); + virtual Audio::Mixer *getMixer(); // Poll CD status @@ -369,6 +380,23 @@ protected: */ MutexRef _graphicsMutex; +#ifdef MIXER_DOUBLE_BUFFERING + SDL_mutex *_soundMutex; + SDL_cond *_soundCond; + SDL_Thread *_soundThread; + bool _soundThreadIsRunning; + bool _soundThreadShouldQuit; + + byte _activeSoundBuf; + uint _soundBufSize; + byte *_soundBuffers[2]; + + void mixerProducerThread(); + static int SDLCALL mixerProducerThreadEntry(void *arg); + void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize); + void deinitThreadedMixer(); +#endif + Common::SaveFileManager *_savefile; Audio::MixerImpl *_mixer; @@ -377,7 +405,7 @@ protected: Common::TimerManager *_timer; - +protected: void addDirtyRgnAuto(const byte *buf); void makeChecksums(const byte *buf); diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl index 1e5e4dc0c8..5d85fc03a2 100644 --- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl +++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl @@ -226,28 +226,31 @@ $VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines"; # now one for each ready-for-release engine - + if (0) + { foreach (@WorkingEngines) { $VariationSets{'ALL'}{$_} = "$DefaultFeatures $_"; } # for scumm, we need to add 2 features: - $VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he"; - + #$VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he"; + } + # now one for each not-ready-for-release-or-testing engine - + if (0) + { 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"; + #$VariationSets{'ALL'}{'saga_mini'} = "saga"; # a smaller version of scumm without support for v7, v8 and HE games - $VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm"; + #$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"; diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index dfeb24d825..660b0c69ed 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -33,7 +33,7 @@ #include "gui/Actions.h" #include "gui/Key.h" #include "gui/message.h" - +#include "sound/mixer_intern.h" #include "..\..\sdl\main.cpp" #ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :( @@ -42,10 +42,22 @@ #define SAMPLES_PER_SEC 16000 #endif +#define KInputBufferLength 128 +// Symbian libc file functionality in order to provide shared file handles +struct TSymbianFileEntry { + RFile iFileHandle; + char iInputBuffer[KInputBufferLength]; + TInt iInputBufferLen; + TInt iInputPos; +}; + +#define FILE void ////////// extern "C" /////////////////////////////////////////////////// namespace Symbian { + + // Show a simple Symbian Info win with Msg & exit void FatalError(const char *msg) { TPtrC8 msgPtr((const TUint8 *)msg); @@ -246,9 +258,9 @@ void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len) if (!this_->_mixer) return; -#ifdef S60 +#if defined (S60) && !defined(S60V3) // If not stereo then we need to downmix - if (_channels != 2) { + if (this_->_mixer->_channels != 2) { this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2); int16 *bitmixDst = (int16 *)samples; @@ -443,15 +455,9 @@ void OSystem_SDL_Symbian::initZones() { } } -// Symbian libc file functionality in order to provide shared file handles -struct TSymbianFileEntry { - RFile iFileHandle; -}; - -#define FILE void - FILE* symbian_fopen(const char* name, const char* mode) { TSymbianFileEntry* fileEntry = new TSymbianFileEntry; + fileEntry->iInputPos = KErrNotFound; if (fileEntry != NULL) { TInt modeLen = strlen(mode); @@ -509,9 +515,71 @@ void symbian_fclose(FILE* handle) { } size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) { - TPtr8 pointer( (unsigned char*) ptr, size*numItems); + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); + TUint32 totsize = size*numItems; + TPtr8 pointer ( (unsigned char*) ptr, totsize); + + // Nothing cached and we want to load at least KInputBufferLength bytes + if(totsize >= KInputBufferLength) { + TUint32 totLength = 0; + if(entry->iInputPos != KErrNotFound) + { + TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer+entry->iInputPos, entry->iInputBufferLen - entry->iInputPos, KInputBufferLength); + pointer.Append(cacheBuffer); + entry->iInputPos = KErrNotFound; + totLength+=pointer.Length(); + pointer.Set(totLength+(unsigned char*) ptr, 0, totsize-totLength); + } - ((TSymbianFileEntry*)(handle))->iFileHandle.Read(pointer); + entry->iFileHandle.Read(pointer); + totLength+=pointer.Length(); + + pointer.Set((unsigned char*) ptr, totLength, totsize); + + } + else { + // Nothing in buffer + if(entry->iInputPos == KErrNotFound) { + TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, KInputBufferLength); + entry->iFileHandle.Read(cacheBuffer); + + if(cacheBuffer.Length() >= totsize) { + pointer.Copy(cacheBuffer.Left(totsize)); + entry->iInputPos = totsize; + entry->iInputBufferLen = cacheBuffer.Length(); + } + else { + pointer.Copy(cacheBuffer); + entry->iInputPos = KErrNotFound; + } + + } + else { + TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, entry->iInputBufferLen, KInputBufferLength); + + if(entry->iInputPos+totsize < entry->iInputBufferLen) { + pointer.Copy(cacheBuffer.Mid(entry->iInputPos, totsize)); + entry->iInputPos+=totsize; + } + else { + + pointer.Copy(cacheBuffer.Mid(entry->iInputPos, entry->iInputBufferLen-entry->iInputPos)); + cacheBuffer.SetLength(0); + entry->iFileHandle.Read(cacheBuffer); + + if(cacheBuffer.Length() >= totsize-pointer.Length()) { + TUint32 restSize = totsize-pointer.Length(); + pointer.Append(cacheBuffer.Left(restSize)); + entry->iInputPos = restSize; + entry->iInputBufferLen = cacheBuffer.Length(); + } + else { + pointer.Append(cacheBuffer); + entry->iInputPos = KErrNotFound; + } + } + } + } return pointer.Length()/size; } @@ -519,6 +587,7 @@ size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) { TPtrC8 pointer( (unsigned char*) ptr, size*numItems); + ((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound; if (((TSymbianFileEntry*)(handle))->iFileHandle.Write(pointer) == KErrNone) { return numItems; } @@ -528,12 +597,18 @@ size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handl bool symbian_feof(FILE* handle) { TInt pos = 0; - if (((TSymbianFileEntry*)(handle))->iFileHandle.Seek(ESeekCurrent, pos) == KErrNone) { + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); + + if (entry->iFileHandle.Seek(ESeekCurrent, pos) == KErrNone) { TInt size = 0; - if (((TSymbianFileEntry*)(handle))->iFileHandle.Size(size) == KErrNone) { - if (pos == size) + if (entry->iFileHandle.Size(size) == KErrNone) { + if(entry->iInputPos == KErrNotFound && pos == size) return true; + + if(entry->iInputPos != KErrNotFound && pos == size && entry->iInputPos == entry->iInputBufferLen) + return true; + return false; } } @@ -549,6 +624,7 @@ long int symbian_ftell(FILE* handle) { } int symbian_fseek(FILE* handle, long int offset, int whence) { + TSeek seekMode = ESeekStart; TInt pos = offset; @@ -564,6 +640,8 @@ int symbian_fseek(FILE* handle, long int offset, int whence) { break; } + + ((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound; return ((TSymbianFileEntry*)(handle))->iFileHandle.Seek(seekMode, pos); } 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/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp index 86d93dcb88..c760b1f7df 100644 --- a/backends/platform/wince/missing/missing.cpp +++ b/backends/platform/wince/missing/missing.cpp @@ -1,8 +1,34 @@ -/* MISSING.C - Implementation for standard and semi-standard C library calls missing in WinCE - environment. - by Vasyl Tsvirkunov -*/ +/* 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$ + * + */ + +/* Original code: + * Implementation for standard and semi-standard C library calls missing in WinCE + * environment. + * by Vasyl Tsvirkunov + */ + #include <windows.h> #include <tchar.h> @@ -17,19 +43,8 @@ #include "time.h" #include "dirent.h" -/* forward declaration */ - -#if _WIN32_WCE < 300 - -#define _STDAFX_H -#include "portdefs.h" - -#else - char *strdup(const char *strSource); -#endif - #ifdef __GNUC__ #define EXT_C extern "C" #else @@ -40,19 +55,27 @@ char *strdup(const char *strSource); void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { - size_t i; + // Perform binary search + size_t lo = 0; + size_t hi = nmemb; + while (lo < hi) { + size_t mid = (lo + hi) / 2; + const void *p = ((const char *)base) + mid * size; + int tmp = (*compar)(key, p); + if (tmp < 0) + hi = mid; + else if (tmp > 0) + lo = mid + 1; + else + return (void *)p; + } - for (i=0; i<nmemb; i++) - if (compar(key, (void*)((size_t)base + size * i)) == 0) - return (void*)((size_t)base + size * i); return NULL; } static WIN32_FIND_DATA wfd; -/* Very limited implementation of stat. Used by UI.C, MEMORY-P.C (latter is not critical) */ -int stat(const char *fname, struct stat *ss) -{ +int stat(const char *fname, struct stat *ss) { TCHAR fnameUnc[MAX_PATH+1]; HANDLE handle; int len; @@ -63,8 +86,7 @@ int stat(const char *fname, struct stat *ss) /* Special case (dummy on WinCE) */ len = strlen(fname); if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' && - (len == 2 || fname[len-3] == '\\')) - { + (len == 2 || fname[len-3] == '\\')) { /* That's everything implemented so far */ memset(ss, 0, sizeof(struct stat)); ss->st_size = 1024; @@ -74,6 +96,7 @@ int stat(const char *fname, struct stat *ss) MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH); handle = FindFirstFile(fnameUnc, &wfd); + FindClose(handle); if (handle == INVALID_HANDLE_VALUE) return -1; else @@ -83,20 +106,16 @@ int stat(const char *fname, struct stat *ss) ss->st_size = wfd.nFileSizeLow; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ss->st_mode |= S_IFDIR; - - FindClose(handle); } return 0; } char cwd[MAX_PATH+1] = ""; -EXT_C char *getcwd(char *buffer, int maxlen) -{ +EXT_C char *getcwd(char *buffer, int maxlen) { TCHAR fileUnc[MAX_PATH+1]; char* plast; - if (cwd[0] == 0) - { + if (cwd[0] == 0) { GetModuleFileName(NULL, fileUnc, MAX_PATH); WideCharToMultiByte(CP_ACP, 0, fileUnc, -1, cwd, MAX_PATH, NULL, NULL); plast = strrchr(cwd, '\\'); @@ -114,8 +133,7 @@ EXT_C char *getcwd(char *buffer, int maxlen) #ifdef __GNUC__ #undef GetCurrentDirectory #endif -EXT_C void GetCurrentDirectory(int len, char *buf) -{ +EXT_C void GetCurrentDirectory(int len, char *buf) { getcwd(buf,len); }; @@ -125,26 +143,22 @@ fully qualified paths refer to root folder rather than current folder (concept not implemented in CE). */ #undef fopen -EXT_C FILE *wce_fopen(const char* fname, const char* fmode) -{ +EXT_C FILE *wce_fopen(const char* fname, const char* fmode) { char fullname[MAX_PATH+1]; if (!fname || fname[0] == '\0') return NULL; - if (fname[0] != '\\' && fname[0] != '/') - { + if (fname[0] != '\\' && fname[0] != '/') { getcwd(fullname, MAX_PATH); strncat(fullname, "\\", MAX_PATH-strlen(fullname)-1); strncat(fullname, fname, MAX_PATH-strlen(fullname)-strlen(fname)); return fopen(fullname, fmode); - } - else + } else return fopen(fname, fmode); } /* Remove file by name */ -int remove(const char* path) -{ +int remove(const char* path) { TCHAR pathUnc[MAX_PATH+1]; MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); return !DeleteFile(pathUnc); @@ -158,14 +172,22 @@ int _access(const char *path, int mode) { WIN32_FIND_DATA ffd; HANDLE h=FindFirstFile(fname, &ffd); + FindClose(h); if (h == INVALID_HANDLE_VALUE) return -1; //Can't find file - FindClose(h); - if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) - return 0; //Always return success if target is directory and exists + if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { + // WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry + // hits for files that don't exist. Checking for the same fname twice + // seems to weed out those false positives. + HANDLE h=FindFirstFile(fname, &ffd); + FindClose(h); + if (h == INVALID_HANDLE_VALUE) + return -1; //Can't find file + return 0; //Always return success if target is directory and exists + } switch (mode) { case 00: //Check existence return 0; @@ -183,8 +205,7 @@ int _access(const char *path, int mode) { #ifndef __GNUC__ /* Limited dirent implementation. Used by UI.C and DEVICES.C */ -DIR* opendir(const char* fname) -{ +DIR* opendir(const char* fname) { DIR* pdir; char fnameMask[MAX_PATH+1]; TCHAR fnameUnc[MAX_PATH+1]; @@ -209,13 +230,10 @@ DIR* opendir(const char* fname) strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */ MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH); - if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) - { + if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) { free(pdir); return NULL; - } - else - { + } else { WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL); pdir->dd_dir.d_name = strdup(nameFound); @@ -224,34 +242,25 @@ DIR* opendir(const char* fname) return pdir; } -struct dirent* readdir(DIR* dir) -{ +struct dirent* readdir(DIR* dir) { char nameFound[MAX_PATH+1]; static struct dirent dummy; - if (dir->dd_stat == 0) - { + if (dir->dd_stat == 0) { dummy.d_name = "."; dummy.d_namlen = 1; dir->dd_stat ++; return &dummy; - } - else if (dir->dd_stat == 1) - { + } else if (dir->dd_stat == 1) { dummy.d_name = ".."; dummy.d_namlen = 2; dir->dd_stat ++; return &dummy; - } - else if (dir->dd_stat == 2) - { + } else if (dir->dd_stat == 2) { dir->dd_stat++; return &dir->dd_dir; - } - else - { - if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) - { + } else { + if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) { dir->dd_stat = -1; return NULL; } @@ -283,12 +292,6 @@ int closedir(DIR* dir) return 1; } -/* in our case unlink is the same as remove */ -int unlink(const char* path) -{ - return remove(path); -} - /* Make directory, Unix style */ void mkdir(char* dirname, int mode) { @@ -299,10 +302,8 @@ void mkdir(char* dirname, int mode) if (*path == '/') *path = '\\'; /* Run through the string and attempt creating all subdirs on the path */ - for (ptr = path+1; *ptr; ptr ++) - { - if (*ptr == '\\' || *ptr == '/') - { + for (ptr = path+1; *ptr; ptr ++) { + if (*ptr == '\\' || *ptr == '/') { *ptr = 0; MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); CreateDirectory(pathUnc, 0); @@ -313,373 +314,40 @@ void mkdir(char* dirname, int mode) CreateDirectory(pathUnc, 0); } -/* Used in DEVICES.C and UI.C for some purpose. Not critical in this port */ -int system(const char* path) { return 0; } - -#if 0 - -char *tmpnam(char *string) -{ - TCHAR pTemp[MAX_PATH+1]; - static char buffer[MAX_PATH+1]; - GetTempFileName(TEXT("."), TEXT("A8_"), 0, pTemp); - WideCharToMultiByte(CP_ACP, 0, pTemp, -1, buffer, MAX_PATH, NULL, NULL); - - if (string) - { - strcpy(string, buffer); - return string; - } - else - return buffer; -} - -FILE *tmpfile() -{ - TCHAR pTemp[MAX_PATH+1]; - if (!GetTempFileName(TEXT("."), TEXT("A8_"), 0, pTemp)) - return _wfopen(pTemp, TEXT("w+b")); - else - return 0; -} - -#endif - -void rewind(FILE *stream) -{ - fseek(stream, 0, SEEK_SET); -} - - -#if _WIN32_WCE < 300 - -int isalnum(int c) { - return ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9')); -} - -char *_strdup(const char *strSource) -#else char *strdup(const char *strSource) -#endif { char* buffer; - buffer = (char*)malloc(strlen(strSource)+1); + size_z len = strlen(strSource)+1; + buffer = (char*)malloc(len); if (buffer) - strcpy(buffer, strSource); + memcpy(buffer, strSource, len); return buffer; } -/* Very limited implementation of sys/time.h */ -void usleep(long usec) -{ - long msec = usec/1000; - if (msec <= 0) - Sleep(0); - else - Sleep(msec); -} - -/* This may provide for better sync mechanism */ -unsigned int clock() -{ - return GetTickCount(); -} - -/* And why do people use this? */ -#if _WIN32_WCE >= 300 -void abort() -{ - exit(1); -} -#endif - -/* -IMHO, no project should use this one, it is not portable at all. This implementation -at least allows some projects to work. -*/ -char* getenv(char* name) -{ - static char buffer[MAX_PATH+1]; - if (strcmp(name, "HOME") == 0 || strcmp(name, "HOMEDIR") == 0) - { - getcwd(buffer, MAX_PATH); - return buffer; - } - else - return ""; -} - -#if _WIN32_WCE < 300 || defined(_TEST_HPC_STDIO) - -void *calloc(size_t n, size_t s) { - void *result = malloc(n * s); - if (result) - memset(result, 0, n * s); - - return result; -} - -char *strpbrk(const char *s, const char *accept) { - int i; - - if (!s || !accept) - return NULL; - - for (i=0; i<strlen(s); i++) { - int j; - for (j=0; j<strlen(accept); j++) - if (s[i] == accept[j]) - return (char*)&s[i]; - } - - return NULL; -} - -#ifndef _TEST_HPC_STDIO - -int isdigit(int c) { - return (c >='0' && c <= '9'); -} - -int isprint(int c) { - return (c >= ' ' && c <= '~'); -} - -int isspace(int c) { - return (c == ' '); -} - -#endif - -#ifndef WIN32_PLATFORM_HPCPRO - - -int printf(const char *format, ...) { - // useless anyway :) - return 0; -} - -FILE *fopen(const char *path, const char *mode) { - TCHAR tempo[MAX_PATH]; - HANDLE result; - bool writeAccess = (mode[0] == 'W' || mode[0] == 'w'); - - MultiByteToWideChar(CP_ACP, 0, path, strlen(path) + 1, tempo, sizeof(tempo)); - - result = CreateFile(tempo, ( writeAccess ? GENERIC_WRITE : GENERIC_READ), 0, NULL, (writeAccess ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL); - if (result == INVALID_HANDLE_VALUE) - return NULL; - else - return (FILE*)result; -} - -FILE * _wfopen(const TCHAR *path, const TCHAR *mode) { - HANDLE result; - bool writeAccess = (mode[0] == 'W' || mode[0] == 'w'); - result = CreateFile(path, ( writeAccess ? GENERIC_WRITE : GENERIC_READ), 0, NULL, (writeAccess ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL); - if (result == INVALID_HANDLE_VALUE) - return NULL; - else - return (FILE*)result; -} - -FILE *_wfreopen(const TCHAR *path, const TCHAR *mode, FILE *stream) { - fclose(stream); - stream = _wfopen(path, mode); - return stream; -} - -int fclose(FILE *stream) { - CloseHandle((HANDLE)stream); - return 1; -} - -int fseek(FILE *stream, long offset, int whence) { - SetFilePointer((HANDLE)stream, offset, NULL, (whence == SEEK_CUR ? FILE_CURRENT : whence == SEEK_END ? FILE_END : FILE_BEGIN)); - return 0; -} - -long ftell(FILE *stream) { - return (SetFilePointer((HANDLE)stream, 0, NULL, FILE_CURRENT)); -} - -size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - DWORD sizeWritten; - - WriteFile((HANDLE)stream, ptr, size * nmemb, &sizeWritten, NULL); - - if (size != 0) - return sizeWritten / size; - else - return 0; -} - -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { - DWORD sizeRead; - - ReadFile((HANDLE)stream, ptr, size * nmemb, &sizeRead, NULL); - - if (size != 0) - return sizeRead / size; - else - return 0; -} - -int fgetc(FILE *stream) { - unsigned char c; - if (fread(&c, 1, 1, stream) != 1) - return -1; - else - return c; -} - -char *fgets(char *s, int size, FILE *stream) { - int i = 0; - char tempo[1]; - - memset(s, 0, size); - while (fread(tempo, 1, 1, stream)) { - //if (tempo[0] == '\r') - // break; - if (tempo[0] == '\r') - continue; - s[i++] = tempo[0]; - if (tempo[0] == '\n') - break; - if (i == size) - break; - } - if (!i) - return NULL; - else - return s; -} - -int feof(FILE *stream) { - DWORD fileSize; - DWORD filePos; - fileSize = GetFileSize((HANDLE)stream, NULL); - filePos = SetFilePointer((HANDLE)stream, 0, 0, FILE_CURRENT); - return (filePos == 0xFFFFFFFF || filePos > (fileSize - 1)); -} - -int ferror(FILE *stream) { - return 0; // FIXME ! -} - -int fprintf(FILE *stream, const char *format, ...) { - char buf[1024]; - va_list va; - - va_start(va, format); - vsnprintf(buf, 1024, format, va); - va_end(va); - - if (buf[strlen(buf) - 1] == '\n') { - int i = strlen(buf) - 1; - buf[i] = '\r'; - buf[i + 1] = '\n'; - buf[i + 2] = 0; - } - - return fwrite(buf, 1, strlen(buf), stream); -} - -FILE* _getstdfilex(int) { - return NULL; -} - -void clearerr(FILE *stream) { -} - -int fflush(FILE *stream) { - return 0; -} - -#endif - -int stricmp( const char *string1, const char *string2 ) { - char src[4096]; - char dest[4096]; - int i; - - for (i=0; i<strlen(string1); i++) - if (string1[i] >= 'A' && string1[i] <= 'Z') - src[i] = string1[i] + 32; - else - src[i] = string1[i]; - src[i] = 0; - - for (i=0; i<strlen(string2); i++) - if (string2[i] >= 'A' && string2[i] <= 'Z') - dest[i] = string2[i] + 32; - else - dest[i] = string2[i]; - dest[i] = 0; - - return strcmp(src, dest); -} - -char *strrchr(const char *s, int c) { - int i; - - for (i = strlen(s) - 1; i > 0; i--) - if (s[i] == c) - return (char*)(s + i); - - return NULL; -} - -long int strtol(const char *nptr, char **endptr, int base) { - // not correct but that's all we are using - - long int result; - sscanf(nptr, "%ld", &result); - return result; -} - - -#endif - - // gcc build only functions follow #else // defined(__GNUC__) #ifndef __MINGW32CE__ -int islower(int c) -{ +int islower(int c) { return (c>='a' && c<='z'); } -int isspace(int c) -{ +int isspace(int c) { return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v'); } -int isalpha(int c) -{ - return (islower(c) || (c>='A' && c<='Z')); +int isalpha(int c) { + return ((c>='a' && c<='z') || (c>='A' && c<='Z')); } -int isalnum(int c) -{ - return (isalpha(c) || (c>='0' && c<='9')); -} - -int isprint(int c) -{ - static char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~"; - int i = 0, flag = 0; - while ((punct[i] != 0) && (flag = (punct[i] != c))) - i++; - return (isalnum(c) || flag); +int isalnum(int c) { + return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')); } -extern "C" int atexit(void (*function)(void)) -{ - return 0; +int isprint(int c) { + //static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~"; + //return (isalnum(c) || strchr(punct, c)); + return (32 <= c && c <= 126); // based on BSD manpage } #endif 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/base/game.cpp b/base/game.cpp index 9628543672..e65c891dc7 100644 --- a/base/game.cpp +++ b/base/game.cpp @@ -32,10 +32,10 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const Pla const PlainGameDescriptor *g = list; while (g->gameid) { if (0 == scumm_stricmp(gameid, g->gameid)) - break; + return g; g++; } - return g; + return 0; } void GameDescriptor::updateDesc(const char *extra) { diff --git a/base/game.h b/base/game.h index 18d7967388..b068c300ce 100644 --- a/base/game.h +++ b/base/game.h @@ -48,7 +48,7 @@ struct PlainGameDescriptor { /** * Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor * matching the given gameid. If not match is found return 0. - * The end of the list marked by a PlainGameDescriptor with gameid equal to 0. + * The end of the list must marked by a PlainGameDescriptor with gameid equal to 0. */ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list); diff --git a/base/internal_version.h b/base/internal_version.h index 069c20b4c9..c867532dd9 100644 --- a/base/internal_version.h +++ b/base/internal_version.h @@ -1 +1 @@ -#define SCUMMVM_VERSION "0.12.0svn" +#define SCUMMVM_VERSION "0.13.0svn" diff --git a/base/plugins.h b/base/plugins.h index 9d3ce97c3b..02116f6433 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -81,17 +81,11 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; #define STATIC_PLUGIN 1 #define DYNAMIC_PLUGIN 2 -// Note: The spaces around ENABLE_##ID have been added on purpose for -// MSVC. For some reason, MSVC tries to add the parenthesis after -// ENABLE_##ID to the check, thus making it false all the time. -// Please do NOT remove them, otherwise no engine plugins will be -// registered under MSVC - #define PLUGIN_ENABLED_STATIC(ID) \ - (defined( ENABLE_##ID ) && !PLUGIN_ENABLED_DYNAMIC(ID)) + (ENABLE_##ID && !PLUGIN_ENABLED_DYNAMIC(ID)) #define PLUGIN_ENABLED_DYNAMIC(ID) \ - (defined( ENABLE_##ID ) && (ENABLE_##ID == DYNAMIC_PLUGIN) && defined(DYNAMIC_MODULES)) + (ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && DYNAMIC_MODULES) /** * REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare diff --git a/common/config-manager.cpp b/common/config-manager.cpp index 5afbbad4ae..59855cf6c9 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -176,7 +176,6 @@ void ConfigManager::loadFile(const String &filename) { if (!cfg_file.open(filename)) { printf("Creating configuration file: %s\n", filename.c_str()); } else { - char buf[MAXLINELEN]; String domain; String comment; int lineno = 0; @@ -184,20 +183,28 @@ void ConfigManager::loadFile(const String &filename) { // TODO: Detect if a domain occurs multiple times (or likewise, if // a key occurs multiple times inside one domain). - while (!cfg_file.eof()) { + while (!cfg_file.eof() && !cfg_file.ioFailed()) { lineno++; - if (!cfg_file.readLine(buf, MAXLINELEN)) - break; - if (buf[0] == '#') { + // Read a line + String line; + while (line.lastChar() != '\n') { + char buf[MAXLINELEN]; + if (!cfg_file.readLine_NEW(buf, MAXLINELEN)) + break; + line += buf; + } + + if (line.size() == 0) { + // Do nothing + } else if (line[0] == '#') { // Accumulate comments here. Once we encounter either the start // of a new domain, or a key-value-pair, we associate the value // of the 'comment' variable with that entity. - comment += buf; - comment += '\n'; - } else if (buf[0] == '[') { + comment += line; + } else if (line[0] == '[') { // It's a new domain which begins here. - char *p = buf + 1; + const char *p = line.c_str() + 1; // Get the domain name, and check whether it's valid (that // is, verify that it only consists of alphanumerics, // dashes and underscores). @@ -209,8 +216,8 @@ void ConfigManager::loadFile(const String &filename) { error("Config file buggy: missing ] in line %d", lineno); break; case ']': - *p = 0; - domain = buf + 1; + domain = String(line.c_str() + 1, p - (line.c_str() + 1)); + //domain = String(line.c_str() + 1, p); // TODO: Pending Common::String changes break; default: error("Config file buggy: Invalid character '%c' occured in domain name in line %d", *p, lineno); @@ -226,10 +233,14 @@ void ConfigManager::loadFile(const String &filename) { _domainSaveOrder.push_back(domain); } else { - // Skip leading & trailing whitespaces - char *t = rtrim(ltrim(buf)); - - // Skip empty lines + // This line should be a line with a 'key=value' pair, or an empty one. + + // Skip leading whitespaces + const char *t = line.c_str(); + while (isspace(*t)) + t++; + + // Skip empty lines / lines with only whitespace if (*t == 0) continue; @@ -238,13 +249,30 @@ void ConfigManager::loadFile(const String &filename) { error("Config file buggy: Key/value pair found outside a domain in line %d", lineno); } - // Split string at '=' into 'key' and 'value'. - char *p = strchr(t, '='); + // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. + const char *p = strchr(t, '='); if (!p) error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); - *p = 0; - String key = rtrim(t); - String value = ltrim(p + 1); + + // Trim spaces before the '=' to obtain the key + const char *p2 = p; + while (p2 > t && isspace(*(p2-1))) + p2--; + String key(t, p2 - t); + + // Skip spaces after the '=' + t = p + 1; + while (isspace(*t)) + t++; + + // Trim trailing spaces + p2 = t + strlen(t); + while (p2 > t && isspace(*(p2-1))) + p2--; + + String value(t, p2 - t); + + // Finally, store the key/value pair in the active domain set(key, value, domain); // Store comment diff --git a/common/file.cpp b/common/file.cpp index 386777e2c5..a1ea1aff77 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -452,10 +452,12 @@ bool File::isOpen() const { } bool File::ioFailed() const { + // TODO/FIXME: Just use ferror() here? return _ioFailed != 0; } void File::clearIOFailed() { + // TODO/FIXME: Just use clearerr() here? _ioFailed = false; } diff --git a/common/str.cpp b/common/str.cpp index ad48ef6087..a2e6e0c66d 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -43,32 +43,43 @@ static int computeCapacity(int len) { return ((len + 32 - 1) & ~0x1F) - 1; } -String::String(const char *str, uint32 len) -: _len(0), _str(_storage) { +String::String(const char *str) : _len(0), _str(_storage) { + if (str == 0) { + _storage[0] = 0; + _len = 0; + } else + initWithCStr(str, strlen(str)); +} + +String::String(const char *str, uint32 len) : _len(0), _str(_storage) { + initWithCStr(str, len); +} + +String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) { + assert(endP >= beginP); + initWithCStr(beginP, endP - beginP); +} + +void String::initWithCStr(const char *str, uint32 len) { + assert(str); // Init _storage member explicitly (ie. without calling its constructor) // for GCC 2.95.x compatibility (see also tracker item #1602879). _storage[0] = 0; - if (str && *str) { - const uint32 tmp = strlen(str); - assert(len <= tmp); - if (len <= 0) - len = tmp; - _len = len; - - if (len >= _builtinCapacity) { - // Not enough internal storage, so allocate more - _extern._capacity = computeCapacity(len); - _extern._refCount = 0; - _str = (char *)malloc(_extern._capacity+1); - assert(_str != 0); - } - - // Copy the string into the storage area - memcpy(_str, str, len); - _str[len] = 0; + _len = len; + + if (len >= _builtinCapacity) { + // Not enough internal storage, so allocate more + _extern._capacity = computeCapacity(len); + _extern._refCount = 0; + _str = (char *)malloc(_extern._capacity+1); + assert(_str != 0); } + + // Copy the string into the storage area + memmove(_str, str, len); + _str[len] = 0; } String::String(const String &str) @@ -91,6 +102,8 @@ String::String(char c) _storage[0] = c; _storage[1] = 0; + // TODO/FIXME: There is no reason for the following check -- we *do* + // allow strings to contain 0 bytes! _len = (c == 0) ? 0 : 1; } @@ -130,11 +143,14 @@ String& String::operator =(const char *str) { uint32 len = strlen(str); ensureCapacity(len, false); _len = len; - memcpy(_str, str, len + 1); + memmove(_str, str, len + 1); return *this; } String &String::operator =(const String &str) { + if (&str == this) + return *this; + if (str.isStorageIntern()) { decRefCount(_extern._refCount); _len = str._len; diff --git a/common/str.h b/common/str.h index a92ec34fff..ae9cb992b6 100644 --- a/common/str.h +++ b/common/str.h @@ -96,10 +96,24 @@ public: static const char *emptyString; #endif + /** Construct a new empty string. */ String() : _len(0), _str(_storage) { _storage[0] = 0; } - String(const char *str, uint32 len = 0); + + /** Construct a new string from the given NULL-terminated C string. */ + String(const char *str); + + /** Construct a new string containing exactly len characters read from address str. */ + String(const char *str, uint32 len); + + /** Construct a new string containing the characters between beginP (including) and endP (excluding). */ + String(const char *beginP, const char *endP); + + /** Construct a copy of the given string. */ String(const String &str); + + /** Construct a string consisting of the given character. */ String(char c); + ~String(); String &operator =(const char *str); @@ -162,7 +176,7 @@ public: void toLowercase(); void toUppercase(); - + uint hash() const; public: @@ -189,6 +203,7 @@ protected: void ensureCapacity(uint32 new_len, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); + void initWithCStr(const char *str, uint32 len); }; // Append two strings to form a new (temp) string diff --git a/common/stream.cpp b/common/stream.cpp index ab9804d7b6..61166fd451 100644 --- a/common/stream.cpp +++ b/common/stream.cpp @@ -148,6 +148,61 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) { return buf; } +char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) { + assert(buf != 0 && bufSize > 1); + char *p = buf; + size_t len = 0; + char c = 0; + + // If end-of-file occurs before any characters are read, return NULL + // and the buffer contents remain unchanged. + if (eos() || ioFailed()) { + return 0; + } + + // Loop as long as the stream has not ended, there is still free + // space in the buffer, and the line has not ended + while (!eos() && len + 1 < bufSize && c != LF) { + c = readByte(); + + // If end-of-file occurs before any characters are read, return + // NULL and the buffer contents remain unchanged. If an error + /// occurs, return NULL and the buffer contents are indeterminate. + if (ioFailed() || (len == 0 && eos())) + return 0; + + // Check for CR or CR/LF + // * DOS and Windows use CRLF line breaks + // * Unix and OS X use LF line breaks + // * Macintosh before OS X used CR line breaks + if (c == CR) { + // Look at the next char -- is it LF? If not, seek back + c = readByte(); + if (c != LF && !eos()) + seek(-1, SEEK_CUR); + // Treat CR & CR/LF as plain LF + c = LF; + } + + *p++ = c; + len++; + } + + // FIXME: + // This should fix a bug while using readLine with Common::File + // it seems that it sets the eos flag after an invalid read + // and at the same time the ioFailed flag + // the config file parser fails out of that reason for the new themes + if (eos()) { + clearIOFailed(); + } + + // We always terminate the buffer if no error occured + *p = 0; + return buf; +} + + uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) { dataSize = MIN(dataSize, _end - _pos); diff --git a/common/stream.h b/common/stream.h index 313a695e82..4cf5fae114 100644 --- a/common/stream.h +++ b/common/stream.h @@ -304,13 +304,40 @@ public: * Read one line of text from a CR or CR/LF terminated plain text file. * This method is a rough analog of the (f)gets function. * + * @bug A main difference (and flaw) in this function is that there is no + * way to detect that a line exceeeds the length of the buffer. + * Code which needs this should use the new readLine_NEW() method instead. + * * @param buf the buffer to store into * @param bufSize the size of the buffer * @return a pointer to the read string, or NULL if an error occurred + * * @note The line terminator (CR or CR/LF) is stripped and not inserted * into the buffer. */ virtual char *readLine(char *buf, size_t bufSize); + + /** + * Reads at most one less than the number of characters specified + * by bufSize from the and stores them in the string buf. Reading + * stops when the end of a line is reached (CR, CR/LF or LF), at + * end-of-file or error. The newline, if any, is retained (CR and + * CR/LF are translated to LF = 0xA = '\n'). If any characters are + * read and there is no error, a `\0' character is appended to end + * the string. + * + * Upon successful completion, return a pointer to the string. If + * end-of-file occurs before any characters are read, returns NULL + * and the buffer contents remain unchanged. If an error occurs, + * returns NULL and the buffer contents are indeterminate. + * This method does not distinguish between end-of-file and error; + * callers muse use ioFailed() or eos() to determine which occurred. + * + * @param buf the buffer to store into + * @param bufSize the size of the buffer + * @return a pointer to the read string, or NULL if an error occurred + */ + virtual char *readLine_NEW(char *s, size_t bufSize); }; /** @@ -129,10 +129,10 @@ _srcdir=`dirname $0` if type mktemp > /dev/null 2>&1 ; then TMPO=`mktemp /tmp/scummvm-conf.XXXXXXXXXX` else - TMPO=${_srcdir}/scummvm-conf + TMPO=scummvm-conf fi TMPC=${TMPO}.cpp -TMPLOG=${_srcdir}/config.log +TMPLOG=config.log # For cross compiling _host="" @@ -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/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/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/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/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/redhat/scummvm.spec b/dists/redhat/scummvm.spec index efde789ce3..1d3b2bce64 100644 --- a/dists/redhat/scummvm.spec +++ b/dists/redhat/scummvm.spec @@ -7,7 +7,7 @@ # Prologue information #------------------------------------------------------------------------------ Name : scummvm -Version : 0.12.0svn +Version : 0.13.0svn Release : 1 Summary : Graphic adventure game interpreter Group : Interpreters diff --git a/dists/scummvm.rc b/dists/scummvm.rc index 73763a1216..0fb2b87071 100644 --- a/dists/scummvm.rc +++ b/dists/scummvm.rc @@ -7,8 +7,8 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico" #endif VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,12,0,0 - PRODUCTVERSION 0,12,0,0 + FILEVERSION 0,13,0,0 + PRODUCTVERSION 0,13,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -25,13 +25,13 @@ BEGIN BEGIN VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0" VALUE "FileDescription", "http://www.scummvm.org/\0" - VALUE "FileVersion", "0.12.0svn\0" + VALUE "FileVersion", "0.13.0svn\0" VALUE "InternalName", "scummvm\0" VALUE "LegalCopyright", "Copyright © 2001-2007 The ScummVM Team\0" VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0" VALUE "OriginalFilename", "scummvm.exe\0" VALUE "ProductName", "ScummVM\0" - VALUE "ProductVersion", "0.12.0svn\0" + VALUE "ProductVersion", "0.13.0svn\0" END END BLOCK "VarFileInfo" diff --git a/dists/slackware/scummvm.SlackBuild b/dists/slackware/scummvm.SlackBuild index 415ee4c867..6ed0ed6e57 100755 --- a/dists/slackware/scummvm.SlackBuild +++ b/dists/slackware/scummvm.SlackBuild @@ -8,7 +8,7 @@ if [ "$TMP" = "" ]; then fi PKG=$TMP/package-scummvm -VERSION=0.12.0svn +VERSION=0.13.0svn ARCH=i486 BUILD=1 diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 74a0b026e9..8ad5487b35 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -1075,6 +1075,8 @@ protected: virtual void drawImage(VC10_state *state); void drawBackGroundImage(VC10_state *state); void drawVertImage(VC10_state *state); + void drawVertImageCompressed(VC10_state *state); + void drawVertImageUncompressed(VC10_state *state); void setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height); diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index c014413bdc..9a3962ea21 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -744,10 +744,6 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { } void AGOSEngine::drawBackGroundImage(VC10_state *state) { - const byte *src; - byte *dst; - uint h, i; - state->width = _screenWidth; if (_window3Flag == 1) { state->width = 0; @@ -755,15 +751,19 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) { state->y_skip = 0; } - src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); - dst = state->surf_addr; + const byte* src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); + byte* dst = state->surf_addr; state->draw_width *= 2; - h = state->draw_height; + uint h = state->draw_height; + const uint w = state->draw_width; + const byte paletteMod = state->paletteMod; do { - for (i = 0; i != state->draw_width; i++) - dst[i] = src[i] + state->paletteMod; + for (uint i = 0; i != w; i+=2) { + dst[i] = src[i] + paletteMod; + dst[i+1] = src[i+1] + paletteMod; + } dst += state->surf_pitch; src += state->width; } while (--h); @@ -771,63 +771,86 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) { void AGOSEngine::drawVertImage(VC10_state *state) { if (state->flags & kDFCompressed) { - uint w, h; - byte *src, *dst, *dstPtr; + drawVertImageCompressed(state); + } else { + drawVertImageUncompressed(state); + } +} - state->x_skip *= 4; /* reached */ +void AGOSEngine::drawVertImageUncompressed(VC10_state *state) { + assert ((state->flags & kDFCompressed) == 0) ; - state->dl = state->width; - state->dh = state->height; + const byte *src; + byte *dst; + uint count; - vc10_skip_cols(state); + src = state->srcPtr + (state->width * state->y_skip) * 8; + dst = state->surf_addr; + state->x_skip *= 4; - dstPtr = state->surf_addr; - if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ - dstPtr += vcReadVar(252); - } - w = 0; - do { + do { + for (count = 0; count != state->draw_width; count++) { byte color; + color = (src[count + state->x_skip] / 16) + state->paletteMod; + if ((state->flags & kDFNonTrans) || color) + dst[count * 2] = color | state->palette; + color = (src[count + state->x_skip] & 15) + state->paletteMod; + if ((state->flags & kDFNonTrans) || color) + dst[count * 2 + 1] = color | state->palette; + } + dst += state->surf_pitch; + src += state->width * 8; + } while (--state->draw_height); +} - src = vc10_depackColumn(state); - dst = dstPtr; +void AGOSEngine::drawVertImageCompressed(VC10_state *state) { + assert (state->flags & kDFCompressed) ; + uint w, h; + + state->x_skip *= 4; /* reached */ - h = 0; + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + + byte *dstPtr = state->surf_addr; + if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ + dstPtr += vcReadVar(252); + } + w = 0; + do { + byte color; + + const byte *src = vc10_depackColumn(state); + byte *dst = dstPtr; + + h = 0; + if (state->flags & kDFNonTrans) { + do { + byte colors = *src; + color = (colors / 16); + dst[0] = color | state->palette; + color = (colors & 15); + dst[1] = color | state->palette; + dst += state->surf_pitch; + src++; + } while (++h != state->draw_height); + } else { do { - color = (*src / 16); - if ((state->flags & kDFNonTrans) || color != 0) + byte colors = *src; + color = (colors / 16); + if (color != 0) dst[0] = color | state->palette; - color = (*src & 15); - if ((state->flags & kDFNonTrans) || color != 0) + color = (colors & 15); + if (color != 0) dst[1] = color | state->palette; dst += state->surf_pitch; src++; } while (++h != state->draw_height); - dstPtr += 2; - } while (++w != state->draw_width); - } else { - const byte *src; - byte *dst; - uint count; - - src = state->srcPtr + (state->width * state->y_skip) * 8; - dst = state->surf_addr; - state->x_skip *= 4; - - do { - for (count = 0; count != state->draw_width; count++) { - byte color; - color = (src[count + state->x_skip] / 16) + state->paletteMod; - if ((state->flags & kDFNonTrans) || color) - dst[count * 2] = color | state->palette; - color = (src[count + state->x_skip] & 15) + state->paletteMod; - if ((state->flags & kDFNonTrans) || color) - dst[count * 2 + 1] = color | state->palette; - } - dst += state->surf_pitch; - src += state->width * 8; - } while (--state->draw_height); - } + } + dstPtr += 2; + } while (++w != state->draw_width); } void AGOSEngine::drawImage(VC10_state *state) { diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 710840c17e..06f2dfd982 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -94,6 +94,7 @@ public: Common::StringList _volumeResourceFiles; StringPtrHashMap _volumeEntriesMap; + TextHandler _textHandler; private: void initialize(void); @@ -107,6 +108,7 @@ private: extern CineEngine *g_cine; #define BOOT_PRC_NAME "AUTO00.PRC" +#define COPY_PROT_FAIL_PRC_NAME "L201.ANI" enum { VAR_MOUSE_X_MODE = 253, diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 47446f2410..1f868ccb75 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -337,7 +337,7 @@ int FWRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { idx = fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw(textTable[idx][0], textTable[idx][1], 16, 8, _backBuffer, x, y); + drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); x += width + 1; } @@ -938,7 +938,7 @@ int OSRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { idx = fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw2(textTable[idx][0], 0, 16, 8, _backBuffer, x, y); + drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); x += width + 1; } @@ -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/prc.cpp b/engines/cine/prc.cpp index 402c97b1a6..27b1044620 100644 --- a/engines/cine/prc.cpp +++ b/engines/cine/prc.cpp @@ -40,8 +40,9 @@ ScriptList objectScripts; /*! \todo Is script size of 0 valid? * \todo Fix script dump code + * @return Was the loading successful? */ -void loadPrc(const char *pPrcName) { +bool loadPrc(const char *pPrcName) { byte i; uint16 numScripts; byte *scriptPtr, *dataPtr; @@ -52,9 +53,9 @@ void loadPrc(const char *pPrcName) { scriptTable.clear(); // This is copy protection. Used to hang the machine - if (!scumm_stricmp(pPrcName, "L201.ANI")) { + if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) { exitEngine = 1; - return; + return false; } checkDataDisk(-1); @@ -107,6 +108,8 @@ void loadPrc(const char *pPrcName) { } } #endif + + return true; } } // End of namespace Cine diff --git a/engines/cine/prc.h b/engines/cine/prc.h index f5129d28b1..05bb240372 100644 --- a/engines/cine/prc.h +++ b/engines/cine/prc.h @@ -31,7 +31,7 @@ namespace Cine { extern ScriptList globalScripts; extern ScriptList objectScripts; -void loadPrc(const char *pPrcName); +bool loadPrc(const char *pPrcName); } // End of namespace Cine diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 148e673095..54a4976000 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1019,6 +1019,20 @@ int FWScript::o1_divVar() { } int FWScript::o1_compareVar() { + // WORKAROUND: A workaround for a script bug in script file CODE2.PRC + // in at least some of the Amiga and Atari ST versions of Future Wars. + // Fixes bug #2016647 (FW: crash with italian amiga version). A local + // variable 251 is compared against value 0 although it's quite apparent + // from the context in the script that instead global variable 251 should + // be compared against value 0. So looks like someone made a typo when + // making the scripts. Therefore we change that particular comparison + // from using the local variable 251 to using the global variable 251. + if (g_cine->getGameType() == Cine::GType_FW && scumm_stricmp(currentPrcName, "CODE2.PRC") == 0 && + (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) && + _script.getByte(_pos) == 251 && _script.getByte(_pos + 1) == 0 && _script.getWord(_pos + 2) == 0) { + return o1_compareGlobalVar(); + } + byte varIdx = getNextByte(); byte varType = getNextByte(); diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index 9b4b83f420..e4fd334926 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -31,8 +31,6 @@ namespace Cine { byte *textDataPtr; -byte textTable[256][2][16 * 8]; - const char **failureMessages; const CommandeType *defaultActionCommand; const CommandeType *systemMenu; @@ -77,14 +75,14 @@ void loadTextData(const char *pFileName, byte *pDestinationBuffer) { loadRelatedPalette(pFileName); for (i = 0; i < numCharacters; i++) { - gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 16, 8); - generateMask(textTable[i][0], textTable[i][1], 16 * 8, 0); + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 16, 8); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 16 * 8, 0); tempBuffer += dataSize; } } else { for (i = 0; i < 90; i++) { - gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 8, 8); - generateMask(textTable[i][0], textTable[i][1], 8 * 8, 0); + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 8, 8); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 8 * 8, 0); tempBuffer += 0x40; } } diff --git a/engines/cine/texte.h b/engines/cine/texte.h index ae82832aea..f471c3c49e 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -34,7 +34,10 @@ namespace Cine { typedef char CommandeType[20]; extern byte *textDataPtr; -extern byte textTable[256][2][16 * 8]; + +struct TextHandler { + byte textTable[256][2][16 * 8]; +}; extern const char **failureMessages; extern const CommandeType *defaultActionCommand; diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 4b5d4efe13..ab2fa645c7 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -466,17 +466,26 @@ bool CineEngine::makeLoad(char *saveName) { broken = brokenSave(*fHandle); + // At savefile position 0x0000: currentDisk = fHandle->readUint16BE(); + // At 0x0002: fHandle->read(currentPartName, 13); + // At 0x000F: fHandle->read(currentDatName, 13); + // At 0x001C: saveVar2 = fHandle->readSint16BE(); + // At 0x001E: fHandle->read(currentPrcName, 13); + // At 0x002B: fHandle->read(currentRelName, 13); + // At 0x0038: fHandle->read(currentMsgName, 13); + // At 0x0045: fHandle->read(bgName, 13); + // At 0x0052: fHandle->read(currentCtName, 13); checkDataDisk(currentDisk); @@ -501,52 +510,84 @@ bool CineEngine::makeLoad(char *saveName) { loadCtFW(currentCtName); } + // At 0x005F: fHandle->readUint16BE(); + // At 0x0061: fHandle->readUint16BE(); + // At 0x0063: for (i = 0; i < 255; i++) { + // At 0x0063 + i * 32 + 0: objectTable[i].x = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 2: objectTable[i].y = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 4: objectTable[i].mask = fHandle->readUint16BE(); + // At 0x0063 + i * 32 + 6: objectTable[i].frame = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 8: objectTable[i].costume = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 10: fHandle->read(objectTable[i].name, 20); + // At 0x0063 + i * 32 + 30: objectTable[i].part = fHandle->readUint16BE(); } + // At 0x2043 (i.e. 0x0063 + 255 * 32): renderer->restorePalette(*fHandle); + // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): globalVars.load(*fHandle, NUM_MAX_VAR - 1); + // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { + // At 0x2281 + i * 2: zoneData[i] = fHandle->readUint16BE(); } + // At 0x22A1 (i.e. 0x2281 + 16 * 2): for (i = 0; i < 4; i++) { + // At 0x22A1 + i * 2: commandVar3[i] = fHandle->readUint16BE(); } + // At 0x22A9 (i.e. 0x22A1 + 4 * 2): fHandle->read(commandBuffer, 0x50); renderer->setCommand(commandBuffer); + // At 0x22F9 (i.e. 0x22A9 + 0x50): renderer->_cmdY = fHandle->readUint16BE(); + // At 0x22FB: bgVar0 = fHandle->readUint16BE(); + // At 0x22FD: allowPlayerInput = fHandle->readUint16BE(); + // At 0x22FF: playerCommand = fHandle->readSint16BE(); + // At 0x2301: commandVar1 = fHandle->readSint16BE(); + // At 0x2303: isDrawCommandEnabled = fHandle->readUint16BE(); + // At 0x2305: var5 = fHandle->readUint16BE(); + // At 0x2307: var4 = fHandle->readUint16BE(); + // At 0x2309: var3 = fHandle->readUint16BE(); + // At 0x230B: var2 = fHandle->readUint16BE(); + // At 0x230D: commandVar2 = fHandle->readSint16BE(); + // At 0x230F: renderer->_messageBg = fHandle->readUint16BE(); + // At 0x2311: fHandle->readUint16BE(); + // At 0x2313: fHandle->readUint16BE(); + // At 0x2315: loadResourcesFromSave(*fHandle, broken); // TODO: handle screen params (really required ?) @@ -1518,12 +1559,22 @@ void mainLoopSub6(void) { void checkForPendingDataLoad(void) { if (newPrcName[0] != 0) { - loadPrc(newPrcName); + bool loadPrcOk = loadPrc(newPrcName); strcpy(currentPrcName, newPrcName); strcpy(newPrcName, ""); - addScriptToList0(1); + // Check that the loading of the script file was successful before + // trying to add script 1 from it to the global scripts list. This + // fixes a crash when failing copy protection in Amiga or Atari ST + // versions of Future Wars. + if (loadPrcOk) { + addScriptToList0(1); + } else if (scumm_stricmp(currentPrcName, COPY_PROT_FAIL_PRC_NAME)) { + // We only show an error here for other files than the file that + // is loaded if copy protection fails (i.e. L201.ANI). + warning("checkForPendingDataLoad: loadPrc(%s) failed", currentPrcName); + } } if (newRelName[0] != 0) { 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 9c39653a1d..df9c1353a0 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 e2b8d65112..865d188a2e 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 d8c33fcce6..2f1d2ec0be 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -880,9 +880,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; @@ -907,8 +913,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, @@ -1046,7 +1052,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 3d6a7942f9..b9373d48b3 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/detection.cpp b/engines/kyra/detection.cpp index f55cd1ac5e..fce1e93bc2 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -527,7 +527,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, { { @@ -542,7 +542,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, { { @@ -557,7 +557,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, // installed version @@ -574,7 +574,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -589,7 +589,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -604,7 +604,7 @@ 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" @@ -654,6 +654,52 @@ const KYRAGameDescription adGameDescs[] = { 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/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index b425c0929f..a4e5b58364 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; 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 d2e0f37a60..85c03dc1bb 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -114,7 +114,7 @@ int KyraEngine_v1::init() { _sound = new SoundTownsPC98_v2(this, _mixer); } else if (_flags.platform == Common::kPlatformPC98) { if (_flags.gameID == GI_KYRA1) - _sound = new SoundPC98(this, _mixer); + _sound = new SoundTowns/*SoundPC98*/(this, _mixer); else _sound = new SoundTownsPC98_v2(this, _mixer); } else if (midiDriver == MD_ADLIB) { @@ -247,8 +247,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) - ConfMan.registerDefault("subtitles", true); + 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/script.cpp b/engines/kyra/script.cpp index a29cdc8ca3..b10a4b32bf 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -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_tim.cpp b/engines/kyra/script_tim.cpp index 6b82ba06de..4b82232049 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -34,6 +34,7 @@ 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 } +#define cmd_return(n) cmd_return_##n static const CommandEntry commandProcs[] = { // 0x00 COMMAND(cmd_initFunc0), @@ -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/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index b30568c7e2..3a497a258f 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -1083,7 +1083,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_lok.cpp b/engines/kyra/sound_lok.cpp index 7d6e1dd378..b43d72ebce 100644 --- a/engines/kyra/sound_lok.cpp +++ b/engines/kyra/sound_lok.cpp @@ -49,20 +49,23 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) { } 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) + if (command == 1) { _sound->beginFadeOut(); - else if (command >= 2) - _sound->playTrack(command); - else + } 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 6be2cae7a4..0f2b916c9d 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -34,11 +34,6 @@ #include "common/util.h" -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif -#include <math.h> - #define EUPHONY_FADEOUT_TICKS 600 namespace Kyra { @@ -2368,7 +2363,7 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : _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; + _baserate = (double)getRate() / 10368.0; } TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { @@ -2657,7 +2652,7 @@ void TownsPC98_OpnDriver::generateTables() { delete [] _oprSinTbl; _oprSinTbl = new uint32[1024]; for (int i = 0; i < 1024; i++) { - double val = sin((double) (((i << 1) + 1) * M_PI / 1024.0)); + 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); @@ -3100,8 +3095,8 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() { } bool SoundTownsPC98_v2::init() { - _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? - TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); + _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 diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 5d094fa13f..c05795dacd 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1034,8 +1034,10 @@ void KyraEngine_LoK::initStaticResource() { } // audio data tables +#if 0 static const char *tIntro98[] = { "intro%d.dat" }; static const char *tIngame98[] = { "kyram%d.dat" }; +#endif static const AudioDataStruct soundData_PC[] = { { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, @@ -1049,18 +1051,20 @@ void KyraEngine_LoK::initStaticResource() { { 0, 0, 0, 0} }; +#if 0 static const AudioDataStruct soundData_PC98[] = { { tIntro98, 1, 0, 0 }, { tIngame98, 1, 0, 0 }, { 0, 0, 0, 0} }; +#endif 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; + _soundData = soundData_TOWNS/*soundData_PC98*/; } @@ -1259,9 +1263,11 @@ void KyraEngine_HoF::initStaticResource() { static const char *fmtMusicFileListFinale[] = { "finale%d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; +#if 0 static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; +#endif static const AudioDataStruct soundData_PC[] = { { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, @@ -1275,18 +1281,20 @@ void KyraEngine_HoF::initStaticResource() { { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } }; +#if 0 static const AudioDataStruct soundData_PC98[] = { { pc98MusicFileListIntro, 1, 0, 0 }, { pc98MusicFileListIngame, 1, 0, 0 }, { pc98MusicFileListFinale, 1, 0, 0 } }; +#endif 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; + _soundData = soundData_TOWNS/*soundData_PC98*/; // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); @@ -1976,12 +1984,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/lure/luredefs.h b/engines/lure/luredefs.h index 603102a099..922e1207d0 100644 --- a/engines/lure/luredefs.h +++ b/engines/lure/luredefs.h @@ -36,7 +36,7 @@ namespace Lure { #define LURE_DAT_MAJOR 1 #define LURE_DAT_MINOR 29 #define LURE_MIN_SAVEGAME_MINOR 25 -#define LURE_SAVEGAME_MINOR 32 +#define LURE_SAVEGAME_MINOR 33 #define LURE_DEBUG 1 diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp index de09f982d1..92cea948f9 100644 --- a/engines/lure/res_struct.cpp +++ b/engines/lure/res_struct.cpp @@ -456,6 +456,8 @@ void HotspotData::saveToStream(WriteStream *stream) { stream->writeSint16LE(startY); stream->writeUint16LE(roomNumber); stream->writeByte(layer); + stream->writeUint16LE(walkX); + stream->writeUint16LE(walkY); stream->writeUint16LE(width); stream->writeUint16LE(height); @@ -503,6 +505,10 @@ void HotspotData::loadFromStream(ReadStream *stream) { uint8 saveVersion = LureEngine::getReference().saveVersion(); if (saveVersion >= 29) layer = stream->readByte(); + if (saveVersion >= 33) { + walkX = stream->readUint16LE(); + walkY = stream->readUint16LE(); + } width = stream->readUint16LE(); height = stream->readUint16LE(); diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index a85fdea02f..5b8bdab9d6 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -380,7 +380,7 @@ void Converse::loadConversation(const char *convName) { uint32 size; uint32 chunk; uint32 data = 0; - uint32 i; + 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/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 3ecc7a9534..ed60a193ce 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; } @@ -424,6 +424,7 @@ void Parallaction_ns::_c_testResult(void *parm) { } _inTestResult = true; + _gfx->freeLabels(); _gfx->updateScreen(); _disk->selectArchive("disk1"); diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 3b6c35d3bb..290f8cfd4f 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -42,13 +42,23 @@ namespace Parallaction { #define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_Y 80 + class DialogueManager { + enum { + RUN_QUESTION, + RUN_ANSWER, + NEXT_QUESTION, + NEXT_ANSWER, + DIALOGUE_OVER + } _state; + Parallaction *_vm; - SpeakData *_data; Dialogue *_dialogue; bool _askPassword; + int _passwordLen; + bool _passwordChanged; bool isNpc; GfxObj *_questioner; @@ -59,98 +69,70 @@ class DialogueManager { uint16 _visAnswers[5]; int _numVisAnswers; + int _answerId; + + int _selection, _oldSelection; + + uint32 _mouseButtons; + Common::Point _mousePos; + bool _isKeyDown; + uint16 _downKey; + + public: - DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) { - _dialogue = _data->_dialogue; - isNpc = scumm_stricmp(_data->_name, "yourself") && _data->_name[0] != '\0'; - _questioner = isNpc ? _vm->_disk->loadTalk(_data->_name) : _vm->_char._talk; - _answerer = _vm->_char._talk; - } + DialogueManager(Parallaction *vm, ZonePtr z); + ~DialogueManager(); - ~DialogueManager() { - if (isNpc) { - delete _questioner; - } + bool isOver() { + return _state == DIALOGUE_OVER; } - void run(); + ZonePtr _z; + CommandList *_cmdList; + protected: - void displayQuestion(); + bool displayQuestion(); bool displayAnswers(); bool displayAnswer(uint16 i); - uint16 getAnswer(); - int16 selectAnswer(); - uint16 askPassword(); + int16 selectAnswer1(); + int16 selectAnswerN(); + int16 askPassword(); int16 getHoverAnswer(int16 x, int16 y); -}; - -uint16 DialogueManager::askPassword() { - debugC(3, kDebugExec, "checkDialoguePassword()"); - - uint16 passwordLen = 0; - _password[0] = '\0'; - - _vm->_gfx->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); - _vm->_gfx->setItemFrame(id, 0); - - Common::Event e; - bool changed = true; // force first refresh - - while (true) { - e.kbd.ascii = 0; - - if (g_system->getEventManager()->pollEvent(e)) { - if (e.type == Common::EVENT_QUIT) { - _engineFlags |= kEngineQuit; - break; - } - - if ((e.type == Common::EVENT_KEYDOWN) && isdigit(e.kbd.ascii)) { - _password[passwordLen] = e.kbd.ascii; - passwordLen++; - _password[passwordLen] = '\0'; - changed = true; - } - } - - if (changed) { - _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 3); - _vm->_gfx->updateScreen(); - changed = false; - } - - if ((passwordLen == MAX_PASSWORD_LENGTH) || (e.kbd.ascii == Common::KEYCODE_RETURN)) { + void runQuestion(); + void runAnswer(); + void nextQuestion(); + void nextAnswer(); - if ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) || - (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) || - (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))) { + bool checkPassword(); + void resetPassword(); + void accumPassword(uint16 ascii); +}; - break; +DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) { + _dialogue = _z->u.speak->_dialogue; + isNpc = scumm_stricmp(_z->u.speak->_name, "yourself") && _z->u.speak->_name[0] != '\0'; + _questioner = isNpc ? _vm->_disk->loadTalk(_z->u.speak->_name) : _vm->_char._talk; + _answerer = _vm->_char._talk; - } else { - passwordLen = 0; - _password[0] = '\0'; - changed = true; - } + _askPassword = false; + _q = _dialogue->_questions[0]; - } + _cmdList = 0; + _answerId = 0; - g_system->delayMillis(20); + _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER; +} +DialogueManager::~DialogueManager() { + if (isNpc) { + delete _questioner; } - - _vm->_gfx->hideDialogueStuff(); - - return 0; - + _z = nullZonePtr; } - - bool DialogueManager::displayAnswer(uint16 i) { Answer *a = _q->_answers[i]; @@ -162,11 +144,11 @@ 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; - _askPassword = (strstr(a->_text, "%p") != NULL); + _askPassword = (strstr(a->_text, "%P") != NULL); _numVisAnswers++; return true; @@ -183,134 +165,242 @@ bool DialogueManager::displayAnswers() { displayAnswer(i); } + if (_askPassword) { + resetPassword(); +// _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); + } else + if (_numVisAnswers == 1) { + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); + _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); + } else + if (_numVisAnswers > 1) { + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, _q->_answers[_visAnswers[0]]->_mood & 0xF); + _oldSelection = -1; + _selection = 0; + } + return _numVisAnswers > 0; } -void DialogueManager::displayQuestion() { - - if (!scumm_stricmp(_q->_text, "NULL")) return; +bool DialogueManager::displayQuestion() { + if (!scumm_stricmp(_q->_text, "NULL")) return false; - _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(); + return true; +} - return; + +bool DialogueManager::checkPassword() { + return ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) || + (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) || + (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))); } -uint16 DialogueManager::getAnswer() { +void DialogueManager::resetPassword() { + _passwordLen = 0; + _password[0] = '\0'; + _passwordChanged = true; +} - uint16 answer = 0; +void DialogueManager::accumPassword(uint16 ascii) { + if (!isdigit(ascii)) { + return; + } - if (_askPassword == false) { - answer = selectAnswer(); - } else { - answer = askPassword(); + _password[_passwordLen] = ascii; + _passwordLen++; + _password[_passwordLen] = '\0'; + _passwordChanged = true; +} + +int16 DialogueManager::askPassword() { + + if (_isKeyDown) { + accumPassword(_downKey); + } + + if (_passwordChanged) { + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); + _passwordChanged = false; } - debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer); + if ((_passwordLen == MAX_PASSWORD_LENGTH) || ((_isKeyDown) && (_downKey == Common::KEYCODE_RETURN))) { + if (checkPassword()) { + return 0; + } else { + resetPassword(); + } + } - return answer; + return -1; } -void DialogueManager::run() { +int16 DialogueManager::selectAnswer1() { - _askPassword = false; - CommandList *cmdlist = NULL; + if (_mouseButtons == kMouseLeftUp) { + return 0; + } - _q = _dialogue->_questions[0]; - int16 answer; + return -1; +} - while (_q) { +int16 DialogueManager::selectAnswerN() { - answer = 0; + _selection = _vm->_balloonMan->hitTestDialogueBalloon(_mousePos.x, _mousePos.y); - displayQuestion(); + if (_selection != _oldSelection) { + if (_oldSelection != -1) { + _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3); + } - if (_engineFlags & kEngineQuit) - return; + if (_selection != -1) { + _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0); + _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF); + } + } - if (_q->_answers[0] == NULL) break; + _oldSelection = _selection; - if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) { - if (!displayAnswers()) break; - answer = getAnswer(); + if ((_mouseButtons == kMouseLeftUp) && (_selection != -1)) { + return _visAnswers[_selection]; + } - if (_engineFlags & kEngineQuit) - return; + return -1; +} - cmdlist = &_q->_answers[answer]->_commands; - } +void DialogueManager::runQuestion() { + debugC(9, kDebugDialogue, "runQuestion\n"); + + if (_mouseButtons == kMouseLeftUp) { + _vm->hideDialogueStuff(); + _state = NEXT_ANSWER; + } + +} - _q = _q->_answers[answer]->_following._question; + +void DialogueManager::nextAnswer() { + debugC(9, kDebugDialogue, "nextAnswer\n"); + + if (_q->_answers[0] == NULL) { + _state = DIALOGUE_OVER; + return; } - if (cmdlist) - _vm->runCommands(*cmdlist); + if (!scumm_stricmp(_q->_answers[0]->_text, "NULL")) { + _answerId = 0; + _state = NEXT_QUESTION; + return; + } + _state = displayAnswers() ? RUN_ANSWER : DIALOGUE_OVER; } -int16 DialogueManager::selectAnswer() { +void DialogueManager::runAnswer() { + debugC(9, kDebugDialogue, "runAnswer\n"); - int16 numAvailableAnswers = _numVisAnswers; + if (_askPassword) { + _answerId = askPassword(); + } else + if (_numVisAnswers == 1) { + _answerId = selectAnswer1(); + } else { + _answerId = selectAnswerN(); + } - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); - _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); + if (_answerId != -1) { + _cmdList = &_q->_answers[_answerId]->_commands; + _vm->hideDialogueStuff(); + _state = NEXT_QUESTION; + } +} - if (numAvailableAnswers == 1) { - _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 0); - _vm->_input->waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); - return 0; +void DialogueManager::nextQuestion() { + debugC(9, kDebugDialogue, "nextQuestion\n"); + + _q = _q->_answers[_answerId]->_following._question; + if (_q == 0) { + _state = DIALOGUE_OVER; + } else { + _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER; } +} - int oldSelection = -1; - int selection = 0; - uint32 event; - Common::Point p; - while ((_engineFlags & kEngineQuit) == 0) { +void DialogueManager::run() { - _vm->_input->readInput(); - _vm->_input->getCursorPos(p); - event = _vm->_input->getLastButtonEvent(); - selection = _vm->_gfx->hitTestDialogueBalloon(p.x, p.y); + // cache event data + _mouseButtons = _vm->_input->getLastButtonEvent(); + _vm->_input->getCursorPos(_mousePos); + _isKeyDown = _vm->_input->getLastKeyDown(_downKey); - if (selection != oldSelection) { - if (oldSelection != -1) { - _vm->_gfx->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); - } + switch (_state) { + case RUN_QUESTION: + runQuestion(); + break; - if (selection != -1) { - _vm->_gfx->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); - _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF); - } - } + case NEXT_ANSWER: + nextAnswer(); + break; + + case NEXT_QUESTION: + nextQuestion(); + break; - if ((selection != -1) && (event == kMouseLeftUp)) { - break; + case RUN_ANSWER: + runAnswer(); + break; + + case DIALOGUE_OVER: + if (_cmdList) { + _vm->_cmdExec->run(*_cmdList); } + break; - _vm->_gfx->updateScreen(); - g_system->delayMillis(20); + default: + error("unknown state in DialogueManager"); - oldSelection = selection; } - _vm->_gfx->hideDialogueStuff(); +} - return _visAnswers[selection]; +void Parallaction::enterDialogueMode(ZonePtr z) { + debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u.speak->_name); + _dialogueMan = new DialogueManager(this, z); + _input->_inputMode = Input::kInputModeDialogue; } +void Parallaction::exitDialogueMode() { + debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()"); + _input->_inputMode = Input::kInputModeGame; -void Parallaction::runDialogue(SpeakData *data) { - debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name); + // The current instance of _dialogueMan must be destroyed before the zone commands + // are executed, because they may create another instance of _dialogueMan that + // overwrite the current one. This would cause headaches (and it did, actually). + ZonePtr z = _dialogueMan->_z; + delete _dialogueMan; + _dialogueMan = 0; - DialogueManager man(this, data); - man.run(); + _cmdExec->run(z->_commands, z); +} + +void Parallaction::runDialogueFrame() { + if (_input->_inputMode != Input::kInputModeDialogue) { + return; + } + + _dialogueMan->run(); + + if (_dialogueMan->isOver()) { + exitDialogueMode(); + } return; } diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 176f10aa10..694d4efa6d 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -61,7 +61,7 @@ public: virtual GfxObj* loadHead(const char* name) = 0; virtual Font* loadFont(const char* name) = 0; virtual GfxObj* loadStatic(const char* name) = 0; - virtual GfxObj* loadFrames(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; virtual Table* loadTable(const char* name) = 0; @@ -153,7 +153,7 @@ public: GfxObj* loadHead(const char* name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(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); Table* loadTable(const char* name); @@ -187,7 +187,7 @@ public: GfxObj* loadHead(const char* name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(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); Table* loadTable(const char* name); @@ -226,7 +226,7 @@ public: GfxObj* loadHead(const char* name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(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); Table* loadTable(const char* name); @@ -251,7 +251,7 @@ public: GfxObj* loadTalk(const char *name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(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 0159d9d406..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() { @@ -280,18 +280,21 @@ Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) { return sprites; } -GfxObj* DosDisk_br::loadFrames(const char* name) { +Frames* DosDisk_br::loadFrames(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); char path[PATH_LEN]; 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 new GfxObj(0, createSprites(stream), name); + return createSprites(stream); } // Slides in Nippon Safes are basically screen-sized pictures with valid @@ -600,13 +603,13 @@ Sprites* AmigaDisk_br::createSprites(const char *path) { return sprites; } -GfxObj* AmigaDisk_br::loadFrames(const char* name) { +Frames* AmigaDisk_br::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name); char path[PATH_LEN]; sprintf(path, "%s/anims/%s", _partPath, name); - return new GfxObj(0, createSprites(path)); + return createSprites(path); } GfxObj* AmigaDisk_br::loadTalk(const char *name) { diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index f45cf83f56..55e6fc5e77 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -490,8 +490,8 @@ GfxObj* DosDisk_ns::loadStatic(const char* name) { return new GfxObj(0, new SurfaceToFrames(cnv), name); } -GfxObj* DosDisk_ns::loadFrames(const char* name) { - return new GfxObj(0, loadCnv(name), name); +Frames* DosDisk_ns::loadFrames(const char* name) { + return loadCnv(name); } // @@ -1258,7 +1258,7 @@ void AmigaDisk_ns::loadSlide(BackgroundInfo& info, const char *name) { return; } -GfxObj* AmigaDisk_ns::loadFrames(const char* name) { +Frames* AmigaDisk_ns::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadFrames '%s'", name); Common::SeekableReadStream *s; @@ -1273,7 +1273,7 @@ GfxObj* AmigaDisk_ns::loadFrames(const char* name) { Cnv *cnv = makeCnv(*s); delete s; - return new GfxObj(0, cnv, name); + return cnv; } GfxObj* AmigaDisk_ns::loadHead(const char* name) { 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 348af2b731..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->hideLabel(_subtitle[0]); - _gfx->hideLabel(_subtitle[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 bd2d54c0a0..9cde27a853 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,154 +147,165 @@ 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; + if ((_ctxt.cmd->u._zone->_type & 0xFFFF) == kZoneSpeak) { + _vm->enterDialogueMode(_ctxt.cmd->u._zone); + } else { + _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 ); } @@ -302,16 +315,17 @@ DECLARE_COMMAND_OPCODE(quit) { 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; } void Parallaction_ns::drawAnimations() { + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); uint16 layer = 0; @@ -352,20 +366,20 @@ void Parallaction_ns::drawAnimations() { } } + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); + return; } -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; @@ -382,17 +396,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++; @@ -405,44 +418,49 @@ 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++) { - - CommandPtr cmd = *it; - uint32 v8 = getLocationFlags(); - if (_engineFlags & kEngineQuit) break; + CommandPtr cmd = *it; + 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"); @@ -451,6 +469,13 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) { } +CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) { + +} + +CommandExec_ns::~CommandExec_ns() { + +} // // ZONE TYPE: EXAMINE @@ -469,7 +494,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); @@ -477,7 +502,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); } @@ -518,16 +543,13 @@ uint16 Parallaction::runZone(ZonePtr z) { break; case kZoneSpeak: - runDialogue(z->u.speak); - if (_engineFlags & kEngineQuit) - return 0; - break; - + enterDialogueMode(z); + return 0; } debugC(3, kDebugExec, "runZone completed"); - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); return 0; } @@ -654,11 +676,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); @@ -680,25 +725,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 383f5d549c..e8250ac8fd 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,12 +86,14 @@ void GfxObj::clearFlags(uint32 flags) { } GfxObj* Gfx::loadAnim(const char *name) { - GfxObj *obj = _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->type = kGfxObjTypeAnim; obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; @@ -110,34 +112,43 @@ GfxObj* Gfx::loadGet(const char *name) { } GfxObj* Gfx::loadDoor(const char *name) { - GfxObj *obj = _disk->loadFrames(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->type = kGfxObjTypeDoor; obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; } -void Gfx::clearGfxObjects() { - _gfxobjList.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) { -// return; -// } - - assert(obj); + if (!obj) { + return; + } if (visible) { obj->setFlags(kGfxObjVisible); } else { obj->clearFlags(kGfxObjVisible); -// _gfxobjList.remove(obj); } - } @@ -181,8 +192,6 @@ 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(); @@ -258,9 +267,6 @@ void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte } -// 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) { diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 838827b19f..9b9ea8605a 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -33,6 +33,11 @@ namespace Parallaction { +// this is the size of the receiving buffer for unpacked frames, +// since BRA uses some insanely big animations. +#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401 + + void Gfx::registerVar(const Common::String &name, int32 initialValue) { if (_vars.contains(name)) { warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str()); @@ -64,10 +69,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 +239,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]; @@ -362,15 +332,13 @@ void Gfx::drawItems() { } 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(); } @@ -686,6 +654,7 @@ void Gfx::freeLabels() { delete _labels[i]; } _labels.clear(); + _floatingLabel = NO_FLOATING_LABEL; } void Gfx::drawLabels() { @@ -779,7 +748,6 @@ Gfx::Gfx(Parallaction* vm) : setPalette(_palette); - _numBalloons = 0; _numItems = 0; _floatingLabel = NO_FLOATING_LABEL; @@ -789,6 +757,9 @@ Gfx::Gfx(Parallaction* vm) : _halfbrite = false; _hbCircleRadius = 0; + _unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE]; + assert(_unpackedBitmap); + registerVar("background_mode", 1); _varBackgroundMode = 1; @@ -804,6 +775,9 @@ Gfx::Gfx(Parallaction* vm) : Gfx::~Gfx() { freeBackground(); + freeLabels(); + + delete []_unpackedBitmap; return; } @@ -830,138 +804,31 @@ void Gfx::setItemFrame(uint item, uint16 f) { _items[item].data->setFlags(kGfxObjVisible); } -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; +GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) { - 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; -} + GfxObj *obj = new GfxObj(kGfxObjTypeBalloon, frames, text); -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; -} - -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; -} - -int Gfx::hitTestDialogueBalloon(int x, int y) { - - Common::Point p; - - for (uint i = 0; i < _numBalloons; i++) { - p.x = x - _balloons[i].x; - p.y = y - _balloons[i].y; + obj->layer = LAYER_FOREGROUND; + obj->frame = 0; + obj->setFlags(kGfxObjVisible); - 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::freeBackground() { _backgroundInfo.free(); } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index df4cab4caf..a7242ba6f4 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -340,11 +340,15 @@ class Disk; enum { kGfxObjVisible = 1, + kGfxObjNormal = 2, + kGfxObjCharacter = 4, kGfxObjTypeDoor = 0, kGfxObjTypeGet = 1, kGfxObjTypeAnim = 2, - kGfxObjTypeLabel = 3 + kGfxObjTypeLabel = 3, + kGfxObjTypeBalloon = 4, + kGfxObjTypeCharacter = 8 }; enum { @@ -355,7 +359,6 @@ enum { class GfxObj { char *_name; Frames *_frames; - uint32 _flags; bool _keep; @@ -364,6 +367,7 @@ public: int32 z; + uint32 _flags; uint type; uint frame; @@ -449,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 { @@ -463,7 +481,7 @@ public: GfxObj* loadDoor(const char *name); void drawGfxObjects(Graphics::Surface &surf); void showGfxObj(GfxObj* obj, bool visible); - void clearGfxObjects(); + void clearGfxObjects(uint filter); void sortAnimations(); @@ -478,12 +496,9 @@ public: 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(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0); @@ -532,6 +547,8 @@ public: uint _screenX; // scrolling position uint _screenY; + byte *_unpackedBitmap; + protected: Parallaction* _vm; bool _halfbrite; @@ -549,18 +566,6 @@ protected: int32 getRenderMode(const char *type); public: - 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; struct Item { GfxObj *data; @@ -573,6 +578,7 @@ public: typedef Common::Array<GfxObj*> GfxObjArray; GfxObjArray _labels; + GfxObjArray _balloons; uint _floatingLabel; @@ -584,9 +590,6 @@ public: 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); diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 5551108693..0be070e345 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -195,7 +195,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/input.cpp b/engines/parallaction/input.cpp index e758bbd41c..9601ae3b36 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -42,12 +42,14 @@ uint16 Input::readInput() { uint16 KeyDown = 0; _mouseButtons = kMouseNone; + _lastKeyDownAscii = -1; Common::EventManager *eventMan = _vm->_system->getEventManager(); while (eventMan->pollEvent(e)) { switch (e.type) { case Common::EVENT_KEYDOWN: + _lastKeyDownAscii = e.kbd.ascii; if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd') _vm->_debugger->attach(); if (_vm->getFeatures() & GF_DEMO) break; @@ -97,6 +99,11 @@ uint16 Input::readInput() { } +bool Input::getLastKeyDown(uint16 &ascii) { + ascii = _lastKeyDownAscii; + return (_lastKeyDownAscii != -1); +} + // FIXME: see comment for readInput() void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { @@ -174,7 +181,7 @@ void Input::updateGameInput() { void Input::updateCommentInput() { waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); _vm->_gfx->setHalfbriteMode(false); _inputMode = kInputModeGame; @@ -192,11 +199,38 @@ InputData* Input::updateInput() { case kInputModeGame: updateGameInput(); break; + + case kInputModeDialogue: + readInput(); + break; } return &_inputData; } +void Input::trackMouse(ZonePtr z) { + if ((z != _hoverZone) && (_hoverZone)) { + stopHovering(); + return; + } + + if (!z) { + return; + } + + if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) { + _hoverZone = z; + _vm->_gfx->showFloatingLabel(_hoverZone->_label); + return; + } +} + +void Input::stopHovering() { + _hoverZone = nullZonePtr; + _vm->_gfx->hideFloatingLabel(); +} + + bool Input::translateGameInput() { if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) { @@ -231,23 +265,10 @@ bool Input::translateGameInput() { return true; } - if ((z != _hoverZone) && (_hoverZone)) { - _hoverZone = nullZonePtr; - _inputData._event = kEvExitZone; - return true; - } - - if (!z) { - _inputData._event = kEvNone; - return true; - } - - if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) { - _hoverZone = z; - _inputData._event = kEvEnterZone; - _inputData._label = z->_label; - return true; - } + trackMouse(z); + if (!z) { + return true; + } if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { @@ -302,7 +323,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 e06fe96705..f260352dba 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -66,6 +66,7 @@ class Input { Common::Point _mousePos; uint16 _mouseButtons; + int32 _lastKeyDownAscii; bool _mouseHidden; ZonePtr _hoverZone; @@ -73,7 +74,8 @@ class Input { public: enum { kInputModeGame = 0, - kInputModeComment = 1 + kInputModeComment = 1, + kInputModeDialogue = 2 }; @@ -99,14 +101,13 @@ public: uint16 readInput(); InputData* updateInput(); + void trackMouse(ZonePtr z); void waitUntilLeftClick(); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } + bool getLastKeyDown(uint16 &ascii); - void stopHovering() { - _hoverZone = nullZonePtr; - } - + void stopHovering(); }; } // namespace Parallaction 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 54afabc318..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,6 +183,8 @@ Zone::~Zone() { break; } + + free(_linkedName); } void Zone::getRect(Common::Rect& r) const { diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 5f5cfdb820..cd852f7c84 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -84,13 +84,15 @@ 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(); @@ -134,6 +136,8 @@ int Parallaction::init() { _debugger = new Debugger(this); + setupBalloonManager(); + return 0; } @@ -157,6 +161,11 @@ void Parallaction::updateView() { } +void Parallaction::hideDialogueStuff() { + _gfx->freeItems(); + _balloonMan->freeBalloons(); +} + void Parallaction::freeCharacter() { debugC(1, kDebugExec, "freeCharacter()"); @@ -164,6 +173,8 @@ void Parallaction::freeCharacter() { delete _objectsNames; _objectsNames = 0; + _gfx->clearGfxObjects(kGfxObjCharacter); + _char.free(); return; @@ -246,7 +257,7 @@ void Parallaction::freeLocation() { _location._walkNodes.clear(); - _gfx->clearGfxObjects(); + _gfx->clearGfxObjects(kGfxObjNormal); freeBackground(); _location._programs.clear(); @@ -281,23 +292,13 @@ 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); } void Parallaction::processInput(InputData *data) { switch (data->_event) { - case kEvEnterZone: - debugC(2, kDebugInput, "processInput: kEvEnterZone"); - _gfx->showFloatingLabel(data->_label); - break; - - case kEvExitZone: - debugC(2, kDebugInput, "processInput: kEvExitZone"); - _gfx->hideFloatingLabel(); - break; - case kEvAction: debugC(2, kDebugInput, "processInput: kEvAction"); _input->stopHovering(); @@ -308,7 +309,6 @@ void Parallaction::processInput(InputData *data) { case kEvOpenInventory: _input->stopHovering(); - _gfx->hideFloatingLabel(); if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { setArrowCursor(); } @@ -357,36 +357,43 @@ void Parallaction::processInput(InputData *data) { void Parallaction::runGame() { InputData *data = _input->updateInput(); - if (data->_event != kEvNone) { - processInput(data); - } - if (_engineFlags & kEngineQuit) return; - runPendingZones(); + if (_input->_inputMode == Input::kInputModeDialogue) { + runDialogueFrame(); + } else { + if (data->_event != kEvNone) { + processInput(data); + } - if (_engineFlags & kEngineQuit) - return; + if (_engineFlags & kEngineQuit) + return; - if (_engineFlags & kEngineChangeLocation) { - changeLocation(_location._name); - } + runPendingZones(); - if (_engineFlags & kEngineQuit) - return; + if (_engineFlags & kEngineQuit) + return; + + if (_engineFlags & kEngineChangeLocation) { + changeLocation(_location._name); + } + } _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(); } // change this to endFrame? updateView(); - } @@ -415,14 +422,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++) { @@ -493,6 +500,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"; @@ -503,6 +538,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; @@ -567,10 +605,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 { @@ -579,8 +621,6 @@ void Character::setName(const char *name) { _engineFlags |= kEngineTransformedDonna; _suffix = _suffixTras; end = s; - } else { - _suffix = _empty; } } if (IS_MINI_CHARACTER(name)) { @@ -616,9 +656,35 @@ void Parallaction::beep() { } void Parallaction::scheduleLocationSwitch(const char *location) { + debugC(9, kDebugExec, "scheduleLocationSwitch(%s)\n", location); strcpy(_location._name, location); _engineFlags |= kEngineChangeLocation; } + + + +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 b1a5995e28..c45d32b013 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" @@ -113,8 +114,6 @@ enum EngineFlags { enum { kEvNone = 0, - kEvEnterZone = 1, - kEvExitZone = 2, kEvAction = 3, kEvOpenInventory = 4, kEvCloseInventory = 5, @@ -164,6 +163,7 @@ class Debugger; class Gfx; class SoundMan; class Input; +class DialogueManager; struct Location { @@ -228,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 @@ -259,41 +260,20 @@ 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); uint16 runZone(ZonePtr z); void freeZones(); - void runDialogue(SpeakData*); - - void runCommands(CommandList& list, ZonePtr z = nullZonePtr); - AnimationPtr findAnimation(const char *name); void freeAnimations(); @@ -327,6 +307,8 @@ public: Gfx* _gfx; Disk* _disk; + CommandExec* _cmdExec; + ProgramExec* _programExec; Character _char; void setLocationFlags(uint32 flags); @@ -367,10 +349,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(); @@ -379,7 +359,7 @@ protected: // members void displayComment(ExamineData *data); - uint16 checkDoor(); + void checkDoor(const Common::Point &foot); void freeCharacter(); @@ -389,6 +369,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; @@ -398,12 +381,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; @@ -429,6 +412,16 @@ public: Inventory *_inventory; InventoryRenderer *_inventoryRenderer; + BalloonManager *_balloonMan; + + void setupBalloonManager(); + + void hideDialogueStuff(); + DialogueManager *_dialogueMan; + void enterDialogueMode(ZonePtr z); + void exitDialogueMode(); + void runDialogueFrame(); + }; @@ -524,7 +517,6 @@ private: void initResources(); void initCursors(); - void initParsers(); static byte _resMouseArrow[256]; byte *_mouseArrow; @@ -587,49 +579,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(); @@ -662,6 +617,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; @@ -689,8 +647,6 @@ private: void initResources(); void initFonts(); void freeFonts(); - void initOpcodes(); - void initParsers(); void setArrowCursor(); void setInventoryCursor(int pos); @@ -732,68 +688,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 b22e1b0f2d..9e2a0f10f1 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; @@ -205,13 +212,21 @@ void Parallaction_br::runPendingZones() { if (_activeZone) { z = _activeZone; // speak Zone or sound _activeZone = nullZonePtr; - runZone(z); // FIXME: BRA doesn't handle sound yet + if ((z->_type & 0xFFFF) == kZoneSpeak) { + enterDialogueMode(z); + } else { + runZone(z); // FIXME: BRA doesn't handle sound yet + } } if (_activeZone2) { z = _activeZone2; // speak Zone or sound _activeZone2 = nullZonePtr; - runZone(z); + if ((z->_type & 0xFFFF) == kZoneSpeak) { + enterDialogueMode(z); + } else { + runZone(z); // FIXME: BRA doesn't handle sound yet + } } } @@ -221,10 +236,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 +254,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 +305,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 af848aa6af..9e925d1e1d 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -135,12 +135,16 @@ 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; @@ -187,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->hideFloatingLabel(); + _input->stopHovering(); _input->_activeItem._id = 0; _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); @@ -298,14 +302,16 @@ void Parallaction_ns::changeLocation(char *location) { _soundMan->playLocationMusic(location); - _gfx->hideFloatingLabel(); + _input->stopHovering(); _gfx->freeLabels(); - _input->stopHovering(); + _zoneTrap = nullZonePtr; + if (_engineFlags & kEngineBlockInput) { setArrowCursor(); } + _gfx->showGfxObj(_char._ani->gfxobj, false); _location._animations.remove(_char._ani); freeLocation(); @@ -327,6 +333,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); @@ -351,11 +358,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); @@ -411,6 +418,8 @@ 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); + _char._ani->gfxobj->clearFlags(kGfxObjNormal); 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..a717b615e6 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,118 @@ 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); + targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected + } } - 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/graphics.cpp b/engines/queen/graphics.cpp index f863f7663c..6d0a11ccfe 100644 --- a/engines/queen/graphics.cpp +++ b/engines/queen/graphics.cpp @@ -1175,15 +1175,8 @@ BamScene::BamScene(QueenEngine *vm) } void BamScene::playSfx() { - // Don't try to play all the sounds. This is only necessary for the - // fight bam, in which the number of 'sfx bam frames' is too much - // important / too much closer. The original game does not have - // this problem since its playSfx() function returns immediately - // if a sound is already being played. - if (_lastSoundIndex == 0 || _index - _lastSoundIndex >= SFX_SKIP) { - _vm->sound()->playSfx(_vm->logic()->currentRoomSfx()); - _lastSoundIndex = _index; - } + _vm->sound()->playSfx(_vm->logic()->currentRoomSfx()); + _lastSoundIndex = _index; } void BamScene::prepareAnimation() { diff --git a/engines/queen/graphics.h b/engines/queen/graphics.h index 6f00111635..7eadf9a191 100644 --- a/engines/queen/graphics.h +++ b/engines/queen/graphics.h @@ -248,10 +248,6 @@ public: F_REQ_STOP = 2 }; - enum { - SFX_SKIP = 8 - }; - uint16 _flag, _index; private: diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index d70fe7209d..f4e0116cf1 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -229,11 +229,6 @@ void PCSound::setVolume(int vol) { _music->setVolume(vol); } -void PCSound::waitFinished(bool isSpeech) { - while (_mixer->isSoundHandleActive(isSpeech ? _speechHandle : _sfxHandle)) - _vm->input()->delay(10); -} - void PCSound::playSound(const char *base, bool isSpeech) { char name[13]; strcpy(name, base); @@ -243,7 +238,13 @@ void PCSound::playSound(const char *base, bool isSpeech) { name[i] = '0'; } strcat(name, ".SB"); - waitFinished(isSpeech); + if (isSpeech) { + while (_mixer->isSoundHandleActive(_speechHandle)) { + _vm->input()->delay(10); + } + } else { + _mixer->stopHandle(_sfxHandle); + } uint32 size; Common::File *f = _vm->resource()->findSound(name, &size); if (f) { @@ -255,6 +256,8 @@ void PCSound::playSound(const char *base, bool isSpeech) { } void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { + // In order to simplify the code, we don't parse the .sb header but hard-code the + // values. Refer to tracker item #1876741 for details on the format/fields. int headerSize; f->seek(2, SEEK_CUR); uint16 version = f->readUint16LE(); @@ -276,7 +279,7 @@ void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *so if (sound) { f->read(sound, size); byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; - _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11025, flags); + _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11840, flags); } } diff --git a/engines/queen/sound.h b/engines/queen/sound.h index c2c1481cc6..331034f746 100644 --- a/engines/queen/sound.h +++ b/engines/queen/sound.h @@ -143,7 +143,6 @@ public: void setVolume(int vol); protected: - void waitFinished(bool isSpeech); void playSound(const char *base, bool isSpeech); virtual void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) = 0; diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 9359c6610c..68d3010199 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 @@ -949,7 +949,7 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const { sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; - for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) { + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { // Obtain the last 2 digits of the filename, since they correspond to the save slot int slotNum = atoi(file->c_str() + file->size() - 2); diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 6d1cf1bbd8..e4e2b2b620 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -297,7 +297,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da break; case GUI::kListSelectionChangedCmd: { if (_gfxWidget) { - updateInfos(); + updateInfos(true); } if (_saveMode) { @@ -350,7 +350,7 @@ void SaveLoadChooser::reflowLayout() { _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR"); _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG"); _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB"); - updateInfos(); + updateInfos(false); } else { _container->setFlags(GUI::WIDGET_INVISIBLE); _gfxWidget->setFlags(GUI::WIDGET_INVISIBLE); @@ -362,7 +362,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -void SaveLoadChooser::updateInfos() { +void SaveLoadChooser::updateInfos(bool redraw) { int selItem = _list->getSelected(); Graphics::Surface *thumb; thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem); @@ -376,7 +376,8 @@ void SaveLoadChooser::updateInfos() { } delete thumb; - _gfxWidget->draw(); + if (redraw) + _gfxWidget->draw(); InfoStuff infos; memset(&infos, 0, sizeof(InfoStuff)); @@ -386,12 +387,14 @@ void SaveLoadChooser::updateInfos() { (infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF, infos.date & 0xFFFF); _date->setLabel(buffer); - _date->draw(); + if (redraw) + _date->draw(); snprintf(buffer, 32, "Time: %.2d:%.2d", (infos.time >> 8) & 0xFF, infos.time & 0xFF); _time->setLabel(buffer); - _time->draw(); + if (redraw) + _time->draw(); int minutes = infos.playtime / 60; int hours = minutes / 60; @@ -400,19 +403,23 @@ void SaveLoadChooser::updateInfos() { snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours & 0xFF, minutes & 0xFF); _playtime->setLabel(buffer); - _playtime->draw(); + if (redraw) + _playtime->draw(); } else { snprintf(buffer, 32, "No date saved"); _date->setLabel(buffer); - _date->draw(); + if (redraw) + _date->draw(); snprintf(buffer, 32, "No time saved"); _time->setLabel(buffer); - _time->draw(); + if (redraw) + _time->draw(); snprintf(buffer, 32, "No playtime saved"); _playtime->setLabel(buffer); - _playtime->draw(); + if (redraw) + _playtime->draw(); } } diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index 7c99a0ebcc..0d04d8faea 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -69,7 +69,7 @@ protected: uint8 _fillR, _fillG, _fillB; - void updateInfos(); + void updateInfos(bool redraw); public: SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine); ~SaveLoadChooser(); 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_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp index 1511b9aefc..b18b0ba70f 100644 --- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -102,10 +102,10 @@ void ImuseDigiSndMgr::prepareSoundFromRMAP(Common::File *file, SoundDesc *sound, int32 version = file->readUint32BE(); if (version != 3) { if (version == 2) { - warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2."); - warning("Suggested to recompress with latest tool from daily builds."); + warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2"); + warning("Suggested to recompress with latest tool from daily builds"); } else - error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d.", version); + error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d", version); } sound->bits = file->readUint32BE(); sound->freq = file->readUint32BE(); 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 36b82519e9..f9e4eb415c 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/sword2/music.cpp b/engines/sword2/music.cpp index fd72ba8d52..3b5a09578b 100644 --- a/engines/sword2/music.cpp +++ b/engines/sword2/music.cpp @@ -52,9 +52,11 @@ namespace Sword2 { static Audio::AudioStream *makeCLUStream(Common::File *fp, int size); static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) { - debug(3, "Playing %s from CD %d", base, cd); + bool alreadyOpen; if (!fh->file.isOpen()) { + alreadyOpen = false; + struct { const char *ext; int mode; @@ -75,16 +77,14 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, char filename[20]; for (int i = 0; i < ARRAYSIZE(file_types); i++) { - Common::File f; - sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext); - if (f.open(filename)) { + if (Common::File::exists(filename)) { soundMode = file_types[i].mode; break; } sprintf(filename, "%s.%s", base, file_types[i].ext); - if (f.open(filename)) { + if (Common::File::exists(filename)) { soundMode = file_types[i].mode; break; } @@ -105,7 +105,8 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, fh->idxTab = NULL; } } - } + } else + alreadyOpen = true; uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3; @@ -134,7 +135,13 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, *numSamples = len; if (!pos || !len) { - fh->file.close(); + // We couldn't find the sound. Possibly as a result of a bad + // installation (e.g. using the music file from CD 2 as the + // first music file). Don't close the file if it was already + // open though, because something is playing from it. + warning("getAudioStream: Could not find %s ID %d! Possibly the wrong file", base, id); + if (!alreadyOpen) + fh->file.close(); return NULL; } diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h index 70bae6f851..b89ef8f12b 100644 --- a/engines/sword2/sound.h +++ b/engines/sword2/sound.h @@ -106,7 +106,7 @@ private: void refill(); inline bool eosIntern() const { - return _pos >= _bufferEnd; + return !_file->isOpen() || _pos >= _bufferEnd; } public: 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/test/common/str.h b/test/common/str.h index dcba554b5a..76574ea70f 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -5,16 +5,25 @@ class StringTestSuite : public CxxTest::TestSuite { public: - void test_empty_clear( void ) - { + void test_constructors(void) { + Common::String str("test-string"); + TS_ASSERT( str == "test-string" ); + str = Common::String(str.c_str()+5, 3); + TS_ASSERT( str == "str" ); + str = "test-string"; + TS_ASSERT( str == "test-string" ); + str = Common::String(str.c_str()+5, str.c_str()+8); + TS_ASSERT( str == "str" ); + } + + void test_empty_clear(void) { Common::String str("test"); TS_ASSERT( !str.empty() ); str.clear(); TS_ASSERT( str.empty() ); } - void test_lastChar( void ) - { + void test_lastChar(void) { Common::String str; TS_ASSERT_EQUALS( str.lastChar(), '\0' ); str = "test"; @@ -23,8 +32,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str2.lastChar(), 'r' ); } - void test_concat1( void ) - { + void test_concat1(void) { Common::String str("foo"); Common::String str2("bar"); str += str2; @@ -32,22 +40,19 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str2, "bar" ); } - void test_concat2( void ) - { + void test_concat2(void) { Common::String str("foo"); str += "bar"; TS_ASSERT_EQUALS( str, "foobar" ); } - void test_concat3( void ) - { + void test_concat3(void) { Common::String str("foo"); str += 'X'; TS_ASSERT_EQUALS( str, "fooX" ); } - void test_refCount( void ) - { + void test_refCount(void) { Common::String foo1("foo"); Common::String foo2("foo"); Common::String foo3(foo2); @@ -57,8 +62,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "foo""X" ); } - void test_refCount2( void ) - { + void test_refCount2(void) { Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo3(foo2); @@ -68,8 +72,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""X" ); } - void test_refCount3( void ) - { + void test_refCount3(void) { Common::String foo1("0123456789abcdefghijk"); Common::String foo2("0123456789abcdefghijk"); Common::String foo3(foo2); @@ -79,8 +82,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "0123456789abcdefghijk""0123456789abcdefghijk" ); } - void test_refCount4( void ) - { + void test_refCount4(void) { Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo3(foo2); @@ -90,8 +92,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd" ); } - void test_hasPrefix( void ) - { + void test_hasPrefix(void) { Common::String str("this/is/a/test, haha"); TS_ASSERT_EQUALS( str.hasPrefix(""), true ); TS_ASSERT_EQUALS( str.hasPrefix("this"), true ); @@ -99,8 +100,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str.hasPrefix("foo"), false ); } - void test_hasSuffix( void ) - { + void test_hasSuffix(void) { Common::String str("this/is/a/test, haha"); TS_ASSERT_EQUALS( str.hasSuffix(""), true ); TS_ASSERT_EQUALS( str.hasSuffix("haha"), true ); @@ -108,8 +108,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str.hasSuffix("hahah"), false ); } - void test_contains( void ) - { + void test_contains(void) { Common::String str("this/is/a/test, haha"); TS_ASSERT_EQUALS( str.contains(""), true ); TS_ASSERT_EQUALS( str.contains("haha"), true ); @@ -117,15 +116,13 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str.contains("test"), true ); } - void test_toLowercase( void ) - { + void test_toLowercase(void) { Common::String str("Test it, NOW! 42"); str.toLowercase(); TS_ASSERT_EQUALS( str, "test it, now! 42" ); } - void test_toUppercase( void ) - { + void test_toUppercase(void) { Common::String str("Test it, NOW! 42"); str.toUppercase(); TS_ASSERT_EQUALS( str, "TEST IT, NOW! 42" ); 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 |