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

View File

@ -19,16 +19,17 @@ RM = rm -f
srcdir = ../../..
VPATH = $(srcdir)
INCDIR = ../../../
DEPDIR = .deps
DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_MPEG2 -DUSE_ZLIB -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar
# PS2SDK-Ports from ps2dev.org's SVN repository for libmad, zlib and ucl
PS2SDK_PORTS = /home/robby/libStuffNew/ps2sdk-ports
PS2SDK_PORTS = /mnt/winxp/scummvm/ports
PS2SDK_PORTS_INCS = /ucl /zlib/include /libmad/ee/include
PS2SDK_PORTS_LIBS = /ucl /zlib/lib /libmad/ee/lib
# we also need SjPcm, Tremor and libmpeg2
MORE_LIBS_DIR = /home/robby/libStuff
MORE_LIBS_DIR = /mnt/winxp/scummvm/ports
MORE_LIBS_INCS = /SjPcm/ee/src /mpeg2dec/include /tremor
MORE_LIBS_LIBS = /SjPcm/ee/lib /mpeg2dec/libmpeg2 /tremor/tremor

View File

@ -340,8 +340,6 @@ FILE *ps2_fopen(const char *fname, const char *mode) {
assert(cacheListSema >= 0);
}
//printf("ps2_fopen: %s, %s\n", fname, mode);
if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) {
printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname);
return NULL;
@ -363,6 +361,8 @@ FILE *ps2_fopen(const char *fname, const char *mode) {
} else {
// Regular access to one of the devices
printf("ps2_fopen = %s\n", fname); // romeo : temp
if (!rdOnly)
return NULL; // we only provide readaccess for cd,dvd,hdd,usb
@ -378,19 +378,22 @@ FILE *ps2_fopen(const char *fname, const char *mode) {
}
int64 cacheId = -1;
if (rdOnly && tocManager.haveEntries())
if (tocManager.haveEntries())
cacheId = tocManager.fileExists(fname);
if (cacheId != 0) {
Ps2File *file = findInCache(cacheId);
if (file)
if (file) {
printf(" findInCache(%x)\n", cacheId); // romeo : temp
return (FILE*)file;
}
bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun");
file = new Ps2ReadFile(cacheId, isAudioFile);
if (file->open(fname)) {
openFileCount++;
printf(" new cacheID = %x\n", cacheId); // romeo : temp
return (FILE*)file;
} else
delete file;
@ -579,7 +582,7 @@ void TocManager::readEntries(const char *root) {
}
char readPath[256];
sprintf(readPath, "%s/", _root);
printf("readDir: %s\n", readPath);
printf("readDir: %s (root: %s )\n", readPath, root);
readDir(readPath, &_rootNode, 0);
}
@ -587,28 +590,62 @@ void TocManager::readDir(const char *path, TocNode **node, int level) {
if (level <= 2) { // we don't scan deeper than that
iox_dirent_t dirent;
int fd = fio.dopen(path);
if (fd >= 0) {
while (fio.dread(fd, &dirent) > 0)
if (dirent.name[0] != '.') { // skip '.' and '..'
*node = new TocNode;
(*node)->sub = (*node)->next = NULL;
TocNode *eNode = NULL; // = *node; // entry node
bool first = true;
printf("path=%s - level=%d fd=%d\n", path, level, fd); // romeo : temp
if (fd >= 0) {
while (fio.dread(fd, &dirent) > 0) {
if (dirent.name[0] != '.') { // skip '.' & '..' - romeo : check
// --- do we have them on PS2?
*node = new TocNode;
if (first) {
eNode = *node;
first = false;
}
(*node)->sub = (*node)->next = NULL;
(*node)->nameLen = strlen(dirent.name);
memcpy((*node)->name, dirent.name, (*node)->nameLen + 1);
if (dirent.stat.mode & FIO_S_IFDIR) { // directory
if (dirent.stat.mode & FIO_S_IFDIR) {
(*node)->isDir = true;
char nextPath[256];
sprintf(nextPath, "%s%s/", path, dirent.name);
readDir(nextPath, &((*node)->sub), level + 1);
} else
printf("dirent.name = %s [DIR]\n", dirent.name);
}
else {
(*node)->isDir = false;
printf("dirent.name = %s\n", dirent.name);
}
node = &((*node)->next);
}
}
fio.dclose(fd);
} else
printf("Can't open path: %s\n", path);
}
TocNode *iNode = eNode;
char nextPath[256];
while (iNode) {
if (iNode->isDir == true) {
sprintf(nextPath, "%s%s/", path, iNode->name);
readDir(nextPath, &(iNode->sub), level + 1);
}
iNode = iNode->next;
}
}
/*
** Wizard of Oz' trick (to get all games running from USB on PS2):
1. Make a list of files / dirs in level #0 (dclose before continuing)
2. Go through the dirs : dopen / dread them / mark dirs / dclose
It's a safe recursion, cause it recurses on 'isDir' nodes
after dclosing the higher hierarchy
*/
}
int64 TocManager::fileExists(const char *name) {

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 },
{ "LIBSD", BIOS, NOTHING, NULL, 0 },
{ "IOMANX.IRX", SYSTEM | NOT_HOST, NOTHING, NULL, 0 }, // already loaded by ps2link
{ "IOMANX.IRX", SYSTEM /*| NOT_HOST*/, NOTHING, NULL, 0 }, // already loaded by ps2link
{ "FILEXIO.IRX", SYSTEM, NOTHING, NULL, 0 },
{ "CODYVDFS.IRX", SYSTEM, NOTHING, NULL, 0 },
{ "SJPCM.IRX", SYSTEM, NOTHING, NULL, 0 },

View File

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

View File

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

View File

@ -191,7 +191,7 @@ OSystem_SDL::OSystem_SDL()
OSystem_SDL::~OSystem_SDL() {
SDL_RemoveTimer(_timerID);
SDL_CloseAudio();
closeMixer();
free(_dirtyChecksums);
free(_currentPalette);
@ -199,7 +199,6 @@ OSystem_SDL::~OSystem_SDL() {
free(_mouseData);
delete _savefile;
delete _mixer;
delete _timer;
}
@ -306,7 +305,7 @@ void OSystem_SDL::quit() {
SDL_ShowCursor(SDL_ENABLE);
SDL_RemoveTimer(_timerID);
SDL_CloseAudio();
closeMixer();
free(_dirtyChecksums);
free(_currentPalette);
@ -314,7 +313,6 @@ void OSystem_SDL::quit() {
free(_mouseData);
delete _savefile;
delete _mixer;
delete _timer;
SDL_Quit();
@ -389,14 +387,110 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) {
#pragma mark --- Audio ---
#pragma mark -
#ifdef MIXER_DOUBLE_BUFFERING
void OSystem_SDL::mixerProducerThread() {
byte nextSoundBuffer;
SDL_LockMutex(_soundMutex);
while (true) {
// Wait till we are allowed to produce data
SDL_CondWait(_soundCond, _soundMutex);
if (_soundThreadShouldQuit)
break;
// Generate samples and put them into the next buffer
nextSoundBuffer = _activeSoundBuf ^ 1;
_mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize);
// Swap buffers
_activeSoundBuf = nextSoundBuffer;
}
SDL_UnlockMutex(_soundMutex);
}
int SDLCALL OSystem_SDL::mixerProducerThreadEntry(void *arg) {
OSystem_SDL *this_ = (OSystem_SDL *)arg;
assert(this_);
this_->mixerProducerThread();
return 0;
}
void OSystem_SDL::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) {
_soundThreadIsRunning = false;
_soundThreadShouldQuit = false;
// Create mutex and condition variable
_soundMutex = SDL_CreateMutex();
_soundCond = SDL_CreateCond();
// Create two sound buffers
_activeSoundBuf = 0;
_soundBufSize = bufSize;
_soundBuffers[0] = (byte *)calloc(1, bufSize);
_soundBuffers[1] = (byte *)calloc(1, bufSize);
_soundThreadIsRunning = true;
// Finally start the thread
_soundThread = SDL_CreateThread(mixerProducerThreadEntry, this);
}
void OSystem_SDL::deinitThreadedMixer() {
// Kill thread?? _soundThread
if (_soundThreadIsRunning) {
// Signal the producer thread to end, and wait for it to actually finish.
_soundThreadShouldQuit = true;
SDL_CondBroadcast(_soundCond);
SDL_WaitThread(_soundThread, NULL);
// Kill the mutex & cond variables.
// Attention: AT this point, the mixer callback must not be running
// anymore, else we will crash!
SDL_DestroyMutex(_soundMutex);
SDL_DestroyCond(_soundCond);
_soundThreadIsRunning = false;
free(_soundBuffers[0]);
free(_soundBuffers[1]);
}
}
void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) {
OSystem_SDL *this_ = (OSystem_SDL *)arg;
assert(this_);
assert(this_->_mixer);
assert((int)this_->_soundBufSize == len);
// Lock mutex, to ensure our data is not overwritten by the producer thread
SDL_LockMutex(this_->_soundMutex);
// Copy data from the current sound buffer
memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len);
// Unlock mutex and wake up the produced thread
SDL_UnlockMutex(this_->_soundMutex);
SDL_CondSignal(this_->_soundCond);
}
#else
void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) {
OSystem_SDL *this_ = (OSystem_SDL *)sys;
assert(this_);
assert(this_->_mixer);
if (this_->_mixer)
this_->_mixer->mixCallback(samples, len);
this_->_mixer->mixCallback(samples, len);
}
#endif
void OSystem_SDL::setupMixer() {
SDL_AudioSpec desired;
SDL_AudioSpec obtained;
@ -443,10 +537,31 @@ void OSystem_SDL::setupMixer() {
// Tell the mixer that we are ready and start the sound processing
_mixer->setOutputRate(_samplesPerSec);
_mixer->setReady(true);
#ifdef MIXER_DOUBLE_BUFFERING
initThreadedMixer(_mixer, obtained.samples * 4);
#endif
// start the sound system
SDL_PauseAudio(0);
}
}
void OSystem_SDL::closeMixer() {
if (_mixer)
_mixer->setReady(false);
SDL_CloseAudio();
delete _mixer;
_mixer = 0;
#ifdef MIXER_DOUBLE_BUFFERING
deinitThreadedMixer();
#endif
}
Audio::Mixer *OSystem_SDL::getMixer() {
assert(_mixer);
return _mixer;

View File

@ -51,6 +51,15 @@ namespace Common {
#define USE_OSD 1
#endif
#if defined(MACOSX)
// On Mac OS X, we need to double buffer the audio buffer, else anything
// which produces sampled data with high latency (like the MT-32 emulator)
// will sound terribly.
// This could be enabled for more / most ports in the future, but needs some
// testing.
#define MIXER_DOUBLE_BUFFERING 1
#endif
enum {
GFX_NORMAL = 0,
@ -137,6 +146,8 @@ public:
virtual void setupMixer();
static void mixCallback(void *s, byte *samples, int len);
virtual void closeMixer();
virtual Audio::Mixer *getMixer();
// Poll CD status
@ -369,6 +380,23 @@ protected:
*/
MutexRef _graphicsMutex;
#ifdef MIXER_DOUBLE_BUFFERING
SDL_mutex *_soundMutex;
SDL_cond *_soundCond;
SDL_Thread *_soundThread;
bool _soundThreadIsRunning;
bool _soundThreadShouldQuit;
byte _activeSoundBuf;
uint _soundBufSize;
byte *_soundBuffers[2];
void mixerProducerThread();
static int SDLCALL mixerProducerThreadEntry(void *arg);
void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize);
void deinitThreadedMixer();
#endif
Common::SaveFileManager *_savefile;
Audio::MixerImpl *_mixer;
@ -377,7 +405,7 @@ protected:
Common::TimerManager *_timer;
protected:
void addDirtyRgnAuto(const byte *buf);
void makeChecksums(const byte *buf);

View File

@ -226,28 +226,31 @@
$VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines";
# now one for each ready-for-release engine
if (0)
{
foreach (@WorkingEngines)
{
$VariationSets{'ALL'}{$_} = "$DefaultFeatures $_";
}
# for scumm, we need to add 2 features:
$VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he";
#$VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he";
}
# now one for each not-ready-for-release-or-testing engine
if (0)
{
foreach (@TestingEngines)
{
$VariationSets{'ALL'}{"test_$_"} = "$DefaultFeatures $_";
}
}
# below here you could specify weird & experimental combinations, non-ready engines
# a small version of the saga engine, because it is so big (no tremor,mad,zlib)
$VariationSets{'ALL'}{'saga_mini'} = "saga";
#$VariationSets{'ALL'}{'saga_mini'} = "saga";
# a smaller version of scumm without support for v7, v8 and HE games
$VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm";
#$VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm";
# maybe you feel lucky and want to test the sword engines? :P
#$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2";

View File

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

View File

@ -1,8 +1,34 @@
/* MISSING.C
Implementation for standard and semi-standard C library calls missing in WinCE
environment.
by Vasyl Tsvirkunov
*/
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
/* Original code:
* Implementation for standard and semi-standard C library calls missing in WinCE
* environment.
* by Vasyl Tsvirkunov
*/
#include <windows.h>
#include <tchar.h>
@ -17,19 +43,8 @@
#include "time.h"
#include "dirent.h"
/* forward declaration */
#if _WIN32_WCE < 300
#define _STDAFX_H
#include "portdefs.h"
#else
char *strdup(const char *strSource);
#endif
#ifdef __GNUC__
#define EXT_C extern "C"
#else
@ -40,19 +55,27 @@ char *strdup(const char *strSource);
void *bsearch(const void *key, const void *base, size_t nmemb,
size_t size, int (*compar)(const void *, const void *)) {
size_t i;
// Perform binary search
size_t lo = 0;
size_t hi = nmemb;
while (lo < hi) {
size_t mid = (lo + hi) / 2;
const void *p = ((const char *)base) + mid * size;
int tmp = (*compar)(key, p);
if (tmp < 0)
hi = mid;
else if (tmp > 0)
lo = mid + 1;
else
return (void *)p;
}
for (i=0; i<nmemb; i++)
if (compar(key, (void*)((size_t)base + size * i)) == 0)
return (void*)((size_t)base + size * i);
return NULL;
}
static WIN32_FIND_DATA wfd;
/* Very limited implementation of stat. Used by UI.C, MEMORY-P.C (latter is not critical) */
int stat(const char *fname, struct stat *ss)
{
int stat(const char *fname, struct stat *ss) {
TCHAR fnameUnc[MAX_PATH+1];
HANDLE handle;
int len;
@ -63,8 +86,7 @@ int stat(const char *fname, struct stat *ss)
/* Special case (dummy on WinCE) */
len = strlen(fname);
if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' &&
(len == 2 || fname[len-3] == '\\'))
{
(len == 2 || fname[len-3] == '\\')) {
/* That's everything implemented so far */
memset(ss, 0, sizeof(struct stat));
ss->st_size = 1024;
@ -74,6 +96,7 @@ int stat(const char *fname, struct stat *ss)
MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH);
handle = FindFirstFile(fnameUnc, &wfd);
FindClose(handle);
if (handle == INVALID_HANDLE_VALUE)
return -1;
else
@ -83,20 +106,16 @@ int stat(const char *fname, struct stat *ss)
ss->st_size = wfd.nFileSizeLow;
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ss->st_mode |= S_IFDIR;
FindClose(handle);
}
return 0;
}
char cwd[MAX_PATH+1] = "";
EXT_C char *getcwd(char *buffer, int maxlen)
{
EXT_C char *getcwd(char *buffer, int maxlen) {
TCHAR fileUnc[MAX_PATH+1];
char* plast;
if (cwd[0] == 0)
{
if (cwd[0] == 0) {
GetModuleFileName(NULL, fileUnc, MAX_PATH);
WideCharToMultiByte(CP_ACP, 0, fileUnc, -1, cwd, MAX_PATH, NULL, NULL);
plast = strrchr(cwd, '\\');
@ -114,8 +133,7 @@ EXT_C char *getcwd(char *buffer, int maxlen)
#ifdef __GNUC__
#undef GetCurrentDirectory
#endif
EXT_C void GetCurrentDirectory(int len, char *buf)
{
EXT_C void GetCurrentDirectory(int len, char *buf) {
getcwd(buf,len);
};
@ -125,26 +143,22 @@ fully qualified paths refer to root folder rather
than current folder (concept not implemented in CE).
*/
#undef fopen
EXT_C FILE *wce_fopen(const char* fname, const char* fmode)
{
EXT_C FILE *wce_fopen(const char* fname, const char* fmode) {
char fullname[MAX_PATH+1];
if (!fname || fname[0] == '\0')
return NULL;
if (fname[0] != '\\' && fname[0] != '/')
{
if (fname[0] != '\\' && fname[0] != '/') {
getcwd(fullname, MAX_PATH);
strncat(fullname, "\\", MAX_PATH-strlen(fullname)-1);
strncat(fullname, fname, MAX_PATH-strlen(fullname)-strlen(fname));
return fopen(fullname, fmode);
}
else
} else
return fopen(fname, fmode);
}
/* Remove file by name */
int remove(const char* path)
{
int remove(const char* path) {
TCHAR pathUnc[MAX_PATH+1];
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
return !DeleteFile(pathUnc);
@ -158,14 +172,22 @@ int _access(const char *path, int mode) {
WIN32_FIND_DATA ffd;
HANDLE h=FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
FindClose(h);
if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) {
// WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry
// hits for files that don't exist. Checking for the same fname twice
// seems to weed out those false positives.
HANDLE h=FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
return 0; //Always return success if target is directory and exists
}
switch (mode) {
case 00: //Check existence
return 0;
@ -183,8 +205,7 @@ int _access(const char *path, int mode) {
#ifndef __GNUC__
/* Limited dirent implementation. Used by UI.C and DEVICES.C */
DIR* opendir(const char* fname)
{
DIR* opendir(const char* fname) {
DIR* pdir;
char fnameMask[MAX_PATH+1];
TCHAR fnameUnc[MAX_PATH+1];
@ -209,13 +230,10 @@ DIR* opendir(const char* fname)
strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */
MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH);
if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE)
{
if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) {
free(pdir);
return NULL;
}
else
{
} else {
WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL);
pdir->dd_dir.d_name = strdup(nameFound);
@ -224,34 +242,25 @@ DIR* opendir(const char* fname)
return pdir;
}
struct dirent* readdir(DIR* dir)
{
struct dirent* readdir(DIR* dir) {
char nameFound[MAX_PATH+1];
static struct dirent dummy;
if (dir->dd_stat == 0)
{
if (dir->dd_stat == 0) {
dummy.d_name = ".";
dummy.d_namlen = 1;
dir->dd_stat ++;
return &dummy;
}
else if (dir->dd_stat == 1)
{
} else if (dir->dd_stat == 1) {
dummy.d_name = "..";
dummy.d_namlen = 2;
dir->dd_stat ++;
return &dummy;
}
else if (dir->dd_stat == 2)
{
} else if (dir->dd_stat == 2) {
dir->dd_stat++;
return &dir->dd_dir;
}
else
{
if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0)
{
} else {
if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) {
dir->dd_stat = -1;
return NULL;
}
@ -283,12 +292,6 @@ int closedir(DIR* dir)
return 1;
}
/* in our case unlink is the same as remove */
int unlink(const char* path)
{
return remove(path);
}
/* Make directory, Unix style */
void mkdir(char* dirname, int mode)
{
@ -299,10 +302,8 @@ void mkdir(char* dirname, int mode)
if (*path == '/')
*path = '\\';
/* Run through the string and attempt creating all subdirs on the path */
for (ptr = path+1; *ptr; ptr ++)
{
if (*ptr == '\\' || *ptr == '/')
{
for (ptr = path+1; *ptr; ptr ++) {
if (*ptr == '\\' || *ptr == '/') {
*ptr = 0;
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
CreateDirectory(pathUnc, 0);
@ -313,373 +314,40 @@ void mkdir(char* dirname, int mode)
CreateDirectory(pathUnc, 0);
}
/* Used in DEVICES.C and UI.C for some purpose. Not critical in this port */
int system(const char* path) { return 0; }
#if 0
char *tmpnam(char *string)
{
TCHAR pTemp[MAX_PATH+1];
static char buffer[MAX_PATH+1];
GetTempFileName(TEXT("."), TEXT("A8_"), 0, pTemp);
WideCharToMultiByte(CP_ACP, 0, pTemp, -1, buffer, MAX_PATH, NULL, NULL);
if (string)
{
strcpy(string, buffer);
return string;
}
else
return buffer;
}
FILE *tmpfile()
{
TCHAR pTemp[MAX_PATH+1];
if (!GetTempFileName(TEXT("."), TEXT("A8_"), 0, pTemp))
return _wfopen(pTemp, TEXT("w+b"));
else
return 0;
}
#endif
void rewind(FILE *stream)
{
fseek(stream, 0, SEEK_SET);
}
#if _WIN32_WCE < 300
int isalnum(int c) {
return ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9'));
}
char *_strdup(const char *strSource)
#else
char *strdup(const char *strSource)
#endif
{
char* buffer;
buffer = (char*)malloc(strlen(strSource)+1);
size_z len = strlen(strSource)+1;
buffer = (char*)malloc(len);
if (buffer)
strcpy(buffer, strSource);
memcpy(buffer, strSource, len);
return buffer;
}
/* Very limited implementation of sys/time.h */
void usleep(long usec)
{
long msec = usec/1000;
if (msec <= 0)
Sleep(0);
else
Sleep(msec);
}
/* This may provide for better sync mechanism */
unsigned int clock()
{
return GetTickCount();
}
/* And why do people use this? */
#if _WIN32_WCE >= 300
void abort()
{
exit(1);
}
#endif
/*
IMHO, no project should use this one, it is not portable at all. This implementation
at least allows some projects to work.
*/
char* getenv(char* name)
{
static char buffer[MAX_PATH+1];
if (strcmp(name, "HOME") == 0 || strcmp(name, "HOMEDIR") == 0)
{
getcwd(buffer, MAX_PATH);
return buffer;
}
else
return "";
}
#if _WIN32_WCE < 300 || defined(_TEST_HPC_STDIO)
void *calloc(size_t n, size_t s) {
void *result = malloc(n * s);
if (result)
memset(result, 0, n * s);
return result;
}
char *strpbrk(const char *s, const char *accept) {
int i;
if (!s || !accept)
return NULL;
for (i=0; i<strlen(s); i++) {
int j;
for (j=0; j<strlen(accept); j++)
if (s[i] == accept[j])
return (char*)&s[i];
}
return NULL;
}
#ifndef _TEST_HPC_STDIO
int isdigit(int c) {
return (c >='0' && c <= '9');
}
int isprint(int c) {
return (c >= ' ' && c <= '~');
}
int isspace(int c) {
return (c == ' ');
}
#endif
#ifndef WIN32_PLATFORM_HPCPRO
int printf(const char *format, ...) {
// useless anyway :)
return 0;
}
FILE *fopen(const char *path, const char *mode) {
TCHAR tempo[MAX_PATH];
HANDLE result;
bool writeAccess = (mode[0] == 'W' || mode[0] == 'w');
MultiByteToWideChar(CP_ACP, 0, path, strlen(path) + 1, tempo, sizeof(tempo));
result = CreateFile(tempo, ( writeAccess ? GENERIC_WRITE : GENERIC_READ), 0, NULL, (writeAccess ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL);
if (result == INVALID_HANDLE_VALUE)
return NULL;
else
return (FILE*)result;
}
FILE * _wfopen(const TCHAR *path, const TCHAR *mode) {
HANDLE result;
bool writeAccess = (mode[0] == 'W' || mode[0] == 'w');
result = CreateFile(path, ( writeAccess ? GENERIC_WRITE : GENERIC_READ), 0, NULL, (writeAccess ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL);
if (result == INVALID_HANDLE_VALUE)
return NULL;
else
return (FILE*)result;
}
FILE *_wfreopen(const TCHAR *path, const TCHAR *mode, FILE *stream) {
fclose(stream);
stream = _wfopen(path, mode);
return stream;
}
int fclose(FILE *stream) {
CloseHandle((HANDLE)stream);
return 1;
}
int fseek(FILE *stream, long offset, int whence) {
SetFilePointer((HANDLE)stream, offset, NULL, (whence == SEEK_CUR ? FILE_CURRENT : whence == SEEK_END ? FILE_END : FILE_BEGIN));
return 0;
}
long ftell(FILE *stream) {
return (SetFilePointer((HANDLE)stream, 0, NULL, FILE_CURRENT));
}
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
DWORD sizeWritten;
WriteFile((HANDLE)stream, ptr, size * nmemb, &sizeWritten, NULL);
if (size != 0)
return sizeWritten / size;
else
return 0;
}
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
DWORD sizeRead;
ReadFile((HANDLE)stream, ptr, size * nmemb, &sizeRead, NULL);
if (size != 0)
return sizeRead / size;
else
return 0;
}
int fgetc(FILE *stream) {
unsigned char c;
if (fread(&c, 1, 1, stream) != 1)
return -1;
else
return c;
}
char *fgets(char *s, int size, FILE *stream) {
int i = 0;
char tempo[1];
memset(s, 0, size);
while (fread(tempo, 1, 1, stream)) {
//if (tempo[0] == '\r')
// break;
if (tempo[0] == '\r')
continue;
s[i++] = tempo[0];
if (tempo[0] == '\n')
break;
if (i == size)
break;
}
if (!i)
return NULL;
else
return s;
}
int feof(FILE *stream) {
DWORD fileSize;
DWORD filePos;
fileSize = GetFileSize((HANDLE)stream, NULL);
filePos = SetFilePointer((HANDLE)stream, 0, 0, FILE_CURRENT);
return (filePos == 0xFFFFFFFF || filePos > (fileSize - 1));
}
int ferror(FILE *stream) {
return 0; // FIXME !
}
int fprintf(FILE *stream, const char *format, ...) {
char buf[1024];
va_list va;
va_start(va, format);
vsnprintf(buf, 1024, format, va);
va_end(va);
if (buf[strlen(buf) - 1] == '\n') {
int i = strlen(buf) - 1;
buf[i] = '\r';
buf[i + 1] = '\n';
buf[i + 2] = 0;
}
return fwrite(buf, 1, strlen(buf), stream);
}
FILE* _getstdfilex(int) {
return NULL;
}
void clearerr(FILE *stream) {
}
int fflush(FILE *stream) {
return 0;
}
#endif
int stricmp( const char *string1, const char *string2 ) {
char src[4096];
char dest[4096];
int i;
for (i=0; i<strlen(string1); i++)
if (string1[i] >= 'A' && string1[i] <= 'Z')
src[i] = string1[i] + 32;
else
src[i] = string1[i];
src[i] = 0;
for (i=0; i<strlen(string2); i++)
if (string2[i] >= 'A' && string2[i] <= 'Z')
dest[i] = string2[i] + 32;
else
dest[i] = string2[i];
dest[i] = 0;
return strcmp(src, dest);
}
char *strrchr(const char *s, int c) {
int i;
for (i = strlen(s) - 1; i > 0; i--)
if (s[i] == c)
return (char*)(s + i);
return NULL;
}
long int strtol(const char *nptr, char **endptr, int base) {
// not correct but that's all we are using
long int result;
sscanf(nptr, "%ld", &result);
return result;
}
#endif
// gcc build only functions follow
#else // defined(__GNUC__)
#ifndef __MINGW32CE__
int islower(int c)
{
int islower(int c) {
return (c>='a' && c<='z');
}
int isspace(int c)
{
int isspace(int c) {
return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v');
}
int isalpha(int c)
{
return (islower(c) || (c>='A' && c<='Z'));
int isalpha(int c) {
return ((c>='a' && c<='z') || (c>='A' && c<='Z'));
}
int isalnum(int c)
{
return (isalpha(c) || (c>='0' && c<='9'));
int isalnum(int c) {
return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'));
}
int isprint(int c)
{
static char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~";
int i = 0, flag = 0;
while ((punct[i] != 0) && (flag = (punct[i] != c)))
i++;
return (isalnum(c) || flag);
}
extern "C" int atexit(void (*function)(void))
{
return 0;
int isprint(int c) {
//static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~";
//return (isalnum(c) || strchr(punct, c));
return (32 <= c && c <= 126); // based on BSD manpage
}
#endif

View File

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

View File

@ -48,7 +48,7 @@ struct PlainGameDescriptor {
/**
* Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor
* matching the given gameid. If not match is found return 0.
* The end of the list marked by a PlainGameDescriptor with gameid equal to 0.
* The end of the list must marked by a PlainGameDescriptor with gameid equal to 0.
*/
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list);

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 DYNAMIC_PLUGIN 2
// Note: The spaces around ENABLE_##ID have been added on purpose for
// MSVC. For some reason, MSVC tries to add the parenthesis after
// ENABLE_##ID to the check, thus making it false all the time.
// Please do NOT remove them, otherwise no engine plugins will be
// registered under MSVC
#define PLUGIN_ENABLED_STATIC(ID) \
(defined( ENABLE_##ID ) && !PLUGIN_ENABLED_DYNAMIC(ID))
(ENABLE_##ID && !PLUGIN_ENABLED_DYNAMIC(ID))
#define PLUGIN_ENABLED_DYNAMIC(ID) \
(defined( ENABLE_##ID ) && (ENABLE_##ID == DYNAMIC_PLUGIN) && defined(DYNAMIC_MODULES))
(ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && DYNAMIC_MODULES)
/**
* REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare

View File

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

View File

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

View File

@ -43,32 +43,43 @@ static int computeCapacity(int len) {
return ((len + 32 - 1) & ~0x1F) - 1;
}
String::String(const char *str, uint32 len)
: _len(0), _str(_storage) {
String::String(const char *str) : _len(0), _str(_storage) {
if (str == 0) {
_storage[0] = 0;
_len = 0;
} else
initWithCStr(str, strlen(str));
}
String::String(const char *str, uint32 len) : _len(0), _str(_storage) {
initWithCStr(str, len);
}
String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) {
assert(endP >= beginP);
initWithCStr(beginP, endP - beginP);
}
void String::initWithCStr(const char *str, uint32 len) {
assert(str);
// Init _storage member explicitly (ie. without calling its constructor)
// for GCC 2.95.x compatibility (see also tracker item #1602879).
_storage[0] = 0;
if (str && *str) {
const uint32 tmp = strlen(str);
assert(len <= tmp);
if (len <= 0)
len = tmp;
_len = len;
_len = len;
if (len >= _builtinCapacity) {
// Not enough internal storage, so allocate more
_extern._capacity = computeCapacity(len);
_extern._refCount = 0;
_str = (char *)malloc(_extern._capacity+1);
assert(_str != 0);
}
// Copy the string into the storage area
memcpy(_str, str, len);
_str[len] = 0;
if (len >= _builtinCapacity) {
// Not enough internal storage, so allocate more
_extern._capacity = computeCapacity(len);
_extern._refCount = 0;
_str = (char *)malloc(_extern._capacity+1);
assert(_str != 0);
}
// Copy the string into the storage area
memmove(_str, str, len);
_str[len] = 0;
}
String::String(const String &str)
@ -91,6 +102,8 @@ String::String(char c)
_storage[0] = c;
_storage[1] = 0;
// TODO/FIXME: There is no reason for the following check -- we *do*
// allow strings to contain 0 bytes!
_len = (c == 0) ? 0 : 1;
}
@ -130,11 +143,14 @@ String& String::operator =(const char *str) {
uint32 len = strlen(str);
ensureCapacity(len, false);
_len = len;
memcpy(_str, str, len + 1);
memmove(_str, str, len + 1);
return *this;
}
String &String::operator =(const String &str) {
if (&str == this)
return *this;
if (str.isStorageIntern()) {
decRefCount(_extern._refCount);
_len = str._len;

View File

@ -96,10 +96,24 @@ public:
static const char *emptyString;
#endif
/** Construct a new empty string. */
String() : _len(0), _str(_storage) { _storage[0] = 0; }
String(const char *str, uint32 len = 0);
/** Construct a new string from the given NULL-terminated C string. */
String(const char *str);
/** Construct a new string containing exactly len characters read from address str. */
String(const char *str, uint32 len);
/** Construct a new string containing the characters between beginP (including) and endP (excluding). */
String(const char *beginP, const char *endP);
/** Construct a copy of the given string. */
String(const String &str);
/** Construct a string consisting of the given character. */
String(char c);
~String();
String &operator =(const char *str);
@ -162,7 +176,7 @@ public:
void toLowercase();
void toUppercase();
uint hash() const;
public:
@ -189,6 +203,7 @@ protected:
void ensureCapacity(uint32 new_len, bool keep_old);
void incRefCount() const;
void decRefCount(int *oldRefCount);
void initWithCStr(const char *str, uint32 len);
};
// Append two strings to form a new (temp) string

View File

@ -148,6 +148,61 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
return buf;
}
char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) {
assert(buf != 0 && bufSize > 1);
char *p = buf;
size_t len = 0;
char c = 0;
// If end-of-file occurs before any characters are read, return NULL
// and the buffer contents remain unchanged.
if (eos() || ioFailed()) {
return 0;
}
// Loop as long as the stream has not ended, there is still free
// space in the buffer, and the line has not ended
while (!eos() && len + 1 < bufSize && c != LF) {
c = readByte();
// If end-of-file occurs before any characters are read, return
// NULL and the buffer contents remain unchanged. If an error
/// occurs, return NULL and the buffer contents are indeterminate.
if (ioFailed() || (len == 0 && eos()))
return 0;
// Check for CR or CR/LF
// * DOS and Windows use CRLF line breaks
// * Unix and OS X use LF line breaks
// * Macintosh before OS X used CR line breaks
if (c == CR) {
// Look at the next char -- is it LF? If not, seek back
c = readByte();
if (c != LF && !eos())
seek(-1, SEEK_CUR);
// Treat CR & CR/LF as plain LF
c = LF;
}
*p++ = c;
len++;
}
// FIXME:
// This should fix a bug while using readLine with Common::File
// it seems that it sets the eos flag after an invalid read
// and at the same time the ioFailed flag
// the config file parser fails out of that reason for the new themes
if (eos()) {
clearIOFailed();
}
// We always terminate the buffer if no error occured
*p = 0;
return buf;
}
uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
dataSize = MIN(dataSize, _end - _pos);

View File

@ -304,13 +304,40 @@ public:
* Read one line of text from a CR or CR/LF terminated plain text file.
* This method is a rough analog of the (f)gets function.
*
* @bug A main difference (and flaw) in this function is that there is no
* way to detect that a line exceeeds the length of the buffer.
* Code which needs this should use the new readLine_NEW() method instead.
*
* @param buf the buffer to store into
* @param bufSize the size of the buffer
* @return a pointer to the read string, or NULL if an error occurred
*
* @note The line terminator (CR or CR/LF) is stripped and not inserted
* into the buffer.
*/
virtual char *readLine(char *buf, size_t bufSize);
/**
* Reads at most one less than the number of characters specified
* by bufSize from the and stores them in the string buf. Reading
* stops when the end of a line is reached (CR, CR/LF or LF), at
* end-of-file or error. The newline, if any, is retained (CR and
* CR/LF are translated to LF = 0xA = '\n'). If any characters are
* read and there is no error, a `\0' character is appended to end
* the string.
*
* Upon successful completion, return a pointer to the string. If
* end-of-file occurs before any characters are read, returns NULL
* and the buffer contents remain unchanged. If an error occurs,
* returns NULL and the buffer contents are indeterminate.
* This method does not distinguish between end-of-file and error;
* callers muse use ioFailed() or eos() to determine which occurred.
*
* @param buf the buffer to store into
* @param bufSize the size of the buffer
* @return a pointer to the read string, or NULL if an error occurred
*/
virtual char *readLine_NEW(char *s, size_t bufSize);
};
/**

4
configure vendored
View File

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

View File

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

View File

@ -7,8 +7,8 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico"
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,12,0,0
PRODUCTVERSION 0,12,0,0
FILEVERSION 0,13,0,0
PRODUCTVERSION 0,13,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -25,13 +25,13 @@ BEGIN
BEGIN
VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0"
VALUE "FileDescription", "http://www.scummvm.org/\0"
VALUE "FileVersion", "0.12.0svn\0"
VALUE "FileVersion", "0.13.0svn\0"
VALUE "InternalName", "scummvm\0"
VALUE "LegalCopyright", "Copyright © 2001-2007 The ScummVM Team\0"
VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0"
VALUE "OriginalFilename", "scummvm.exe\0"
VALUE "ProductName", "ScummVM\0"
VALUE "ProductVersion", "0.12.0svn\0"
VALUE "ProductVersion", "0.13.0svn\0"
END
END
BLOCK "VarFileInfo"

View File

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

View File

@ -1076,6 +1076,8 @@ protected:
virtual void drawImage(VC10_state *state);
void drawBackGroundImage(VC10_state *state);
void drawVertImage(VC10_state *state);
void drawVertImageCompressed(VC10_state *state);
void drawVertImageUncompressed(VC10_state *state);
void setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height);

View File

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

View File

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

View File

@ -337,7 +337,7 @@ int FWRenderer::drawChar(char character, int x, int y) {
x += 5;
} else if ((width = fontParamTable[(unsigned char)character].characterWidth)) {
idx = fontParamTable[(unsigned char)character].characterIdx;
drawSpriteRaw(textTable[idx][0], textTable[idx][1], 16, 8, _backBuffer, x, y);
drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y);
x += width + 1;
}
@ -938,7 +938,7 @@ int OSRenderer::drawChar(char character, int x, int y) {
x += 5;
} else if ((width = fontParamTable[(unsigned char)character].characterWidth)) {
idx = fontParamTable[(unsigned char)character].characterIdx;
drawSpriteRaw2(textTable[idx][0], 0, 16, 8, _backBuffer, x, y);
drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y);
x += width + 1;
}

View File

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

View File

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

View File

@ -1019,6 +1019,20 @@ int FWScript::o1_divVar() {
}
int FWScript::o1_compareVar() {
// WORKAROUND: A workaround for a script bug in script file CODE2.PRC
// in at least some of the Amiga and Atari ST versions of Future Wars.
// Fixes bug #2016647 (FW: crash with italian amiga version). A local
// variable 251 is compared against value 0 although it's quite apparent
// from the context in the script that instead global variable 251 should
// be compared against value 0. So looks like someone made a typo when
// making the scripts. Therefore we change that particular comparison
// from using the local variable 251 to using the global variable 251.
if (g_cine->getGameType() == Cine::GType_FW && scumm_stricmp(currentPrcName, "CODE2.PRC") == 0 &&
(g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) &&
_script.getByte(_pos) == 251 && _script.getByte(_pos + 1) == 0 && _script.getWord(_pos + 2) == 0) {
return o1_compareGlobalVar();
}
byte varIdx = getNextByte();
byte varType = getNextByte();

View File

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

View File

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

View File

@ -464,17 +464,26 @@ bool CineEngine::makeLoad(char *saveName) {
broken = brokenSave(*fHandle);
// At savefile position 0x0000:
currentDisk = fHandle->readUint16BE();
// At 0x0002:
fHandle->read(currentPartName, 13);
// At 0x000F:
fHandle->read(currentDatName, 13);
// At 0x001C:
saveVar2 = fHandle->readSint16BE();
// At 0x001E:
fHandle->read(currentPrcName, 13);
// At 0x002B:
fHandle->read(currentRelName, 13);
// At 0x0038:
fHandle->read(currentMsgName, 13);
// At 0x0045:
fHandle->read(bgName, 13);
// At 0x0052:
fHandle->read(currentCtName, 13);
checkDataDisk(currentDisk);
@ -499,52 +508,84 @@ bool CineEngine::makeLoad(char *saveName) {
loadCtFW(currentCtName);
}
// At 0x005F:
fHandle->readUint16BE();
// At 0x0061:
fHandle->readUint16BE();
// At 0x0063:
for (i = 0; i < 255; i++) {
// At 0x0063 + i * 32 + 0:
objectTable[i].x = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 2:
objectTable[i].y = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 4:
objectTable[i].mask = fHandle->readUint16BE();
// At 0x0063 + i * 32 + 6:
objectTable[i].frame = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 8:
objectTable[i].costume = fHandle->readSint16BE();
// At 0x0063 + i * 32 + 10:
fHandle->read(objectTable[i].name, 20);
// At 0x0063 + i * 32 + 30:
objectTable[i].part = fHandle->readUint16BE();
}
// At 0x2043 (i.e. 0x0063 + 255 * 32):
renderer->restorePalette(*fHandle);
// At 0x2083 (i.e. 0x2043 + 16 * 2 * 2):
globalVars.load(*fHandle, NUM_MAX_VAR - 1);
// At 0x2281 (i.e. 0x2083 + 255 * 2):
for (i = 0; i < 16; i++) {
// At 0x2281 + i * 2:
zoneData[i] = fHandle->readUint16BE();
}
// At 0x22A1 (i.e. 0x2281 + 16 * 2):
for (i = 0; i < 4; i++) {
// At 0x22A1 + i * 2:
commandVar3[i] = fHandle->readUint16BE();
}
// At 0x22A9 (i.e. 0x22A1 + 4 * 2):
fHandle->read(commandBuffer, 0x50);
renderer->setCommand(commandBuffer);
// At 0x22F9 (i.e. 0x22A9 + 0x50):
renderer->_cmdY = fHandle->readUint16BE();
// At 0x22FB:
bgVar0 = fHandle->readUint16BE();
// At 0x22FD:
allowPlayerInput = fHandle->readUint16BE();
// At 0x22FF:
playerCommand = fHandle->readSint16BE();
// At 0x2301:
commandVar1 = fHandle->readSint16BE();
// At 0x2303:
isDrawCommandEnabled = fHandle->readUint16BE();
// At 0x2305:
var5 = fHandle->readUint16BE();
// At 0x2307:
var4 = fHandle->readUint16BE();
// At 0x2309:
var3 = fHandle->readUint16BE();
// At 0x230B:
var2 = fHandle->readUint16BE();
// At 0x230D:
commandVar2 = fHandle->readSint16BE();
// At 0x230F:
renderer->_messageBg = fHandle->readUint16BE();
// At 0x2311:
fHandle->readUint16BE();
// At 0x2313:
fHandle->readUint16BE();
// At 0x2315:
loadResourcesFromSave(*fHandle, broken);
// TODO: handle screen params (really required ?)
@ -1516,12 +1557,22 @@ void mainLoopSub6(void) {
void checkForPendingDataLoad(void) {
if (newPrcName[0] != 0) {
loadPrc(newPrcName);
bool loadPrcOk = loadPrc(newPrcName);
strcpy(currentPrcName, newPrcName);
strcpy(newPrcName, "");
addScriptToList0(1);
// Check that the loading of the script file was successful before
// trying to add script 1 from it to the global scripts list. This
// fixes a crash when failing copy protection in Amiga or Atari ST
// versions of Future Wars.
if (loadPrcOk) {
addScriptToList0(1);
} else if (scumm_stricmp(currentPrcName, COPY_PROT_FAIL_PRC_NAME)) {
// We only show an error here for other files than the file that
// is loaded if copy protection fails (i.e. L201.ANI).
warning("checkForPendingDataLoad: loadPrc(%s) failed", currentPrcName);
}
}
if (newRelName[0] != 0) {

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -224,7 +224,11 @@ DECLARE_COMMAND_OPCODE(start) {
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() {
debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n");
uint16 layer = 0;
@ -362,6 +367,8 @@ void Parallaction_ns::drawAnimations() {
}
}
debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n");
return;
}
@ -417,7 +424,6 @@ label1:
return;
}
void CommandExec::run(CommandList& list, ZonePtr z) {
if (list.size() == 0) {
debugC(3, kDebugExec, "runCommands: nothing to do");
@ -542,11 +548,8 @@ uint16 Parallaction::runZone(ZonePtr z) {
break;
case kZoneSpeak:
runDialogue(z->u.speak);
if (_vm->quit())
return 0;
break;
enterDialogueMode(z);
return 0;
}
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
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 {
// this is the size of the receiving buffer for unpacked frames,
// since BRA uses some insanely big animations.
#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401
void Gfx::registerVar(const Common::String &name, int32 initialValue) {
if (_vars.contains(name)) {
warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str());
@ -752,6 +757,9 @@ Gfx::Gfx(Parallaction* vm) :
_halfbrite = false;
_hbCircleRadius = 0;
_unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE];
assert(_unpackedBitmap);
registerVar("background_mode", 1);
_varBackgroundMode = 1;
@ -769,6 +777,8 @@ Gfx::~Gfx() {
freeBackground();
freeLabels();
delete []_unpackedBitmap;
return;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1175,15 +1175,8 @@ BamScene::BamScene(QueenEngine *vm)
}
void BamScene::playSfx() {
// Don't try to play all the sounds. This is only necessary for the
// fight bam, in which the number of 'sfx bam frames' is too much
// important / too much closer. The original game does not have
// this problem since its playSfx() function returns immediately
// if a sound is already being played.
if (_lastSoundIndex == 0 || _index - _lastSoundIndex >= SFX_SKIP) {
_vm->sound()->playSfx(_vm->logic()->currentRoomSfx());
_lastSoundIndex = _index;
}
_vm->sound()->playSfx(_vm->logic()->currentRoomSfx());
_lastSoundIndex = _index;
}
void BamScene::prepareAnimation() {

View File

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

View File

@ -227,11 +227,6 @@ void PCSound::setVolume(int vol) {
_music->setVolume(vol);
}
void PCSound::waitFinished(bool isSpeech) {
while (_mixer->isSoundHandleActive(isSpeech ? _speechHandle : _sfxHandle))
_vm->input()->delay(10);
}
void PCSound::playSound(const char *base, bool isSpeech) {
char name[13];
strcpy(name, base);
@ -241,7 +236,13 @@ void PCSound::playSound(const char *base, bool isSpeech) {
name[i] = '0';
}
strcat(name, ".SB");
waitFinished(isSpeech);
if (isSpeech) {
while (_mixer->isSoundHandleActive(_speechHandle)) {
_vm->input()->delay(10);
}
} else {
_mixer->stopHandle(_sfxHandle);
}
uint32 size;
Common::File *f = _vm->resource()->findSound(name, &size);
if (f) {
@ -253,6 +254,8 @@ void PCSound::playSound(const char *base, bool isSpeech) {
}
void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) {
// In order to simplify the code, we don't parse the .sb header but hard-code the
// values. Refer to tracker item #1876741 for details on the format/fields.
int headerSize;
f->seek(2, SEEK_CUR);
uint16 version = f->readUint16LE();

View File

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

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..)
SaveStateList saveList;
for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
// Obtain the last 2 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 2);

View File

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

View File

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

View File

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

View File

@ -52,9 +52,11 @@ namespace Sword2 {
static Audio::AudioStream *makeCLUStream(Common::File *fp, int size);
static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) {
debug(3, "Playing %s from CD %d", base, cd);
bool alreadyOpen;
if (!fh->file.isOpen()) {
alreadyOpen = false;
struct {
const char *ext;
int mode;
@ -75,16 +77,14 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base,
char filename[20];
for (int i = 0; i < ARRAYSIZE(file_types); i++) {
Common::File f;
sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext);
if (f.open(filename)) {
if (Common::File::exists(filename)) {
soundMode = file_types[i].mode;
break;
}
sprintf(filename, "%s.%s", base, file_types[i].ext);
if (f.open(filename)) {
if (Common::File::exists(filename)) {
soundMode = file_types[i].mode;
break;
}
@ -105,7 +105,8 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base,
fh->idxTab = NULL;
}
}
}
} else
alreadyOpen = true;
uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3;
@ -134,7 +135,13 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base,
*numSamples = len;
if (!pos || !len) {
fh->file.close();
// We couldn't find the sound. Possibly as a result of a bad
// installation (e.g. using the music file from CD 2 as the
// first music file). Don't close the file if it was already
// open though, because something is playing from it.
warning("getAudioStream: Could not find %s ID %d! Possibly the wrong file", base, id);
if (!alreadyOpen)
fh->file.close();
return NULL;
}

View File

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

View File

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