Merged revisions 33052-33053,33056-33058,33061-33064,33068,33070,33072,33075,33078-33079,33083,33086-33087,33089,33094-33096,33098-33099,33104,33108-33109,33114-33117,33120,33135-33146,33160,33162,33165,33167-33169 via svnmerge from

https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk

svn-id: r33183
This commit is contained in:
Christopher Page 2008-07-21 22:46:39 +00:00
commit 09f4fd946e
70 changed files with 4241 additions and 930 deletions

View file

@ -132,8 +132,7 @@ bail:
return MERR_DEVICE_NOT_AVAILABLE; return MERR_DEVICE_NOT_AVAILABLE;
} }
void MidiDriver_QT::close() void MidiDriver_QT::close() {
{
MidiDriver_MPU401::close(); MidiDriver_MPU401::close();
dispose(); dispose();
} }
@ -248,8 +247,7 @@ void MidiDriver_QT::setPitchBendRange (byte channel, uint range) {
NASetController(qtNoteAllocator, qtNoteChannel[channel], kControllerPitchBend, theBend); NASetController(qtNoteAllocator, qtNoteChannel[channel], kControllerPitchBend, theBend);
} }
void MidiDriver_QT::dispose() void MidiDriver_QT::dispose() {
{
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (qtNoteChannel[i] != 0) if (qtNoteChannel[i] != 0)
NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]); NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]);

View file

@ -19,16 +19,17 @@ RM = rm -f
srcdir = ../../.. srcdir = ../../..
VPATH = $(srcdir) VPATH = $(srcdir)
INCDIR = ../../../ INCDIR = ../../../
DEPDIR = .deps
DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_MPEG2 -DUSE_ZLIB -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar 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 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_INCS = /ucl /zlib/include /libmad/ee/include
PS2SDK_PORTS_LIBS = /ucl /zlib/lib /libmad/ee/lib PS2SDK_PORTS_LIBS = /ucl /zlib/lib /libmad/ee/lib
# we also need SjPcm, Tremor and libmpeg2 # 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_INCS = /SjPcm/ee/src /mpeg2dec/include /tremor
MORE_LIBS_LIBS = /SjPcm/ee/lib /mpeg2dec/libmpeg2 /tremor/tremor MORE_LIBS_LIBS = /SjPcm/ee/lib /mpeg2dec/libmpeg2 /tremor/tremor

View file

@ -340,8 +340,6 @@ FILE *ps2_fopen(const char *fname, const char *mode) {
assert(cacheListSema >= 0); assert(cacheListSema >= 0);
} }
//printf("ps2_fopen: %s, %s\n", fname, mode);
if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) { if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) {
printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname);
return NULL; return NULL;
@ -363,6 +361,8 @@ FILE *ps2_fopen(const char *fname, const char *mode) {
} else { } else {
// Regular access to one of the devices // Regular access to one of the devices
printf("ps2_fopen = %s\n", fname); // romeo : temp
if (!rdOnly) if (!rdOnly)
return NULL; // we only provide readaccess for cd,dvd,hdd,usb 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; int64 cacheId = -1;
if (rdOnly && tocManager.haveEntries()) if (tocManager.haveEntries())
cacheId = tocManager.fileExists(fname); cacheId = tocManager.fileExists(fname);
if (cacheId != 0) { if (cacheId != 0) {
Ps2File *file = findInCache(cacheId); Ps2File *file = findInCache(cacheId);
if (file) if (file) {
printf(" findInCache(%x)\n", cacheId); // romeo : temp
return (FILE*)file; return (FILE*)file;
}
bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun"); bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun");
file = new Ps2ReadFile(cacheId, isAudioFile); file = new Ps2ReadFile(cacheId, isAudioFile);
if (file->open(fname)) { if (file->open(fname)) {
openFileCount++; openFileCount++;
printf(" new cacheID = %x\n", cacheId); // romeo : temp
return (FILE*)file; return (FILE*)file;
} else } else
delete file; delete file;
@ -579,7 +582,7 @@ void TocManager::readEntries(const char *root) {
} }
char readPath[256]; char readPath[256];
sprintf(readPath, "%s/", _root); sprintf(readPath, "%s/", _root);
printf("readDir: %s\n", readPath); printf("readDir: %s (root: %s )\n", readPath, root);
readDir(readPath, &_rootNode, 0); 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 if (level <= 2) { // we don't scan deeper than that
iox_dirent_t dirent; iox_dirent_t dirent;
int fd = fio.dopen(path); int fd = fio.dopen(path);
if (fd >= 0) { TocNode *eNode = NULL; // = *node; // entry node
while (fio.dread(fd, &dirent) > 0) bool first = true;
if (dirent.name[0] != '.') { // skip '.' and '..'
*node = new TocNode;
(*node)->sub = (*node)->next = NULL;
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 '.' & '..' - 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); (*node)->nameLen = strlen(dirent.name);
memcpy((*node)->name, dirent.name, (*node)->nameLen + 1); 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; (*node)->isDir = true;
char nextPath[256]; printf("dirent.name = %s [DIR]\n", dirent.name);
sprintf(nextPath, "%s%s/", path, dirent.name); }
readDir(nextPath, &((*node)->sub), level + 1); else {
} else
(*node)->isDir = false; (*node)->isDir = false;
printf("dirent.name = %s\n", dirent.name);
}
node = &((*node)->next); node = &((*node)->next);
} }
}
fio.dclose(fd); 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) { int64 TocManager::fileExists(const char *name) {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -43,7 +43,7 @@ IrxFile irxFiles[] = {
{ "PADMAN", BIOS, NOTHING, NULL, 0 }, { "PADMAN", BIOS, NOTHING, NULL, 0 },
{ "LIBSD", 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 }, { "FILEXIO.IRX", SYSTEM, NOTHING, NULL, 0 },
{ "CODYVDFS.IRX", SYSTEM, NOTHING, NULL, 0 }, { "CODYVDFS.IRX", SYSTEM, NOTHING, NULL, 0 },
{ "SJPCM.IRX", SYSTEM, NOTHING, NULL, 0 }, { "SJPCM.IRX", SYSTEM, NOTHING, NULL, 0 },

View file

@ -54,9 +54,11 @@
#include "graphics/surface.h" #include "graphics/surface.h"
#include "graphics/font.h" #include "graphics/font.h"
#include "backends/timer/default/default-timer.h" #include "backends/timer/default/default-timer.h"
#include "sound/mixer.h" #include "sound/mixer_intern.h"
#include "common/events.h" #include "common/events.h"
#include "backends/platform/ps2/ps2debug.h" #include "backends/platform/ps2/ps2debug.h"
#include "backends/fs/ps2/ps2-fs-factory.h"
// asm("mfc0 %0, $9\n" : "=r"(tickStart)); // asm("mfc0 %0, $9\n" : "=r"(tickStart));
extern void *_gp; extern void *_gp;
@ -309,7 +311,9 @@ OSystem_PS2::OSystem_PS2(const char *elfPath) {
void OSystem_PS2::init(void) { void OSystem_PS2::init(void) {
sioprintf("Timer...\n"); sioprintf("Timer...\n");
_scummTimerManager = new DefaultTimerManager(); _scummTimerManager = new DefaultTimerManager();
_scummMixer = new Audio::Mixer(); _scummMixer = new Audio::MixerImpl(this);
_scummMixer->setOutputRate(44100);
_scummMixer->setReady(true);
initTimer(); initTimer();
sioprintf("Starting SavefileManager\n"); sioprintf("Starting SavefileManager\n");
@ -410,7 +414,8 @@ void OSystem_PS2::soundThread(void) {
// we have to produce more samples, call sound mixer // we have to produce more samples, call sound mixer
// the scratchpad at 0x70000000 is used as temporary soundbuffer // the scratchpad at 0x70000000 is used as temporary soundbuffer
//_scummSoundProc(_scummSoundParam, (uint8*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); //_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 // demux data into 2 buffers, L and R
__asm__ ( __asm__ (
@ -534,10 +539,6 @@ Common::TimerManager *OSystem_PS2::getTimerManager() {
return _scummTimerManager; return _scummTimerManager;
} }
int OSystem_PS2::getOutputSampleRate(void) const {
return 48000;
}
Audio::Mixer *OSystem_PS2::getMixer() { Audio::Mixer *OSystem_PS2::getMixer() {
return _scummMixer; return _scummMixer;
} }
@ -546,6 +547,10 @@ Common::SaveFileManager *OSystem_PS2::getSavefileManager(void) {
return _saveManager; return _saveManager;
} }
FilesystemFactory *OSystem_PS2::getFilesystemFactory() {
return &Ps2FilesystemFactory::instance();
}
void OSystem_PS2::setShakePos(int shakeOffset) { void OSystem_PS2::setShakePos(int shakeOffset) {
_screen->setShakePos(shakeOffset); _screen->setShakePos(shakeOffset);
} }

View file

@ -33,6 +33,7 @@ class DefaultTimerManager;
class Gs2dScreen; class Gs2dScreen;
class Ps2Input; class Ps2Input;
class Ps2SaveFileManager; class Ps2SaveFileManager;
// class Ps2FilesystemFactory;
struct IrxReference; struct IrxReference;
#define MAX_MUTEXES 16 #define MAX_MUTEXES 16
@ -48,7 +49,7 @@ namespace Common {
}; };
namespace Audio { namespace Audio {
class Mixer; class MixerImpl;
}; };
class OSystem_PS2 : public OSystem { class OSystem_PS2 : public OSystem {
@ -87,7 +88,6 @@ public:
virtual bool pollEvent(Common::Event &event); virtual bool pollEvent(Common::Event &event);
virtual Audio::Mixer *getMixer(); virtual Audio::Mixer *getMixer();
virtual int getOutputSampleRate(void) const;
virtual bool openCD(int drive); virtual bool openCD(int drive);
virtual bool pollCD(); virtual bool pollCD();
@ -112,6 +112,7 @@ public:
virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b);
virtual Common::SaveFileManager *getSavefileManager(); virtual Common::SaveFileManager *getSavefileManager();
virtual FilesystemFactory *getFilesystemFactory();
virtual void getTimeAndDate(struct tm &t) const; virtual void getTimeAndDate(struct tm &t) const;
@ -133,7 +134,7 @@ private:
void readRtcTime(void); void readRtcTime(void);
DefaultTimerManager *_scummTimerManager; DefaultTimerManager *_scummTimerManager;
Audio::Mixer *_scummMixer; Audio::MixerImpl *_scummMixer;
bool _mouseVisible; bool _mouseVisible;

View file

@ -191,7 +191,7 @@ OSystem_SDL::OSystem_SDL()
OSystem_SDL::~OSystem_SDL() { OSystem_SDL::~OSystem_SDL() {
SDL_RemoveTimer(_timerID); SDL_RemoveTimer(_timerID);
SDL_CloseAudio(); closeMixer();
free(_dirtyChecksums); free(_dirtyChecksums);
free(_currentPalette); free(_currentPalette);
@ -199,7 +199,6 @@ OSystem_SDL::~OSystem_SDL() {
free(_mouseData); free(_mouseData);
delete _savefile; delete _savefile;
delete _mixer;
delete _timer; delete _timer;
} }
@ -306,7 +305,7 @@ void OSystem_SDL::quit() {
SDL_ShowCursor(SDL_ENABLE); SDL_ShowCursor(SDL_ENABLE);
SDL_RemoveTimer(_timerID); SDL_RemoveTimer(_timerID);
SDL_CloseAudio(); closeMixer();
free(_dirtyChecksums); free(_dirtyChecksums);
free(_currentPalette); free(_currentPalette);
@ -314,7 +313,6 @@ void OSystem_SDL::quit() {
free(_mouseData); free(_mouseData);
delete _savefile; delete _savefile;
delete _mixer;
delete _timer; delete _timer;
SDL_Quit(); SDL_Quit();
@ -389,14 +387,110 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) {
#pragma mark --- Audio --- #pragma mark --- Audio ---
#pragma mark - #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) { void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) {
OSystem_SDL *this_ = (OSystem_SDL *)sys; OSystem_SDL *this_ = (OSystem_SDL *)sys;
assert(this_); assert(this_);
assert(this_->_mixer);
if (this_->_mixer) this_->_mixer->mixCallback(samples, len);
this_->_mixer->mixCallback(samples, len);
} }
#endif
void OSystem_SDL::setupMixer() { void OSystem_SDL::setupMixer() {
SDL_AudioSpec desired; SDL_AudioSpec desired;
SDL_AudioSpec obtained; SDL_AudioSpec obtained;
@ -443,10 +537,31 @@ void OSystem_SDL::setupMixer() {
// Tell the mixer that we are ready and start the sound processing // Tell the mixer that we are ready and start the sound processing
_mixer->setOutputRate(_samplesPerSec); _mixer->setOutputRate(_samplesPerSec);
_mixer->setReady(true); _mixer->setReady(true);
#ifdef MIXER_DOUBLE_BUFFERING
initThreadedMixer(_mixer, obtained.samples * 4);
#endif
// start the sound system
SDL_PauseAudio(0); 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() { Audio::Mixer *OSystem_SDL::getMixer() {
assert(_mixer); assert(_mixer);
return _mixer; return _mixer;

View file

@ -51,6 +51,15 @@ namespace Common {
#define USE_OSD 1 #define USE_OSD 1
#endif #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 { enum {
GFX_NORMAL = 0, GFX_NORMAL = 0,
@ -137,6 +146,8 @@ public:
virtual void setupMixer(); virtual void setupMixer();
static void mixCallback(void *s, byte *samples, int len); static void mixCallback(void *s, byte *samples, int len);
virtual void closeMixer();
virtual Audio::Mixer *getMixer(); virtual Audio::Mixer *getMixer();
// Poll CD status // Poll CD status
@ -369,6 +380,23 @@ protected:
*/ */
MutexRef _graphicsMutex; 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; Common::SaveFileManager *_savefile;
Audio::MixerImpl *_mixer; Audio::MixerImpl *_mixer;
@ -377,7 +405,7 @@ protected:
Common::TimerManager *_timer; Common::TimerManager *_timer;
protected:
void addDirtyRgnAuto(const byte *buf); void addDirtyRgnAuto(const byte *buf);
void makeChecksums(const byte *buf); void makeChecksums(const byte *buf);

View file

@ -226,28 +226,31 @@
$VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines"; $VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines";
# now one for each ready-for-release engine # now one for each ready-for-release engine
if (0)
{
foreach (@WorkingEngines) foreach (@WorkingEngines)
{ {
$VariationSets{'ALL'}{$_} = "$DefaultFeatures $_"; $VariationSets{'ALL'}{$_} = "$DefaultFeatures $_";
} }
# for scumm, we need to add 2 features: # 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 # now one for each not-ready-for-release-or-testing engine
if (0)
{
foreach (@TestingEngines) foreach (@TestingEngines)
{ {
$VariationSets{'ALL'}{"test_$_"} = "$DefaultFeatures $_"; $VariationSets{'ALL'}{"test_$_"} = "$DefaultFeatures $_";
} }
}
# below here you could specify weird & experimental combinations, non-ready engines # 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) # 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 # 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 # maybe you feel lucky and want to test the sword engines? :P
#$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2"; #$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2";

View file

@ -33,7 +33,7 @@
#include "gui/Actions.h" #include "gui/Actions.h"
#include "gui/Key.h" #include "gui/Key.h"
#include "gui/message.h" #include "gui/message.h"
#include "sound/mixer_intern.h"
#include "..\..\sdl\main.cpp" #include "..\..\sdl\main.cpp"
#ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :( #ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :(
@ -42,10 +42,22 @@
#define SAMPLES_PER_SEC 16000 #define SAMPLES_PER_SEC 16000
#endif #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" /////////////////////////////////////////////////// ////////// extern "C" ///////////////////////////////////////////////////
namespace Symbian { namespace Symbian {
// Show a simple Symbian Info win with Msg & exit // Show a simple Symbian Info win with Msg & exit
void FatalError(const char *msg) { void FatalError(const char *msg) {
TPtrC8 msgPtr((const TUint8 *)msg); TPtrC8 msgPtr((const TUint8 *)msg);
@ -246,9 +258,9 @@ void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len)
if (!this_->_mixer) if (!this_->_mixer)
return; return;
#ifdef S60 #if defined (S60) && !defined(S60V3)
// If not stereo then we need to downmix // If not stereo then we need to downmix
if (_channels != 2) { if (this_->_mixer->_channels != 2) {
this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2); this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2);
int16 *bitmixDst = (int16 *)samples; 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) { FILE* symbian_fopen(const char* name, const char* mode) {
TSymbianFileEntry* fileEntry = new TSymbianFileEntry; TSymbianFileEntry* fileEntry = new TSymbianFileEntry;
fileEntry->iInputPos = KErrNotFound;
if (fileEntry != NULL) { if (fileEntry != NULL) {
TInt modeLen = strlen(mode); 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) { 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);
((TSymbianFileEntry*)(handle))->iFileHandle.Read(pointer); // 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);
}
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; 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) { size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) {
TPtrC8 pointer( (unsigned char*) ptr, size*numItems); TPtrC8 pointer( (unsigned char*) ptr, size*numItems);
((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound;
if (((TSymbianFileEntry*)(handle))->iFileHandle.Write(pointer) == KErrNone) { if (((TSymbianFileEntry*)(handle))->iFileHandle.Write(pointer) == KErrNone) {
return numItems; 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) { bool symbian_feof(FILE* handle) {
TInt pos = 0; 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; TInt size = 0;
if (((TSymbianFileEntry*)(handle))->iFileHandle.Size(size) == KErrNone) { if (entry->iFileHandle.Size(size) == KErrNone) {
if (pos == size) if(entry->iInputPos == KErrNotFound && pos == size)
return true; return true;
if(entry->iInputPos != KErrNotFound && pos == size && entry->iInputPos == entry->iInputBufferLen)
return true;
return false; return false;
} }
} }
@ -549,6 +624,7 @@ long int symbian_ftell(FILE* handle) {
} }
int symbian_fseek(FILE* handle, long int offset, int whence) { int symbian_fseek(FILE* handle, long int offset, int whence) {
TSeek seekMode = ESeekStart; TSeek seekMode = ESeekStart;
TInt pos = offset; TInt pos = offset;
@ -564,6 +640,8 @@ int symbian_fseek(FILE* handle, long int offset, int whence) {
break; break;
} }
((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound;
return ((TSymbianFileEntry*)(handle))->iFileHandle.Seek(seekMode, pos); return ((TSymbianFileEntry*)(handle))->iFileHandle.Seek(seekMode, pos);
} }

View file

@ -1,8 +1,34 @@
/* MISSING.C /* ScummVM - Graphic Adventure Engine
Implementation for standard and semi-standard C library calls missing in WinCE *
environment. * ScummVM is the legal property of its developers, whose names
by Vasyl Tsvirkunov * 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 <windows.h>
#include <tchar.h> #include <tchar.h>
@ -17,19 +43,8 @@
#include "time.h" #include "time.h"
#include "dirent.h" #include "dirent.h"
/* forward declaration */
#if _WIN32_WCE < 300
#define _STDAFX_H
#include "portdefs.h"
#else
char *strdup(const char *strSource); char *strdup(const char *strSource);
#endif
#ifdef __GNUC__ #ifdef __GNUC__
#define EXT_C extern "C" #define EXT_C extern "C"
#else #else
@ -40,19 +55,27 @@ char *strdup(const char *strSource);
void *bsearch(const void *key, const void *base, size_t nmemb, void *bsearch(const void *key, const void *base, size_t nmemb,
size_t size, int (*compar)(const void *, const void *)) { 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; return NULL;
} }
static WIN32_FIND_DATA wfd; 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]; TCHAR fnameUnc[MAX_PATH+1];
HANDLE handle; HANDLE handle;
int len; int len;
@ -63,8 +86,7 @@ int stat(const char *fname, struct stat *ss)
/* Special case (dummy on WinCE) */ /* Special case (dummy on WinCE) */
len = strlen(fname); len = strlen(fname);
if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' && 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 */ /* That's everything implemented so far */
memset(ss, 0, sizeof(struct stat)); memset(ss, 0, sizeof(struct stat));
ss->st_size = 1024; 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); MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH);
handle = FindFirstFile(fnameUnc, &wfd); handle = FindFirstFile(fnameUnc, &wfd);
FindClose(handle);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return -1; return -1;
else else
@ -83,20 +106,16 @@ int stat(const char *fname, struct stat *ss)
ss->st_size = wfd.nFileSizeLow; ss->st_size = wfd.nFileSizeLow;
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ss->st_mode |= S_IFDIR; ss->st_mode |= S_IFDIR;
FindClose(handle);
} }
return 0; return 0;
} }
char cwd[MAX_PATH+1] = ""; 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]; TCHAR fileUnc[MAX_PATH+1];
char* plast; char* plast;
if (cwd[0] == 0) if (cwd[0] == 0) {
{
GetModuleFileName(NULL, fileUnc, MAX_PATH); GetModuleFileName(NULL, fileUnc, MAX_PATH);
WideCharToMultiByte(CP_ACP, 0, fileUnc, -1, cwd, MAX_PATH, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, fileUnc, -1, cwd, MAX_PATH, NULL, NULL);
plast = strrchr(cwd, '\\'); plast = strrchr(cwd, '\\');
@ -114,8 +133,7 @@ EXT_C char *getcwd(char *buffer, int maxlen)
#ifdef __GNUC__ #ifdef __GNUC__
#undef GetCurrentDirectory #undef GetCurrentDirectory
#endif #endif
EXT_C void GetCurrentDirectory(int len, char *buf) EXT_C void GetCurrentDirectory(int len, char *buf) {
{
getcwd(buf,len); getcwd(buf,len);
}; };
@ -125,26 +143,22 @@ fully qualified paths refer to root folder rather
than current folder (concept not implemented in CE). than current folder (concept not implemented in CE).
*/ */
#undef fopen #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]; char fullname[MAX_PATH+1];
if (!fname || fname[0] == '\0') if (!fname || fname[0] == '\0')
return NULL; return NULL;
if (fname[0] != '\\' && fname[0] != '/') if (fname[0] != '\\' && fname[0] != '/') {
{
getcwd(fullname, MAX_PATH); getcwd(fullname, MAX_PATH);
strncat(fullname, "\\", MAX_PATH-strlen(fullname)-1); strncat(fullname, "\\", MAX_PATH-strlen(fullname)-1);
strncat(fullname, fname, MAX_PATH-strlen(fullname)-strlen(fname)); strncat(fullname, fname, MAX_PATH-strlen(fullname)-strlen(fname));
return fopen(fullname, fmode); return fopen(fullname, fmode);
} } else
else
return fopen(fname, fmode); return fopen(fname, fmode);
} }
/* Remove file by name */ /* Remove file by name */
int remove(const char* path) int remove(const char* path) {
{
TCHAR pathUnc[MAX_PATH+1]; TCHAR pathUnc[MAX_PATH+1];
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
return !DeleteFile(pathUnc); return !DeleteFile(pathUnc);
@ -158,14 +172,22 @@ int _access(const char *path, int mode) {
WIN32_FIND_DATA ffd; WIN32_FIND_DATA ffd;
HANDLE h=FindFirstFile(fname, &ffd); HANDLE h=FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE) if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file return -1; //Can't find file
FindClose(h);
if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) 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 return 0; //Always return success if target is directory and exists
}
switch (mode) { switch (mode) {
case 00: //Check existence case 00: //Check existence
return 0; return 0;
@ -183,8 +205,7 @@ int _access(const char *path, int mode) {
#ifndef __GNUC__ #ifndef __GNUC__
/* Limited dirent implementation. Used by UI.C and DEVICES.C */ /* Limited dirent implementation. Used by UI.C and DEVICES.C */
DIR* opendir(const char* fname) DIR* opendir(const char* fname) {
{
DIR* pdir; DIR* pdir;
char fnameMask[MAX_PATH+1]; char fnameMask[MAX_PATH+1];
TCHAR fnameUnc[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 */ strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */
MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH); 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); free(pdir);
return NULL; return NULL;
} } else {
else
{
WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL);
pdir->dd_dir.d_name = strdup(nameFound); pdir->dd_dir.d_name = strdup(nameFound);
@ -224,34 +242,25 @@ DIR* opendir(const char* fname)
return pdir; return pdir;
} }
struct dirent* readdir(DIR* dir) struct dirent* readdir(DIR* dir) {
{
char nameFound[MAX_PATH+1]; char nameFound[MAX_PATH+1];
static struct dirent dummy; static struct dirent dummy;
if (dir->dd_stat == 0) if (dir->dd_stat == 0) {
{
dummy.d_name = "."; dummy.d_name = ".";
dummy.d_namlen = 1; dummy.d_namlen = 1;
dir->dd_stat ++; dir->dd_stat ++;
return &dummy; return &dummy;
} } else if (dir->dd_stat == 1) {
else if (dir->dd_stat == 1)
{
dummy.d_name = ".."; dummy.d_name = "..";
dummy.d_namlen = 2; dummy.d_namlen = 2;
dir->dd_stat ++; dir->dd_stat ++;
return &dummy; return &dummy;
} } else if (dir->dd_stat == 2) {
else if (dir->dd_stat == 2)
{
dir->dd_stat++; dir->dd_stat++;
return &dir->dd_dir; return &dir->dd_dir;
} } else {
else if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) {
{
if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0)
{
dir->dd_stat = -1; dir->dd_stat = -1;
return NULL; return NULL;
} }
@ -283,12 +292,6 @@ int closedir(DIR* dir)
return 1; return 1;
} }
/* in our case unlink is the same as remove */
int unlink(const char* path)
{
return remove(path);
}
/* Make directory, Unix style */ /* Make directory, Unix style */
void mkdir(char* dirname, int mode) void mkdir(char* dirname, int mode)
{ {
@ -299,10 +302,8 @@ void mkdir(char* dirname, int mode)
if (*path == '/') if (*path == '/')
*path = '\\'; *path = '\\';
/* Run through the string and attempt creating all subdirs on the path */ /* Run through the string and attempt creating all subdirs on the path */
for (ptr = path+1; *ptr; ptr ++) for (ptr = path+1; *ptr; ptr ++) {
{ if (*ptr == '\\' || *ptr == '/') {
if (*ptr == '\\' || *ptr == '/')
{
*ptr = 0; *ptr = 0;
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
CreateDirectory(pathUnc, 0); CreateDirectory(pathUnc, 0);
@ -313,373 +314,40 @@ void mkdir(char* dirname, int mode)
CreateDirectory(pathUnc, 0); 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) char *strdup(const char *strSource)
#endif
{ {
char* buffer; char* buffer;
buffer = (char*)malloc(strlen(strSource)+1); size_z len = strlen(strSource)+1;
buffer = (char*)malloc(len);
if (buffer) if (buffer)
strcpy(buffer, strSource); memcpy(buffer, strSource, len);
return buffer; 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 // gcc build only functions follow
#else // defined(__GNUC__) #else // defined(__GNUC__)
#ifndef __MINGW32CE__ #ifndef __MINGW32CE__
int islower(int c) int islower(int c) {
{
return (c>='a' && c<='z'); 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'); return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v');
} }
int isalpha(int c) int isalpha(int c) {
{ return ((c>='a' && c<='z') || (c>='A' && c<='Z'));
return (islower(c) || (c>='A' && c<='Z'));
} }
int isalnum(int c) int isalnum(int c) {
{ return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'));
return (isalpha(c) || (c>='0' && c<='9'));
} }
int isprint(int c) int isprint(int c) {
{ //static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~";
static char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~"; //return (isalnum(c) || strchr(punct, c));
int i = 0, flag = 0; return (32 <= c && c <= 126); // based on BSD manpage
while ((punct[i] != 0) && (flag = (punct[i] != c)))
i++;
return (isalnum(c) || flag);
}
extern "C" int atexit(void (*function)(void))
{
return 0;
} }
#endif #endif

View file

@ -32,10 +32,10 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const Pla
const PlainGameDescriptor *g = list; const PlainGameDescriptor *g = list;
while (g->gameid) { while (g->gameid) {
if (0 == scumm_stricmp(gameid, g->gameid)) if (0 == scumm_stricmp(gameid, g->gameid))
break; return g;
g++; g++;
} }
return g; return 0;
} }
void GameDescriptor::updateDesc(const char *extra) { void GameDescriptor::updateDesc(const char *extra) {

View file

@ -48,7 +48,7 @@ struct PlainGameDescriptor {
/** /**
* Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor * Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor
* matching the given gameid. If not match is found return 0. * 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); const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list);

View file

@ -1 +1 @@
#define SCUMMVM_VERSION "0.12.0svn" #define SCUMMVM_VERSION "0.13.0svn"

View file

@ -81,17 +81,11 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
#define STATIC_PLUGIN 1 #define STATIC_PLUGIN 1
#define DYNAMIC_PLUGIN 2 #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) \ #define PLUGIN_ENABLED_STATIC(ID) \
(defined( ENABLE_##ID ) && !PLUGIN_ENABLED_DYNAMIC(ID)) (ENABLE_##ID && !PLUGIN_ENABLED_DYNAMIC(ID))
#define 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 * REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare

View file

@ -176,7 +176,6 @@ void ConfigManager::loadFile(const String &filename) {
if (!cfg_file.open(filename)) { if (!cfg_file.open(filename)) {
printf("Creating configuration file: %s\n", filename.c_str()); printf("Creating configuration file: %s\n", filename.c_str());
} else { } else {
char buf[MAXLINELEN];
String domain; String domain;
String comment; String comment;
int lineno = 0; int lineno = 0;
@ -184,20 +183,28 @@ void ConfigManager::loadFile(const String &filename) {
// TODO: Detect if a domain occurs multiple times (or likewise, if // TODO: Detect if a domain occurs multiple times (or likewise, if
// a key occurs multiple times inside one domain). // a key occurs multiple times inside one domain).
while (!cfg_file.eof()) { while (!cfg_file.eof() && !cfg_file.ioFailed()) {
lineno++; 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 // Accumulate comments here. Once we encounter either the start
// of a new domain, or a key-value-pair, we associate the value // of a new domain, or a key-value-pair, we associate the value
// of the 'comment' variable with that entity. // of the 'comment' variable with that entity.
comment += buf; comment += line;
comment += '\n'; } else if (line[0] == '[') {
} else if (buf[0] == '[') {
// It's a new domain which begins here. // 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 // Get the domain name, and check whether it's valid (that
// is, verify that it only consists of alphanumerics, // is, verify that it only consists of alphanumerics,
// dashes and underscores). // dashes and underscores).
@ -209,8 +216,8 @@ void ConfigManager::loadFile(const String &filename) {
error("Config file buggy: missing ] in line %d", lineno); error("Config file buggy: missing ] in line %d", lineno);
break; break;
case ']': case ']':
*p = 0; domain = String(line.c_str() + 1, p - (line.c_str() + 1));
domain = buf + 1; //domain = String(line.c_str() + 1, p); // TODO: Pending Common::String changes
break; break;
default: default:
error("Config file buggy: Invalid character '%c' occured in domain name in line %d", *p, lineno); 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); _domainSaveOrder.push_back(domain);
} else { } else {
// Skip leading & trailing whitespaces // This line should be a line with a 'key=value' pair, or an empty one.
char *t = rtrim(ltrim(buf));
// Skip leading whitespaces
const char *t = line.c_str();
while (isspace(*t))
t++;
// Skip empty lines // Skip empty lines / lines with only whitespace
if (*t == 0) if (*t == 0)
continue; 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); error("Config file buggy: Key/value pair found outside a domain in line %d", lineno);
} }
// Split string at '=' into 'key' and 'value'. // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter.
char *p = strchr(t, '='); const char *p = strchr(t, '=');
if (!p) if (!p)
error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); error("Config file buggy: Junk found in line line %d: '%s'", lineno, t);
*p = 0;
String key = rtrim(t); // Trim spaces before the '=' to obtain the key
String value = ltrim(p + 1); 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); set(key, value, domain);
// Store comment // Store comment

View file

@ -452,10 +452,12 @@ bool File::isOpen() const {
} }
bool File::ioFailed() const { bool File::ioFailed() const {
// TODO/FIXME: Just use ferror() here?
return _ioFailed != 0; return _ioFailed != 0;
} }
void File::clearIOFailed() { void File::clearIOFailed() {
// TODO/FIXME: Just use clearerr() here?
_ioFailed = false; _ioFailed = false;
} }

View file

@ -43,32 +43,43 @@ static int computeCapacity(int len) {
return ((len + 32 - 1) & ~0x1F) - 1; return ((len + 32 - 1) & ~0x1F) - 1;
} }
String::String(const char *str, uint32 len) String::String(const char *str) : _len(0), _str(_storage) {
: _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) // Init _storage member explicitly (ie. without calling its constructor)
// for GCC 2.95.x compatibility (see also tracker item #1602879). // for GCC 2.95.x compatibility (see also tracker item #1602879).
_storage[0] = 0; _storage[0] = 0;
if (str && *str) { _len = len;
const uint32 tmp = strlen(str);
assert(len <= tmp);
if (len <= 0)
len = tmp;
_len = len;
if (len >= _builtinCapacity) { if (len >= _builtinCapacity) {
// Not enough internal storage, so allocate more // Not enough internal storage, so allocate more
_extern._capacity = computeCapacity(len); _extern._capacity = computeCapacity(len);
_extern._refCount = 0; _extern._refCount = 0;
_str = (char *)malloc(_extern._capacity+1); _str = (char *)malloc(_extern._capacity+1);
assert(_str != 0); assert(_str != 0);
}
// Copy the string into the storage area
memcpy(_str, str, len);
_str[len] = 0;
} }
// Copy the string into the storage area
memmove(_str, str, len);
_str[len] = 0;
} }
String::String(const String &str) String::String(const String &str)
@ -91,6 +102,8 @@ String::String(char c)
_storage[0] = c; _storage[0] = c;
_storage[1] = 0; _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; _len = (c == 0) ? 0 : 1;
} }
@ -130,11 +143,14 @@ String& String::operator =(const char *str) {
uint32 len = strlen(str); uint32 len = strlen(str);
ensureCapacity(len, false); ensureCapacity(len, false);
_len = len; _len = len;
memcpy(_str, str, len + 1); memmove(_str, str, len + 1);
return *this; return *this;
} }
String &String::operator =(const String &str) { String &String::operator =(const String &str) {
if (&str == this)
return *this;
if (str.isStorageIntern()) { if (str.isStorageIntern()) {
decRefCount(_extern._refCount); decRefCount(_extern._refCount);
_len = str._len; _len = str._len;

View file

@ -96,10 +96,24 @@ public:
static const char *emptyString; static const char *emptyString;
#endif #endif
/** Construct a new empty string. */
String() : _len(0), _str(_storage) { _storage[0] = 0; } 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); String(const String &str);
/** Construct a string consisting of the given character. */
String(char c); String(char c);
~String(); ~String();
String &operator =(const char *str); String &operator =(const char *str);
@ -162,7 +176,7 @@ public:
void toLowercase(); void toLowercase();
void toUppercase(); void toUppercase();
uint hash() const; uint hash() const;
public: public:
@ -189,6 +203,7 @@ protected:
void ensureCapacity(uint32 new_len, bool keep_old); void ensureCapacity(uint32 new_len, bool keep_old);
void incRefCount() const; void incRefCount() const;
void decRefCount(int *oldRefCount); void decRefCount(int *oldRefCount);
void initWithCStr(const char *str, uint32 len);
}; };
// Append two strings to form a new (temp) string // Append two strings to form a new (temp) string

View file

@ -148,6 +148,61 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
return buf; 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) { uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
dataSize = MIN(dataSize, _end - _pos); dataSize = MIN(dataSize, _end - _pos);

View file

@ -304,13 +304,40 @@ public:
* Read one line of text from a CR or CR/LF terminated plain text file. * 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. * 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 buf the buffer to store into
* @param bufSize the size of the buffer * @param bufSize the size of the buffer
* @return a pointer to the read string, or NULL if an error occurred * @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 * @note The line terminator (CR or CR/LF) is stripped and not inserted
* into the buffer. * into the buffer.
*/ */
virtual char *readLine(char *buf, size_t bufSize); 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);
}; };
/** /**

4
configure vendored
View file

@ -129,10 +129,10 @@ _srcdir=`dirname $0`
if type mktemp > /dev/null 2>&1 ; then if type mktemp > /dev/null 2>&1 ; then
TMPO=`mktemp /tmp/scummvm-conf.XXXXXXXXXX` TMPO=`mktemp /tmp/scummvm-conf.XXXXXXXXXX`
else else
TMPO=${_srcdir}/scummvm-conf TMPO=scummvm-conf
fi fi
TMPC=${TMPO}.cpp TMPC=${TMPO}.cpp
TMPLOG=${_srcdir}/config.log TMPLOG=config.log
# For cross compiling # For cross compiling
_host="" _host=""

View file

@ -7,7 +7,7 @@
# Prologue information # Prologue information
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
Name : scummvm Name : scummvm
Version : 0.12.0svn Version : 0.13.0svn
Release : 1 Release : 1
Summary : Graphic adventure game interpreter Summary : Graphic adventure game interpreter
Group : Interpreters Group : Interpreters

View file

@ -7,8 +7,8 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico"
#endif #endif
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,12,0,0 FILEVERSION 0,13,0,0
PRODUCTVERSION 0,12,0,0 PRODUCTVERSION 0,13,0,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -25,13 +25,13 @@ BEGIN
BEGIN BEGIN
VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0" VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0"
VALUE "FileDescription", "http://www.scummvm.org/\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 "InternalName", "scummvm\0"
VALUE "LegalCopyright", "Copyright © 2001-2007 The ScummVM Team\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 "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 "OriginalFilename", "scummvm.exe\0"
VALUE "ProductName", "ScummVM\0" VALUE "ProductName", "ScummVM\0"
VALUE "ProductVersion", "0.12.0svn\0" VALUE "ProductVersion", "0.13.0svn\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -8,7 +8,7 @@ if [ "$TMP" = "" ]; then
fi fi
PKG=$TMP/package-scummvm PKG=$TMP/package-scummvm
VERSION=0.12.0svn VERSION=0.13.0svn
ARCH=i486 ARCH=i486
BUILD=1 BUILD=1

View file

@ -1076,6 +1076,8 @@ protected:
virtual void drawImage(VC10_state *state); virtual void drawImage(VC10_state *state);
void drawBackGroundImage(VC10_state *state); void drawBackGroundImage(VC10_state *state);
void drawVertImage(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); void setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height);

View file

@ -744,10 +744,6 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) {
} }
void AGOSEngine::drawBackGroundImage(VC10_state *state) { void AGOSEngine::drawBackGroundImage(VC10_state *state) {
const byte *src;
byte *dst;
uint h, i;
state->width = _screenWidth; state->width = _screenWidth;
if (_window3Flag == 1) { if (_window3Flag == 1) {
state->width = 0; state->width = 0;
@ -755,15 +751,19 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) {
state->y_skip = 0; state->y_skip = 0;
} }
src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); const byte* src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8);
dst = state->surf_addr; byte* dst = state->surf_addr;
state->draw_width *= 2; 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 { do {
for (i = 0; i != state->draw_width; i++) for (uint i = 0; i != w; i+=2) {
dst[i] = src[i] + state->paletteMod; dst[i] = src[i] + paletteMod;
dst[i+1] = src[i+1] + paletteMod;
}
dst += state->surf_pitch; dst += state->surf_pitch;
src += state->width; src += state->width;
} while (--h); } while (--h);
@ -771,63 +771,86 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) {
void AGOSEngine::drawVertImage(VC10_state *state) { void AGOSEngine::drawVertImage(VC10_state *state) {
if (state->flags & kDFCompressed) { if (state->flags & kDFCompressed) {
uint w, h; drawVertImageCompressed(state);
byte *src, *dst, *dstPtr; } else {
drawVertImageUncompressed(state);
}
}
state->x_skip *= 4; /* reached */ void AGOSEngine::drawVertImageUncompressed(VC10_state *state) {
assert ((state->flags & kDFCompressed) == 0) ;
state->dl = state->width; const byte *src;
state->dh = state->height; 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; do {
if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ for (count = 0; count != state->draw_width; count++) {
dstPtr += vcReadVar(252);
}
w = 0;
do {
byte color; 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); void AGOSEngine::drawVertImageCompressed(VC10_state *state) {
dst = dstPtr; assert (state->flags & kDFCompressed) ;
uint w, h;
h = 0; state->x_skip *= 4; /* reached */
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 { do {
color = (*src / 16); byte colors = *src;
if ((state->flags & kDFNonTrans) || color != 0) 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 {
byte colors = *src;
color = (colors / 16);
if (color != 0)
dst[0] = color | state->palette; dst[0] = color | state->palette;
color = (*src & 15); color = (colors & 15);
if ((state->flags & kDFNonTrans) || color != 0) if (color != 0)
dst[1] = color | state->palette; dst[1] = color | state->palette;
dst += state->surf_pitch; dst += state->surf_pitch;
src++; src++;
} while (++h != state->draw_height); } while (++h != state->draw_height);
dstPtr += 2; }
} while (++w != state->draw_width); dstPtr += 2;
} else { } while (++w != state->draw_width);
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);
}
} }
void AGOSEngine::drawImage(VC10_state *state) { void AGOSEngine::drawImage(VC10_state *state) {

View file

@ -94,6 +94,7 @@ public:
Common::StringList _volumeResourceFiles; Common::StringList _volumeResourceFiles;
StringPtrHashMap _volumeEntriesMap; StringPtrHashMap _volumeEntriesMap;
TextHandler _textHandler;
private: private:
void initialize(void); void initialize(void);
@ -107,6 +108,7 @@ private:
extern CineEngine *g_cine; extern CineEngine *g_cine;
#define BOOT_PRC_NAME "AUTO00.PRC" #define BOOT_PRC_NAME "AUTO00.PRC"
#define COPY_PROT_FAIL_PRC_NAME "L201.ANI"
enum { enum {
VAR_MOUSE_X_MODE = 253, VAR_MOUSE_X_MODE = 253,

View file

@ -337,7 +337,7 @@ int FWRenderer::drawChar(char character, int x, int y) {
x += 5; x += 5;
} else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) {
idx = fontParamTable[(unsigned char)character].characterIdx; 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; x += width + 1;
} }
@ -938,7 +938,7 @@ int OSRenderer::drawChar(char character, int x, int y) {
x += 5; x += 5;
} else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) {
idx = fontParamTable[(unsigned char)character].characterIdx; 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; x += width + 1;
} }

View file

@ -41,8 +41,9 @@ ScriptList objectScripts;
/*! \todo Is script size of 0 valid? /*! \todo Is script size of 0 valid?
* \todo Fix script dump code * \todo Fix script dump code
* @return Was the loading successful?
*/ */
void loadPrc(const char *pPrcName) { bool loadPrc(const char *pPrcName) {
byte i; byte i;
uint16 numScripts; uint16 numScripts;
byte *scriptPtr, *dataPtr; byte *scriptPtr, *dataPtr;
@ -53,11 +54,11 @@ void loadPrc(const char *pPrcName) {
scriptTable.clear(); scriptTable.clear();
// This is copy protection. Used to hang the machine // This is copy protection. Used to hang the machine
if (!scumm_stricmp(pPrcName, "L201.ANI")) { if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) {
Common::Event event; Common::Event event;
event.type = Common::EVENT_RTL; event.type = Common::EVENT_RTL;
g_system->getEventManager()->pushEvent(event); g_system->getEventManager()->pushEvent(event);
return; return false;
} }
checkDataDisk(-1); checkDataDisk(-1);
@ -110,6 +111,8 @@ void loadPrc(const char *pPrcName) {
} }
} }
#endif #endif
return true;
} }
} // End of namespace Cine } // End of namespace Cine

View file

@ -31,7 +31,7 @@ namespace Cine {
extern ScriptList globalScripts; extern ScriptList globalScripts;
extern ScriptList objectScripts; extern ScriptList objectScripts;
void loadPrc(const char *pPrcName); bool loadPrc(const char *pPrcName);
} // End of namespace Cine } // End of namespace Cine

View file

@ -1019,6 +1019,20 @@ int FWScript::o1_divVar() {
} }
int FWScript::o1_compareVar() { 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 varIdx = getNextByte();
byte varType = getNextByte(); byte varType = getNextByte();

View file

@ -31,8 +31,6 @@ namespace Cine {
byte *textDataPtr; byte *textDataPtr;
byte textTable[256][2][16 * 8];
const char **failureMessages; const char **failureMessages;
const CommandeType *defaultActionCommand; const CommandeType *defaultActionCommand;
const CommandeType *systemMenu; const CommandeType *systemMenu;
@ -77,14 +75,14 @@ void loadTextData(const char *pFileName, byte *pDestinationBuffer) {
loadRelatedPalette(pFileName); loadRelatedPalette(pFileName);
for (i = 0; i < numCharacters; i++) { for (i = 0; i < numCharacters; i++) {
gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 16, 8); gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 16, 8);
generateMask(textTable[i][0], textTable[i][1], 16 * 8, 0); generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 16 * 8, 0);
tempBuffer += dataSize; tempBuffer += dataSize;
} }
} else { } else {
for (i = 0; i < 90; i++) { for (i = 0; i < 90; i++) {
gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 8, 8); gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 8, 8);
generateMask(textTable[i][0], textTable[i][1], 8 * 8, 0); generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 8 * 8, 0);
tempBuffer += 0x40; tempBuffer += 0x40;
} }
} }

View file

@ -34,7 +34,10 @@ namespace Cine {
typedef char CommandeType[20]; typedef char CommandeType[20];
extern byte *textDataPtr; extern byte *textDataPtr;
extern byte textTable[256][2][16 * 8];
struct TextHandler {
byte textTable[256][2][16 * 8];
};
extern const char **failureMessages; extern const char **failureMessages;
extern const CommandeType *defaultActionCommand; extern const CommandeType *defaultActionCommand;

View file

@ -464,17 +464,26 @@ bool CineEngine::makeLoad(char *saveName) {
broken = brokenSave(*fHandle); broken = brokenSave(*fHandle);
// At savefile position 0x0000:
currentDisk = fHandle->readUint16BE(); currentDisk = fHandle->readUint16BE();
// At 0x0002:
fHandle->read(currentPartName, 13); fHandle->read(currentPartName, 13);
// At 0x000F:
fHandle->read(currentDatName, 13); fHandle->read(currentDatName, 13);
// At 0x001C:
saveVar2 = fHandle->readSint16BE(); saveVar2 = fHandle->readSint16BE();
// At 0x001E:
fHandle->read(currentPrcName, 13); fHandle->read(currentPrcName, 13);
// At 0x002B:
fHandle->read(currentRelName, 13); fHandle->read(currentRelName, 13);
// At 0x0038:
fHandle->read(currentMsgName, 13); fHandle->read(currentMsgName, 13);
// At 0x0045:
fHandle->read(bgName, 13); fHandle->read(bgName, 13);
// At 0x0052:
fHandle->read(currentCtName, 13); fHandle->read(currentCtName, 13);
checkDataDisk(currentDisk); checkDataDisk(currentDisk);
@ -499,52 +508,84 @@ bool CineEngine::makeLoad(char *saveName) {
loadCtFW(currentCtName); loadCtFW(currentCtName);
} }
// At 0x005F:
fHandle->readUint16BE(); fHandle->readUint16BE();
// At 0x0061:
fHandle->readUint16BE(); fHandle->readUint16BE();
// At 0x0063:
for (i = 0; i < 255; i++) { for (i = 0; i < 255; i++) {
// At 0x0063 + i * 32 + 0:
objectTable[i].x = fHandle->readSint16BE(); objectTable[i].x = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 2:
objectTable[i].y = fHandle->readSint16BE(); objectTable[i].y = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 4:
objectTable[i].mask = fHandle->readUint16BE(); objectTable[i].mask = fHandle->readUint16BE();
// At 0x0063 + i * 32 + 6:
objectTable[i].frame = fHandle->readSint16BE(); objectTable[i].frame = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 8:
objectTable[i].costume = fHandle->readSint16BE(); objectTable[i].costume = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 10:
fHandle->read(objectTable[i].name, 20); fHandle->read(objectTable[i].name, 20);
// At 0x0063 + i * 32 + 30:
objectTable[i].part = fHandle->readUint16BE(); objectTable[i].part = fHandle->readUint16BE();
} }
// At 0x2043 (i.e. 0x0063 + 255 * 32):
renderer->restorePalette(*fHandle); renderer->restorePalette(*fHandle);
// At 0x2083 (i.e. 0x2043 + 16 * 2 * 2):
globalVars.load(*fHandle, NUM_MAX_VAR - 1); globalVars.load(*fHandle, NUM_MAX_VAR - 1);
// At 0x2281 (i.e. 0x2083 + 255 * 2):
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
// At 0x2281 + i * 2:
zoneData[i] = fHandle->readUint16BE(); zoneData[i] = fHandle->readUint16BE();
} }
// At 0x22A1 (i.e. 0x2281 + 16 * 2):
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
// At 0x22A1 + i * 2:
commandVar3[i] = fHandle->readUint16BE(); commandVar3[i] = fHandle->readUint16BE();
} }
// At 0x22A9 (i.e. 0x22A1 + 4 * 2):
fHandle->read(commandBuffer, 0x50); fHandle->read(commandBuffer, 0x50);
renderer->setCommand(commandBuffer); renderer->setCommand(commandBuffer);
// At 0x22F9 (i.e. 0x22A9 + 0x50):
renderer->_cmdY = fHandle->readUint16BE(); renderer->_cmdY = fHandle->readUint16BE();
// At 0x22FB:
bgVar0 = fHandle->readUint16BE(); bgVar0 = fHandle->readUint16BE();
// At 0x22FD:
allowPlayerInput = fHandle->readUint16BE(); allowPlayerInput = fHandle->readUint16BE();
// At 0x22FF:
playerCommand = fHandle->readSint16BE(); playerCommand = fHandle->readSint16BE();
// At 0x2301:
commandVar1 = fHandle->readSint16BE(); commandVar1 = fHandle->readSint16BE();
// At 0x2303:
isDrawCommandEnabled = fHandle->readUint16BE(); isDrawCommandEnabled = fHandle->readUint16BE();
// At 0x2305:
var5 = fHandle->readUint16BE(); var5 = fHandle->readUint16BE();
// At 0x2307:
var4 = fHandle->readUint16BE(); var4 = fHandle->readUint16BE();
// At 0x2309:
var3 = fHandle->readUint16BE(); var3 = fHandle->readUint16BE();
// At 0x230B:
var2 = fHandle->readUint16BE(); var2 = fHandle->readUint16BE();
// At 0x230D:
commandVar2 = fHandle->readSint16BE(); commandVar2 = fHandle->readSint16BE();
// At 0x230F:
renderer->_messageBg = fHandle->readUint16BE(); renderer->_messageBg = fHandle->readUint16BE();
// At 0x2311:
fHandle->readUint16BE(); fHandle->readUint16BE();
// At 0x2313:
fHandle->readUint16BE(); fHandle->readUint16BE();
// At 0x2315:
loadResourcesFromSave(*fHandle, broken); loadResourcesFromSave(*fHandle, broken);
// TODO: handle screen params (really required ?) // TODO: handle screen params (really required ?)
@ -1516,12 +1557,22 @@ void mainLoopSub6(void) {
void checkForPendingDataLoad(void) { void checkForPendingDataLoad(void) {
if (newPrcName[0] != 0) { if (newPrcName[0] != 0) {
loadPrc(newPrcName); bool loadPrcOk = loadPrc(newPrcName);
strcpy(currentPrcName, newPrcName); strcpy(currentPrcName, newPrcName);
strcpy(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) { if (newRelName[0] != 0) {

View file

@ -112,7 +112,7 @@ int KyraEngine_v1::init() {
_sound = new SoundTownsPC98_v2(this, _mixer); _sound = new SoundTownsPC98_v2(this, _mixer);
} else if (_flags.platform == Common::kPlatformPC98) { } else if (_flags.platform == Common::kPlatformPC98) {
if (_flags.gameID == GI_KYRA1) if (_flags.gameID == GI_KYRA1)
_sound = new SoundPC98(this, _mixer); _sound = new SoundTowns/*SoundPC98*/(this, _mixer);
else else
_sound = new SoundTownsPC98_v2(this, _mixer); _sound = new SoundTownsPC98_v2(this, _mixer);
} else if (midiDriver == MD_ADLIB) { } else if (midiDriver == MD_ADLIB) {

View file

@ -2363,7 +2363,7 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) :
_numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false),
_numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) {
setTempo(84); setTempo(84);
_baserate = (3579545.0 / (double)getRate()) / 144.0; _baserate = (double)getRate() / 10368.0;
} }
TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { TownsPC98_OpnDriver::~TownsPC98_OpnDriver() {
@ -3095,8 +3095,8 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() {
} }
bool SoundTownsPC98_v2::init() { bool SoundTownsPC98_v2::init() {
_driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? _driver = new TownsPC98_OpnDriver(_mixer, /*_vm->gameFlags().platform == Common::kPlatformPC98 ?
TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); TownsPC98_OpnDriver::OD_TYPE86 :*/ TownsPC98_OpnDriver::OD_TOWNS);
_useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false;
_vm->checkCD(); _vm->checkCD();
// FIXME: While checking for 'track1.XXX(X)' looks like // FIXME: While checking for 'track1.XXX(X)' looks like

View file

@ -1034,8 +1034,10 @@ void KyraEngine_LoK::initStaticResource() {
} }
// audio data tables // audio data tables
#if 0
static const char *tIntro98[] = { "intro%d.dat" }; static const char *tIntro98[] = { "intro%d.dat" };
static const char *tIngame98[] = { "kyram%d.dat" }; static const char *tIngame98[] = { "kyram%d.dat" };
#endif
static const AudioDataStruct soundData_PC[] = { static const AudioDataStruct soundData_PC[] = {
{ _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, { _soundFilesIntro, _soundFilesIntroSize, 0, 0 },
@ -1049,18 +1051,20 @@ void KyraEngine_LoK::initStaticResource() {
{ 0, 0, 0, 0} { 0, 0, 0, 0}
}; };
#if 0
static const AudioDataStruct soundData_PC98[] = { static const AudioDataStruct soundData_PC98[] = {
{ tIntro98, 1, 0, 0 }, { tIntro98, 1, 0, 0 },
{ tIngame98, 1, 0, 0 }, { tIngame98, 1, 0, 0 },
{ 0, 0, 0, 0} { 0, 0, 0, 0}
}; };
#endif
if (_flags.platform == Common::kPlatformPC) if (_flags.platform == Common::kPlatformPC)
_soundData = soundData_PC; _soundData = soundData_PC;
else if (_flags.platform == Common::kPlatformFMTowns) else if (_flags.platform == Common::kPlatformFMTowns)
_soundData = soundData_TOWNS; _soundData = soundData_TOWNS;
else if (_flags.platform == Common::kPlatformPC98) 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 *fmtMusicFileListFinale[] = { "finale%d.twn" };
static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" };
#if 0
static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; static const char *pc98MusicFileListIntro[] = { "intro%d.86" };
static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListFinale[] = { "finale%d.86" };
static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" };
#endif
static const AudioDataStruct soundData_PC[] = { static const AudioDataStruct soundData_PC[] = {
{ _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, { _musicFileListIntro, _musicFileListIntroSize, 0, 0 },
@ -1275,18 +1281,20 @@ void KyraEngine_HoF::initStaticResource() {
{ fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 }
}; };
#if 0
static const AudioDataStruct soundData_PC98[] = { static const AudioDataStruct soundData_PC98[] = {
{ pc98MusicFileListIntro, 1, 0, 0 }, { pc98MusicFileListIntro, 1, 0, 0 },
{ pc98MusicFileListIngame, 1, 0, 0 }, { pc98MusicFileListIngame, 1, 0, 0 },
{ pc98MusicFileListFinale, 1, 0, 0 } { pc98MusicFileListFinale, 1, 0, 0 }
}; };
#endif
if (_flags.platform == Common::kPlatformPC) if (_flags.platform == Common::kPlatformPC)
_soundData = soundData_PC; _soundData = soundData_PC;
else if (_flags.platform == Common::kPlatformFMTowns) else if (_flags.platform == Common::kPlatformFMTowns)
_soundData = soundData_TOWNS; _soundData = soundData_TOWNS;
else if (_flags.platform == Common::kPlatformPC98) else if (_flags.platform == Common::kPlatformPC98)
_soundData = soundData_PC98; _soundData = soundData_TOWNS/*soundData_PC98*/;
// setup sequence data // setup sequence data
_sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize);

View file

@ -36,7 +36,7 @@ namespace Lure {
#define LURE_DAT_MAJOR 1 #define LURE_DAT_MAJOR 1
#define LURE_DAT_MINOR 29 #define LURE_DAT_MINOR 29
#define LURE_MIN_SAVEGAME_MINOR 25 #define LURE_MIN_SAVEGAME_MINOR 25
#define LURE_SAVEGAME_MINOR 32 #define LURE_SAVEGAME_MINOR 33
#define LURE_DEBUG 1 #define LURE_DEBUG 1

View file

@ -456,6 +456,8 @@ void HotspotData::saveToStream(WriteStream *stream) {
stream->writeSint16LE(startY); stream->writeSint16LE(startY);
stream->writeUint16LE(roomNumber); stream->writeUint16LE(roomNumber);
stream->writeByte(layer); stream->writeByte(layer);
stream->writeUint16LE(walkX);
stream->writeUint16LE(walkY);
stream->writeUint16LE(width); stream->writeUint16LE(width);
stream->writeUint16LE(height); stream->writeUint16LE(height);
@ -503,6 +505,10 @@ void HotspotData::loadFromStream(ReadStream *stream) {
uint8 saveVersion = LureEngine::getReference().saveVersion(); uint8 saveVersion = LureEngine::getReference().saveVersion();
if (saveVersion >= 29) if (saveVersion >= 29)
layer = stream->readByte(); layer = stream->readByte();
if (saveVersion >= 33) {
walkX = stream->readUint16LE();
walkY = stream->readUint16LE();
}
width = stream->readUint16LE(); width = stream->readUint16LE();
height = stream->readUint16LE(); height = stream->readUint16LE();

View file

@ -424,6 +424,7 @@ void Parallaction_ns::_c_testResult(void *parm) {
} }
_inTestResult = true; _inTestResult = true;
_gfx->freeLabels();
_gfx->updateScreen(); _gfx->updateScreen();
_disk->selectArchive("disk1"); _disk->selectArchive("disk1");

View file

@ -42,13 +42,23 @@ namespace Parallaction {
#define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_X 10
#define ANSWER_CHARACTER_Y 80 #define ANSWER_CHARACTER_Y 80
class DialogueManager { class DialogueManager {
enum {
RUN_QUESTION,
RUN_ANSWER,
NEXT_QUESTION,
NEXT_ANSWER,
DIALOGUE_OVER
} _state;
Parallaction *_vm; Parallaction *_vm;
SpeakData *_data;
Dialogue *_dialogue; Dialogue *_dialogue;
bool _askPassword; bool _askPassword;
int _passwordLen;
bool _passwordChanged;
bool isNpc; bool isNpc;
GfxObj *_questioner; GfxObj *_questioner;
@ -59,92 +69,69 @@ class DialogueManager {
uint16 _visAnswers[5]; uint16 _visAnswers[5];
int _numVisAnswers; int _numVisAnswers;
int _answerId;
int _selection, _oldSelection;
uint32 _mouseButtons;
Common::Point _mousePos;
bool _isKeyDown;
uint16 _downKey;
public: public:
DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) { DialogueManager(Parallaction *vm, ZonePtr z);
_dialogue = _data->_dialogue; ~DialogueManager();
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() { bool isOver() {
if (isNpc) { return _state == DIALOGUE_OVER;
delete _questioner;
}
} }
void run(); void run();
ZonePtr _z;
CommandList *_cmdList;
protected: protected:
void displayQuestion(); bool displayQuestion();
bool displayAnswers(); bool displayAnswers();
bool displayAnswer(uint16 i); bool displayAnswer(uint16 i);
uint16 getAnswer(); int16 selectAnswer1();
int16 selectAnswer(); int16 selectAnswerN();
uint16 askPassword(); int16 askPassword();
int16 getHoverAnswer(int16 x, int16 y); int16 getHoverAnswer(int16 x, int16 y);
void runQuestion();
void runAnswer();
void nextQuestion();
void nextAnswer();
bool checkPassword();
void resetPassword();
void accumPassword(uint16 ascii);
}; };
uint16 DialogueManager::askPassword() { DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) {
debugC(3, kDebugExec, "checkDialoguePassword()"); _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;
uint16 passwordLen = 0; _askPassword = false;
_password[0] = '\0'; _q = _dialogue->_questions[0];
_vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); _cmdList = 0;
int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); _answerId = 0;
_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_KEYDOWN) && isdigit(e.kbd.ascii)) {
_password[passwordLen] = e.kbd.ascii;
passwordLen++;
_password[passwordLen] = '\0';
changed = true;
}
}
if (changed) {
_vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3);
_vm->_gfx->updateScreen();
changed = false;
}
if ((passwordLen == MAX_PASSWORD_LENGTH) || (e.kbd.ascii == Common::KEYCODE_RETURN)) {
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))) {
break;
} else {
passwordLen = 0;
_password[0] = '\0';
changed = true;
}
}
g_system->delayMillis(20);
}
_vm->hideDialogueStuff();
return 0;
_state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER;
} }
DialogueManager::~DialogueManager() {
if (isNpc) {
delete _questioner;
}
_z = nullZonePtr;
}
bool DialogueManager::displayAnswer(uint16 i) { bool DialogueManager::displayAnswer(uint16 i) {
@ -161,7 +148,7 @@ bool DialogueManager::displayAnswer(uint16 i) {
assert(id >= 0); assert(id >= 0);
_visAnswers[id] = i; _visAnswers[id] = i;
_askPassword = (strstr(a->_text, "%p") != NULL); _askPassword = (strstr(a->_text, "%P") != NULL);
_numVisAnswers++; _numVisAnswers++;
return true; return true;
@ -178,134 +165,244 @@ bool DialogueManager::displayAnswers() {
displayAnswer(i); 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; return _numVisAnswers > 0;
} }
void DialogueManager::displayQuestion() { bool DialogueManager::displayQuestion() {
if (!scumm_stricmp(_q->_text, "NULL")) return false;
if (!scumm_stricmp(_q->_text, "NULL")) return;
_vm->_balloonMan->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); int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y);
_vm->_gfx->setItemFrame(id, _q->_mood & 0xF); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF);
_vm->_gfx->updateScreen(); return true;
_vm->_input->waitUntilLeftClick();
_vm->hideDialogueStuff();
return;
} }
uint16 DialogueManager::getAnswer() {
uint16 answer = 0; 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)));
}
if (_askPassword == false) { void DialogueManager::resetPassword() {
answer = selectAnswer(); _passwordLen = 0;
} else { _password[0] = '\0';
answer = askPassword(); _passwordChanged = true;
}
void DialogueManager::accumPassword(uint16 ascii) {
if (!isdigit(ascii)) {
return;
} }
debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer); _password[_passwordLen] = ascii;
_passwordLen++;
_password[_passwordLen] = '\0';
_passwordChanged = true;
}
return answer; int16 DialogueManager::askPassword() {
if (_isKeyDown) {
accumPassword(_downKey);
}
if (_passwordChanged) {
_vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3);
_passwordChanged = false;
}
if ((_passwordLen == MAX_PASSWORD_LENGTH) || ((_isKeyDown) && (_downKey == Common::KEYCODE_RETURN))) {
if (checkPassword()) {
return 0;
} else {
resetPassword();
}
}
return -1;
}
int16 DialogueManager::selectAnswer1() {
if (_mouseButtons == kMouseLeftUp) {
return 0;
}
return -1;
}
int16 DialogueManager::selectAnswerN() {
_selection = _vm->_balloonMan->hitTestDialogueBalloon(_mousePos.x, _mousePos.y);
if (_selection != _oldSelection) {
if (_oldSelection != -1) {
_vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3);
}
if (_vm->quit())
return -1;
if (_selection != -1) {
_vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0);
_vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF);
}
}
_oldSelection = _selection;
if ((_mouseButtons == kMouseLeftUp) && (_selection != -1)) {
return _visAnswers[_selection];
}
return -1;
}
void DialogueManager::runQuestion() {
debugC(9, kDebugDialogue, "runQuestion\n");
if (_mouseButtons == kMouseLeftUp) {
_vm->hideDialogueStuff();
_state = NEXT_ANSWER;
}
}
void DialogueManager::nextAnswer() {
debugC(9, kDebugDialogue, "nextAnswer\n");
if (_q->_answers[0] == NULL) {
_state = DIALOGUE_OVER;
return;
}
if (!scumm_stricmp(_q->_answers[0]->_text, "NULL")) {
_answerId = 0;
_state = NEXT_QUESTION;
return;
}
_state = displayAnswers() ? RUN_ANSWER : DIALOGUE_OVER;
}
void DialogueManager::runAnswer() {
debugC(9, kDebugDialogue, "runAnswer\n");
if (_askPassword) {
_answerId = askPassword();
} else
if (_numVisAnswers == 1) {
_answerId = selectAnswer1();
} else {
_answerId = selectAnswerN();
}
if (_answerId != -1) {
_cmdList = &_q->_answers[_answerId]->_commands;
_vm->hideDialogueStuff();
_state = NEXT_QUESTION;
}
}
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;
}
} }
void DialogueManager::run() { void DialogueManager::run() {
_askPassword = false; // cache event data
CommandList *cmdlist = NULL; _mouseButtons = _vm->_input->getLastButtonEvent();
_vm->_input->getCursorPos(_mousePos);
_isKeyDown = _vm->_input->getLastKeyDown(_downKey);
_q = _dialogue->_questions[0]; switch (_state) {
int16 answer; case RUN_QUESTION:
runQuestion();
break;
while (_q) { case NEXT_ANSWER:
nextAnswer();
break;
answer = 0; case NEXT_QUESTION:
nextQuestion();
break;
displayQuestion(); case RUN_ANSWER:
runAnswer();
break;
if (_vm->quit()) case DIALOGUE_OVER:
return; if (_cmdList) {
_vm->_cmdExec->run(*_cmdList);
if (_q->_answers[0] == NULL) break;
if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) {
if (!displayAnswers()) break;
answer = getAnswer();
if (_vm->quit())
return;
cmdlist = &_q->_answers[answer]->_commands;
} }
break;
default:
error("unknown state in DialogueManager");
_q = _q->_answers[answer]->_following._question;
} }
if (cmdlist)
_vm->_cmdExec->run(*cmdlist);
} }
int16 DialogueManager::selectAnswer() { void Parallaction::enterDialogueMode(ZonePtr z) {
debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u.speak->_name);
int16 numAvailableAnswers = _numVisAnswers; _dialogueMan = new DialogueManager(this, z);
_input->_inputMode = Input::kInputModeDialogue;
int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
_vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF);
if (numAvailableAnswers == 1) {
_vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 0);
_vm->_input->waitUntilLeftClick();
_vm->hideDialogueStuff();
return 0;
}
int oldSelection = -1;
int selection = 0;
uint32 event;
Common::Point p;
while (!_vm->quit()) {
_vm->_input->readInput();
_vm->_input->getCursorPos(p);
event = _vm->_input->getLastButtonEvent();
selection = _vm->_balloonMan->hitTestDialogueBalloon(p.x, p.y);
if (selection != oldSelection) {
if (oldSelection != -1) {
_vm->_balloonMan->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3);
}
if (selection != -1) {
_vm->_balloonMan->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0);
_vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF);
}
}
if ((selection != -1) && (event == kMouseLeftUp)) {
break;
}
_vm->_gfx->updateScreen();
g_system->delayMillis(20);
oldSelection = selection;
}
_vm->hideDialogueStuff();
return _visAnswers[selection];
} }
void Parallaction::exitDialogueMode() {
debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()");
_input->_inputMode = Input::kInputModeGame;
void Parallaction::runDialogue(SpeakData *data) { // The current instance of _dialogueMan must be destroyed before the zone commands
debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name); // 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); _cmdExec->run(z->_commands, z);
man.run(); }
void Parallaction::runDialogueFrame() {
if (_input->_inputMode != Input::kInputModeDialogue) {
return;
}
_dialogueMan->run();
if (_dialogueMan->isOver()) {
exitDialogueMode();
}
return; return;
} }

View file

@ -224,7 +224,11 @@ DECLARE_COMMAND_OPCODE(start) {
DECLARE_COMMAND_OPCODE(speak) { DECLARE_COMMAND_OPCODE(speak) {
_vm->_activeZone = _ctxt.cmd->u._zone; if ((_ctxt.cmd->u._zone->_type & 0xFFFF) == kZoneSpeak) {
_vm->enterDialogueMode(_ctxt.cmd->u._zone);
} else {
_vm->_activeZone = _ctxt.cmd->u._zone;
}
} }
@ -322,6 +326,7 @@ DECLARE_COMMAND_OPCODE(stop) {
void Parallaction_ns::drawAnimations() { void Parallaction_ns::drawAnimations() {
debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n");
uint16 layer = 0; uint16 layer = 0;
@ -362,6 +367,8 @@ void Parallaction_ns::drawAnimations() {
} }
} }
debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n");
return; return;
} }
@ -417,7 +424,6 @@ label1:
return; return;
} }
void CommandExec::run(CommandList& list, ZonePtr z) { void CommandExec::run(CommandList& list, ZonePtr z) {
if (list.size() == 0) { if (list.size() == 0) {
debugC(3, kDebugExec, "runCommands: nothing to do"); debugC(3, kDebugExec, "runCommands: nothing to do");
@ -542,11 +548,8 @@ uint16 Parallaction::runZone(ZonePtr z) {
break; break;
case kZoneSpeak: case kZoneSpeak:
runDialogue(z->u.speak); enterDialogueMode(z);
if (_vm->quit()) return 0;
return 0;
break;
} }
debugC(3, kDebugExec, "runZone completed"); debugC(3, kDebugExec, "runZone completed");

View file

@ -267,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 #if 0
void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {

View file

@ -33,6 +33,11 @@
namespace Parallaction { 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) { void Gfx::registerVar(const Common::String &name, int32 initialValue) {
if (_vars.contains(name)) { if (_vars.contains(name)) {
warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str()); warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str());
@ -752,6 +757,9 @@ Gfx::Gfx(Parallaction* vm) :
_halfbrite = false; _halfbrite = false;
_hbCircleRadius = 0; _hbCircleRadius = 0;
_unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE];
assert(_unpackedBitmap);
registerVar("background_mode", 1); registerVar("background_mode", 1);
_varBackgroundMode = 1; _varBackgroundMode = 1;
@ -769,6 +777,8 @@ Gfx::~Gfx() {
freeBackground(); freeBackground();
freeLabels(); freeLabels();
delete []_unpackedBitmap;
return; return;
} }

View file

@ -547,6 +547,8 @@ public:
uint _screenX; // scrolling position uint _screenX; // scrolling position
uint _screenY; uint _screenY;
byte *_unpackedBitmap;
protected: protected:
Parallaction* _vm; Parallaction* _vm;
bool _halfbrite; bool _halfbrite;

View file

@ -42,12 +42,14 @@ uint16 Input::readInput() {
uint16 KeyDown = 0; uint16 KeyDown = 0;
_mouseButtons = kMouseNone; _mouseButtons = kMouseNone;
_lastKeyDownAscii = -1;
Common::EventManager *eventMan = _vm->_system->getEventManager(); Common::EventManager *eventMan = _vm->_system->getEventManager();
while (eventMan->pollEvent(e)) { while (eventMan->pollEvent(e)) {
switch (e.type) { switch (e.type) {
case Common::EVENT_KEYDOWN: case Common::EVENT_KEYDOWN:
_lastKeyDownAscii = e.kbd.ascii;
if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd') if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd')
_vm->_debugger->attach(); _vm->_debugger->attach();
if (_vm->getFeatures() & GF_DEMO) break; 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() // FIXME: see comment for readInput()
void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) {
@ -192,11 +199,38 @@ InputData* Input::updateInput() {
case kInputModeGame: case kInputModeGame:
updateGameInput(); updateGameInput();
break; break;
case kInputModeDialogue:
readInput();
break;
} }
return &_inputData; 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() { bool Input::translateGameInput() {
if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) { if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) {
@ -231,23 +265,10 @@ bool Input::translateGameInput() {
return true; return true;
} }
if ((z != _hoverZone) && (_hoverZone)) { trackMouse(z);
_hoverZone = nullZonePtr; if (!z) {
_inputData._event = kEvExitZone; return true;
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;
}
if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) {

View file

@ -66,6 +66,7 @@ class Input {
Common::Point _mousePos; Common::Point _mousePos;
uint16 _mouseButtons; uint16 _mouseButtons;
int32 _lastKeyDownAscii;
bool _mouseHidden; bool _mouseHidden;
ZonePtr _hoverZone; ZonePtr _hoverZone;
@ -73,7 +74,8 @@ class Input {
public: public:
enum { enum {
kInputModeGame = 0, kInputModeGame = 0,
kInputModeComment = 1 kInputModeComment = 1,
kInputModeDialogue = 2
}; };
@ -99,14 +101,13 @@ public:
uint16 readInput(); uint16 readInput();
InputData* updateInput(); InputData* updateInput();
void trackMouse(ZonePtr z);
void waitUntilLeftClick(); void waitUntilLeftClick();
void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1);
uint32 getLastButtonEvent() { return _mouseButtons; } uint32 getLastButtonEvent() { return _mouseButtons; }
bool getLastKeyDown(uint16 &ascii);
void stopHovering() { void stopHovering();
_hoverZone = nullZonePtr;
}
}; };
} // namespace Parallaction } // namespace Parallaction

View file

@ -164,6 +164,11 @@ void Parallaction::updateView() {
} }
void Parallaction::hideDialogueStuff() {
_gfx->freeItems();
_balloonMan->freeBalloons();
}
void Parallaction::freeCharacter() { void Parallaction::freeCharacter() {
debugC(1, kDebugExec, "freeCharacter()"); debugC(1, kDebugExec, "freeCharacter()");
@ -297,16 +302,6 @@ void Parallaction::showLocationComment(const char *text, bool end) {
void Parallaction::processInput(InputData *data) { void Parallaction::processInput(InputData *data) {
switch (data->_event) { 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: case kEvAction:
debugC(2, kDebugInput, "processInput: kEvAction"); debugC(2, kDebugInput, "processInput: kEvAction");
_input->stopHovering(); _input->stopHovering();
@ -317,7 +312,6 @@ void Parallaction::processInput(InputData *data) {
case kEvOpenInventory: case kEvOpenInventory:
_input->stopHovering(); _input->stopHovering();
_gfx->hideFloatingLabel();
if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) {
setArrowCursor(); setArrowCursor();
} }
@ -367,25 +361,29 @@ void Parallaction::processInput(InputData *data) {
void Parallaction::runGame() { void Parallaction::runGame() {
InputData *data = _input->updateInput(); InputData *data = _input->updateInput();
if (data->_event != kEvNone) { if (_vm->quit())
processInput(data); return;
if (_input->_inputMode == Input::kInputModeDialogue) {
runDialogueFrame();
} else {
if (data->_event != kEvNone) {
processInput(data);
}
if (_vm->quit())
return;
runPendingZones();
if (_vm->quit())
return;
if (_engineFlags & kEngineChangeLocation) {
changeLocation(_location._name);
}
} }
if (_vm->quit())
return;
runPendingZones();
if (_vm->quit())
return;
if (_engineFlags & kEngineChangeLocation) {
changeLocation(_location._name);
}
if (_vm->quit())
return;
_gfx->beginFrame(); _gfx->beginFrame();
if (_input->_inputMode == Input::kInputModeGame) { if (_input->_inputMode == Input::kInputModeGame) {
@ -400,7 +398,6 @@ void Parallaction::runGame() {
// change this to endFrame? // change this to endFrame?
updateView(); updateView();
} }
@ -668,6 +665,7 @@ void Parallaction::beep() {
} }
void Parallaction::scheduleLocationSwitch(const char *location) { void Parallaction::scheduleLocationSwitch(const char *location) {
debugC(9, kDebugExec, "scheduleLocationSwitch(%s)\n", location);
strcpy(_location._name, location); strcpy(_location._name, location);
_engineFlags |= kEngineChangeLocation; _engineFlags |= kEngineChangeLocation;
} }

View file

@ -113,8 +113,6 @@ enum EngineFlags {
enum { enum {
kEvNone = 0, kEvNone = 0,
kEvEnterZone = 1,
kEvExitZone = 2,
kEvAction = 3, kEvAction = 3,
kEvOpenInventory = 4, kEvOpenInventory = 4,
kEvCloseInventory = 5, kEvCloseInventory = 5,
@ -164,6 +162,7 @@ class Debugger;
class Gfx; class Gfx;
class SoundMan; class SoundMan;
class Input; class Input;
class DialogueManager;
struct Location { struct Location {
@ -281,8 +280,6 @@ public:
uint16 runZone(ZonePtr z); uint16 runZone(ZonePtr z);
void freeZones(); void freeZones();
void runDialogue(SpeakData*);
AnimationPtr findAnimation(const char *name); AnimationPtr findAnimation(const char *name);
void freeAnimations(); void freeAnimations();
@ -425,10 +422,11 @@ public:
void setupBalloonManager(); void setupBalloonManager();
void hideDialogueStuff() { void hideDialogueStuff();
_gfx->freeItems(); DialogueManager *_dialogueMan;
_balloonMan->freeBalloons(); void enterDialogueMode(ZonePtr z);
} void exitDialogueMode();
void runDialogueFrame();
}; };

View file

@ -212,13 +212,21 @@ void Parallaction_br::runPendingZones() {
if (_activeZone) { if (_activeZone) {
z = _activeZone; // speak Zone or sound z = _activeZone; // speak Zone or sound
_activeZone = nullZonePtr; _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) { if (_activeZone2) {
z = _activeZone2; // speak Zone or sound z = _activeZone2; // speak Zone or sound
_activeZone2 = nullZonePtr; _activeZone2 = nullZonePtr;
runZone(z); if ((z->_type & 0xFFFF) == kZoneSpeak) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
}
} }
} }

View file

@ -191,7 +191,7 @@ void Parallaction_ns::setArrowCursor() {
debugC(1, kDebugInput, "setting mouse cursor to arrow"); debugC(1, kDebugInput, "setting mouse cursor to arrow");
// this stuff is needed to avoid artifacts with labels and selected items when switching cursors // this stuff is needed to avoid artifacts with labels and selected items when switching cursors
_gfx->hideFloatingLabel(); _input->stopHovering();
_input->_activeItem._id = 0; _input->_activeItem._id = 0;
_system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0);
@ -302,12 +302,11 @@ void Parallaction_ns::changeLocation(char *location) {
_soundMan->playLocationMusic(location); _soundMan->playLocationMusic(location);
_gfx->hideFloatingLabel(); _input->stopHovering();
_gfx->freeLabels(); _gfx->freeLabels();
_zoneTrap = nullZonePtr; _zoneTrap = nullZonePtr;
_input->stopHovering();
if (_engineFlags & kEngineBlockInput) { if (_engineFlags & kEngineBlockInput) {
setArrowCursor(); setArrowCursor();
} }
@ -420,6 +419,7 @@ void Parallaction_ns::changeCharacter(const char *name) {
Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1");
_char._ani->gfxobj = _gfx->loadAnim(_char.getFullName()); _char._ani->gfxobj = _gfx->loadAnim(_char.getFullName());
_char._ani->gfxobj->setFlags(kGfxObjCharacter); _char._ani->gfxobj->setFlags(kGfxObjCharacter);
_char._ani->gfxobj->clearFlags(kGfxObjNormal);
if (!_char.dummy()) { if (!_char.dummy()) {
if (getPlatform() == Common::kPlatformAmiga) { if (getPlatform() == Common::kPlatformAmiga) {

View file

@ -354,6 +354,7 @@ void Parallaction_ns::walk(Character &character) {
if (newPos == curPos) { if (newPos == curPos) {
debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle");
finalizeWalk(character); finalizeWalk(character);
targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected
} }
} }

View file

@ -1175,15 +1175,8 @@ BamScene::BamScene(QueenEngine *vm)
} }
void BamScene::playSfx() { void BamScene::playSfx() {
// Don't try to play all the sounds. This is only necessary for the _vm->sound()->playSfx(_vm->logic()->currentRoomSfx());
// fight bam, in which the number of 'sfx bam frames' is too much _lastSoundIndex = _index;
// 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;
}
} }
void BamScene::prepareAnimation() { void BamScene::prepareAnimation() {

View file

@ -248,10 +248,6 @@ public:
F_REQ_STOP = 2 F_REQ_STOP = 2
}; };
enum {
SFX_SKIP = 8
};
uint16 _flag, _index; uint16 _flag, _index;
private: private:

View file

@ -227,11 +227,6 @@ void PCSound::setVolume(int vol) {
_music->setVolume(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) { void PCSound::playSound(const char *base, bool isSpeech) {
char name[13]; char name[13];
strcpy(name, base); strcpy(name, base);
@ -241,7 +236,13 @@ void PCSound::playSound(const char *base, bool isSpeech) {
name[i] = '0'; name[i] = '0';
} }
strcat(name, ".SB"); strcat(name, ".SB");
waitFinished(isSpeech); if (isSpeech) {
while (_mixer->isSoundHandleActive(_speechHandle)) {
_vm->input()->delay(10);
}
} else {
_mixer->stopHandle(_sfxHandle);
}
uint32 size; uint32 size;
Common::File *f = _vm->resource()->findSound(name, &size); Common::File *f = _vm->resource()->findSound(name, &size);
if (f) { if (f) {
@ -253,6 +254,8 @@ void PCSound::playSound(const char *base, bool isSpeech) {
} }
void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { 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; int headerSize;
f->seek(2, SEEK_CUR); f->seek(2, SEEK_CUR);
uint16 version = f->readUint16LE(); uint16 version = f->readUint16LE();

View file

@ -143,7 +143,6 @@ public:
void setVolume(int vol); void setVolume(int vol);
protected: protected:
void waitFinished(bool isSpeech);
void playSound(const char *base, bool isSpeech); void playSound(const char *base, bool isSpeech);
virtual void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) = 0; virtual void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) = 0;

View file

@ -949,7 +949,7 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const {
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList; 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 // Obtain the last 2 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 2); int slotNum = atoi(file->c_str() + file->size() - 2);

View file

@ -297,7 +297,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
break; break;
case GUI::kListSelectionChangedCmd: { case GUI::kListSelectionChangedCmd: {
if (_gfxWidget) { if (_gfxWidget) {
updateInfos(); updateInfos(true);
} }
if (_saveMode) { if (_saveMode) {
@ -350,7 +350,7 @@ void SaveLoadChooser::reflowLayout() {
_fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR"); _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR");
_fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG"); _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG");
_fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB"); _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB");
updateInfos(); updateInfos(false);
} else { } else {
_container->setFlags(GUI::WIDGET_INVISIBLE); _container->setFlags(GUI::WIDGET_INVISIBLE);
_gfxWidget->setFlags(GUI::WIDGET_INVISIBLE); _gfxWidget->setFlags(GUI::WIDGET_INVISIBLE);
@ -362,7 +362,7 @@ void SaveLoadChooser::reflowLayout() {
Dialog::reflowLayout(); Dialog::reflowLayout();
} }
void SaveLoadChooser::updateInfos() { void SaveLoadChooser::updateInfos(bool redraw) {
int selItem = _list->getSelected(); int selItem = _list->getSelected();
Graphics::Surface *thumb; Graphics::Surface *thumb;
thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem); thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
@ -376,7 +376,8 @@ void SaveLoadChooser::updateInfos() {
} }
delete thumb; delete thumb;
_gfxWidget->draw(); if (redraw)
_gfxWidget->draw();
InfoStuff infos; InfoStuff infos;
memset(&infos, 0, sizeof(InfoStuff)); memset(&infos, 0, sizeof(InfoStuff));
@ -386,12 +387,14 @@ void SaveLoadChooser::updateInfos() {
(infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF, (infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF,
infos.date & 0xFFFF); infos.date & 0xFFFF);
_date->setLabel(buffer); _date->setLabel(buffer);
_date->draw(); if (redraw)
_date->draw();
snprintf(buffer, 32, "Time: %.2d:%.2d", snprintf(buffer, 32, "Time: %.2d:%.2d",
(infos.time >> 8) & 0xFF, infos.time & 0xFF); (infos.time >> 8) & 0xFF, infos.time & 0xFF);
_time->setLabel(buffer); _time->setLabel(buffer);
_time->draw(); if (redraw)
_time->draw();
int minutes = infos.playtime / 60; int minutes = infos.playtime / 60;
int hours = minutes / 60; int hours = minutes / 60;
@ -400,19 +403,23 @@ void SaveLoadChooser::updateInfos() {
snprintf(buffer, 32, "Playtime: %.2d:%.2d", snprintf(buffer, 32, "Playtime: %.2d:%.2d",
hours & 0xFF, minutes & 0xFF); hours & 0xFF, minutes & 0xFF);
_playtime->setLabel(buffer); _playtime->setLabel(buffer);
_playtime->draw(); if (redraw)
_playtime->draw();
} else { } else {
snprintf(buffer, 32, "No date saved"); snprintf(buffer, 32, "No date saved");
_date->setLabel(buffer); _date->setLabel(buffer);
_date->draw(); if (redraw)
_date->draw();
snprintf(buffer, 32, "No time saved"); snprintf(buffer, 32, "No time saved");
_time->setLabel(buffer); _time->setLabel(buffer);
_time->draw(); if (redraw)
_time->draw();
snprintf(buffer, 32, "No playtime saved"); snprintf(buffer, 32, "No playtime saved");
_playtime->setLabel(buffer); _playtime->setLabel(buffer);
_playtime->draw(); if (redraw)
_playtime->draw();
} }
} }

View file

@ -69,7 +69,7 @@ protected:
uint8 _fillR, _fillG, _fillB; uint8 _fillR, _fillG, _fillB;
void updateInfos(); void updateInfos(bool redraw);
public: public:
SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine); SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine);
~SaveLoadChooser(); ~SaveLoadChooser();

View file

@ -102,10 +102,10 @@ void ImuseDigiSndMgr::prepareSoundFromRMAP(Common::File *file, SoundDesc *sound,
int32 version = file->readUint32BE(); int32 version = file->readUint32BE();
if (version != 3) { if (version != 3) {
if (version == 2) { if (version == 2) {
warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 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("Suggested to recompress with latest tool from daily builds");
} else } 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->bits = file->readUint32BE();
sound->freq = file->readUint32BE(); sound->freq = file->readUint32BE();

View file

@ -52,9 +52,11 @@ namespace Sword2 {
static Audio::AudioStream *makeCLUStream(Common::File *fp, int size); static Audio::AudioStream *makeCLUStream(Common::File *fp, int size);
static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) { 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()) { if (!fh->file.isOpen()) {
alreadyOpen = false;
struct { struct {
const char *ext; const char *ext;
int mode; int mode;
@ -75,16 +77,14 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base,
char filename[20]; char filename[20];
for (int i = 0; i < ARRAYSIZE(file_types); i++) { for (int i = 0; i < ARRAYSIZE(file_types); i++) {
Common::File f;
sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext); 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; soundMode = file_types[i].mode;
break; break;
} }
sprintf(filename, "%s.%s", base, file_types[i].ext); sprintf(filename, "%s.%s", base, file_types[i].ext);
if (f.open(filename)) { if (Common::File::exists(filename)) {
soundMode = file_types[i].mode; soundMode = file_types[i].mode;
break; break;
} }
@ -105,7 +105,8 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base,
fh->idxTab = NULL; fh->idxTab = NULL;
} }
} }
} } else
alreadyOpen = true;
uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3; uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3;
@ -134,7 +135,13 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base,
*numSamples = len; *numSamples = len;
if (!pos || !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; return NULL;
} }

View file

@ -106,7 +106,7 @@ private:
void refill(); void refill();
inline bool eosIntern() const { inline bool eosIntern() const {
return _pos >= _bufferEnd; return !_file->isOpen() || _pos >= _bufferEnd;
} }
public: public:

View file

@ -5,16 +5,25 @@
class StringTestSuite : public CxxTest::TestSuite class StringTestSuite : public CxxTest::TestSuite
{ {
public: 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"); Common::String str("test");
TS_ASSERT( !str.empty() ); TS_ASSERT( !str.empty() );
str.clear(); str.clear();
TS_ASSERT( str.empty() ); TS_ASSERT( str.empty() );
} }
void test_lastChar( void ) void test_lastChar(void) {
{
Common::String str; Common::String str;
TS_ASSERT_EQUALS( str.lastChar(), '\0' ); TS_ASSERT_EQUALS( str.lastChar(), '\0' );
str = "test"; str = "test";
@ -23,8 +32,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( str2.lastChar(), 'r' ); TS_ASSERT_EQUALS( str2.lastChar(), 'r' );
} }
void test_concat1( void ) void test_concat1(void) {
{
Common::String str("foo"); Common::String str("foo");
Common::String str2("bar"); Common::String str2("bar");
str += str2; str += str2;
@ -32,22 +40,19 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( str2, "bar" ); TS_ASSERT_EQUALS( str2, "bar" );
} }
void test_concat2( void ) void test_concat2(void) {
{
Common::String str("foo"); Common::String str("foo");
str += "bar"; str += "bar";
TS_ASSERT_EQUALS( str, "foobar" ); TS_ASSERT_EQUALS( str, "foobar" );
} }
void test_concat3( void ) void test_concat3(void) {
{
Common::String str("foo"); Common::String str("foo");
str += 'X'; str += 'X';
TS_ASSERT_EQUALS( str, "fooX" ); TS_ASSERT_EQUALS( str, "fooX" );
} }
void test_refCount( void ) void test_refCount(void) {
{
Common::String foo1("foo"); Common::String foo1("foo");
Common::String foo2("foo"); Common::String foo2("foo");
Common::String foo3(foo2); Common::String foo3(foo2);
@ -57,8 +62,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( foo3, "foo""X" ); TS_ASSERT_EQUALS( foo3, "foo""X" );
} }
void test_refCount2( void ) void test_refCount2(void) {
{
Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
Common::String foo3(foo2); Common::String foo3(foo2);
@ -68,8 +72,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""X" ); TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""X" );
} }
void test_refCount3( void ) void test_refCount3(void) {
{
Common::String foo1("0123456789abcdefghijk"); Common::String foo1("0123456789abcdefghijk");
Common::String foo2("0123456789abcdefghijk"); Common::String foo2("0123456789abcdefghijk");
Common::String foo3(foo2); Common::String foo3(foo2);
@ -79,8 +82,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( foo3, "0123456789abcdefghijk""0123456789abcdefghijk" ); TS_ASSERT_EQUALS( foo3, "0123456789abcdefghijk""0123456789abcdefghijk" );
} }
void test_refCount4( void ) void test_refCount4(void) {
{
Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
Common::String foo3(foo2); Common::String foo3(foo2);
@ -90,8 +92,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd" ); TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd" );
} }
void test_hasPrefix( void ) void test_hasPrefix(void) {
{
Common::String str("this/is/a/test, haha"); Common::String str("this/is/a/test, haha");
TS_ASSERT_EQUALS( str.hasPrefix(""), true ); TS_ASSERT_EQUALS( str.hasPrefix(""), true );
TS_ASSERT_EQUALS( str.hasPrefix("this"), true ); TS_ASSERT_EQUALS( str.hasPrefix("this"), true );
@ -99,8 +100,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( str.hasPrefix("foo"), false ); TS_ASSERT_EQUALS( str.hasPrefix("foo"), false );
} }
void test_hasSuffix( void ) void test_hasSuffix(void) {
{
Common::String str("this/is/a/test, haha"); Common::String str("this/is/a/test, haha");
TS_ASSERT_EQUALS( str.hasSuffix(""), true ); TS_ASSERT_EQUALS( str.hasSuffix(""), true );
TS_ASSERT_EQUALS( str.hasSuffix("haha"), true ); TS_ASSERT_EQUALS( str.hasSuffix("haha"), true );
@ -108,8 +108,7 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( str.hasSuffix("hahah"), false ); TS_ASSERT_EQUALS( str.hasSuffix("hahah"), false );
} }
void test_contains( void ) void test_contains(void) {
{
Common::String str("this/is/a/test, haha"); Common::String str("this/is/a/test, haha");
TS_ASSERT_EQUALS( str.contains(""), true ); TS_ASSERT_EQUALS( str.contains(""), true );
TS_ASSERT_EQUALS( str.contains("haha"), true ); TS_ASSERT_EQUALS( str.contains("haha"), true );
@ -117,15 +116,13 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( str.contains("test"), true ); TS_ASSERT_EQUALS( str.contains("test"), true );
} }
void test_toLowercase( void ) void test_toLowercase(void) {
{
Common::String str("Test it, NOW! 42"); Common::String str("Test it, NOW! 42");
str.toLowercase(); str.toLowercase();
TS_ASSERT_EQUALS( str, "test it, now! 42" ); TS_ASSERT_EQUALS( str, "test it, now! 42" );
} }
void test_toUppercase( void ) void test_toUppercase(void) {
{
Common::String str("Test it, NOW! 42"); Common::String str("Test it, NOW! 42");
str.toUppercase(); str.toUppercase();
TS_ASSERT_EQUALS( str, "TEST IT, NOW! 42" ); TS_ASSERT_EQUALS( str, "TEST IT, NOW! 42" );