diff options
author | Norbert Lange | 2009-08-08 19:09:30 +0000 |
---|---|---|
committer | Norbert Lange | 2009-08-08 19:09:30 +0000 |
commit | 0350a1598deea8d1af252ddd96a490699d10e2e2 (patch) | |
tree | 11557d7a87ee5da2ee20e6c13e8be7d2607f393c | |
parent | df06592be1b4c9904acde5a843d3ab3d076c65ac (diff) | |
parent | 65a39cc2b0ebb989444330c561743ba0466c1a9c (diff) | |
download | scummvm-rg350-0350a1598deea8d1af252ddd96a490699d10e2e2.tar.gz scummvm-rg350-0350a1598deea8d1af252ddd96a490699d10e2e2.tar.bz2 scummvm-rg350-0350a1598deea8d1af252ddd96a490699d10e2e2.zip |
merge with trunk
svn-id: r43134
334 files changed, 10438 insertions, 4974 deletions
@@ -15,14 +15,19 @@ ScummVM Team ------------ SCUMM: Torbjorn Andersson + James Brown - (retired) + Jonathan Gray - (retired) + Vincent Hamm - (retired) Max Horn Travis Howell Pawel Kolodziejski - Codecs, iMUSE, Smush, etc. Gregory Montoir Eugene Sandulenko - FT INSANE, MM NES, MM C64, game detection, Herc/CGA + Ludvig Strigeus - (retired) HE: + Jonathan Gray - (retired) Travis Howell Gregory Montoir Eugene Sandulenko @@ -35,42 +40,53 @@ ScummVM Team Walter van Niftrik Kari Salminen Eugene Sandulenko + David Symonds - (retired) AGOS: Torbjorn Andersson Paul Gilbert Travis Howell + Oliver Kiehl - (retired) + Ludvig Strigeus - (retired) BASS: + Robert Goeffringmann - (retired) + Oliver Kiehl - (retired) Joost Peters Broken Sword 1: + Fabio Battaglia - PSX version support + Robert Goeffringmann - (retired) Broken Sword 2: Torbjorn Andersson + Fabio Battaglia - PSX version support + Jonathan Gray - (retired) Cinematique evo 1: - Vincent Hamm - original CinE engine author + Vincent Hamm - (retired) Pawel Kolodziejski Gregory Montoir + Kari Salminen Eugene Sandulenko Cinematique evo 2: - Vincent Hamm - original CruisE engine author Paul Gilbert + Vincent Hamm - (retired) Drascula: Filippos Karapetis Pawel Kolodziejski FOTAQ: + David Eriksson - (retired) Gregory Montoir Joost Peters Gob: Torbjorn Andersson + Arnaud Boutonne Sven Hesse - Willem Jan Palenstijn Eugene Sandulenko Groovie: @@ -103,7 +119,6 @@ ScummVM Team SAGA: Torbjorn Andersson - Sven Hesse Filippos Karapetis Andrew Kurushin Eugene Sandulenko @@ -114,11 +129,13 @@ ScummVM Team Max Horn Filippos Karapetis Walter van Niftrik + Willem Jan Palenstijn Jordi Vilalta Prat Lars Skovlund Tinsel: Torbjorn Andersson + Fabio Battaglia - PSX version support Paul Gilbert Sven Hesse Max Horn @@ -152,9 +169,11 @@ ScummVM Team Chris Apers PocketPC / WinCE: + Nicolas Bacca - (retired) Kostas Nakos PlayStation 2: + Robert Goeffringmann - (retired) Max Lingua PSP (PlayStation Portable): @@ -179,19 +198,26 @@ ScummVM Team Eugene Sandulenko GUI: + Vicent Marti Eugene Sandulenko Johannes Schickel Miscellaneous: David Corrales-Lopez - Filesystem access improvements (GSoC 2007 - task) - Jerome Fisher - MT-32 emulator + task) (retired) + Jerome Fisher - MT-32 emulator (retired) + Benjamin Haisch - Heavily improved de-/encoder for DXA videos Jochen Hoenicke - Speaker & PCjr sound support, AdLib work + (retired) Chris Page - Return to launcher, savestate improvements, - leak fixes, ... (GSoC 2008 task) + leak fixes, ... (GSoC 2008 task) (retired) Robin Watts - ARM assembly routines for nice speedups on several ports; improvements to the sound mixer + Website (code) + -------------- + Fredrik Wendel + Website (content) ----------------- All active team members @@ -201,86 +227,25 @@ ScummVM Team Joachim Eberhard - Numerous contributions to documentation Matthew Hoops - Wiki editor - FreeSCI Contributors - -------------------- - Anders Baden Nielsen - PPC testing - Bas Zoetekouw - Man pages, debian package management, CVS - maintenance - Carl Muckenhoupt - Sources to the SCI resource viewer tools that - started it all - Chris Kehler - Makefile enhancements - Christoph Reichenbach - UN*X code, VM/Graphics/Sound/other - infrastructure - Christopher T. Lansdo - Original CVS maintainer, Alpha compatibility - fixes - Claudio Matsuoka - CVS snapshots, daily builds, BeOS and cygwin - ports - Dark Minister - SCI research (bytecode and parser) - Dmitry Jemerov - Port to the Win32 platform, numerous bugfixes - Emmanuel Jeandel - Bugfixes and bug reports - Francois-R Boyer - MT-32 information and mapping code - George Reid - FreeBSD package management - Hubert Maier - AmigaOS 4 port - Hugues Valois - Game selection menu - Johannes Manhave - Document format translation - Jordi Vilalta - Numerous code and website clean-up patches - Lars Skovlund - Project maintenance, most documentation, - bugfixes, SCI1 support - Magnus Reftel - Heap implementation, Python class viewer, - bugfixes - Matt Hargett - Clean-ups, bugfixes, Hardcore QA, Win32 - Max Horn - SetJump implementation - Paul David Doherty - Game version information - Petr Vyhnak - The DCL-INFLATE algorithm, many Win32 - improvements - Rainer Canavan - IRIX MIDI driver and bug fixes - Rainer De Temple - SCI research - Ravi I. - SCI0 sound resource specification - Ruediger Hanke - Port to the MorphOS platform - Rune Orsval - Configuration file editor - Rickard Lind - MT32->GM MIDI mapping magic, sound research - Rink Springer - Port to the DOS platform, several bug fixes - Robey Pointer - Bug tracking system hosting - Sergey Lapin - Port of Carl's type 2 decompression code - Solomon Peachy - SDL ports and much of the sound subsystem - Vyacheslav Dikonov - Config script improvements - Walter van Niftrik - Ports to the Dreamcast and GP32 platforms - Xiaojun Chen - Sean Terrell - - Special thanks to Prof. Dr. Gary Nutt for allowing the FreeSCI VM - extension as a course project in his Advanced OS course - - Special thanks to Bob Heitman and Corey Cole for their support of - FreeSCI - Retired Team Members -------------------- - Tore Anderson - Former Debian GNU/Linux maintainer - Nicolas Bacca - Former WinCE porter Ralph Brorsen - Help with GUI implementation Jamieson Christian - iMUSE, MIDI, all things musical - David Eriksson - Engines: FOTAQ - Hans-Jorg Frieden - Former AmigaOS 4 packager - Robert Goeffringmann - Original PS2 porter; Engines: BASS, BS1 - Jonathan Gray - Engines: SCUMM, HE, BS2 - Ruediger Hanke - Port: MorphOS Felix Jakschitsch - Zak256 reverse engineering - Oliver Kiehl - Engines: AGOS, BASS Mutwin Kraus - Original MacOS porter Peter Moraliyski - Port: GP32 - Juha Niemimaki - Former AmigaOS 4 packager Jeremy Newman - Former webmaster Lionel Ulmer - Port: X11 Won Star - Former GP32 porter - David Symonds - Engines: AGI Other contributions ******************* Packages -------- AmigaOS 4: + Hans-Jorg Frieden - (retired) Hubert Maier + Juha Niemimaki - (retired) Atari/FreeMiNT: Keith Scroggins @@ -290,6 +255,7 @@ Other contributions Luc Schrijvers Debian GNU/Linux: + Tore Anderson - (retired) David Weinehall Fedora / RedHat: @@ -304,6 +270,7 @@ Other contributions MorphOS: Fabien Coeurjoly + Ruediger Hanke - (retired) OS/2: Paul Smedley @@ -341,7 +308,6 @@ Other contributions Thierry Crozat - Support for Broken Sword 1 Macintosh version Martin Doucha - CinE engine objectification Thomas Fach-Pedersen - ProTracker module player - Benjamin Haisch - Heavily improved de-/encoder for DXA videos Janne Huttunen - V3 actor mask support, Dig/FT SMUSH audio Kovacs Endre Janos - Several fixes for Simon1 Jeroen Janssen - Numerous readability and bugfix patches @@ -356,12 +322,66 @@ Other contributions Tim Phillips - Initial MI1 CD music support Quietust - Sound support for Amiga SCUMM V2/V3 games, MM NES support + segra - Improved support for Apple II/C64 versions of MM Andreas Roever - Broken Sword 1/2 MPEG2 cutscene support Edward Rudd - Fixes for playing MP3 versions of MI1/Loom audio Daniel Schepler - Final MI1 CD music support, initial Ogg Vorbis support Andre Souza - SDL-based OpenGL renderer + FreeSCI Contributors + -------------------- + Anders Baden Nielsen - PPC testing + Bas Zoetekouw - Man pages, debian package management, CVS + maintenance + Carl Muckenhoupt - Sources to the SCI resource viewer tools that + started it all + Chris Kehler - Makefile enhancements + Christoph Reichenbach - UN*X code, VM/Graphics/Sound/other + infrastructure + Christopher T. Lansdo - Original CVS maintainer, Alpha compatibility + fixes + Claudio Matsuoka - CVS snapshots, daily builds, BeOS and cygwin + ports + Dark Minister - SCI research (bytecode and parser) + Dmitry Jemerov - Port to the Win32 platform, numerous bugfixes + Emmanuel Jeandel - Bugfixes and bug reports + Francois-R Boyer - MT-32 information and mapping code + George Reid - FreeBSD package management + Hubert Maier - AmigaOS 4 port + Hugues Valois - Game selection menu + Johannes Manhave - Document format translation + Jordi Vilalta - Numerous code and website clean-up patches + Lars Skovlund - Project maintenance, most documentation, + bugfixes, SCI1 support + Magnus Reftel - Heap implementation, Python class viewer, + bugfixes + Matt Hargett - Clean-ups, bugfixes, Hardcore QA, Win32 + Max Horn - SetJump implementation + Paul David Doherty - Game version information + Petr Vyhnak - The DCL-INFLATE algorithm, many Win32 + improvements + Rainer Canavan - IRIX MIDI driver and bug fixes + Rainer De Temple - SCI research + Ravi I. - SCI0 sound resource specification + Ruediger Hanke - Port to the MorphOS platform + Rune Orsval - Configuration file editor + Rickard Lind - MT32->GM MIDI mapping magic, sound research + Rink Springer - Port to the DOS platform, several bug fixes + Robey Pointer - Bug tracking system hosting + Sergey Lapin - Port of Carl's type 2 decompression code + Solomon Peachy - SDL ports and much of the sound subsystem + Vyacheslav Dikonov - Config script improvements + Walter van Niftrik - Ports to the Dreamcast and GP32 platforms + Xiaojun Chen + Sean Terrell + + Special thanks to Prof. Dr. Gary Nutt for allowing the FreeSCI VM + extension as a course project in his Advanced OS course. + + Special thanks to Bob Heitman and Corey Cole for their support of + FreeSCI. + And to all the contributors, users, and beta testers we've missed. Thanks! Special thanks to diff --git a/Makefile.common b/Makefile.common index 51261d65d9..caf5ba22fa 100644 --- a/Makefile.common +++ b/Makefile.common @@ -144,25 +144,6 @@ endif ###################################################################### -# Create the files that depend on the version -###################################################################### - -VERSION_FILES = \ - $(srcdir)/dists/iphone/Info.plist \ - $(srcdir)/dists/macosx/Info.plist - -$(VERSION_FILES): %: %.in - @echo "Creating $@" - @cat $< | sed \ - -e "s/@VER_MAJOR@/$(VER_MAJOR)/g" \ - -e "s/@VER_MINOR@/$(VER_MINOR)/g" \ - -e "s/@VER_PATCH@/$(VER_PATCH)/g" \ - -e "s/@VER_EXTRA@/$(VER_EXTRA)/g" \ - -e "s/@VERSION@/$(VERSION)/g" \ - > $@ - - -###################################################################### # Distribution settings ###################################################################### @@ -1,6 +1,13 @@ For a more comprehensive changelog for the latest experimental SVN code, see: http://scummvm.svn.sourceforge.net/viewvc/scummvm/?view=log +1.1.0 (????-??-??) + General: + - Added support for a custom SJIS font for FM-TOWNS and PC98 games. + + KYRA: + - Adapted KYRA to support the custom SJIS font. + 1.0.0 (2009-??-??) New Games: - Added support for Discworld. @@ -18,6 +25,9 @@ For a more comprehensive changelog for the latest experimental SVN code, see: - Added per-game GUI options. - Improved Mass Add dialog. + New Ports: + - Added GP2X Wiz port. + AGI: - Increased compatibility for Sierra games. - Implemented all 'unknown' commands. @@ -41,13 +51,12 @@ For a more comprehensive changelog for the latest experimental SVN code, see: - Introduced a new savegame format to fix a fatal flaw of the old one, breaking compatibility with old savegames made on big-endian systems. + Groovie: + - Increased microscope puzzle difficulty to match original. + KYRA: - Added support for PC Speaker based music and sound effects. - - Added support for 16 color dithering in Kyrandia PC-9801 (Japanese version - only). - - New Ports: - - Added GP2X Wiz port. + - Added support for 16 color dithering in Kyrandia PC-9801. 0.13.1 (2009-04-27) AGOS: @@ -771,10 +771,8 @@ site, please see the section on reporting bugs. The Legend of Kyrandia: - Amiga versions aren't supported - Waxworks: - - No music in the PC version - Humongous Entertainment games: + - Only the original load and save interface can be used. - No support for printing images diff --git a/backends/base-backend.h b/backends/base-backend.h index 697577cd33..3fcca9c3b7 100644 --- a/backends/base-backend.h +++ b/backends/base-backend.h @@ -29,7 +29,7 @@ #include "common/system.h" #include "backends/events/default/default-events.h" -class BaseBackend : public OSystem, EventProvider { +class BaseBackend : public OSystem, Common::EventSource { public: virtual Common::EventManager *getEventManager(); virtual void displayMessageOnOSD(const char *msg); diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index 4fdf96e57e..2efaec32f2 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -35,242 +35,38 @@ #include "engines/engine.h" #include "gui/message.h" -#define RECORD_SIGNATURE 0x54455354 -#define RECORD_VERSION 1 - -void readRecord(Common::InSaveFile *inFile, uint32 &diff, Common::Event &event) { - diff = inFile->readUint32LE(); - - event.type = (Common::EventType)inFile->readUint32LE(); - - switch(event.type) { - case Common::EVENT_KEYDOWN: - case Common::EVENT_KEYUP: - event.kbd.keycode = (Common::KeyCode)inFile->readSint32LE(); - event.kbd.ascii = inFile->readUint16LE(); - event.kbd.flags = inFile->readByte(); - break; - case Common::EVENT_MOUSEMOVE: - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONDOWN: - case Common::EVENT_RBUTTONUP: - case Common::EVENT_WHEELUP: - case Common::EVENT_WHEELDOWN: - event.mouse.x = inFile->readSint16LE(); - event.mouse.y = inFile->readSint16LE(); - break; - default: - break; - } -} - -void writeRecord(Common::OutSaveFile *outFile, uint32 diff, Common::Event &event) { - outFile->writeUint32LE(diff); - - outFile->writeUint32LE((uint32)event.type); - - switch(event.type) { - case Common::EVENT_KEYDOWN: - case Common::EVENT_KEYUP: - outFile->writeSint32LE(event.kbd.keycode); - outFile->writeUint16LE(event.kbd.ascii); - outFile->writeByte(event.kbd.flags); - break; - case Common::EVENT_MOUSEMOVE: - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONDOWN: - case Common::EVENT_RBUTTONUP: - case Common::EVENT_WHEELUP: - case Common::EVENT_WHEELDOWN: - outFile->writeSint16LE(event.mouse.x); - outFile->writeSint16LE(event.mouse.y); - break; - default: - break; - } -} - -DefaultEventManager::DefaultEventManager(EventProvider *boss) : - _boss(boss), +DefaultEventManager::DefaultEventManager(Common::EventSource *boss) : _buttonState(0), _modifierState(0), _shouldQuit(false), _shouldRTL(false), _confirmExitDialogActive(false) { - assert(_boss); + assert(boss); - _recordFile = NULL; - _recordTimeFile = NULL; - _playbackFile = NULL; - _playbackTimeFile = NULL; - _timeMutex = g_system->createMutex(); - _recorderMutex = g_system->createMutex(); + _dispatcher.registerSource(boss, false); + _dispatcher.registerSource(&_artificialEventSource, false); - _eventCount = 0; - _lastEventCount = 0; - _lastMillis = 0; - - Common::String recordModeString = ConfMan.get("record_mode"); - if (recordModeString.compareToIgnoreCase("record") == 0) { - _recordMode = kRecorderRecord; - } else { - if (recordModeString.compareToIgnoreCase("playback") == 0) { - _recordMode = kRecorderPlayback; - } else { - _recordMode = kPassthrough; - } - } - - _recordFileName = ConfMan.get("record_file_name"); - if (_recordFileName.empty()) { - _recordFileName = "record.bin"; - } - _recordTempFileName = ConfMan.get("record_temp_file_name"); - if (_recordTempFileName.empty()) { - _recordTempFileName = "record.tmp"; - } - _recordTimeFileName = ConfMan.get("record_time_file_name"); - if (_recordTimeFileName.empty()) { - _recordTimeFileName = "record.time"; - } + _dispatcher.registerObserver(this, kEventManPriority, false); // Reset key repeat _currentKeyDown.keycode = 0; - // recorder stuff - if (_recordMode == kRecorderRecord) { - _recordCount = 0; - _recordTimeCount = 0; - _recordFile = g_system->getSavefileManager()->openForSaving(_recordTempFileName); - _recordTimeFile = g_system->getSavefileManager()->openForSaving(_recordTimeFileName); - _recordSubtitles = ConfMan.getBool("subtitles"); - } - - uint32 sign; - uint32 version; - uint32 randomSourceCount; - if (_recordMode == kRecorderPlayback) { - _playbackCount = 0; - _playbackTimeCount = 0; - _playbackFile = g_system->getSavefileManager()->openForLoading(_recordFileName); - _playbackTimeFile = g_system->getSavefileManager()->openForLoading(_recordTimeFileName); - - if (!_playbackFile) { - warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str()); - _recordMode = kPassthrough; - } - - if (!_playbackTimeFile) { - warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str()); - _recordMode = kPassthrough; - } - } - - if (_recordMode == kRecorderPlayback) { - sign = _playbackFile->readUint32LE(); - if (sign != RECORD_SIGNATURE) { - error("Unknown record file signature"); - } - version = _playbackFile->readUint32LE(); - - // conf vars - ConfMan.setBool("subtitles", _playbackFile->readByte() != 0); - - _recordCount = _playbackFile->readUint32LE(); - _recordTimeCount = _playbackFile->readUint32LE(); - randomSourceCount = _playbackFile->readUint32LE(); - for (uint i = 0; i < randomSourceCount; ++i) { - RandomSourceRecord rec; - rec.name = ""; - uint32 sLen = _playbackFile->readUint32LE(); - for (uint j = 0; j < sLen; ++j) { - char c = _playbackFile->readSByte(); - rec.name += c; - } - rec.seed = _playbackFile->readUint32LE(); - _randomSourceRecords.push_back(rec); - } - - _hasPlaybackEvent = false; - } - #ifdef ENABLE_VKEYBD _vk = new Common::VirtualKeyboard(); #endif #ifdef ENABLE_KEYMAPPER _keymapper = new Common::Keymapper(this); + // EventDispatcher will automatically free the keymapper + _dispatcher.registerMapper(_keymapper); _remap = false; #endif } DefaultEventManager::~DefaultEventManager() { -#ifdef ENABLE_KEYMAPPER - delete _keymapper; -#endif #ifdef ENABLE_VKEYBD delete _vk; #endif - g_system->lockMutex(_timeMutex); - g_system->lockMutex(_recorderMutex); - _recordMode = kPassthrough; - g_system->unlockMutex(_timeMutex); - g_system->unlockMutex(_recorderMutex); - - if (!artificialEventQueue.empty()) - artificialEventQueue.clear(); - - if (_playbackFile != NULL) { - delete _playbackFile; - } - if (_playbackTimeFile != NULL) { - delete _playbackTimeFile; - } - - if (_recordFile != NULL) { - _recordFile->finalize(); - delete _recordFile; - _recordTimeFile->finalize(); - delete _recordTimeFile; - - _playbackFile = g_system->getSavefileManager()->openForLoading(_recordTempFileName); - - assert(_playbackFile); - - _recordFile = g_system->getSavefileManager()->openForSaving(_recordFileName); - _recordFile->writeUint32LE(RECORD_SIGNATURE); - _recordFile->writeUint32LE(RECORD_VERSION); - - // conf vars - _recordFile->writeByte(_recordSubtitles ? 1 : 0); - - _recordFile->writeUint32LE(_recordCount); - _recordFile->writeUint32LE(_recordTimeCount); - - _recordFile->writeUint32LE(_randomSourceRecords.size()); - for (uint i = 0; i < _randomSourceRecords.size(); ++i) { - _recordFile->writeUint32LE(_randomSourceRecords[i].name.size()); - _recordFile->writeString(_randomSourceRecords[i].name); - _recordFile->writeUint32LE(_randomSourceRecords[i].seed); - } - - for (uint i = 0; i < _recordCount; ++i) { - uint32 tempDiff; - Common::Event tempEvent; - readRecord(_playbackFile, tempDiff, tempEvent); - writeRecord(_recordFile, tempDiff, tempEvent); - } - - _recordFile->finalize(); - delete _recordFile; - delete _playbackFile; - - //TODO: remove recordTempFileName'ed file - } - g_system->deleteMutex(_timeMutex); - g_system->deleteMutex(_recorderMutex); } void DefaultEventManager::init() { @@ -283,145 +79,14 @@ void DefaultEventManager::init() { #endif } -bool DefaultEventManager::playback(Common::Event &event) { - - if (!_hasPlaybackEvent) { - if (_recordCount > _playbackCount) { - readRecord(_playbackFile, const_cast<uint32&>(_playbackDiff), _playbackEvent); - _playbackCount++; - _hasPlaybackEvent = true; - } - } - - if (_hasPlaybackEvent) { - if (_playbackDiff <= (_eventCount - _lastEventCount)) { - switch(_playbackEvent.type) { - case Common::EVENT_MOUSEMOVE: - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONDOWN: - case Common::EVENT_RBUTTONUP: - case Common::EVENT_WHEELUP: - case Common::EVENT_WHEELDOWN: - g_system->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y); - break; - default: - break; - } - event = _playbackEvent; - _hasPlaybackEvent = false; - _lastEventCount = _eventCount; - return true; - } - } - - return false; -} - -void DefaultEventManager::record(Common::Event &event) { - writeRecord(_recordFile, _eventCount - _lastEventCount, event); - - _recordCount++; - _lastEventCount = _eventCount; -} - -void DefaultEventManager::registerRandomSource(Common::RandomSource &rnd, const char *name) { - - if (_recordMode == kRecorderRecord) { - RandomSourceRecord rec; - rec.name = name; - rec.seed = rnd.getSeed(); - _randomSourceRecords.push_back(rec); - } - - if (_recordMode == kRecorderPlayback) { - for (uint i = 0; i < _randomSourceRecords.size(); ++i) { - if (_randomSourceRecords[i].name == name) { - rnd.setSeed(_randomSourceRecords[i].seed); - _randomSourceRecords.remove_at(i); - break; - } - } - } -} - -void DefaultEventManager::processMillis(uint32 &millis) { - uint32 d; - if (_recordMode == kPassthrough) { - return; - } - - g_system->lockMutex(_timeMutex); - if (_recordMode == kRecorderRecord) { - //Simple RLE compression - d = millis - _lastMillis; - if (d >= 0xff) { - _recordTimeFile->writeByte(0xff); - _recordTimeFile->writeUint32LE(d); - } else { - _recordTimeFile->writeByte(d); - } - _recordTimeCount++; - } - - if (_recordMode == kRecorderPlayback) { - if (_recordTimeCount > _playbackTimeCount) { - d = _playbackTimeFile->readByte(); - if (d == 0xff) { - d = _playbackTimeFile->readUint32LE(); - } - millis = _lastMillis + d; - _playbackTimeCount++; - } - } - - _lastMillis = millis; - g_system->unlockMutex(_timeMutex); -} - bool DefaultEventManager::pollEvent(Common::Event &event) { uint32 time = g_system->getMillis(); - bool result; + bool result = false; - if (!artificialEventQueue.empty()) { - event = artificialEventQueue.pop(); + _dispatcher.dispatch(); + if (!_eventQueue.empty()) { + event = _eventQueue.pop(); result = true; - } else { - result = _boss->pollEvent(event); - -#ifdef ENABLE_KEYMAPPER - if (result) { - // send key press events to keymapper - if (event.type == Common::EVENT_KEYDOWN) { - if (_keymapper->mapKeyDown(event.kbd)) { - result = false; - } - } else if (event.type == Common::EVENT_KEYUP) { - if (_keymapper->mapKeyUp(event.kbd)) { - result = false; - } - } - } -#endif - } - - if (_recordMode != kPassthrough) { - - g_system->lockMutex(_recorderMutex); - _eventCount++; - - if (_recordMode == kRecorderPlayback) { - if (event.type != Common::EVENT_QUIT) { - result = playback(event); - } - } else { - if (_recordMode == kRecorderRecord) { - if (result) { - record(event); - } - } - } - g_system->unlockMutex(_recorderMutex); } if (result) { @@ -598,13 +263,12 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { } void DefaultEventManager::pushEvent(const Common::Event &event) { - // If already received an EVENT_QUIT, don't add another one if (event.type == Common::EVENT_QUIT) { if (!_shouldQuit) - artificialEventQueue.push(event); + _artificialEventSource.addEvent(event); } else - artificialEventQueue.push(event); + _artificialEventSource.addEvent(event); } #endif // !defined(DISABLE_DEFAULT_EVENTMANAGER) diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h index 9d47104608..06db1dc027 100644 --- a/backends/events/default/default-events.h +++ b/backends/events/default/default-events.h @@ -27,8 +27,6 @@ #define BACKEND_EVENTS_DEFAULT_H #include "common/events.h" -#include "common/savefile.h" -#include "common/mutex.h" #include "common/queue.h" namespace Common { @@ -41,21 +39,7 @@ namespace Common { } -class EventProvider { -public: - virtual ~EventProvider() {} - /** - * Get the next event in the event queue. - * @param event point to an Common::Event struct, which will be filled with the event data. - * @return true if an event was retrieved. - */ - virtual bool pollEvent(Common::Event &event) = 0; -}; - - -class DefaultEventManager : public Common::EventManager { - EventProvider *_boss; - +class DefaultEventManager : public Common::EventManager, Common::EventObserver { #ifdef ENABLE_VKEYBD Common::VirtualKeyboard *_vk; #endif @@ -65,7 +49,13 @@ class DefaultEventManager : public Common::EventManager { bool _remap; #endif - Common::Queue<Common::Event> _artificialEventQueue; + Common::ArtificialEventSource _artificialEventSource; + + Common::Queue<Common::Event> _eventQueue; + bool notifyEvent(const Common::Event &ev) { + _eventQueue.push(ev); + return true; + } Common::Point _mousePos; int _buttonState; @@ -74,44 +64,6 @@ class DefaultEventManager : public Common::EventManager { bool _shouldRTL; bool _confirmExitDialogActive; - class RandomSourceRecord { - public: - Common::String name; - uint32 seed; - }; - Common::Array<RandomSourceRecord> _randomSourceRecords; - - bool _recordSubtitles; - volatile uint32 _recordCount; - volatile uint32 _lastRecordEvent; - volatile uint32 _recordTimeCount; - Common::OutSaveFile *_recordFile; - Common::OutSaveFile *_recordTimeFile; - Common::MutexRef _timeMutex; - Common::MutexRef _recorderMutex; - volatile uint32 _lastMillis; - - volatile uint32 _playbackCount; - volatile uint32 _playbackDiff; - volatile bool _hasPlaybackEvent; - volatile uint32 _playbackTimeCount; - Common::Event _playbackEvent; - Common::InSaveFile *_playbackFile; - Common::InSaveFile *_playbackTimeFile; - - volatile uint32 _eventCount; - volatile uint32 _lastEventCount; - - enum RecordMode { - kPassthrough = 0, - kRecorderRecord = 1, - kRecorderPlayback = 2 - }; - volatile RecordMode _recordMode; - Common::String _recordFileName; - Common::String _recordTempFileName; - Common::String _recordTimeFileName; - // for continuous events (keyDown) enum { kKeyRepeatInitialDelay = 400, @@ -124,18 +76,13 @@ class DefaultEventManager : public Common::EventManager { int keycode; } _currentKeyDown; uint32 _keyRepeatTime; - - void record(Common::Event &event); - bool playback(Common::Event &event); public: - DefaultEventManager(EventProvider *boss); + DefaultEventManager(Common::EventSource *boss); ~DefaultEventManager(); virtual void init(); virtual bool pollEvent(Common::Event &event); virtual void pushEvent(const Common::Event &event); - virtual void registerRandomSource(Common::RandomSource &rnd, const char *name); - virtual void processMillis(uint32 &millis); virtual Common::Point getMousePos() const { return _mousePos; } virtual int getButtonState() const { return _buttonState; } diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp index 7d888828c6..c0c454168c 100644 --- a/backends/keymapper/keymapper.cpp +++ b/backends/keymapper/keymapper.cpp @@ -168,6 +168,15 @@ void Keymapper::popKeymap() { _activeMaps.pop(); } +bool Keymapper::notifyEvent(const Common::Event &ev) { + if (ev.type == Common::EVENT_KEYDOWN) + return mapKeyDown(ev.kbd); + else if (ev.type == Common::EVENT_KEYUP) + return mapKeyUp(ev.kbd); + else + return false; +} + bool Keymapper::mapKeyDown(const KeyState& key) { return mapKey(key, true); } @@ -255,7 +264,7 @@ void Keymapper::executeAction(const Action *action, bool keyDown) { } evt.mouse = _eventMan->getMousePos(); - _eventMan->pushEvent(evt); + addEvent(evt); } } diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h index c82f64b0ed..f492882ca2 100644 --- a/backends/keymapper/keymapper.h +++ b/backends/keymapper/keymapper.h @@ -39,7 +39,7 @@ namespace Common { -class Keymapper { +class Keymapper : public Common::EventMapper, private Common::ArtificialEventSource { public: struct MapRecord { @@ -134,6 +134,10 @@ public: */ void popKeymap(); + // Implementation of the EventMapper interface + bool notifyEvent(const Common::Event &ev); + bool pollEvent(Common::Event &ev) { return Common::ArtificialEventSource::pollEvent(ev); } + /** * @brief Map a key press event. * If the active keymap contains a Action mapped to the given key, then diff --git a/backends/platform/dc/dreamcast.mk b/backends/platform/dc/dreamcast.mk index c33867b7f4..cd0d4748bd 100644 --- a/backends/platform/dc/dreamcast.mk +++ b/backends/platform/dc/dreamcast.mk @@ -6,8 +6,7 @@ ronindir = /usr/local/ronin CC := $(CXX) ASFLAGS := $(CXXFLAGS) - -dist : SCUMMVM.BIN plugin_dist +dist : SCUMMVM.BIN IP.BIN plugin_dist plugin_dist : plugins @[ -z "$(PLUGINS)" ] || for p in $(or $(PLUGINS),none); do \ @@ -24,4 +23,12 @@ SCUMMVM.BIN : scummvm.bin scummvm.bin : scummvm.elf sh-elf-objcopy -S -R .stack -O binary $< $@ +IP.BIN : ip.txt + makeip $< $@ + +ip.txt : $(srcdir)/backends/platform/dc/ip.txt.in + if [ x"$(VER_EXTRA)" = xsvn ]; then \ + if [ -z "$(VER_SVNREV)" ]; then ver="SVN"; else ver="r$(VER_SVNREV)"; fi; \ + else ver="V$(VERSION)"; fi; \ + sed -e 's/[@]VERSION[@]/'"$$ver"/ -e 's/[@]DATE[@]/$(shell date '+%Y%m%d')/' < $< > $@ diff --git a/backends/platform/dc/ip.txt.in b/backends/platform/dc/ip.txt.in new file mode 100644 index 0000000000..23424e0950 --- /dev/null +++ b/backends/platform/dc/ip.txt.in @@ -0,0 +1,11 @@ +Hardware ID : SEGA SEGAKATANA +Maker ID : SEGA ENTERPRISES +Device Info : 0000 CD-ROM1/1 +Area Symbols : JUE +Peripherals : E000F10 +Product No : T0000 +Version : @VERSION@ +Release Date : @DATE@ +Boot Filename : SCUMMVM.BIN +SW Maker Name : The ScummVM team +Game Title : ScummVM diff --git a/backends/platform/ds/arm9/source/fat/disc_io.h b/backends/platform/ds/arm9/source/fat/disc_io.h index d9a3c67353..0fc83a7493 100644 --- a/backends/platform/ds/arm9/source/fat/disc_io.h +++ b/backends/platform/ds/arm9/source/fat/disc_io.h @@ -64,7 +64,7 @@ #endif #ifdef NDS - #include <nds/jtypes.h> + #include <nds/ndstypes.h> #else #include "gba_types.h" #endif diff --git a/backends/platform/ds/arm9/source/fat/gba_nds_fat.h b/backends/platform/ds/arm9/source/fat/gba_nds_fat.h index f9746560e0..dd5c8ba85f 100644 --- a/backends/platform/ds/arm9/source/fat/gba_nds_fat.h +++ b/backends/platform/ds/arm9/source/fat/gba_nds_fat.h @@ -47,7 +47,7 @@ #endif #ifdef NDS - #include <nds/jtypes.h> + #include <nds/ndstypes.h> #else #include "gba_types.h" #endif diff --git a/backends/platform/ds/arm9/source/portdefs.h b/backends/platform/ds/arm9/source/portdefs.h index 7f22709206..560bd8ab4b 100644 --- a/backends/platform/ds/arm9/source/portdefs.h +++ b/backends/platform/ds/arm9/source/portdefs.h @@ -36,7 +36,7 @@ typedef unsigned int u32; typedef signed int s32; */ -#include "nds/jtypes.h" +#include "nds/ndstypes.h" // Somebody removed these from scummsys.h, but they're still required, so I'm adding them here diff --git a/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h b/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h index 743d158d34..9344be68f9 100644 --- a/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h +++ b/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h @@ -27,7 +27,7 @@ ////////////////////////////////////////////////////////////////////// -#include <nds/jtypes.h> +#include <nds/ndstypes.h> #include <nds/ipc.h> ////////////////////////////////////////////////////////////////////// diff --git a/backends/platform/ds/ds.mk b/backends/platform/ds/ds.mk new file mode 100644 index 0000000000..aeba1820c6 --- /dev/null +++ b/backends/platform/ds/ds.mk @@ -0,0 +1,111 @@ +# Repeat "all" target here, to make sure it is the first target +# Currently disabled, so only arm7.bin gets build +#all: + + + +# Files in this list will be optimisied for speed, otherwise they will be optimised for space +OPTLIST := actor.cpp ds_main.cpp osystem_ds.cpp blitters.cpp fmopl.cpp rate.cpp isomap.cpp image.cpp gfx.cpp sprite.cpp actor_path.cpp actor_walk.cpp +#OPTLIST := + +# Compiler options for files which should be optimised for speed +OPT_SPEED := -O3 + +# Compiler options for files which should be optimised for space +OPT_SIZE := -Os -mthumb + + +#-mthumb -fno-gcse -fno-schedule-insns2 + + +OBJS := $(DATA_OBJS) $(LIBCARTRESET_OBJS) $(PORT_OBJS) $(COMPRESSOR_OBJS) $(FAT_OBJS) + + +# TODO: Handle files in OPTLIST. +# For this, the list should be made explicit. So, replace actor.cpp by path/to/actor.cpp -- +# in fact, there are several actor.cpp files, and right now all are "optimized", but +# I think Neil only had the SAGA one in mind. Same for gfx.cpp + + + + + + +############################################################################# +############################################################################# +############################################################################# + + +#ndsdir = $(srcdir)/backends/platform/ds +ndsdir = backends/platform/ds + +############################################################################# +# +# ARM7 rules. +# For ARM7 files, we need different compiler flags, which leads to the +# extra rules for .o files below +# +############################################################################# + +$(ndsdir)/arm7/arm7.bin: $(ndsdir)/arm7/arm7.elf + +$(ndsdir)/arm7/arm7.elf: \ + $(ndsdir)/arm7/source/libcartreset/cartreset.o \ + $(ndsdir)/arm7/source/main.o + +# HACK/FIXME: C compiler, for cartreset.c -- we should switch this to use CXX +# as soon as possible. +CC := $(DEVKITARM)/bin/arm-eabi-gcc + +# HACK/TODO: Pointer to objcopy. This should really be set by configure +OBJCOPY := $(DEVKITARM)/bin/arm-eabi-objcopy + +# +# Set various flags +# +ARM7_ARCH := -mthumb-interwork + +# note: arm9tdmi isn't the correct CPU arch, but anything newer and LD +# *insists* it has a FPU or VFP, and it won't take no for an answer! +ARM7_CFLAGS := -g -Wall -O2\ + -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ + -ffast-math \ + $(ARM7_ARCH) \ + -I$(srcdir)/$(ndsdir)/arm7/source/libcartreset \ + -I$(srcdir)/$(ndsdir)/commoninclude \ + -I$(DEVKITPRO)/libnds/include \ + -I$(DEVKITPRO)/libnds/include/nds \ + -DARM7 + +ARM7_CXXFLAGS := $(ARM7_CFLAGS) -fno-exceptions -fno-rtti + +ARM7_LDFLAGS := -g $(ARM7_ARCH) -mno-fpu + +# HACK/FIXME: Define a custom build rule for cartreset.c. +# We do this because it is a .c file, not a .cpp file and so is outside our +# regular build system anyway. But this is *bad*. It should be changed into a +# .cpp file and this rule be removed. +%.o: %.c + $(MKDIR) $(*D)/$(DEPDIR) + $(CC) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o + + +# Set custom build flags for cartreset.o +$(ndsdir)/arm7/source/libcartreset/cartreset.o: CXXFLAGS=$(ARM7_CFLAGS) +$(ndsdir)/arm7/source/libcartreset/cartreset.o: CPPFLAGS= + +# Set custom build flags for main.o +$(ndsdir)/arm7/source/main.o: CXXFLAGS=$(ARM7_CXXFLAGS) +$(ndsdir)/arm7/source/main.o: CPPFLAGS= + +# Rule for creating ARM7 .bin files from .elf files +%.bin: %.elf + @echo ------ + @echo Building $@... + $(OBJCOPY) -O binary $< $@ + +# Rule for creating ARM7 .elf files by linking .o files together with a special linker script +%.elf: + @echo ------ + @echo Building $@... + $(CXX) $(ARM7_LDFLAGS) -specs=ds_arm7.specs $+ -L/opt/devkitPro/libnds/lib -lnds7 -o $@ diff --git a/backends/platform/ds/module.mk b/backends/platform/ds/module.mk new file mode 100644 index 0000000000..16630dc070 --- /dev/null +++ b/backends/platform/ds/module.mk @@ -0,0 +1,71 @@ +MODULE := backends/platform/ds + +ARM7_MODULE_OBJS := \ + arm7/source/main.o \ + arm7/source/libcartreset/cartreset.o \ + +PORT_OBJS := \ + arm9/source/blitters_arm.o \ + arm9/source/cdaudio.o \ + arm9/source/dsmain.o \ + ../../fs/ds/ds-fs.o \ + arm9/source/gbampsave.o \ + arm9/source/scummhelp.o \ + arm9/source/osystem_ds.o \ + arm9/source/portdefs.o \ + arm9/source/ramsave.o \ + arm9/source/touchkeyboard.o \ + arm9/source/zipreader.o \ + arm9/source/dsoptions.o \ + arm9/source/keys.o \ + arm9/source/wordcompletion.o \ + arm9/source/interrupt.o + +ifdef USE_PROFILER + PORT_OBJS += arm9/source/profiler/cyg-profile.o +endif + +DATA_OBJS := \ + arm9/data/icons.o \ + arm9/data/keyboard.o \ + arm9/data/keyboard_pal.o \ + arm9/data/default_font.o \ + arm9/data/8x8font_tga.o + +COMPRESSOR_OBJS := #arm9/source/compressor/lz.o + +FAT_OBJS := arm9/source/fat/disc_io.o arm9/source/fat/gba_nds_fat.o\ + arm9/source/fat/io_fcsr.o \ + arm9/source/fat/io_m3cf.o \ + arm9/source/fat/io_mpcf.o \ + arm9/source/fat/io_sccf.o \ + arm9/source/fat/io_m3sd.o \ + arm9/source/fat/io_nmmc.o \ + arm9/source/fat/io_scsd.o \ + arm9/source/fat/io_scsd_asm.o \ + arm9/source/fat/io_njsd.o \ + arm9/source/fat/io_mmcf.o \ + arm9/source/fat/io_sd_common.o \ + arm9/source/fat/io_m3_common.o \ + arm9/source/fat/io_dldi.o \ + arm9/source/fat/m3sd.o + + +# arm9/source/fat/io_cf_common.o arm9/source/fat/io_m3_common.o\ +# arm9/source/fat/io_sd_common.o arm9/source/fat/io_scsd_s.o \ +# arm9/source/fat/io_sc_common.o arm9/source/fat/io_sd_common.o + +LIBCARTRESET_OBJS := + #arm9/source/libcartreset/cartreset.o + + +MODULE_OBJS := + + + +# TODO: Should add more dirs to MODULE_DIRS so that "make distclean" can remove .deps dirs. +MODULE_DIRS += \ + backends/platform/ds/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/platform/gp2x/build/README-GP2X b/backends/platform/gp2x/build/README-GP2X index 7e10fc484e..f95a974230 100644 --- a/backends/platform/gp2x/build/README-GP2X +++ b/backends/platform/gp2x/build/README-GP2X @@ -12,10 +12,19 @@ Contents: * How to save <#How_to_save> * Controller mappings <#Controller_mappings> * Know issues <#Know_issues> - * Major TODO's <#Major_TODOs> + * TODO's <#Major_TODOs> * Additional resources/links <#Additional_resourceslinks> * Credits <#Credits> +------------------------------------------------------------------------ + +Please refer to the: + +GP2X/GP2XWiz ScummVM Forum: <http://forums.scummvm.org/viewforum.php?f=14> +WiKi: <http://wiki.scummvm.org/index.php/GP2X> + +for the most current information on the port and any updates to this +documentation. ------------------------------------------------------------------------ About the backend/port @@ -58,22 +67,6 @@ Included engines Just because an engine is included does not mean any/all of its games are supported. Please check game compatability for more infomation. - * Scumm - (All games supported by ScummVM should work to some - extent, using the hardware scalar if needed) - * AGOS (AKA Simon) - (Simon the Sorcerer one and two). - * Sky - (Beneath a Steel Sky) - * Sword - (Broken Sword 1) - This engine uses the hardware scalar to - downsize the graphics to fix on the GP2X. It is NOT very nice to - look at. - * Sword2 - (Broken Sword 2) - This engine uses the hardware scalar - to downsize the graphics to fix on the GP2X. It is NOT very nice - to look at. - * Gob - (Goblins one) - * Queen - (Flight of the Amazon Queen) - * Kyra - (The Legend of Kyrandia) - -All other game engines are disabled in this release. - ------------------------------------------------------------------------ Supported audio options @@ -169,16 +162,10 @@ It happens very infrequently, both times it was in the DOTT CD intro. Saving often is never a bad idea anyhow. ------------------------------------------------------------------------ -Major TODO's +TODO's Fix save support when using the Sky engine (Beneath a Steel Sky) - You CAN'T save at the moment but auto save works. -Look into inconsistencies with AGOS engine and map Y key to a button -combination to allow clean quitting (Simon 1/2). -Add splash-screen and pre-ScummVM config menu (CPU speed, LCD timings -etc.) - Partly done. -Fix TV out, maybe make it an option in the pre-ScummVM config menu. -Any help appreciated :). ------------------------------------------------------------------------ Additional resources/links @@ -186,7 +173,7 @@ Additional resources/links * ScummVM WiKi GP2X page <http://wiki.scummvm.org/index.php/GP2X> * ScummVM forums GP2X forum <http://forums.scummvm.org/viewforum.php?f=14> - * My own ScummVM page <http://www.distant-earth.com/scummvm> (for + * My own ScummVM page <http://scummvm.distant-earth.com/> (for SVN/test builds) * Main ScummVM site <http://www.scummvm.org> (for official supported release builds) @@ -197,4 +184,3 @@ Credits Core ScummVM code (c) The ScummVM Team Portions of the GP2X backend (c) John Willis Detailed (c) information can be found within the source code - diff --git a/backends/platform/gp2x/build/README-GP2X.html b/backends/platform/gp2x/build/README-GP2X.html deleted file mode 100644 index 1b5f1a4173..0000000000 --- a/backends/platform/gp2x/build/README-GP2X.html +++ /dev/null @@ -1,369 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>ScummVM - GP2X SPECIFIC README</title> - - -</head> - - -<body> - -<span style="font-weight: bold;">ScummVM - -GP2X SPECIFIC README - HEAD SVN<br> - -</span> -<hr style="width: 100%; height: 2px;"><br> - -<span style="font-weight: bold;">Contents:</span><br> - -<ul> - - <li><a href="#About_the_backendport">About the -backend/port</a></li> - - <li><a href="#Game_compatibility">Game -compatability</a></li> - - <li><a href="#Included_engines">Included engines</a></li> - - <li><a href="#Supported_audio_options">Supported -audio options</a></li> - - <li><a href="#Supported_cut-scene_options">Supported -cut-scene options</a></li> - - <li><a href="#Recent_changes">Recent changes</a></li> - - <li><a href="#How_to_save">How to save</a></li> - - <li><a href="#Controller_mappings">Controller -mappings</a></li> - - <li><a href="#Know_issues">Know issues</a></li> - - <li><a href="#Major_TODOs">Major TODO's</a></li> - - <li><a href="#Additional_resourceslinks">Additional -resources/links</a></li> - - <li><a href="#Credits">Credits</a></li> - -</ul> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="About_the_backendport"></a><span style="font-weight: bold;">About the backend/port</span><br> - -<br> - -This is the readme for the offficial GP2X ScummVM backend (also known -as the GP2X port).<br> - -<br> - -This is an SVN test release of ScummVM for the GP2X, it would be -appreciated -if this SVN test distribution was not mirrored and that people be -directed to <a href="http://www.distant-earth.com/scummvm">http://www.distant-earth.com/scummvm</a> -instead for updated SVN builds.<br> - -<br> - -Full supported official releases of the GP2X ScummVM backend are made -in line with main official releases and are avalalble from the <a href="http://www.scummvm.org/downloads.php">ScummVM -downloads page</a>.<br> - -<br> - -This build is in an active state of development and as such no -‘expected’ behavior can be guaranteed ;).<br> - -<br> - -SVN builds are quickly tested with firmware 2.0.0 for reference.<br> - -<br> - -Please refer to the <a href="http://forums.scummvm.org/viewforum.php?f=14">GP2X -ScummVM forum</a> and <a href="http://wiki.scummvm.org/index.php/GP2X">WiKi</a> -for the latest information on the port.<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Game_compatibility"></a><span style="font-weight: bold;">Game compatibility</span><br> - -<br> - -For information on the compatability of a specific game please refer to -the <a href="http://wiki.scummvm.org/index.php/GP2X#Compatibility_List">GP2X -compatability section of the ScummVM WiKi</a>.<br> - -<br> - -Please note the version and date of the ScummVM build you are running -when reviewing the above list.<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Included_engines"></a><span style="font-weight: bold;">Included engines</span><br> - -<br> - -Just because an engine is included does not mean any/all of its games -are supported. Please check game compatability for more infomation.<br> - -<ul> - - <li>Scumm - (All games supported by ScummVM should work to some -extent, using the hardware scalar if needed)</li> - - <li>AGOS (AKA Simon) - (Simon the Sorcerer one and two).</li> - - <li>Sky - (Beneath a Steel Sky)</li> - - <li>Sword - (Broken Sword 1) - This engine uses the hardware -scalar to -downsize the graphics to fix on the GP2X. It is NOT very nice to look -at.</li> - - <li>Sword2 - (Broken Sword 2) - This engine uses the hardware -scalar to downsize the graphics to fix on the GP2X. It is NOT very nice -to look at.</li> - - <li>Gob - (Goblins one)</li> - - <li>Queen - (Flight of the Amazon Queen)</li> - - <li>Kyra - (The Legend of Kyrandia)</li> - -</ul> - -All other game engines are disabled in this release.<br> - -<br style="font-weight: bold;"> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Supported_audio_options"></a><span style="font-weight: bold;">Supported audio options</span><br> - -<br> - -Raw audio.<br> - -MP3 audio.<br> - -OGG Vorbis audio.<br> - -<br> - -FLAC audio is currently unsupported.<br> - -<br> - -For best results use uncompressed audio in games.<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Supported_cut-scene_options"></a><span style="font-weight: bold;">Supported cut-scene options</span><br> - -<br> - -No cut scene compression options are currently supported. <br> - -<br> - -DXA video support will be added as soon as it is stable.<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Recent_changes"></a><span style="font-weight: bold;">Recent changes<br> - -<br> - -</span>Refined audio hacks to reduce audio delay a little more.<br> - -Enabled hardware scalar code.<br> - -Now built using SDL 1.2.9 for the parts of the port that use SDL (some -parts now hit the hardware directly).<br> - -Enabled new launcher - (Ensure defaulttheme.zip is in the same folder -as the executable).<br> - -Aspect Ratio Correction can now be disabled ‘per -game’. When adding a game you can find this option on the GFX -tab. <br> - -Note: This will cause the game to run with a black border at the bottom -as it will be rendered to a 320*200 frame.<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="How_to_save"></a><span style="font-weight: bold;">How to save</span><br> - -<br> - -<span style="font-weight: bold;">NOTE:</span> -Everything is saved to the SD card, saves are stored in the <span style="font-weight: bold;">saves</span> folder under -your main ScummVM executable unless you set another save location.<br> - -<br> - -The configiration file for ScummVM (.scummvmrc) is stored in the -same place as the ScummVM executable.<br> - -<br> - -The save process below is for Scumm engine games but the -principle is the same for all.<br> - -<br> - -In Game.<br> - -<br> - -1. Right Trigger<br> - -2. Select SAVE with B<br> - -3. Select a position with B<br> - -4. Right trigger puts ? in the name box for some text.<br> - -5. Press B to save<br> - -<br> - -Basically the emulated keys you can use are equivelent to the values -buttons are mapped to, <br> - -<br> - -I have a virtual keyboard like the GP32 one (left/right on the stick to -pick chars) to add in at some point ;-)<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Controller_mappings"></a><span style="font-weight: bold;">Controller mappings</span><br> - -<br> - -<span style="font-weight: bold;">Mouse emulation:</span><br> - -<br> - -Stick: Move Pointer<br> - -Stick Click: ‘light’ Left Click<br> - -B: Left click<br> - -X: Right click<br> - -<br> - -<span style="font-weight: bold;">Keyboard emulation:</span><br> - -<br> - -Start: Return<br> - -Select: Escape<br> - -Y: Space Bar (Pause)<br> - -Right Trigger: Game Menu (Save, Load, Quit etc.)<br> - -Volume Buttons: Increase and Decrease volume (5% per press)<br> - -<br> - -<span style="font-weight: bold;">Fancy button combos:</span><br> - -<br> - -NOTE: To use button combos press and hold the Left Trigger then...<br> - -<br> - -Y: Toggle "zoom" mode - Try it in larger games like Broken Sword.<br> - -Volume Buttons: Increase and Decrease subtitle speed (In SCUMM games)<br> - -Right Trigger: 0 (For skipping the copy protection in Monkey Island 2)<br> - -Select: Exit ScummVM completely (and gracefully)<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Know_issues"></a><span style="font-weight: bold;">Know issues</span><br> - -<br> - -Possible random crash (well SegFault). I have had this happen twice and -have not tracked down the cause. <br> - -It happens very infrequently, both times it was in the DOTT CD intro. -Saving often is never a bad idea anyhow.<br> - -<br> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Major_TODOs"></a><span style="font-weight: bold;">Major TODO's</span><br> - -<br> - -Fix save support when using the Sky engine (Beneath a Steel Sky) - You -CAN'T save at the moment but auto save works.<br> - -Look into inconsistencies with AGOS engine and map Y key to a button -combination to allow clean quitting (Simon 1/2).<br> - -Add splash-screen and pre-ScummVM config menu (CPU speed, LCD timings -etc.) - Partly done.<br> - -Fix TV out, maybe make it an option in the pre-ScummVM config menu.<br> - -Any help appreciated :).<br> - -<br style="font-weight: bold;"> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Additional_resourceslinks"></a><span style="font-weight: bold;">Additional resources/links<br> - -<br> - -</span><span style="font-weight: bold;">Note:</span> -When providing feedback, -requests, forum posts, bug reports or anything like that always include -a mention of the version of ScummVM you are using (the build version, -date and time can be seen in the main game launcher window).<br> - -<ul> - - <li><a href="http://wiki.scummvm.org/index.php/GP2X">ScummVM -WiKi GP2X page</a></li> - - <li><a href="http://forums.scummvm.org/viewforum.php?f=14">ScummVM -forums GP2X forum</a></li> - - <li><a href="http://www.distant-earth.com/scummvm">My -own ScummVM page</a> (for SVN/test builds)</li> - - <li><a href="http://www.scummvm.org">Main ScummVM -site</a> (for official supported release builds)</li> - -</ul> - -<hr style="width: 100%; height: 2px;"><a style="font-weight: bold;" name="Credits"></a><span style="font-weight: bold;">Credits</span><br> - -<br> - -Core ScummVM code (c) The ScummVM Team<br> - -Portions of the GP2X backend (c) John Willis<br> - -Detailed (c) information can be found within the source code<br> - -<br> - -</body> -</html> diff --git a/backends/platform/gp2x/build/bundle.sh b/backends/platform/gp2x/build/bundle.sh index 560f096ed4..c68c62191b 100755 --- a/backends/platform/gp2x/build/bundle.sh +++ b/backends/platform/gp2x/build/bundle.sh @@ -19,7 +19,6 @@ echo "Please put your save games in this dir" >> "scummvm-gp2x-`date '+%Y-%m-%d' cp ./scummvm.gpe ./scummvm-gp2x-`date '+%Y-%m-%d'`/ cp ./scummvm.png ./scummvm-gp2x-`date '+%Y-%m-%d'`/ -cp ./README-GP2X.html ./scummvm-gp2x-`date '+%Y-%m-%d'`/ cp ./README-GP2X ./scummvm-gp2x-`date '+%Y-%m-%d'`/ cp ./mmuhack.o ./scummvm-gp2x-`date '+%Y-%m-%d'`/ cp ../../../../scummvm.gp2x ./scummvm-gp2x-`date '+%Y-%m-%d'`/ diff --git a/backends/platform/gp2x/build/config-alleng.sh b/backends/platform/gp2x/build/config-alleng.sh index 5724f39dc5..4a3526d50c 100755 --- a/backends/platform/gp2x/build/config-alleng.sh +++ b/backends/platform/gp2x/build/config-alleng.sh @@ -18,6 +18,6 @@ export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. ./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-all-engines --enable-vkeybd -# --enable-plugins --default-dynamic +#--enable-plugins --default-dynamic echo Generating config for GP2X complete. Check for errors. diff --git a/backends/platform/gp2x/build/config.sh b/backends/platform/gp2x/build/config.sh index 55954d6231..2bc49564f7 100755 --- a/backends/platform/gp2x/build/config.sh +++ b/backends/platform/gp2x/build/config.sh @@ -18,6 +18,6 @@ export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. ./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-vkeybd -# --enable-plugins --default-dynamic +#--enable-plugins --default-dynamic echo Generating config for GP2X complete. Check for errors. diff --git a/backends/platform/gp2x/events.cpp b/backends/platform/gp2x/events.cpp index 9a9a59765d..8cd034d2d5 100644 --- a/backends/platform/gp2x/events.cpp +++ b/backends/platform/gp2x/events.cpp @@ -35,7 +35,7 @@ #include "common/events.h" // FIXME move joystick defines out and replace with confile file options -// we should really allow users to map any key to a joystick button +// we should really allow users to map any key to a joystick button using the keymapper. #define JOY_DEADZONE 2200 #define JOY_XAXIS 0 @@ -273,7 +273,7 @@ bool OSystem_GP2X::pollEvent(Common::Event &event) { Combos: - GP2X_BUTTON_VOLUP & GP2X_BUTTON_VOLDOWN 0 (For Monkey 2 CP) + GP2X_BUTTON_VOLUP & GP2X_BUTTON_VOLDOWN 0 (For Monkey 2 CP) or Virtual Keyboard if enabled GP2X_BUTTON_L & GP2X_BUTTON_SELECT Common::EVENT_QUIT (Calls Sync() to make sure SD is flushed) GP2X_BUTTON_L & GP2X_BUTTON_Y Toggles setZoomOnMouse() for larger then 320*240 games to scale to the point + raduis. GP2X_BUTTON_L & GP2X_BUTTON_START Common::EVENT_MAINMENU (ScummVM Global Main Menu) @@ -434,29 +434,22 @@ bool OSystem_GP2X::pollEvent(Common::Event &event) { } break; case GP2X_BUTTON_VOLUP: - //if (GP2X_BUTTON_STATE_L == TRUE) { - // displayMessageOnOSD("Setting CPU Speed at 230MHz"); - // GP2X_setCpuspeed(200); - //event.kbd.keycode = Common::KEYCODE_PLUS; - //event.kbd.ascii = mapKey(SDLK_PLUS, ev.key.keysym.mod, 0); - //} else { - GP2X_mixer_move_volume(1); + GP2X_HW::mixerMoveVolume(2); + if (GP2X_HW::volumeLevel == 100) { + displayMessageOnOSD("Maximum Volume"); + } else { displayMessageOnOSD("Increasing Volume"); - //} + } break; case GP2X_BUTTON_VOLDOWN: - //if (GP2X_BUTTON_STATE_L == TRUE) { - // displayMessageOnOSD("Setting CPU Speed at 60MHz"); - // GP2X_setCpuspeed(60); - //event.kbd.keycode = Common::KEYCODE_MINUS; - //event.kbd.ascii = mapKey(SDLK_MINUS, ev.key.keysym.mod, 0); - //} else { - GP2X_mixer_move_volume(0); + GP2X_HW::mixerMoveVolume(1); + if (GP2X_HW::volumeLevel == 0) { + displayMessageOnOSD("Minimal Volume"); + } else { displayMessageOnOSD("Decreasing Volume"); - //} + } break; - } } return true; diff --git a/backends/platform/gp2x/gp2x-hw.cpp b/backends/platform/gp2x/gp2x-hw.cpp index fe02e029f7..38799ea7ad 100644 --- a/backends/platform/gp2x/gp2x-hw.cpp +++ b/backends/platform/gp2x/gp2x-hw.cpp @@ -48,6 +48,20 @@ #include <sys/time.h> #include <unistd.h> +namespace GP2X_HW { + +enum { + VOLUME_NOCHG = 0, + VOLUME_DOWN = 1, + VOLUME_UP = 2, + VOLUME_CHANGE_RATE = 8, + VOLUME_MIN = 0, + VOLUME_INITIAL = 70, + VOLUME_MAX = 100 +}; + +int volumeLevel = VOLUME_INITIAL; + /* system registers */ static struct { @@ -61,14 +75,14 @@ static volatile unsigned short *MEM_REG; #define SYS_CLK_FREQ 7372800 -void GP2X_device_init() { +void deviceInit() { // Open devices if (!gp2x_dev[0]) gp2x_dev[0] = open("/dev/mixer", O_RDWR); if (!gp2x_dev[1]) gp2x_dev[1] = open("/dev/batt", O_RDONLY); if (!gp2x_dev[2]) gp2x_dev[2] = open("/dev/mem", O_RDWR); } -void GP2X_device_deinit() { +void deviceDeinit() { // Close devices { int i; @@ -92,68 +106,35 @@ void GP2X_device_deinit() { unpatchMMU(); } -// Vairous mixer level fudges. -// TODO: Clean up and merge quick hacks. - -void GP2X_mixer_set_volume(int L /*0..100*/, int R /*0..100*/) { - - /* Set an arbitrary percentage value for the hardware mixer volume. - - Parameters: - L (0..100) - volume percentage for the left channel - R (0..100) - volume percentage for the right channel - - Note: - - A higher percentage than 100 will distort your sound. - */ - - unsigned char temp[4]; - - if (L < 0) L = 0; - if (L > GP2X_MAXVOL) L = GP2X_MAXVOL; - if (R < 0) R = 0; - if (R > GP2X_MAXVOL) R = GP2X_MAXVOL; - - temp[0]=(unsigned char)L; - temp[1]=(unsigned char)R; - temp[2]=temp[3]=0; - - //warning("GP2X_mixer_set_volume is about to set %d %d", L, R); - ioctl(gp2x_dev[0], SOUND_MIXER_WRITE_PCM, temp); -} - -int GP2X_mixer_get_volume() { - int vol; - ioctl(gp2x_dev[0], SOUND_MIXER_READ_PCM, &vol); - //warning("GP2X_mixer_get_volume returned %d %d", (int)((vol & 0xff)), (int)((vol >> 8) & 0xff)); - return (int)((vol & 0xff)); +void mixerMoveVolume(int direction) { + if (volumeLevel <= 10) { + if (direction == VOLUME_UP) volumeLevel += VOLUME_CHANGE_RATE/2; + if (direction == VOLUME_DOWN) volumeLevel -= VOLUME_CHANGE_RATE/2; + } else { + if(direction == VOLUME_UP) volumeLevel += VOLUME_CHANGE_RATE; + if(direction == VOLUME_DOWN) volumeLevel -= VOLUME_CHANGE_RATE; + } + + if (volumeLevel < VOLUME_MIN) volumeLevel = VOLUME_MIN; + if (volumeLevel > VOLUME_MAX) volumeLevel = VOLUME_MAX; + + unsigned long soundDev = open("/dev/mixer", O_RDWR); + + if(soundDev) { + int vol = ((volumeLevel << 8) | volumeLevel); + ioctl(soundDev, SOUND_MIXER_WRITE_PCM, &vol); + close(soundDev); + } } -void GP2X_mixer_move_volume(int UpDown) { - // Raise volume 5% if 1 passed, lower 5% if 0. - int curvol, newvol; - ioctl(gp2x_dev[0], SOUND_MIXER_READ_PCM, &curvol); - curvol = ((int)((curvol & 0xff))); - newvol = ((int)((curvol & 0xff))); - //warning("GP2X_mixer_move_volume got current volume @ %d", curvol); - if (UpDown == 1) { - newvol = (curvol + 5); - } else if (UpDown == 0) { - newvol = (curvol - 5); - } - //warning("GP2X_mixer_move_volume is about to set volume @ %d", newvol); - GP2X_mixer_set_volume(newvol, newvol); - return; -} - -void GP2X_setCpuspeed(unsigned int mhz) +void setCpuspeed(unsigned int mhz) { set_FCLK(mhz); set_DCLK_Div(0); set_920_Div(0); } -int GP2X_getBattLevel() { +int getBattLevel() { int devbatt; unsigned short currentval=0; devbatt = open("/dev/batt", O_RDONLY); @@ -213,3 +194,6 @@ void gp2x_video_wait_vsync(void) MEM_REG[0x2846>>1]=(MEM_REG[0x2846>>1] | 0x20) & ~2; while (!(MEM_REG[0x2846>>1] & 2)); } + +} /* namespace GP2X_HW */ + diff --git a/backends/platform/gp2x/gp2x-hw.h b/backends/platform/gp2x/gp2x-hw.h index 89ad1093e4..7e72812cc4 100644 --- a/backends/platform/gp2x/gp2x-hw.h +++ b/backends/platform/gp2x/gp2x-hw.h @@ -31,16 +31,18 @@ #ifndef GP2X_HW_H #define GP2X_HW_H +namespace GP2X_HW { + #define GP2X_MAXVOL 100 // Highest level permitted by GP2X's mixer #define SYS_CLK_FREQ 7372800 // Clock Frequency -extern void GP2X_device_init(); -extern void GP2X_device_deinit(); -extern void GP2X_mixer_set_volume(int, int); -extern int GP2X_mixer_get_volume(); -extern void GP2X_mixer_move_volume(int); -extern void GP2X_setCpuspeed(unsigned int cpuspeed); -extern int GP2X_getBattLevel(); +extern int volumeLevel; + +extern void deviceInit(); +extern void deviceDeinit(); +extern void mixerMoveVolume(int); +extern void setCpuspeed(unsigned int cpuspeed); +extern int getBattLevel(); extern void save_system_regs(void); /* save some registers */ extern void set_display_clock_div(unsigned div); @@ -50,4 +52,6 @@ extern void set_DCLK_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+di extern void Disable_940(void); /* 940t down */ extern void gp2x_video_wait_vsync(void); +} /* namespace GP2X_HW */ + #endif //GP2X_HW_H diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp index 15b5e19e5d..3d416f8415 100644 --- a/backends/platform/gp2x/gp2x.cpp +++ b/backends/platform/gp2x/gp2x.cpp @@ -34,6 +34,7 @@ #include "common/archive.h" #include "common/config-manager.h" #include "common/debug.h" +#include "common/EventRecorder.h" #include "common/events.h" #include "common/util.h" @@ -232,15 +233,16 @@ void OSystem_GP2X::initBackend() { // switch. Still, it's a potential future change to keep in mind. _timer = new DefaultTimerManager(); _timerID = SDL_AddTimer(10, &timer_handler, _timer); + } + + /* Initialise any GP2X specific stuff we may want (Batt Status, scaler etc.) */ + GP2X_HW::deviceInit(); - // Initialise any GP2X specific stuff we may want (Volume, Batt Status etc.) - GP2X_device_init(); + /* Set Default hardware mixer volume to a preset level (VOLUME_INITIAL). This is done to 'reset' volume level if set by other apps. */ + GP2X_HW::mixerMoveVolume(0); // Set Default hardware mixer volume to a plesent level. // This is done to 'reset' volume level if set by other apps. - GP2X_mixer_set_volume(70, 70); - - } //if (SDL_GP2X_MouseType() == 0) { // // No mouse, F100 default state. @@ -318,7 +320,7 @@ OSystem_GP2X::~OSystem_GP2X() { uint32 OSystem_GP2X::getMillis() { uint32 millis = SDL_GetTicks(); - getEventManager()->processMillis(millis); + g_eventRec.processMillis(millis); return millis; } @@ -446,8 +448,7 @@ void OSystem_GP2X::quit() { if (_joystick) SDL_JoystickClose(_joystick); - //CloseRam(); - GP2X_device_deinit(); + GP2X_HW::deviceDeinit(); SDL_RemoveTimer(_timerID); closeMixer(); diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp index 775c3afb73..a77afd88b7 100644 --- a/backends/platform/gp2x/graphics.cpp +++ b/backends/platform/gp2x/graphics.cpp @@ -30,6 +30,7 @@ #include "backends/platform/gp2x/gp2x-common.h" #include "common/util.h" +#include "common/mutex.h" #include "graphics/font.h" #include "graphics/fontman.h" #include "graphics/scaler.h" diff --git a/backends/platform/gp2xwiz/build/README-GP2XWIZ b/backends/platform/gp2xwiz/build/README-GP2XWIZ index 95ac844a2c..ec8142a6f3 100644 --- a/backends/platform/gp2xwiz/build/README-GP2XWIZ +++ b/backends/platform/gp2xwiz/build/README-GP2XWIZ @@ -11,19 +11,27 @@ Contents: * Recent changes <#Recent_changes> * How to save <#How_to_save> * Controller mappings <#Controller_mappings> - * Know issues <#Know_issues> - * Major TODO's <#Major_TODOs> + * Known issues <#Knonw_issues> * Additional resources/links <#Additional_resourceslinks> * Credits <#Credits> +------------------------------------------------------------------------ + +Please refer to the: + +GP2X/GP2XWiz ScummVM Forum: <http://forums.scummvm.org/viewforum.php?f=14> +WiKi: <http://wiki.scummvm.org/index.php/GP2XWiz> + +for the most current information on the port and any updates to this +documentation. ------------------------------------------------------------------------ About the backend/port -This is the readme for the offficial GP2X WIZ ScummVM backend (also known as -the GP2X WIZ port). +This is the readme for the official GP2XWiz ScummVM backend (also known as +the GP2XWiz port). -This is an SVN test release of ScummVM for the GP2X WIZ, it would be +This is an SVN test release of ScummVM for the GP2XWiz, it would be appreciated if this SVN test distribution was not mirrored and that people be directed to http://scummvm.distant-earth.com/ instead for updated SVN builds. @@ -35,19 +43,12 @@ downloads page <http://www.scummvm.org/downloads.php>. This build is in an active state of development and as such no "expected" behavior can be guaranteed ;). -SVN builds are quickly tested with firmware 1.0.0 for reference. - -Please refer to the GP2X/GP2X WIZ ScummVM forum -<http://forums.scummvm.org/viewforum.php?f=14> and WiKi -<http://wiki.scummvm.org/index.php/GP2X> for the latest information on -the port. - ------------------------------------------------------------------------ Game compatibility For information on the compatability of a specific game please refer to -the GP2X compatability section of the ScummVM WiKi -<http://wiki.scummvm.org/index.php/GP2X#Compatibility_List>. +the GP2XWiz compatability section of the ScummVM WiKi +<http://wiki.scummvm.org/index.php/GP2XWiz#Compatibility_List>. Please note the version and date of the ScummVM build you are running when reviewing the above list. @@ -105,22 +106,20 @@ Right Trigger: Return Select: Escape Y: Space Bar (Pause) Menu: Game Menu (Save, Load, Quit etc.) -Volume Buttons: Increase and Decrease volume (5% per press) +Volume Buttons: Increase and Decrease volume Fancy button combos: NOTE: To use button combos press and hold the Left Trigger then... -Right Trigger: 0 (For skipping the copy protection in Monkey Island 2) +Right Trigger: Display Virtual Keyboard Menu: Bring up the Global main menu for ScummVM Select: Exit ScummVM completely (and gracefully) ------------------------------------------------------------------------ -Know issues +Known issues -Possible random crash (well SegFault). I have had this happen twice and -have not tracked down the cause. -It happens very infrequently, both times it was in the DOTT CD intro. +No major known issues ------------------------------------------------------------------------ Additional resources/links @@ -128,7 +127,7 @@ Additional resources/links * ScummVM WiKi GP2X page <http://wiki.scummvm.org/index.php/GP2X> * ScummVM forums GP2X forum <http://forums.scummvm.org/viewforum.php?f=14> - * My own ScummVM page <http://www.distant-earth.com/scummvm> (for + * My own ScummVM page <http://scummvm.distant-earth.com/> (for SVN/test builds) * Main ScummVM site <http://www.scummvm.org> (for official supported release builds) diff --git a/backends/platform/gp2xwiz/build/bundle.sh b/backends/platform/gp2xwiz/build/bundle.sh index 506dfcb742..492ba9e1c6 100755 --- a/backends/platform/gp2xwiz/build/bundle.sh +++ b/backends/platform/gp2xwiz/build/bundle.sh @@ -8,6 +8,8 @@ mkdir "scummvm-wiz-`date '+%Y-%m-%d'`/scummvm" mkdir "scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/saves" mkdir "scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/plugins" mkdir "scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/engine-data" +mkdir "scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/lib" + echo "Please put your save games in this dir" >> "scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/saves/PUT_SAVES_IN_THIS_DIR" @@ -27,6 +29,13 @@ cp ../../../../dists/pred.dic ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/ cp ../../../../dists/engine-data/* ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/engine-data cp ../../../../plugins/* ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/plugins +# Copy over dynamic libs needed by the app (as the ones in the default filesystem are broken). +f=`which arm-open2x-linux-g++` +loc=`dirname "$f"` +cp $loc/../lib/libz.so.1.2.3 ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/lib/libz.so.1 +cp $loc/../lib/libvorbisidec.so.1.0.2 ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/lib/libvorbisidec.so.1 + + echo Making Stripped exe. arm-open2x-linux-strip ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/scummvm.wiz diff --git a/backends/platform/gp2xwiz/build/scummvm.gpe b/backends/platform/gp2xwiz/build/scummvm.gpe index 037b81d937..42cc00a22a 100755 --- a/backends/platform/gp2xwiz/build/scummvm.gpe +++ b/backends/platform/gp2xwiz/build/scummvm.gpe @@ -1,5 +1,9 @@ #!/bin/sh +# Export the location of any libs ScummVM depends on +# (to avoid installing to the NAND and overwriting the broken ones there). +export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH + # Run ScummVM, important this bit. ./scummvm.wiz --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc diff --git a/backends/platform/gp2xwiz/gp2xwiz-events.cpp b/backends/platform/gp2xwiz/gp2xwiz-events.cpp index dfb36742dc..48c9af00ff 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-events.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-events.cpp @@ -81,8 +81,13 @@ static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) { } void OSystem_GP2XWIZ::fillMouseEvent(Common::Event &event, int x, int y) { - event.mouse.x = x; - event.mouse.y = y; + if(_videoMode.mode == GFX_HALF && !_overlayVisible){ + event.mouse.x = x*2; + event.mouse.y = y*2; + } else { + event.mouse.x = x; + event.mouse.y = y; + } // Update the "keyboard mouse" coords _km.x = x; @@ -203,7 +208,7 @@ bool OSystem_GP2XWIZ::pollEvent(Common::Event &event) { Combos: - GP2X_BUTTON_VOLUP & GP2X_BUTTON_VOLDOWN 0 (For Monkey 2 CP) + GP2X_BUTTON_VOLUP & GP2X_BUTTON_VOLDOWN 0 (For Monkey 2 CP) or Virtual Keyboard if enabled GP2X_BUTTON_L & GP2X_BUTTON_SELECT Common::EVENT_QUIT (Calls Sync() to make sure SD is flushed) GP2X_BUTTON_L & GP2X_BUTTON_MENU Common::EVENT_MAINMENU (ScummVM Global Main Menu) GP2X_BUTTON_L & GP2X_BUTTON_A Common::EVENT_PREDICTIVE_DIALOG for predictive text entry box (AGI games) diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp index 2482051286..90f2c821aa 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp @@ -24,10 +24,433 @@ */ #include "backends/platform/gp2xwiz/gp2xwiz-sdl.h" +#include "backends/platform/gp2xwiz/gp2xwiz-scaler.h" // TODO: Make GFX_HALF/HalfScale generic. +#include "common/mutex.h" +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/scaler/intern.h" +#include "graphics/surface.h" -/* TODO: Add code to ensure that overlay is always 320*240 and maybe invoke some custom scale code. */ +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"1x", "Fullscreen", GFX_NORMAL}, +// {"½x", "Downscale", GFX_HALF}, + {0, 0, 0} +}; + + +const OSystem::GraphicsMode *OSystem_GP2XWIZ::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_GP2XWIZ::getDefaultGraphicsMode() const { + return GFX_NORMAL; +} + +bool OSystem_GP2XWIZ::setGraphicsMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) + return true; + + int newScaleFactor = 1; + + switch(mode) { + case GFX_NORMAL: + newScaleFactor = 1; + break; + case GFX_HALF: + newScaleFactor = 1; + break; + default: + warning("unknown gfx mode %d", mode); + return false; + } + + _transactionDetails.normal1xScaler = (mode == GFX_NORMAL); + if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor) + _transactionDetails.needHotswap = true; + + _transactionDetails.needUpdatescreen = true; + + _videoMode.mode = mode; + _videoMode.scaleFactor = newScaleFactor; + + return true; +} + +void OSystem_GP2XWIZ::setGraphicsModeIntern() { + Common::StackLock lock(_graphicsMutex); + ScalerProc *newScalerProc = 0; + + switch (_videoMode.mode) { + case GFX_NORMAL: + newScalerProc = Normal1x; + break; + case GFX_HALF: + newScalerProc = HalfScale; + break; + + default: + error("Unknown gfx mode %d", _videoMode.mode); + } + + _scalerProc = newScalerProc; + + if (!_screen || !_hwscreen) + return; + + // Blit everything to the screen + _forceFull = true; + + // Even if the old and new scale factors are the same, we may have a + // different scaler for the cursor now. + blitCursor(); +} + + +void OSystem_GP2XWIZ::initSize(uint w, uint h) { + assert(_transactionMode == kTransactionActive); + + // Avoid redundant res changes + if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) + return; + + _videoMode.screenWidth = w; + _videoMode.screenHeight = h; + if(w > 320 || h > 240){ + setGraphicsMode(GFX_HALF); + setGraphicsModeIntern(); + toggleMouseGrab(); + } + + _cksumNum = (w * h / (8 * 8)); + + _transactionDetails.sizeChanged = true; + + free(_dirtyChecksums); + _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32)); +} bool OSystem_GP2XWIZ::loadGFXMode() { + _videoMode.overlayWidth = 320; + _videoMode.overlayHeight = 240; + _videoMode.fullscreen = true; + + if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400) + _videoMode.aspectRatioCorrection = false; + OSystem_SDL::loadGFXMode(); } + +void OSystem_GP2XWIZ::drawMouse() { + if (!_mouseVisible || !_mouseSurface) { + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + return; + } + + SDL_Rect dst; + int scale; + int width, height; + int hotX, hotY; + + if(_videoMode.mode == GFX_HALF && !_overlayVisible){ + dst.x = _mouseCurState.x/2; + dst.y = _mouseCurState.y/2; + } else { + dst.x = _mouseCurState.x; + dst.y = _mouseCurState.y; + } + + if (!_overlayVisible) { + scale = _videoMode.scaleFactor; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + dst.w = _mouseCurState.vW; + dst.h = _mouseCurState.vH; + hotX = _mouseCurState.vHotX; + hotY = _mouseCurState.vHotY; + } else { + scale = 1; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + hotX = _mouseCurState.rHotX; + hotY = _mouseCurState.rHotY; + } + + // The mouse is undrawn using virtual coordinates, i.e. they may be + // scaled and aspect-ratio corrected. + + _mouseBackup.x = dst.x - hotX; + _mouseBackup.y = dst.y - hotY; + _mouseBackup.w = dst.w; + _mouseBackup.h = dst.h; + + // We draw the pre-scaled cursor image, so now we need to adjust for + // scaling, shake position and aspect ratio correction manually. + + if (!_overlayVisible) { + dst.y += _currentShakePos; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst.y = real2Aspect(dst.y); + + dst.x = scale * dst.x - _mouseCurState.rHotX; + dst.y = scale * dst.y - _mouseCurState.rHotY; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + + // Note that SDL_BlitSurface() and addDirtyRect() will both perform any + // clipping necessary + + if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + // The screen will be updated using real surface coordinates, i.e. + // they will not be scaled or aspect-ratio corrected. + addDirtyRect(dst.x, dst.y, dst.w, dst.h, true); +} + +void OSystem_GP2XWIZ::undrawMouse() { + const int x = _mouseBackup.x; + const int y = _mouseBackup.y; + + // When we switch bigger overlay off mouse jumps. Argh! + // This is intended to prevent undrawing offscreen mouse + if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight)) + return; + + if (_mouseBackup.w != 0 && _mouseBackup.h != 0){ + if(_videoMode.mode == GFX_HALF && !_overlayVisible){ + addDirtyRect(x*2, y*2, _mouseBackup.w*2, _mouseBackup.h*2); + } else { + addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h); + } + } +} + +void OSystem_GP2XWIZ::internUpdateScreen() { + SDL_Surface *srcSurf, *origSurf; + int height, width; + ScalerProc *scalerProc; + int scale1; + +#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?) + assert(_hwscreen != NULL); + assert(_hwscreen->map->sw_data != NULL); +#endif + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos) { + SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor}; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + blackrect.h = real2Aspect(blackrect.h - 1) + 1; + + SDL_FillRect(_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_screen && _paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + +#ifdef USE_OSD + // OSD visible (i.e. non-transparent)? + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + // Updated alpha value + const int diff = SDL_GetTicks() - _osdFadeStartTime; + if (diff > 0) { + if (diff >= kOSDFadeOutDuration) { + // Back to full transparency + _osdAlpha = SDL_ALPHA_TRANSPARENT; + } else { + // Do a linear fade out... + const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + } + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + _forceFull = true; + } + } +#endif + + if (!_overlayVisible) { + origSurf = _screen; + srcSurf = _tmpscreen; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + scalerProc = _scalerProc; + scale1 = _videoMode.scaleFactor; + } else { + origSurf = _overlayscreen; + srcSurf = _tmpscreen2; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + scalerProc = Normal1x; + + scale1 = 1; + } + + // Add the area covered by the mouse cursor to the list of dirty rects if + // we have to redraw the mouse. + if (_mouseNeedsRedraw) + undrawMouse(); + + // Force a full redraw if requested + if (_forceFull) { + _numDirtyRects = 1; + _dirtyRectList[0].x = 0; + _dirtyRectList[0].y = 0; + _dirtyRectList[0].w = width; + _dirtyRectList[0].h = height; + } + + // Only draw anything if necessary + if (_numDirtyRects > 0 || _mouseNeedsRedraw) { + SDL_Rect *r; + SDL_Rect dst; + uint32 srcPitch, dstPitch; + SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects; + + for (r = _dirtyRectList; r != lastRect; ++r) { + dst = *r; + dst.x++; // Shift rect by one since 2xSai needs to access the data around + dst.y++; // any pixel to scale it, and we want to avoid mem access crashes. + + if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + } + + SDL_LockSurface(srcSurf); + SDL_LockSurface(_hwscreen); + + srcPitch = srcSurf->pitch; + dstPitch = _hwscreen->pitch; + + for (r = _dirtyRectList; r != lastRect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + register int dst_w = r->w; + register int orig_dst_y = 0; + register int dst_x = r->x; + register int src_y; + register int src_x; + + if (dst_y < height) { + dst_h = r->h; + if (dst_h > height - dst_y) + dst_h = height - dst_y; + + orig_dst_y = dst_y; + src_x = dst_x; + src_y = dst_y; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst_y = real2Aspect(dst_y); + + assert(scalerProc != NULL); + + if(_videoMode.mode == GFX_HALF && scalerProc == HalfScale){ + if(dst_x%2==1){ + dst_x--; + dst_w++; + } + if(dst_y%2==1){ + dst_y--; + dst_h++; + } + src_x = dst_x; + src_y = dst_y; + dst_x = dst_x / 2; + dst_y = dst_y / 2; + } + scalerProc((byte *)srcSurf->pixels + (src_x * 2 + 2) + (src_y + 1) * srcPitch, srcPitch, + (byte *)_hwscreen->pixels + dst_x * 2 + dst_y * dstPitch, dstPitch, dst_w, dst_h); + } + + if(_videoMode.mode == GFX_HALF && scalerProc == HalfScale){ + r->w = r->w / 2; + r->h = dst_h / 2; + } else { + r->w = r->w; + r->h = dst_h; + } + + r->x = dst_x; + r->y = dst_y; + + +#ifndef DISABLE_SCALERS + if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible) + r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1); +#endif + } + SDL_UnlockSurface(srcSurf); + SDL_UnlockSurface(_hwscreen); + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirtyRectList[0].y = 0; + _dirtyRectList[0].h = (_videoMode.mode == GFX_HALF) ? effectiveScreenHeight()/2 : effectiveScreenHeight(); + } + + drawMouse(); + +#ifdef USE_OSD + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } +#endif + // Finally, blit all our changes to the screen + SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } + + _numDirtyRects = 0; + _forceFull = false; + _mouseNeedsRedraw = false; +} + +void OSystem_GP2XWIZ::showOverlay() { + if(_videoMode.mode == GFX_HALF){ + _mouseCurState.x = _mouseCurState.x / 2; + _mouseCurState.y = _mouseCurState.y / 2; + } + OSystem_SDL::showOverlay(); +} + +void OSystem_GP2XWIZ::hideOverlay() { + if(_videoMode.mode == GFX_HALF){ + _mouseCurState.x = _mouseCurState.x * 2; + _mouseCurState.y = _mouseCurState.y * 2; + } + OSystem_SDL::hideOverlay(); +} + +void OSystem_GP2XWIZ::warpMouse(int x, int y) { + if (_mouseCurState.x != x || _mouseCurState.y != y) { + if(_videoMode.mode == GFX_HALF && !_overlayVisible){ + x = x / 2; + y = y / 2; + } + } + OSystem_SDL::warpMouse(x, y); +} diff --git a/backends/platform/gp2xwiz/gp2xwiz-hw.cpp b/backends/platform/gp2xwiz/gp2xwiz-hw.cpp index 4d69915e27..4a86443aa7 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-hw.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-hw.cpp @@ -48,7 +48,7 @@ enum { VOLUME_UP = 2, VOLUME_CHANGE_RATE = 8, VOLUME_MIN = 0, - VOLUME_INITIAL = 70, + VOLUME_INITIAL = 60, VOLUME_MAX = 100 }; diff --git a/backends/platform/gp2xwiz/gp2xwiz-main.cpp b/backends/platform/gp2xwiz/gp2xwiz-main.cpp index 4bd3f98211..394c3090c3 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-main.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-main.cpp @@ -148,9 +148,9 @@ void OSystem_GP2XWIZ::initBackend() { WIZ_HW::mixerMoveVolume(0); /* Up default volume values as we use a seperate system level volume anyway. */ - ConfMan.registerDefault("music_volume", 220); - ConfMan.registerDefault("sfx_volume", 220); - ConfMan.registerDefault("speech_volume", 220); + ConfMan.registerDefault("music_volume", 192); + ConfMan.registerDefault("sfx_volume", 192); + ConfMan.registerDefault("speech_volume", 192); /* Trigger autosave every 4 minutes - On low batts 5 mins is about your warning time. */ ConfMan.registerDefault("autosave_period", 4 * 60); diff --git a/backends/platform/gp2xwiz/gp2xwiz-scaler.cpp b/backends/platform/gp2xwiz/gp2xwiz-scaler.cpp new file mode 100644 index 0000000000..3a95280eab --- /dev/null +++ b/backends/platform/gp2xwiz/gp2xwiz-scaler.cpp @@ -0,0 +1,40 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ +#include "graphics/scaler/intern.h" +#include "backends/platform/gp2xwiz/gp2xwiz-sdl.h" + +SDL_PixelFormat *screenPixelFormat; + +extern "C" { + void PocketPCHalfARM(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height, int mask, int round); + // Rounding constants and masks used for different pixel formats + int roundingconstants[] = { 0x00200802, 0x00201002 }; + int redbluegreenMasks[] = { 0x03E07C1F, 0x07E0F81F }; +} + +void HalfScale(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + int maskUsed = (gBitFormat == 565); + PocketPCHalfARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height, redbluegreenMasks[maskUsed],roundingconstants[maskUsed]); +} diff --git a/backends/platform/gp2xwiz/gp2xwiz-scaler.h b/backends/platform/gp2xwiz/gp2xwiz-scaler.h new file mode 100644 index 0000000000..5867693dfb --- /dev/null +++ b/backends/platform/gp2xwiz/gp2xwiz-scaler.h @@ -0,0 +1,42 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GP2XWIZ_SCALER_H +#define GP2XWIZ_SCALER_H + +#include "common/scummsys.h" +#include "common/system.h" +#include "graphics/scaler.h" +#include "graphics/scaler/intern.h" + +// FIXME: For now keep hacks in this header to save polluting the SDL backend. +enum { + GFX_HALF = 12 +}; + +// TODO/FIXME: Move this platform specific scaler into /graphics/scaler and properly merge with the WinCE PocketPCHalf that it is based on. +DECLARE_SCALER(HalfScale); + +#endif diff --git a/backends/platform/gp2xwiz/gp2xwiz-sdl.h b/backends/platform/gp2xwiz/gp2xwiz-sdl.h index 8811f86edf..1f67624d5c 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-sdl.h +++ b/backends/platform/gp2xwiz/gp2xwiz-sdl.h @@ -27,6 +27,7 @@ #define GP2XWIZ_SDL_H #include "backends/platform/sdl/sdl.h" +#include "backends/platform/gp2xwiz/gp2xwiz-scaler.h" #include <SDL.h> @@ -42,12 +43,24 @@ public: OSystem_GP2XWIZ() {} /* Graphics */ - bool loadGFXMode(); + void initSize(uint w, uint h); + void setGraphicsModeIntern(); + bool setGraphicsMode(int mode); + void internUpdateScreen(); + const OSystem::GraphicsMode *getSupportedGraphicsModes() const; + bool setGraphicsMode(const char *name); + int getDefaultGraphicsMode() const; + bool loadGFXMode(); + void drawMouse(); + void undrawMouse(); + void showOverlay(); + void hideOverlay(); /* Event Stuff */ bool pollEvent(Common::Event &event); void moveStick(); void fillMouseEvent(Common::Event&, int, int); + void warpMouse(int, int); bool remapKey(SDL_Event&, Common::Event&); /* Platform Setup Stuff */ diff --git a/backends/platform/gp2xwiz/module.mk b/backends/platform/gp2xwiz/module.mk index 03241f7b60..f2e27a7cce 100644 --- a/backends/platform/gp2xwiz/module.mk +++ b/backends/platform/gp2xwiz/module.mk @@ -1,6 +1,8 @@ MODULE := backends/platform/gp2xwiz MODULE_OBJS := \ + gp2xwiz-scaler.o \ + ../wince/ARMscaler.o \ gp2xwiz-graphics.o \ gp2xwiz-events.o \ gp2xwiz-hw.o \ diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp index 78b8bd8c63..ffdcd675e6 100644 --- a/backends/platform/sdl/graphics.cpp +++ b/backends/platform/sdl/graphics.cpp @@ -364,7 +364,7 @@ bool OSystem_SDL::loadGFXMode() { int hwW, hwH; -#ifndef __MAEMO__ +#if !defined(__MAEMO__) && !defined(GP2XWIZ) _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; @@ -675,7 +675,7 @@ void OSystem_SDL::internUpdateScreen() { for (r = _dirtyRectList; r != lastRect; ++r) { dst = *r; - dst.x++; // Shift rect by one since 2xSai needs to acces the data around + dst.x++; // Shift rect by one since 2xSai needs to access the data around dst.y++; // any pixel to scale it, and we want to avoid mem access crashes. if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0) diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 57a277d1ff..e40966f6b0 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -33,7 +33,7 @@ #include "common/archive.h" #include "common/config-manager.h" #include "common/debug.h" -#include "common/events.h" +#include "common/EventRecorder.h" #include "common/util.h" #ifdef UNIX @@ -263,7 +263,7 @@ OSystem_SDL::~OSystem_SDL() { uint32 OSystem_SDL::getMillis() { uint32 millis = SDL_GetTicks(); - getEventManager()->processMillis(millis); + g_eventRec.processMillis(millis); return millis; } diff --git a/backends/platform/wii/osystem_events.cpp b/backends/platform/wii/osystem_events.cpp index f28e5b547b..0967db1625 100644 --- a/backends/platform/wii/osystem_events.cpp +++ b/backends/platform/wii/osystem_events.cpp @@ -316,13 +316,13 @@ bool OSystem_Wii::pollEvent(Common::Event &event) { #endif if (bd || bu) { - PAD_EVENT(PADS_Z, Common::KEYCODE_RETURN, Common::ASCII_RETURN, 0); - PAD_EVENT(PADS_X, Common::KEYCODE_ESCAPE, Common::ASCII_ESCAPE, 0); - PAD_EVENT(PADS_Y, Common::KEYCODE_PERIOD, '.', 0); - PAD_EVENT(PADS_START, Common::KEYCODE_F5, Common::ASCII_F5, 0); - PAD_EVENT(PADS_UP, Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL); - PAD_EVENT(PADS_DOWN, Common::KEYCODE_F7, Common::ASCII_F7, 0); - //PAD_EVENT(PADS_LEFT, Common::KEYCODE_F8, Common::ASCII_F8, 0); + byte flags = 0; + + if (bh & PADS_UP) { + PAD_EVENT(PADS_START, Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL); + + flags = Common::KBD_SHIFT; + } if (bd & PADS_RIGHT) { event.type = Common::EVENT_PREDICTIVE_DIALOG; @@ -330,6 +330,14 @@ bool OSystem_Wii::pollEvent(Common::Event &event) { return true; } + PAD_EVENT(PADS_Z, Common::KEYCODE_RETURN, Common::ASCII_RETURN, flags); + PAD_EVENT(PADS_X, Common::KEYCODE_ESCAPE, Common::ASCII_ESCAPE, flags); + PAD_EVENT(PADS_Y, Common::KEYCODE_PERIOD, '.', flags); + PAD_EVENT(PADS_START, Common::KEYCODE_F5, Common::ASCII_F5, flags); + PAD_EVENT(PADS_UP, Common::KEYCODE_LSHIFT, 0, flags); + PAD_EVENT(PADS_DOWN, Common::KEYCODE_F7, Common::ASCII_F7, flags); + //PAD_EVENT(PADS_LEFT, Common::KEYCODE_F8, Common::ASCII_F8, 0); + if ((bd | bu) & (PADS_A | PADS_B)) { if (bd & PADS_A) event.type = Common::EVENT_LBUTTONDOWN; diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 1f6eeb3770..45dbad12cc 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -133,12 +133,14 @@ void CEActionsPocket::initInstanceGame() { bool is_tucker = (gameid == "tucker"); bool is_groovie = (gameid == "groovie"); bool is_tinsel = (gameid == "tinsel"); + bool is_cruise = (gameid == "cruise"); + bool is_made = (gameid == "made"); GUI_Actions::initInstanceGame(); // See if a right click mapping could be needed if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_tinsel || - is_samnmax || is_cine || is_touche || is_parallaction || is_drascula) + is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise) _right_click_needed = true; // See if a "hide toolbar" mapping could be needed @@ -158,10 +160,10 @@ void CEActionsPocket::initInstanceGame() { } else if (is_sky) { _action_enabled[POCKET_ACTION_SAVE] = true; _key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_F5, SDLK_F5); - } else if (is_cine || is_drascula) { + } else if (is_cine || is_drascula || is_cruise) { _action_enabled[POCKET_ACTION_SAVE] = true; _key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_F10, SDLK_F10); // F10 - } else if (is_agi) { + } else if (is_agi || is_made) { _action_enabled[POCKET_ACTION_SAVE] = true; _key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_ESCAPE, SDLK_ESCAPE); } else if (is_parallaction) { @@ -177,7 +179,7 @@ void CEActionsPocket::initInstanceGame() { // Quit _action_enabled[POCKET_ACTION_QUIT] = true; // Skip - if (!is_cine && !is_parallaction && !is_groovie) + if (!is_cine && !is_parallaction && !is_groovie && !is_cruise && !is_made) _action_enabled[POCKET_ACTION_SKIP] = true; if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_tinsel || is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker) @@ -214,6 +216,12 @@ void CEActionsPocket::initInstanceGame() { _key_action[POCKET_ACTION_MULTI].setKey('V', SDLK_v, KMOD_SHIFT); // FT cheat : shift-V // Key bind method _action_enabled[POCKET_ACTION_BINDKEYS] = true; + // Disable double-tap right-click for convenience + if (is_tinsel || is_cruise) + if (!ConfMan.hasKey("no_doubletap_rightclick")) { + ConfMan.setBool("no_doubletap_rightclick", true); + ConfMan.flushToDisk(); + } } diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index 99f73bf37d..47733ae317 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -123,12 +123,14 @@ void CEActionsSmartphone::initInstanceGame() { bool is_tucker = (gameid == "tucker"); bool is_groovie = (gameid == "groovie"); bool is_tinsel = (gameid == "tinsel"); + bool is_cruise = (gameid == "cruise"); + bool is_made = (gameid == "made"); GUI_Actions::initInstanceGame(); // See if a right click mapping could be needed if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_tinsel || - is_samnmax || is_cine || is_touche || is_parallaction || is_drascula) + is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise) _right_click_needed = true; // Initialize keys for different actions @@ -141,10 +143,10 @@ void CEActionsSmartphone::initInstanceGame() { } else if (is_sky) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; _key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_F5, SDLK_F5); - } else if (is_cine || is_drascula) { + } else if (is_cine || is_drascula || is_cruise) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; _key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_F10, SDLK_F10); //F10 - } else if (is_agi) { + } else if (is_agi || is_made) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; _key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_ESCAPE, SDLK_ESCAPE); } else if (is_parallaction) { @@ -160,7 +162,8 @@ void CEActionsSmartphone::initInstanceGame() { // Skip _action_enabled[SMARTPHONE_ACTION_SKIP] = true; if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_tinsel || - is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker || is_groovie) + is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker || + is_groovie || is_cruise || is_made) _key_action[SMARTPHONE_ACTION_SKIP].setKey(VK_ESCAPE); else _key_action[SMARTPHONE_ACTION_SKIP].setKey(KEY_ALL_SKIP); @@ -178,6 +181,12 @@ void CEActionsSmartphone::initInstanceGame() { _key_action[SMARTPHONE_ACTION_MULTI].setKey('V', SDLK_v, KMOD_SHIFT); // FT cheat : shift-V // Bind keys _action_enabled[SMARTPHONE_ACTION_BINDKEYS] = true; + // Disable double-tap right-click for convenience + if (is_tinsel || is_cruise) + if (!ConfMan.hasKey("no_doubletap_rightclick")) { + ConfMan.setBool("no_doubletap_rightclick", true); + ConfMan.flushToDisk(); + } } diff --git a/backends/platform/wince/CEScaler.cpp b/backends/platform/wince/CEScaler.cpp index bfdb74319d..d26db3190f 100644 --- a/backends/platform/wince/CEScaler.cpp +++ b/backends/platform/wince/CEScaler.cpp @@ -53,15 +53,6 @@ void PocketPCPortraitTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPt } MAKE_WRAPPER(PocketPCPortrait) -void PocketPCRawPortrait(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { - - while (height--) { - memcpy(dstPtr, srcPtr, width*sizeof(uint16_t)); - srcPtr += srcPitch; - dstPtr += dstPitch; - } -} - // Our version of an aspect scaler. Main difference is the out-of-place // operation, omitting a straight blit step the sdl backend does. Also, // tests show unaligned access errors with the stock aspect scaler. @@ -234,8 +225,8 @@ void SmartphoneLandscape(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, ui SmartphoneLandscapeARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height, redbluegreenMasks[maskUsed]); #else if (gBitFormat == 565) - SmartphoneLandscape<565>(srcPtr, srcPitch, dstPtr, dstPitch, width, height); + SmartphoneLandscapeTemplate<565>(srcPtr, srcPitch, dstPtr, dstPitch, width, height); else - SmartphoneLandscape<555>(srcPtr, srcPitch, dstPtr, dstPitch, width, height); + SmartphoneLandscapeTemplate<555>(srcPtr, srcPitch, dstPtr, dstPitch, width, height); #endif } diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.cpp b/backends/platform/wince/CEgui/SDL_ImageResource.cpp index e1a9d911de..ce6ebd6382 100644 --- a/backends/platform/wince/CEgui/SDL_ImageResource.cpp +++ b/backends/platform/wince/CEgui/SDL_ImageResource.cpp @@ -60,7 +60,7 @@ namespace CEGUI { _surface = SDL_LoadBMP_RW(surfaceData, 1); return _surface; - }; + } SDL_Surface* SDL_ImageResource::get() { return _surface; diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile index 1846029469..acade8ac9a 100644 --- a/backends/platform/wince/Makefile +++ b/backends/platform/wince/Makefile @@ -39,12 +39,12 @@ ENABLE_PARALLACTION = STATIC_PLUGIN ENABLE_DRASCULA = STATIC_PLUGIN ENABLE_GROOVIE = STATIC_PLUGIN ENABLE_TUCKER = STATIC_PLUGIN +ENABLE_TINSEL = STATIC_PLUGIN +ENABLE_CRUISE = STATIC_PLUGIN +ENABLE_MADE = STATIC_PLUGIN #ENABLE_SCI = STATIC_PLUGIN -#ENABLE_TINSEL = STATIC_PLUGIN -#ENABLE_CRUISE = STATIC_PLUGIN #ENABLE_IGOR = STATIC_PLUGIN #ENABLE_M4 = STATIC_PLUGIN -#ENABLE_MADE = STATIC_PLUGIN ######################################################################## ## Pick which libraries you want to use here @@ -76,6 +76,7 @@ USE_ARM_SOUND_ASM = 1 USE_ARM_SMUSH_ASM = 1 USE_ARM_GFX_ASM = 1 USE_ARM_COSTUME_ASM = 1 +USE_ARM_SCALER_ASM = 1 ######################################################################## ## Hopefully you shouldn't need to change anything below here. ## @@ -167,6 +168,10 @@ ifdef USE_ARM_COSTUME_ASM DEFINES += -DUSE_ARM_COSTUME_ASM endif +ifdef USE_ARM_SCALER_ASM +DEFINES += -DUSE_ARM_SCALER_ASM +endif + ######################################################################## # Targets follow here diff --git a/backends/platform/wince/README-WinCE.txt b/backends/platform/wince/README-WinCE.txt index 6a289766a2..5b3215e34e 100644 --- a/backends/platform/wince/README-WinCE.txt +++ b/backends/platform/wince/README-WinCE.txt @@ -6,26 +6,19 @@ Release version: 0.13.0 New in this version ------------------- -0.13.0: -Important: Two builds for ScummVM CE +1.0.0rc1: +This version features optimized ARM assembly versions for the Smartphone, +Normal2x and Normal2xAspect scalers, courtesy of Robin Watts. There should +be a speed improvement when using these scalers. -For this release, two binaries (executables) are provided. The first, -with file name scummvm1.exe, includes support for the following engines: - - scumm, sword1, sword2, queen, sky, lure, agi, touche -while the second, with file name scummvm2.exe: - - gob, cine, saga, kyra, agos, parallaction, drascula, groovie, tucker -The user must make sure to execute the correct file for a game. All -previously detected games will be shown in the launcher. Trying to launch -a gob engine game with scummvm1.exe will not work. -Detection also works as implied: scummvm1.exe will detect only the games -for which it has support; the same holds for scummvm2.exe. -This change has been done so users with less free memory can play more -memory hungry games. - -Also noted are problems with flac support. Your mileage may vary. Please -consider using ogg or mp3 for those games (smaller sizes are better for -handheld devices too!) +Also new is the aspect 2x upscaling mode, which is auto detected and used +when the scaler is set to (normal) 2x mode and the panel is hidden. Hence, +a 320x200 game running on a VGA or higher resolution device will be +aspect scaled to fill the 640x480 screen. +Be aware that Discworld 2 tries to allocate a big chunk of memory (10 MB) +and this will fail on many devices (file under the not enough memory +category). ------------------------------------------------------------------------ @@ -590,6 +583,20 @@ By default, the double tap to right click action is disabled in this game as this interferes with the game's controls. This setting can be overridden (see 'no_doubletap_rightclick' parameter above). +----------------- +-- Discworld 2 -- +----------------- + +Crashes at startup of this game are usually due to the high memory +requirements of this game. + +------------------------- +-- Cruise for a Corpse -- +------------------------- + +As with Discworld, the double-tap-to-right-click action interferes and will +be disabled by default. + ------------------------------------------------------------------------ Support @@ -637,6 +644,27 @@ http://www.scummvm.org/ Old news follow ... ------------------------------------------------------------------------ +0.13.0: +Important: Two builds for ScummVM CE + +For this release, two binaries (executables) are provided. The first, +with file name scummvm1.exe, includes support for the following engines: + - scumm, sword1, sword2, queen, sky, lure, agi, touche +while the second, with file name scummvm2.exe: + - gob, cine, saga, kyra, agos, parallaction, drascula, groovie, tucker +The user must make sure to execute the correct file for a game. All +previously detected games will be shown in the launcher. Trying to launch +a gob engine game with scummvm1.exe will not work. +Detection also works as implied: scummvm1.exe will detect only the games +for which it has support; the same holds for scummvm2.exe. +This change has been done so users with less free memory can play more +memory hungry games. + +Also noted are problems with flac support. Your mileage may vary. Please +consider using ogg or mp3 for those games (smaller sizes are better for +handheld devices too!) + + 0.12.0: - Improved SMUSH support (deprecated 'Smush_force_redraw' option) No skipped frames in Full Throttle action sequences. The 'Smush_force_redraw' diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp index f63ad72298..2d9765b0f2 100644 --- a/backends/platform/wince/missing/missing.cpp +++ b/backends/platform/wince/missing/missing.cpp @@ -42,6 +42,7 @@ #endif #include "time.h" #include "dirent.h" +#include "common/debug.h" char *strdup(const char *strSource); @@ -135,7 +136,7 @@ EXT_C char *getcwd(char *buffer, int maxlen) { #endif EXT_C void GetCurrentDirectory(int len, char *buf) { getcwd(buf,len); -}; +} /* Windows CE fopen has non-standard behavior -- not @@ -182,11 +183,19 @@ int _access(const char *path, int mode) { HANDLE h = FindFirstFile(fname, &ffd); FindClose(h); - if (h == INVALID_HANDLE_VALUE) - return -1; //Can't find file + if (h == INVALID_HANDLE_VALUE) { + // WORKAROUND: WinCE 3.0 doesn't find paths ending in '\' + if (path[strlen(path)-1] == '\\') { + char p2[MAX_PATH]; + strncpy(p2, path, strlen(path)-1); + p2[strlen(path) - 1]= '\0'; + return _access(p2, mode); + } else + return -1; //Can't find file + } - if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { - // WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // WORKAROUND: WinCE (or the emulator) sometimes returns bogus directory // hits for files that don't exist. TRIPLE checking for the same fname // seems to weed out those false positives. // Exhibited in kyra engine. @@ -206,7 +215,7 @@ int _access(const char *path, int mode) { return 0; case 06: //Check Read & Write permission case 02: //Check Write permission - return ffd.dwFileAttributes&FILE_ATTRIBUTE_READONLY?-1:0; + return ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? -1 : 0; case 04: //Check Read permission return 0; //Assume always have read permission } diff --git a/backends/platform/wince/module.mk b/backends/platform/wince/module.mk new file mode 100644 index 0000000000..5fefe08d79 --- /dev/null +++ b/backends/platform/wince/module.mk @@ -0,0 +1,21 @@ +MODULE := backends/platform/wince + +MODULE_OBJS := \ + CEActionsPocket.o CEDevice.o CEScaler.o \ + CEActionsSmartphone.o CELauncherDialog.o wince-sdl.o \ + CEgui/GUIElement.o CEgui/Panel.o CEgui/SDL_ImageResource.o \ + CEgui/ItemAction.o CEgui/PanelItem.o CEgui/Toolbar.o \ + CEgui/ItemSwitch.o CEgui/PanelKeyboard.o CEgui/ToolbarHandler.o \ + CEkeys/EventsBuffer.o \ + ../../../gui/Actions.o ../../../gui/Key.o ../../../gui/KeysDialog.o \ + ../sdl/sdl.o ../sdl/graphics.o ../sdl/events.o ../sdl/hardwarekeys.o \ + missing/missing.o \ + PocketSCUMM.o \ + ARMscaler.o \ + smartLandScale.o + +MODULE_DIRS += \ + backends/platform/wince/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 8b2e0848f8..65082014da 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -403,9 +403,8 @@ static Uint32 timer_handler_wrapper(Uint32 interval) { void OSystem_WINCE3::initBackend() { // Instantiate our own sound mixer - // mixer init is postponed until a game engine is selected. - if (_mixer == 0) - _mixer = new Audio::MixerImpl(this); + // mixer init is rerun when a game engine is selected. + setupMixer(); // Create the timer. CE SDL does not support multiple timers (SDL_AddTimer). // We work around this by using the SetTimer function, since we only use @@ -792,11 +791,15 @@ void OSystem_WINCE3::setupMixer() { SDL_AudioSpec desired; int thread_priority; + compute_sample_rate(); if (_sampleRate == 0) warning("setSoundCallback called with 0 _sampleRate. Audio will not work."); + else if (_mixer && _mixer->getOutputRate() == _sampleRate) { + debug(1, "Skipping sound mixer re-init: samplerate is good"); + return; + } memset(&desired, 0, sizeof(desired)); - desired.freq = _sampleRate; desired.format = AUDIO_S16SYS; desired.channels = 2; @@ -913,7 +916,6 @@ void OSystem_WINCE3::engineInit() { //update_game_settings(); // finalize mixer init - compute_sample_rate(); setupMixer(); } @@ -1080,13 +1082,6 @@ void OSystem_WINCE3::update_game_settings() { if (ConfMan.hasKey("no_doubletap_rightclick")) _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick"); - else if (gameid == "tinsel") { - _noDoubleTapRMB = true; - ConfMan.setBool("no_doubletap_rightclick", true); - ConfMan.flushToDisk(); - } - - compute_sample_rate(); } void OSystem_WINCE3::initSize(uint w, uint h) { @@ -1147,13 +1142,13 @@ void OSystem_WINCE3::setGraphicsModeIntern() { } bool OSystem_WINCE3::update_scalers() { - if (_videoMode.mode != GFX_NORMAL) - return false; - _videoMode.aspectRatioCorrection = false; if (CEDevice::hasPocketPCResolution()) { - if ( (!_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) + if (_videoMode.mode != GFX_NORMAL) + return false; + + if ((!_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) || CEDevice::hasSquareQVGAResolution() ) { if (getScreenWidth() != 320) { _scaleFactorXm = 3; @@ -1204,9 +1199,32 @@ bool OSystem_WINCE3::update_scalers() { } return true; - } + } else if (CEDevice::hasWideResolution()) { +#ifdef USE_ARM_SCALER_ASM + if ( _videoMode.mode == GFX_DOUBLESIZE && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth) ) { + if ( !_panelVisible && !_overlayVisible && _canBeAspectScaled ) { + _scaleFactorXm = 2; + _scaleFactorXd = 1; + _scaleFactorYm = 12; + _scaleFactorYd = 5; + _scalerProc = Normal2xAspect; + _modeFlags = 0; + _videoMode.aspectRatioCorrection = true; + } else if ( (_panelVisible || _overlayVisible) && _canBeAspectScaled ) { + _scaleFactorXm = 2; + _scaleFactorXd = 1; + _scaleFactorYm = 2; + _scaleFactorYd = 1; + _scalerProc = Normal2x; + _modeFlags = 0; + } + return true; + } +#endif + } else if (CEDevice::hasSmartphoneResolution()) { + if (_videoMode.mode != GFX_NORMAL) + return false; - if (CEDevice::hasSmartphoneResolution()) { if (_videoMode.screenWidth > 320) error("Game resolution not supported on Smartphone"); #ifdef ARM @@ -1373,8 +1391,8 @@ bool OSystem_WINCE3::loadGFXMode() { displayWidth = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd; displayHeight = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd; } else { - displayWidth = _videoMode.screenWidth; - displayHeight = _videoMode.screenHeight; + displayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + displayHeight = _videoMode.screenHeight* _videoMode.scaleFactor; } switch (_orientationLandscape) { @@ -1916,8 +1934,7 @@ void OSystem_WINCE3::setMouseCursor(const byte *buf, uint w, uint h, int hotspot _mouseData = (byte *) malloc(w * h); memcpy(_mouseData, buf, w * h); - if (w > _mouseBackupDim || h > _mouseBackupDim) - { + if (w > _mouseBackupDim || h > _mouseBackupDim) { // mouse has been undrawn, adjust sprite backup area free(_mouseBackupOld); free(_mouseBackupToolbar); @@ -2032,7 +2049,6 @@ void OSystem_WINCE3::undrawMouse() { if (_mouseNeedsRedraw) return; - _mouseNeedsRedraw = true; int old_mouse_x = _mouseCurState.x - _mouseHotspotX; int old_mouse_y = _mouseCurState.y - _mouseHotspotY; @@ -2083,6 +2099,22 @@ void OSystem_WINCE3::undrawMouse() { addDirtyRect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen); + + _mouseNeedsRedraw = true; +} + +bool OSystem_WINCE3::showMouse(bool visible) { + if (_mouseVisible == visible) + return visible; + + if (visible == false) + undrawMouse(); + + bool last = _mouseVisible; + _mouseVisible = visible; + _mouseNeedsRedraw = true; + + return last; } void OSystem_WINCE3::drawToolbarMouse(SDL_Surface *surf, bool draw) { @@ -2439,9 +2471,12 @@ bool OSystem_WINCE3::pollEvent(Common::Event &event) { } if (_toolbarHandler.action(event.mouse.x, event.mouse.y, false)) { - if (!_toolbarHandler.drawn()) + if (!_toolbarHandler.drawn()) { _toolbarHighDrawn = false; internUpdateScreen(); + } + return false; + } return true; diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h index cc2948f93d..deafde6d80 100644 --- a/backends/platform/wince/wince-sdl.h +++ b/backends/platform/wince/wince-sdl.h @@ -94,6 +94,7 @@ public: void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale); // overloaded by CE backend void undrawMouse(); void blitCursor(); + bool showMouse(bool visible); void setMousePos(int x, int y); void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME) void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); diff --git a/backends/platform/wince/wince.mk b/backends/platform/wince/wince.mk new file mode 100644 index 0000000000..5551b27289 --- /dev/null +++ b/backends/platform/wince/wince.mk @@ -0,0 +1,5 @@ +all: PocketSCUMM.o + +PocketSCUMM.o: $(srcdir)/backends/platform/wince/PocketSCUMM.rc + mkdir -p backends/platform/wince + $(WINDRES) -I$(srcdir)/backends/platform/wince $(srcdir)/backends/platform/wince/PocketSCUMM.rc backends/platform/wince/PocketSCUMM.o diff --git a/backends/vkeybd/packs/vkeybd_default.zip b/backends/vkeybd/packs/vkeybd_default.zip Binary files differindex 9311b2a902..94c4649768 100644 --- a/backends/vkeybd/packs/vkeybd_default.zip +++ b/backends/vkeybd/packs/vkeybd_default.zip diff --git a/backends/vkeybd/packs/vkeybd_default/lowercase-symbols320x240.bmp b/backends/vkeybd/packs/vkeybd_default/lowercase-symbols320x240.bmp Binary files differindex 02254aa3c7..08d40a0373 100644 --- a/backends/vkeybd/packs/vkeybd_default/lowercase-symbols320x240.bmp +++ b/backends/vkeybd/packs/vkeybd_default/lowercase-symbols320x240.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/lowercase-symbols640x480.bmp b/backends/vkeybd/packs/vkeybd_default/lowercase-symbols640x480.bmp Binary files differindex 98c602acbe..3496c368f6 100644 --- a/backends/vkeybd/packs/vkeybd_default/lowercase-symbols640x480.bmp +++ b/backends/vkeybd/packs/vkeybd_default/lowercase-symbols640x480.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/lowercase320x240.bmp b/backends/vkeybd/packs/vkeybd_default/lowercase320x240.bmp Binary files differindex 3270bf21e4..25579234bb 100644 --- a/backends/vkeybd/packs/vkeybd_default/lowercase320x240.bmp +++ b/backends/vkeybd/packs/vkeybd_default/lowercase320x240.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/lowercase640x480.bmp b/backends/vkeybd/packs/vkeybd_default/lowercase640x480.bmp Binary files differindex 610f0844d0..398685618a 100644 --- a/backends/vkeybd/packs/vkeybd_default/lowercase640x480.bmp +++ b/backends/vkeybd/packs/vkeybd_default/lowercase640x480.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/uppercase-symbols320x240.bmp b/backends/vkeybd/packs/vkeybd_default/uppercase-symbols320x240.bmp Binary files differindex 8fd645eb22..76a7f51839 100644 --- a/backends/vkeybd/packs/vkeybd_default/uppercase-symbols320x240.bmp +++ b/backends/vkeybd/packs/vkeybd_default/uppercase-symbols320x240.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/uppercase-symbols640x480.bmp b/backends/vkeybd/packs/vkeybd_default/uppercase-symbols640x480.bmp Binary files differindex cbdfbf19e9..84d31443a7 100644 --- a/backends/vkeybd/packs/vkeybd_default/uppercase-symbols640x480.bmp +++ b/backends/vkeybd/packs/vkeybd_default/uppercase-symbols640x480.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/uppercase320x240.bmp b/backends/vkeybd/packs/vkeybd_default/uppercase320x240.bmp Binary files differindex 6a1132314a..96ce1adbe4 100644 --- a/backends/vkeybd/packs/vkeybd_default/uppercase320x240.bmp +++ b/backends/vkeybd/packs/vkeybd_default/uppercase320x240.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/uppercase640x480.bmp b/backends/vkeybd/packs/vkeybd_default/uppercase640x480.bmp Binary files differindex e635a3ccf2..1f938d7c17 100644 --- a/backends/vkeybd/packs/vkeybd_default/uppercase640x480.bmp +++ b/backends/vkeybd/packs/vkeybd_default/uppercase640x480.bmp diff --git a/backends/vkeybd/packs/vkeybd_default/vkeybd_default.xml b/backends/vkeybd/packs/vkeybd_default/vkeybd_default.xml index 982c4f45ef..86f39d3d4d 100644 --- a/backends/vkeybd/packs/vkeybd_default/vkeybd_default.xml +++ b/backends/vkeybd/packs/vkeybd_default/vkeybd_default.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <keyboard initial_mode="lowercase" v_align="bottom" h_align="centre"> - +<!-- coords key = "start x, start y, end x, end y" --> <!-- Lowercase --> <mode name="lowercase" resolutions="320x240,640x480"> <layout resolution="320x240" bitmap="lowercase320x240.bmp" transparent_color="255,0,255"> @@ -20,7 +20,8 @@ <area shape="rect" coords="235,26,253,43" target="f11" /> <area shape="rect" coords="255,26,272,45" target="f12" /> <area shape="rect" coords="276,27,310,43" target="del" /> - <area shape="rect" coords="276,47,308,64" target="backspace" /> + <area shape="rect" coords="276,46,299,65" target="delete" /> + <area shape="rect" coords="300,46,311,65" target="backspace" /> <area shape="rect" coords="8,68,32,85" target="tab" /> <area shape="rect" coords="36,68,53,85" target="q" /> <area shape="rect" coords="57,68,75,86" target="w" /> @@ -76,85 +77,86 @@ <area shape="rect" coords="202,110,219,128" target="," /> <area shape="rect" coords="223,110,241,128" target="." /> <area shape="rect" coords="243,110,261,128" target="/" /> - <area shape="rect" coords="277,133,292,148" target="ok" /> - <area shape="rect" coords="292,133,309,148" target="cancel" /> + <area shape="rect" coords="269,131,288,150" target="ok" /> + <area shape="rect" coords="292,131,311,150" target="cancel" /> </map> </layout> <layout resolution="640x480" bitmap="lowercase640x480.bmp" transparent_color="255,0,255"> <map> - <area shape="rect" coords="26,23,613,37" target="display_area" /> - <area shape="rect" coords="18,52,51,85" target="esc" /> - <area shape="rect" coords="100,51,135,88" target="f2" /> - <area shape="rect" coords="59,49,94,88" target="f1" /> - <area shape="rect" coords="142,53,176,89" target="f3" /> - <area shape="rect" coords="181,51,216,87" target="f4" /> - <area shape="rect" coords="223,52,258,88" target="f5" /> - <area shape="rect" coords="265,52,299,89" target="f6" /> - <area shape="rect" coords="306,51,341,90" target="f7" /> - <area shape="rect" coords="347,53,382,89" target="f8" /> - <area shape="rect" coords="389,49,424,88" target="f9" /> - <area shape="rect" coords="431,52,464,89" target="f10" /> - <area shape="rect" coords="470,53,506,88" target="f11" /> - <area shape="rect" coords="511,52,546,90" target="f12" /> - <area shape="rect" coords="552,55,620,87" target="del" /> - <area shape="rect" coords="553,94,618,129" target="backspace" /> - <area shape="rect" coords="17,136,66,171" target="tab" /> - <area shape="rect" coords="73,137,108,171" target="q" /> - <area shape="rect" coords="114,136,150,172" target="w" /> - <area shape="rect" coords="157,134,189,171" target="e" /> - <area shape="rect" coords="197,135,232,171" target="r" /> - <area shape="rect" coords="239,135,274,172" target="t" /> - <area shape="rect" coords="282,136,317,173" target="y" /> - <area shape="rect" coords="322,135,359,173" target="u" /> - <area shape="rect" coords="364,134,399,172" target="i" /> - <area shape="rect" coords="404,135,440,171" target="o" /> - <area shape="rect" coords="446,136,480,172" target="p" /> - <area shape="rect" coords="89,177,127,216" target="a" /> - <area shape="rect" coords="131,177,169,214" target="s" /> - <area shape="rect" coords="173,178,209,215" target="d" /> - <area shape="rect" coords="215,178,250,214" target="f" /> - <area shape="rect" coords="256,178,291,214" target="g" /> - <area shape="rect" coords="299,176,332,214" target="h" /> - <area shape="rect" coords="339,178,374,215" target="j" /> - <area shape="rect" coords="379,178,415,215" target="k" /> - <area shape="rect" coords="421,178,457,215" target="l" /> - <area shape="rect" coords="546,179,622,214" target="enter" /> - <area shape="rect" coords="19,221,101,256" target="shift" /> - <area shape="rect" coords="17,179,84,213" target="caps" /> - <area shape="rect" coords="117,220,152,256" target="z" /> - <area shape="rect" coords="158,220,192,256" target="x" /> - <area shape="rect" coords="198,219,233,256" target="c" /> - <area shape="rect" coords="240,220,276,257" target="v" /> - <area shape="rect" coords="283,219,316,255" target="b" /> - <area shape="rect" coords="324,220,359,256" target="n" /> - <area shape="rect" coords="365,220,399,257" target="m" /> - <area shape="rect" coords="542,219,623,257" target="symbols" /> - <area shape="rect" coords="19,260,68,296" target="ctrl" /> - <area shape="rect" coords="76,261,123,295" target="alt" /> - <area shape="rect" coords="135,261,525,297" target="space" /> - <area shape="rect" coords="16,95,53,129" target="|" /> - <area shape="rect" coords="57,95,92,129" target="1" /> - <area shape="rect" coords="100,94,134,130" target="2" /> - <area shape="rect" coords="140,93,174,131" target="3" /> - <area shape="rect" coords="182,93,217,130" target="4" /> - <area shape="rect" coords="222,93,258,132" target="5" /> - <area shape="rect" coords="265,94,299,131" target="6" /> - <area shape="rect" coords="305,94,341,129" target="7" /> - <area shape="rect" coords="348,93,382,128" target="8" /> - <area shape="rect" coords="389,94,423,130" target="9" /> - <area shape="rect" coords="431,93,465,130" target="0" /> - <area shape="rect" coords="471,94,505,131" target="-" /> - <area shape="rect" coords="511,93,546,131" target="=" /> - <area shape="rect" coords="488,136,522,172" target="[" /> - <area shape="rect" coords="529,135,565,173" target="]" /> - <area shape="rect" coords="569,136,620,172" target="#" /> - <area shape="rect" coords="462,177,498,214" target=";" /> - <area shape="rect" coords="503,178,539,214" target="’" /> - <area shape="rect" coords="405,220,440,256" target="," /> - <area shape="rect" coords="447,220,483,256" target="." /> - <area shape="rect" coords="487,220,524,256" target="/" /> - <area shape="rect" coords="555,266,585,298" target="ok" /> - <area shape="rect" coords="585,266,619,298" target="cancel" /> + <area shape="rect" coords="26,23,613,37" target="display_area" /> + <area shape="rect" coords="18,52,51,85" target="esc" /> + <area shape="rect" coords="100,51,135,88" target="f2" /> + <area shape="rect" coords="59,49,94,88" target="f1" /> + <area shape="rect" coords="142,53,176,89" target="f3" /> + <area shape="rect" coords="181,51,216,87" target="f4" /> + <area shape="rect" coords="223,52,258,88" target="f5" /> + <area shape="rect" coords="265,52,299,89" target="f6" /> + <area shape="rect" coords="306,51,341,90" target="f7" /> + <area shape="rect" coords="347,53,382,89" target="f8" /> + <area shape="rect" coords="389,49,424,88" target="f9" /> + <area shape="rect" coords="431,52,464,89" target="f10" /> + <area shape="rect" coords="470,53,506,88" target="f11" /> + <area shape="rect" coords="511,52,546,90" target="f12" /> + <area shape="rect" coords="552,55,620,87" target="del" /> + <area shape="rect" coords="552,93,598,131" target="delete" /> + <area shape="rect" coords="601,93,623,131" target="backspace" /> + <area shape="rect" coords="17,136,66,171" target="tab" /> + <area shape="rect" coords="73,137,108,171" target="q" /> + <area shape="rect" coords="114,136,150,172" target="w" /> + <area shape="rect" coords="157,134,189,171" target="e" /> + <area shape="rect" coords="197,135,232,171" target="r" /> + <area shape="rect" coords="239,135,274,172" target="t" /> + <area shape="rect" coords="282,136,317,173" target="y" /> + <area shape="rect" coords="322,135,359,173" target="u" /> + <area shape="rect" coords="364,134,399,172" target="i" /> + <area shape="rect" coords="404,135,440,171" target="o" /> + <area shape="rect" coords="446,136,480,172" target="p" /> + <area shape="rect" coords="89,177,127,216" target="a"/> + <area shape="rect" coords="131,177,169,214" target="s" /> + <area shape="rect" coords="173,178,209,215" target="d" /> + <area shape="rect" coords="215,178,250,214" target="f" /> + <area shape="rect" coords="256,178,291,214" target="g" /> + <area shape="rect" coords="299,176,332,214" target="h" /> + <area shape="rect" coords="339,178,374,215" target="j" /> + <area shape="rect" coords="379,178,415,215" target="k" /> + <area shape="rect" coords="421,178,457,215" target="l" /> + <area shape="rect" coords="546,179,622,214" target="enter" /> + <area shape="rect" coords="19,221,101,256" target="shift" /> + <area shape="rect" coords="17,179,84,213" target="caps" /> + <area shape="rect" coords="117,220,152,256" target="z" /> + <area shape="rect" coords="158,220,192,256" target="x" /> + <area shape="rect" coords="198,219,233,256" target="c" /> + <area shape="rect" coords="240,220,276,257" target="v" /> + <area shape="rect" coords="283,219,316,255" target="b" /> + <area shape="rect" coords="324,220,359,256" target="n" /> + <area shape="rect" coords="365,220,399,257" target="m" /> + <area shape="rect" coords="542,219,623,257" target="symbols" /> + <area shape="rect" coords="19,260,68,296" target="ctrl" /> + <area shape="rect" coords="76,261,123,295" target="alt" /> + <area shape="rect" coords="135,261,525,297" target="space" /> + <area shape="rect" coords="16,95,53,129" target="|" /> + <area shape="rect" coords="57,95,92,129" target="1" /> + <area shape="rect" coords="100,94,134,130" target="2" /> + <area shape="rect" coords="140,93,174,131" target="3" /> + <area shape="rect" coords="182,93,217,130" target="4" /> + <area shape="rect" coords="222,93,258,132" target="5" /> + <area shape="rect" coords="265,94,299,131" target="6" /> + <area shape="rect" coords="305,94,341,129" target="7" /> + <area shape="rect" coords="348,93,382,128" target="8" /> + <area shape="rect" coords="389,94,423,130" target="9" /> + <area shape="rect" coords="431,93,465,130" target="0" /> + <area shape="rect" coords="471,94,505,131" target="-" /> + <area shape="rect" coords="511,93,546,131" target="=" /> + <area shape="rect" coords="488,136,522,172" target="[" /> + <area shape="rect" coords="529,135,565,173" target="]" /> + <area shape="rect" coords="569,136,620,172" target="#" /> + <area shape="rect" coords="462,177,498,214" target=";" /> + <area shape="rect" coords="503,178,539,214" target="’" /> + <area shape="rect" coords="405,220,440,256" target="," /> + <area shape="rect" coords="447,220,483,256" target="." /> + <area shape="rect" coords="487,220,524,256" target="/" /> + <area shape="rect" coords="538,266,576,298" target="ok" /> + <area shape="rect" coords="585,266,622,298" target="cancel" /> </map> </layout> <event name="esc" type="key" code="27" ascii="27" modifiers="" /> @@ -230,6 +232,7 @@ <event name="ok" type="submit" /> <event name="cancel" type="cancel" /> <event name="quit" type="submit" /> + <event name="delete" type="delete" /> </mode> <!-- Uppercase --> @@ -251,7 +254,8 @@ <area shape="rect" coords="235,26,253,43" target="f11" /> <area shape="rect" coords="255,26,272,45" target="f12" /> <area shape="rect" coords="276,27,310,43" target="del" /> - <area shape="rect" coords="276,47,308,64" target="backspace" /> + <area shape="rect" coords="276,46,299,65" target="delete" /> + <area shape="rect" coords="300,46,311,65" target="backspace" /> <area shape="rect" coords="8,68,32,85" target="tab" /> <area shape="rect" coords="36,68,53,85" target="Q" /> <area shape="rect" coords="57,68,75,86" target="W" /> @@ -307,81 +311,86 @@ <area shape="rect" coords="202,110,219,128" target="," /> <area shape="rect" coords="223,110,241,128" target="." /> <area shape="rect" coords="243,110,261,128" target="/" /> + <area shape="rect" coords="269,131,288,150" target="ok" /> + <area shape="rect" coords="292,131,311,150" target="cancel" /> </map> </layout> <layout resolution="640x480" bitmap="uppercase640x480.bmp" transparent_color="255,0,255"> <map> - <area shape="rect" coords="26,23,613,37" target="display_area" /> - <area shape="rect" coords="18,52,51,85" target="esc" /> - <area shape="rect" coords="100,51,135,88" target="f2" /> - <area shape="rect" coords="59,49,94,88" target="f1" /> - <area shape="rect" coords="142,53,176,89" target="f3" /> - <area shape="rect" coords="181,51,216,87" target="f4" /> - <area shape="rect" coords="223,52,258,88" target="f5" /> - <area shape="rect" coords="265,52,299,89" target="f6" /> - <area shape="rect" coords="306,51,341,90" target="f7" /> - <area shape="rect" coords="347,53,382,89" target="f8" /> - <area shape="rect" coords="389,49,424,88" target="f9" /> - <area shape="rect" coords="431,52,464,89" target="f10" /> - <area shape="rect" coords="470,53,506,88" target="f11" /> - <area shape="rect" coords="511,52,546,90" target="f12" /> - <area shape="rect" coords="552,55,620,87" target="del" /> - <area shape="rect" coords="553,94,618,129" target="backspace" /> - <area shape="rect" coords="17,136,66,171" target="tab" /> - <area shape="rect" coords="73,137,108,171" target="Q" /> - <area shape="rect" coords="114,136,150,172" target="W" /> - <area shape="rect" coords="157,134,189,171" target="E" /> - <area shape="rect" coords="197,135,232,171" target="R" /> - <area shape="rect" coords="239,135,274,172" target="T" /> - <area shape="rect" coords="282,136,317,173" target="Y" /> - <area shape="rect" coords="322,135,359,173" target="U" /> - <area shape="rect" coords="364,134,399,172" target="I" /> - <area shape="rect" coords="404,135,440,171" target="O" /> - <area shape="rect" coords="446,136,480,172" target="P" /> - <area shape="rect" coords="89,177,127,216" target="A" /> - <area shape="rect" coords="131,177,169,214" target="S" /> - <area shape="rect" coords="173,178,209,215" target="D" /> - <area shape="rect" coords="215,178,250,214" target="F" /> - <area shape="rect" coords="256,178,291,214" target="G" /> - <area shape="rect" coords="299,176,332,214" target="H" /> - <area shape="rect" coords="339,178,374,215" target="J" /> - <area shape="rect" coords="379,178,415,215" target="K" /> - <area shape="rect" coords="421,178,457,215" target="L" /> - <area shape="rect" coords="546,179,622,214" target="enter" /> - <area shape="rect" coords="19,221,101,256" target="shift" /> - <area shape="rect" coords="17,179,84,213" target="caps" /> - <area shape="rect" coords="117,220,152,256" target="Z" /> - <area shape="rect" coords="158,220,192,256" target="X" /> - <area shape="rect" coords="198,219,233,256" target="C" /> - <area shape="rect" coords="240,220,276,257" target="V" /> - <area shape="rect" coords="283,219,316,255" target="B" /> - <area shape="rect" coords="324,220,359,256" target="N" /> - <area shape="rect" coords="365,220,399,257" target="M" /> - <area shape="rect" coords="542,219,623,257" target="symbols" /> - <area shape="rect" coords="19,260,68,296" target="ctrl" /> - <area shape="rect" coords="76,261,123,295" target="alt" /> - <area shape="rect" coords="135,261,525,297" target="space" /> - <area shape="rect" coords="16,95,53,129" target="|" /> - <area shape="rect" coords="57,95,92,129" target="1" /> - <area shape="rect" coords="100,94,134,130" target="2" /> - <area shape="rect" coords="140,93,174,131" target="3" /> - <area shape="rect" coords="182,93,217,130" target="4" /> - <area shape="rect" coords="222,93,258,132" target="5" /> - <area shape="rect" coords="265,94,299,131" target="6" /> - <area shape="rect" coords="305,94,341,129" target="7" /> - <area shape="rect" coords="348,93,382,128" target="8" /> - <area shape="rect" coords="389,94,423,130" target="9" /> - <area shape="rect" coords="431,93,465,130" target="0" /> - <area shape="rect" coords="471,94,505,131" target="-" /> - <area shape="rect" coords="511,93,546,131" target="=" /> - <area shape="rect" coords="488,136,522,172" target="[" /> - <area shape="rect" coords="529,135,565,173" target="]" /> - <area shape="rect" coords="569,136,620,172" target="#" /> - <area shape="rect" coords="462,177,498,214" target=";" /> - <area shape="rect" coords="503,178,539,214" target="’" /> - <area shape="rect" coords="405,220,440,256" target="," /> - <area shape="rect" coords="447,220,483,256" target="." /> - <area shape="rect" coords="487,220,524,256" target="/" /> + <area shape="rect" coords="26,23,613,37" target="display_area" /> + <area shape="rect" coords="18,52,51,85" target="esc" /> + <area shape="rect" coords="100,51,135,88" target="f2" /> + <area shape="rect" coords="59,49,94,88" target="f1" /> + <area shape="rect" coords="142,53,176,89" target="f3" /> + <area shape="rect" coords="181,51,216,87" target="f4" /> + <area shape="rect" coords="223,52,258,88" target="f5" /> + <area shape="rect" coords="265,52,299,89" target="f6" /> + <area shape="rect" coords="306,51,341,90" target="f7" /> + <area shape="rect" coords="347,53,382,89" target="f8" /> + <area shape="rect" coords="389,49,424,88" target="f9" /> + <area shape="rect" coords="431,52,464,89" target="f10" /> + <area shape="rect" coords="470,53,506,88" target="f11" /> + <area shape="rect" coords="511,52,546,90" target="f12" /> + <area shape="rect" coords="552,55,620,87" target="del" /> + <area shape="rect" coords="552,93,598,131" target="delete" /> + <area shape="rect" coords="601,93,623,131" target="backspace" /> + <area shape="rect" coords="17,136,66,171" target="tab" /> + <area shape="rect" coords="73,137,108,171" target="Q" /> + <area shape="rect" coords="114,136,150,172" target="W" /> + <area shape="rect" coords="157,134,189,171" target="E" /> + <area shape="rect" coords="197,135,232,171" target="R" /> + <area shape="rect" coords="239,135,274,172" target="T" /> + <area shape="rect" coords="282,136,317,173" target="Y" /> + <area shape="rect" coords="322,135,359,173" target="U" /> + <area shape="rect" coords="364,134,399,172" target="I" /> + <area shape="rect" coords="404,135,440,171" target="O" /> + <area shape="rect" coords="446,136,480,172" target="P" /> + <area shape="rect" coords="89,177,127,216" target="A" /> + <area shape="rect" coords="131,177,169,214" target="S" /> + <area shape="rect" coords="173,178,209,215" target="D" /> + <area shape="rect" coords="215,178,250,214" target="F" /> + <area shape="rect" coords="256,178,291,214" target="G" /> + <area shape="rect" coords="299,176,332,214" target="H" /> + <area shape="rect" coords="339,178,374,215" target="J" /> + <area shape="rect" coords="379,178,415,215" target="K" /> + <area shape="rect" coords="421,178,457,215" target="L" /> + <area shape="rect" coords="546,179,622,214" target="enter" /> + <area shape="rect" coords="19,221,101,256" target="shift" /> + <area shape="rect" coords="17,179,84,213" target="caps" /> + <area shape="rect" coords="117,220,152,256" target="Z" /> + <area shape="rect" coords="158,220,192,256" target="X" /> + <area shape="rect" coords="198,219,233,256" target="C" /> + <area shape="rect" coords="240,220,276,257" target="V" /> + <area shape="rect" coords="283,219,316,255" target="B" /> + <area shape="rect" coords="324,220,359,256" target="N" /> + <area shape="rect" coords="365,220,399,257" target="M" /> + <area shape="rect" coords="542,219,623,257" target="symbols" /> + <area shape="rect" coords="19,260,68,296" target="ctrl" /> + <area shape="rect" coords="76,261,123,295" target="alt" /> + <area shape="rect" coords="135,261,525,297" target="space" /> + <area shape="rect" coords="16,95,53,129" target="|" /> + <area shape="rect" coords="57,95,92,129" target="1" /> + <area shape="rect" coords="100,94,134,130" target="2" /> + <area shape="rect" coords="140,93,174,131" target="3" /> + <area shape="rect" coords="182,93,217,130" target="4" /> + <area shape="rect" coords="222,93,258,132" target="5" /> + <area shape="rect" coords="265,94,299,131" target="6" /> + <area shape="rect" coords="305,94,341,129" target="7" /> + <area shape="rect" coords="348,93,382,128" target="8" /> + <area shape="rect" coords="389,94,423,130" target="9" /> + <area shape="rect" coords="431,93,465,130" target="0" /> + <area shape="rect" coords="471,94,505,131" target="-" /> + <area shape="rect" coords="511,93,546,131" target="=" /> + <area shape="rect" coords="488,136,522,172" target="[" /> + <area shape="rect" coords="529,135,565,173" target="]" /> + <area shape="rect" coords="569,136,620,172" target="#" /> + <area shape="rect" coords="462,177,498,214" target=";" /> + <area shape="rect" coords="503,178,539,214" target="’" /> + <area shape="rect" coords="405,220,440,256" target="," /> + <area shape="rect" coords="447,220,483,256" target="." /> + <area shape="rect" coords="487,220,524,256" target="/" /> + <area shape="rect" coords="538,266,576,298" target="ok" /> + <area shape="rect" coords="585,266,622,298" target="cancel" /> </map> </layout> <event name="esc" type="key" code="27" ascii="27" modifiers="" /> @@ -454,7 +463,10 @@ <event name="7" type="key" code="55" ascii="55" modifiers="" /> <event name="8" type="key" code="56" ascii="56" modifiers="" /> <event name="9" type="key" code="57" ascii="57" modifiers="" /> + <event name="ok" type="submit" /> + <event name="cancel" type="cancel" /> <event name="quit" type="submit" /> + <event name="delete" type="delete" /> </mode> <!-- Lowercase Symbols --> @@ -489,7 +501,8 @@ <area shape="rect" coords="215,46,232,64" target=")" /> <area shape="rect" coords="235,47,252,65" target="_" /> <area shape="rect" coords="255,46,272,65" target="+" /> - <area shape="rect" coords="276,47,308,64" target="backspace" /> + <area shape="rect" coords="276,46,299,65" target="delete" /> + <area shape="rect" coords="300,46,311,65" target="backspace" /> <area shape="rect" coords="8,68,32,85" target="tab" /> <area shape="rect" coords="36,68,53,85" target="q" /> <area shape="rect" coords="57,68,75,86" target="w" /> @@ -532,81 +545,86 @@ <area shape="rect" coords="9,130,33,148" target="ctrl" /> <area shape="rect" coords="38,130,61,147" target="alt" /> <area shape="rect" coords="67,130,262,148" target="space" /> + <area shape="rect" coords="269,131,288,150" target="ok" /> + <area shape="rect" coords="292,131,311,150" target="cancel" /> </map> </layout> <layout resolution="640x480" bitmap="lowercase-symbols640x480.bmp" transparent_color="255,0,255"> <map> - <area shape="rect" coords="26,23,613,37" target="display_area" /> - <area shape="rect" coords="18,52,51,85" target="esc" /> - <area shape="rect" coords="100,51,135,88" target="f2" /> - <area shape="rect" coords="59,49,94,88" target="f1" /> - <area shape="rect" coords="142,53,176,89" target="f3" /> - <area shape="rect" coords="181,51,216,87" target="f4" /> - <area shape="rect" coords="223,52,258,88" target="f5" /> - <area shape="rect" coords="265,52,299,89" target="f6" /> - <area shape="rect" coords="306,51,341,90" target="f7" /> - <area shape="rect" coords="347,53,382,89" target="f8" /> - <area shape="rect" coords="389,49,424,88" target="f9" /> - <area shape="rect" coords="431,52,464,89" target="f10" /> - <area shape="rect" coords="470,53,506,88" target="f11" /> - <area shape="rect" coords="511,52,546,90" target="f12" /> - <area shape="rect" coords="552,55,620,87" target="del" /> - <area shape="rect" coords="16,95,53,129" target="¬" /> - <area shape="rect" coords="57,95,92,129" target="!" /> - <area shape="rect" coords="100,94,134,130" target="quote" /> - <area shape="rect" coords="140,93,174,131" target="£" /> - <area shape="rect" coords="182,93,217,130" target="$" /> - <area shape="rect" coords="222,93,258,132" target="%" /> - <area shape="rect" coords="265,94,299,131" target="^" /> - <area shape="rect" coords="305,94,341,129" target="&" /> - <area shape="rect" coords="348,93,382,128" target="*" /> - <area shape="rect" coords="389,94,423,130" target="(" /> - <area shape="rect" coords="431,93,465,130" target=")" /> - <area shape="rect" coords="471,94,505,131" target="_" /> - <area shape="rect" coords="511,93,546,131" target="+" /> - <area shape="rect" coords="553,94,618,129" target="backspace" /> - <area shape="rect" coords="17,136,66,171" target="tab" /> - <area shape="rect" coords="73,137,108,171" target="q" /> - <area shape="rect" coords="114,136,150,172" target="w" /> - <area shape="rect" coords="157,134,189,171" target="e" /> - <area shape="rect" coords="197,135,232,171" target="r" /> - <area shape="rect" coords="239,135,274,172" target="t" /> - <area shape="rect" coords="282,136,317,173" target="y" /> - <area shape="rect" coords="322,135,359,173" target="u" /> - <area shape="rect" coords="364,134,399,172" target="i" /> - <area shape="rect" coords="404,135,440,171" target="o" /> - <area shape="rect" coords="446,136,480,172" target="p" /> - <area shape="rect" coords="488,136,522,172" target="{" /> - <area shape="rect" coords="529,135,565,173" target="}" /> - <area shape="rect" coords="569,136,620,172" target="~" /> - <area shape="rect" coords="17,179,84,213" target="caps" /> - <area shape="rect" coords="89,177,127,216" target="a" /> - <area shape="rect" coords="131,177,169,214" target="s" /> - <area shape="rect" coords="173,178,209,215" target="d" /> - <area shape="rect" coords="215,178,250,214" target="f" /> - <area shape="rect" coords="256,178,291,214" target="g" /> - <area shape="rect" coords="299,176,332,214" target="h" /> - <area shape="rect" coords="339,178,374,215" target="j" /> - <area shape="rect" coords="379,178,415,215" target="k" /> - <area shape="rect" coords="421,178,457,215" target="l" /> - <area shape="rect" coords="462,177,498,214" target=":" /> - <area shape="rect" coords="503,178,539,214" target="@" /> - <area shape="rect" coords="546,179,622,214" target="enter" /> - <area shape="rect" coords="19,221,101,256" target="shift" /> - <area shape="rect" coords="117,220,152,256" target="z" /> - <area shape="rect" coords="158,220,192,256" target="x" /> - <area shape="rect" coords="198,219,233,256" target="c" /> - <area shape="rect" coords="240,220,276,257" target="v" /> - <area shape="rect" coords="283,219,316,255" target="b" /> - <area shape="rect" coords="324,220,359,256" target="n" /> - <area shape="rect" coords="365,220,399,257" target="m" /> - <area shape="rect" coords="405,220,440,256" target="<" /> - <area shape="rect" coords="447,220,483,256" target=">" /> - <area shape="rect" coords="487,220,524,256" target="?" /> - <area shape="rect" coords="542,219,623,257" target="symbols" /> - <area shape="rect" coords="19,260,68,296" target="ctrl" /> - <area shape="rect" coords="76,261,123,295" target="alt" /> - <area shape="rect" coords="135,261,525,297" target="space" /> + <area shape="rect" coords="26,23,613,37" target="display_area" /> + <area shape="rect" coords="18,52,51,85" target="esc" /> + <area shape="rect" coords="100,51,135,88" target="f2" /> + <area shape="rect" coords="59,49,94,88" target="f1" /> + <area shape="rect" coords="142,53,176,89" target="f3" /> + <area shape="rect" coords="181,51,216,87" target="f4" /> + <area shape="rect" coords="223,52,258,88" target="f5" /> + <area shape="rect" coords="265,52,299,89" target="f6" /> + <area shape="rect" coords="306,51,341,90" target="f7" /> + <area shape="rect" coords="347,53,382,89" target="f8" /> + <area shape="rect" coords="389,49,424,88" target="f9" /> + <area shape="rect" coords="431,52,464,89" target="f10" /> + <area shape="rect" coords="470,53,506,88" target="f11" /> + <area shape="rect" coords="511,52,546,90" target="f12" /> + <area shape="rect" coords="552,55,620,87" target="del" /> + <area shape="rect" coords="16,95,53,129" target="¬" /> + <area shape="rect" coords="57,95,92,129" target="!" /> + <area shape="rect" coords="100,94,134,130" target="quote" /> + <area shape="rect" coords="140,93,174,131" target="£" /> + <area shape="rect" coords="182,93,217,130" target="$" /> + <area shape="rect" coords="222,93,258,132" target="%" /> + <area shape="rect" coords="265,94,299,131" target="^" /> + <area shape="rect" coords="305,94,341,129" target="&" /> + <area shape="rect" coords="348,93,382,128" target="*" /> + <area shape="rect" coords="389,94,423,130" target="(" /> + <area shape="rect" coords="431,93,465,130" target=")" /> + <area shape="rect" coords="471,94,505,131" target="_" /> + <area shape="rect" coords="511,93,546,131" target="+" /> + <area shape="rect" coords="552,93,598,131" target="delete" /> + <area shape="rect" coords="601,93,623,131" target="backspace" /> + <area shape="rect" coords="17,136,66,171" target="tab" /> + <area shape="rect" coords="73,137,108,171" target="q" /> + <area shape="rect" coords="114,136,150,172" target="w" /> + <area shape="rect" coords="157,134,189,171" target="e" /> + <area shape="rect" coords="197,135,232,171" target="r" /> + <area shape="rect" coords="239,135,274,172" target="t" /> + <area shape="rect" coords="282,136,317,173" target="y" /> + <area shape="rect" coords="322,135,359,173" target="u" /> + <area shape="rect" coords="364,134,399,172" target="i" /> + <area shape="rect" coords="404,135,440,171" target="o" /> + <area shape="rect" coords="446,136,480,172" target="p" /> + <area shape="rect" coords="488,136,522,172" target="{" /> + <area shape="rect" coords="529,135,565,173" target="}" /> + <area shape="rect" coords="569,136,620,172" target="~" /> + <area shape="rect" coords="17,179,84,213" target="caps" /> + <area shape="rect" coords="89,177,127,216" target="a" /> + <area shape="rect" coords="131,177,169,214" target="s" /> + <area shape="rect" coords="173,178,209,215" target="d" /> + <area shape="rect" coords="215,178,250,214" target="f" /> + <area shape="rect" coords="256,178,291,214" target="g" /> + <area shape="rect" coords="299,176,332,214" target="h" /> + <area shape="rect" coords="339,178,374,215" target="j" /> + <area shape="rect" coords="379,178,415,215" target="k" /> + <area shape="rect" coords="421,178,457,215" target="l" /> + <area shape="rect" coords="462,177,498,214" target=":" /> + <area shape="rect" coords="503,178,539,214" target="@" /> + <area shape="rect" coords="546,179,622,214" target="enter" /> + <area shape="rect" coords="19,221,101,256" target="shift" /> + <area shape="rect" coords="117,220,152,256" target="z" /> + <area shape="rect" coords="158,220,192,256" target="x" /> + <area shape="rect" coords="198,219,233,256" target="c" /> + <area shape="rect" coords="240,220,276,257" target="v" /> + <area shape="rect" coords="283,219,316,255" target="b" /> + <area shape="rect" coords="324,220,359,256" target="n" /> + <area shape="rect" coords="365,220,399,257" target="m" /> + <area shape="rect" coords="405,220,440,256" target="<" /> + <area shape="rect" coords="447,220,483,256" target=">" /> + <area shape="rect" coords="487,220,524,256" target="?" /> + <area shape="rect" coords="542,219,623,257" target="symbols" /> + <area shape="rect" coords="19,260,68,296" target="ctrl" /> + <area shape="rect" coords="76,261,123,295" target="alt" /> + <area shape="rect" coords="135,261,525,297" target="space" /> + <area shape="rect" coords="538,266,576,298" target="ok" /> + <area shape="rect" coords="585,266,622,298" target="cancel" /> </map> </layout> <event name="esc" type="key" code="27" ascii="27" modifiers="" /> @@ -679,7 +697,10 @@ <event name="x" type="key" code="120" ascii="120" modifiers="" /> <event name="y" type="key" code="121" ascii="121" modifiers="" /> <event name="z" type="key" code="122" ascii="122" modifiers="" /> + <event name="ok" type="submit" /> + <event name="cancel" type="cancel" /> <event name="quit" type="submit" /> + <event name="delete" type="delete" /> </mode> <!-- Uppercase Symbols --> @@ -714,7 +735,8 @@ <area shape="rect" coords="215,46,232,64" target=")" /> <area shape="rect" coords="235,47,252,65" target="_" /> <area shape="rect" coords="255,46,272,65" target="+" /> - <area shape="rect" coords="276,47,308,64" target="backspace" /> + <area shape="rect" coords="276,46,299,65" target="delete" /> + <area shape="rect" coords="300,46,311,65" target="backspace" /> <area shape="rect" coords="8,68,32,85" target="tab" /> <area shape="rect" coords="36,68,53,85" target="Q" /> <area shape="rect" coords="57,68,75,86" target="W" /> @@ -757,81 +779,86 @@ <area shape="rect" coords="9,130,33,148" target="ctrl" /> <area shape="rect" coords="38,130,61,147" target="alt" /> <area shape="rect" coords="67,130,262,148" target="space" /> + <area shape="rect" coords="269,131,288,150" target="ok" /> + <area shape="rect" coords="292,131,311,150" target="cancel" /> </map> </layout> <layout resolution="640x480" bitmap="uppercase-symbols640x480.bmp" transparent_color="255,0,255"> <map> - <area shape="rect" coords="26,23,613,37" target="display_area" /> - <area shape="rect" coords="18,52,51,85" target="esc" /> - <area shape="rect" coords="100,51,135,88" target="f2" /> - <area shape="rect" coords="59,49,94,88" target="f1" /> - <area shape="rect" coords="142,53,176,89" target="f3" /> - <area shape="rect" coords="181,51,216,87" target="f4" /> - <area shape="rect" coords="223,52,258,88" target="f5" /> - <area shape="rect" coords="265,52,299,89" target="f6" /> - <area shape="rect" coords="306,51,341,90" target="f7" /> - <area shape="rect" coords="347,53,382,89" target="f8" /> - <area shape="rect" coords="389,49,424,88" target="f9" /> - <area shape="rect" coords="431,52,464,89" target="f10" /> - <area shape="rect" coords="470,53,506,88" target="f11" /> - <area shape="rect" coords="511,52,546,90" target="f12" /> - <area shape="rect" coords="552,55,620,87" target="del" /> - <area shape="rect" coords="16,95,53,129" target="¬" /> - <area shape="rect" coords="57,95,92,129" target="!" /> - <area shape="rect" coords="100,94,134,130" target="quote" /> - <area shape="rect" coords="140,93,174,131" target="£" /> - <area shape="rect" coords="182,93,217,130" target="$" /> - <area shape="rect" coords="222,93,258,132" target="%" /> - <area shape="rect" coords="265,94,299,131" target="^" /> - <area shape="rect" coords="305,94,341,129" target="&" /> - <area shape="rect" coords="348,93,382,128" target="*" /> - <area shape="rect" coords="389,94,423,130" target="(" /> - <area shape="rect" coords="431,93,465,130" target=")" /> - <area shape="rect" coords="471,94,505,131" target="_" /> - <area shape="rect" coords="511,93,546,131" target="+" /> - <area shape="rect" coords="553,94,618,129" target="backspace" /> - <area shape="rect" coords="17,136,66,171" target="tab" /> - <area shape="rect" coords="73,137,108,171" target="Q" /> - <area shape="rect" coords="114,136,150,172" target="W" /> - <area shape="rect" coords="157,134,189,171" target="E" /> - <area shape="rect" coords="197,135,232,171" target="R" /> - <area shape="rect" coords="239,135,274,172" target="T" /> - <area shape="rect" coords="282,136,317,173" target="Y" /> - <area shape="rect" coords="322,135,359,173" target="U" /> - <area shape="rect" coords="364,134,399,172" target="I" /> - <area shape="rect" coords="404,135,440,171" target="O" /> - <area shape="rect" coords="446,136,480,172" target="P" /> - <area shape="rect" coords="488,136,522,172" target="{" /> - <area shape="rect" coords="529,135,565,173" target="}" /> - <area shape="rect" coords="569,136,620,172" target="~" /> - <area shape="rect" coords="17,179,84,213" target="caps" /> - <area shape="rect" coords="89,177,127,216" target="A" /> - <area shape="rect" coords="131,177,169,214" target="S" /> - <area shape="rect" coords="173,178,209,215" target="D" /> - <area shape="rect" coords="215,178,250,214" target="F" /> - <area shape="rect" coords="256,178,291,214" target="G" /> - <area shape="rect" coords="299,176,332,214" target="H" /> - <area shape="rect" coords="339,178,374,215" target="J" /> - <area shape="rect" coords="379,178,415,215" target="K" /> - <area shape="rect" coords="421,178,457,215" target="L" /> - <area shape="rect" coords="462,177,498,214" target=":" /> - <area shape="rect" coords="503,178,539,214" target="@" /> - <area shape="rect" coords="546,179,622,214" target="enter" /> - <area shape="rect" coords="19,221,101,256" target="shift" /> - <area shape="rect" coords="117,220,152,256" target="z" /> - <area shape="rect" coords="158,220,192,256" target="x" /> - <area shape="rect" coords="198,219,233,256" target="c" /> - <area shape="rect" coords="240,220,276,257" target="v" /> - <area shape="rect" coords="283,219,316,255" target="b" /> - <area shape="rect" coords="324,220,359,256" target="n" /> - <area shape="rect" coords="365,220,399,257" target="m" /> - <area shape="rect" coords="405,220,440,256" target="<" /> - <area shape="rect" coords="447,220,483,256" target=">" /> - <area shape="rect" coords="487,220,524,256" target="?" /> - <area shape="rect" coords="542,219,623,257" target="symbols" /> - <area shape="rect" coords="19,260,68,296" target="ctrl" /> - <area shape="rect" coords="76,261,123,295" target="alt" /> - <area shape="rect" coords="135,261,525,297" target="space" /> + <area shape="rect" coords="26,23,613,37" target="display_area" /> + <area shape="rect" coords="18,52,51,85" target="esc" /> + <area shape="rect" coords="100,51,135,88" target="f2" /> + <area shape="rect" coords="59,49,94,88" target="f1" /> + <area shape="rect" coords="142,53,176,89" target="f3" /> + <area shape="rect" coords="181,51,216,87" target="f4" /> + <area shape="rect" coords="223,52,258,88" target="f5" /> + <area shape="rect" coords="265,52,299,89" target="f6" /> + <area shape="rect" coords="306,51,341,90" target="f7" /> + <area shape="rect" coords="347,53,382,89" target="f8" /> + <area shape="rect" coords="389,49,424,88" target="f9" /> + <area shape="rect" coords="431,52,464,89" target="f10" /> + <area shape="rect" coords="470,53,506,88" target="f11" /> + <area shape="rect" coords="511,52,546,90" target="f12" /> + <area shape="rect" coords="552,55,620,87" target="del" /> + <area shape="rect" coords="16,95,53,129" target="¬" /> + <area shape="rect" coords="57,95,92,129" target="!" /> + <area shape="rect" coords="100,94,134,130" target="quote" /> + <area shape="rect" coords="140,93,174,131" target="£" /> + <area shape="rect" coords="182,93,217,130" target="$" /> + <area shape="rect" coords="222,93,258,132" target="%" /> + <area shape="rect" coords="265,94,299,131" target="^" /> + <area shape="rect" coords="305,94,341,129" target="&" /> + <area shape="rect" coords="348,93,382,128" target="*" /> + <area shape="rect" coords="389,94,423,130" target="(" /> + <area shape="rect" coords="431,93,465,130" target=")" /> + <area shape="rect" coords="471,94,505,131" target="_" /> + <area shape="rect" coords="511,93,546,131" target="+" /> + <area shape="rect" coords="552,93,598,131" target="delete" /> + <area shape="rect" coords="601,93,623,131" target="backspace" /> + <area shape="rect" coords="17,136,66,171" target="tab" /> + <area shape="rect" coords="73,137,108,171" target="Q" /> + <area shape="rect" coords="114,136,150,172" target="W" /> + <area shape="rect" coords="157,134,189,171" target="E" /> + <area shape="rect" coords="197,135,232,171" target="R" /> + <area shape="rect" coords="239,135,274,172" target="T" /> + <area shape="rect" coords="282,136,317,173" target="Y" /> + <area shape="rect" coords="322,135,359,173" target="U" /> + <area shape="rect" coords="364,134,399,172" target="I" /> + <area shape="rect" coords="404,135,440,171" target="O" /> + <area shape="rect" coords="446,136,480,172" target="P" /> + <area shape="rect" coords="488,136,522,172" target="{" /> + <area shape="rect" coords="529,135,565,173" target="}" /> + <area shape="rect" coords="569,136,620,172" target="~" /> + <area shape="rect" coords="17,179,84,213" target="caps" /> + <area shape="rect" coords="89,177,127,216" target="A" /> + <area shape="rect" coords="131,177,169,214" target="S" /> + <area shape="rect" coords="173,178,209,215" target="D" /> + <area shape="rect" coords="215,178,250,214" target="F" /> + <area shape="rect" coords="256,178,291,214" target="G" /> + <area shape="rect" coords="299,176,332,214" target="H" /> + <area shape="rect" coords="339,178,374,215" target="J" /> + <area shape="rect" coords="379,178,415,215" target="K" /> + <area shape="rect" coords="421,178,457,215" target="L" /> + <area shape="rect" coords="462,177,498,214" target=":" /> + <area shape="rect" coords="503,178,539,214" target="@" /> + <area shape="rect" coords="546,179,622,214" target="enter" /> + <area shape="rect" coords="19,221,101,256" target="shift" /> + <area shape="rect" coords="117,220,152,256" target="z" /> + <area shape="rect" coords="158,220,192,256" target="x" /> + <area shape="rect" coords="198,219,233,256" target="c" /> + <area shape="rect" coords="240,220,276,257" target="v" /> + <area shape="rect" coords="283,219,316,255" target="b" /> + <area shape="rect" coords="324,220,359,256" target="n" /> + <area shape="rect" coords="365,220,399,257" target="m" /> + <area shape="rect" coords="405,220,440,256" target="<" /> + <area shape="rect" coords="447,220,483,256" target=">" /> + <area shape="rect" coords="487,220,524,256" target="?" /> + <area shape="rect" coords="542,219,623,257" target="symbols" /> + <area shape="rect" coords="19,260,68,296" target="ctrl" /> + <area shape="rect" coords="76,261,123,295" target="alt" /> + <area shape="rect" coords="135,261,525,297" target="space" /> + <area shape="rect" coords="538,266,576,298" target="ok" /> + <area shape="rect" coords="585,266,622,298" target="cancel" /> </map> </layout> <event name="esc" type="key" code="27" ascii="27" modifiers="" /> @@ -914,7 +941,9 @@ <event name="7" type="key" code="55" ascii="55" modifiers="" /> <event name="8" type="key" code="56" ascii="56" modifiers="" /> <event name="9" type="key" code="57" ascii="57" modifiers="" /> + <event name="ok" type="submit" /> + <event name="cancel" type="cancel" /> <event name="quit" type="submit" /> + <event name="delete" type="delete" /> </mode> - </keyboard> diff --git a/base/internal_version.h b/base/internal_version.h index 0838e8ad2a..68e3127020 100644 --- a/base/internal_version.h +++ b/base/internal_version.h @@ -2,4 +2,4 @@ #define SCUMMVM_SVN_REVISION #endif -#define SCUMMVM_VERSION "1.0.0svn" SCUMMVM_SVN_REVISION +#define SCUMMVM_VERSION "1.1.0svn" SCUMMVM_SVN_REVISION diff --git a/base/main.cpp b/base/main.cpp index 6f8a61a595..39647f1534 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -41,6 +41,7 @@ #include "common/config-manager.h" #include "common/debug.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/fs.h" #include "common/system.h" @@ -168,9 +169,9 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const // Set the window caption to the game name Common::String caption(ConfMan.get("description")); - Common::String desc = EngineMan.findGame(ConfMan.get("gameid")).description(); - if (caption.empty() && !desc.empty()) - caption = desc; + if (caption.empty()) { + caption = EngineMan.findGame(ConfMan.get("gameid")).description(); + } if (caption.empty()) caption = ConfMan.getActiveDomainName(); // Use the domain (=target) name if (!caption.empty()) { @@ -389,6 +390,14 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { // take place after the backend is initiated and the screen has been setup system.getEventManager()->init(); + // Directly after initializing the event manager, we will initialize our + // event recorder. + // + // TODO: This is just to match the current behavior, when we further extend + // our event recorder, we might do this at another place. Or even change + // the whole API for that ;-). + g_eventRec.init(); + // Now as the event manager is created, setup the keymapper setupKeymapper(system); diff --git a/common/EventDispatcher.cpp b/common/EventDispatcher.cpp new file mode 100644 index 0000000000..57765f9d13 --- /dev/null +++ b/common/EventDispatcher.cpp @@ -0,0 +1,138 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/events.h" + +namespace Common { + +EventDispatcher::EventDispatcher() : _mapper(0) { +} + +EventDispatcher::~EventDispatcher() { + for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) { + if (i->autoFree) + delete i->source; + } + + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->autoFree) + delete i->observer; + } + + delete _mapper; + _mapper = 0; +} + +void EventDispatcher::dispatch() { + Common::Event event; + + for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) { + const bool allowMapping = i->source->allowMapping(); + + while (i->source->pollEvent(event)) { + // We only try to process the events via the setup event mapper, when + // we have a setup mapper and when the event source allows mapping. + if (_mapper && allowMapping) { + if (_mapper->notifyEvent(event)) { + // We allow the event mapper to create multiple events, when + // eating an event. + while (_mapper->pollEvent(event)) + dispatchEvent(event); + + // Try getting another event from the current EventSource. + continue; + } + } + + dispatchEvent(event); + } + } +} + +void EventDispatcher::registerMapper(EventMapper *mapper) { + if (_mapper) + delete _mapper; + _mapper = mapper; +} + +void EventDispatcher::registerSource(EventSource *source, bool autoFree) { + SourceEntry newEntry; + + newEntry.source = source; + newEntry.autoFree = autoFree; + + _sources.push_back(newEntry); +} + +void EventDispatcher::unregisterSource(EventSource *source) { + for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) { + if (i->source == source) { + if (i->autoFree) + delete source; + + _sources.erase(i); + return; + } + } +} + +void EventDispatcher::registerObserver(EventObserver *obs, uint priority, bool autoFree) { + ObserverEntry newEntry; + + newEntry.observer = obs; + newEntry.priority = priority; + newEntry.autoFree = autoFree; + + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->priority < priority) { + _observers.insert(i, newEntry); + return; + } + } + + _observers.push_back(newEntry); +} + +void EventDispatcher::unregisterObserver(EventObserver *obs) { + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->observer == obs) { + if (i->autoFree) + delete obs; + + _observers.erase(i); + return; + } + } +} + +void EventDispatcher::dispatchEvent(const Event &event) { + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->observer->notifyEvent(event)) + break; + } +} + +} // end of namespace Common + diff --git a/common/EventRecorder.cpp b/common/EventRecorder.cpp new file mode 100644 index 0000000000..3d5eee3e52 --- /dev/null +++ b/common/EventRecorder.cpp @@ -0,0 +1,366 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/EventRecorder.h" + +#include "common/config-manager.h" + +DECLARE_SINGLETON(Common::EventRecorder); + +namespace Common { + +#define RECORD_SIGNATURE 0x54455354 +#define RECORD_VERSION 1 + +void readRecord(Common::InSaveFile *inFile, uint32 &diff, Common::Event &event) { + diff = inFile->readUint32LE(); + + event.type = (Common::EventType)inFile->readUint32LE(); + + switch(event.type) { + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + event.kbd.keycode = (Common::KeyCode)inFile->readSint32LE(); + event.kbd.ascii = inFile->readUint16LE(); + event.kbd.flags = inFile->readByte(); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + event.mouse.x = inFile->readSint16LE(); + event.mouse.y = inFile->readSint16LE(); + break; + default: + break; + } +} + +void writeRecord(Common::OutSaveFile *outFile, uint32 diff, const Common::Event &event) { + outFile->writeUint32LE(diff); + + outFile->writeUint32LE((uint32)event.type); + + switch(event.type) { + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + outFile->writeSint32LE(event.kbd.keycode); + outFile->writeUint16LE(event.kbd.ascii); + outFile->writeByte(event.kbd.flags); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + outFile->writeSint16LE(event.mouse.x); + outFile->writeSint16LE(event.mouse.y); + break; + default: + break; + } +} + +EventRecorder::EventRecorder() { + _recordFile = NULL; + _recordTimeFile = NULL; + _playbackFile = NULL; + _playbackTimeFile = NULL; + _timeMutex = g_system->createMutex(); + _recorderMutex = g_system->createMutex(); + + _eventCount = 0; + _lastEventCount = 0; + _lastMillis = 0; + +} + +EventRecorder::~EventRecorder() { + deinit(); +} + +void EventRecorder::init() { + Common::String recordModeString = ConfMan.get("record_mode"); + if (recordModeString.compareToIgnoreCase("record") == 0) { + _recordMode = kRecorderRecord; + } else { + if (recordModeString.compareToIgnoreCase("playback") == 0) { + _recordMode = kRecorderPlayback; + } else { + _recordMode = kPassthrough; + } + } + + _recordFileName = ConfMan.get("record_file_name"); + if (_recordFileName.empty()) { + _recordFileName = "record.bin"; + } + _recordTempFileName = ConfMan.get("record_temp_file_name"); + if (_recordTempFileName.empty()) { + _recordTempFileName = "record.tmp"; + } + _recordTimeFileName = ConfMan.get("record_time_file_name"); + if (_recordTimeFileName.empty()) { + _recordTimeFileName = "record.time"; + } + + // recorder stuff + if (_recordMode == kRecorderRecord) { + _recordCount = 0; + _recordTimeCount = 0; + _recordFile = g_system->getSavefileManager()->openForSaving(_recordTempFileName); + _recordTimeFile = g_system->getSavefileManager()->openForSaving(_recordTimeFileName); + _recordSubtitles = ConfMan.getBool("subtitles"); + } + + uint32 sign; + uint32 version; + uint32 randomSourceCount; + if (_recordMode == kRecorderPlayback) { + _playbackCount = 0; + _playbackTimeCount = 0; + _playbackFile = g_system->getSavefileManager()->openForLoading(_recordFileName); + _playbackTimeFile = g_system->getSavefileManager()->openForLoading(_recordTimeFileName); + + if (!_playbackFile) { + warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str()); + _recordMode = kPassthrough; + } + + if (!_playbackTimeFile) { + warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str()); + _recordMode = kPassthrough; + } + } + + if (_recordMode == kRecorderPlayback) { + sign = _playbackFile->readUint32LE(); + if (sign != RECORD_SIGNATURE) { + error("Unknown record file signature"); + } + version = _playbackFile->readUint32LE(); + + // conf vars + ConfMan.setBool("subtitles", _playbackFile->readByte() != 0); + + _recordCount = _playbackFile->readUint32LE(); + _recordTimeCount = _playbackFile->readUint32LE(); + randomSourceCount = _playbackFile->readUint32LE(); + for (uint i = 0; i < randomSourceCount; ++i) { + RandomSourceRecord rec; + rec.name = ""; + uint32 sLen = _playbackFile->readUint32LE(); + for (uint j = 0; j < sLen; ++j) { + char c = _playbackFile->readSByte(); + rec.name += c; + } + rec.seed = _playbackFile->readUint32LE(); + _randomSourceRecords.push_back(rec); + } + + _hasPlaybackEvent = false; + } + + g_system->getEventManager()->getEventDispatcher()->registerSource(this, false); + g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 1, false); +} + +void EventRecorder::deinit() { + g_system->getEventManager()->getEventDispatcher()->unregisterSource(this); + g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); + + g_system->lockMutex(_timeMutex); + g_system->lockMutex(_recorderMutex); + _recordMode = kPassthrough; + g_system->unlockMutex(_timeMutex); + g_system->unlockMutex(_recorderMutex); + + if (_playbackFile != NULL) { + delete _playbackFile; + } + if (_playbackTimeFile != NULL) { + delete _playbackTimeFile; + } + + if (_recordFile != NULL) { + _recordFile->finalize(); + delete _recordFile; + _recordTimeFile->finalize(); + delete _recordTimeFile; + + _playbackFile = g_system->getSavefileManager()->openForLoading(_recordTempFileName); + + assert(_playbackFile); + + _recordFile = g_system->getSavefileManager()->openForSaving(_recordFileName); + _recordFile->writeUint32LE(RECORD_SIGNATURE); + _recordFile->writeUint32LE(RECORD_VERSION); + + // conf vars + _recordFile->writeByte(_recordSubtitles ? 1 : 0); + + _recordFile->writeUint32LE(_recordCount); + _recordFile->writeUint32LE(_recordTimeCount); + + _recordFile->writeUint32LE(_randomSourceRecords.size()); + for (uint i = 0; i < _randomSourceRecords.size(); ++i) { + _recordFile->writeUint32LE(_randomSourceRecords[i].name.size()); + _recordFile->writeString(_randomSourceRecords[i].name); + _recordFile->writeUint32LE(_randomSourceRecords[i].seed); + } + + for (uint i = 0; i < _recordCount; ++i) { + uint32 tempDiff; + Common::Event tempEvent; + readRecord(_playbackFile, tempDiff, tempEvent); + writeRecord(_recordFile, tempDiff, tempEvent); + } + + _recordFile->finalize(); + delete _recordFile; + delete _playbackFile; + + //TODO: remove recordTempFileName'ed file + } + + g_system->deleteMutex(_timeMutex); + g_system->deleteMutex(_recorderMutex); +} + +void EventRecorder::registerRandomSource(Common::RandomSource &rnd, const char *name) { + if (_recordMode == kRecorderRecord) { + RandomSourceRecord rec; + rec.name = name; + rec.seed = rnd.getSeed(); + _randomSourceRecords.push_back(rec); + } + + if (_recordMode == kRecorderPlayback) { + for (uint i = 0; i < _randomSourceRecords.size(); ++i) { + if (_randomSourceRecords[i].name == name) { + rnd.setSeed(_randomSourceRecords[i].seed); + _randomSourceRecords.remove_at(i); + break; + } + } + } +} + +void EventRecorder::processMillis(uint32 &millis) { + uint32 d; + if (_recordMode == kPassthrough) { + return; + } + + g_system->lockMutex(_timeMutex); + if (_recordMode == kRecorderRecord) { + //Simple RLE compression + d = millis - _lastMillis; + if (d >= 0xff) { + _recordTimeFile->writeByte(0xff); + _recordTimeFile->writeUint32LE(d); + } else { + _recordTimeFile->writeByte(d); + } + _recordTimeCount++; + } + + if (_recordMode == kRecorderPlayback) { + if (_recordTimeCount > _playbackTimeCount) { + d = _playbackTimeFile->readByte(); + if (d == 0xff) { + d = _playbackTimeFile->readUint32LE(); + } + millis = _lastMillis + d; + _playbackTimeCount++; + } + } + + _lastMillis = millis; + g_system->unlockMutex(_timeMutex); +} + +bool EventRecorder::notifyEvent(const Common::Event &ev) { + if (_recordMode != kRecorderRecord) + return false; + + Common::StackLock lock(_recorderMutex); + ++_eventCount; + + writeRecord(_recordFile, _eventCount - _lastEventCount, ev); + + _recordCount++; + _lastEventCount = _eventCount; + + return false; +} + +bool EventRecorder::pollEvent(Common::Event &ev) { + if (_recordMode != kRecorderPlayback) + return false; + + Common::StackLock lock(_recorderMutex); + ++_eventCount; + + if (!_hasPlaybackEvent) { + if (_recordCount > _playbackCount) { + readRecord(_playbackFile, const_cast<uint32&>(_playbackDiff), _playbackEvent); + _playbackCount++; + _hasPlaybackEvent = true; + } + } + + if (_hasPlaybackEvent) { + if (_playbackDiff <= (_eventCount - _lastEventCount)) { + switch(_playbackEvent.type) { + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + g_system->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y); + break; + default: + break; + } + ev = _playbackEvent; + _hasPlaybackEvent = false; + _lastEventCount = _eventCount; + return true; + } + } + + return false; +} + +} // end of namespace Common + diff --git a/common/EventRecorder.h b/common/EventRecorder.h new file mode 100644 index 0000000000..e6ea961737 --- /dev/null +++ b/common/EventRecorder.h @@ -0,0 +1,106 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef COMMON_EVENTRECORDER_H +#define COMMON_EVENTRECORDER_H + +#include "common/scummsys.h" +#include "common/events.h" +#include "common/singleton.h" +#include "common/savefile.h" +#include "common/mutex.h" +#include "common/array.h" + +#define g_eventRec (Common::EventRecorder::instance()) + +namespace Common { + +/** + * Our generic event recorder. + * + * TODO: Add more documentation. + */ +class EventRecorder : private EventSource, private EventObserver, public Singleton<EventRecorder> { + friend class Common::Singleton<SingletonBaseType>; + EventRecorder(); + ~EventRecorder(); +public: + void init(); + void deinit(); + + /** Register random source so it can be serialized in game test purposes */ + void registerRandomSource(Common::RandomSource &rnd, const char *name); + + /** TODO: Add documentation, this is only used by the backend */ + void processMillis(uint32 &millis); + +private: + bool notifyEvent(const Common::Event &ev); + bool pollEvent(Common::Event &ev); + bool allowMapping() const { return false; } + + class RandomSourceRecord { + public: + Common::String name; + uint32 seed; + }; + Common::Array<RandomSourceRecord> _randomSourceRecords; + + bool _recordSubtitles; + volatile uint32 _recordCount; + volatile uint32 _lastRecordEvent; + volatile uint32 _recordTimeCount; + Common::OutSaveFile *_recordFile; + Common::OutSaveFile *_recordTimeFile; + Common::MutexRef _timeMutex; + Common::MutexRef _recorderMutex; + volatile uint32 _lastMillis; + + volatile uint32 _playbackCount; + volatile uint32 _playbackDiff; + volatile bool _hasPlaybackEvent; + volatile uint32 _playbackTimeCount; + Common::Event _playbackEvent; + Common::InSaveFile *_playbackFile; + Common::InSaveFile *_playbackTimeFile; + + volatile uint32 _eventCount; + volatile uint32 _lastEventCount; + + enum RecordMode { + kPassthrough = 0, + kRecorderRecord = 1, + kRecorderPlayback = 2 + }; + volatile RecordMode _recordMode; + Common::String _recordFileName; + Common::String _recordTempFileName; + Common::String _recordTimeFileName; +}; + +} // end of namespace Common + +#endif + diff --git a/common/events.h b/common/events.h index 82b85e60ea..34769729ea 100644 --- a/common/events.h +++ b/common/events.h @@ -31,6 +31,9 @@ #include "common/rect.h" #include "common/noncopyable.h" +#include "common/list.h" +#include "common/singleton.h" + namespace Common { /** @@ -126,6 +129,190 @@ struct Event { Event() : type(EVENT_INVALID), synthetic(false) {} }; +/** + * A source of Events. + * + * An example for this is OSystem, it provides events created by the system + * and or user. + */ +class EventSource { +public: + virtual ~EventSource() {} + + /** + * Queries a event from the source. + * + * @param event a reference to the event struct, where the event should be stored. + * @return true if an event was polled, false otherwise. + */ + virtual bool pollEvent(Event &event) = 0; + + /** + * Checks whether events from this source are allowed to be mapped. + * + * Possible event sources not allowing mapping are: the event recorder/player and/or + * the EventManager, which allows user events to be pushed. + * + * By default we allow mapping for every event source. + */ + virtual bool allowMapping() const { return true; } +}; + +/** + * An artificial event source. This is class is used as an event source, which is + * made up by client specific events. + * + * Example usage cases for this are the Keymapper or the DefaultEventManager. + */ +class ArtificialEventSource : public EventSource { +protected: + Common::Queue<Common::Event> _artificialEventQueue; +public: + void addEvent(const Common::Event &ev) { + _artificialEventQueue.push(ev); + } + + bool pollEvent(Common::Event &ev) { + if (!_artificialEventQueue.empty()) { + ev = _artificialEventQueue.pop(); + return true; + } else { + return false; + } + } + + /** + * By default an artificial event source prevents its events + * from being mapped. + */ + virtual bool allowMapping() const { return false; } +}; + +/** + * Object which catches and processes Events. + * + * An example for this is the Engine object, it is catching events and processing them. + */ +class EventObserver { +public: + virtual ~EventObserver() {} + + /** + * Notifies the source of an incoming event. + * + * An obeser is supposed to eat the event, with returning true, when + * it might want prevent other observers from preventing to receive + * the event. An usage example here is the keymapper: + * If it processes an Event, it should 'eat' it and create a new + * event, which the EventDispatcher will then catch. + * + * @param event the event, which is incoming. + * @return true if this observer uses this event, false otherwise. + */ + virtual bool notifyEvent(const Event &event) = 0; +}; + +/** + * A event mapper, which will map events to others. + * + * An example for this is the Keymapper. + */ +class EventMapper : public EventSource, public EventObserver { +public: + /** For event mappers resulting events should never be mapped */ + bool allowMapping() const { return false; } +}; + +/** + * Dispatches events from various sources to various observers. + * + * EventDispatcher is using a priority based approach. Observers + * with higher priority will be notified before observers with + * lower priority. Because of the possibility that oberservers + * might 'eat' events, not all observers might be notified. + * + * Another speciality is the support for a event mapper, which + * will catch events and create new events out of them. This + * mapper will be processed before an event is sent to the + * observers. + */ +class EventDispatcher { +public: + EventDispatcher(); + ~EventDispatcher(); + + /** + * Tries to catch events from the registered event + * sources and dispatch them to the observers. + * + * This dispatches *all* events the sources offer. + */ + void dispatch(); + + /** + * Registers an event mapper with the dispatcher. + * + * The ownership of the "mapper" variable will pass + * to the EventDispatcher, thus it will be deleted + * with "delete", when EventDispatcher is destroyed. + * + * Note there is only one mapper per EventDispatcher + * possible, thus when this method is called twice, + * the former mapper will be destroied. + */ + void registerMapper(EventMapper *mapper); + + /** + * Queries the setup event mapper. + */ + EventMapper *queryMapper() const { return _mapper; } + + /** + * Registers a new EventSource with the Dispatcher. + */ + void registerSource(EventSource *source, bool autoFree); + + /** + * Unregisters a EventSource. + * + * This takes the "autoFree" flag passed to registerSource into account. + */ + void unregisterSource(EventSource *source); + + /** + * Registers a new EventObserver with the Dispatcher. + */ + void registerObserver(EventObserver *obs, uint priority, bool autoFree); + + /** + * Unregisters a EventObserver. + * + * This takes the "autoFree" flag passed to registerObserver into account. + */ + void unregisterObserver(EventObserver *obs); +private: + EventMapper *_mapper; + + struct Entry { + bool autoFree; + }; + + struct SourceEntry : public Entry { + EventSource *source; + }; + + Common::List<SourceEntry> _sources; + + struct ObserverEntry : public Entry { + uint priority; + EventObserver *observer; + }; + + Common::List<ObserverEntry> _observers; + + void dispatchEvent(const Event &event); +}; + class Keymapper; /** @@ -161,11 +348,6 @@ public: */ virtual void pushEvent(const Common::Event &event) = 0; - /** Register random source so it can be serialized in game test purposes **/ - virtual void registerRandomSource(Common::RandomSource &rnd, const char *name) = 0; - - virtual void processMillis(uint32 &millis) = 0; - /** Return the current mouse position */ virtual Common::Point getMousePos() const = 0; @@ -209,9 +391,21 @@ public: virtual Common::Keymapper *getKeymapper() = 0; #endif -protected: + enum { + /** + * Priority of the event manager, for now it's lowest since it eats + * *all* events, we might to change that in the future though. + */ + kEventManPriority = 0 + }; - Common::Queue<Common::Event> artificialEventQueue; + /** + * Returns the underlying EventDispatcher. + */ + EventDispatcher *getEventDispatcher() { return &_dispatcher; } + +protected: + EventDispatcher _dispatcher; }; } // End of namespace Common diff --git a/common/file.cpp b/common/file.cpp index 7836a7d4a8..dd4281bd03 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -120,15 +120,6 @@ bool File::isOpen() const { return _handle != NULL; } -bool File::ioFailed() const { - return !_handle || (eos() || err()); -} - -void File::clearIOFailed() { - if (_handle) - _handle->clearErr(); -} - bool File::err() const { assert(_handle); return _handle->err(); diff --git a/common/file.h b/common/file.h index a98d23a96a..6ac633c462 100644 --- a/common/file.h +++ b/common/file.h @@ -126,19 +126,6 @@ public: */ const char *getName() const { return _name.c_str(); } - /** - * DEPRECATED: Use err() or eos() instead. - * Returns true if any I/O failure occurred or the end of the - * stream was reached while reading. - */ - bool ioFailed() const; - - /** - * DEPRECATED: Don't use this unless you are still using ioFailed(). - * Reset the I/O error status. - */ - void clearIOFailed(); - bool err() const; // implement abstract Stream method void clearErr(); // implement abstract Stream method bool eos() const; // implement abstract SeekableReadStream method diff --git a/common/module.mk b/common/module.mk index bdf9590962..d4f92f0791 100644 --- a/common/module.mk +++ b/common/module.mk @@ -5,6 +5,8 @@ MODULE_OBJS := \ config-file.o \ config-manager.o \ debug.o \ + EventDispatcher.o \ + EventRecorder.o \ file.o \ fs.o \ hashmap.o \ diff --git a/common/str.cpp b/common/str.cpp index 0d24f2edac..b422a34c3c 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -28,6 +28,8 @@ #include "common/memorypool.h" +#include <stdarg.h> + #if !defined(__SYMBIAN32__) #include <new> #endif @@ -435,6 +437,33 @@ uint String::hash() const { return hashit(c_str()); } +// static +String String::printf(const char *fmt, ...) { + String output; + assert(output.isStorageIntern()); + + va_list va; + va_start(va, fmt); + int len = vsnprintf(output._str, _builtinCapacity, fmt, va); + va_end(va); + + if (len < (int)_builtinCapacity) { + // vsnprintf succeeded + output._size = len; + } else { + // vsnprintf didn't have enough space, so grow buffer + output.ensureCapacity(len, false); + va_start(va, fmt); + int len2 = vsnprintf(output._str, len+1, fmt, va); + va_end(va); + assert(len == len2); + output._size = len2; + } + + return output; +} + + #pragma mark - bool String::operator ==(const String &x) const { diff --git a/common/str.h b/common/str.h index b7dbd6535a..2fc88e9c91 100644 --- a/common/str.h +++ b/common/str.h @@ -218,6 +218,11 @@ public: uint hash() const; + /** + * Printf-like function. Returns a formatted String. + */ + static Common::String printf(const char *fmt, ...) GCC_PRINTF(1,2); + public: typedef char * iterator; typedef const char * const_iterator; diff --git a/common/stream.h b/common/stream.h index 80e2978fb9..9b03c20bd2 100644 --- a/common/stream.h +++ b/common/stream.h @@ -179,7 +179,7 @@ public: * DEPRECATED * Default implementation for backward compatibility */ - virtual bool ioFailed() { return (eos() || err()); } + inline bool ioFailed() { return (eos() || err()); } /** * Read an unsigned byte from the stream and return it. diff --git a/common/unarj.cpp b/common/unarj.cpp index 428b4a426e..0312cc5b08 100644 --- a/common/unarj.cpp +++ b/common/unarj.cpp @@ -105,7 +105,7 @@ public: void decode(int32 origsize); void decode_f(int32 origsize); - MemoryReadStream *_compressed; + BufferedReadStream *_compressed; MemoryWriteStream *_outstream; //protected: @@ -360,6 +360,9 @@ bool ArjFile::open(const Common::String &filename) { return false; ArjHeader *hdr = _headers[_fileMap[filename]]; + + // TODO: It would be good if ArjFile could decompress files in a streaming + // mode, so it would not need to pre-allocate the entire output. byte *uncompressedData = (byte *)malloc(hdr->origSize); File archiveFile; @@ -372,10 +375,11 @@ bool ArjFile::open(const Common::String &filename) { } else { ArjDecoder *decoder = new ArjDecoder(hdr); - byte *compressedData = (byte *)malloc(hdr->compSize); - archiveFile.read(compressedData, hdr->compSize); - - decoder->_compressed = new MemoryReadStream(compressedData, hdr->compSize, true); + // TODO: It might not be appropriate to use this wrapper inside ArjFile. + // If reading from archiveFile directly is too slow to be usable, + // maybe the filesystem code should instead wrap its files + // in a BufferedReadStream. + decoder->_compressed = new BufferedReadStream(&archiveFile, 4096, false); decoder->_outstream = new MemoryWriteStream(uncompressedData, hdr->origSize); if (hdr->method == 1 || hdr->method == 2 || hdr->method == 3) @@ -88,7 +88,7 @@ add_engine queen "Flight of the Amazon Queen" yes add_engine saga "SAGA" yes "ihnm saga2" add_engine ihnm "IHNM" yes add_engine saga2 "SAGA 2 games" no -add_engine sci "SCI" no "sci32" +add_engine sci "SCI" yes "sci32" add_engine sci32 "SCI32 games" no add_engine sky "Beneath a Steel Sky" yes add_engine sword1 "Broken Sword 1" yes @@ -110,8 +110,10 @@ _alsa=auto _zlib=auto _mpeg2=no _fluidsynth=auto -_mt32emu=yes +_readline=auto # Default option behaviour yes/no +_text_console=no +_mt32emu=yes _build_hq_scalers=yes _build_scalers=yes # Default vkeybd/keymapper options @@ -265,7 +267,7 @@ find_sdlconfig() { # get_system_exe_extension() { case $1 in - mingw* | *os2-emx) + mingw* | *os2-emx | wince) _exeext=".exe" ;; arm-riscos) @@ -277,7 +279,7 @@ get_system_exe_extension() { gp2x-linux) _exeext=".gp2x" ;; - dreamcast | wii | gamecube | psp) + dreamcast | wii | gamecube | nds | psp) _exeext=".elf" ;; *) @@ -551,7 +553,7 @@ Usage: $0 [OPTIONS]... Configuration: -h, --help display this help and exit - --backend=BACKEND backend to build (sdl, morphos, dc, gp2x, gp2xwiz, iphone, wii, psp, null) [sdl] + --backend=BACKEND backend to build (sdl, dc, gp2x, gp2xwiz, iphone, morphos, nds, psp, wii, wince, null) [sdl] Installation directories: --prefix=DIR use this prefix for installing ScummVM [/usr/local] @@ -566,7 +568,9 @@ Special configuration feature: dreamcast for Sega Dreamcast wii for Nintendo Wii gamecube for Nintendo Gamecube + nds for Nintendo DS iphone for Apple iPhone + wince for Windows CE psp for PlayStation Portable Optional Features: @@ -580,6 +584,7 @@ $engines_help --disable-mt32emu don't enable the integrated MT-32 emulator --disable-hq-scalers exclude HQ2x and HQ3x scalers --disable-scalers exclude scalers + --enable-text-console use text console instead of graphical console Optional Libraries: --with-alsa-prefix=DIR Prefix where alsa is installed (optional) @@ -612,6 +617,9 @@ Optional Libraries: --with-nasm-prefix=DIR Prefix where nasm executable is installed (optional) --disable-nasm disable assembly language optimizations [autodetect] + --with-readline-prefix=DIR Prefix where readline is installed (optional) + --disable-readline disable readline support in text console [autodetect] + Some influential environment variables: LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> @@ -647,6 +655,8 @@ for ac_option in $@; do --disable-nasm) _nasm=no ;; --enable-mpeg2) _mpeg2=yes ;; --disable-fluidsynth) _fluidsynth=no ;; + --enable-readline) _readline=yes ;; + --disable-readline) _readline=no ;; --enable-plugins) _dynamic_modules=yes ;; --default-dynamic) _plugins_default=dynamic ;; --enable-mt32emu) _mt32emu=yes ;; @@ -655,6 +665,8 @@ for ac_option in $@; do --disable-vkeybd) _vkeybd=no ;; --enable-keymapper) _keymapper=yes ;; --disable-keymapper) _keymapper=no ;; + --enable-text-console) _text_console=yes ;; + --disable-text-console) _text_console=no ;; --with-fluidsynth-prefix=*) arg=`echo $ac_option | cut -d '=' -f 2` FLUIDSYNTH_CFLAGS="-I$arg/include" @@ -700,6 +712,11 @@ for ac_option in $@; do ZLIB_CFLAGS="-I$arg/include" ZLIB_LIBS="-L$arg/lib" ;; + --with-readline-prefix=*) + arg=`echo $ac_option | cut -d '=' -f 2` + READLINE_CFLAGS="-I$arg/include" + READLINE_LIBS="-L$arg/lib" + ;; --backend=*) _backend=`echo $ac_option | cut -d '=' -f 2` ;; @@ -804,6 +821,11 @@ iphone) _host_cpu=arm _host_alias=arm-apple-darwin9 ;; +wince) + _host_os=wince + _host_cpu=arm + _host_alias=arm-wince-mingw32ce + ;; neuros) _host_os=linux _host_cpu=arm @@ -820,17 +842,22 @@ wii) _host_cpu=ppc _host_alias=powerpc-gekko ;; +gamecube) + _host_os=gamecube + _host_cpu=ppc + _host_alias=powerpc-gekko + ;; +nds) + _host_os=nds + _host_cpu=arm + _host_alias=arm-eabi + ;; psp) _host_os=psp _host_cpu=mipsallegrexel _host_alias=psp LDFLAGS="$LDFLAGS -L$PSPDEV/psp/sdk/lib -specs=$_srcdir/backends/platform/psp/psp.spec" ;; -gamecube) - _host_os=gamecube - _host_cpu=ppc - _host_alias=powerpc-gekko - ;; *) if test -n "$_host"; then guessed_host=`$_srcdir/config.sub $_host` @@ -867,7 +894,7 @@ esac # Platform specific sanity checks # case $_host_os in -wii | gamecube) +wii | gamecube | nds) if test -z "$DEVKITPRO"; then echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>" exit 1 @@ -1147,9 +1174,16 @@ case $_host_os in CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include" LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube" ;; + nds) + # TODO nds + ;; psp) CXXFLAGS="$CXXFLAGS -O2 -G0 -I$PSPDEV/psp/sdk/include -D_PSP_FW_VERSION=150" ;; + wince) + CXXFLAGS="$CXXFLAGS -O3 -march=armv4 -mtune=xscale -D_WIN32_WCE=300 -D__ARM__ -D_ARM_ -DUNICODE -DFPM_DEFAULT -DNONSTANDARD_PORT" + CXXFLAGS="$CXXFLAGS -DWIN32 -Dcdecl= -D__cdecl__= -Wno-multichar" + ;; # given this is a shell script assume some type of unix *) echo "WARNING: could not establish system type, assuming unix like" @@ -1191,7 +1225,7 @@ if test -n "$_host"; then ;; gp2xwiz) echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" - DEFINES="$DEFINES -DUNIX -DGP2XWIZ -DNDEBUG -DUSE_ARM_SMUSH_ASM" + DEFINES="$DEFINES -DUNIX -DGP2XWIZ -DNDEBUG -DUSE_ARM_SMUSH_ASM -DUSE_ARM_GFX_ASM -DUSE_ARM_SCALER_ASM -DUSE_ARM_COSTUME_ASM" CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s -mtune=arm926ej-s" LDFLAGS="$LDFLAGS" _endian=little @@ -1203,13 +1237,16 @@ if test -n "$_host"; then _ranlib=$_host_alias-ranlib add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1' + add_line_to_config_mk 'USE_ARM_GFX_ASM = 1' + add_line_to_config_mk 'USE_ARM_SCALER_ASM = 1' + add_line_to_config_mk 'USE_ARM_COSTUME_ASM = 1' _backend="gp2xwiz" _build_hq_scalers="no" _mt32emu="no" ;; gp2x) echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" - DEFINES="$DEFINES -DUNIX -DGP2X -DNDEBUG -DUSE_ARM_SMUSH_ASM" + DEFINES="$DEFINES -DUNIX -DGP2X -DNDEBUG -DUSE_ARM_SMUSH_ASM -DUSE_ARM_GFX_ASM -DUSE_ARM_SCALER_ASM -DUSE_ARM_COSTUME_ASM" CXXFLAGS="$CXXFLAGS -march=armv4t" LDFLAGS="$LDFLAGS -static" _endian=little @@ -1221,6 +1258,9 @@ if test -n "$_host"; then _ranlib=$_host_alias-ranlib add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1' + add_line_to_config_mk 'USE_ARM_GFX_ASM = 1' + add_line_to_config_mk 'USE_ARM_SCALER_ASM = 1' + add_line_to_config_mk 'USE_ARM_COSTUME_ASM = 1' _backend="gp2x" _build_hq_scalers="no" _mt32emu="no" @@ -1284,6 +1324,28 @@ if test -n "$_host"; then _ranlib=$_host_alias-ranlib _strip=$_host_alias-strip ;; + wince) + echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" + LDFLAGS="$LDFLAGS -Wl,-Map,scummvm.exe.map -Wl,--stack,65536" + _endian=little + _need_memalign=yes + type_1_byte='char' + type_2_byte='short' + type_4_byte='int' + add_line_to_config_mk 'USE_TREMOLO = 1' + add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' + add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1' + add_line_to_config_mk 'USE_ARM_GFX_ASM = 1' + add_line_to_config_mk 'USE_ARM_COSTUME_ASM = 1' + add_line_to_config_mk 'USE_ARM_SCALER_ASM = 1' + _backend="wince" + _ar="$_host_alias-ar cru" + _ranlib=$_host_alias-ranlib + _strip=$_host_alias-strip + _windres=$_host_alias-windres + _mt32emu="no" + add_line_to_config_mk 'include $(srcdir)/backends/platform/wince/wince.mk' + ;; dreamcast) echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE" @@ -1342,6 +1404,24 @@ if test -n "$_host"; then add_line_to_config_h "/* #define DEBUG_WII_MEMSTATS */" add_line_to_config_h "/* #define DEBUG_WII_GDB */" ;; + nds) + echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" + # TODO: complete this + # TODO: Maybe rename nds -> ds (would be more consistent with other backends) + DEFINES="$DEFINES -DUSE_ARM_SMUSH_ASM" + _endian=little + _need_memalign=yes + type_1_byte='char' + type_2_byte='short' + type_4_byte='int' + _backend="nds" + _build_hq_scalers="no" + _mt32emu="no" + add_line_to_config_mk 'include $(srcdir)/backends/platform/ds/ds.mk' + # TODO: Enable more ARM optimizations -- requires testing! + add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' + add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1' + ;; psp) echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" _endian=little @@ -1802,6 +1882,45 @@ echo "$_fluidsynth" rm -rf $TMPC $TMPO$HOSTEXEEXT $TMPO.dSYM # +# Check for readline if text_console is enabled +# +echocheck "readline" +if test "$_text_console" = yes ; then + if test "$_readline" = auto ; then + _readline=no + cat > $TMPC << EOF +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> + +int main(void) { + char *x = readline(""); +} +EOF + cc_check $LDFLAGS $CXXFLAGS $READLINE_CFLAGS $READLINE_LIBS -lreadline && _readline=yes + fi + echo "$_readline" + rm -rf $TMPC $TMPO$HOSTEXEEXT $TMPO.dSYM +else + _readline=no + echo "skipping (text console disabled)" +fi + +if test "$_readline" = yes ; then + _def_readline='#define USE_READLINE' + LIBS="$LIBS $READLINE_LIBS -lreadline" + INCLUDES="$INCLUDES $READLINE_CFLAGS" +else + _def_readline='#undef USE_READLINE' +fi + +if test "$_text_console" = yes ; then + _def_text_console='#define USE_TEXT_CONSOLE' +else + _def_text_console='#undef USE_TEXT_CONSOLE' +fi + +# # Check for nasm # if test "$_have_x86" = yes ; then @@ -1884,6 +2003,10 @@ if test "$_mt32emu" = yes ; then echo_n ", MT-32 emu" fi +if test "$_text_console" = yes ; then + echo_n ", text console" +fi + if test "$_vkeybd" = yes ; then echo_n ", virtual keyboard" fi @@ -1925,6 +2048,10 @@ case $_backend in OBJCFLAGS="$OBJCFLAGS --std=c99" LIBS="$LIBS -lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES -framework QuartzCore -framework GraphicsServices -framework CoreFoundation -framework Foundation -framework AudioToolbox -framework CoreAudio" ;; + wince) + INCLUDES="$INCLUDES "'-I$(srcdir) -I$(srcdir)/backends/platform/wince -I$(srcdir)/engines -I$(srcdir)/backends/platform/wince/missing/gcc -I$(srcdir)/backends/platform/wince/CEgui -I$(srcdir)/backends/platform/wince/CEkeys' + LIBS="$LIBS -static -lSDL" + ;; dc) INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc -isystem $(ronindir)/include' LDFLAGS="$LDFLAGS -Wl,-Ttext,0x8c010000 -nostartfiles "'$(ronindir)/lib/crt0.o -L$(ronindir)/lib' @@ -1941,6 +2068,9 @@ case $_backend in ;; esac ;; + nds) + # TODO nds + ;; psp) DEFINES="$DEFINES -D__PSP__ -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE" INCLUDES="$INCLUDES -I$PSPDEV/psp/include/SDL" @@ -1960,7 +2090,7 @@ if test "$_cxx_major" -ge "3" ; then case $_host_os in # newlib-based system include files suppress non-C89 function # declarations under __STRICT_ANSI__ - mingw* | dreamcast | wii | gamecube | psp | amigaos*) + mingw* | dreamcast | wii | gamecube | psp | wince | amigaos*) CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter" ;; *) @@ -2095,6 +2225,10 @@ $_def_alsa $_def_zlib $_def_mpeg2 $_def_fluidsynth +$_def_readline + +/* Options */ +$_def_text_console $_def_mt32emu /* Plugin settings */ diff --git a/dists/iphone/Info.plist b/dists/iphone/Info.plist new file mode 100644 index 0000000000..1a0a8bf0b6 --- /dev/null +++ b/dists/iphone/Info.plist @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>ScummVM</string> + <key>CFBundleIdentifier</key> + <string>org.scummvm.scummvm</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>ScummVM</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleShortVersionString</key> + <string>1.1.0svn</string> + <key>CFBundleVersion</key> + <string>svn</string> + <key>CFBundleIconFile</key> + <string>icon.png</string> + <key>UIPrerenderedIcon</key> + <true/> +</dict> +</plist> diff --git a/dists/macosx/Info.plist b/dists/macosx/Info.plist new file mode 100644 index 0000000000..5600084eae --- /dev/null +++ b/dists/macosx/Info.plist @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleDisplayName</key> + <string>ScummVM</string> + <key>CFBundleExecutable</key> + <string>scummvm</string> + <key>CFBundleGetInfoString</key> + <string>1.1.0svn, Copyright 2001-2008 The ScummVM team</string> + <key>CFBundleIconFile</key> + <string>scummvm.icns</string> + <key>CFBundleIdentifier</key> + <string>org.scummvm.scummvm</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>ScummVM</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.1.0svn</string> + <key>CFBundleVersion</key> + <string>1.1.0svn</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright 2001-2008 The ScummVM team</string> +</dict> +</plist> diff --git a/dists/msvc8/gob.vcproj b/dists/msvc8/gob.vcproj index 5878abe30b..c691aae742 100644 --- a/dists/msvc8/gob.vcproj +++ b/dists/msvc8/gob.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8,00" + Version="8.00" Name="gob" ProjectGUID="{976D947A-A45F-4437-991E-412F695C64C7}" RootNamespace="gob" @@ -15,6 +15,33 @@ <Configuration Name="Release|Win32" ConfigurationType="4" InheritedPropertySheets=".\ScummVM_Release.vsprops" /> </Configurations> <Files> + <Filter Name="demos"> + <File RelativePath="..\..\engines\gob\demos\batplayer.cpp" /> + <File RelativePath="..\..\engines\gob\demos\batplayer.h" /> + <File RelativePath="..\..\engines\gob\demos\demoplayer.cpp" /> + <File RelativePath="..\..\engines\gob\demos\demoplayer.h" /> + <File RelativePath="..\..\engines\gob\demos\scnplayer.cpp" /> + <File RelativePath="..\..\engines\gob\demos\scnplayer.h" /> + </Filter> + <Filter Name="save"> + <File RelativePath="..\..\engines\gob\save\saveconverter.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter.h" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v2.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v3.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v4.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v6.cpp" /> + <File RelativePath="..\..\engines\gob\save\savefile.cpp" /> + <File RelativePath="..\..\engines\gob\save\savefile.h" /> + <File RelativePath="..\..\engines\gob\save\savehandler.cpp" /> + <File RelativePath="..\..\engines\gob\save\savehandler.h" /> + <File RelativePath="..\..\engines\gob\save\saveload.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload.h" /> + <File RelativePath="..\..\engines\gob\save\saveload_v2.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_v3.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_v4.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_v6.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp" /> + </Filter> <Filter Name="sound"> <File RelativePath="..\..\engines\gob\sound\adlib.cpp" /> <File RelativePath="..\..\engines\gob\sound\adlib.h" /> @@ -37,12 +64,8 @@ <File RelativePath="..\..\engines\gob\sound\soundmixer.cpp" /> <File RelativePath="..\..\engines\gob\sound\soundmixer.h" /> </Filter> - <File RelativePath="..\..\engines\gob\demos\batplayer.cpp" /> - <File RelativePath="..\..\engines\gob\demos\batplayer.h" /> <File RelativePath="..\..\engines\gob\dataio.cpp" /> <File RelativePath="..\..\engines\gob\dataio.h" /> - <File RelativePath="..\..\engines\gob\demos\demoplayer.cpp" /> - <File RelativePath="..\..\engines\gob\demos\demoplayer.h" /> <File RelativePath="..\..\engines\gob\detection.cpp" /> <File RelativePath="..\..\engines\gob\draw.cpp" /> <File RelativePath="..\..\engines\gob\draw.h" /> @@ -74,6 +97,7 @@ <File RelativePath="..\..\engines\gob\init_v1.cpp" /> <File RelativePath="..\..\engines\gob\init_v2.cpp" /> <File RelativePath="..\..\engines\gob\init_v3.cpp" /> + <File RelativePath="..\..\engines\gob\init_v4.cpp" /> <File RelativePath="..\..\engines\gob\init_v6.cpp" /> <File RelativePath="..\..\engines\gob\inter.cpp" /> <File RelativePath="..\..\engines\gob\inter.h" /> @@ -89,7 +113,6 @@ <File RelativePath="..\..\engines\gob\map.h" /> <File RelativePath="..\..\engines\gob\map_v1.cpp" /> <File RelativePath="..\..\engines\gob\map_v2.cpp" /> - <File RelativePath="..\..\engines\gob\map_v4.cpp" /> <File RelativePath="..\..\engines\gob\mult.cpp" /> <File RelativePath="..\..\engines\gob\mult.h" /> <File RelativePath="..\..\engines\gob\mult_v1.cpp" /> @@ -98,29 +121,10 @@ <File RelativePath="..\..\engines\gob\palanim.h" /> <File RelativePath="..\..\engines\gob\resources.cpp" /> <File RelativePath="..\..\engines\gob\resources.h" /> - <File RelativePath="..\..\engines\gob\save\saveconverter.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter.h" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v2.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v3.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v4.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v6.cpp" /> - <File RelativePath="..\..\engines\gob\save\savefile.cpp" /> - <File RelativePath="..\..\engines\gob\save\savefile.h" /> - <File RelativePath="..\..\engines\gob\save\savehandler.cpp" /> - <File RelativePath="..\..\engines\gob\save\savehandler.h" /> - <File RelativePath="..\..\engines\gob\save\saveload.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload.h" /> - <File RelativePath="..\..\engines\gob\save\saveload_v2.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_v3.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_v4.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_v6.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp" /> <File RelativePath="..\..\engines\gob\scenery.cpp" /> <File RelativePath="..\..\engines\gob\scenery.h" /> <File RelativePath="..\..\engines\gob\scenery_v1.cpp" /> <File RelativePath="..\..\engines\gob\scenery_v2.cpp" /> - <File RelativePath="..\..\engines\gob\demos\scnplayer.cpp" /> - <File RelativePath="..\..\engines\gob\demos\scnplayer.h" /> <File RelativePath="..\..\engines\gob\script.cpp" /> <File RelativePath="..\..\engines\gob\script.h" /> <File RelativePath="..\..\engines\gob\totfile.cpp" /> diff --git a/dists/msvc9/gob.vcproj b/dists/msvc9/gob.vcproj index 8852e59fa3..984c153e35 100644 --- a/dists/msvc9/gob.vcproj +++ b/dists/msvc9/gob.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="9,00" + Version="9.00" Name="gob" ProjectGUID="{976D947A-A45F-4437-991E-412F695C64C7}" RootNamespace="gob" @@ -16,6 +16,33 @@ <Configuration Name="Release|Win32" ConfigurationType="4" InheritedPropertySheets=".\ScummVM_Release.vsprops" /> </Configurations> <Files> + <Filter Name="demos"> + <File RelativePath="..\..\engines\gob\demos\batplayer.cpp" /> + <File RelativePath="..\..\engines\gob\demos\batplayer.h" /> + <File RelativePath="..\..\engines\gob\demos\demoplayer.cpp" /> + <File RelativePath="..\..\engines\gob\demos\demoplayer.h" /> + <File RelativePath="..\..\engines\gob\demos\scnplayer.cpp" /> + <File RelativePath="..\..\engines\gob\demos\scnplayer.h" /> + </Filter> + <Filter Name="save"> + <File RelativePath="..\..\engines\gob\save\saveconverter.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter.h" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v2.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v3.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v4.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveconverter_v6.cpp" /> + <File RelativePath="..\..\engines\gob\save\savefile.cpp" /> + <File RelativePath="..\..\engines\gob\save\savefile.h" /> + <File RelativePath="..\..\engines\gob\save\savehandler.cpp" /> + <File RelativePath="..\..\engines\gob\save\savehandler.h" /> + <File RelativePath="..\..\engines\gob\save\saveload.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload.h" /> + <File RelativePath="..\..\engines\gob\save\saveload_v2.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_v3.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_v4.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_v6.cpp" /> + <File RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp" /> + </Filter> <Filter Name="sound"> <File RelativePath="..\..\engines\gob\sound\adlib.cpp" /> <File RelativePath="..\..\engines\gob\sound\adlib.h" /> @@ -38,12 +65,8 @@ <File RelativePath="..\..\engines\gob\sound\soundmixer.cpp" /> <File RelativePath="..\..\engines\gob\sound\soundmixer.h" /> </Filter> - <File RelativePath="..\..\engines\gob\demos\batplayer.cpp" /> - <File RelativePath="..\..\engines\gob\demos\batplayer.h" /> <File RelativePath="..\..\engines\gob\dataio.cpp" /> <File RelativePath="..\..\engines\gob\dataio.h" /> - <File RelativePath="..\..\engines\gob\demos\demoplayer.cpp" /> - <File RelativePath="..\..\engines\gob\demos\demoplayer.h" /> <File RelativePath="..\..\engines\gob\detection.cpp" /> <File RelativePath="..\..\engines\gob\draw.cpp" /> <File RelativePath="..\..\engines\gob\draw.h" /> @@ -75,6 +98,7 @@ <File RelativePath="..\..\engines\gob\init_v1.cpp" /> <File RelativePath="..\..\engines\gob\init_v2.cpp" /> <File RelativePath="..\..\engines\gob\init_v3.cpp" /> + <File RelativePath="..\..\engines\gob\init_v4.cpp" /> <File RelativePath="..\..\engines\gob\init_v6.cpp" /> <File RelativePath="..\..\engines\gob\inter.cpp" /> <File RelativePath="..\..\engines\gob\inter.h" /> @@ -90,7 +114,6 @@ <File RelativePath="..\..\engines\gob\map.h" /> <File RelativePath="..\..\engines\gob\map_v1.cpp" /> <File RelativePath="..\..\engines\gob\map_v2.cpp" /> - <File RelativePath="..\..\engines\gob\map_v4.cpp" /> <File RelativePath="..\..\engines\gob\mult.cpp" /> <File RelativePath="..\..\engines\gob\mult.h" /> <File RelativePath="..\..\engines\gob\mult_v1.cpp" /> @@ -99,29 +122,10 @@ <File RelativePath="..\..\engines\gob\palanim.h" /> <File RelativePath="..\..\engines\gob\resources.cpp" /> <File RelativePath="..\..\engines\gob\resources.h" /> - <File RelativePath="..\..\engines\gob\save\saveconverter.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter.h" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v2.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v3.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v4.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveconverter_v6.cpp" /> - <File RelativePath="..\..\engines\gob\save\savefile.cpp" /> - <File RelativePath="..\..\engines\gob\save\savefile.h" /> - <File RelativePath="..\..\engines\gob\save\savehandler.cpp" /> - <File RelativePath="..\..\engines\gob\save\savehandler.h" /> - <File RelativePath="..\..\engines\gob\save\saveload.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload.h" /> - <File RelativePath="..\..\engines\gob\save\saveload_v2.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_v3.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_v4.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_v6.cpp" /> - <File RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp" /> <File RelativePath="..\..\engines\gob\scenery.cpp" /> <File RelativePath="..\..\engines\gob\scenery.h" /> <File RelativePath="..\..\engines\gob\scenery_v1.cpp" /> <File RelativePath="..\..\engines\gob\scenery_v2.cpp" /> - <File RelativePath="..\..\engines\gob\demos\scnplayer.cpp" /> - <File RelativePath="..\..\engines\gob\demos\scnplayer.h" /> <File RelativePath="..\..\engines\gob\script.cpp" /> <File RelativePath="..\..\engines\gob\script.h" /> <File RelativePath="..\..\engines\gob\totfile.cpp" /> diff --git a/dists/msvc9/scummvm-tfmx.vcproj b/dists/msvc9/scummvm-tfmx.vcproj index 421cec08e6..ba2c231886 100644 --- a/dists/msvc9/scummvm-tfmx.vcproj +++ b/dists/msvc9/scummvm-tfmx.vcproj @@ -389,6 +389,18 @@ > </File> <File + RelativePath="..\..\common\EventDispatcher.cpp" + > + </File> + <File + RelativePath="..\..\common\EventRecorder.cpp" + > + </File> + <File + RelativePath="..\..\common\EventRecorder.h" + > + </File> + <File RelativePath="..\..\common\events.h" > </File> diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj index edcf9c4ebc..51c532a195 100644 --- a/dists/msvc9/scummvm.vcproj +++ b/dists/msvc9/scummvm.vcproj @@ -9,209 +9,861 @@ TargetFrameworkVersion="131072" > <Platforms> - <Platform Name="Win32" /> + <Platform + Name="Win32" + /> </Platforms> + <ToolFiles> + </ToolFiles> <Configurations> - <Configuration Name="Debug|Win32" ConfigurationType="1" InheritedPropertySheets=".\ScummVM_Debug.vsprops"> - <Tool Name="VCLinkerTool" OutputFile="$(OutDir)/scummvm.exe" + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ScummVM_Debug.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib $(OutDir)/*.lib" + OutputFile="$(OutDir)/scummvm.exe" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" /> </Configuration> - <Configuration Name="Release|Win32" ConfigurationType="1" InheritedPropertySheets=".\ScummVM_Release.vsprops"> - <Tool Name="VCLinkerTool" OutputFile="$(OutDir)/scummvm.exe" + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\ScummVM_Release.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib $(OutDir)/*.lib" + OutputFile="$(OutDir)/scummvm.exe" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" /> </Configuration> </Configurations> + <References> + </References> <Files> - <Filter Name="base"> - <File RelativePath="..\..\base\commandLine.cpp" /> - <File RelativePath="..\..\base\commandLine.h" /> - <File RelativePath="..\..\base\internal_version.h" /> - <File RelativePath="..\..\base\main.cpp" /> - <File RelativePath="..\..\base\main.h" /> - <File RelativePath="..\..\base\plugins.cpp" /> - <File RelativePath="..\..\base\plugins.h" /> - <File RelativePath="..\..\base\version.cpp" /> - <File RelativePath="..\..\base\version.h" /> + <Filter + Name="base" + > + <File + RelativePath="..\..\base\commandLine.cpp" + > + </File> + <File + RelativePath="..\..\base\commandLine.h" + > + </File> + <File + RelativePath="..\..\base\internal_version.h" + > + </File> + <File + RelativePath="..\..\base\main.cpp" + > + </File> + <File + RelativePath="..\..\base\main.h" + > + </File> + <File + RelativePath="..\..\base\plugins.cpp" + > + </File> + <File + RelativePath="..\..\base\plugins.h" + > + </File> + <File + RelativePath="..\..\base\version.cpp" + > + </File> + <File + RelativePath="..\..\base\version.h" + > + </File> </Filter> - <Filter Name="common"> - <File RelativePath="..\..\common\algorithm.h" /> - <File RelativePath="..\..\common\archive.cpp" /> - <File RelativePath="..\..\common\archive.h" /> - <File RelativePath="..\..\common\array.h" /> - <File RelativePath="..\..\common\config-file.cpp" /> - <File RelativePath="..\..\common\config-file.h" /> - <File RelativePath="..\..\common\config-manager.cpp" /> - <File RelativePath="..\..\common\config-manager.h" /> - <File RelativePath="..\..\common\debug.cpp" /> - <File RelativePath="..\..\common\debug.h" /> - <File RelativePath="..\..\common\endian.h" /> - <File RelativePath="..\..\common\error.h" /> - <File RelativePath="..\..\common\events.h" /> - <File RelativePath="..\..\common\file.cpp" /> - <File RelativePath="..\..\common\file.h" /> - <File RelativePath="..\..\common\frac.h" /> - <File RelativePath="..\..\common\fs.cpp" /> - <File RelativePath="..\..\common\fs.h" /> - <File RelativePath="..\..\common\func.h" /> - <File RelativePath="..\..\common\hash-str.h" /> - <File RelativePath="..\..\common\hashmap.cpp" /> - <File RelativePath="..\..\common\hashmap.h" /> - <File RelativePath="..\..\common\iff_container.h" /> - <File RelativePath="..\..\common\keyboard.h" /> - <File RelativePath="..\..\common\list.h" /> - <File RelativePath="..\..\common\list_intern.h" /> - <File RelativePath="..\..\common\md5.cpp" /> - <File RelativePath="..\..\common\md5.h" /> - <File RelativePath="..\..\common\memorypool.cpp" /> - <File RelativePath="..\..\common\memorypool.h" /> - <File RelativePath="..\..\common\mutex.cpp" /> - <File RelativePath="..\..\common\mutex.h" /> - <File RelativePath="..\..\common\noncopyable.h" /> - <File RelativePath="..\..\common\pack-end.h" /> - <File RelativePath="..\..\common\pack-start.h" /> - <File RelativePath="..\..\common\ptr.h" /> - <File RelativePath="..\..\common\queue.h" /> - <File RelativePath="..\..\common\rect.h" /> - <File RelativePath="..\..\common\savefile.h" /> - <File RelativePath="..\..\common\scummsys.h" /> - <File RelativePath="..\..\common\serializer.h" /> - <File RelativePath="..\..\common\singleton.h" /> - <File RelativePath="..\..\common\stack.h" /> - <File RelativePath="..\..\common\str.cpp" /> - <File RelativePath="..\..\common\str.h" /> - <File RelativePath="..\..\common\stream.cpp" /> - <File RelativePath="..\..\common\stream.h" /> - <File RelativePath="..\..\common\system.cpp" /> - <File RelativePath="..\..\common\system.h" /> - <File RelativePath="..\..\common\timer.h" /> - <File RelativePath="..\..\common\unarj.cpp" /> - <File RelativePath="..\..\common\unarj.h" /> - <File RelativePath="..\..\common\unzip.cpp" /> - <File RelativePath="..\..\common\unzip.h" /> - <File RelativePath="..\..\common\util.cpp" /> - <File RelativePath="..\..\common\util.h" /> - <File RelativePath="..\..\common\xmlparser.cpp" /> - <File RelativePath="..\..\common\xmlparser.h" /> - <File RelativePath="..\..\common\zlib.cpp" /> - <File RelativePath="..\..\common\zlib.h" /> + <Filter + Name="common" + > + <File + RelativePath="..\..\common\algorithm.h" + > + </File> + <File + RelativePath="..\..\common\archive.cpp" + > + </File> + <File + RelativePath="..\..\common\archive.h" + > + </File> + <File + RelativePath="..\..\common\array.h" + > + </File> + <File + RelativePath="..\..\common\config-file.cpp" + > + </File> + <File + RelativePath="..\..\common\config-file.h" + > + </File> + <File + RelativePath="..\..\common\config-manager.cpp" + > + </File> + <File + RelativePath="..\..\common\config-manager.h" + > + </File> + <File + RelativePath="..\..\common\debug.cpp" + > + </File> + <File + RelativePath="..\..\common\debug.h" + > + </File> + <File + RelativePath="..\..\common\endian.h" + > + </File> + <File + RelativePath="..\..\common\error.h" + > + </File> + <File + RelativePath="..\..\common\EventDispatcher.cpp" + > + </File> + <File + RelativePath="..\..\common\EventRecorder.cpp" + > + </File> + <File + RelativePath="..\..\common\EventRecorder.h" + > + </File> + <File + RelativePath="..\..\common\events.h" + > + </File> + <File + RelativePath="..\..\common\file.cpp" + > + </File> + <File + RelativePath="..\..\common\file.h" + > + </File> + <File + RelativePath="..\..\common\frac.h" + > + </File> + <File + RelativePath="..\..\common\fs.cpp" + > + </File> + <File + RelativePath="..\..\common\fs.h" + > + </File> + <File + RelativePath="..\..\common\func.h" + > + </File> + <File + RelativePath="..\..\common\hash-str.h" + > + </File> + <File + RelativePath="..\..\common\hashmap.cpp" + > + </File> + <File + RelativePath="..\..\common\hashmap.h" + > + </File> + <File + RelativePath="..\..\common\iff_container.h" + > + </File> + <File + RelativePath="..\..\common\keyboard.h" + > + </File> + <File + RelativePath="..\..\common\list.h" + > + </File> + <File + RelativePath="..\..\common\list_intern.h" + > + </File> + <File + RelativePath="..\..\common\md5.cpp" + > + </File> + <File + RelativePath="..\..\common\md5.h" + > + </File> + <File + RelativePath="..\..\common\memorypool.cpp" + > + </File> + <File + RelativePath="..\..\common\memorypool.h" + > + </File> + <File + RelativePath="..\..\common\mutex.cpp" + > + </File> + <File + RelativePath="..\..\common\mutex.h" + > + </File> + <File + RelativePath="..\..\common\noncopyable.h" + > + </File> + <File + RelativePath="..\..\common\pack-end.h" + > + </File> + <File + RelativePath="..\..\common\pack-start.h" + > + </File> + <File + RelativePath="..\..\common\ptr.h" + > + </File> + <File + RelativePath="..\..\common\queue.h" + > + </File> + <File + RelativePath="..\..\common\rect.h" + > + </File> + <File + RelativePath="..\..\common\savefile.h" + > + </File> + <File + RelativePath="..\..\common\scummsys.h" + > + </File> + <File + RelativePath="..\..\common\serializer.h" + > + </File> + <File + RelativePath="..\..\common\singleton.h" + > + </File> + <File + RelativePath="..\..\common\stack.h" + > + </File> + <File + RelativePath="..\..\common\str.cpp" + > + </File> + <File + RelativePath="..\..\common\str.h" + > + </File> + <File + RelativePath="..\..\common\stream.cpp" + > + </File> + <File + RelativePath="..\..\common\stream.h" + > + </File> + <File + RelativePath="..\..\common\system.cpp" + > + </File> + <File + RelativePath="..\..\common\system.h" + > + </File> + <File + RelativePath="..\..\common\timer.h" + > + </File> + <File + RelativePath="..\..\common\unarj.cpp" + > + </File> + <File + RelativePath="..\..\common\unarj.h" + > + </File> + <File + RelativePath="..\..\common\unzip.cpp" + > + </File> + <File + RelativePath="..\..\common\unzip.h" + > + </File> + <File + RelativePath="..\..\common\util.cpp" + > + </File> + <File + RelativePath="..\..\common\util.h" + > + </File> + <File + RelativePath="..\..\common\xmlparser.cpp" + > + </File> + <File + RelativePath="..\..\common\xmlparser.h" + > + </File> + <File + RelativePath="..\..\common\zlib.cpp" + > + </File> + <File + RelativePath="..\..\common\zlib.h" + > + </File> </Filter> - <Filter Name="sound"> - <File RelativePath="..\..\sound\adpcm.cpp" /> - <File RelativePath="..\..\sound\adpcm.h" /> - <File RelativePath="..\..\sound\aiff.cpp" /> - <File RelativePath="..\..\sound\aiff.h" /> - <File RelativePath="..\..\sound\audiocd.cpp" /> - <File RelativePath="..\..\sound\audiocd.h" /> - <File RelativePath="..\..\sound\audiostream.cpp" /> - <File RelativePath="..\..\sound\audiostream.h" /> - <File RelativePath="..\..\sound\flac.cpp" /> - <File RelativePath="..\..\sound\flac.h" /> - <File RelativePath="..\..\sound\fmopl.cpp" /> - <File RelativePath="..\..\sound\fmopl.h" /> - <File RelativePath="..\..\sound\iff_sound.cpp" /> - <File RelativePath="..\..\sound\iff_sound.h" /> - <File RelativePath="..\..\sound\mididrv.cpp" /> - <File RelativePath="..\..\sound\mididrv.h" /> - <File RelativePath="..\..\sound\midiparser.cpp" /> - <File RelativePath="..\..\sound\midiparser.h" /> - <File RelativePath="..\..\sound\midiparser_smf.cpp" /> - <File RelativePath="..\..\sound\midiparser_xmidi.cpp" /> - <File RelativePath="..\..\sound\mixer.cpp" /> - <File RelativePath="..\..\sound\mixer.h" /> - <File RelativePath="..\..\sound\mixer_intern.h" /> - <File RelativePath="..\..\sound\mp3.cpp" /> - <File RelativePath="..\..\sound\mp3.h" /> - <File RelativePath="..\..\sound\mpu401.cpp" /> - <File RelativePath="..\..\sound\mpu401.h" /> - <File RelativePath="..\..\sound\musicplugin.cpp" /> - <File RelativePath="..\..\sound\musicplugin.h" /> - <File RelativePath="..\..\sound\null.cpp" /> - <File RelativePath="..\..\sound\rate.cpp" /> - <File RelativePath="..\..\sound\rate.h" /> - <File RelativePath="..\..\sound\shorten.cpp" /> - <File RelativePath="..\..\sound\shorten.h" /> - <File RelativePath="..\..\sound\timestamp.cpp" /> - <File RelativePath="..\..\sound\timestamp.h" /> - <File RelativePath="..\..\sound\vag.cpp" /> - <File RelativePath="..\..\sound\vag.h" /> - <File RelativePath="..\..\sound\voc.cpp" /> - <File RelativePath="..\..\sound\voc.h" /> - <File RelativePath="..\..\sound\vorbis.cpp" /> - <File RelativePath="..\..\sound\vorbis.h" /> - <File RelativePath="..\..\sound\wave.cpp" /> - <File RelativePath="..\..\sound\wave.h" /> - <Filter Name="softhsynth"> - <File RelativePath="..\..\sound\softsynth\adlib.cpp" /> - <File RelativePath="..\..\sound\softsynth\emumidi.h" /> - <File RelativePath="..\..\sound\softsynth\fluidsynth.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32.cpp" /> - <File RelativePath="..\..\sound\softsynth\pcspk.cpp" /> - <File RelativePath="..\..\sound\softsynth\pcspk.h" /> - <File RelativePath="..\..\sound\softsynth\ym2612.cpp" /> - <File RelativePath="..\..\sound\softsynth\ym2612.h" /> - <Filter Name="mt32"> - <File RelativePath="..\..\sound\softsynth\mt32\freeverb.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\freeverb.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\i386.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\i386.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\mt32_file.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\mt32_file.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\mt32emu.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\part.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\part.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\partial.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\partial.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\partialManager.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\partialManager.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\structures.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\synth.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\synth.h" /> - <File RelativePath="..\..\sound\softsynth\mt32\tables.cpp" /> - <File RelativePath="..\..\sound\softsynth\mt32\tables.h" /> + <Filter + Name="sound" + > + <File + RelativePath="..\..\sound\adpcm.cpp" + > + </File> + <File + RelativePath="..\..\sound\adpcm.h" + > + </File> + <File + RelativePath="..\..\sound\aiff.cpp" + > + </File> + <File + RelativePath="..\..\sound\aiff.h" + > + </File> + <File + RelativePath="..\..\sound\audiocd.cpp" + > + </File> + <File + RelativePath="..\..\sound\audiocd.h" + > + </File> + <File + RelativePath="..\..\sound\audiostream.cpp" + > + </File> + <File + RelativePath="..\..\sound\audiostream.h" + > + </File> + <File + RelativePath="..\..\sound\flac.cpp" + > + </File> + <File + RelativePath="..\..\sound\flac.h" + > + </File> + <File + RelativePath="..\..\sound\fmopl.cpp" + > + </File> + <File + RelativePath="..\..\sound\fmopl.h" + > + </File> + <File + RelativePath="..\..\sound\iff_sound.cpp" + > + </File> + <File + RelativePath="..\..\sound\iff_sound.h" + > + </File> + <File + RelativePath="..\..\sound\mididrv.cpp" + > + </File> + <File + RelativePath="..\..\sound\mididrv.h" + > + </File> + <File + RelativePath="..\..\sound\midiparser.cpp" + > + </File> + <File + RelativePath="..\..\sound\midiparser.h" + > + </File> + <File + RelativePath="..\..\sound\midiparser_smf.cpp" + > + </File> + <File + RelativePath="..\..\sound\midiparser_xmidi.cpp" + > + </File> + <File + RelativePath="..\..\sound\mixer.cpp" + > + </File> + <File + RelativePath="..\..\sound\mixer.h" + > + </File> + <File + RelativePath="..\..\sound\mixer_intern.h" + > + </File> + <File + RelativePath="..\..\sound\mp3.cpp" + > + </File> + <File + RelativePath="..\..\sound\mp3.h" + > + </File> + <File + RelativePath="..\..\sound\mpu401.cpp" + > + </File> + <File + RelativePath="..\..\sound\mpu401.h" + > + </File> + <File + RelativePath="..\..\sound\musicplugin.cpp" + > + </File> + <File + RelativePath="..\..\sound\musicplugin.h" + > + </File> + <File + RelativePath="..\..\sound\null.cpp" + > + </File> + <File + RelativePath="..\..\sound\rate.cpp" + > + </File> + <File + RelativePath="..\..\sound\rate.h" + > + </File> + <File + RelativePath="..\..\sound\shorten.cpp" + > + </File> + <File + RelativePath="..\..\sound\shorten.h" + > + </File> + <File + RelativePath="..\..\sound\timestamp.cpp" + > + </File> + <File + RelativePath="..\..\sound\timestamp.h" + > + </File> + <File + RelativePath="..\..\sound\vag.cpp" + > + </File> + <File + RelativePath="..\..\sound\vag.h" + > + </File> + <File + RelativePath="..\..\sound\voc.cpp" + > + </File> + <File + RelativePath="..\..\sound\voc.h" + > + </File> + <File + RelativePath="..\..\sound\vorbis.cpp" + > + </File> + <File + RelativePath="..\..\sound\vorbis.h" + > + </File> + <File + RelativePath="..\..\sound\wave.cpp" + > + </File> + <File + RelativePath="..\..\sound\wave.h" + > + </File> + <Filter + Name="softhsynth" + > + <File + RelativePath="..\..\sound\softsynth\adlib.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\emumidi.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\fluidsynth.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\pcspk.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\pcspk.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\ym2612.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\ym2612.h" + > + </File> + <Filter + Name="mt32" + > + <File + RelativePath="..\..\sound\softsynth\mt32\freeverb.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\freeverb.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\i386.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\i386.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\mt32_file.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\mt32_file.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\mt32emu.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\part.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\part.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partial.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partial.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partialManager.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partialManager.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\structures.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\synth.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\synth.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\tables.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\tables.h" + > + </File> </Filter> - <Filter Name="opl"> - <File RelativePath="..\..\sound\softsynth\opl\dosbox.cpp" /> - <File RelativePath="..\..\sound\softsynth\opl\dosbox.h" /> - <File RelativePath="..\..\sound\softsynth\opl\mame.cpp" /> - <File RelativePath="..\..\sound\softsynth\opl\mame.h" /> - <File RelativePath="..\..\sound\softsynth\opl\opl_impl.h" /> - <File RelativePath="..\..\sound\softsynth\opl\opl_inc.h" /> + <Filter + Name="opl" + > + <File + RelativePath="..\..\sound\softsynth\opl\dosbox.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\dosbox.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\mame.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\mame.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\opl_impl.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\opl_inc.h" + > + </File> </Filter> </Filter> - <Filter Name="mods"> - <File RelativePath="..\..\sound\mods\infogrames.cpp" /> - <File RelativePath="..\..\sound\mods\infogrames.h" /> - <File RelativePath="..\..\sound\mods\module.cpp" /> - <File RelativePath="..\..\sound\mods\module.h" /> - <File RelativePath="..\..\sound\mods\paula.cpp" /> - <File RelativePath="..\..\sound\mods\paula.h" /> - <File RelativePath="..\..\sound\mods\protracker.cpp" /> - <File RelativePath="..\..\sound\mods\protracker.h" /> - <File RelativePath="..\..\sound\mods\rjp1.cpp" /> - <File RelativePath="..\..\sound\mods\rjp1.h" /> - <File RelativePath="..\..\sound\mods\soundfx.cpp" /> - <File RelativePath="..\..\sound\mods\soundfx.h" /> + <Filter + Name="mods" + > + <File + RelativePath="..\..\sound\mods\infogrames.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\infogrames.h" + > + </File> + <File + RelativePath="..\..\sound\mods\module.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\module.h" + > + </File> + <File + RelativePath="..\..\sound\mods\paula.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\paula.h" + > + </File> + <File + RelativePath="..\..\sound\mods\protracker.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\protracker.h" + > + </File> + <File + RelativePath="..\..\sound\mods\rjp1.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\rjp1.h" + > + </File> + <File + RelativePath="..\..\sound\mods\soundfx.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\soundfx.h" + > + </File> </Filter> </Filter> - <Filter Name="txt"> - <File RelativePath="..\..\COPYING" /> - <File RelativePath="..\..\NEWS" /> - <File RelativePath="..\..\README" /> - <File RelativePath="..\..\TODO" /> + <Filter + Name="txt" + > + <File + RelativePath="..\..\COPYING" + > + </File> + <File + RelativePath="..\..\NEWS" + > + </File> + <File + RelativePath="..\..\README" + > + </File> + <File + RelativePath="..\..\TODO" + > + </File> </Filter> - <Filter Name="rsc"> - <File RelativePath="..\..\icons\scummvm.ico" /> - <File RelativePath="..\..\dists\scummvm.rc" /> + <Filter + Name="rsc" + > + <File + RelativePath="..\..\icons\scummvm.ico" + > + </File> + <File + RelativePath="..\..\dists\scummvm.rc" + > + </File> </Filter> - <Filter Name="backends"> - <File RelativePath="..\..\backends\base-backend.cpp" /> - <File RelativePath="..\..\backends\base-backend.h" /> - <Filter Name="sdl"> - <File RelativePath="..\..\backends\platform\sdl\events.cpp" /> - <File RelativePath="..\..\backends\platform\sdl\graphics.cpp" /> - <File RelativePath="..\..\backends\platform\sdl\hardwarekeys.cpp" /> + <Filter + Name="backends" + > + <File + RelativePath="..\..\backends\base-backend.cpp" + > + </File> + <File + RelativePath="..\..\backends\base-backend.h" + > + </File> + <Filter + Name="sdl" + > + <File + RelativePath="..\..\backends\platform\sdl\events.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\graphics.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\hardwarekeys.cpp" + > + </File> <File RelativePath="..\..\backends\platform\sdl\main.cpp" > @@ -234,152 +886,542 @@ /> </FileConfiguration> </File> - <File RelativePath="..\..\backends\platform\sdl\sdl.cpp" /> - <File RelativePath="..\..\backends\platform\sdl\sdl.h" /> + <File + RelativePath="..\..\backends\platform\sdl\sdl.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\sdl.h" + > + </File> </Filter> - <Filter Name="fs"> - <File RelativePath="..\..\backends\fs\abstract-fs.cpp" /> - <File RelativePath="..\..\backends\fs\abstract-fs.h" /> - <File RelativePath="..\..\backends\fs\fs-factory.h" /> - <File RelativePath="..\..\backends\fs\stdiostream.cpp" /> - <File RelativePath="..\..\backends\fs\stdiostream.h" /> - <Filter Name="windows"> - <File RelativePath="..\..\backends\fs\windows\windows-fs-factory.cpp" /> - <File RelativePath="..\..\backends\fs\windows\windows-fs-factory.h" /> + <Filter + Name="fs" + > + <File + RelativePath="..\..\backends\fs\abstract-fs.cpp" + > + </File> + <File + RelativePath="..\..\backends\fs\abstract-fs.h" + > + </File> + <File + RelativePath="..\..\backends\fs\fs-factory.h" + > + </File> + <File + RelativePath="..\..\backends\fs\stdiostream.cpp" + > + </File> + <File + RelativePath="..\..\backends\fs\stdiostream.h" + > + </File> + <Filter + Name="windows" + > + <File + RelativePath="..\..\backends\fs\windows\windows-fs-factory.cpp" + > + </File> + <File + RelativePath="..\..\backends\fs\windows\windows-fs-factory.h" + > + </File> </Filter> </Filter> - <Filter Name="midi"> - <File RelativePath="..\..\backends\midi\windows.cpp" /> + <Filter + Name="midi" + > + <File + RelativePath="..\..\backends\midi\windows.cpp" + > + </File> </Filter> - <Filter Name="timer"> - <File RelativePath="..\..\backends\timer\default\default-timer.cpp" /> - <File RelativePath="..\..\backends\timer\default\default-timer.h" /> + <Filter + Name="timer" + > + <File + RelativePath="..\..\backends\timer\default\default-timer.cpp" + > + </File> + <File + RelativePath="..\..\backends\timer\default\default-timer.h" + > + </File> </Filter> - <Filter Name="saves"> - <File RelativePath="..\..\backends\saves\default\default-saves.cpp" /> - <File RelativePath="..\..\backends\saves\default\default-saves.h" /> - <File RelativePath="..\..\backends\saves\savefile.cpp" /> + <Filter + Name="saves" + > + <File + RelativePath="..\..\backends\saves\default\default-saves.cpp" + > + </File> + <File + RelativePath="..\..\backends\saves\default\default-saves.h" + > + </File> + <File + RelativePath="..\..\backends\saves\savefile.cpp" + > + </File> </Filter> - <Filter Name="events"> - <Filter Name="default"> - <File RelativePath="..\..\backends\events\default\default-events.cpp" /> - <File RelativePath="..\..\backends\events\default\default-events.h" /> + <Filter + Name="events" + > + <Filter + Name="default" + > + <File + RelativePath="..\..\backends\events\default\default-events.cpp" + > + </File> + <File + RelativePath="..\..\backends\events\default\default-events.h" + > + </File> </Filter> </Filter> - <Filter Name="keymapper"> - <File RelativePath="..\..\backends\keymapper\action.cpp" /> - <File RelativePath="..\..\backends\keymapper\action.h" /> - <File RelativePath="..\..\backends\keymapper\hardware-key.h" /> - <File RelativePath="..\..\backends\keymapper\keymap.cpp" /> - <File RelativePath="..\..\backends\keymapper\keymap.h" /> - <File RelativePath="..\..\backends\keymapper\keymapper.cpp" /> - <File RelativePath="..\..\backends\keymapper\keymapper.h" /> - <File RelativePath="..\..\backends\keymapper\remap-dialog.cpp" /> - <File RelativePath="..\..\backends\keymapper\remap-dialog.h" /> - <File RelativePath="..\..\backends\keymapper\types.h" /> + <Filter + Name="keymapper" + > + <File + RelativePath="..\..\backends\keymapper\action.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\action.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\hardware-key.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymap.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymap.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymapper.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymapper.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\remap-dialog.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\remap-dialog.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\types.h" + > + </File> </Filter> - <Filter Name="vkeybd"> - <File RelativePath="..\..\backends\vkeybd\image-map.cpp" /> - <File RelativePath="..\..\backends\vkeybd\image-map.h" /> - <File RelativePath="..\..\backends\vkeybd\keycode-descriptions.h" /> - <File RelativePath="..\..\backends\vkeybd\polygon.cpp" /> - <File RelativePath="..\..\backends\vkeybd\polygon.h" /> - <File RelativePath="..\..\backends\vkeybd\virtual-keyboard-gui.cpp" /> - <File RelativePath="..\..\backends\vkeybd\virtual-keyboard-gui.h" /> - <File RelativePath="..\..\backends\vkeybd\virtual-keyboard-parser.cpp" /> - <File RelativePath="..\..\backends\vkeybd\virtual-keyboard-parser.h" /> - <File RelativePath="..\..\backends\vkeybd\virtual-keyboard.cpp" /> - <File RelativePath="..\..\backends\vkeybd\virtual-keyboard.h" /> + <Filter + Name="vkeybd" + > + <File + RelativePath="..\..\backends\vkeybd\image-map.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\image-map.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\keycode-descriptions.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\polygon.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\polygon.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-gui.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-gui.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-parser.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-parser.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard.h" + > + </File> </Filter> </Filter> - <Filter Name="gui"> - <File RelativePath="..\..\gui\about.cpp" /> - <File RelativePath="..\..\gui\about.h" /> - <File RelativePath="..\..\gui\browser.cpp" /> - <File RelativePath="..\..\gui\browser.h" /> - <File RelativePath="..\..\gui\chooser.cpp" /> - <File RelativePath="..\..\gui\chooser.h" /> - <File RelativePath="..\..\gui\console.cpp" /> - <File RelativePath="..\..\gui\console.h" /> - <File RelativePath="..\..\gui\credits.h" /> - <File RelativePath="..\..\gui\debugger.cpp" /> - <File RelativePath="..\..\gui\debugger.h" /> - <File RelativePath="..\..\gui\dialog.cpp" /> - <File RelativePath="..\..\gui\dialog.h" /> - <File RelativePath="..\..\gui\editable.cpp" /> - <File RelativePath="..\..\gui\editable.h" /> - <File RelativePath="..\..\gui\EditTextWidget.cpp" /> - <File RelativePath="..\..\gui\EditTextWidget.h" /> - <File RelativePath="..\..\gui\GuiManager.cpp" /> - <File RelativePath="..\..\gui\GuiManager.h" /> - <File RelativePath="..\..\gui\Key.cpp" /> - <File RelativePath="..\..\gui\Key.h" /> - <File RelativePath="..\..\gui\launcher.cpp" /> - <File RelativePath="..\..\gui\launcher.h" /> - <File RelativePath="..\..\gui\ListWidget.cpp" /> - <File RelativePath="..\..\gui\ListWidget.h" /> - <File RelativePath="..\..\gui\massadd.cpp" /> - <File RelativePath="..\..\gui\massadd.h" /> - <File RelativePath="..\..\gui\message.cpp" /> - <File RelativePath="..\..\gui\message.h" /> - <File RelativePath="..\..\gui\object.cpp" /> - <File RelativePath="..\..\gui\object.h" /> - <File RelativePath="..\..\gui\options.cpp" /> - <File RelativePath="..\..\gui\options.h" /> - <File RelativePath="..\..\gui\PopUpWidget.cpp" /> - <File RelativePath="..\..\gui\PopUpWidget.h" /> - <File RelativePath="..\..\gui\saveload.cpp" /> - <File RelativePath="..\..\gui\saveload.h" /> - <File RelativePath="..\..\gui\ScrollBarWidget.cpp" /> - <File RelativePath="..\..\gui\ScrollBarWidget.h" /> - <File RelativePath="..\..\gui\TabWidget.cpp" /> - <File RelativePath="..\..\gui\TabWidget.h" /> - <File RelativePath="..\..\gui\themebrowser.cpp" /> - <File RelativePath="..\..\gui\themebrowser.h" /> - <File RelativePath="..\..\gui\ThemeEngine.cpp" /> - <File RelativePath="..\..\gui\ThemeEngine.h" /> - <File RelativePath="..\..\gui\ThemeEval.cpp" /> - <File RelativePath="..\..\gui\ThemeLayout.cpp" /> - <File RelativePath="..\..\gui\ThemeLayout.h" /> - <File RelativePath="..\..\gui\ThemeParser.cpp" /> - <File RelativePath="..\..\gui\ThemeParser.h" /> - <File RelativePath="..\..\gui\widget.cpp" /> - <File RelativePath="..\..\gui\widget.h" /> + <Filter + Name="gui" + > + <File + RelativePath="..\..\gui\about.cpp" + > + </File> + <File + RelativePath="..\..\gui\about.h" + > + </File> + <File + RelativePath="..\..\gui\browser.cpp" + > + </File> + <File + RelativePath="..\..\gui\browser.h" + > + </File> + <File + RelativePath="..\..\gui\chooser.cpp" + > + </File> + <File + RelativePath="..\..\gui\chooser.h" + > + </File> + <File + RelativePath="..\..\gui\console.cpp" + > + </File> + <File + RelativePath="..\..\gui\console.h" + > + </File> + <File + RelativePath="..\..\gui\credits.h" + > + </File> + <File + RelativePath="..\..\gui\debugger.cpp" + > + </File> + <File + RelativePath="..\..\gui\debugger.h" + > + </File> + <File + RelativePath="..\..\gui\dialog.cpp" + > + </File> + <File + RelativePath="..\..\gui\dialog.h" + > + </File> + <File + RelativePath="..\..\gui\editable.cpp" + > + </File> + <File + RelativePath="..\..\gui\editable.h" + > + </File> + <File + RelativePath="..\..\gui\EditTextWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\EditTextWidget.h" + > + </File> + <File + RelativePath="..\..\gui\GuiManager.cpp" + > + </File> + <File + RelativePath="..\..\gui\GuiManager.h" + > + </File> + <File + RelativePath="..\..\gui\Key.cpp" + > + </File> + <File + RelativePath="..\..\gui\Key.h" + > + </File> + <File + RelativePath="..\..\gui\launcher.cpp" + > + </File> + <File + RelativePath="..\..\gui\launcher.h" + > + </File> + <File + RelativePath="..\..\gui\ListWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\ListWidget.h" + > + </File> + <File + RelativePath="..\..\gui\massadd.cpp" + > + </File> + <File + RelativePath="..\..\gui\massadd.h" + > + </File> + <File + RelativePath="..\..\gui\message.cpp" + > + </File> + <File + RelativePath="..\..\gui\message.h" + > + </File> + <File + RelativePath="..\..\gui\object.cpp" + > + </File> + <File + RelativePath="..\..\gui\object.h" + > + </File> + <File + RelativePath="..\..\gui\options.cpp" + > + </File> + <File + RelativePath="..\..\gui\options.h" + > + </File> + <File + RelativePath="..\..\gui\PopUpWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\PopUpWidget.h" + > + </File> + <File + RelativePath="..\..\gui\saveload.cpp" + > + </File> + <File + RelativePath="..\..\gui\saveload.h" + > + </File> + <File + RelativePath="..\..\gui\ScrollBarWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\ScrollBarWidget.h" + > + </File> + <File + RelativePath="..\..\gui\TabWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\TabWidget.h" + > + </File> + <File + RelativePath="..\..\gui\themebrowser.cpp" + > + </File> + <File + RelativePath="..\..\gui\themebrowser.h" + > + </File> + <File + RelativePath="..\..\gui\ThemeEngine.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeEngine.h" + > + </File> + <File + RelativePath="..\..\gui\ThemeEval.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeLayout.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeLayout.h" + > + </File> + <File + RelativePath="..\..\gui\ThemeParser.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeParser.h" + > + </File> + <File + RelativePath="..\..\gui\widget.cpp" + > + </File> + <File + RelativePath="..\..\gui\widget.h" + > + </File> </Filter> - <Filter Name="graphics"> - <File RelativePath="..\..\graphics\colormasks.h" /> - <File RelativePath="..\..\graphics\cursorman.cpp" /> - <File RelativePath="..\..\graphics\cursorman.h" /> - <File RelativePath="..\..\graphics\dither.cpp" /> - <File RelativePath="..\..\graphics\dither.h" /> - <File RelativePath="..\..\graphics\font.cpp" /> - <File RelativePath="..\..\graphics\font.h" /> - <File RelativePath="..\..\graphics\fontman.cpp" /> - <File RelativePath="..\..\graphics\fontman.h" /> - <File RelativePath="..\..\graphics\iff.cpp" /> - <File RelativePath="..\..\graphics\iff.h" /> - <File RelativePath="..\..\graphics\imagedec.cpp" /> - <File RelativePath="..\..\graphics\imagedec.h" /> - <File RelativePath="..\..\graphics\pixelformat.h" /> - <File RelativePath="..\..\graphics\primitives.cpp" /> - <File RelativePath="..\..\graphics\primitives.h" /> - <File RelativePath="..\..\graphics\scaler.cpp" /> - <File RelativePath="..\..\graphics\scaler.h" /> - <File RelativePath="..\..\graphics\sjis.cpp" /> - <File RelativePath="..\..\graphics\sjis.h" /> - <File RelativePath="..\..\graphics\surface.cpp" /> - <File RelativePath="..\..\graphics\surface.h" /> - <File RelativePath="..\..\graphics\thumbnail.cpp" /> - <File RelativePath="..\..\graphics\thumbnail.h" /> - <File RelativePath="..\..\graphics\VectorRenderer.cpp" /> - <File RelativePath="..\..\graphics\VectorRenderer.h" /> - <File RelativePath="..\..\graphics\VectorRendererSpec.cpp" /> - <File RelativePath="..\..\graphics\VectorRendererSpec.h" /> - <Filter Name="scaler"> - <File RelativePath="..\..\graphics\scaler\2xsai.cpp" /> - <File RelativePath="..\..\graphics\scaler\aspect.cpp" /> - <File RelativePath="..\..\graphics\scaler\hq2x.cpp" /> - <File RelativePath="..\..\graphics\scaler\hq2x.h" /> + <Filter + Name="graphics" + > + <File + RelativePath="..\..\graphics\colormasks.h" + > + </File> + <File + RelativePath="..\..\graphics\cursorman.cpp" + > + </File> + <File + RelativePath="..\..\graphics\cursorman.h" + > + </File> + <File + RelativePath="..\..\graphics\dither.cpp" + > + </File> + <File + RelativePath="..\..\graphics\dither.h" + > + </File> + <File + RelativePath="..\..\graphics\font.cpp" + > + </File> + <File + RelativePath="..\..\graphics\font.h" + > + </File> + <File + RelativePath="..\..\graphics\fontman.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fontman.h" + > + </File> + <File + RelativePath="..\..\graphics\iff.cpp" + > + </File> + <File + RelativePath="..\..\graphics\iff.h" + > + </File> + <File + RelativePath="..\..\graphics\imagedec.cpp" + > + </File> + <File + RelativePath="..\..\graphics\imagedec.h" + > + </File> + <File + RelativePath="..\..\graphics\pixelformat.h" + > + </File> + <File + RelativePath="..\..\graphics\primitives.cpp" + > + </File> + <File + RelativePath="..\..\graphics\primitives.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler.h" + > + </File> + <File + RelativePath="..\..\graphics\sjis.cpp" + > + </File> + <File + RelativePath="..\..\graphics\sjis.h" + > + </File> + <File + RelativePath="..\..\graphics\surface.cpp" + > + </File> + <File + RelativePath="..\..\graphics\surface.h" + > + </File> + <File + RelativePath="..\..\graphics\thumbnail.cpp" + > + </File> + <File + RelativePath="..\..\graphics\thumbnail.h" + > + </File> + <File + RelativePath="..\..\graphics\VectorRenderer.cpp" + > + </File> + <File + RelativePath="..\..\graphics\VectorRenderer.h" + > + </File> + <File + RelativePath="..\..\graphics\VectorRendererSpec.cpp" + > + </File> + <File + RelativePath="..\..\graphics\VectorRendererSpec.h" + > + </File> + <Filter + Name="scaler" + > + <File + RelativePath="..\..\graphics\scaler\2xsai.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\aspect.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq2x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq2x.h" + > + </File> <File RelativePath="..\..\graphics\scaler\hq2x_i386.asm" > @@ -402,8 +1444,14 @@ /> </FileConfiguration> </File> - <File RelativePath="..\..\graphics\scaler\hq3x.cpp" /> - <File RelativePath="..\..\graphics\scaler\hq3x.h" /> + <File + RelativePath="..\..\graphics\scaler\hq3x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq3x.h" + > + </File> <File RelativePath="..\..\graphics\scaler\hq3x_i386.asm" > @@ -426,51 +1474,169 @@ /> </FileConfiguration> </File> - <File RelativePath="..\..\graphics\scaler\intern.h" /> - <File RelativePath="..\..\graphics\scaler\scale2x.cpp" /> - <File RelativePath="..\..\graphics\scaler\scale2x.h" /> - <File RelativePath="..\..\graphics\scaler\scale3x.cpp" /> - <File RelativePath="..\..\graphics\scaler\scale3x.h" /> - <File RelativePath="..\..\graphics\scaler\scalebit.cpp" /> - <File RelativePath="..\..\graphics\scaler\scalebit.h" /> - <File RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp" /> + <File + RelativePath="..\..\graphics\scaler\intern.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale2x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale2x.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale3x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale3x.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scalebit.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scalebit.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp" + > + </File> </Filter> - <Filter Name="fonts"> - <File RelativePath="..\..\graphics\fonts\consolefont.cpp" /> - <File RelativePath="..\..\graphics\fonts\newfont.cpp" /> - <File RelativePath="..\..\graphics\fonts\newfont_big.cpp" /> - <File RelativePath="..\..\graphics\fonts\scummfont.cpp" /> + <Filter + Name="fonts" + > + <File + RelativePath="..\..\graphics\fonts\consolefont.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fonts\newfont.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fonts\newfont_big.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fonts\scummfont.cpp" + > + </File> </Filter> - <Filter Name="video"> - <File RelativePath="..\..\graphics\video\dxa_decoder.cpp" /> - <File RelativePath="..\..\graphics\video\dxa_decoder.h" /> - <File RelativePath="..\..\graphics\video\flic_decoder.cpp" /> - <File RelativePath="..\..\graphics\video\flic_decoder.h" /> - <File RelativePath="..\..\graphics\video\mpeg_player.cpp" /> - <File RelativePath="..\..\graphics\video\mpeg_player.h" /> - <File RelativePath="..\..\graphics\video\smk_decoder.cpp" /> - <File RelativePath="..\..\graphics\video\smk_decoder.h" /> - <File RelativePath="..\..\graphics\video\video_player.cpp" /> - <File RelativePath="..\..\graphics\video\video_player.h" /> - <Filter Name="coktelvideo"> - <File RelativePath="..\..\graphics\video\coktelvideo\coktelvideo.cpp" /> - <File RelativePath="..\..\graphics\video\coktelvideo\coktelvideo.h" /> - <File RelativePath="..\..\graphics\video\coktelvideo\indeo3.cpp" /> - <File RelativePath="..\..\graphics\video\coktelvideo\indeo3.h" /> - <File RelativePath="..\..\graphics\video\coktelvideo\indeo3data.h" /> + <Filter + Name="video" + > + <File + RelativePath="..\..\graphics\video\dxa_decoder.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\dxa_decoder.h" + > + </File> + <File + RelativePath="..\..\graphics\video\flic_decoder.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\flic_decoder.h" + > + </File> + <File + RelativePath="..\..\graphics\video\mpeg_player.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\mpeg_player.h" + > + </File> + <File + RelativePath="..\..\graphics\video\smk_decoder.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\smk_decoder.h" + > + </File> + <File + RelativePath="..\..\graphics\video\video_player.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\video_player.h" + > + </File> + <Filter + Name="coktelvideo" + > + <File + RelativePath="..\..\graphics\video\coktelvideo\coktelvideo.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\coktelvideo.h" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\indeo3.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\indeo3.h" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\indeo3data.h" + > + </File> </Filter> </Filter> </Filter> - <Filter Name="engines"> - <File RelativePath="..\..\engines\advancedDetector.cpp" /> - <File RelativePath="..\..\engines\advancedDetector.h" /> - <File RelativePath="..\..\engines\dialogs.cpp" /> - <File RelativePath="..\..\engines\dialogs.h" /> - <File RelativePath="..\..\engines\engine.cpp" /> - <File RelativePath="..\..\engines\engine.h" /> - <File RelativePath="..\..\engines\game.cpp" /> - <File RelativePath="..\..\engines\game.h" /> - <File RelativePath="..\..\engines\metaengine.h" /> + <Filter + Name="engines" + > + <File + RelativePath="..\..\engines\advancedDetector.cpp" + > + </File> + <File + RelativePath="..\..\engines\advancedDetector.h" + > + </File> + <File + RelativePath="..\..\engines\dialogs.cpp" + > + </File> + <File + RelativePath="..\..\engines\dialogs.h" + > + </File> + <File + RelativePath="..\..\engines\engine.cpp" + > + </File> + <File + RelativePath="..\..\engines\engine.h" + > + </File> + <File + RelativePath="..\..\engines\game.cpp" + > + </File> + <File + RelativePath="..\..\engines\game.h" + > + </File> + <File + RelativePath="..\..\engines\metaengine.h" + > + </File> </Filter> </Files> + <Globals> + </Globals> </VisualStudioProject> diff --git a/dists/redhat/scummvm.spec b/dists/redhat/scummvm.spec index 9981940678..2a4383c17b 100644 --- a/dists/redhat/scummvm.spec +++ b/dists/redhat/scummvm.spec @@ -7,7 +7,7 @@ # Prologue information #------------------------------------------------------------------------------ Name : scummvm -Version : 1.0.0svn +Version : 1.1.0svn Release : 1 Summary : Graphic adventure game interpreter Group : Interpreters diff --git a/dists/scummvm.rc b/dists/scummvm.rc index 2b794fdded..31e4b8bacb 100644 --- a/dists/scummvm.rc +++ b/dists/scummvm.rc @@ -7,8 +7,8 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico" #endif VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 + FILEVERSION 1,1,0,0 + PRODUCTVERSION 1,1,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", "1.0.0svn\0" + VALUE "FileVersion", "1.1.0svn\0" VALUE "InternalName", "scummvm\0" VALUE "LegalCopyright", "Copyright © 2001-2009 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", "1.0.0svn\0" + VALUE "ProductVersion", "1.1.0svn\0" END END BLOCK "VarFileInfo" diff --git a/dists/slackware/scummvm.SlackBuild b/dists/slackware/scummvm.SlackBuild index 095581bf52..4ca5a7c662 100755 --- a/dists/slackware/scummvm.SlackBuild +++ b/dists/slackware/scummvm.SlackBuild @@ -8,7 +8,7 @@ if [ "$TMP" = "" ]; then fi PKG=$TMP/package-scummvm -VERSION=1.0.0svn +VERSION=1.1.0svn ARCH=i486 BUILD=1 diff --git a/dists/wii/READMII b/dists/wii/READMII index b9460a9863..32f97b5425 100644 --- a/dists/wii/READMII +++ b/dists/wii/READMII @@ -44,10 +44,9 @@ CONTROLS plus: "." (skip current line of text) 2: enter home: f5 (scummvm menu) - dpad up: shift (mass add for the gui) - dpad down: "0" - dpad left: "y" - dpad right: "n" + dpad up: shift (mass add for the gui, combined with home: GMM) + dpad down: virtual keyboard + dpad right: predictive dialog (only in AGI games) gamecube pad @@ -58,10 +57,9 @@ CONTROLS y: "." (skip current line of text) z: enter start: f5 (scummvm menu) - dpad up: shift (mass add for the gui) - dpad down: "0" - dpad left: "y" - dpad right: "n" + dpad up: shift (mass add for the gui, combined with start: GMM) + dpad down: virtual keyboard + dpad right: predictive dialog (only in AGI games) DISPLAY SETUP diff --git a/dists/wii/meta.xml b/dists/wii/meta.xml index a0cb6838fc..99d96e7f01 100644 --- a/dists/wii/meta.xml +++ b/dists/wii/meta.xml @@ -2,7 +2,7 @@ <app version="1"> <name>ScummVM</name> <coder>The ScummVM Team</coder> - <version>1.0.0svn@REVISION@</version> + <version>1.1.0svn@REVISION@</version> <release_date>@TIMESTAMP@</release_date> <short_description>Point & Click Adventures</short_description> <long_description>ScummVM is a program which allows you to run certain classic graphical point-and-click adventure games, provided you already have their data files. The clever part about this: ScummVM just replaces the executables shipped with the games, allowing you to play them on systems for which they were never designed! diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index e373dd3e6d..69b27e10f9 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -25,6 +25,7 @@ #include "common/md5.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -271,19 +272,6 @@ void AgiEngine::processEvents() { } } -void AgiEngine::checkQuickLoad() { - if (ConfMan.hasKey("save_slot")) { - char saveNameBuffer[256]; - - snprintf (saveNameBuffer, 256, "%s.%03d", _targetName.c_str(), ConfMan.getInt("save_slot")); - - if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id - _game.exitAllLogics = 1; - _menu->enableAll(); - } - } -} - void AgiEngine::pollTimer(void) { static uint32 m = 0; uint32 dm; @@ -301,40 +289,10 @@ void AgiEngine::pollTimer(void) { m = g_tickTimer; } -bool AgiEngine::isKeypress(void) { - processEvents(); - return _keyQueueStart != _keyQueueEnd; -} - -int AgiEngine::getKeypress(void) { - int k; - - while (_keyQueueStart == _keyQueueEnd) // block - pollTimer(); - - keyDequeue(k); - - return k; -} - -void AgiEngine::clearKeyQueue(void) { - while (isKeypress()) { - getKeypress(); - } -} - void AgiEngine::agiTimerFunctionLow(void *refCon) { g_tickTimer++; } -void AgiEngine::clearImageStack(void) { - _imageStack.clear(); -} - -void AgiEngine::releaseImageStack(void) { - _imageStack.clear(); -} - void AgiEngine::pause(uint32 msec) { uint32 endTime = _system->getMillis() + msec; @@ -348,38 +306,6 @@ void AgiEngine::pause(uint32 msec) { _gfx->setCursor(_renderMode == Common::kRenderAmiga); } -void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, - int16 p4, int16 p5, int16 p6, int16 p7) { - ImageStackElement pnew; - - pnew.type = type; - pnew.pad = 0; - pnew.parm1 = p1; - pnew.parm2 = p2; - pnew.parm3 = p3; - pnew.parm4 = p4; - pnew.parm5 = p5; - pnew.parm6 = p6; - pnew.parm7 = p7; - - _imageStack.push(pnew); -} - -void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, - int16 p4, int16 p5, int16 p6, int16 p7) { - switch (type) { - case ADD_PIC: - debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1); - agiLoadResource(rPICTURE, p1); - _picture->decodePicture(p1, p2, p3 != 0); - break; - case ADD_VIEW: - agiLoadResource(rVIEW, p1); - _sprites->addToPic(p1, p2, p3, p4, p5, p6, p7); - break; - } -} - void AgiEngine::initPriTable() { int i, p, y = 0; @@ -489,11 +415,6 @@ int AgiEngine::agiInit() { _game.mouseFence.setWidth(0); // Reset - _game.lastController = 0; - for (i = 0; i < MAX_DIRS; i++) - _game.controllerOccured[i] = false; - - return ec; } @@ -530,21 +451,6 @@ int AgiEngine::agiDeinit() { return ec; } -int AgiEngine::agiDetectGame() { - int ec = errOK; - - assert(_gameDescription != NULL); - - if (getVersion() <= 0x2999) { - _loader = new AgiLoader_v2(this); - } else { - _loader = new AgiLoader_v3(this); - } - ec = _loader->detectGame(); - - return ec; -} - int AgiEngine::agiLoadResource(int r, int n) { int i; @@ -587,67 +493,6 @@ static const GameSettings agiSettings[] = { {NULL, NULL, 0, 0, NULL} }; -AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const { - if (_amigaStyle) { - if (positive) { - if (pressed) { // Positive pressed Amiga-style button - if (_olderAgi) { - return AgiTextColor(amigaBlack, amigaOrange); - } else { - return AgiTextColor(amigaBlack, amigaPurple); - } - } else { // Positive unpressed Amiga-style button - return AgiTextColor(amigaWhite, amigaGreen); - } - } else { // _amigaStyle && !positive - if (pressed) { // Negative pressed Amiga-style button - return AgiTextColor(amigaBlack, amigaCyan); - } else { // Negative unpressed Amiga-style button - return AgiTextColor(amigaWhite, amigaRed); - } - } - } else { // PC-style button - if (hasFocus || pressed) { // A pressed or in focus PC-style button - return AgiTextColor(pcWhite, pcBlack); - } else { // An unpressed PC-style button without focus - return AgiTextColor(pcBlack, pcWhite); - } - } -} - -AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const { - return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor)); -} - -AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const { - if (hasFocus || pressed) - return baseColor.swap(); - else - return baseColor; -} - -int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const { - return (pressed && !_amigaStyle) ? 1 : 0; -} - -bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const { - return _amigaStyle && !_authenticAmiga && (hasFocus || pressed); -} - -void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) { - _amigaStyle = amigaStyle; - _olderAgi = olderAgi; - _authenticAmiga = authenticAmiga; -} - -void AgiButtonStyle::setPcStyle(bool pcStyle) { - setAmigaStyle(!pcStyle); -} - -AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) { - setAmigaStyle(renderMode == Common::kRenderAmiga); -} - AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { _noSaveLoadAllowed = false; @@ -671,7 +516,7 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas parseFeatures(); _rnd = new Common::RandomSource(); - syst->getEventManager()->registerRandomSource(*_rnd, "agi"); + g_eventRec.registerRandomSource(*_rnd, "agi"); Common::addDebugChannel(kDebugLevelMain, "Main", "Generic debug level"); Common::addDebugChannel(kDebugLevelResources, "Resources", "Resources debugging"); @@ -718,6 +563,12 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas _predictiveDictLine = NULL; _predictiveDictLineCount = 0; _firstSlot = 0; + + // NOTE: On game reload the keys do not get set again, + // thus it is incorrect to reset it in agiInit(). Fixes bug #2823762 + _game.lastController = 0; + for (int i = 0; i < MAX_DIRS; i++) + _game.controllerOccured[i] = false; } void AgiEngine::initialize() { diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 14e1fd448b..ab572b0dd0 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -760,8 +760,6 @@ public: void initVersion(void); void setVersion(uint16 version); - Common::Error loadGameState(int slot); - Common::Error saveGameState(int slot, const char *desc); bool canLoadGameStateCurrently(); bool canSaveGameStateCurrently(); }; @@ -785,6 +783,8 @@ public: return _gameId; } + Common::Error loadGameState(int slot); + Common::Error saveGameState(int slot, const char *desc); private: diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index bf4622bc08..d212f8c2e0 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -328,7 +328,7 @@ int AgiEngine::playGame() { _game.vars[vKey] = 0; debugC(2, kDebugLevelMain, "Entering main loop"); - bool firstLoop = true; + bool firstLoop = !getflag(fRestartGame); // Do not restore on game restart do { diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 910f6e0e55..553e42f88e 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -1290,20 +1290,6 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const Common::FSList &fsl namespace Agi { -Common::Error AgiBase::loadGameState(int slot) { - static char saveLoadSlot[12]; - sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); - loadGame(saveLoadSlot); - return Common::kNoError; // TODO: return success/failure -} - -Common::Error AgiBase::saveGameState(int slot, const char *desc) { - static char saveLoadSlot[12]; - sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); - saveGame(saveLoadSlot, desc); - return Common::kNoError; // TODO: return success/failure -} - bool AgiBase::canLoadGameStateCurrently() { return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed); } @@ -1312,4 +1298,19 @@ bool AgiBase::canSaveGameStateCurrently() { return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed && _game.inputEnabled); } +int AgiEngine::agiDetectGame() { + int ec = errOK; + + assert(_gameDescription != NULL); + + if (getVersion() <= 0x2999) { + _loader = new AgiLoader_v2(this); + } else { + _loader = new AgiLoader_v3(this); + } + ec = _loader->detectGame(); + + return ec; +} + } // End of namespace Agi diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index 6604587051..b47a39e592 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -393,6 +393,11 @@ int AgiEngine::waitKey() { _gfx->doUpdate(); } + + // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() + // Fixes bug #2823759 + _game.keypress = 0; + return key; } @@ -409,7 +414,33 @@ int AgiEngine::waitAnyKey() { break; _gfx->doUpdate(); } + + // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() + _game.keypress = 0; + return key; } +bool AgiEngine::isKeypress(void) { + processEvents(); + return _keyQueueStart != _keyQueueEnd; +} + +int AgiEngine::getKeypress(void) { + int k; + + while (_keyQueueStart == _keyQueueEnd) // block + pollTimer(); + + keyDequeue(k); + + return k; +} + +void AgiEngine::clearKeyQueue(void) { + while (isKeypress()) { + getKeypress(); + } +} + } // End of namespace Agi diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp index 27e234ebc9..5d30eda81d 100644 --- a/engines/agi/menu.cpp +++ b/engines/agi/menu.cpp @@ -493,4 +493,66 @@ void Menu::enableAll() { } } + +AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const { + if (_amigaStyle) { + if (positive) { + if (pressed) { // Positive pressed Amiga-style button + if (_olderAgi) { + return AgiTextColor(amigaBlack, amigaOrange); + } else { + return AgiTextColor(amigaBlack, amigaPurple); + } + } else { // Positive unpressed Amiga-style button + return AgiTextColor(amigaWhite, amigaGreen); + } + } else { // _amigaStyle && !positive + if (pressed) { // Negative pressed Amiga-style button + return AgiTextColor(amigaBlack, amigaCyan); + } else { // Negative unpressed Amiga-style button + return AgiTextColor(amigaWhite, amigaRed); + } + } + } else { // PC-style button + if (hasFocus || pressed) { // A pressed or in focus PC-style button + return AgiTextColor(pcWhite, pcBlack); + } else { // An unpressed PC-style button without focus + return AgiTextColor(pcBlack, pcWhite); + } + } +} + +AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const { + return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor)); +} + +AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const { + if (hasFocus || pressed) + return baseColor.swap(); + else + return baseColor; +} + +int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const { + return (pressed && !_amigaStyle) ? 1 : 0; +} + +bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const { + return _amigaStyle && !_authenticAmiga && (hasFocus || pressed); +} + +void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) { + _amigaStyle = amigaStyle; + _olderAgi = olderAgi; + _authenticAmiga = authenticAmiga; +} + +void AgiButtonStyle::setPcStyle(bool pcStyle) { + setAmigaStyle(!pcStyle); +} + +AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) { + setAmigaStyle(renderMode == Common::kRenderAmiga); +} + } // End of namespace Agi diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index e728f2f695..7a6608d0d0 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -1267,7 +1267,7 @@ void Mickey::pressOB(int iButton) { } // print pressed buttons - printLine("MICKEY HAS PRESSED: "); + printLine("MICKEY HAS PRESSED: "); _vm->drawStr(20, 22, IDA_DEFAULT, szButtons); waitAnyKey(); } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index 7c84f1dd72..50b329c0b6 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -32,6 +32,7 @@ #include "common/file.h" #include "graphics/thumbnail.h" +#include "common/config-manager.h" #include "agi/agi.h" #include "agi/graphics.h" @@ -925,4 +926,85 @@ int AgiEngine::loadGameSimple() { return rc; } +void AgiEngine::recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) { + ImageStackElement pnew; + + pnew.type = type; + pnew.pad = 0; + pnew.parm1 = p1; + pnew.parm2 = p2; + pnew.parm3 = p3; + pnew.parm4 = p4; + pnew.parm5 = p5; + pnew.parm6 = p6; + pnew.parm7 = p7; + + _imageStack.push(pnew); +} + +void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) { + switch (type) { + case ADD_PIC: + debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1); + agiLoadResource(rPICTURE, p1); + _picture->decodePicture(p1, p2, p3 != 0); + break; + case ADD_VIEW: + agiLoadResource(rVIEW, p1); + _sprites->addToPic(p1, p2, p3, p4, p5, p6, p7); + break; + } +} + +void AgiEngine::clearImageStack(void) { + _imageStack.clear(); +} + +void AgiEngine::releaseImageStack(void) { + _imageStack.clear(); +} + +void AgiEngine::checkQuickLoad() { + if (ConfMan.hasKey("save_slot")) { + char saveNameBuffer[256]; + + snprintf (saveNameBuffer, 256, "%s.%03d", _targetName.c_str(), ConfMan.getInt("save_slot")); + + _sprites->eraseBoth(); + _sound->stopSound(); + + if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id + _game.exitAllLogics = 1; + _menu->enableAll(); + } + } +} + +Common::Error AgiEngine::loadGameState(int slot) { + static char saveLoadSlot[12]; + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); + + _sprites->eraseBoth(); + _sound->stopSound(); + + if (loadGame(saveLoadSlot) == errOK) { + _game.exitAllLogics = 1; + _menu->enableAll(); + return Common::kNoError; + } else { + return Common::kUnknownError; + } +} + +Common::Error AgiEngine::saveGameState(int slot, const char *desc) { + static char saveLoadSlot[12]; + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); + if (saveGame(saveLoadSlot, desc) == errOK) + return Common::kNoError; + else + return Common::kUnknownError; +} + } // End of namespace Agi diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp index f3c0b7365c..63ac880267 100644 --- a/engines/agi/sprite.cpp +++ b/engines/agi/sprite.cpp @@ -56,9 +56,10 @@ struct Sprite { void *SpritesMgr::poolAlloc(int size) { uint8 *x; - // Adjust size to 32-bit boundary to prevent data misalignment + // Adjust size to sizeof(void *) boundary to prevent data misalignment // errors. - size = (size + 3) & ~3; + const int alignPadding = sizeof(void*) - 1; + size = (size + alignPadding) & ~alignPadding; x = _poolTop; _poolTop += size; diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index 9903952577..0e53698b59 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -27,6 +27,7 @@ #include "common/file.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "agos/debugger.h" #include "agos/intern.h" @@ -528,7 +529,7 @@ AGOSEngine::AGOSEngine(OSystem *syst) File::addDefaultDirectory(_gameDataDir.getChild("speech")); File::addDefaultDirectory(_gameDataDir.getChild("SPEECH")); - syst->getEventManager()->registerRandomSource(_rnd, "agos"); + g_eventRec.registerRandomSource(_rnd, "agos"); } Common::Error AGOSEngine::init() { diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 263811b78a..ac1f33428b 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -1248,6 +1248,7 @@ protected: void hitarea_stuff_helper_2(); void fastFadeIn(); void slowFadeIn(); + void fullFade(); virtual void vcStopAnimation(uint16 zone, uint16 sprite); @@ -1265,20 +1266,6 @@ protected: #ifdef ENABLE_PN class AGOSEngine_PN : public AGOSEngine { - struct StackFrame { - StackFrame *nextframe; - int16 flag[6]; - int16 param[8]; - int16 classnum; - uint8 *linpos; - uint8 *lbase; - int16 ll; - int16 linenum; - int16 process; - jmp_buf *savearea; - StackFrame() { memset(this, 0, sizeof(*this)); } - }; - virtual Common::Error go(); void demoSeq(); @@ -1358,8 +1345,30 @@ public: void opn_opcode62(); void opn_opcode63(); +protected: + struct StackFrame { + StackFrame *nextframe; + int16 flag[6]; + int16 param[8]; + int16 classnum; + uint8 *linpos; + uint8 *lbase; + int16 ll; + int16 linenum; + int16 process; + int tagOfParentDoline; ///< tag of the doline "instance" to which this StackFrame belongs + StackFrame() { memset(this, 0, sizeof(*this)); } + }; + + StackFrame *_stackbase; + int _tagOfActiveDoline; ///< tag of the active doline "instance" + int _dolineReturnVal; + + jmp_buf _loadfail; + + byte *_dataBase, *_textBase; uint32 _dataBaseSize, _textBaseSize; @@ -1404,8 +1413,6 @@ public: int _linembr; uint8 *_linebase; uint8 *_workptr; - jmp_buf *_cjmpbuff; - jmp_buf _loadfail; uint16 getptr(uint32 pos); uint32 getlong(uint32 pos); @@ -1429,7 +1436,6 @@ public: void addstack(int type); void dumpstack(); - void junkstack(); void popstack(int type); void funccpy(int *store); void funcentry(int *storestore, int procn); @@ -1465,8 +1471,8 @@ public: virtual void windowPutChar(WindowBlock *window, byte c, byte b = 0); bool badload(int8 errorNum); - int loadfl(char *name); - int savfl(char *name); + int loadFile(char *name); + int saveFile(char *name); void getFilename(); void sysftodb(); void dbtosysf(); diff --git a/engines/agos/debug.h b/engines/agos/debug.h index 375878a4bc..38674de765 100644 --- a/engines/agos/debug.h +++ b/engines/agos/debug.h @@ -2549,7 +2549,7 @@ const char *const ww_videoOpcodeNameTable[] = { "j|IF_EGA", /* 60 */ "d|STOP_ANIMATE", - "d|VC_61", + "d|INTRO", "|FASTFADEOUT", "|FASTFADEIN", }; diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h index ec21acc0a1..0c672aef52 100644 --- a/engines/agos/detection_tables.h +++ b/engines/agos/detection_tables.h @@ -26,6 +26,8 @@ namespace AGOS { using Common::GUIO_NONE; +using Common::GUIO_NOMIDI; +using Common::GUIO_NOMUSIC; using Common::GUIO_NOSPEECH; using Common::GUIO_NOSUBTITLES; @@ -45,7 +47,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_PN, @@ -68,7 +70,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_PN, @@ -91,7 +93,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_PN, @@ -137,7 +139,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -158,7 +160,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -179,7 +181,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -200,7 +202,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -223,7 +225,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -246,7 +248,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -269,7 +271,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA1, @@ -410,7 +412,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -436,7 +438,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -462,7 +464,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -488,7 +490,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -514,7 +516,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -540,7 +542,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -566,7 +568,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_ELVIRA2, @@ -802,7 +804,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_WW, @@ -829,7 +831,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_WW, @@ -992,7 +994,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAcorn, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1017,7 +1019,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAcorn, ADGF_DEMO, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1042,7 +1044,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAcorn, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1066,7 +1068,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1090,7 +1092,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1114,7 +1116,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1138,7 +1140,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1162,7 +1164,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1186,7 +1188,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOMIDI }, GType_SIMON1, @@ -1210,7 +1212,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOMIDI }, GType_SIMON1, @@ -1234,7 +1236,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOMIDI }, GType_SIMON1, @@ -1523,7 +1525,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1548,7 +1550,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1573,7 +1575,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1598,7 +1600,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::RU_RUS, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1623,7 +1625,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1648,7 +1650,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1673,7 +1675,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::HB_ISR, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1698,7 +1700,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1724,7 +1726,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1749,7 +1751,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1774,7 +1776,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1799,7 +1801,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_SIMON1, @@ -1824,7 +1826,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSPEECH }, GType_SIMON2, @@ -1949,7 +1951,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -1974,7 +1976,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -1999,7 +2001,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2024,7 +2026,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2049,7 +2051,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2074,7 +2076,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2099,7 +2101,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2124,7 +2126,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2175,7 +2177,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2200,7 +2202,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2225,7 +2227,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::CZ_CZE, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2250,7 +2252,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2275,7 +2277,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2300,7 +2302,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2325,7 +2327,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::PL_POL, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NONE }, GType_SIMON2, @@ -2346,7 +2348,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2367,7 +2369,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2391,7 +2393,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2415,7 +2417,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2439,7 +2441,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2463,7 +2465,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2487,7 +2489,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2511,7 +2513,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2534,7 +2536,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2557,7 +2559,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::PL_POL, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2580,7 +2582,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2603,7 +2605,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2626,7 +2628,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2649,7 +2651,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2672,7 +2674,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_FF, @@ -2693,7 +2695,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOMUSIC }, GType_PP, @@ -2714,7 +2716,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2735,7 +2737,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2756,7 +2758,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2777,7 +2779,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, @@ -2798,7 +2800,7 @@ static const AGOSGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES }, GType_PP, diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp index 45443aa335..368da5db83 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -871,13 +871,11 @@ void AGOSEngine::slowFadeIn() { _fastFadeInFlag &= ~0x8000; _paletteFlag = false; - memset(_videoBuf1, 0, 1024); - memcpy(_currentPalette, _displayPalette, 1024); - memcpy(_videoBuf1 + 1024, _displayPalette, 1024); + memset(_currentPalette, 0, sizeof(_currentPalette)); for (c = 255; c >= 0; c -= 4) { - src = _videoBuf1 + 1024; - dst = _videoBuf1; + src = _displayPalette; + dst = _currentPalette; for (p = _fastFadeInFlag; p !=0 ; p -= 3) { if (src[0] >= c) @@ -889,7 +887,7 @@ void AGOSEngine::slowFadeIn() { src += 4; dst += 4; } - _system->setPalette(_videoBuf1, 0, _fastFadeCount); + _system->setPalette(_currentPalette, 0, _fastFadeCount); delay(5); } _fastFadeInFlag = 0; diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index cf6e808384..5c37fe620a 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -664,10 +664,11 @@ void AGOSEngine_PN::handleKeyboard() { } } if (chr == -1) { - chr = _keyPressed.ascii; - if (chr == 8 || chr == 13) { + if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE || _keyPressed.keycode == Common::KEYCODE_RETURN) { + chr = _keyPressed.keycode; addChar(chr); } else if (!(_videoLockOut & 0x10)) { + chr = _keyPressed.ascii; if (chr >= 32) addChar(chr); } diff --git a/engines/agos/midiparser_s1d.cpp b/engines/agos/midiparser_s1d.cpp index d77621cc7b..568135ef8c 100644 --- a/engines/agos/midiparser_s1d.cpp +++ b/engines/agos/midiparser_s1d.cpp @@ -126,6 +126,10 @@ void MidiParser_S1D::parseNextEvent(EventInfo &info) { switch (info.event & 0x0F) { case 0x0: // Trigged by MOD2/MOD6/MOD15 in Waxworks + // Pure guesswork + info.ext.type = *(_position._play_pos++); + info.length = readVLQ(_position._play_pos); + info.ext.data = _position._play_pos; break; case 0x3: // Not sure, Song Select? diff --git a/engines/agos/pn.cpp b/engines/agos/pn.cpp index d92efa9077..e8135f56cd 100644 --- a/engines/agos/pn.cpp +++ b/engines/agos/pn.cpp @@ -35,6 +35,10 @@ namespace AGOS { AGOSEngine_PN::AGOSEngine_PN(OSystem *system) : AGOSEngine(system) { + _stackbase = 0; + _tagOfActiveDoline = 0; + _dolineReturnVal = 0; + _dataBase = 0; _dataBaseSize = 0; _textBase = 0; @@ -70,7 +74,7 @@ AGOSEngine_PN::AGOSEngine_PN(OSystem *system) _objects = 0; _objectCountS = 0; - _bp = 0; + _bp = 0; _xofs = 0; _havinit = 0; _seed = 0; @@ -84,16 +88,12 @@ AGOSEngine_PN::AGOSEngine_PN(OSystem *system) _linebase = 0; _workptr = 0; - - _cjmpbuff = NULL; } AGOSEngine_PN::~AGOSEngine_PN() { free(_dataBase); free(_textBase); - free(_cjmpbuff); - free(_stackbase); } const byte egaPalette[48] = { @@ -251,29 +251,33 @@ void AGOSEngine_PN::setupBoxes() { } void AGOSEngine_PN::processor() { - int q; - setqptrs(); - q = setjmp(_loadfail); - _variableArray[6] = 0; + _tagOfActiveDoline = 0; + int q = 0; + do { + assert(_tagOfActiveDoline == 0); + _dolineReturnVal = 0; - if (getPlatform() == Common::kPlatformAtariST) { - _variableArray[21] = 2; - } else if (getPlatform() == Common::kPlatformAmiga) { - _variableArray[21] = 0; - } else { - _variableArray[21] = 1; - } + _variableArray[6] = 0; + + if (getPlatform() == Common::kPlatformAtariST) { + _variableArray[21] = 2; + } else if (getPlatform() == Common::kPlatformAmiga) { + _variableArray[21] = 0; + } else { + _variableArray[21] = 1; + } - _variableArray[16] = _quickshort[6]; - _variableArray[17] = _quickshort[7]; - _variableArray[19] = getptr(55L); + _variableArray[16] = _quickshort[6]; + _variableArray[17] = _quickshort[7]; + _variableArray[19] = getptr(55L); - // q indicates the process to run and is 0 the first time, - // but 1 later on (i.e., when we are "called" from badload()). - setposition(q, 0); - doline(0); + // q indicates the process to run and is 0 the first time, + // but 1 later on (i.e., when we are "called" from badload()). + setposition(0, 0); + q = doline(0); + } while (q); } void AGOSEngine_PN::setqptrs() { diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp index e85440d8e1..4f3582b55d 100644 --- a/engines/agos/res_snd.cpp +++ b/engines/agos/res_snd.cpp @@ -285,10 +285,6 @@ void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) { void AGOSEngine::playMusic(uint16 music, uint16 track) { stopMusic(); - // FIXME: Music too unstable, when switching locations. - if (getPlatform() == Common::kPlatformPC && getGameType() == GType_WW) - return; - if (getPlatform() == Common::kPlatformAmiga) { playModule(music); } else if (getPlatform() == Common::kPlatformAtariST) { diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 16bde0097b..3787617be7 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -23,8 +23,6 @@ * */ - - #include "common/savefile.h" #include "common/system.h" @@ -231,7 +229,7 @@ bool AGOSEngine::confirmOverWrite(WindowBlock *window) { break; case Common::DE_DEU: message1 = "\rDatei existiert bereits.\r\r"; - message2 = " berschreiben ?\r\r"; + message2 = " Ueberschreiben ?\r\r"; message3 = " Ja Nein"; break; default: @@ -1555,13 +1553,16 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { bool AGOSEngine_PN::badload(int8 errorNum) { if (errorNum == -2) return 0; - /* Load error recovery routine */ + // Load error recovery routine + + // Clear any stack while (_stackbase != NULL) { - /* Clear any stack */ dumpstack(); } - /* Restart from process 1 */ - longjmp(_loadfail, 1); + + // Restart from process 1 + _tagOfActiveDoline = 1; + _dolineReturnVal = 3; return 1; } @@ -1572,7 +1573,7 @@ void AGOSEngine_PN::getFilename() { memset(_saveFile, 0, sizeof(_saveFile)); while (!shouldQuit() && !strlen(_saveFile)) { const char *msg = "File name : "; - pcf((unsigned char)'\n'); + pcf((unsigned char)'\n'); while (*msg) pcf((unsigned char)*msg++); @@ -1582,7 +1583,7 @@ void AGOSEngine_PN::getFilename() { } } -int AGOSEngine_PN::loadfl(char *name) { +int AGOSEngine_PN::loadFile(char *name) { Common::InSaveFile *f; haltAnimation(); @@ -1609,13 +1610,13 @@ int AGOSEngine_PN::loadfl(char *name) { delete f; return -1; } - delete f; + delete f; restartAnimation(); dbtosysf(); return 0; } -int AGOSEngine_PN::savfl(char *name) { +int AGOSEngine_PN::saveFile(char *name) { Common::OutSaveFile *f; sysftodb(); haltAnimation(); @@ -1625,7 +1626,7 @@ int AGOSEngine_PN::savfl(char *name) { restartAnimation(); const char *msg = "Couldn't save. "; - pcf((unsigned char)'\n'); + pcf((unsigned char)'\n'); while (*msg) pcf((unsigned char)*msg++); diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp index 4f9aab2965..2885781a9f 100644 --- a/engines/agos/script_pn.cpp +++ b/engines/agos/script_pn.cpp @@ -324,8 +324,8 @@ void AGOSEngine_PN::opn_opcode24() { // That value then is returned to actCallD, which once again // returns it. In the end, this amounts to a setScriptReturn(true) // (but possibly in a different level than the current one). - longjmp(*(_stackbase->savearea), 2); - setScriptReturn(false); + _dolineReturnVal = 2; + _tagOfActiveDoline = _stackbase->tagOfParentDoline; } void AGOSEngine_PN::opn_opcode25() { @@ -334,13 +334,13 @@ void AGOSEngine_PN::opn_opcode25() { // That value then is returned to actCallD, which once again // returns it. In the end, this amounts to a setScriptReturn(false) // (but possibly in a different level than the current one). - longjmp(*(_stackbase->savearea), 1); - setScriptReturn(false); + _dolineReturnVal = 1; + _tagOfActiveDoline = _stackbase->tagOfParentDoline; } void AGOSEngine_PN::opn_opcode26() { while ((_stackbase != NULL) && (_stackbase->classnum != kJmpClassNum)) - junkstack(); + dumpstack(); dumpstack(); setScriptReturn(true); } @@ -353,16 +353,16 @@ void AGOSEngine_PN::opn_opcode27() { void AGOSEngine_PN::opn_opcode28() { addstack(varval()); - _stackbase->savearea = _cjmpbuff; + _stackbase->tagOfParentDoline = _tagOfActiveDoline; setScriptReturn(false); } void AGOSEngine_PN::opn_opcode29() { popstack(varval()); - // Jump back to the last doline indicated by the top stackfram. + // Jump back to the last doline indicated by the top stackframe. // The -1 tells it to simply go on with its business. - longjmp(*(_stackbase->savearea), -1); - setScriptReturn(false); + _dolineReturnVal = -1; + _tagOfActiveDoline = _stackbase->tagOfParentDoline; } void AGOSEngine_PN::opn_opcode30() { @@ -386,7 +386,7 @@ void AGOSEngine_PN::opn_opcode31() { strcpy(bf, genSaveName(slot)); break; case 1: - strcpy(bf, "test.sav"); + strcpy(bf, "pn.sav"); break; case 2: // NOTE: Is this case ever used? @@ -397,7 +397,7 @@ void AGOSEngine_PN::opn_opcode31() { if (slot == -1) { setScriptReturn(false); } else { - a = loadfl(bf); + a = loadFile(bf); if (a) setScriptReturn(badload(a)); else @@ -426,7 +426,7 @@ void AGOSEngine_PN::opn_opcode32() { strcpy(bf, genSaveName(curSlot)); break; case 1: - strcpy(bf, "test.sav"); + strcpy(bf, "pn.sav"); break; case 2: // NOTE: Is this case ever used? @@ -434,7 +434,7 @@ void AGOSEngine_PN::opn_opcode32() { break; } - a = savfl(bf); + a = saveFile(bf); setScriptReturn(a); } @@ -520,19 +520,32 @@ void AGOSEngine_PN::opn_opcode39() { } void AGOSEngine_PN::opn_opcode40() { - setScriptReturn(doaction() | doaction()); + int a = doaction(); + if (_dolineReturnVal != 0) + return; + int b = doaction(); + setScriptReturn(a | b); } void AGOSEngine_PN::opn_opcode41() { - setScriptReturn(doaction() & doaction()); + int a = doaction(); + if (_dolineReturnVal != 0) + return; + int b = doaction(); + setScriptReturn(a & b); } void AGOSEngine_PN::opn_opcode42() { - setScriptReturn(doaction() ^ doaction()); + int a = doaction(); + if (_dolineReturnVal != 0) + return; + int b = doaction(); + setScriptReturn(a ^ b); } void AGOSEngine_PN::opn_opcode43() { - setScriptReturn(!(doaction())); + int a = doaction(); + setScriptReturn(!a); } void AGOSEngine_PN::opn_opcode44() { @@ -874,41 +887,14 @@ int AGOSEngine_PN::doaction() { } int AGOSEngine_PN::doline(int needsave) { - int x; - jmp_buf *old_jmpbuf = NULL; - jmp_buf *mybuf; + assert(!_stackbase == !needsave); - mybuf = (jmp_buf *)malloc(sizeof(jmp_buf)); - if (mybuf == NULL) - error("doline: Out of memory - stack overflow"); - - x = setjmp(*mybuf); - // Looking at the longjmp calls below, x can be -1, 1 or 2 - // (and of course 0 when it returns directly, as always). - if (x > 0) { - dumpstack(); - // Restore the active jmpbuf to its previous value, - // then return the longjmp value (will be 2-1=1 or 1-1=0). - _cjmpbuff = old_jmpbuf; - free((char *)mybuf); - return (x - 1); - } + int x; + int myTag = ++_tagOfActiveDoline; // Obtain a unique tag for this doline invocation + _dolineReturnVal = 0; - if (x == -1) { - // Make this doline instance the active one (again). - // This is used to "return" over possibly multiple - // layers of nested script invocations. - // Kind of like throwing an exception. - _cjmpbuff = mybuf; - goto carryon; - } - - // Remember the previous active jmpbuf (gets restored - // above when a longjmp with a positive param occurs). - old_jmpbuf = _cjmpbuff; - _cjmpbuff = mybuf; if (needsave) - _stackbase->savearea = mybuf; + _stackbase->tagOfParentDoline = myTag; do { _linct = ((*_linebase) & 127) - 1; @@ -919,9 +905,26 @@ int AGOSEngine_PN::doline(int needsave) { goto skipln; } -carryon: do { x = doaction(); + + if (_dolineReturnVal != 0) { + if (_tagOfActiveDoline != myTag) + return 0; + + x = _dolineReturnVal; + _dolineReturnVal = 0; + + if (x > 0) { + if (x != 3) + dumpstack(); + // Restore the active jmpbuf to its previous value, + // then return _dolineReturnVal-1 (will be 2-1=1 or 1-1=0). + _tagOfActiveDoline = myTag - 1; + return (x - 1); + } + } + } while (x && !shouldQuit()); skipln: @@ -1063,7 +1066,7 @@ void AGOSEngine_PN::addstack(int type) { StackFrame *a; int i; - a = (StackFrame *)malloc(sizeof(StackFrame)); + a = (StackFrame *)calloc(1, sizeof(StackFrame)); if (a == NULL) error("addstack: Out of memory - stack overflow"); @@ -1093,24 +1096,13 @@ void AGOSEngine_PN::dumpstack() { _stackbase = a; } -void AGOSEngine_PN::junkstack() { - StackFrame *a; - - if (_stackbase == NULL) - error("junkstack: Stack underflow or unknown longjmp"); - - a = _stackbase->nextframe; - if (_stackbase->classnum == kJmpClassNum) - free((char *)_stackbase->savearea); - free((char *)_stackbase); - _stackbase = a; -} - void AGOSEngine_PN::popstack(int type) { - int i; + int i = 0; - while ((_stackbase != NULL) && (_stackbase->classnum != type)) - junkstack(); + while ((_stackbase != NULL) && (_stackbase->classnum != type)) { + dumpstack(); + ++i; + } if (_stackbase == NULL) error("popstack: Stack underflow or unknown longjmp"); diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp index 2e3d936037..81efb5cd81 100644 --- a/engines/agos/script_s1.cpp +++ b/engines/agos/script_s1.cpp @@ -576,18 +576,15 @@ void AGOSEngine_Simon1::os1_specialFade() { // 187: fade to black uint i; - memcpy(_videoBuf1, _currentPalette, 4 * 256); - for (i = 32; i != 0; --i) { - paletteFadeOut(_videoBuf1, 32, 8); - paletteFadeOut(_videoBuf1 + 4 * 48, 144, 8); - paletteFadeOut(_videoBuf1 + 4 * 208, 48, 8); - _system->setPalette(_videoBuf1, 0, 256); + paletteFadeOut(_currentPalette, 32, 8); + paletteFadeOut(_currentPalette + 4 * 48, 144, 8); + paletteFadeOut(_currentPalette + 4 * 208, 48, 8); + _system->setPalette(_currentPalette, 0, 256); delay(5); } - memcpy(_currentPalette, _videoBuf1, 1024); - memcpy(_displayPalette, _videoBuf1, 1024); + memcpy(_displayPalette, _currentPalette, 1024); } void AGOSEngine::scriptMouseOff() { diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp index f6e6630d43..de3cb55963 100644 --- a/engines/agos/vga_e2.cpp +++ b/engines/agos/vga_e2.cpp @@ -353,9 +353,32 @@ void AGOSEngine::vc55_moveBox() { _needHitAreaRecalc++; } -void AGOSEngine::vc56_fullScreen() { - uint8 palette[1024]; +void AGOSEngine::fullFade() { + uint8 *srcPal, *dstPal; + int c, p; + + for (c = 64; c != 0; c --) { + srcPal = _curVgaFile2 + 32; + dstPal = _currentPalette; + for (p = 768; p !=0 ; p -= 3) { + uint8 r = srcPal[0] * 4; + if (dstPal[0] != r) + dstPal[0] += 4; + uint8 g = srcPal[1] * 4; + if (dstPal[1] != g) + dstPal[1] += 4; + uint8 b = srcPal[2] * 4; + if (dstPal[2] != b) + dstPal[2] += 4; + srcPal += 3; + dstPal += 4; + } + _system->setPalette(_currentPalette, 0, 256); + delay(5); + } +} +void AGOSEngine::vc56_fullScreen() { Graphics::Surface *screen = _system->lockScreen(); byte *dst = (byte *)screen->pixels; byte *src = _curVgaFile2 + 800; @@ -367,23 +390,12 @@ void AGOSEngine::vc56_fullScreen() { } _system->unlockScreen(); - //fullFade(); - - src = _curVgaFile2 + 32; - for (int i = 0; i < 256; i++) { - palette[i * 4 + 0] = *src++ * 4; - palette[i * 4 + 1] = *src++ * 4; - palette[i * 4 + 2] = *src++ * 4; - palette[i * 4 + 3] = 0; - } - - _system->setPalette(palette, 0, 256); + fullFade(); } void AGOSEngine::vc57_blackPalette() { - uint8 palette[1024]; - memset(palette, 0, sizeof(palette)); - _system->setPalette(palette, 0, 256); + memset(_currentPalette, 0, sizeof(_currentPalette)); + _system->setPalette(_currentPalette, 0, 256); } void AGOSEngine::vc58_checkCodeWheel() { diff --git a/engines/agos/vga_ww.cpp b/engines/agos/vga_ww.cpp index e7f2ad7807..afc05f7869 100644 --- a/engines/agos/vga_ww.cpp +++ b/engines/agos/vga_ww.cpp @@ -193,20 +193,8 @@ void AGOSEngine::vc61() { _system->unlockScreen(); - if (a == 6) { - //fullFade(); - src = _curVgaFile2 + 32; - - uint8 palette[1024]; - for (int i = 0; i < 256; i++) { - palette[i * 4 + 0] = *src++ * 4; - palette[i * 4 + 1] = *src++ * 4; - palette[i * 4 + 2] = *src++ * 4; - palette[i * 4 + 3] = 0; - } - - _system->setPalette(palette, 0, 256); - } + if (a == 6) + fullFade(); } void AGOSEngine::vc62_fastFadeOut() { @@ -221,8 +209,6 @@ void AGOSEngine::vc62_fastFadeOut() { _fastFadeCount = 208; } - memcpy(_videoBuf1, _currentPalette, _fastFadeCount * 4); - if (getGameType() == GType_FF || getGameType() == GType_PP) { if (getGameType() == GType_FF && getBitFlag(75)) { fadeCount = 4; @@ -237,8 +223,8 @@ void AGOSEngine::vc62_fastFadeOut() { } for (i = fadeCount; i != 0; --i) { - paletteFadeOut(_videoBuf1, _fastFadeCount, fadeSize); - _system->setPalette(_videoBuf1, 0, _fastFadeCount); + paletteFadeOut(_currentPalette, _fastFadeCount, fadeSize); + _system->setPalette(_currentPalette, 0, _fastFadeCount); delay(5); } diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 64a9a9dfb8..8756a2fc3c 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -64,7 +65,7 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng g_cine = this; - syst->getEventManager()->registerRandomSource(_rnd, "cine"); + g_eventRec.registerRandomSource(_rnd, "cine"); } CineEngine::~CineEngine() { @@ -113,6 +114,9 @@ int CineEngine::modifyGameSpeed(int speedChange) { } void CineEngine::initialize() { + // Initialize all savegames' descriptions to empty strings + memset(currentSaveName, 0, sizeof(currentSaveName)); + // Resize object table to its correct size and reset all its elements objectTable.resize(NUM_MAX_OBJECT); resetObjectTable(); diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp index 4786005647..3bc26ab417 100644 --- a/engines/cine/detection.cpp +++ b/engines/cine/detection.cpp @@ -607,35 +607,37 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const { pattern += ".?"; Common::StringList filenames = saveFileMan->listSavefiles(pattern); sort(filenames.begin(), filenames.end()); - Common::StringList::const_iterator file = filenames.begin(); + Common::StringList::const_iterator file; Common::String filename = target; filename += ".dir"; Common::InSaveFile *in = saveFileMan->openForLoading(filename); if (in) { - int8 ch; - char saveDesc[20]; - do { + typedef char CommandeType[20]; + CommandeType saveNames[10]; + + // Initialize all savegames' descriptions to empty strings + // so that if the savegames' descriptions can only be partially read from file + // then the missing ones are correctly set to empty strings. + memset(saveNames, 0, sizeof(saveNames)); + + in->read(saveNames, 10 * 20); + CommandeType saveDesc; + + for (file = filenames.begin(); file != filenames.end(); ++file) { + // Jump over savegame files that don't end with a digit (e.g. "fw.3" is ok, "fw.a" is not). + if (!isdigit(file->lastChar())) + continue; + // Obtain the last digit of the filename, since they correspond to the save slot int slotNum = atoi(file->c_str() + file->size() - 1); - uint pos = 0; - do { - ch = in->readByte(); - if (pos < (sizeof(saveDesc) - 1)) { - if (ch < 32 || in->eos()) { - saveDesc[pos++] = '\0'; - } - else if (ch >= 32) { - saveDesc[pos++] = ch; - } - } - } while (ch >= 32 && !in->eos()); - if (saveDesc[0] != 0) { - saveList.push_back(SaveStateDescriptor(slotNum, saveDesc)); - file++; - } - } while (!in->eos()); + // Copy the savegame description making sure it ends with a trailing zero + strncpy(saveDesc, saveNames[slotNum], 20); + saveDesc[sizeof(CommandeType) - 1] = 0; + + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc)); + } } delete in; @@ -650,6 +652,11 @@ void CineMetaEngine::removeSaveState(const char *target, int slot) const { typedef char CommandeType[20]; CommandeType saveNames[10]; + // Initialize all savegames' descriptions to empty strings + // so that if the savegames' descriptions can only be partially read from file + // then the missing ones are correctly set to empty strings. + memset(saveNames, 0, sizeof(saveNames)); + Common::InSaveFile *in; char tmp[80]; @@ -707,8 +714,9 @@ Common::Error CineEngine::saveGameState(int slot, const char *desc) { // Load savegame descriptions from index file loadSaveDirectory(); - // Set description for selected slot + // Set description for selected slot making sure it ends with a trailing zero strncpy(currentSaveName[slot], desc, 20); + currentSaveName[slot][sizeof(CommandeType) - 1] = 0; // Update savegame descriptions char indexFile[80]; diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp index b3e3629239..757419ef87 100644 --- a/engines/cine/pal.cpp +++ b/engines/cine/pal.cpp @@ -239,9 +239,6 @@ Palette &Palette::saturatedAddNormalizedGray(Palette& output, byte firstIndex, b } // a.k.a. transformColor -// Parameter color components (i.e. r, g and b) are in range [-7, 7] -// e.g. r = 7 sets the resulting color's red component to maximum -// e.g. r = -7 sets the resulting color's red component to minimum (i.e. zero) Cine::Palette::Color Palette::saturatedAddColor(Cine::Palette::Color baseColor, signed r, signed g, signed b) const { Cine::Palette::Color result; result.r = CLIP<int>(baseColor.r + r, 0, _format.rMax()); diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index be1e19b229..158d209289 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -468,9 +468,18 @@ bool CineEngine::loadSaveDirectory(void) { return false; } + // Initialize all savegames' descriptions to empty strings + // so that if the savegames' descriptions can only be partially read from file + // then the missing ones are correctly set to empty strings. + memset(currentSaveName, 0, sizeof(currentSaveName)); + fHandle->read(currentSaveName, 10 * 20); delete fHandle; + // Make sure all savegames' descriptions end with a trailing zero. + for (int i = 0; i < ARRAYSIZE(currentSaveName); i++) + currentSaveName[i][sizeof(CommandeType) - 1] = 0; + return true; } diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index 3d3a44a36c..7abf83f054 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -65,7 +66,7 @@ CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc _debugger = new Debugger(); _sound = new PCSound(_mixer, this); - syst->getEventManager()->registerRandomSource(_rnd, "cruise"); + g_eventRec.registerRandomSource(_rnd, "cruise"); } CruiseEngine::~CruiseEngine() { diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index e5864ebb31..94dfc95cb5 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -1390,7 +1390,7 @@ int CruiseEngine::processInput(void) { } // Player Menu - test for both buttons or the F10 key - if (((button & MB_BOTH) == MB_BOTH) || (keyboardCode == Common::KEYCODE_F10)) { + if (((button & CRS_MB_BOTH) == CRS_MB_BOTH) || (keyboardCode == Common::KEYCODE_F10)) { changeCursor(CURSOR_NORMAL); keyboardCode = Common::KEYCODE_INVALID; return (playerMenu(mouseX, mouseY)); @@ -1398,7 +1398,7 @@ int CruiseEngine::processInput(void) { if (userWait) { // Check for left mouse button click or Space to end user waiting - if ((keyboardCode == Common::KEYCODE_SPACE) || (button == MB_LEFT)) + if ((keyboardCode == Common::KEYCODE_SPACE) || (button == CRS_MB_LEFT)) userWait = 0; keyboardCode = Common::KEYCODE_INVALID; @@ -1450,7 +1450,7 @@ int CruiseEngine::processInput(void) { menuDown = 0; } } else { - if ((button & MB_LEFT) && (buttonDown == 0)) { + if ((button & CRS_MB_LEFT) && (buttonDown == 0)) { if (menuTable[0]) { callRelation(getSelectedEntryInMenu(menuTable[0]), dialogueObj); @@ -1472,7 +1472,7 @@ int CruiseEngine::processInput(void) { } } - } else if ((button & MB_LEFT) && (buttonDown == 0)) { + } else if ((button & CRS_MB_LEFT) && (buttonDown == 0)) { // left click buttonDown = 1; @@ -1538,20 +1538,17 @@ int CruiseEngine::processInput(void) { aniX = mouseX; aniY = mouseY; animationStart = true; - buttonDown = 0; } } else { aniX = mouseX; aniY = mouseY; animationStart = true; - buttonDown = 0; } } else { // No object found, we move the character to the cursor aniX = mouseX; aniY = mouseY; animationStart = true; - buttonDown = 0; } } else { // handle click in menu @@ -1590,7 +1587,7 @@ int CruiseEngine::processInput(void) { } } } - } else if ((button & MB_RIGHT) || (keyboardCode == Common::KEYCODE_F9)) { + } else if ((button & CRS_MB_RIGHT) || (keyboardCode == Common::KEYCODE_F9)) { if (buttonDown == 0) { keyboardCode = Common::KEYCODE_INVALID; @@ -1628,29 +1625,28 @@ bool bFastMode = false; bool manageEvents() { Common::Event event; - bool result = false; Common::EventManager * eventMan = g_system->getEventManager(); - while (eventMan->pollEvent(event) && !result) { - result = true; + while (eventMan->pollEvent(event)) { + bool abortFlag = true; switch (event.type) { case Common::EVENT_LBUTTONDOWN: - currentMouseButton |= MB_LEFT; + currentMouseButton |= CRS_MB_LEFT; break; case Common::EVENT_LBUTTONUP: - currentMouseButton &= ~MB_LEFT; + currentMouseButton &= ~CRS_MB_LEFT; break; case Common::EVENT_RBUTTONDOWN: - currentMouseButton |= MB_RIGHT; + currentMouseButton |= CRS_MB_RIGHT; break; case Common::EVENT_RBUTTONUP: - currentMouseButton &= ~MB_RIGHT; + currentMouseButton &= ~CRS_MB_RIGHT; break; case Common::EVENT_MOUSEMOVE: currentMouseX = event.mouse.x; currentMouseY = event.mouse.y; - result = false; + abortFlag = false; break; case Common::EVENT_QUIT: case Common::EVENT_RTL: @@ -1659,7 +1655,7 @@ bool manageEvents() { case Common::EVENT_KEYUP: switch (event.kbd.keycode) { case Common::KEYCODE_ESCAPE: - currentMouseButton &= ~MB_MIDDLE; + currentMouseButton &= ~CRS_MB_MIDDLE; break; default: break; @@ -1668,7 +1664,7 @@ bool manageEvents() { case Common::EVENT_KEYDOWN: switch (event.kbd.keycode) { case Common::KEYCODE_ESCAPE: - currentMouseButton |= MB_MIDDLE; + currentMouseButton |= CRS_MB_MIDDLE; break; default: keyboardCode = event.kbd.keycode; @@ -1689,9 +1685,12 @@ bool manageEvents() { default: break; } + + if (abortFlag) + return true; } - return result; + return false; } void getMouseStatus(int16 *pMouseVar, int16 *pMouseX, int16 *pMouseButton, int16 *pMouseY) { @@ -1798,6 +1797,9 @@ void CruiseEngine::mainLoop(void) { // User waiting has ended changeScriptParamInList(-1, -1, &procHead, 9999, 0); changeScriptParamInList(-1, -1, &relHead, 9999, 0); + + // Disable any mouse click used to end the user wait + currentMouseButton = 0; } manageScripts(&relHead); @@ -1899,8 +1901,6 @@ void CruiseEngine::mainLoop(void) { g_system->updateScreen(); } - manageEvents(); - } while (!playerDontAskQuit && quitValue2 && quitValue != 7); } diff --git a/engines/cruise/cruise_main.h b/engines/cruise/cruise_main.h index d2e9350d70..5f4d5c5c13 100644 --- a/engines/cruise/cruise_main.h +++ b/engines/cruise/cruise_main.h @@ -56,10 +56,10 @@ namespace Cruise { enum MouseButton { - MB_LEFT = 1, - MB_RIGHT = 2, - MB_MIDDLE = 4, - MB_BOTH = MB_LEFT | MB_RIGHT + CRS_MB_LEFT = 1, + CRS_MB_RIGHT = 2, + CRS_MB_MIDDLE = 4, + CRS_MB_BOTH = CRS_MB_LEFT | CRS_MB_RIGHT }; /*#define DUMP_SCRIPT diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp index 3cf3957703..1202d06fbc 100644 --- a/engines/cruise/dataLoader.cpp +++ b/engines/cruise/dataLoader.cpp @@ -382,7 +382,7 @@ int loadFNTSub(uint8 *ptr, int destIdx) { currentPtr = destPtr + 14; - for (i = 0; i < *(int16 *)(destPtr + 8); i++) { + for (i = 0; i < (int16)READ_UINT16(destPtr + 8); i++) { bigEndianLongToNative((int32 *) currentPtr); currentPtr += 4; diff --git a/engines/cruise/linker.cpp b/engines/cruise/linker.cpp index bb6f682e1e..2d14d46ce3 100644 --- a/engines/cruise/linker.cpp +++ b/engines/cruise/linker.cpp @@ -23,6 +23,7 @@ * */ +#include "common/endian.h" #include "cruise/cruise_main.h" namespace Cruise { @@ -182,9 +183,7 @@ int updateScriptImport(int ovlIdx) { uint8 *ptr = ptrData + temp; *(ptr + 1) = out2; - *(int16 *)(ptr + 2) = ptrDest2->idx; - - bigEndianShortToNative((int16 *)(ptr + 2)); + WRITE_BE_UINT16(ptr + 2, ptrDest2->idx); } else { if (param2 == 20 || param2 == 30 || param2 == 40 || param2 == 50) { // this patch a double push uint8 *ptr = ptrData + temp; @@ -192,9 +191,7 @@ int updateScriptImport(int ovlIdx) { *(ptr + 1) = 0; *(ptr + 2) = out2; // update the overlay number - *(int16 *)(ptr + 4) = ptrDest2->idx; - - bigEndianShortToNative((int16 *)(ptr + 4)); + WRITE_BE_UINT16(ptr + 4, ptrDest2->idx); } else { int var_4 = ptrDest2->var4; @@ -213,17 +210,7 @@ int updateScriptImport(int ovlIdx) { *(ptrData + temp) = param2; *(ptrData + temp + 1) = out2; - *(int16 *)(ptrData + temp + 2) = ptrDest2->idx; - - bigEndianShortToNative - ( - (int16 - *) - (ptrData - + - temp - + - 2)); + WRITE_BE_UINT16(ptrData + temp + 2, ptrDest2->idx); } } } diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp index 2932e6dc7d..047f00ee90 100644 --- a/engines/cruise/mainDraw.cpp +++ b/engines/cruise/mainDraw.cpp @@ -206,10 +206,34 @@ int m_first_Y; int m_scaleValue; int m_color; -int16 DIST_3D[512]; -int16 polyBuffer2[512]; -int16 XMIN_XMAX[404]; -int16 polyBuffer4[512]; +/* + FIXME: Whether intentional or not, the game often seems to use negative indexing + of one or more of the arrays below and expects(?) to end up in the preceding one. + This "worked" on many platforms so far, but on OSX apparently the buffers don't + occupy contiguous memory, and this causes severe corruption and subsequent crashes. + Since I'm not really familiar with how the strange drawing code is supposed to work, + or whether this behaviour is intentional or not, the short-term fix is to allocate a big + buffer and setup pointers within it. This fixes the crashes I'm seeing without causing any + (visual) side-effects. + If anyone wants to look, this is easily reproduced by starting the game and examining the rug. + drawPolyMode1() will then (indirectly) negatively index polyBuffer4. Good luck! +*/ + +//int16 DIST_3D[512]; +//int16 polyBuffer2[512]; +//int16 XMIN_XMAX[404]; +//int16 polyBuffer4[512]; + +int16 bigPolyBuf[512 + 512 + 404 + 512]; /* consolidates the 4 separate buffers above */ + +//set up the replacement index pointers. +int16 *DIST_3D = &bigPolyBuf[0]; +int16 *polyBuffer2 = &bigPolyBuf[512]; +int16 *XMIN_XMAX = &bigPolyBuf[512 + 512]; +int16 *polyBuffer4 = &bigPolyBuf[512 + 512 + 404]; + + + // this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2) void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], unsigned char *dataPtr) { diff --git a/engines/cruise/mainDraw.h b/engines/cruise/mainDraw.h index dc988b551d..620ac6e4d7 100644 --- a/engines/cruise/mainDraw.h +++ b/engines/cruise/mainDraw.h @@ -29,8 +29,8 @@ namespace Cruise { extern int currentTransparent; -extern int16 polyBuffer2[512]; -extern int16 XMIN_XMAX[404]; +extern int16 *polyBuffer2; +extern int16 *XMIN_XMAX; extern int m_color; int upscaleValue(int value, int scale); diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp index 54f686f32a..7e454e78f8 100644 --- a/engines/cruise/menu.cpp +++ b/engines/cruise/menu.cpp @@ -179,6 +179,7 @@ int processMenu(menuStruct *pMenu) { flipScreen(); manageEvents(); + g_system->delayMillis(10); // readKeyboard(); } while (!si); diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp index 9f89f04069..761bba3673 100644 --- a/engines/cruise/script.cpp +++ b/engines/cruise/script.cpp @@ -23,6 +23,7 @@ * */ +#include "cruise/cruise.h" #include "cruise/cruise_main.h" #include "common/endian.h" @@ -632,7 +633,11 @@ int executeScripts(scriptInstanceStruct *ptr) { #endif opcodeType = getByteFromScript(); - // printf("opType: %d\n",(opcodeType&0xFB)>>3); + debugC(5, kCruiseDebugScript, "Script %s/%d ip=%d opcode=%d", + overlayTable[currentScriptPtr->overlayNumber].overlayName, + currentScriptPtr->scriptNumber, + currentScriptPtr->scriptOffset, + (opcodeType & 0xFB) >> 3); currentScriptOpcodeType = opcodeType & 7; diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp index 92c2ac6256..7ca4246785 100644 --- a/engines/cruise/sound.cpp +++ b/engines/cruise/sound.cpp @@ -766,6 +766,10 @@ void PCSoundFxPlayer::doSync(Common::Serializer &s) { for (int i = 0; i < NUM_CHANNELS; ++i) { _instrumentsChannelTable[i] = -1; } + + _numOrders = _sfxData[470]; + _eventsDelay = (244 - _sfxData[471]) * 100 / 1060; + _updateTicksCounter = 0; } s.syncAsSint16LE(_songPlayed); diff --git a/engines/cruise/staticres.cpp b/engines/cruise/staticres.cpp index d49d12c05b..595ac5a38b 100644 --- a/engines/cruise/staticres.cpp +++ b/engines/cruise/staticres.cpp @@ -168,6 +168,59 @@ int16 german_fontCharacterTable[256] = { -1, -1, -1, -1 }; +int16 spanish_fontCharacterTable[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, + -1, -1, -1, + 0x72, 0x80 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0x7f, 0x79, 0x7b, 0x81, 0x82, 0x83, + -1, -1, + 0x7d, + -1, -1, -1, -1, + 0x7E, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, + 0x6A, 0x69, + -1, -1, -1, -1, + 0x6B, 0x6C, + -1, -1, + 0x6D, 0x6E, + -1, -1, -1, -1, -1, -1, + 0x6F, + -1, + 0x70, + -1, -1, + 0x71, 0x72, + -1, -1, + 0x74, 0x5D, + -1, + 0x76, + -1, + 0x5E, + -1, + 0x75, 0x73, 0x60, 0x5F, 0x61, 0x62, 0x79, 0x78, 0x63, 0x64, + -1, -1, + 0x7B, 0x7A, + 0x65, + -1, + 0x66, + -1, -1, + 0x67, + -1, + 0x68, + -1, -1, -1, -1 +}; + // // Mouse data // diff --git a/engines/cruise/staticres.h b/engines/cruise/staticres.h index ef9a1b47e9..964bf294dc 100644 --- a/engines/cruise/staticres.h +++ b/engines/cruise/staticres.h @@ -41,9 +41,11 @@ extern int actor_invstat[][13]; extern short int english_fontCharacterTable[256]; extern short int german_fontCharacterTable[256]; +extern short int spanish_fontCharacterTable[256]; #define fontCharacterTable (_vm->getLanguage() == Common::DE_DEU ? \ - german_fontCharacterTable : english_fontCharacterTable) + german_fontCharacterTable : (_vm->getLanguage() == Common::ES_ESP ? \ + spanish_fontCharacterTable : english_fontCharacterTable)) // Mouse cursor data extern const byte mouseCursorNormal[]; diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp index 4aa8ee0d9e..006f16ab45 100644 --- a/engines/drascula/converse.cpp +++ b/engines/drascula/converse.cpp @@ -141,8 +141,9 @@ void DrasculaEngine::converse(int index) { int game1 = kDialogOptionUnselected, game2 = kDialogOptionUnselected, game3 = kDialogOptionUnselected; - char phrase1[78], phrase2[78], phrase3[78], phrase4[78]; + char phrase1[128], phrase2[128], phrase3[128], phrase4[128]; char sound1[13], sound2[13], sound3[13], sound4[13]; + int phrase1_bottom, phrase2_bottom, phrase3_bottom, phrase4_bottom; int answer1, answer2, answer3; char buffer[256]; @@ -207,12 +208,12 @@ void DrasculaEngine::converse(int index) { updateEvents(); - print_abc_opc(phrase1, 2, game1); - print_abc_opc(phrase2, 10, game2); - print_abc_opc(phrase3, 18, game3); - print_abc_opc(phrase4, 26, kDialogOptionUnselected); + phrase1_bottom = 8 * print_abc_opc(phrase1, 2, game1); + phrase2_bottom = phrase1_bottom + 8 * print_abc_opc(phrase2, phrase1_bottom + 2, game2); + phrase3_bottom = phrase2_bottom + 8 * print_abc_opc(phrase3, phrase2_bottom + 2, game3); + phrase4_bottom = phrase3_bottom + 8 * print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionUnselected); - if (mouseY > 0 && mouseY < 9) { + if (mouseY > 0 && mouseY < phrase1_bottom) { if (game1 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game1 != kDialogOptionClicked && _color != kColorLightGreen) @@ -226,13 +227,13 @@ void DrasculaEngine::converse(int index) { talk(phrase1, sound1); response(answer1); } - } else if (mouseY > 8 && mouseY < 17) { + } else if (mouseY > phrase1_bottom && mouseY < phrase2_bottom) { if (game2 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game2 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); - print_abc_opc(phrase2, 10, kDialogOptionSelected); + print_abc_opc(phrase2, phrase1_bottom + 2, kDialogOptionSelected); if (leftMouseButton == 1) { delay(100); @@ -240,13 +241,13 @@ void DrasculaEngine::converse(int index) { talk(phrase2, sound2); response(answer2); } - } else if (mouseY > 16 && mouseY < 25) { + } else if (mouseY > phrase2_bottom && mouseY < phrase3_bottom) { if (game3 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game3 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); - print_abc_opc(phrase3, 18, kDialogOptionSelected); + print_abc_opc(phrase3, phrase2_bottom + 2, kDialogOptionSelected); if (leftMouseButton == 1) { delay(100); @@ -254,8 +255,8 @@ void DrasculaEngine::converse(int index) { talk(phrase3, sound3); response(answer3); } - } else if (mouseY > 24 && mouseY < 33) { - print_abc_opc(phrase4, 26, kDialogOptionSelected); + } else if (mouseY > phrase3_bottom && mouseY < phrase4_bottom) { + print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionSelected); if (leftMouseButton == 1) { delay(100); @@ -265,6 +266,7 @@ void DrasculaEngine::converse(int index) { } else if (_color != kColorLightGreen) color_abc(kColorLightGreen); + _system->delayMillis(10); updateScreen(); } // while (breakOut == 0) diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index a3c56be1f4..2e3db3478e 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/keyboard.h" #include "common/file.h" #include "common/savefile.h" @@ -92,7 +93,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam *textName = 0; _rnd = new Common::RandomSource(); - syst->getEventManager()->registerRandomSource(*_rnd, "drascula"); + g_eventRec.registerRandomSource(*_rnd, "drascula"); int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) @@ -181,10 +182,6 @@ Common::Error DrasculaEngine::run() { for (;;) { int i; - - VGA = (byte *)malloc(320 * 200); - memset(VGA, 0, 64000); - takeObject = 0; _menuBar = false; _menuScreen = false; @@ -295,7 +292,6 @@ void DrasculaEngine::endChapter() { MusicFadeout(); stopMusic(); freeMemory(); - free(VGA); } bool DrasculaEngine::runCurrentChapter() { @@ -716,7 +712,8 @@ bool DrasculaEngine::verify2() { Common::KeyCode DrasculaEngine::getScan() { updateEvents(); - if (_keyBufferHead == _keyBufferTail) return Common::KEYCODE_INVALID; + if (_keyBufferHead == _keyBufferTail) + return Common::KEYCODE_INVALID; Common::KeyCode key = _keyBuffer[_keyBufferTail].keycode; _keyBufferTail = (_keyBufferTail + 1) % KEYBUFSIZE; diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index b06a2c9d4b..85f31ea2d1 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -344,7 +344,6 @@ public: byte *mouseCursor; // Graphics buffers/pointers - byte *VGA; byte *bgSurface; byte *backSurface; byte *drawSurface3; @@ -353,7 +352,6 @@ public: byte *extraSurface; // not sure about this one, was "dir_hare_dch" byte *screenSurface; byte *frontSurface; - byte *textSurface; byte *memPtr; byte *mSession; @@ -564,7 +562,7 @@ public: void playTalkSequence(int sequence); void doTalkSequenceCommand(TalkSequenceCommand cmd); void converse(int); - void print_abc_opc(const char *, int, int); + int print_abc_opc(const char *, int, int); void response(int); void activatePendulum(); diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 76a551c980..74b9e131e3 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -24,6 +24,7 @@ */ #include "drascula/drascula.h" +#include "graphics/surface.h" namespace Drascula { @@ -47,7 +48,7 @@ void DrasculaEngine::allocMemory() { assert(tableSurface); extraSurface = (byte *)malloc(64000); assert(extraSurface); - crosshairCursor = (byte *)malloc(40 * 25); + crosshairCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT); assert(crosshairCursor); mouseCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT); assert(mouseCursor); @@ -126,16 +127,18 @@ void DrasculaEngine::showFrame(bool firstFrame) { } byte *prevFrame = (byte *)malloc(64000); - memcpy(prevFrame, VGA, 64000); + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; + memcpy(prevFrame, screenBuffer, 64000); - decodeRLE(pcxData, VGA); + decodeRLE(pcxData, screenBuffer); free(pcxData); if (!firstFrame) - mixVideo(VGA, prevFrame); + mixVideo(screenBuffer, prevFrame); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + _system->unlockScreen(); _system->updateScreen(); + if (firstFrame) setPalette(cPal); @@ -192,8 +195,9 @@ void DrasculaEngine::copyRect(int xorg, int yorg, int xdes, int ydes, int width, } void DrasculaEngine::updateScreen(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *buffer) { - copyBackground(xorg, yorg, xdes, ydes, width, height, buffer, VGA); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; + copyBackground(xorg, yorg, xdes, ydes, width, height, buffer, screenBuffer); + _system->unlockScreen(); _system->updateScreen(); } @@ -235,13 +239,30 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) { } // for } -void DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { +int DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { int signY, letterY, letterX = 0; uint len = strlen(said); int screenX = 1; + int lines = 1; for (uint h = 0; h < len; h++) { + int wordLength; + + // Look ahead to the end of the word. + wordLength = 0; + int pos = h; + while (said[pos] && said[pos] != ' ') { + wordLength++; + pos++; + } + + if (screenX + wordLength * CHAR_WIDTH_OPC > 317) { + screenX = 0; + screenY += (CHAR_HEIGHT + 2); + lines++; + } + if (game == 1) { letterY = 6; signY = 15; @@ -281,6 +302,8 @@ void DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { screenX = screenX + CHAR_WIDTH_OPC; } + + return lines; } bool DrasculaEngine::textFitsCentered(char *text, int x) { @@ -402,6 +425,7 @@ void DrasculaEngine::screenSaver() { int x1_, y1_, off1, off2; + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; for (int i = 0; i < 200; i++) { for (int j = 0; j < 320; j++) { x1_ = j + tempRow[i]; @@ -419,10 +443,11 @@ void DrasculaEngine::screenSaver() { y1_ = checkWrapY(y1_); off2 = 320 * y1_ + x1_; - VGA[320 * i + j] = ghost[bgSurface[off2] + (copia[off1] << 8)]; + screenBuffer[320 * i + j] = ghost[bgSurface[off2] + (copia[off1] << 8)]; } } - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + + _system->unlockScreen(); _system->updateScreen(); _system->delayMillis(20); @@ -515,11 +540,14 @@ int DrasculaEngine::playFrameSSN() { decodeRLE(BufferSSN, screenSurface); free(BufferSSN); waitFrameSSN(); + + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; if (FrameSSN) - mixVideo(VGA, screenSurface); + mixVideo(screenBuffer, screenSurface); else - memcpy(VGA, screenSurface, 64000); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + memcpy(screenBuffer, screenSurface, 64000); + + _system->unlockScreen(); _system->updateScreen(); FrameSSN++; } else { @@ -534,11 +562,13 @@ int DrasculaEngine::playFrameSSN() { decodeOffset(BufferSSN, screenSurface, length); free(BufferSSN); waitFrameSSN(); + byte *screenBuffer = (byte *)_system->lockScreen()->pixels; if (FrameSSN) - mixVideo(VGA, screenSurface); + mixVideo(screenBuffer, screenSurface); else - memcpy(VGA, screenSurface, 64000); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + memcpy(screenBuffer, screenSurface, 64000); + + _system->unlockScreen(); _system->updateScreen(); FrameSSN++; } diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 8284112c1e..c9912f25d2 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -1866,69 +1866,68 @@ void DrasculaEngine::enterRoom(int roomIndex) { } void DrasculaEngine::clearRoom() { - memset(VGA, 0, 64000); _system->fillScreen(0); _system->updateScreen(); } -bool DrasculaEngine::exitRoom(int l) { - debug(2, "Exiting room from door %d", l); +bool DrasculaEngine::exitRoom(int doorNumber) { + debug(2, "Exiting room from door %d", doorNumber); int roomNum = 0; // Player can't exit the inn in chapter 1 - if (currentChapter == 1 && objectNum[l] == 104) { + if (currentChapter == 1 && objectNum[doorNumber] == 104) { return false; } - if (currentChapter == 1 && objectNum[l] == 105 && flags[0] == 0) { + if (currentChapter == 1 && objectNum[doorNumber] == 105 && flags[0] == 0) { talk(442); return false; } - updateDoor(l); - if (isDoor[l] != 0 && - ((currentChapter != 3 && currentChapter != 5) || visible[l] == 1)) { + updateDoor(doorNumber); + if (isDoor[doorNumber] != 0 && + ((currentChapter != 3 && currentChapter != 5) || visible[doorNumber] == 1)) { hideCursor(); - gotoObject(roomObjX[l], roomObjY[l]); + gotoObject(roomObjX[doorNumber], roomObjY[doorNumber]); if (currentChapter != 2) { - trackProtagonist = trackObj[l]; + trackProtagonist = trackObj[doorNumber]; updateRoom(); updateScreen(); } characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = roomExits[l]; + trackProtagonist = trackCharacter_alkeva[doorNumber]; + objExit = roomExits[doorNumber]; doBreak = 1; previousMusic = roomMusic; // Object specific actions - if (currentChapter == 1 && objectNum[l] == 105) { + if (currentChapter == 1 && objectNum[doorNumber] == 105) { animation_2_1(); return true; } else if (currentChapter == 2) { - if (objectNum[l] == 136) + if (objectNum[doorNumber] == 136) animation_2_2(); - if (objectNum[l] == 124) { + if (objectNum[doorNumber] == 124) { gotoObject(163, 106); gotoObject(287, 101); trackProtagonist = 0; } - if (objectNum[l] == 173) { + if (objectNum[doorNumber] == 173) { animation_35_2(); return true; } - if (objectNum[l] == 146 && flags[39] == 1) { + if (objectNum[doorNumber] == 146 && flags[39] == 1) { flags[5] = 1; flags[11] = 1; } - if (objectNum[l] == 176 && flags[29] == 1) { + if (objectNum[doorNumber] == 176 && flags[29] == 1) { flags[29] = 0; removeObject(kItemEarWithEarPlug); addObject(kItemEarplugs); } - } else if (currentChapter == 4 && objectNum[l] == 108) { + } else if (currentChapter == 4 && objectNum[doorNumber] == 108) { gotoObject(171, 78); } @@ -1936,7 +1935,7 @@ bool DrasculaEngine::exitRoom(int l) { hare_se_ve = 1; clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); + sscanf(_targetSurface[doorNumber], "%d", &roomNum); curX = -1; enterRoom(roomNum); diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index 7c94938c9b..4b649ce8db 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -803,6 +803,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha p = 0; + memset(buf, 0, sizeof(buf)); talkInit(filename); do { diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 99cf7c1193..3b7a61d485 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -35,21 +35,22 @@ namespace Gob { DataStream::DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose) { _io = &io; - _handle = handle; - _size = dSize; + + _handle = handle; + _size = dSize; _dispose = dispose; - _data = 0; + _data = 0; _stream = 0; } DataStream::DataStream(byte *buf, uint32 dSize, bool dispose) { - _data = buf; - _size = dSize; - _stream = new Common::MemoryReadStream(_data, _size); + _data = buf; + _size = dSize; + _stream = new Common::MemoryReadStream(_data, _size); _dispose = dispose; - _io = 0; + _io = 0; _handle = -1; } @@ -84,7 +85,7 @@ int32 DataStream::size() const { bool DataStream::seek(int32 offset, int whence) { if (_stream) return _stream->seek(offset, whence); - else if ((_handle < 50) || (_handle >= 128)) + else if (!_io->isDataFileChunk(_handle)) return _io->file_getHandle(_handle)->seek(offset, whence); else { _io->seekChunk(_handle, offset, whence); @@ -103,7 +104,7 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { if (_stream) return _stream->read(dataPtr, dataSize); - if ((_handle < 50) || (_handle >= 128)) + if (!_io->isDataFileChunk(_handle)) return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); byte *data = (byte *) dataPtr; @@ -111,7 +112,7 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { while (dataSize > 0x3FFF) { _io->readChunk(_handle, (byte *) data, 0x3FFF); dataSize -= 0x3FFF; - data += 0x3FFF; + data += 0x3FFF; haveRead += 0x3FFF; } _io->readChunk(_handle, (byte *) data, dataSize); @@ -121,11 +122,10 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { DataIO::DataIO(GobEngine *vm) : _vm(vm) { for (int i = 0; i < MAX_DATA_FILES; i++) { - _dataFiles[i] = 0; - _numDataChunks[i] = 0; + _dataFiles[i] = 0; + _numDataChunks[i] = 0; _dataFileHandles[i] = -1; } - _packedSize = 0; } DataIO::~DataIO() { @@ -136,6 +136,46 @@ DataIO::~DataIO() { } } +bool DataIO::isDataFileChunk(int16 handle) const { + return (handle >= 50) && (handle < 128); +} + +bool DataIO::isPacked(int16 handle) const { + if (!isDataFileChunk(handle)) + return false; + + return _chunk[getIndex(handle)]->packed != 0; +} + +int DataIO::getFile(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return (handle - 50) / 10; +} + +int DataIO::getSlot(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return (handle - 50) % 10; +} + +int DataIO::getIndex(int16 handle) const { + if (!isDataFileChunk(handle)) + return -1; + + return getIndex(getFile(handle), getSlot(handle)); +} + +int DataIO::getIndex(int file, int slot) const { + return file * MAX_SLOT_COUNT + slot; +} + +int16 DataIO::getHandle(int file, int slot) const { + return file * 10 + slot + 50; +} + int32 DataIO::unpackData(byte *src, byte *dest) { uint32 realSize; uint32 counter; @@ -222,13 +262,11 @@ int16 DataIO::file_open(const char *path) { } int16 DataIO::getChunk(const char *chunkName) { - int16 slot; - struct ChunkDesc *dataDesc; - for (int16 file = 0; file < MAX_DATA_FILES; file++) { if (_dataFiles[file] == 0) return -1; + int16 slot; for (slot = 0; slot < MAX_SLOT_COUNT; slot++) if (_chunkPos[file * MAX_SLOT_COUNT + slot] == -1) break; @@ -238,59 +276,55 @@ int16 DataIO::getChunk(const char *chunkName) { return -1; } - dataDesc = _dataFiles[file]; + ChunkDesc *dataDesc = _dataFiles[file]; for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; - _isCurrentSlot[file * MAX_SLOT_COUNT + slot] = false; - _chunkSize[file * MAX_SLOT_COUNT + slot] = dataDesc->size; - _chunkOffset[file * MAX_SLOT_COUNT + slot] = dataDesc->offset; - _chunkPos[file * MAX_SLOT_COUNT + slot] = 0; - return file * 10 + slot + 50; + int index = getIndex(file, slot); + + _isCurrentSlot[index] = false; + _chunk [index] = dataDesc; + _chunkPos [index] = 0; + + return getHandle(file, slot); } } return -1; } char DataIO::freeChunk(int16 handle) { - if ((handle >= 50) && (handle < 128)) { - handle -= 50; - _chunkPos[(handle / 10) * MAX_SLOT_COUNT + (handle % 10)] = -1; + if (isDataFileChunk(handle)) { + _chunkPos[getIndex(handle)] = -1; return 0; } return 1; } int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { - int16 file; - int16 slot; - int16 i; - int32 offset; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return -2; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; - int index = file * MAX_SLOT_COUNT + slot; + int file = getFile(handle); + int slot = getSlot(handle); + int index = getIndex(file, slot); - _chunkPos[index] = CLIP<int32>(_chunkPos[index], 0, _chunkSize[index]); + _chunkPos[index] = CLIP<int32>(_chunkPos[index], 0, _chunk[index]->size); if (!_isCurrentSlot[index]) { - for (i = 0; i < MAX_SLOT_COUNT; i++) + for (int16 i = 0; i < MAX_SLOT_COUNT; i++) _isCurrentSlot[file * MAX_SLOT_COUNT + i] = false; - offset = _chunkOffset[index] + _chunkPos[index]; + int32 offset = _chunk[index]->offset + _chunkPos[index]; - debugC(7, kDebugFileIO, "seek: %d, %d", _chunkOffset[index], _chunkPos[index]); + debugC(7, kDebugFileIO, "seek: %d, %d", _chunk[index]->offset, _chunkPos[index]); file_getHandle(_dataFileHandles[file])->seek(offset, SEEK_SET); } _isCurrentSlot[index] = true; - if ((_chunkPos[index] + size) > (_chunkSize[index])) - size = _chunkSize[index] - _chunkPos[index]; + if ((_chunkPos[index] + size) > (int32) (_chunk[index]->size)) + size = _chunk[index]->size - _chunkPos[index]; file_getHandle(_dataFileHandles[file])->read(buf, size); _chunkPos[index] += size; @@ -298,15 +332,12 @@ int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { } int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { - int16 file; - int16 slot; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return -1; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; - int index = file * MAX_SLOT_COUNT + slot; + int file = getFile(handle); + int slot = getSlot(handle); + int index = getIndex(file, slot); _isCurrentSlot[index] = false; if (from == SEEK_SET) @@ -314,50 +345,45 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { else if (from == SEEK_CUR) _chunkPos[index] += pos; else if (from == SEEK_END) - _chunkPos[index] = _chunkSize[index] - pos; + _chunkPos[index] = _chunk[index]->size - pos; return _chunkPos[index]; } uint32 DataIO::getChunkPos(int16 handle) const { - int16 file; - int16 slot; - - if ((handle < 50) || (handle >= 128)) + if (!isDataFileChunk(handle)) return 0xFFFFFFFF; - file = (handle - 50) / 10; - slot = (handle - 50) % 10; + int file = getFile(handle); + int slot = getSlot(handle); return _chunkPos[file * MAX_SLOT_COUNT + slot]; } -int32 DataIO::getChunkSize(const char *chunkName) { - int16 file; - struct ChunkDesc *dataDesc; - int16 slot; - int32 realSize; - - for (file = 0; file < MAX_DATA_FILES; file++) { +int32 DataIO::getChunkSize(const char *chunkName, int32 &packSize) { + for (int16 file = 0; file < MAX_DATA_FILES; file++) { if (_dataFiles[file] == 0) return -1; - dataDesc = _dataFiles[file]; + ChunkDesc *dataDesc = _dataFiles[file]; for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; if (dataDesc->packed == 0) { - _packedSize = -1; + packSize = -1; return dataDesc->size; } - for (slot = 0; slot < MAX_SLOT_COUNT; slot++) + for (int16 slot = 0; slot < MAX_SLOT_COUNT; slot++) _isCurrentSlot[slot] = false; + int32 realSize; + file_getHandle(_dataFileHandles[file])->seek(dataDesc->offset, SEEK_SET); realSize = file_getHandle(_dataFileHandles[file])->readUint32LE(); - _packedSize = dataDesc->size; + packSize = dataDesc->size; + return realSize; } } @@ -365,10 +391,7 @@ int32 DataIO::getChunkSize(const char *chunkName) { } void DataIO::openDataFile(const char *src, bool itk) { - ChunkDesc *dataDesc; char path[128]; - int16 file; - char *fakeTotPtr; strncpy0(path, src, 127); if (!strchr(path, '.')) { @@ -376,6 +399,7 @@ void DataIO::openDataFile(const char *src, bool itk) { strcat(path, ".stk"); } + int16 file; for (file = 0; file < MAX_DATA_FILES; file++) if (_dataFiles[file] == 0) break; @@ -388,17 +412,17 @@ void DataIO::openDataFile(const char *src, bool itk) { if (_dataFileHandles[file] == -1) error("DataIO::openDataFile(): Can't open data file \"%s\"", path); - _dataFileItk[file] = itk; + _dataFileItk [file] = itk; _numDataChunks[file] = file_getHandle(_dataFileHandles[file])->readUint16LE(); debugC(7, kDebugFileIO, "DataChunks: %d [for %s]", _numDataChunks[file], path); - dataDesc = new ChunkDesc[_numDataChunks[file]]; + ChunkDesc *dataDesc = new ChunkDesc[_numDataChunks[file]]; _dataFiles[file] = dataDesc; for (int i = 0; i < _numDataChunks[file]; i++) { file_getHandle(_dataFileHandles[file])->read(dataDesc[i].chunkName, 13); - dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE(); + dataDesc[i].size = file_getHandle(_dataFileHandles[file])->readUint32LE(); dataDesc[i].offset = file_getHandle(_dataFileHandles[file])->readUint32LE(); dataDesc[i].packed = file_getHandle(_dataFileHandles[file])->readByte(); @@ -410,7 +434,7 @@ void DataIO::openDataFile(const char *src, bool itk) { Util::replaceChar(dataDesc[i].chunkName, (char) 0x92, 'T'); // Geisha use 0ot files, which are compressed TOT files without the packed byte set. - fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT"); + char *fakeTotPtr = strstr(dataDesc[i].chunkName, "0OT"); if (fakeTotPtr != 0) { strncpy(fakeTotPtr, "TOT", 3); dataDesc[i].packed = 1; @@ -436,33 +460,29 @@ void DataIO::closeDataFile(bool itk) { } byte *DataIO::getUnpackedData(const char *name) { - int32 realSize; - int16 chunk; - byte *unpackBuf; - byte *packBuf; - byte *ptr; - int32 sizeLeft; - - realSize = getChunkSize(name); - if ((_packedSize == -1) || (realSize == -1)) + int32 realSize, packSize; + + realSize = getChunkSize(name, packSize); + + if ((packSize == -1) || (realSize == -1)) return 0; - chunk = getChunk(name); + int16 chunk = getChunk(name); if (chunk == -1) return 0; - unpackBuf = new byte[realSize]; + byte *unpackBuf = new byte[realSize]; assert(unpackBuf); - packBuf = new byte[_packedSize]; + byte *packBuf = new byte[packSize]; assert(packBuf); - sizeLeft = _packedSize; - ptr = packBuf; + int32 sizeLeft = packSize; + byte *ptr = packBuf; while (sizeLeft > 0x4000) { readChunk(chunk, ptr, 0x4000); sizeLeft -= 0x4000; - ptr += 0x4000; + ptr += 0x4000; } readChunk(chunk, ptr, sizeLeft); freeChunk(chunk); @@ -478,9 +498,7 @@ void DataIO::closeData(int16 handle) { } int16 DataIO::openData(const char *path) { - int16 handle; - - handle = getChunk(path); + int16 handle = getChunk(path); if (handle >= 0) return handle; @@ -492,7 +510,6 @@ bool DataIO::existData(const char *path) { return false; int16 handle = openData(path); - if (handle < 0) return false; @@ -510,9 +527,7 @@ DataStream *DataIO::openAsStream(int16 handle, bool dispose) { } uint32 DataIO::getPos(int16 handle) { - uint32 resPos; - - resPos = getChunkPos(handle); + uint32 resPos = getChunkPos(handle); if (resPos != 0xFFFFFFFF) return resPos; @@ -520,9 +535,7 @@ uint32 DataIO::getPos(int16 handle) { } void DataIO::seekData(int16 handle, int32 pos, int16 from) { - int32 resPos; - - resPos = seekChunk(handle, pos, from); + int32 resPos = seekChunk(handle, pos, from); if (resPos != -1) return; @@ -530,9 +543,7 @@ void DataIO::seekData(int16 handle, int32 pos, int16 from) { } int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { - int32 res; - - res = readChunk(handle, buf, size); + int16 res = readChunk(handle, buf, size); if (res >= 0) return res; @@ -541,45 +552,42 @@ int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { int32 DataIO::getDataSize(const char *name) { char buf[128]; - int32 chunkSz; - Common::File file; strncpy0(buf, name, 127); - chunkSz = getChunkSize(buf); - if (chunkSz >= 0) - return chunkSz; + int32 chunkSize, packSize; + + chunkSize = getChunkSize(buf, packSize); + if (chunkSize >= 0) + return chunkSize; + Common::File file; if (!file.open(buf)) error("DataIO::getDataSize(): Can't find data \"%s\"", name); - chunkSz = file.size(); + chunkSize = file.size(); file.close(); - return chunkSz; + return chunkSize; } byte *DataIO::getData(const char *path) { - byte *data; - byte *ptr; - int32 size; - int16 handle; - - data = getUnpackedData(path); + byte *data = getUnpackedData(path); if (data) return data; - size = getDataSize(path); + int32 size = getDataSize(path); + data = new byte[size]; assert(data); - handle = openData(path); + int16 handle = openData(path); - ptr = data; + byte *ptr = data; while (size > 0x4000) { readData(handle, ptr, 0x4000); size -= 0x4000; - ptr += 0x4000; + ptr += 0x4000; } readData(handle, ptr, size); closeData(handle); @@ -588,12 +596,26 @@ byte *DataIO::getData(const char *path) { DataStream *DataIO::getDataStream(const char *path) { if (!existData(path)) + return 0; + + int16 handle = openData(path); + if (handle < 0) return 0; - uint32 size = getDataSize(path); - byte *data = getData(path); + if (isDataFileChunk(handle) && isPacked(handle)) { + // It's a packed chunk in the data files, packed, + // so we have to read it in completely and unpack it + + closeData(handle); + + uint32 size = getDataSize(path); + byte *data = getData(path); + + return new DataStream(data, size); - return new DataStream(data, size); + } else + // Otherwise, we can just return a stream + return openAsStream(handle, true); } } // End of namespace Gob diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index 1f55cac90d..6a86667e1b 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -26,16 +26,14 @@ #ifndef GOB_DATAIO_H #define GOB_DATAIO_H - #include "common/endian.h" - #include "common/file.h" namespace Gob { -#define MAX_FILES 30 -#define MAX_DATA_FILES 8 -#define MAX_SLOT_COUNT 8 +#define MAX_FILES 30 +#define MAX_DATA_FILES 8 +#define MAX_SLOT_COUNT 8 class DataIO; @@ -56,20 +54,20 @@ public: private: DataIO *_io; - int16 _handle; - uint32 _size; - byte *_data; + int16 _handle; + uint32 _size; + byte *_data; + bool _dispose; Common::MemoryReadStream *_stream; - bool _dispose; }; class DataIO { public: struct ChunkDesc { - char chunkName[13]; + char chunkName[13]; uint32 size; uint32 offset; - byte packed; + byte packed; ChunkDesc() : size(0), offset(0), packed(0) { chunkName[0] = 0; } }; @@ -77,10 +75,13 @@ public: void openDataFile(const char *src, bool itk = 0); void closeDataFile(bool itk = 0); + byte *getUnpackedData(const char *name); - void closeData(int16 handle); + + void closeData(int16 handle); int16 openData(const char *path); - bool existData(const char *path); + bool existData(const char *path); + DataStream *openAsStream(int16 handle, bool dispose = false); int32 getDataSize(const char *name); @@ -92,34 +93,47 @@ public: protected: Common::File _filesHandles[MAX_FILES]; - struct ChunkDesc *_dataFiles[MAX_DATA_FILES]; - uint16 _numDataChunks[MAX_DATA_FILES]; - int16 _dataFileHandles[MAX_DATA_FILES]; - bool _dataFileItk[MAX_DATA_FILES]; - int32 _chunkPos[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _chunkOffset[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _chunkSize[MAX_SLOT_COUNT * MAX_DATA_FILES]; - bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; - int32 _packedSize; + + ChunkDesc *_dataFiles [MAX_DATA_FILES]; + uint16 _numDataChunks [MAX_DATA_FILES]; + int16 _dataFileHandles[MAX_DATA_FILES]; + bool _dataFileItk [MAX_DATA_FILES]; + + ChunkDesc *_chunk [MAX_SLOT_COUNT * MAX_DATA_FILES]; + int32 _chunkPos [MAX_SLOT_COUNT * MAX_DATA_FILES]; + bool _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; class GobEngine *_vm; + bool isDataFileChunk(int16 handle) const; + bool isPacked (int16 handle) const; + + int getFile (int16 handle) const; + int getSlot (int16 handle) const; + int getIndex(int16 handle) const; + + int getIndex (int file, int slot) const; + int16 getHandle(int file, int slot) const; + int16 file_open(const char *path); Common::File *file_getHandle(int16 handle); const Common::File *file_getHandle(int16 handle) const; int16 getChunk(const char *chunkName); - char freeChunk(int16 handle); + char freeChunk(int16 handle); int32 readChunk(int16 handle, byte *buf, uint16 size); int16 seekChunk(int16 handle, int32 pos, int16 from); + uint32 getChunkPos(int16 handle) const; - int32 getChunkSize(const char *chunkName); + + int32 getChunkSize(const char *chunkName, int32 &packSize); uint32 getPos(int16 handle); - void seekData(int16 handle, int32 pos, int16 from); + void seekData(int16 handle, int32 pos, int16 from); + int32 readData(int16 handle, byte *buf, uint16 size); -friend class DataStream; + friend class DataStream; }; } // End of namespace Gob diff --git a/engines/gob/demos/demoplayer.cpp b/engines/gob/demos/demoplayer.cpp index 7f65721ce5..13b7aa5327 100644 --- a/engines/gob/demos/demoplayer.cpp +++ b/engines/gob/demos/demoplayer.cpp @@ -34,6 +34,7 @@ #include "gob/draw.h" #include "gob/inter.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -186,6 +187,30 @@ void DemoPlayer::playVideo(const char *fileName) { free(filePtr); } +void DemoPlayer::playADL(const char *params) { + const char *end; + + end = strchr(params, ' '); + if (!end) + end = params + strlen(params); + + Common::String fileName(params, end); + bool waitEsc = true; + int32 repeat = -1; + + if (*end != '\0') { + const char *start = end + 1; + + waitEsc = (*start != '0'); + + end = strchr(start, ' '); + if (end) + repeat = atoi(end + 1); + } + + playADL(fileName, waitEsc, repeat); +} + void DemoPlayer::playVideoNormal() { _vm->_vidPlayer->primaryPlay(); } @@ -233,6 +258,26 @@ void DemoPlayer::playVideoDoubled() { } } +void DemoPlayer::playADL(const Common::String &fileName, bool waitEsc, int32 repeat) { + debugC(1, kDebugDemo, "Playing ADL \"%s\" (%d, %d)", fileName.c_str(), waitEsc, repeat); + + _vm->_sound->adlibUnload(); + _vm->_sound->adlibLoadADL(fileName.c_str()); + _vm->_sound->adlibSetRepeating(repeat); + _vm->_sound->adlibPlay(); + + if (!waitEsc) + return; + + int16 key = 0; + while (!_vm->shouldQuit() && (key != kKeyEscape) && _vm->_sound->adlibIsPlaying()) { + _vm->_util->longDelay(1); + while (_vm->_util->checkKey(key)) + if (key == kKeyEscape) + break; + } +} + void DemoPlayer::evaluateVideoMode(const char *mode) { debugC(2, kDebugDemo, "Video mode \"%s\"", mode); diff --git a/engines/gob/demos/demoplayer.h b/engines/gob/demos/demoplayer.h index 64c98b58c5..f0672b9645 100644 --- a/engines/gob/demos/demoplayer.h +++ b/engines/gob/demos/demoplayer.h @@ -57,9 +57,11 @@ protected: void evaluateVideoMode(const char *mode); void clearScreen(); void playVideo(const char *fileName); + void playADL(const char *params); void playVideoNormal(); void playVideoDoubled(); + void playADL(const Common::String &fileName, bool waitEsc = true, int32 repeat = -1); private: enum ScriptSource { diff --git a/engines/gob/demos/scnplayer.cpp b/engines/gob/demos/scnplayer.cpp index 616da3272a..bf81773a15 100644 --- a/engines/gob/demos/scnplayer.cpp +++ b/engines/gob/demos/scnplayer.cpp @@ -66,6 +66,8 @@ bool SCNPlayer::playStream(Common::SeekableReadStream &scn) { _rebase0 = true; } else if (lineStartsWith(line, "REBASE0:OFF")) { _rebase0 = false; + } else if (lineStartsWith(line, "ADL ")) { + playADL(line.c_str() + 4); } // Mind user input diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 61c17b16f8..6088d622f8 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -2750,7 +2750,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2764,7 +2764,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2778,7 +2778,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2792,7 +2792,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2806,7 +2806,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2820,7 +2820,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2834,7 +2834,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2848,7 +2848,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2862,7 +2862,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2876,7 +2876,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2890,7 +2890,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2904,7 +2904,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2918,7 +2918,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2932,7 +2932,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2946,7 +2946,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2960,7 +2960,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2974,7 +2974,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2988,7 +2988,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3002,7 +3002,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3016,7 +3016,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3030,7 +3030,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3044,7 +3044,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3058,7 +3058,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3072,7 +3072,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3086,7 +3086,7 @@ static const GOBGameDescription gameDescriptions[] = { PL_POL, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSUBTITLES | GUIO_NOSPEECH + GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -4299,7 +4299,7 @@ static const GOBGameDescription fallbackDescs[] = { GUIO_NONE }, kGameTypeUrban, - kFeatures640 | kFeaturesSCNDemo, + kFeaturesAdlib | kFeatures640 | kFeaturesSCNDemo, "", "", 8 } }; diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index fb3cb9bbcd..46f75f67aa 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -303,6 +303,8 @@ void Draw::dirtiedRect(SurfaceDescPtr surface, invalidateRect(left, top, right, bottom); else if (surface == _frontSurface) _vm->_video->dirtyRectsAdd(left, top, right, bottom); + else if (_vm->_video->_splitSurf && (surface == _vm->_video->_splitSurf)) + _vm->_video->retrace(); } void Draw::initSpriteSurf(int16 index, int16 width, int16 height, diff --git a/engines/gob/draw.h b/engines/gob/draw.h index ba32df0c3e..1da6ba4b74 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -39,7 +39,7 @@ namespace Gob { #define RENDERFLAG_USEDELTAS 0x0010 #define RENDERFLAG_UNKNOWN 0x0080 #define RENDERFLAG_NOBLITINVALIDATED 0x0200 -#define RENDERFLAG_SKIPOPTIONALTEXT 0x0400 +#define RENDERFLAG_NOSUBTITLES 0x0400 #define RENDERFLAG_FROMSPLIT 0x0800 #define RENDERFLAG_DOUBLECOORDS 0x1000 @@ -77,6 +77,9 @@ public: int16 _backDeltaX; int16 _backDeltaY; + int16 _subtitleFont; + int16 _subtitleColor; + FontToSprite _fontToSprite[4]; Font *_fonts[kFontCount]; diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp index e2cfcb613d..719945fd6f 100644 --- a/engines/gob/draw_v1.cpp +++ b/engines/gob/draw_v1.cpp @@ -318,6 +318,8 @@ void Draw_v1::spriteOperation(int16 operation) { int16 perLine; Resource *resource; + operation &= 0x0F; + if (_sourceSurface >= 100) _sourceSurface -= 80; if (_destSurface >= 100) diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 8fe70589a7..a1074d7ecb 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -216,7 +216,9 @@ void Draw_v2::printTotText(int16 id) { dataPtr = textItem->getData(); ptr = dataPtr; - if ((_renderFlags & RENDERFLAG_SKIPOPTIONALTEXT) && (ptr[1] & 0x80)) { + bool isSubtitle = (ptr[1] & 0x80) != 0; + + if (isSubtitle && !_vm->_global->_doSubtitles) { delete textItem; return; } @@ -398,10 +400,15 @@ void Draw_v2::printTotText(int16 id) { } else { _destSpriteX = offX; _destSpriteY = offY; - _fontIndex = fontIndex; - _frontColor = frontColor; + _fontIndex = fontIndex; + _frontColor = frontColor; _textToPrint = str; + if (isSubtitle) { + _fontIndex = _subtitleFont; + _frontColor = _subtitleColor; + } + if (_needAdjust != 2) { if ((_destSpriteX >= destX) && (_destSpriteY >= destY) && (((_fonts[_fontIndex]->getCharHeight() / 2) + _destSpriteY - 1) <= spriteBottom)) { @@ -449,6 +456,10 @@ void Draw_v2::printTotText(int16 id) { ptr++; offX = destX + (int16)READ_LE_UINT16(ptr); offY = destY + (int16)READ_LE_UINT16(ptr + 2); + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { + offX += (int16)READ_LE_UINT16(ptr); + offY += (int16)READ_LE_UINT16(ptr + 2); + } ptr += 4; break; @@ -457,11 +468,19 @@ void Draw_v2::printTotText(int16 id) { fontIndex = ((*ptr & 0xF0) >> 4) & 7; frontColor = *ptr & 0x0F; ptr++; + + if (isSubtitle) { + _subtitleFont = fontIndex; + _subtitleColor = frontColor; + } break; case 4: ptr++; frontColor = *ptr++; + + if (isSubtitle) + _subtitleColor = frontColor; break; case 6: @@ -502,8 +521,7 @@ void Draw_v2::printTotText(int16 id) { case 10: str[0] = (char) 255; - WRITE_LE_UINT16((uint16 *) (str + 1), - ptr - _vm->_game->_resources->getTexts()); + WRITE_LE_UINT16(str + 1, ptr - _vm->_game->_resources->getTexts()); str[3] = 0; ptr++; for (int i = *ptr++; i > 0; i--) { diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index d201019d08..4e2bd223b7 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -275,6 +275,12 @@ void Game::playTot(int16 skipPlay) { _vm->_draw->_fontToSprite[i].height = -1; } + // Gobliiins music stopping + if (_vm->getGameType() == kGameTypeGob1) { + _vm->_sound->adlibStop(); + _vm->_sound->cdStop(); + } + _vm->_mult->initAll(); _vm->_mult->zeroMultData(); diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp index 2969ed0870..f4f1303386 100644 --- a/engines/gob/global.cpp +++ b/engines/gob/global.cpp @@ -124,6 +124,8 @@ Global::Global(GobEngine *vm) : _vm(vm) { _speedFactor = 1; + _doSubtitles = false; + _noCd = false; } diff --git a/engines/gob/global.h b/engines/gob/global.h index 7849490107..5830e3e58c 100644 --- a/engines/gob/global.h +++ b/engines/gob/global.h @@ -141,6 +141,8 @@ public: // Can be 1, 2 or 3 for normal, double and triple speed, respectively uint8 _speedFactor; + bool _doSubtitles; + bool _noCd; Global(GobEngine *vm); diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index fa4f04eab8..082345e675 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -25,6 +25,7 @@ #include "common/endian.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "base/plugins.h" #include "common/config-manager.h" @@ -129,7 +130,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) { Common::addDebugChannel(kDebugHotspots, "Hotspots", "Hotspots debug level"); Common::addDebugChannel(kDebugDemo, "Demo", "Demo script debug level"); - syst->getEventManager()->registerRandomSource(_rnd, "gob"); + g_eventRec.registerRandomSource(_rnd, "gob"); } GobEngine::~GobEngine() { @@ -302,7 +303,6 @@ void GobEngine::pauseEngineIntern(bool pause) { } else { uint32 duration = _system->getMillis() - _pauseStart; - _vidPlayer->notifyPaused(duration); _util->notifyPaused(duration); _game->_startTimeKey += duration; @@ -314,6 +314,12 @@ void GobEngine::pauseEngineIntern(bool pause) { _mixer->pauseAll(pause); } +void GobEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + + _init->updateConfig(); +} + void GobEngine::pauseGame() { pauseEngineIntern(true); @@ -329,139 +335,138 @@ bool GobEngine::initGameParts() { _saveLoad = 0; - _global = new Global(this); - _util = new Util(this); - _dataIO = new DataIO(this); - _palAnim = new PalAnim(this); + _global = new Global(this); + _util = new Util(this); + _dataIO = new DataIO(this); + _palAnim = new PalAnim(this); _vidPlayer = new VideoPlayer(this); - _sound = new Sound(this); - _game = new Game(this); + _sound = new Sound(this); + _game = new Game(this); switch (_gameType) { case kGameTypeGeisha: case kGameTypeAdibouUnknown: case kGameTypeGob1: - _init = new Init_v1(this); - _video = new Video_v1(this); - _inter = new Inter_v1(this); - _mult = new Mult_v1(this); - _draw = new Draw_v1(this); - _map = new Map_v1(this); - _goblin = new Goblin_v1(this); - _scenery = new Scenery_v1(this); + _init = new Init_v1(this); + _video = new Video_v1(this); + _inter = new Inter_v1(this); + _mult = new Mult_v1(this); + _draw = new Draw_v1(this); + _map = new Map_v1(this); + _goblin = new Goblin_v1(this); + _scenery = new Scenery_v1(this); break; case kGameTypeFascination: - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_Fascination(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_Fascination(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); break; case kGameTypeWeen: case kGameTypeGob2: - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_v2(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); break; case kGameTypeBargon: - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_Bargon(this); - _mult = new Mult_v2(this); - _draw = new Draw_Bargon(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_Bargon(this); + _mult = new Mult_v2(this); + _draw = new Draw_Bargon(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); break; case kGameTypeGob3: case kGameTypeInca2: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v3(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v3(this); - _scenery = new Scenery_v2(this); + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v3(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), SaveLoad_v3::kScreenshotTypeGob3); break; case kGameTypeLostInTime: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v3(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v3(this); - _scenery = new Scenery_v2(this); + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v3(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), SaveLoad_v3::kScreenshotTypeLost); break; case kGameTypeWoodruff: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v4(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v4(this); - _goblin = new Goblin_v4(this); - _scenery = new Scenery_v2(this); + _init = new Init_v4(this); + _video = new Video_v2(this); + _inter = new Inter_v4(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); break; case kGameTypeDynasty: - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v5(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v4(this); - _goblin = new Goblin_v4(this); - _scenery = new Scenery_v2(this); + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v5(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad(this); break; case kGameTypeAdibou4: case kGameTypeUrban: - _init = new Init_v6(this); - _video = new Video_v6(this); - _inter = new Inter_v6(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v4(this); - _goblin = new Goblin_v4(this); - _scenery = new Scenery_v2(this); + _init = new Init_v6(this); + _video = new Video_v6(this); + _inter = new Inter_v6(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v6(this, _targetName.c_str()); break; case kGameTypePlaytoon: case kGameTypePlaytnCk: case kGameTypeBambou: - _init = new Init_v2(this); - _video = new Video_v2(this); -// _inter = new Inter_Playtoons(this); - _inter = new Inter_v6(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_v6(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_Playtoons(this); break; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 02f6af51bf..84ff707877 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -75,8 +75,6 @@ class SaveLoad; #define GET_VAR_FSTR(var) _vm->_inter->_variables->getAddressVarString(var) #define GET_VARO_FSTR(off) _vm->_inter->_variables->getAddressOffString(off) -#define VAR_ADDRESS(var) _vm->_inter->_variables->getAddressVar32(var) - #define WRITE_VAR_OFFSET(off, val) WRITE_VARO_UINT32((off), (val)) #define WRITE_VAR(var, val) WRITE_VAR_UINT32((var), (val)) #define VAR_OFFSET(off) READ_VARO_UINT32(off) @@ -165,6 +163,7 @@ private: virtual Common::Error run(); virtual bool hasFeature(EngineFeature f) const; virtual void pauseEngineIntern(bool pause); + virtual void syncSoundSettings(); bool initGameParts(); void deinitGameParts(); diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index faf85a5b41..834e9b8553 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -49,6 +49,9 @@ Init::Init(GobEngine *vm) : _vm(vm) { _palDesc = 0; } +Init::~Init() { +} + void Init::cleanup() { _vm->_video->freeDriver(); _vm->_global->_primarySurfDesc.reset(); @@ -87,6 +90,7 @@ void Init::initGame() { char buffer[128]; initVideo(); + updateConfig(); if (!_vm->isDemo()) { if (_vm->_dataIO->existData(_vm->_startStk.c_str())) @@ -206,4 +210,7 @@ void Init::initGame() { cleanup(); } +void Init::updateConfig() { +} + } // End of namespace Gob diff --git a/engines/gob/init.h b/engines/gob/init.h index 60642d0189..c2784a59ac 100644 --- a/engines/gob/init.h +++ b/engines/gob/init.h @@ -32,12 +32,14 @@ namespace Gob { class Init { public: + Init(GobEngine *vm); + virtual ~Init(); + virtual void initGame(); virtual void initVideo() = 0; - Init(GobEngine *vm); - virtual ~Init() {} + virtual void updateConfig(); protected: Video::PalDesc *_palDesc; @@ -50,34 +52,42 @@ protected: class Init_v1 : public Init { public: - virtual void initVideo(); - Init_v1(GobEngine *vm); - virtual ~Init_v1() {} + ~Init_v1(); + + void initVideo(); }; class Init_v2 : public Init_v1 { public: - virtual void initVideo(); - Init_v2(GobEngine *vm); - virtual ~Init_v2() {} + ~Init_v2(); + + void initVideo(); }; class Init_v3 : public Init_v2 { public: - virtual void initVideo(); - Init_v3(GobEngine *vm); - virtual ~Init_v3() {} + ~Init_v3(); + + void initVideo(); }; -class Init_v6 : public Init_v3 { +class Init_v4 : public Init_v3 { public: - virtual void initGame(); + Init_v4(GobEngine *vm); + ~Init_v4(); + + void updateConfig(); +}; +class Init_v6 : public Init_v3 { +public: Init_v6(GobEngine *vm); - virtual ~Init_v6() {} + ~Init_v6(); + + void initGame(); }; } // End of namespace Gob diff --git a/engines/gob/init_v1.cpp b/engines/gob/init_v1.cpp index e482104ff9..50db774734 100644 --- a/engines/gob/init_v1.cpp +++ b/engines/gob/init_v1.cpp @@ -35,6 +35,9 @@ namespace Gob { Init_v1::Init_v1(GobEngine *vm) : Init(vm) { } +Init_v1::~Init_v1() { +} + void Init_v1::initVideo() { if (_vm->_global->_videoMode) _vm->validateVideoMode(_vm->_global->_videoMode); diff --git a/engines/gob/init_v2.cpp b/engines/gob/init_v2.cpp index 4c65b8102c..f89d5a8cfb 100644 --- a/engines/gob/init_v2.cpp +++ b/engines/gob/init_v2.cpp @@ -36,6 +36,9 @@ namespace Gob { Init_v2::Init_v2(GobEngine *vm) : Init_v1(vm) { } +Init_v2::~Init_v2() { +} + void Init_v2::initVideo() { if (_vm->_global->_videoMode) _vm->validateVideoMode(_vm->_global->_videoMode); diff --git a/engines/gob/init_v3.cpp b/engines/gob/init_v3.cpp index 67304b389a..c96005ed5a 100644 --- a/engines/gob/init_v3.cpp +++ b/engines/gob/init_v3.cpp @@ -34,6 +34,9 @@ namespace Gob { Init_v3::Init_v3(GobEngine *vm) : Init_v2(vm) { } +Init_v3::~Init_v3() { +} + void Init_v3::initVideo() { Init_v2::initVideo(); diff --git a/engines/gob/init_v4.cpp b/engines/gob/init_v4.cpp new file mode 100644 index 0000000000..3bd50a494d --- /dev/null +++ b/engines/gob/init_v4.cpp @@ -0,0 +1,45 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/config-manager.h" + +#include "gob/gob.h" +#include "gob/init.h" +#include "gob/global.h" + +namespace Gob { + +Init_v4::Init_v4(GobEngine *vm) : Init_v3(vm) { +} + +Init_v4::~Init_v4() { +} + +void Init_v4::updateConfig() { + _vm->_global->_doSubtitles = ConfMan.getBool("subtitles"); +} + +} // End of namespace Gob diff --git a/engines/gob/init_v6.cpp b/engines/gob/init_v6.cpp index 4b14c8a29c..40b4769e78 100644 --- a/engines/gob/init_v6.cpp +++ b/engines/gob/init_v6.cpp @@ -34,6 +34,9 @@ namespace Gob { Init_v6::Init_v6(GobEngine *vm) : Init_v3(vm) { } +Init_v6::~Init_v6() { +} + void Init_v6::initGame() { _vm->_global->_noCd = false; diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 69c392b198..446d86643d 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -972,6 +972,7 @@ bool Inter_v1::o1_loadTot(OpFuncParams ¶ms) { bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { int index1, index2; + int16 id; byte cmd; Resource *resource; @@ -1116,7 +1117,8 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { case 61: index1 = _vm->_game->_script->readByte(); index2 = (_vm->_game->_script->readByte() - index1 + 1) * 3; - resource = _vm->_game->_resources->getResource(_vm->_game->_script->readInt16()); + id = _vm->_game->_script->readInt16(); + resource = _vm->_game->_resources->getResource(id); if (!resource) break; @@ -1124,6 +1126,13 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { resource->getData() + index1 * 3, index2); delete resource; + // WORKAROUND: The Last Dynasty overwrites the 0. palette entry but depends on it staying black. + if ((_vm->getGameType() == kGameTypeDynasty) && (index1 == 0)) { + _vm->_draw->_vgaPalette[0].red = 0; + _vm->_draw->_vgaPalette[0].green = 0; + _vm->_draw->_vgaPalette[0].blue = 0; + } + if (_vm->_draw->_applyPal) { _vm->_draw->_applyPal = false; _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); @@ -2303,7 +2312,7 @@ void Inter_v1::o1_setItemPos(OpGobParams ¶ms) { void Inter_v1::o1_loadObjects(OpGobParams ¶ms) { params.extraData = _vm->_game->_script->readInt16(); - _vm->_goblin->loadObjects((char *) VAR_ADDRESS(params.extraData)); + _vm->_goblin->loadObjects(_variables->getAddressVarString(params.extraData)); } void Inter_v1::o1_freeObjects(OpGobParams ¶ms) { diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 20f812bb88..19cac86465 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -25,6 +25,8 @@ #include "common/endian.h" +#include "gui/message.h" + #include "sound/mixer.h" #include "sound/mods/infogrames.h" @@ -587,6 +589,11 @@ void Inter_v2::o2_totSub() { if (!scumm_stricmp(totFile, "edit")) _vm->_util->forceMouseUp(); + // WORKAROUND: For some reason, the variable indicating which TOT to load next + // is overwritten in the guard house card game in Woodruff + if ((_vm->getGameType() == kGameTypeWoodruff) && !scumm_stricmp(totFile, "6")) + strcpy(totFile, "EMAP2011"); + flags = _vm->_game->_script->readByte(); _vm->_game->totSub(flags, totFile); } @@ -1297,16 +1304,23 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { size = -1; handle = 1; - mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); + char *file = _vm->_game->_script->getResultStr(); + + // WORKAROUND: For some reason, the variable indicating which TOT to load next + // is overwritten in the guard house card game in Woodruff + if ((_vm->getGameType() == kGameTypeWoodruff) && !scumm_stricmp(file, "6.TOT")) + strcpy(file, "EMAP2011.TOT"); + + mode = _vm->_saveLoad->getSaveMode(file); if (mode == SaveLoad::kSaveModeNone) { - if (_vm->_dataIO->existData(_vm->_game->_script->getResultStr())) - size = _vm->_dataIO->getDataSize(_vm->_game->_script->getResultStr()); + if (_vm->_dataIO->existData(file)) + size = _vm->_dataIO->getDataSize(file); else - warning("File \"%s\" not found", _vm->_game->_script->getResultStr()); + warning("File \"%s\" not found", file); } else if (mode == SaveLoad::kSaveModeSave) - size = _vm->_saveLoad->getSize(_vm->_game->_script->getResultStr()); + size = _vm->_saveLoad->getSize(file); else if (mode == SaveLoad::kSaveModeExists) size = 23; @@ -1314,7 +1328,7 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { handle = -1; debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d", - _vm->_game->_script->getResultStr(), size); + file, size); WRITE_VAR_OFFSET(varOff, handle); WRITE_VAR(16, (uint32) size); @@ -1338,21 +1352,32 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { offset = _vm->_game->_script->getResultInt(); retSize = 0; + char *file = _vm->_game->_script->getResultStr(); + debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)", - _vm->_game->_script->getResultStr(), dataVar, size, offset); + file, dataVar, size, offset); - mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); + mode = _vm->_saveLoad->getSaveMode(file); if (mode == SaveLoad::kSaveModeSave) { + WRITE_VAR(1, 1); - if (_vm->_saveLoad->load(_vm->_game->_script->getResultStr(), dataVar, size, offset)) + + if (!_vm->_saveLoad->load(file, dataVar, size, offset)) { + + GUI::MessageDialog dialog("Failed to load game state from file."); + dialog.runModal(); + + } else WRITE_VAR(1, 0); + return false; + } else if (mode == SaveLoad::kSaveModeIgnore) return false; if (size < 0) { warning("Attempted to read a raw sprite from file \"%s\"", - _vm->_game->_script->getResultStr()); + file); return false ; } else if (size == 0) { dataVar = 0; @@ -1361,13 +1386,13 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { buf = _variables->getAddressOff8(dataVar); - if (_vm->_game->_script->getResultStr()[0] == 0) { + if (file[0] == 0) { WRITE_VAR(1, size); return false; } WRITE_VAR(1, 1); - handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr()); + handle = _vm->_dataIO->openData(file); if (handle < 0) return false; @@ -1408,17 +1433,26 @@ bool Inter_v2::o2_writeData(OpFuncParams ¶ms) { _vm->_game->_script->evalExpr(0); offset = _vm->_game->_script->getResultInt(); + char *file = _vm->_game->_script->getResultStr(); + debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)", - _vm->_game->_script->getResultStr(), dataVar, size, offset); + file, dataVar, size, offset); WRITE_VAR(1, 1); - mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); + mode = _vm->_saveLoad->getSaveMode(file); if (mode == SaveLoad::kSaveModeSave) { - if (_vm->_saveLoad->save(_vm->_game->_script->getResultStr(), dataVar, size, offset)) + + if (!_vm->_saveLoad->save(file, dataVar, size, offset)) { + + GUI::MessageDialog dialog("Failed to save game state to file."); + dialog.runModal(); + + } else WRITE_VAR(1, 0); + } else if (mode == SaveLoad::kSaveModeNone) - warning("Attempted to write to file \"%s\"", _vm->_game->_script->getResultStr()); + warning("Attempted to write to file \"%s\"", file); return false; } diff --git a/engines/gob/map.h b/engines/gob/map.h index 4a211f205d..ba976ff7ac 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -204,14 +204,6 @@ protected: void loadGoblinStates(Common::SeekableReadStream &data, int index); }; -class Map_v4 : public Map_v2 { -public: - virtual void loadMapObjects(const char *avjFile); - - Map_v4(GobEngine *vm); - virtual ~Map_v4(); -}; - } // End of namespace Gob #endif // GOB_MAP_H diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp index 6ceda7ab44..51caad74b8 100644 --- a/engines/gob/map_v2.cpp +++ b/engines/gob/map_v2.cpp @@ -60,7 +60,10 @@ void Map_v2::loadMapObjects(const char *avjFile) { id = _vm->_game->_script->readInt16(); - if (id == -1) { + if (((uint16) id) >= 65520) { + warning("Map_v2::loadMapObjects(): ID >= 65520"); + return; + } else if (id == -1) { _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); return; } @@ -71,13 +74,20 @@ void Map_v2::loadMapObjects(const char *avjFile) { Common::SeekableReadStream &mapData = *resource->stream(); - if (mapData.readByte() == 3) { + _widthByte = mapData.readByte(); + if (_widthByte == 4) { _screenWidth = 640; + _screenHeight = 400; + } else if (_widthByte == 3) { _passWidth = 65; + _screenWidth = 640; + _screenHeight = 200; } else { - _screenWidth = 320; _passWidth = 40; + _screenWidth = 320; + _screenHeight = 200; } + _wayPointsCount = mapData.readByte(); _tilesWidth = mapData.readSint16LE(); _tilesHeight = mapData.readSint16LE(); @@ -85,6 +95,11 @@ void Map_v2::loadMapObjects(const char *avjFile) { _bigTiles = !(_tilesHeight & 0xFF00); _tilesHeight &= 0xFF; + if (_widthByte == 4) { + _screenWidth = mapData.readSint16LE(); + _screenHeight = mapData.readSint16LE(); + } + _mapWidth = _screenWidth / _tilesWidth; _mapHeight = _screenHeight / _tilesHeight; @@ -104,6 +119,11 @@ void Map_v2::loadMapObjects(const char *avjFile) { _wayPoints[i].notWalkable = mapData.readSByte(); } + if (_widthByte == 4) { + _mapWidth = VAR(17); + _passWidth = _mapWidth; + } + // In the original asm, this writes byte-wise into the variables-array tmpPos = mapData.pos(); mapData.seek(passPos); diff --git a/engines/gob/map_v4.cpp b/engines/gob/map_v4.cpp deleted file mode 100644 index 1db3d6a3f8..0000000000 --- a/engines/gob/map_v4.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stream.h" - -#include "gob/gob.h" -#include "gob/map.h" -#include "gob/global.h" -#include "gob/goblin.h" -#include "gob/inter.h" -#include "gob/game.h" -#include "gob/script.h" -#include "gob/resources.h" -#include "gob/mult.h" - -namespace Gob { - -Map_v4::Map_v4(GobEngine *vm) : Map_v2(vm) { -} - -Map_v4::~Map_v4() { -} - -void Map_v4::loadMapObjects(const char *avjFile) { - uint8 wayPointsCount; - int16 var; - int16 id; - int16 mapWidth, mapHeight; - int16 tmp; - byte *variables; - uint32 tmpPos; - uint32 passPos; - - var = _vm->_game->_script->readVarIndex(); - variables = _vm->_inter->_variables->getAddressOff8(var); - - id = _vm->_game->_script->readInt16(); - - if (((uint16) id) >= 65520) { - warning("Woodruff Stub: loadMapObjects ID >= 65520"); - return; - } else if (id == -1) { - _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); - return; - } - - Resource *resource = _vm->_game->_resources->getResource(id); - if (!resource) - return; - - Common::SeekableReadStream &mapData = *resource->stream(); - - _widthByte = mapData.readByte(); - if (_widthByte == 4) { - _screenWidth = 640; - _screenHeight = 400; - } else if (_widthByte == 3) { - _screenWidth = 640; - _screenHeight = 200; - } else { - _screenWidth = 320; - _screenHeight = 200; - } - - _wayPointsCount = mapData.readByte(); - _tilesWidth = mapData.readSint16LE(); - _tilesHeight = mapData.readSint16LE(); - - _bigTiles = !(_tilesHeight & 0xFF00); - _tilesHeight &= 0xFF; - - if (_widthByte == 4) { - _screenWidth = mapData.readSint16LE(); - _screenHeight = mapData.readSint16LE(); - } - - _mapWidth = _screenWidth / _tilesWidth; - _mapHeight = _screenHeight / _tilesHeight; - - passPos = mapData.pos(); - mapData.skip(_mapWidth * _mapHeight); - - if (resource->getData()[0] == 1) - wayPointsCount = _wayPointsCount = 40; - else - wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount; - - delete[] _wayPoints; - _wayPoints = new Point[wayPointsCount]; - for (int i = 0; i < _wayPointsCount; i++) { - _wayPoints[i].x = mapData.readSByte(); - _wayPoints[i].y = mapData.readSByte(); - _wayPoints[i].notWalkable = mapData.readSByte(); - } - - if (_widthByte == 4) - _mapWidth = VAR(17); - - _passWidth = _mapWidth; - - // In the original asm, this writes byte-wise into the variables-array - tmpPos = mapData.pos(); - mapData.seek(passPos); - if ((variables != 0) && - (variables != _vm->_inter->_variables->getAddressOff8(0))) { - - _passMap = (int8 *) variables; - mapHeight = _screenHeight / _tilesHeight; - mapWidth = _screenWidth / _tilesWidth; - - for (int i = 0; i < mapHeight; i++) { - for (int j = 0; j < mapWidth; j++) - setPass(j, i, mapData.readSByte()); - _vm->_inter->_variables->getAddressOff8(var + i * _passWidth); - } - } - mapData.seek(tmpPos); - - tmp = mapData.readSint16LE(); - mapData.skip(tmp * 14); - tmp = mapData.readSint16LE(); - mapData.skip(tmp * 14 + 28); - tmp = mapData.readSint16LE(); - mapData.skip(tmp * 14); - - _vm->_goblin->_gobsCount = tmp; - for (int i = 0; i < _vm->_goblin->_gobsCount; i++) - loadGoblinStates(mapData, i); - - _vm->_goblin->_soundSlotsCount = _vm->_game->_script->readInt16(); - for (int i = 0; i < _vm->_goblin->_soundSlotsCount; i++) - _vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1); - - delete resource; -} - -} // End of namespace Gob diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 611abb6038..26cc4e5d27 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -23,6 +23,7 @@ MODULE_OBJS := \ init_v1.o \ init_v2.o \ init_v3.o \ + init_v4.o \ init_v6.o \ inter.o \ inter_v1.o \ @@ -36,7 +37,6 @@ MODULE_OBJS := \ map.o \ map_v1.o \ map_v2.o \ - map_v4.o \ mult.o \ mult_v1.o \ mult_v2.o \ diff --git a/engines/gob/resources.cpp b/engines/gob/resources.cpp index c52b65f0d7..2f3b1b23e7 100644 --- a/engines/gob/resources.cpp +++ b/engines/gob/resources.cpp @@ -144,8 +144,6 @@ Resources::~Resources() { bool Resources::load(const Common::String &fileName) { unload(); - Common::String fileBase; - _totFile = TOTFile::createFileName(fileName, _hasLOM); if (_hasLOM) { @@ -154,9 +152,9 @@ bool Resources::load(const Common::String &fileName) { return false; } - fileBase = TOTFile::getFileBase(fileName); + _fileBase = TOTFile::getFileBase(fileName); - _extFile = fileBase + ".ext"; + _extFile = _fileBase + ".ext"; bool hasTOTRes = loadTOTResourceTable(); bool hasEXTRes = loadEXTResourceTable(); @@ -165,7 +163,7 @@ bool Resources::load(const Common::String &fileName) { return false; if (hasTOTRes) { - if (!loadTOTTextTable(fileBase)) { + if (!loadTOTTextTable(_fileBase)) { unload(); return false; } @@ -195,6 +193,7 @@ void Resources::unload(bool del) { delete[] _totData; delete[] _imData; + _fileBase.clear(); _totFile.clear(); _extFile.clear(); _exFile.clear(); @@ -573,6 +572,41 @@ byte *Resources::getTexts() const { return _totTextTable->data; } +bool Resources::dumpResource(const Resource &resource, + const Common::String &fileName) const { + + Common::DumpFile dump; + + if (!dump.open(fileName)) + return false; + + if (dump.write(resource.getData(), resource.getSize()) != ((uint32) resource.getSize())) + return false; + + if (!dump.flush()) + return false; + if (dump.err()) + return false; + + dump.close(); + return true; +} + +bool Resources::dumpResource(const Resource &resource, uint16 id, + const Common::String &ext) const { + + Common::String fileName = _fileBase; + + char idStr[7]; + + snprintf(idStr, 7, "_%05d", id); + fileName += idStr; + fileName += "."; + fileName += ext; + + return dumpResource(resource, fileName); +} + Resource *Resources::getTOTResource(uint16 id) const { if (id >= _totResourceTable->itemsCount) { warning("Trying to load non-existent TOT resource (%s, %d/%d)", diff --git a/engines/gob/resources.h b/engines/gob/resources.h index d316be83e5..7511185954 100644 --- a/engines/gob/resources.h +++ b/engines/gob/resources.h @@ -91,6 +91,11 @@ public: byte *getTexts() const; + bool dumpResource(const Resource &resource, + const Common::String &fileName) const; + bool dumpResource(const Resource &resource, uint16 id, + const Common::String &ext = "dmp") const; + private: // Structure sizes in the files static const int kTOTResItemSize = 4 + 2 + 2 + 2; @@ -166,6 +171,7 @@ private: GobEngine *_vm; + Common::String _fileBase; Common::String _totFile; Common::String _extFile; Common::String _exFile; diff --git a/engines/gob/save/saveconverter.cpp b/engines/gob/save/saveconverter.cpp index 38fec06859..7bfb2a2da2 100644 --- a/engines/gob/save/saveconverter.cpp +++ b/engines/gob/save/saveconverter.cpp @@ -122,14 +122,14 @@ bool SaveConverter::swapDataEndian(byte *data, const byte *sizes, uint32 count) while (count-- > 0) { if (*sizes == 3) // 32bit value (3 additional bytes) - *((uint32 *) data) = SWAP_BYTES_32(*((uint32 *) data)); + WRITE_UINT32(data, SWAP_BYTES_32(READ_UINT32(data))); else if (*sizes == 1) // 16bit value (1 additional byte) - *((uint16 *) data) = SWAP_BYTES_16(*((uint16 *) data)); + WRITE_UINT16(data, SWAP_BYTES_16(READ_UINT16(data))); else if (*sizes != 0) // else, it has to be an 8bit value return false; count -= *sizes; - data += *sizes + 1; + data += *sizes + 1; sizes += *sizes + 1; } diff --git a/engines/gob/save/saveload.h b/engines/gob/save/saveload.h index 8d785c7233..1a1a47178b 100644 --- a/engines/gob/save/saveload.h +++ b/engines/gob/save/saveload.h @@ -74,15 +74,15 @@ protected: /** Save/Load class for Gobliins 2, Ween: The Prophecy and Bargon Attack. */ class SaveLoad_v2 : public SaveLoad { public: + static const uint32 kSlotCount = 15; + static const uint32 kSlotNameLength = 40; + SaveLoad_v2(GobEngine *vm, const char *targetName); virtual ~SaveLoad_v2(); SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 15; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; @@ -136,6 +136,9 @@ protected: /** Save/Load class for Goblins 3 and Lost in Time. */ class SaveLoad_v3 : public SaveLoad { public: + static const uint32 kSlotCount = 30; + static const uint32 kSlotNameLength = 40; + enum ScreenshotType { kScreenshotTypeGob3, //!< Goblins 3 type screenshot kScreenshotTypeLost //!< Lost in Time type screenshot @@ -147,9 +150,6 @@ public: SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 30; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; @@ -264,15 +264,15 @@ protected: /** Save/Load class for Woodruff. */ class SaveLoad_v4 : public SaveLoad { public: + static const uint32 kSlotCount = 10; + static const uint32 kSlotNameLength = 40; + SaveLoad_v4(GobEngine *vm, const char *targetName); virtual ~SaveLoad_v4(); SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 10; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; @@ -289,6 +289,8 @@ protected: GameHandler(GobEngine *vm, const char *target); ~GameHandler(); + int getLastSlot() const; + int32 getSize(); bool load(int16 dataVar, int32 size, int32 offset); bool save(int16 dataVar, int32 size, int32 offset); @@ -317,6 +319,8 @@ protected: File *_slotFile; + int _lastSlot; + SaveReader *_reader; SaveWriter *_writer; @@ -386,15 +390,15 @@ protected: /** Save/Load class for Urban Runner. */ class SaveLoad_v6 : public SaveLoad { public: + static const uint32 kSlotCount = 60; + static const uint32 kSlotNameLength = 40; + SaveLoad_v6(GobEngine *vm, const char *targetName); virtual ~SaveLoad_v6(); SaveMode getSaveMode(const char *fileName) const; protected: - static const uint32 kSlotCount = 60; - static const uint32 kSlotNameLength = 40; - struct SaveFile { const char *sourceName; SaveMode mode; diff --git a/engines/gob/save/saveload_v4.cpp b/engines/gob/save/saveload_v4.cpp index 06280af2a6..16c87b9a64 100644 --- a/engines/gob/save/saveload_v4.cpp +++ b/engines/gob/save/saveload_v4.cpp @@ -84,6 +84,8 @@ SaveLoad_v4::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveH _slotFile = new File(vm, target); + _lastSlot = -1; + _writer = 0; _reader = 0; } @@ -94,6 +96,10 @@ SaveLoad_v4::GameHandler::~GameHandler() { delete _writer; } +int SaveLoad_v4::GameHandler::getLastSlot() const { + return _lastSlot; +} + int32 SaveLoad_v4::GameHandler::getSize() { // Fake an empty save file for the very first query, to get clear properties if (_firstSize) { @@ -178,6 +184,7 @@ bool SaveLoad_v4::GameHandler::load(int16 dataVar, int32 size, int32 offset) { if (!vars.writeInto(0, 0, varSize)) return false; + _lastSlot = slot; } return true; @@ -261,6 +268,7 @@ bool SaveLoad_v4::GameHandler::save(int16 dataVar, int32 size, int32 offset) { if (!_writer->writePart(1, &vars)) return false; + _lastSlot = slot; } return true; @@ -465,7 +473,11 @@ bool SaveLoad_v4::ScreenPropsHandler::load(int16 dataVar, int32 size, int32 offs return false; } - return _gameHandler->loadScreenProps(_file->getSlot(offset), _curProps->_props); + int slot = _gameHandler->getLastSlot(); + if (slot == -1) + slot = _file->getSlot(offset); + + return _gameHandler->loadScreenProps(slot, _curProps->_props); } bool SaveLoad_v4::ScreenPropsHandler::save(int16 dataVar, int32 size, int32 offset) { @@ -474,7 +486,11 @@ bool SaveLoad_v4::ScreenPropsHandler::save(int16 dataVar, int32 size, int32 offs return false; } - return _gameHandler->saveScreenProps(_file->getSlot(offset), _curProps->_props); + int slot = _gameHandler->getLastSlot(); + if (slot == -1) + slot = _file->getSlot(offset); + + return _gameHandler->saveScreenProps(slot, _curProps->_props); } diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index 7a4b8ad868..a6d6c06544 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -95,7 +95,7 @@ void Scenery::init() { int16 Scenery::loadStatic(char search) { int16 size; - int16 *backsPtr; + byte *backsPtr; int16 picsCount; int16 resId; int16 sceneryIndex; @@ -108,7 +108,7 @@ int16 Scenery::loadStatic(char search) { _vm->_game->_script->evalExpr(&sceneryIndex); size = _vm->_game->_script->readInt16(); - backsPtr = (int16 *) (_vm->_game->_script->getData() + _vm->_game->_script->pos()); + backsPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos(); _vm->_game->_script->skip(size * 2); picsCount = _vm->_game->_script->readInt16(); resId = _vm->_game->_script->readInt16(); @@ -162,7 +162,7 @@ int16 Scenery::loadStatic(char search) { ptr->layers[i].planes = 0; ptr->layers[i].backResId = (int16) READ_LE_UINT16(backsPtr); - backsPtr++; + backsPtr += 2; } ptr->pieces = new PieceDesc*[picsCount]; @@ -185,7 +185,7 @@ int16 Scenery::loadStatic(char search) { _staticPictToSprite[7 * sceneryIndex + i] = sprIndex; _spriteRefs[sprIndex]++; } else { - for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; sprIndex--); + for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; sprIndex--) { } _staticPictToSprite[7 * sceneryIndex + i] = sprIndex; _spriteRefs[sprIndex] = 1; @@ -632,6 +632,11 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); } + // Subtitle + Graphics::CoktelVideo::State state = _vm->_vidPlayer->getState(obj.videoSlot - 1); + if (state.flags & Graphics::CoktelVideo::kStateSpeech) + _vm->_draw->printTotText(state.speechId); + destX = 0; destY = 0; left = *(obj.pPosX); diff --git a/engines/gob/script.cpp b/engines/gob/script.cpp index 38b1f8fa40..0475bb06f7 100644 --- a/engines/gob/script.cpp +++ b/engines/gob/script.cpp @@ -201,7 +201,7 @@ int32 Script::readInt32() { char *Script::readString(int32 length) { if (length < 0) { length = 0; - while (_totPtr[length++] != '\0'); + while (_totPtr[length++] != '\0') { } } char *string = (char *) _totPtr; diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp index 6ce184155e..f0977aa45b 100644 --- a/engines/gob/sound/bgatmosphere.cpp +++ b/engines/gob/sound/bgatmosphere.cpp @@ -25,6 +25,7 @@ #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "gob/sound/bgatmosphere.h" #include "gob/sound/sounddesc.h" @@ -39,7 +40,7 @@ BackgroundAtmosphere::BackgroundAtmosphere(Audio::Mixer &mixer) : _shaded = false; _shadable = true; - g_system->getEventManager()->registerRandomSource(_rnd, "gobBA"); + g_eventRec.registerRandomSource(_rnd, "gobBA"); } BackgroundAtmosphere::~BackgroundAtmosphere() { diff --git a/engines/gob/sound/sounddesc.cpp b/engines/gob/sound/sounddesc.cpp index b9b327d105..e8045d21f7 100644 --- a/engines/gob/sound/sounddesc.cpp +++ b/engines/gob/sound/sounddesc.cpp @@ -121,9 +121,9 @@ void SoundDesc::convToSigned() { return; if (_mixerFlags & Audio::Mixer::FLAG_16BITS) { - uint16 *data = (uint16 *) _dataPtr; - for (uint32 i = 0; i < _size; i++) - data[i] ^= 0x8000; + byte *data = _dataPtr; + for (uint32 i = 0; i < _size; i++, data += 2) + WRITE_LE_UINT16(data, READ_LE_UINT16(data) ^ 0x8000); } else for (uint32 i = 0; i < _size; i++) _dataPtr[i] ^= 0x80; diff --git a/engines/gob/sound/soundmixer.cpp b/engines/gob/sound/soundmixer.cpp index 68a96d3b01..eb6d7882f0 100644 --- a/engines/gob/sound/soundmixer.cpp +++ b/engines/gob/sound/soundmixer.cpp @@ -33,8 +33,7 @@ SoundMixer::SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type) : _mix _rate = _mixer->getOutputRate(); _end = true; - _data8 = 0; - _data16 = 0; + _data = 0; _length = 0; _freq = 0; _repCount = 0; @@ -61,9 +60,9 @@ SoundMixer::~SoundMixer() { inline int16 SoundMixer::getData(int offset) { if (!_16bit) - return (int16) _data8[offset]; + return (int16) ((int8) _data[offset]); else - return (int16) FROM_LE_16(_data16[offset]); + return (int16) READ_LE_UINT16(_data + (offset * 2)); } bool SoundMixer::isPlaying() const { @@ -78,8 +77,7 @@ void SoundMixer::stop(int16 fadeLength) { Common::StackLock slock(_mutex); if (fadeLength <= 0) { - _data8 = 0; - _data16 = 0; + _data = 0; _end = true; _playingSound = 0; return; @@ -109,13 +107,7 @@ void SoundMixer::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, _16bit = (sndDesc._mixerFlags & Audio::Mixer::FLAG_16BITS) != 0; - if (_16bit) { - _data16 = (int16 *) sndDesc.getData(); - _shift = 0; - } else { - _data8 = (int8 *) sndDesc.getData(); - _shift = 8; - } + _data = sndDesc.getData(); _length = sndDesc.size(); _freq = frequency; @@ -171,7 +163,7 @@ int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); for (int i = 0; i < numSamples; i++) { - if (!_data8 && !_data16) + if (!_data) return i; if (_end || (_offset >= _length)) checkEndSample(); @@ -181,7 +173,7 @@ int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { // Linear interpolation. See sound/rate.cpp int16 val = (_last + (((_cur - _last) * _offsetFrac + - FRAC_HALF) >> FRAC_BITS)) << _shift; + FRAC_HALF) >> FRAC_BITS)) << (_16bit ? 0 : 8); *buffer++ = (val * _fadeVol) >> 16; _offsetFrac += _offsetInc; @@ -211,8 +203,7 @@ int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { void SoundMixer::endFade() { if (_fadeVolStep > 0) { - _data8 = 0; - _data16 = 0; + _data = 0; _end = true; _playingSound = 0; } else { diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h index 20376b5152..9e66c474e9 100644 --- a/engines/gob/sound/soundmixer.h +++ b/engines/gob/sound/soundmixer.h @@ -62,11 +62,9 @@ protected: Common::Mutex _mutex; bool _16bit; - int _shift; bool _end; - int8 *_data8; - int16 *_data16; + byte *_data; uint32 _length; uint32 _rate; int32 _freq; diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 356eb3c643..1a8668b1c2 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -45,7 +45,6 @@ Util::Util(GobEngine *vm) : _vm(vm) { _frameRate = 12; _frameWaitTime = 0; _startFrameTime = 0; - _frameWaitLag = 0; } uint32 Util::getTimeKey(void) { @@ -331,12 +330,10 @@ void Util::setFrameRate(int16 rate) { _frameRate = rate; _frameWaitTime = 1000 / rate; _startFrameTime = getTimeKey(); - _frameWaitLag = 0; } void Util::notifyNewAnim() { _startFrameTime = getTimeKey(); - _frameWaitLag = 0; } void Util::waitEndFrame() { @@ -350,17 +347,12 @@ void Util::waitEndFrame() { return; } - int32 waitTime = _frameWaitTime - _frameWaitLag; - int32 toWait = waitTime - time; + int32 toWait = _frameWaitTime - time; if (toWait > 0) delay(toWait); - int32 now = getTimeKey(); - - _frameWaitLag = (now - _startFrameTime) - waitTime; - - _startFrameTime = now; + _startFrameTime = getTimeKey(); } void Util::setScrollOffset(int16 x, int16 y) { diff --git a/engines/gob/util.h b/engines/gob/util.h index 82e2df94de..ef972eb68c 100644 --- a/engines/gob/util.h +++ b/engines/gob/util.h @@ -145,7 +145,6 @@ protected: int16 _frameRate; int16 _frameWaitTime; uint32 _startFrameTime; - int32 _frameWaitLag; GobEngine *_vm; diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp index 1183ec21ae..572cba0796 100644 --- a/engines/gob/variables.cpp +++ b/engines/gob/variables.cpp @@ -123,22 +123,6 @@ uint8 *Variables::getAddressVar8(uint32 var) { return getAddressOff8(var * 4); } -const uint16 *Variables::getAddressVar16(uint32 var) const { - return getAddressOff16(var * 4); -} - -uint16 *Variables::getAddressVar16(uint32 var) { - return getAddressOff16(var * 4); -} - -const uint32 *Variables::getAddressVar32(uint32 var) const { - return getAddressOff32(var * 4); -} - -uint32 *Variables::getAddressVar32(uint32 var) { - return getAddressOff32(var * 4); -} - const char *Variables::getAddressVarString(uint32 var) const { return getAddressOffString(var * 4); } @@ -155,22 +139,6 @@ uint8 *Variables::getAddressOff8(uint32 offset) { return ((uint8 *) (_vars + offset)); } -const uint16 *Variables::getAddressOff16(uint32 offset) const { - return ((const uint16 *) (_vars + offset)); -} - -uint16 *Variables::getAddressOff16(uint32 offset) { - return ((uint16 *) (_vars + offset)); -} - -const uint32 *Variables::getAddressOff32(uint32 offset) const { - return ((const uint32 *) (_vars + offset)); -} - -uint32 *Variables::getAddressOff32(uint32 offset) { - return ((uint32 *) (_vars + offset)); -} - const char *Variables::getAddressOffString(uint32 offset) const { return ((const char *) (_vars + offset)); } diff --git a/engines/gob/variables.h b/engines/gob/variables.h index 84a4772baa..d11b91ea16 100644 --- a/engines/gob/variables.h +++ b/engines/gob/variables.h @@ -69,24 +69,12 @@ public: const uint8 *getAddressVar8(uint32 var) const; uint8 *getAddressVar8(uint32 var); - const uint16 *getAddressVar16(uint32 var) const; - uint16 *getAddressVar16(uint32 var); - - const uint32 *getAddressVar32(uint32 var) const; - uint32 *getAddressVar32(uint32 var); - const char *getAddressVarString(uint32 var) const; char *getAddressVarString(uint32 var); const uint8 *getAddressOff8(uint32 offset) const; uint8 *getAddressOff8(uint32 offset); - const uint16 *getAddressOff16(uint32 offset) const; - uint16 *getAddressOff16(uint32 offset); - - const uint32 *getAddressOff32(uint32 offset) const; - uint32 *getAddressOff32(uint32 offset); - const char *getAddressOffString(uint32 offset) const; char *getAddressOffString(uint32 offset); diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index da552d7202..a7399caa54 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -156,6 +156,7 @@ VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { _backSurf = false; _needBlit = false; _noCursorSwitch = false; + _woodruffCohCottWorkaround = false; } VideoPlayer::~VideoPlayer() { @@ -248,6 +249,14 @@ bool VideoPlayer::primaryOpen(const char *videoFile, int16 x, int16 y, _noCursorSwitch = true; } + // WORKAROUND: In Woodruff, Coh Cott vanished in one video on her party. + // This is a bug in video, so we work around it. + _woodruffCohCottWorkaround = false; + if (_vm->getGameType() == kGameTypeWoodruff) { + if (!scumm_stricmp(fileName, "SQ32-03.VMD")) + _woodruffCohCottWorkaround = true; + } + _ownSurf = false; if (!(flags & kFlagNoVideo)) { @@ -316,6 +325,7 @@ bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, endFrame = lastFrame; palCmd &= 0x3F; + int16 realStartFrame = startFrame; if (video.getCurrentFrame() != startFrame) { if (!forceSeek && (video.getFeatures() & Graphics::CoktelVideo::kFeaturesSound)) startFrame = video.getCurrentFrame(); @@ -331,7 +341,9 @@ bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, bool canceled = false; while (startFrame <= lastFrame) { - if (doPlay(startFrame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame)) { + if (doPlay(startFrame, breakKey, + palCmd, palStart, palEnd, palFrame, endFrame, startFrame < realStartFrame)) { + canceled = true; break; } @@ -621,7 +633,7 @@ Common::MemoryReadStream *VideoPlayer::getExtraData(const char *fileName, int sl void VideoPlayer::playFrame(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame) { + int16 palFrame, int16 endFrame, bool noRetrace) { if (!_primaryVideo) return; @@ -657,6 +669,12 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey, Graphics::CoktelVideo::State state = video.nextFrame(); WRITE_VAR(11, frame); + if (_woodruffCohCottWorkaround && (frame == 32)) { + // WORKAROUND: This frame mistakenly masks Coh Cott, making her vanish + // To prevent that, we'll never draw that part + state.left += 50; + } + if (_needBlit) _vm->_draw->forceBlit(true); @@ -688,9 +706,14 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey, _vm->_draw->blitInvalidated(); } else _vm->_video->dirtyRectsAdd(state.left, state.top, state.right, state.bottom); - _vm->_video->retrace(); + + if (!noRetrace) + _vm->_video->retrace(); } + // Subtitle + if (state.flags & Graphics::CoktelVideo::kStateSpeech) + _vm->_draw->printTotText(state.speechId); if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); @@ -698,9 +721,9 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey, bool VideoPlayer::doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame) { + int16 palFrame, int16 endFrame, bool noRetrace) { - playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame); + playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame, noRetrace); _vm->_util->processInput(); @@ -716,6 +739,8 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_inter->storeKey(_vm->_util->checkKey()); if (VAR(0) == (unsigned) breakKey) { _primaryVideo->getVideo()->disableSound(); + // Seek to the last frame. Some scripts depend on that. + _primaryVideo->getVideo()->seekFrame(endFrame, SEEK_SET, true); return true; } } @@ -749,7 +774,7 @@ void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, height = _primaryVideo->getVideo()->getHeight(); if (VAR_OFFSET(varX) == 0xFFFFFFFF) - _primaryVideo->getVideo()->getAnchor(1, 2, x, y, width, height); + _primaryVideo->getVideo()->getFrameCoords(1, x, y, width, height); WRITE_VAR_OFFSET(varX, x); WRITE_VAR_OFFSET(varY, y); @@ -774,13 +799,4 @@ void VideoPlayer::evalBgShading(Graphics::CoktelVideo &video) { _vm->_sound->bgUnshade(); } -void VideoPlayer::notifyPaused(uint32 duration) { - if (_primaryVideo->isOpen()) - _primaryVideo->getVideo()->notifyPaused(duration); - - for (uint i = 0; i < _videoSlots.size(); i++) - if (_videoSlots[i] && _videoSlots[i]->isOpen()) - _videoSlots[i]->getVideo()->notifyPaused(duration); -} - } // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index ead752d446..28e72ab43a 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -70,7 +70,7 @@ public: void playFrame(int16 frame, int16 breakKey = kShortKeyEscape, uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, - int16 palFrame = -1 , int16 endFrame = -1); + int16 palFrame = -1 , int16 endFrame = -1, bool noRetrace = false); int slotOpen(const char *videoFile, Type which = kVideoTypeTry); void slotPlay(int slot, int16 frame = -1); @@ -103,8 +103,6 @@ public: void writeVideoInfo(const char *videoFile, int16 varX, int16 varY, int16 varFrames, int16 varWidth, int16 varHeight); - void notifyPaused(uint32 duration); - private: class Video { public: @@ -152,6 +150,8 @@ private: bool _needBlit; bool _noCursorSwitch; + bool _woodruffCohCottWorkaround; + bool findFile(char *fileName, Type &which); const Video *getVideoBySlot(int slot = -1) const; @@ -162,7 +162,7 @@ private: void copyPalette(Graphics::CoktelVideo &video, int16 palStart = -1, int16 palEnd = -1); bool doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame); + int16 palFrame, int16 endFrame, bool noRetrace = false); void evalBgShading(Graphics::CoktelVideo &video); }; diff --git a/engines/groovie/cell.cpp b/engines/groovie/cell.cpp index 3bc8650aa6..c257ac108e 100644 --- a/engines/groovie/cell.cpp +++ b/engines/groovie/cell.cpp @@ -27,156 +27,773 @@ namespace Groovie { -CellGame::CellGame(byte *board) : - _board(board) { +CellGame::CellGame() { _startX = _startY = _endX = _endY = 255; -} -int8 CellGame::calcMove(byte *origboard, uint8 color, uint8 depth) { - uint8 i, j; - int8 di, dj; - uint8 bestStartX, bestStartY, bestEndX, bestEndY; - int8 bestDiff = -100; - int8 origBoardCount = countBoard(origboard, color); - int8 currDiff = -100; - byte *newboard; - uint8 boardmemsize = sizeof(byte) * BOARDSIZE * BOARDSIZE; - uint8 oppColor = 3 - color; + _stack_index = _boardStackPtr = 0; + _flag4 = false; + _flag2 = false; + _coeff3 = 0; - bestStartX = bestStartY = bestEndX = bestEndY = 255; - newboard = (byte*) malloc(boardmemsize); - memcpy(newboard, origboard, boardmemsize); + _moveCount = 0; +} - if (0 == depth) { +byte CellGame::getStartX() { + if (_startX > BOARDSIZE) { + warning ("CellGame::getStartX: not calculated yet (%d)!", _startX); return 0; + } else { + return _startX; + } +} + +byte CellGame::getStartY() { + if (_startY > BOARDSIZE) { + warning ("CellGame::getStartY: not calculated yet (%d)!", _startY); + return 6; + } else { + return _startY; + } +} + +byte CellGame::getEndX() { + if (_endX > BOARDSIZE) { + warning ("CellGame::getEndX: not calculated yet (%d)!", _endX); + return 1; + } else { + return _endX; + } +} + +byte CellGame::getEndY() { + if (_endY > BOARDSIZE) { + warning ("CellGame::getEndY: not calculated yet (%d)!", _endY); + return 6; + } else { + return _endY; + } +} + +CellGame::~CellGame() { +} + +const int8 possibleMoves[][9] = { + { 1, 7, 8, -1 }, + { 0, 2, 7, 8, 9, -1 }, + { 1, 3, 8, 9, 10, -1 }, + { 2, 4, 9, 10, 11, -1 }, + { 3, 5, 10, 11, 12, -1 }, + { 4, 6, 11, 12, 13, -1 }, // 5 + { 5, 12, 13, -1 }, + { 0, 1, 8, 14, 15, -1 }, + { 0, 1, 2, 7, 9, 14, 15, 16, -1 }, + { 1, 2, 3, 8, 10, 15, 16, 17, -1 }, + { 2, 3, 4, 9, 11, 16, 17, 18, -1 }, // 10 + { 3, 4, 5, 10, 12, 17, 18, 19, -1 }, + { 4, 5, 6, 11, 13, 18, 19, 20, -1 }, + { 5, 6, 12, 19, 20, -1 }, + { 7, 8, 15, 21, 22, -1 }, + { 7, 8, 9, 14, 16, 21, 22, 23, -1 }, // 15 + { 8, 9, 10, 15, 17, 22, 23, 24, -1 }, + { 9, 10, 11, 16, 18, 23, 24, 25, -1 }, + { 10, 11, 12, 17, 19, 24, 25, 26, -1 }, + { 11, 12, 13, 18, 20, 25, 26, 27, -1 }, + { 12, 13, 19, 26, 27, -1 }, // 20 + { 14, 15, 22, 28, 29, -1 }, + { 14, 15, 16, 21, 23, 28, 29, 30, -1 }, + { 15, 16, 17, 22, 24, 29, 30, 31, -1 }, + { 16, 17, 18, 23, 25, 30, 31, 32, -1 }, + { 17, 18, 19, 24, 26, 31, 32, 33, -1 }, // 25 + { 18, 19, 20, 25, 27, 32, 33, 34, -1 }, + { 19, 20, 26, 33, 34, -1 }, + { 21, 22, 29, 35, 36, -1 }, + { 21, 22, 23, 28, 30, 35, 36, 37, -1 }, + { 22, 23, 24, 29, 31, 36, 37, 38, -1 }, // 30 + { 23, 24, 25, 30, 32, 37, 38, 39, -1 }, + { 24, 25, 26, 31, 33, 38, 39, 40, -1 }, + { 25, 26, 27, 32, 34, 39, 40, 41, -1 }, + { 26, 27, 33, 40, 41, -1 }, + { 28, 29, 36, 42, 43, -1 }, // 35 + { 28, 29, 30, 35, 37, 42, 43, 44, -1 }, + { 29, 30, 31, 36, 38, 43, 44, 45, -1 }, + { 30, 31, 32, 37, 39, 44, 45, 46, -1 }, + { 31, 32, 33, 38, 40, 45, 46, 47, -1 }, + { 32, 33, 34, 39, 41, 46, 47, 48, -1 }, // 40 + { 33, 34, 40, 47, 48, -1 }, + { 35, 36, 43, -1 }, + { 35, 36, 37, 42, 44, -1 }, + { 36, 37, 38, 43, 45, -1 }, + { 37, 38, 39, 44, 46, -1 }, // 45 + { 38, 39, 40, 45, 47, -1 }, + { 39, 40, 41, 46, 48, -1 }, + { 40, 41, 47, -1 } +}; + + +const int8 strategy2[][17] = { + { 2, 9, 14, 15, 16, -1 }, + { 3, 10, 14, 15, 16, 17, -1 }, + { 0, 4, 7, 11, 14, 15, 16, 17, 18, -1 }, + { 1, 5, 8, 12, 15, 16, 17, 18, 19, -1 }, + { 2, 6, 9, 13, 16, 17, 18, 19, 20, -1 }, + { 3, 10, 17, 18, 19, 20, -1 }, // 5 + { 4, 11, 18, 19, 20, -1 }, + { 2, 9, 16, 21, 22, 23, -1 }, + { 3, 10, 17, 21, 22, 23, 24, -1 }, + { 0, 4, 7, 11, 14, 18, 21, 22, 23, 24, 25, -1 }, + { 1, 5, 8, 12, 15, 19, 22, 23, 24, 25, 26, -1 }, // 10 + { 2, 6, 9, 13, 16, 20, 23, 24, 25, 26, 27, -1 }, + { 3, 10, 17, 24, 25, 26, 27, -1 }, + { 4, 11, 18, 25, 26, 27, -1 }, + { 0, 1, 2, 9, 16, 23, 28, 29, 30, -1 }, + { 0, 1, 2, 3, 10, 17, 24, 28, 29, 30, 31, -1 }, // 15 + { 0, 1, 2, 3, 4, 7, 11, 14, 18, 21, 25, 28, 29, 30, 31, 32, -1 }, + { 1, 2, 3, 4, 5, 8, 12, 15, 19, 22, 26, 29, 30, 31, 32, 33, -1 }, + { 2, 3, 4, 5, 6, 9, 13, 16, 20, 23, 27, 30, 31, 32, 33, 34, -1 }, + { 3, 4, 5, 6, 10, 17, 24, 31, 32, 33, 34, -1 }, + { 4, 5, 6, 11, 18, 25, 32, 33, 34, -1 }, // 20 + { 7, 8, 9, 16, 23, 30, 35, 36, 37, -1 }, + { 7, 8, 9, 10, 17, 24, 31, 35, 36, 37, 38, -1 }, + { 7, 8, 9, 10, 11, 14, 18, 21, 25, 28, 32, 35, 36, 37, 38, 39, -1 }, + { 8, 9, 10, 11, 12, 15, 19, 22, 26, 29, 33, 36, 37, 38, 39, 40, -1 }, + { 9, 10, 11, 12, 13, 16, 20, 23, 27, 30, 34, 37, 38, 39, 40, 41, -1 }, // 25 + { 10, 11, 12, 13, 17, 24, 31, 38, 39, 40, 41, -1 }, + { 11, 12, 13, 18, 25, 32, 39, 40, 41, -1 }, + { 14, 15, 16, 23, 30, 37, 42, 43, 44, -1 }, + { 14, 15, 16, 17, 24, 31, 38, 42, 43, 44, 45, -1 }, + { 14, 15, 16, 17, 18, 21, 25, 28, 32, 35, 39, 42, 43, 44, 45, 46, -1 }, // 30 + { 15, 16, 17, 18, 19, 22, 26, 29, 33, 36, 40, 43, 44, 45, 46, 47, -1 }, + { 16, 17, 18, 19, 20, 23, 27, 30, 34, 37, 41, 44, 45, 46, 47, 48, -1 }, + { 17, 18, 19, 20, 24, 31, 38, 45, 46, 47, 48, -1 }, + { 18, 19, 20, 25, 32, 39, 46, 47, 48, -1 }, + { 21, 22, 23, 30, 37, 44, -1 }, // 35 + { 21, 22, 23, 24, 31, 38, 45, -1 }, + { 21, 22, 23, 24, 25, 28, 32, 35, 39, 42, 46, -1 }, + { 22, 23, 24, 25, 26, 29, 33, 36, 40, 43, 47, -1 }, + { 23, 24, 25, 26, 27, 30, 34, 37, 41, 44, 48, -1 }, + { 24, 25, 26, 27, 31, 38, 45, -1 }, // 40 + { 25, 26, 27, 32, 39, 46, -1 }, + { 28, 29, 30, 37, 44, -1 }, + { 28, 29, 30, 31, 38, 45, -1 }, + { 28, 29, 30, 31, 32, 35, 39, 42, 46, -1 }, + { 29, 30, 31, 32, 33, 36, 40, 43, 47, -1 }, // 45 + { 30, 31, 32, 33, 34, 37, 41, 44, 48, -1 }, + { 31, 32, 33, 34, 38, 45, -1 }, + { 32, 33, 34, 39, 46, -1 } +}; + +void CellGame::copyToTempBoard() { + for (int i = 0; i < 53; ++i) { + _tempBoard[i] = _board[i]; + } +} + +void CellGame::copyFromTempBoard() { + for (int i = 0; i < 53; ++i) { + _board[i] = _tempBoard[i]; } +} + +void CellGame::copyToShadowBoard() { + _board[53] = 0; + _board[55] = 1; + _board[56] = 0; + + for (int i = 0; i < 49; ++i) { + _shadowBoard[i] = _board[i]; + } +} + +void CellGame::pushBoard() { + assert(_boardStackPtr < 57 * 9); - for (i = 0; BOARDSIZE > i; i++) { // For every square on the board - for (j = 0; BOARDSIZE > j; j++) { // - if (color == *(origboard + i + (BOARDSIZE * j))) { // If the square is the desired colour - for (di = -2; 2 >= di; di++) { // Check every square two or less in every direction - for (dj = -2; 2 >= dj; dj++) { // - if (di != 0 || dj != 0) { // Don't allow a move onto itself - debugC(7, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Testing move %d, %d-> %d, %d", depth, i, j, i+di, j+dj); - if (validMove(origboard, color, i+di, j+dj)) { - int8 nextlevel; - debugC(5, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Valid move %d, %d-> %d, %d", depth, i, j, i+di, j+dj); - execMove (newboard, color, i, j, i+di, j+dj); - - nextlevel = calcMove (newboard, oppColor, depth - 1); - debugC(5, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Next level down returned %d", depth, nextlevel); - currDiff = countBoard(newboard, color) - origBoardCount - nextlevel; - if (currDiff > bestDiff) { - debugC(4, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Found new best move (diff of %d): %d, %d-> %d, %d", depth, currDiff, i, j, i+di, j+dj); - bestDiff = currDiff; - bestStartX = i; - bestStartY = j; - bestEndX = i+di; - bestEndY = j+dj; - - } - // TODO: ideal would be to revert the move, rather than copy the board again. I think. - memcpy(newboard, origboard, boardmemsize); - } - } + for (int i = 0; i < 57; ++i) + _boardStack[_boardStackPtr + i] = _board[i]; + _boardStackPtr += 57; +} + +void CellGame::popBoard() { + assert(_boardStackPtr > 0); + + _boardStackPtr -= 57; + for (int i = 0; i < 57; ++i) { + _board[i] = _boardStack[_boardStackPtr + i]; + } +} + +void CellGame::pushShadowBoard() { + assert(_boardStackPtr < 57 * 9); + + for (int i = 0; i < 57; ++i) + _boardStack[_boardStackPtr + i] = _shadowBoard[i]; + + _boardStackPtr += 57; +} + +void CellGame::popShadowBoard() { + assert(_boardStackPtr > 0); + + _boardStackPtr -= 57; + + for (int i = 0; i < 57; ++i) { + _shadowBoard[i] = _boardStack[_boardStackPtr + i]; + } +} + +void CellGame::clearMoves() { + _stack_startXY[0] = _board[53]; + _stack_endXY[0] = _board[54]; + _stack_pass[0] = _board[55]; + + _stack_index = 1; +} + +void CellGame::pushMove() { + _stack_startXY[_stack_index] = _board[53]; + _stack_endXY[_stack_index] = _board[54]; + _stack_pass[_stack_index] = _board[55]; + + _stack_index++; +} + +void CellGame::resetMove() { + _board[53] = 0; + _board[54] = 0; + _board[55] = 0; +} + +void CellGame::takeCells(uint16 whereTo, int8 color) { + int cellN; + const int8 *str; + + str = possibleMoves[whereTo]; + while (1) { + cellN = *str++; + if (cellN < 0) + break; + if (_tempBoard[cellN] > 0) { + --_tempBoard[_tempBoard[cellN] + 48]; + _tempBoard[cellN] = color; + ++_tempBoard[color + 48]; + } + } +} + +void CellGame::countAllCells() { + _board[49] = 0; + _board[50] = 0; + _board[51] = 0; + _board[52] = 0; + + for (int i = 0; i < 49; i++) { + switch (_board[i]) { + case 1: // CELL_BLUE + _board[49]++; + break; + case 2: // CELL_GREEN + _board[50]++; + break; + case 3: + _board[51]++; + break; + case 4: + _board[52]++; + break; + } + } +} + +int CellGame::countCellsOnTempBoard(int8 color) { + const int8 *str; + int res = 0; + int i; + + for (i = 0; i < 49; i++) + _boardSum[i] = 0; + + for (i = 0; i < 49; i++) { + if (_tempBoard[i] == color) { + for (str = possibleMoves[i]; *str > 0; str++) { + if (!_tempBoard[*str]) + ++_boardSum[*str]; + } + } + } + + for (i = 0; i < 49; i++) + res += _boardSum[i]; + + return res; +} + +bool CellGame::canMoveFunc1(int8 color) { + const int8 *str; + + if (_board[55] == 1) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &possibleMoves[_board[53]][_board[56]]; + for (;_board[56] < 8; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_shadowBoard[_board[54]]) { + _shadowBoard[_board[54]] = -1; + ++_board[56]; + return true; } } + _board[56] = 0; + } + } + _board[53] = 0; + _board[55] = 2; + _board[56] = 0; + } + if (_board[55] == 2) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &strategy2[_board[53]][_board[56]]; + for (;_board[56] < 16; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_board[_board[54]]) { + ++_board[56]; + return true; + } + } + _board[56] = 0; } } } - _startX = bestStartX; - _startY = bestStartY; - _endX = bestEndX; - _endY = bestEndY; - - debugC(2, kGroovieDebugCell | kGroovieDebugAll, "Depth: %d: Best move is (diff of %d): %d, %d-> %d, %d", depth, bestDiff, _startX, _startY, _endX, _endY); - free(newboard); - debugC(5, kGroovieDebugCell | kGroovieDebugAll, "Freed newboard"); - return bestDiff; + return false; } -void CellGame::execMove(byte *board, uint8 color, int8 startX, int8 startY, int8 endX, int8 endY) { - int8 i, j; - uint8 colorToEat = 3 - color; // The opposite of the colour passed: 2 -> 1, 1 -> 2 +bool CellGame::canMoveFunc3(int8 color) { + const int8 *str; + + if (_board[55] == 1) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &possibleMoves[_board[53]][_board[56]]; + for (;_board[56] < 8; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_shadowBoard[_board[54]]) { + _shadowBoard[_board[54]] = -1; + ++_board[56]; + return true; + } + } + _board[56] = 0; + } + } - if (abs(endX - startX) == 2 || abs(endY - startY) == 2) { - *(board + startX + BOARDSIZE * startY) = 0; + _board[53] = 0; + _board[55] = 2; + _board[56] = 0; + for (int i = 0; i < 49; ++i) + _shadowBoard[i] = _board[i]; + } + if (_board[55] == 2) { + for (; _board[53] < 49; _board[53]++) { + if (_shadowBoard[_board[53]] == color) { + str = &strategy2[_board[53]][_board[56]]; + for (;_board[56] < 16; _board[56]++) { + _board[54] = *str++; + if (_board[54] < 0) + break; + if (!_shadowBoard[_board[54]]) { + _shadowBoard[_board[54]] = -1; + ++_board[56]; + return true; + } + } + _board[56] = 0; + } + } } - *(board + endX + BOARDSIZE * endY) = color; + return false; +} + +bool CellGame::canMoveFunc2(int8 color) { + const int8 *str; - for (i = (endX - 1); endX + 1 >= i; i++) { - for (j = (endY - 1); endY + 1 >= j; j++) { - if (BOARDSIZE > i && BOARDSIZE > j && 0 <= i && 0 <= j) { // Don't wrap around the board edges! - uint8 offset = i + BOARDSIZE * j; - if (colorToEat == *(board + offset)) { - *(board + offset) = color; + while (1) { + while (_board[_board[54]]) { + ++_board[54]; + if (_board[54] >= 49) + return false; + } + if (!_board[55]) { + str = possibleMoves[_board[54]]; + while (1) { + _board[53] = *str++; + if (_board[53] < 0) + break; + if (_board[_board[53]] == color) { + _board[55] = 1; + return true; + } + } + _board[55] = 1; + } + if (_board[55] == 1) { + _board[55] = 2; + _board[56] = 0; + } + if (_board[55] == 2) { + str = &strategy2[_board[54]][_board[56]]; + for (; _board[56] < 16; _board[56]++) { + _board[53] = *str++; + if (_board[53] < 0) + break; + if (_board[_board[53]] == color) { + ++_board[56]; + return true; } } + ++_board[54]; + _board[55] = 0; + if (_board[54] >= 49) + break; } } + return false; +} + +void CellGame::makeMove(int8 color) { + copyToTempBoard(); + _tempBoard[_board[54]] = color; + ++_tempBoard[color + 48]; + if (_board[55] == 2) { + _tempBoard[_board[53]] = 0; + --_tempBoard[color + 48]; + } + takeCells(_board[54], color); } -bool CellGame::validMove(byte *board, uint8 color, int8 endX, int8 endY) { - if (0 > endX || 0 > endY || BOARDSIZE <= endX || BOARDSIZE <= endY) { // Move is out of bounds - return false; +int CellGame::getBoardWeight(int8 color1, int8 color2) { + int8 celln; + const int8 *str; + byte cellCnt[8]; + + str = possibleMoves[_board[54]]; + cellCnt[1] = _board[49]; + cellCnt[2] = _board[50]; + cellCnt[3] = _board[51]; + cellCnt[4] = _board[52]; + if (_board[55] != 2) + ++cellCnt[color2]; + celln = *str++; + + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; } - if (0 == *(board + endX + (BOARDSIZE * endY))) { - return true; + celln = *str++; + + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; } - return false; + celln = *str++; + + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; + } + while (1) { + celln = *str++; + if (celln < 0) + break; + celln = _board[celln]; + if (celln > 0) { + --cellCnt[celln]; + ++cellCnt[color2]; + } + } + return _coeff3 + 2 * (2 * cellCnt[color1] - cellCnt[1] - cellCnt[2] - cellCnt[3] - cellCnt[4]); } -uint8 CellGame::countBoard(byte *board, uint8 color) { - uint8 total = 0; - for (uint8 i = 0; BOARDSIZE > i; i++) { - for (uint8 j = 0; BOARDSIZE > j; j++) { - if (color == *(board + i + (BOARDSIZE * j))) { - total++; +void CellGame::chooseBestMove(int8 color) { + int moveIndex = 0; + int curWeight; + int bestWeight; + + if (_flag2) { + bestWeight = 32767; + for (int i = 0; i < _stack_index; ++i) { + _board[53] = _stack_startXY[i]; + _board[54] = _stack_endXY[i]; + _board[55] = _stack_pass[i]; + makeMove(color); + curWeight = countCellsOnTempBoard(color); + if (curWeight <= bestWeight) { + if (curWeight < bestWeight) + moveIndex = 0; + bestWeight = curWeight; + _stack_startXY[moveIndex] = _board[53]; + _stack_endXY[moveIndex] = _board[54]; + _stack_pass[moveIndex++] = _board[55]; } } + _stack_index = moveIndex; } - return total; + + _startX = _stack_startXY[0] % 7; + _startY = _stack_startXY[0] / 7; + _endX = _stack_endXY[0] % 7; + _endY = _stack_endXY[0] / 7; } -byte CellGame::getStartX() { - if (_startX > BOARDSIZE) { - warning ("CellGame::getStartX: not calculated yet!"); - return 0; +int8 CellGame::calcBestWeight(int8 color1, int8 color2, uint16 depth, int bestWeight) { + int8 res; + int8 curColor; + bool canMove; + int type; + uint16 i; + int8 currBoardWeight; + int8 weight; + + pushBoard(); + copyFromTempBoard(); + curColor = color2; + for (i = 0;; ++i) { + if (i >= 4) { + res = _coeff3 + 2 * (2 * _board[color1 + 48] - _board[49] - _board[50] - _board[51] - _board[52]); + popBoard(); + return res; + } + ++curColor; + if (curColor > 4) + curColor = 1; + + if (_board[curColor + 48]) { + if (_board[curColor + 48] >= 49 - _board[49] - _board[50] - _board[51] - _board[52]) { + resetMove(); + canMove = canMoveFunc2(curColor); + type = 1; + } else { + copyToShadowBoard(); + if (depth == 1) { + canMove = canMoveFunc3(curColor); + type = 3; + } else { + canMove = canMoveFunc1(curColor); + type = 2; + } + } + if (canMove) + break; + } + } + if (_flag1) { + popBoard(); + return bestWeight + 1; + } + + depth -= 1; + if (depth) { + makeMove(curColor); + if (type == 1) { + res = calcBestWeight(color1, curColor, depth, bestWeight); + } else { + pushShadowBoard(); + res = calcBestWeight(color1, curColor, depth, bestWeight); + popShadowBoard(); + } } else { - return _startX; + res = getBoardWeight(color1, curColor); + } + + if ((res < bestWeight && color1 != curColor) || _flag4) { + popBoard(); + return res; + } + + currBoardWeight = _coeff3 + 2 * (2 * _board[color1 + 48] - _board[49] - _board[50] - _board[51] - _board[52]); + while (1) { + if (type == 1) { + canMove = canMoveFunc2(curColor); + } else if (type == 2) { + canMove = canMoveFunc1(curColor); + } else { + canMove = canMoveFunc3(curColor); + } + + if (!canMove) + break; + if (_flag1) { + popBoard(); + return bestWeight + 1; + } + if (_board[55] == 2) { + if (getBoardWeight(color1, curColor) == currBoardWeight) + continue; + } + if (!depth) { + weight = getBoardWeight(color1, curColor); + if (type == 1) { + if (_board[55] == 2) + _board[56] = 16; + } + } else { + makeMove(curColor); + if (type != 1) { + pushShadowBoard(); + weight = calcBestWeight(color1, curColor, depth, bestWeight); + popShadowBoard(); + } else { + weight = calcBestWeight(color1, curColor, depth, bestWeight); + } + } + if ((weight < res && color1 != curColor) || (weight > res && color1 == curColor)) + res = weight; + + if ((res < bestWeight && color1 != curColor) || _flag4) + break; } + popBoard(); + + return res; } -byte CellGame::getStartY() { - if (_startY > BOARDSIZE) { - warning ("CellGame::getStartY: not calculated yet!"); - return 6; +int16 CellGame::doGame(int8 color, int depth) { + bool canMove; + int type; + int8 currBoardWeight; + int8 w1; + int8 w2; + + countAllCells(); + if (_board[color + 48] >= 49 - _board[49] - _board[50] - _board[51] - _board[52]) { + resetMove(); + canMove = canMoveFunc2(color); + type = true; } else { - return _startY; + copyToShadowBoard(); + canMove = canMoveFunc1(color); + type = false; } -} -byte CellGame::getEndX() { - if (_endX > BOARDSIZE) { - warning ("CellGame::getEndX: not calculated yet!"); + if (canMove) { + if (_board[color + 48] - _board[49] - _board[50] - _board[51] - _board[52] == 0) + depth = 0; + _coeff3 = 0; + if (_board[55] == 1) + _coeff3 = 1; + clearMoves(); + if (depth) { + makeMove(color); + _flag4 = false; + if (type) { + w2 = calcBestWeight(color, color, depth, -127); + } else { + pushShadowBoard(); + w2 = calcBestWeight(color, color, depth, -127); + popShadowBoard(); + } + } else { + w2 = getBoardWeight(color, color); + } + currBoardWeight = 2 * (2 * _board[color + 48] - _board[49] - _board[50] - _board[51] - _board[52]); + while (1) { + if (type) + canMove = canMoveFunc2(color); + else + canMove = canMoveFunc1(color); + + if (!canMove) + break; + if (_flag1) + break; + _coeff3 = 0; + if (_board[55] == 2) { + if (getBoardWeight(color, color) == currBoardWeight) + continue; + } + if (_board[55] == 1) + _coeff3 = 1; + if (depth) { + makeMove(color); + _flag4 = false; + if (type) { + w1 = calcBestWeight(color, color, depth, w2); + } else { + pushShadowBoard(); + w1 = calcBestWeight(color, color, depth, w2); + popShadowBoard(); + } + } else { + w1 = getBoardWeight(color, color); + } + if (w1 == w2) + pushMove(); + + if (w1 > w2) { + clearMoves(); + w2 = w1; + } + } + chooseBestMove(color); return 1; - } else { - return _endX; } + + return 0; } -byte CellGame::getEndY() { - if (_endY > BOARDSIZE) { - warning ("CellGame::getEndY: not calculated yet!"); - return 6; +const int8 depths[] = { 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 3 }; + +int16 CellGame::calcMove(int8 color, uint16 depth) { + int result; + + _flag1 = false; + ++_moveCount; + if (depth) { + if (depth == 1) { + _flag2 = true; + result = doGame(color, 0); + } else { + int newDepth; + + newDepth = depths[3 * (depth - 2) + _moveCount % 3]; + _flag2 = true; + if (newDepth >= 20) { + assert(0); // This branch is not implemented + } else { + result = doGame(color, newDepth); + } + } } else { - return _endY; + _flag2 = false; + result = doGame(color, depth); } + return result; } -CellGame::~CellGame() { +int CellGame::playStauf(byte color, uint16 depth, byte *scriptBoard) { + int i; + + for (i = 0; i < 49; i++, scriptBoard++) { + _board[i] = 0; + if (*scriptBoard == 50) + _board[i] = 1; + if (*scriptBoard == 66) + _board[i] = 2; + } + for (i = 49; i < 57; i++) + _board[i] = 0; + + return calcMove(color, depth); } + } // End of Groovie namespace diff --git a/engines/groovie/cell.h b/engines/groovie/cell.h index 70e135b62d..39ee529beb 100644 --- a/engines/groovie/cell.h +++ b/engines/groovie/cell.h @@ -29,6 +29,7 @@ #include "common/file.h" #include "common/util.h" +#include "groovie/cell.h" #include "groovie/groovie.h" #define BOARDSIZE 7 @@ -43,24 +44,59 @@ class Script; class CellGame { public: - CellGame(byte *board); + CellGame(); ~CellGame(); - int8 calcMove(byte *origboard, uint8 color, uint8 depth); byte getStartX(); byte getStartY(); byte getEndX(); byte getEndY(); + int playStauf(byte color, uint16 depth, byte *scriptBoard); private: - bool validMove(byte *board, uint8 color, int8 endX, int8 endY); - void execMove(byte *board, uint8 color, int8 startX, int8 startY, int8 endX, int8 endY); - uint8 countBoard(byte* board, uint8 color); - byte *_board; + void copyToTempBoard(); + void copyFromTempBoard(); + void copyToShadowBoard(); + void pushBoard(); + void popBoard(); + void pushShadowBoard(); + void popShadowBoard(); + void clearMoves(); + void pushMove(); + void resetMove(); + bool canMoveFunc1(int8 color); + bool canMoveFunc2(int8 color); + bool canMoveFunc3(int8 color); + void takeCells(uint16 whereTo, int8 color); + void countAllCells(); + int countCellsOnTempBoard(int8 color); + void makeMove(int8 color); + int getBoardWeight(int8 color1, int8 color2); + void chooseBestMove(int8 color); + int8 calcBestWeight(int8 color1, int8 color2, uint16 depth, int bestWeight); + int16 doGame(int8 color, int depth); + int16 calcMove(int8 color, uint16 depth); byte _startX; byte _startY; byte _endX; byte _endY; + + int8 _board[57]; + int8 _tempBoard[58]; + int8 _shadowBoard[64]; + int8 _boardStack[570]; + int _boardStackPtr; + + int8 _boardSum[58]; + + int8 _stack_startXY[128]; + int8 _stack_endXY[128]; + int8 _stack_pass[128]; + int _stack_index; + + int _coeff3; + bool _flag1, _flag2, _flag4; + int _moveCount; }; } // End of Groovie namespace diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index 1a1de92156..797290a6f3 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -35,7 +35,7 @@ namespace Groovie { MusicPlayer::MusicPlayer(GroovieEngine *vm) : _vm(vm), _isPlaying(false), _backgroundFileRef(0), _gameVolume(100), - _prevCDtrack(0) { + _prevCDtrack(0), _backgroundDelay(0) { } void MusicPlayer::playSong(uint32 fileref) { @@ -56,6 +56,18 @@ void MusicPlayer::setBackgroundSong(uint32 fileref) { _backgroundFileRef = fileref; } +void MusicPlayer::frameTick() { + if (_backgroundDelay > 0) { + _backgroundDelay--; + if (_backgroundDelay == 0) + playSong(_backgroundFileRef); + } +} + +void MusicPlayer::setBackgroundDelay(uint16 delay) { + _backgroundDelay = delay; +} + void MusicPlayer::playCD(uint8 track) { int startms = 0; diff --git a/engines/groovie/music.h b/engines/groovie/music.h index db50930c37..9909c8a185 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -44,6 +44,9 @@ public: void playCD(uint8 track); void startBackground(); + void frameTick(); + void setBackgroundDelay(uint16 delay); + // Volume void setUserVolume(uint16 volume); void setGameVolume(uint16 volume, uint16 time); @@ -55,6 +58,8 @@ private: uint32 _backgroundFileRef; uint8 _prevCDtrack; + uint16 _backgroundDelay; + // Volume fading uint32 _fadingStartTime; uint16 _fadingStartVolume; diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index eb53842b91..7fdfa6c780 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -33,6 +33,7 @@ #include "common/config-manager.h" #include "common/endian.h" #include "common/events.h" +#include "common/EventRecorder.h" #define NUM_OPCODES 90 @@ -61,7 +62,7 @@ static void debugScript(int level, bool nl, const char *s, ...) { Script::Script(GroovieEngine *vm, EngineVersion version) : _code(NULL), _savedCode(NULL), _stacktop(0), _debugger(NULL), _vm(vm), - _videoFile(NULL), _videoRef(0), _font(NULL) { + _videoFile(NULL), _videoRef(0), _font(NULL), _staufsMove(NULL) { // Initialize the opcode set depending on the engine version switch (version) { case kGroovieT7G: @@ -73,7 +74,7 @@ Script::Script(GroovieEngine *vm, EngineVersion version) : } // Initialize the random source - _vm->_system->getEventManager()->registerRandomSource(_random, "GroovieScripts"); + g_eventRec.registerRandomSource(_random, "GroovieScripts"); // Prepare the variables _bitflags = 0; @@ -195,6 +196,10 @@ void Script::directGameLoad(int slot) { // TODO: We'll probably need to start by running the beginning of the // script to let it do the soundcard initialization and then do the // actual loading. + + // Due to HACK above, the call to check valid save slots is not run. + // As this is where we load save names, manually call it here. + o_checkvalidsaves(); } void Script::step() { @@ -559,6 +564,7 @@ bool Script::playvideofromref(uint32 fileref) { // Video available, play one frame if (_videoFile) { bool endVideo = _vm->_videoPlayer->playFrame(); + _vm->_musicPlayer->frameTick(); if (endVideo) { // Close the file @@ -1376,33 +1382,21 @@ void Script::o_sub() { } void Script::o_cellmove() { - uint16 arg = readScript8bits(); + uint16 depth = readScript8bits(); byte *scriptBoard = &_variables[0x19]; - byte *board = (byte*) malloc (BOARDSIZE * BOARDSIZE * sizeof(byte)); byte startX, startY, endX, endY; - debugScript(1, true, "CELL MOVE var[0x%02X]", arg); - - // Arguments used by the original implementation: (2, arg, scriptBoard) - for (int y = 0; y < 7; y++) { - for (int x = 0; x < 7; x++) { - uint8 offset = x + BOARDSIZE * y; - *(board + offset) = 0; - if (*scriptBoard == 0x32) *(board + offset) = CELL_BLUE; - if (*scriptBoard == 0x42) *(board + offset) = CELL_GREEN; - scriptBoard++; - debugScript(1, false, "%d", *(board + offset)); - } - debugScript(1, false, "\n"); - } + debugScript(1, true, "CELL MOVE var[0x%02X]", depth); + + if (!_staufsMove) + _staufsMove = new CellGame; - CellGame staufsMove((byte*) board); - staufsMove.calcMove((byte*) board, CELL_GREEN, 2); - startX = staufsMove.getStartX(); - startY = staufsMove.getStartY(); - endX = staufsMove.getEndX(); - endY = staufsMove.getEndY(); + _staufsMove->playStauf(2, depth, scriptBoard); + startX = _staufsMove->getStartX(); + startY = _staufsMove->getStartY(); + endX = _staufsMove->getEndX(); + endY = _staufsMove->getEndY(); // Set the movement origin setVariable(0, startY); // y @@ -1410,8 +1404,6 @@ void Script::o_cellmove() { // Set the movement destination setVariable(2, endY); setVariable(3, endX); - - free (board); } void Script::o_returnscript() { @@ -1500,6 +1492,14 @@ void Script::o_playcd() { _vm->_musicPlayer->playCD(val); } +void Script::o_musicdelay() { + uint16 delay = readScript16bits(); + + debugScript(1, true, "MUSICDELAY %d", delay); + + _vm->_musicPlayer->setBackgroundDelay(delay); +} + void Script::o_hotspot_outrect() { uint16 left = readScript16bits(); uint16 top = readScript16bits(); @@ -1671,7 +1671,7 @@ Script::OpcodeFunc Script::_opcodesT7G[NUM_OPCODES] = { &Script::o_nop8, &Script::o_getcd, // 0x4C &Script::o_playcd, - &Script::o_nop16, + &Script::o_musicdelay, &Script::o_nop16, &Script::o_nop16, // 0x50 &Script::o_nop16, diff --git a/engines/groovie/script.h b/engines/groovie/script.h index 664cac82d8..e9e0be69ec 100644 --- a/engines/groovie/script.h +++ b/engines/groovie/script.h @@ -40,6 +40,7 @@ enum EngineVersion { }; class GroovieEngine; +class CellGame; class Script { friend class Debugger; @@ -120,6 +121,8 @@ private: Common::String _debugString; uint16 _oldInstruction; + CellGame *_staufsMove; + // Helper functions uint8 getCodeByte(uint16 address); uint8 readScript8bits(); @@ -216,6 +219,7 @@ private: void o_sethotspotleft(); void o_getcd(); void o_playcd(); + void o_musicdelay(); void o_hotspot_outrect(); void o_stub56(); void o_stub59(); diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp index 85d974f675..d9924d233b 100644 --- a/engines/kyra/gui.cpp +++ b/engines/kyra/gui.cpp @@ -538,18 +538,18 @@ int MainMenu::handle(int dim) { int item = (mouse.y - menuRect.top) / fh; if (item != selected) { - printString(_static.strings[selected], textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5); - printString(_static.strings[item], textPos, menuRect.top + item * fh, _static.menuTable[6], 0, 5); + printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]); + printString("%s", textPos, menuRect.top + item * fh, _static.menuTable[6], 0, 5, _static.strings[item]); selected = item; } if (mousePressed) { for (int i = 0; i < 3; i++) { - printString(_static.strings[selected], textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5); + printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]); _screen->updateScreen(); _system->delayMillis(50); - printString(_static.strings[selected], textPos, menuRect.top + selected * fh, _static.menuTable[6], 0, 5); + printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[6], 0, 5, _static.strings[selected]); _screen->updateScreen(); _system->delayMillis(50); } @@ -577,7 +577,7 @@ void MainMenu::draw(int select) { for (int i = 0; i < _static.menuTable[3]; ++i) { int curY = top + i * _screen->getFontHeight(); int color = (i == select) ? _static.menuTable[6] : _static.menuTable[5]; - printString(_static.strings[i], ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5); + printString("%s", ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5, _static.strings[i]); } } diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 69e7419757..cb2476ff99 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -757,7 +757,6 @@ int GUI_HoF::optionsButton(Button *button) { initMenu(*_currentMenu); _madeSave = false; _loadedSave = false; - _vm->_itemInHand = -1; updateAllMenuButtons(); if (_isDeathMenu) { @@ -821,6 +820,7 @@ void GUI_HoF::resetState(int item) { _vm->setNextIdleAnimTimer(); _isDeathMenu = false; if (!_loadedSave) { + _vm->_itemInHand = -1; _vm->setHandItem(item); } else { _vm->setHandItem(_vm->_itemInHand); diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 9f42697ec7..4624aced90 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -681,6 +681,7 @@ void GUI_LoK::updateSavegameString() { } int GUI_LoK::saveGame(Button *button) { + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); updateMenuButton(button); _vm->_gameToLoad = _menu[2].item[button->index-0xC].saveSlot; @@ -729,6 +730,7 @@ int GUI_LoK::saveGame(Button *button) { } } + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); return 0; } diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index e7001ed31f..858e3fde94 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -1141,6 +1141,7 @@ void GUI_MR::resetState(int item) { _vm->setNextIdleAnimTimer(); _isDeathMenu = false; if (!_loadedSave) { + _vm->_itemInHand = -1; _vm->setHandItem(item); } else { _vm->setHandItem(_vm->_itemInHand); @@ -1260,7 +1261,6 @@ int GUI_MR::optionsButton(Button *button) { initMenu(*_currentMenu); _madeSave = false; _loadedSave = false; - _vm->_itemInHand = -1; updateAllMenuButtons(); if (_isDeathMenu) { diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index e5c8637fb5..3633a546e7 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -661,7 +661,9 @@ int GUI_v2::clickSaveSlot(Button *caller) { initMenu(_savenameMenu); _screen->fillRect(0x26, 0x5B, 0x11F, 0x66, textFieldColor2()); + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); const char *desc = nameInputProcess(_saveDescription, 0x27, 0x5C, textFieldColor1(), textFieldColor2(), textFieldColor3(), 0x50); + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); restorePage1(_vm->_screenBuffer); backUpPage1(_vm->_screenBuffer); if (desc) { diff --git a/engines/kyra/items_mr.cpp b/engines/kyra/items_mr.cpp index 5397651e97..d08d58e65d 100644 --- a/engines/kyra/items_mr.cpp +++ b/engines/kyra/items_mr.cpp @@ -87,7 +87,8 @@ void KyraEngine_MR::setMouseCursor(uint16 item) { shape = item+248; } - if ((int16)item != _itemInHand) + _mouseState = item; + if ((int16)item >= 0) _screen->setMouseCursor(hotX, hotY, getShapePtr(shape)); } diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 5c41989713..bf515498dc 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -1658,7 +1658,7 @@ void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { if (!file) error("Couldn't load cauldron palette"); file->seek(state*18, SEEK_SET); - _screen->getPalette(0).loadVGAPalette(*file, 241, 6); + _screen->getPalette(2).loadVGAPalette(*file, 241, 6); delete file; file = 0; @@ -1673,8 +1673,8 @@ void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { _screen->getPalette(0).copy(_screen->getPalette(2), 241, 6); _cauldronState = state; _cauldronUseCount = 0; - //if (state == 5) - // sub_27149(); + if (state == 5) + setDlgIndex(5); } void KyraEngine_HoF::clearCauldronTable() { diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 88bfb8c89b..2204f78b82 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -495,6 +495,7 @@ private: bool _useFrameTable; int o3a_setCharacterFrame(EMCState *script); + int o3a_playSoundEffect(EMCState *script); // special shape code int initAnimationShapes(uint8 *filedata); diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 5f5dc10e75..9ee6935384 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -24,6 +24,7 @@ */ #include "common/config-manager.h" +#include "common/EventRecorder.h" #include "sound/mididrv.h" #include "sound/mixer.h" @@ -84,7 +85,7 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags) Common::addDebugChannel(kDebugLevelMovie, "Movie", "Movie debug level"); Common::addDebugChannel(kDebugLevelTimer, "Timer", "Timer debug level"); - _eventMan->registerRandomSource(_rnd, "kyra"); + g_eventRec.registerRandomSource(_rnd, "kyra"); } ::GUI::Debugger *KyraEngine_v1::getDebugger() { diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 83230d6e3b..9e0ddcea4f 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -222,11 +222,7 @@ const char *KyraEngine_v1::getSavegameFilename(int num) { Common::String KyraEngine_v1::getSavegameFilename(const Common::String &target, int num) { assert(num >= 0 && num <= 999); - - char extension[5]; - sprintf(extension, "%03d", num); - - return target + "." + extension; + return target + Common::String::printf(".%03d", num); } bool KyraEngine_v1::saveFileLoadable(int slot) { diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 6c2c48cb02..7a7544a589 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -95,25 +95,10 @@ bool Screen::init() { } if (_useSJIS) { - if (!_sjisFont) { - // we use the FM-TOWNS font rom for PC-98, too, until we feel - // like adding support for the PC-98 font - //if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { - // FM-TOWNS - Common::SeekableReadStream *rom = _vm->resource()->createReadStream("FMT_FNT.ROM"); - Graphics::FontTowns *townsFont = new Graphics::FontTowns(); - if (!rom || !townsFont || !townsFont->loadFromStream(*rom)) - error("Could not load font rom ('FMT_FNT.ROM') required for this version"); - _sjisFont = townsFont; - delete rom; - /*} else { - // PC-98 - _sjisFontData = _vm->resource()->fileData("FONT.ROM", 0); - if (!_sjisFontData) - error("missing font rom ('FONT.ROM') required for this version"); - }*/ - } - + _sjisFont = Graphics::FontSJIS::createFont(_vm->gameFlags().platform); + + if (!_sjisFont) + error("Could not load any SJIS font, neither the original nor ScummVM's 'SJIS.FNT'"); _sjisFont->enableOutline(!_use16ColorMode); } } diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index 1800bd1939..819bf838ca 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -1114,6 +1114,12 @@ int KyraEngine_MR::o3a_setCharacterFrame(EMCState *script) { return 0; } +int KyraEngine_MR::o3a_playSoundEffect(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3a_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0)); + snd_playSoundEffect(stackPos(0), 200); + return 0; +} + #pragma mark - int KyraEngine_MR::o3d_updateAnim(EMCState *script) { @@ -1374,7 +1380,7 @@ void KyraEngine_MR::setupOpcodeTable() { // 0x00 Opcode(o2a_setAnimationShapes); Opcode(o3a_setCharacterFrame); - Opcode(o3_playSoundEffect); + Opcode(o3a_playSoundEffect); Opcode(o3_dummy); // 0x04 Opcode(o2a_setResetFrame); diff --git a/engines/kyra/sequences_mr.cpp b/engines/kyra/sequences_mr.cpp index 4d1117f3c9..a1830aec5c 100644 --- a/engines/kyra/sequences_mr.cpp +++ b/engines/kyra/sequences_mr.cpp @@ -42,7 +42,8 @@ void KyraEngine_MR::showBadConscience() { _badConscienceAnim = 6; else if (_currentChapter == 5 && _rnd.getRandomNumberRng(1, 100) <= 25) _badConscienceAnim = 7; - else if (_characterShapeFile == 9) + + if (_characterShapeFile == 9) _badConscienceAnim = 4; _badConsciencePosition = (_mainCharacter.x1 <= 160); diff --git a/engines/kyra/sound_digital.cpp b/engines/kyra/sound_digital.cpp index 6b81b1c022..1d8bc5b03c 100644 --- a/engines/kyra/sound_digital.cpp +++ b/engines/kyra/sound_digital.cpp @@ -346,7 +346,7 @@ int AUDStream::readChunk(int16 *buffer, const int maxSamples) { #pragma mark - -SoundDigital::SoundDigital(KyraEngine_MR *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _sounds() { +SoundDigital::SoundDigital(KyraEngine_MR *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { for (uint i = 0; i < ARRAYSIZE(_sounds); ++i) _sounds[i].stream = 0; } diff --git a/engines/kyra/sprites.cpp b/engines/kyra/sprites.cpp index 3cc632a391..456dcc06f3 100644 --- a/engines/kyra/sprites.cpp +++ b/engines/kyra/sprites.cpp @@ -28,6 +28,8 @@ #include "common/stream.h" #include "common/util.h" #include "common/system.h" +#include "common/EventRecorder.h" + #include "kyra/screen.h" #include "kyra/kyra_lok.h" #include "kyra/sprites.h" @@ -47,7 +49,7 @@ Sprites::Sprites(KyraEngine_LoK *vm, OSystem *system) { _spriteDefStart = 0; memset(_drawLayerTable, 0, sizeof(_drawLayerTable)); _sceneAnimatorBeaconFlag = 0; - _vm->getEventManager()->registerRandomSource(_rnd, "kyraSprites"); + g_eventRec.registerRandomSource(_rnd, "kyraSprites"); } Sprites::~Sprites() { diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index 969d8215fb..b5ec00fdf9 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -38,6 +38,7 @@ #include "lure/sound.h" #include "lure/lure.h" #include "common/endian.h" +#include "common/EventRecorder.h" namespace Lure { @@ -600,7 +601,7 @@ void Hotspot::setRandomDest() { Common::RandomSource rnd; int16 xp, yp; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); if (currentActions().isEmpty()) currentActions().addFront(START_WALKING, roomNumber()); @@ -2691,7 +2692,19 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) { return; } h.currentActions().top().setAction(WALKING); - h.setPosition(h.x(), h.y() & 0xfff8); + + // WORKAROUND: A character that had enteredg an exit area might have been blocked from entering the new room. + // The Y position adjust below could thus place a character further into the exit area. So don't do the + // position adjustment if the user is already in an exit area + int16 x = h.x() + (h.widthCopy() >> 1); + int16 y = h.y() + h.heightCopy() - (h.yCorrection() >> 1); + + RoomData *roomData = Resources::getReference().getRoom(h.roomNumber()); + RoomExitData *exitRec = roomData->exits.checkExits(x, y); + + if (!exitRec) + h.setPosition(h.x(), h.y() & 0xfff8); + } else if (h.blockedState() == BS_FINAL) { // If this point is reached, the character twice hasn't found a walking path debugC(ERROR_DETAILED, kLureDebugAnimations, "Character is hopelessly blocked"); @@ -3135,7 +3148,7 @@ void HotspotTickHandlers::followerAnimHandler(Hotspot &h) { Common::RandomSource rnd; RandomActionType actionType; uint16 scheduleId; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); int actionIndex = rnd.getRandomNumber(set->numActions() - 1); set->getEntry(actionIndex, actionType, scheduleId); @@ -3325,7 +3338,7 @@ void HotspotTickHandlers::prisonerAnimHandler(Hotspot &h) { ValueTableData &fields = Resources::getReference().fieldList(); Common::RandomSource rnd; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); h.handleTalkDialog(); if (h.frameCtr() > 0) { @@ -3368,7 +3381,7 @@ void HotspotTickHandlers::morkusAnimHandler(Hotspot &h) { if (h.executeScript()) { // Script is done - set new script to one of two alternates randomly Common::RandomSource rnd; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); h.setHotspotScript(rnd.getRandomNumber(100) >= 50 ? 0x54 : 0); h.setFrameCtr(20 + rnd.getRandomNumber(63)); @@ -3668,7 +3681,7 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) { Common::RandomSource rnd; static bool ewanXOffset = false; - g_system->getEventManager()->registerRandomSource(rnd, "lureHotspots"); + g_eventRec.registerRandomSource(rnd, "lureHotspots"); h.handleTalkDialog(); if (h.delayCtr() > 0) { diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp index 95cb0a2f1b..7eb76cad32 100644 --- a/engines/lure/res.cpp +++ b/engines/lure/res.cpp @@ -30,6 +30,7 @@ #include "lure/lure.h" #include "common/endian.h" #include "common/events.h" +#include "common/EventRecorder.h" namespace Lure { @@ -42,7 +43,7 @@ Resources &Resources::getReference() { } Resources::Resources() { - g_system->getEventManager()->registerRandomSource(_rnd, "lureResources"); + g_eventRec.registerRandomSource(_rnd, "lureResources"); int_resources = this; reloadData(); diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp index 391147ebd5..f9d854a73b 100644 --- a/engines/lure/scripts.cpp +++ b/engines/lure/scripts.cpp @@ -34,6 +34,7 @@ #include "lure/sound.h" #include "common/stack.h" #include "common/endian.h" +#include "common/EventRecorder.h" namespace Lure { @@ -739,7 +740,7 @@ void Script::addActions(uint16 hotspotId, uint16 actions, uint16 v3) { void Script::randomToGeneral(uint16 maxVal, uint16 minVal, uint16 v3) { Common::RandomSource rnd; - g_system->getEventManager()->registerRandomSource(rnd, "lureScripts"); + g_eventRec.registerRandomSource(rnd, "lureScripts"); uint16 v = minVal + rnd.getRandomNumber(maxVal - minVal); Resources::getReference().fieldList().setField(GENERAL, v); } diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp index c27f151fdf..b4973002a6 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -53,6 +53,7 @@ #include "common/file.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/endian.h" #include "common/system.h" #include "common/config-manager.h" @@ -192,7 +193,7 @@ Common::Error M4Engine::run() { _animation = new Animation(this); //_callbacks = new Callbacks(this); _random = new Common::RandomSource(); - g_system->getEventManager()->registerRandomSource(*_random, "m4"); + g_eventRec.registerRandomSource(*_random, "m4"); if (isM4()) return goM4(); diff --git a/engines/made/made.cpp b/engines/made/made.cpp index 50a14c3e34..c83f7aaf02 100644 --- a/engines/made/made.cpp +++ b/engines/made/made.cpp @@ -24,6 +24,7 @@ */ #include "common/events.h" +#include "common/EventRecorder.h" #include "common/keyboard.h" #include "common/file.h" #include "common/savefile.h" @@ -74,7 +75,7 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng _gameId = g->id; _rnd = new Common::RandomSource(); - syst->getEventManager()->registerRandomSource(*_rnd, "made"); + g_eventRec.registerRandomSource(*_rnd, "made"); int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 7aee966aa6..8fadd4e462 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -25,6 +25,7 @@ #include "common/config-manager.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/file.h" #include "common/util.h" #include "common/system.h" @@ -70,7 +71,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam Common::addDebugChannel(kDebugMenu, "menu", "Menu debug level"); Common::addDebugChannel(kDebugInventory, "inventory", "Inventory debug level"); - syst->getEventManager()->registerRandomSource(_rnd, "parallaction"); + g_eventRec.registerRandomSource(_rnd, "parallaction"); } diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index b7c8a9e029..3672fd3b09 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -172,14 +172,14 @@ protected: DECLARE_UNQUALIFIED_COMMAND_PARSER(simple); DECLARE_UNQUALIFIED_COMMAND_PARSER(move); DECLARE_UNQUALIFIED_COMMAND_PARSER(endcommands); - +public: virtual void parseGetData(ZonePtr z); virtual void parseExamineData(ZonePtr z); virtual void parseDoorData(ZonePtr z); virtual void parseMergeData(ZonePtr z); virtual void parseHearData(ZonePtr z); virtual void parseSpeakData(ZonePtr z); - +protected: Common::String parseComment(); Common::String parseDialogueString(); Dialogue *parseDialogue(); @@ -289,10 +289,12 @@ protected: DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); virtual void parseZoneTypeBlock(ZonePtr z); - void parsePathData(ZonePtr z); - void parseGetData(ZonePtr z); - void parseDoorData(ZonePtr z); - void parseAnswerCounter(Answer *answer); +public: + virtual void parsePathData(ZonePtr z); + virtual void parseGetData(ZonePtr z); + virtual void parseDoorData(ZonePtr z); +protected: + void parseAnswerCounter(Answer *answer); virtual Answer *parseAnswer(); public: diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index b1dd86a693..563faa16e6 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -808,26 +808,27 @@ void LocationParser_br::parseDoorData(ZonePtr z) { } } +typedef void (LocationParser_br::*ZoneTypeParser)(ZonePtr); +static ZoneTypeParser parsers[] = { + 0, // no type + &LocationParser_br::parseExamineData, + &LocationParser_br::parseDoorData, + &LocationParser_br::parseGetData, + &LocationParser_br::parseMergeData, + 0, // taste + &LocationParser_br::parseHearData, + 0, // feel + &LocationParser_br::parseSpeakData, + 0, // none + 0, // trap + 0, // you + 0, // command + &LocationParser_br::parsePathData, + 0, // box +}; + void LocationParser_br::parseZoneTypeBlock(ZonePtr z) { debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type); - typedef void (LocationParser_br::*ZoneTypeParser)(ZonePtr); - ZoneTypeParser parsers[] = { - 0, // no type - &LocationParser_br::parseExamineData, - &LocationParser_br::parseDoorData, - &LocationParser_br::parseGetData, - &LocationParser_br::parseMergeData, - 0, // taste - &LocationParser_br::parseHearData, - 0, // feel - &LocationParser_br::parseSpeakData, - 0, // none - 0, // trap - 0, // you - 0, // command - &LocationParser_br::parsePathData, - 0, // box - }; ZoneTypeParser p = parsers[ACTIONTYPE(z)]; do { diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 9971828c31..1c06f86bfa 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1411,24 +1411,25 @@ void LocationParser_ns::parseSpeakData(ZonePtr z) { } } +typedef void (LocationParser_ns::*ZoneTypeParser)(ZonePtr); +static ZoneTypeParser parsers[] = { + 0, // no type + &LocationParser_ns::parseExamineData, + &LocationParser_ns::parseDoorData, + &LocationParser_ns::parseGetData, + &LocationParser_ns::parseMergeData, + 0, // taste + &LocationParser_ns::parseHearData, + 0, // feel + &LocationParser_ns::parseSpeakData, + 0, // none + 0, // trap + 0, // you + 0 // command +}; + void LocationParser_ns::parseZoneTypeBlock(ZonePtr z) { debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type); - typedef void (LocationParser_ns::*ZoneTypeParser)(ZonePtr); - ZoneTypeParser parsers[] = { - 0, // no type - &LocationParser_ns::parseExamineData, - &LocationParser_ns::parseDoorData, - &LocationParser_ns::parseGetData, - &LocationParser_ns::parseMergeData, - 0, // taste - &LocationParser_ns::parseHearData, - 0, // feel - &LocationParser_ns::parseSpeakData, - 0, // none - 0, // trap - 0, // you - 0 // command - }; ZoneTypeParser p = parsers[ACTIONTYPE(z)]; do { diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index 5db0e732ee..d95decfd4f 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -67,16 +67,6 @@ public: virtual void reflowLayout(); }; -Common::String SaveLoad_ns::genOldSaveFileName(uint slot) { - assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); - - char s[20]; - sprintf(s, "game.%i", slot); - - return Common::String(s); -} - - Common::String SaveLoad::genSaveFileName(uint slot) { assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); @@ -430,55 +420,55 @@ void SaveLoad_ns::getGamePartProgress(bool *complete, int size) { complete[2] = s.contains("dough"); } -void SaveLoad_ns::renameOldSavefiles() { +static bool askRenameOldSavefiles() { + GUI::MessageDialog dialog0( + "ScummVM found that you have old savefiles for Nippon Safes that should be renamed.\n" + "The old names are no longer supported, so you will not be able to load your games if you don't convert them.\n\n" + "Press OK to convert them now, otherwise you will be asked next time.\n", "OK", "Cancel"); - bool exists[NUM_SAVESLOTS]; - uint num = 0; - uint i; + return (dialog0.runModal() != 0); +} - for (i = 0; i < NUM_SAVESLOTS; i++) { - exists[i] = false; - Common::String name = genOldSaveFileName(i); - Common::InSaveFile *f = _saveFileMan->openForLoading(name); - if (f) { - exists[i] = true; - num++; +void SaveLoad_ns::renameOldSavefiles() { + Common::StringList oldFilenames = _saveFileMan->listSavefiles("game.*"); + uint numOldSaves = oldFilenames.size(); + + bool rename = false; + uint success = 0, id; + Common::String oldName, newName; + for (uint i = 0; i < oldFilenames.size(); ++i) { + oldName = oldFilenames[i]; + int e = sscanf(oldName.c_str(), "game.%u", &id); + if (e != 1) { + // this wasn't a savefile, so adjust numOldSaves accordingly + --numOldSaves; + continue; } - delete f; - } - - if (num == 0) { - // there are no old savefiles: nothing to do - return; - } - GUI::MessageDialog dialog0( - "ScummVM found that you have old savefiles for Nippon Safes that should be renamed.\n" - "The old names are no longer supported, so you will not be able to load your games if you don't convert them.\n\n" - "Press OK to convert them now, otherwise you will be asked you next time.\n", "OK", "Cancel"); + if (!rename) { + rename = askRenameOldSavefiles(); + } + if (!rename) { + // return immediately if the user doesn't want to rename the files + return; + } - int choice = dialog0.runModal(); - if (choice == 0) { - // user pressed cancel - return; + newName = genSaveFileName(id); + if (_saveFileMan->renameSavefile(oldName, newName)) { + success++; + } else { + warning("Error %i (%s) occurred while renaming %s to %s", _saveFileMan->getError(), + _saveFileMan->getErrorDesc().c_str(), oldName.c_str(), newName.c_str()); + } } - uint success = 0; - for (i = 0; i < NUM_SAVESLOTS; i++) { - if (exists[i]) { - Common::String oldName = genOldSaveFileName(i); - Common::String newName = genSaveFileName(i); - if (_saveFileMan->renameSavefile(oldName, newName)) { - success++; - } else { - warning("Error %i (%s) occurred while renaming %s to %s", _saveFileMan->getError(), - _saveFileMan->getErrorDesc().c_str(), oldName.c_str(), newName.c_str()); - } - } + if (numOldSaves == 0) { + // there were no old savefiles: nothing to notify + return; } char msg[200]; - if (success == num) { + if (success == numOldSaves) { sprintf(msg, "ScummVM successfully converted all your savefiles."); } else { sprintf(msg, diff --git a/engines/parallaction/saveload.h b/engines/parallaction/saveload.h index 2b2a7ab6a5..0bcc930c8a 100644 --- a/engines/parallaction/saveload.h +++ b/engines/parallaction/saveload.h @@ -62,7 +62,6 @@ public: class SaveLoad_ns : public SaveLoad { Parallaction_ns *_vm; - Common::String genOldSaveFileName(uint slot); protected: void renameOldSavefiles(); diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp index bac7c5f419..ae223ff6cf 100644 --- a/engines/queen/display.cpp +++ b/engines/queen/display.cpp @@ -25,6 +25,7 @@ #include "common/system.h" +#include "common/EventRecorder.h" #include "common/events.h" #include "graphics/cursorman.h" @@ -74,7 +75,7 @@ Display::Display(QueenEngine *vm, OSystem *system) memset(&_dynalum, 0, sizeof(_dynalum)); setupInkColors(); - system->getEventManager()->registerRandomSource(_rnd, "queenDisplay"); + g_eventRec.registerRandomSource(_rnd, "queenDisplay"); } Display::~Display() { diff --git a/engines/queen/music.cpp b/engines/queen/music.cpp index 8a50ae6b40..3d5bfbdf73 100644 --- a/engines/queen/music.cpp +++ b/engines/queen/music.cpp @@ -25,6 +25,7 @@ #include "common/config-manager.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "queen/music.h" #include "queen/queen.h" @@ -84,7 +85,7 @@ MidiMusic::MidiMusic(QueenEngine *vm) _parser->setMidiDriver(this); _parser->setTimerRate(_driver->getBaseTempo()); - vm->getEventManager()->registerRandomSource(_rnd, "queenMusic"); + g_eventRec.registerRandomSource(_rnd, "queenMusic"); } MidiMusic::~MidiMusic() { diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp index ec074190d3..7c351842c4 100644 --- a/engines/queen/queen.cpp +++ b/engines/queen/queen.cpp @@ -31,6 +31,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "queen/queen.h" #include "queen/bankman.h" @@ -193,7 +194,7 @@ namespace Queen { QueenEngine::QueenEngine(OSystem *syst) : Engine(syst), _debugger(0) { - syst->getEventManager()->registerRandomSource(randomizer, "queen"); + g_eventRec.registerRandomSource(randomizer, "queen"); } QueenEngine::~QueenEngine() { diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index faf9cbed80..265008992a 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -204,7 +204,7 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const { // Obtain the last 2 digits of the filename, since they correspond to the save slot slotNum = atoi(file->c_str() + file->size() - 2); - if (slotNum >= 0 && slotNum <= 99) { + if (slotNum >= 0 && slotNum < MAX_SAVES) { Common::InSaveFile *in = saveFileMan->openForLoading(*file); if (in) { for (int i = 0; i < 3; i++) @@ -219,7 +219,7 @@ SaveStateList SagaMetaEngine::listSaves(const char *target) const { return saveList; } -int SagaMetaEngine::getMaximumSaveSlot() const { return 99; } +int SagaMetaEngine::getMaximumSaveSlot() const { return MAX_SAVES - 1; } void SagaMetaEngine::removeSaveState(const char *target, int slot) const { char extension[6]; diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp index d58d1a8900..8b9b45d3ff 100644 --- a/engines/saga/font.cpp +++ b/engines/saga/font.cpp @@ -143,10 +143,7 @@ void Font::createOutline(FontData *font) { int i; int row; int newByteWidth; - int oldByteWidth; int newRowLength = 0; - size_t indexOffset = 0; - int index; int currentByte; unsigned char *basePointer; unsigned char *srcPointer; @@ -154,57 +151,22 @@ void Font::createOutline(FontData *font) { unsigned char *destPointer2; unsigned char *destPointer3; unsigned char charRep; - int nextIndex = 0; - // Populate new font style character data for (i = 0; i < FONT_CHARCOUNT; i++) { newByteWidth = 0; - oldByteWidth = 0; - index = font->normal.fontCharEntry[i].index; - if ((index > 0) || (i == FONT_FIRSTCHAR)) { - index += indexOffset; - } - - bool skip = false; - - if (font->normal.fontCharEntry[i].width != 0 && font->normal.fontCharEntry[i].index < nextIndex) { - // Some characters are copies of earlier characters. - // Look up the original, and make sure not to grow the size of - // the outline font twice. - skip = true; - bool found = false; - for (int j = 0; j < i; j++) { - if (font->normal.fontCharEntry[i].index == font->normal.fontCharEntry[j].index) { - index = font->outline.fontCharEntry[j].index; - found = true; - break; - } - } - if (!found) - error("Invalid index backreference in font char %d", i); - } - font->outline.fontCharEntry[i].index = index; + font->outline.fontCharEntry[i].index = newRowLength; font->outline.fontCharEntry[i].tracking = font->normal.fontCharEntry[i].tracking; font->outline.fontCharEntry[i].flag = font->normal.fontCharEntry[i].flag; - if (font->normal.fontCharEntry[i].width != 0) { + if (font->normal.fontCharEntry[i].width != 0) newByteWidth = getByteLen(font->normal.fontCharEntry[i].width + 2); - oldByteWidth = getByteLen(font->normal.fontCharEntry[i].width); - - if (!skip && newByteWidth > oldByteWidth) { - indexOffset++; - } - } font->outline.fontCharEntry[i].width = font->normal.fontCharEntry[i].width + 2; font->outline.fontCharEntry[i].byteWidth = newByteWidth; - if (!skip) { - newRowLength += newByteWidth; - nextIndex = font->normal.fontCharEntry[i].index + oldByteWidth; - } + newRowLength += newByteWidth; } debug(2, "New row length: %d", newRowLength); @@ -220,10 +182,6 @@ void Font::createOutline(FontData *font) { // Generate outline font representation for (i = 0; i < FONT_CHARCOUNT; i++) { - if (i > 0 && font->normal.fontCharEntry[i].index < font->normal.fontCharEntry[i-1].index) { - // Skip copies - continue; - } for (row = 0; row < font->normal.header.charHeight; row++) { for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) { basePointer = font->outline.font + font->outline.fontCharEntry[i].index + currentByte; diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 4acf93d030..2a2a4b993c 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -29,6 +29,7 @@ #include "common/config-manager.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "sound/mixer.h" @@ -114,7 +115,7 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); _displayClip.left = _displayClip.top = 0; - syst->getEventManager()->registerRandomSource(_rnd, "saga"); + g_eventRec.registerRandomSource(_rnd, "saga"); } SagaEngine::~SagaEngine() { diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 7c1a165ec1..2ddc6979c9 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -194,6 +194,7 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { scriptState.seekLevel = 0; scriptState.runningStep = 0; scriptState.stopOnEvent = false; + scriptState.debugging = false; } Console::~Console() { @@ -2091,28 +2092,30 @@ bool Console::cmdBacktrace(int argc, const char **argv) { printf("\n"); } - return 0; return true; } bool Console::cmdStep(int argc, const char **argv) { if (argc == 2 && atoi(argv[1]) > 0) scriptState.runningStep = atoi(argv[1]) - 1; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepEvent(int argc, const char **argv) { scriptState.stopOnEvent = true; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepRet(int argc, const char **argv) { scriptState.seeking = kDebugSeekLevelRet; scriptState.seekLevel = _vm->_gamestate->_executionStack.size() - 1; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepGlobal(int argc, const char **argv) { @@ -2124,8 +2127,9 @@ bool Console::cmdStepGlobal(int argc, const char **argv) { scriptState.seeking = kDebugSeekGlobal; scriptState.seekSpecial = atoi(argv[1]); + scriptState.debugging = true; - return true; + return false; } bool Console::cmdStepCallk(int argc, const char **argv) { @@ -2156,8 +2160,9 @@ bool Console::cmdStepCallk(int argc, const char **argv) { } else { scriptState.seeking = kDebugSeekCallk; } + scriptState.debugging = true; - return true; + return false; } bool Console::cmdDissassemble(int argc, const char **argv) { @@ -2227,7 +2232,7 @@ bool Console::cmdDissassembleAddress(int argc, const char **argv) { _vm->_gamestate->seg_manager->dereference(vpc, &size); size += vpc.offset; // total segment size - for (int i = 1; i < argc; i++) { + for (int i = 2; i < argc; i++) { if (!scumm_stricmp(argv[i], "bwt")) do_bwc = 1; else if (!scumm_stricmp(argv[i], "bc")) @@ -2322,14 +2327,16 @@ bool Console::cmdSend(int argc, const char **argv) { xstack->fp += argc; _vm->_gamestate->_executionStackPosChanged = true; + scriptState.debugging = true; - return true; + return false; } bool Console::cmdGo(int argc, const char **argv) { + // CHECKME: is this necessary? scriptState.seeking = kDebugSeekNothing; - return true; + return Cmd_Exit(argc, argv); } bool Console::cmdBreakpointList(int argc, const char **argv) { diff --git a/engines/sci/debug.h b/engines/sci/debug.h index cd2de2b3a9..a3c4fab372 100644 --- a/engines/sci/debug.h +++ b/engines/sci/debug.h @@ -38,6 +38,7 @@ enum DebugSeeking { }; struct ScriptState { + bool debugging; bool stopOnEvent; DebugSeeking seeking; // Stepping forward until some special condition is met int runningStep; // Set to > 0 to allow multiple stepping diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 92cfe9daf3..11dd56f2aa 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -311,11 +311,18 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod void script_debug(EngineState *s, bool bp) { // Do we support a separate console? - printf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc)); - disassemble(s, scriptState.xs->addr.pc, 0, 1); - if (scriptState.seeking == kDebugSeekGlobal) - printf("Global %d (0x%x) = %04x:%04x\n", scriptState.seekSpecial, - scriptState.seekSpecial, PRINT_REG(s->script_000->locals_block->_locals[scriptState.seekSpecial])); + /* if (sci_debug_flags & _DEBUG_FLAG_LOGGING) { */ + printf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc)); + disassemble(s, scriptState.xs->addr.pc, 0, 1); + if (scriptState.seeking == kDebugSeekGlobal) + printf("Global %d (0x%x) = %04x:%04x\n", scriptState.seekSpecial, + scriptState.seekSpecial, PRINT_REG(s->script_000->locals_block->_locals[scriptState.seekSpecial])); + /* } */ + +#if 0 + if (!scriptState.debugging) + return; +#endif if (scriptState.seeking && !bp) { // Are we looking for something special? MemObject *mobj = GET_SEGMENT(*s->seg_manager, scriptState.xs->addr.pc.segment, MEM_OBJ_SCRIPT); @@ -370,9 +377,19 @@ void script_debug(EngineState *s, bool bp) { // OK, found whatever we were looking for } } - + printf("Step #%d\n", script_step_counter); disassemble(s, scriptState.xs->addr.pc, 0, 1); + + if (scriptState.runningStep) { + scriptState.runningStep--; + return; + } + + scriptState.debugging = false; + + Console *con = ((Sci::SciEngine*)g_engine)->getSciDebugger(); + con->attach(); } } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 6752ba3e56..905cba9d94 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -169,7 +169,9 @@ int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) { setScriptSize(scr, s, script_nr); scr.buf = (byte *)malloc(scr.buf_size); - dbgPrint("scr.buf ", scr.buf); +#ifdef DEBUG_SEG_MANAGER + printf("scr.buf = %p ", scr.buf); +#endif if (!scr.buf) { scr.freeScript(); warning("SegManager: Not enough memory space for script size"); @@ -864,14 +866,5 @@ int SegManager::freeDynmem(reg_t addr) { return 0; // OK } -void SegManager::dbgPrint(const char* msg, void *i) { -#ifdef DEBUG_SEG_MANAGER - char buf[1000]; - sprintf(buf, "%s = [0x%x], dec:[%d]", msg, i, i); - perror(buf); -#endif -} - - } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index a41d820014..9d406f559f 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -362,13 +362,6 @@ private: * 'seg' is a valid segment */ bool check(SegmentId seg); - - void dbgPrint(const char* msg, void *i); // for debug only - - // Perform garbage collection - // Parameters: (EngineState *) s: The state to operate on - // Effects : Unreachable objects in 's' are deallocated - //void sm_gc(EngineState *s); }; } // End of namespace Sci diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 99b5a86e53..0f8fee0876 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -258,6 +258,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP if (bp->type == BREAK_EXPORT && bp->data.address == bpaddress) { Console *con = ((SciEngine *)g_engine)->getSciDebugger(); con->DebugPrintf("Break on script %d, export %d\n", script, pubfunct); + scriptState.debugging = true; breakpointFlag = true; break; } @@ -325,6 +326,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt con->DebugPrintf("Break on %s (in [%04x:%04x])\n", method_name, PRINT_REG(send_obj)); print_send_action = 1; breakpointFlag = true; + scriptState.debugging = true; break; } bp = bp->next; @@ -652,17 +654,19 @@ void run_vm(EngineState *s, int restoring) { } - if (script_abort_flag) + if (script_abort_flag || g_engine->shouldQuit()) return; // Emergency -// TODO: re-enable this -#if 0 // Debug if this has been requested: - if (script_debug_flag || sci_debug_flags) { + // TODO: re-implement sci_debug_flags + if (scriptState.debugging /* sci_debug_flags*/) { script_debug(s, breakpointFlag); breakpointFlag = false; } -#endif + Console *con = ((Sci::SciEngine*)g_engine)->getSciDebugger(); + if (con->isAttached()) { + con->onFrame(); + } #ifndef DISABLE_VALIDATIONS if (scriptState.xs->sp < scriptState.xs->fp) diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index f711570d11..ba225a9c00 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -266,18 +266,19 @@ struct ExecStack { }; +// These types are used both as identifiers and as elements of bitfields enum BreakpointType { /** * Break when selector is executed. data contains (char *) selector name * (in the format Object::Method) */ - BREAK_SELECTOR, + BREAK_SELECTOR = 1, /** * Break when an exported function is called. data contains * script_no << 16 | export_no. */ - BREAK_EXPORT + BREAK_EXPORT = 2 }; struct Breakpoint { diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index 6b15cdc516..94bb6e0443 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -1380,7 +1380,6 @@ static sci_event_t scummvm_get_event(GfxDriver *drv) { // Open debug console Console *con = ((Sci::SciEngine*)g_engine)->getSciDebugger(); con->attach(); - con->onFrame(); // Clear keyboard event input.type = SCI_EVT_NONE; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index d99f9f0771..943361332f 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -882,7 +882,7 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, if (resnumber == -1) return; if (!file.open(source->location_name)) { - perror("""__FILE__"": (""__LINE__""): failed to open"); + warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str()); return; } fsize = file.size(); @@ -1007,8 +1007,7 @@ int ResourceManager::readResourceMapSCI0(ResourceSource *map) { offset = file.readUint32LE(); if (file.ioFailed()) { - warning("Error while reading %s: ", map->location_name.c_str()); - perror(""); + warning("Error while reading %s", map->location_name.c_str()); return SCI_ERROR_RESMAP_NOT_FOUND; } if (offset == 0xFFFFFFFF) @@ -1079,8 +1078,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { } } if (file.ioFailed()) { - warning("Error while reading %s: ", map->location_name.c_str()); - perror(""); + warning("Error while reading %s", map->location_name.c_str()); return SCI_ERROR_RESMAP_NOT_FOUND; } resId = ResourceId((ResourceType)type, number); diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 504e38c7c1..65d0a4753a 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -283,9 +283,7 @@ uint32 SciEngine::getFlags() const { } Common::String SciEngine::getSavegameName(int nr) const { - char extension[6]; - snprintf(extension, sizeof(extension), ".%03d", nr); - return _targetName + extension; + return _targetName + Common::String::printf(".%03d", nr); } Common::String SciEngine::getSavegamePattern() const { diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 88c258a2e6..3033904357 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -527,9 +527,15 @@ void Actor_v2::walkActor() { if (_moving & MF_TURN) { new_dir = updateActorDirection(false); // FIXME: is this correct? - if (_facing != new_dir) + if (_facing != new_dir) { + + // Actor never stops walking when an object has been selected without this + if (_vm->_game.version ==0) + _moving = 0; + setDirection(new_dir); - else + + } else _moving = 0; return; } @@ -817,6 +823,16 @@ void Actor::setDirection(int direction) { if (_costume == 0) return; + // V0 MM + if (_vm->_game.version == 0) { + if (_moving) + _vm->_costumeLoader->costumeDecodeData(this, _walkFrame, 0); + else + _vm->_costumeLoader->costumeDecodeData(this, _standFrame, 0); + _needRedraw = true; + return; + } + // Update the costume for the new direction (and mark the actor for redraw) aMask = 0x8000; for (i = 0; i < 16; i++, aMask >>= 1) { @@ -1224,7 +1240,10 @@ void Actor::showActor() { _vm->ensureResourceLoaded(rtCostume, _costume); - if (_vm->_game.version <= 2) { + if (_vm->_game.version == 0) { + _cost.reset(); + startAnimActor(_standFrame); + } else if (_vm->_game.version <= 2) { _cost.reset(); startAnimActor(_standFrame); startAnimActor(_initFrame); @@ -1380,6 +1399,13 @@ void ScummEngine::processActors() { Actor** end = _sortedActors + numactors; for (Actor** ac = _sortedActors; ac != end; ++ac) { Actor* a = *ac; + + // V0 MM: 0x057B + if (_game.version == 0) { + ActorC64 *A = (ActorC64*) a; + if ((A->_speaking & 1)) + A->_speaking ^= 0xFE; + } // Draw and animate the actors, except those w/o a costume. // Note: We could 'optimize' this a little bit by only putting // actors with a costume into the _sortedActors array in the @@ -1572,6 +1598,8 @@ void Actor_v2::prepareDrawActorCostume(BaseCostumeRenderer *bcr) { // we need to shift it 8 pixels to the left if (_facing == 90) bcr->_actorX -= 8; + } else if (_vm->_game.version == 0) { + bcr->_actorX += 12; } else if (_vm->_game.version <= 2) { // HACK: We have to adjust the x position by one strip (8 pixels) in // V2 games. However, it is not quite clear to me why. And to fully @@ -1703,6 +1731,12 @@ void Actor::animateActor(int anim) { case 4: // turn to new direction turnToDirection(dir); break; + case 64: + if (_vm->_game.version == 0) { + _moving &= ~MF_TURN; + setDirection(dir); + break; + } default: if (_vm->_game.version <= 2) startAnimActor(anim / 4); @@ -2167,21 +2201,38 @@ void Actor::setActorCostume(int c) { } } -static const char* v0ActorNames[7] = { +static const char* v0ActorNames[0x19] = { "Syd", "Razor", "Dave", "Michael", "Bernard", "Wendy", - "Jeff" + "Jeff", + "", + "Dr Fred", + "Nurse Edna", + "Weird Ed", + "Dead Cousin Ted", + "Purple Tentacle", + "Green Tentacle", + "Meteor", + "Plant", + "", + "", + "", + "", + "", + "", + "Sandy" }; const byte *Actor::getActorName() { - const byte *ptr; + const byte *ptr = NULL; if (_vm->_game.version == 0) { - ptr = (const byte *)v0ActorNames[_number - 1]; + if (_number) + ptr = (const byte *)v0ActorNames[_number - 1]; } else { ptr = _vm->getResourceAddress(rtActorName, _number); } diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index 3e8fe6626b..3f67d42a50 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -380,11 +380,15 @@ protected: class ActorC64 : public Actor_v2 { public: - // FIXME: This flag is never saved, which might lead to broken save states. + // FIXME: These vars are never saved, which might lead to broken save states. byte _miscflags; + byte _speaking, _speakingPrev; + byte _costCommand, _costFrame; public: - ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {} + ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) { + _speaking = _speakingPrev = _costCommand = _costFrame = 0; + } virtual void initActor(int mode) { Actor_v2::initActor(mode); if (mode == -1) { diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp index 472e04b5f3..d480209501 100644 --- a/engines/scumm/boxes.cpp +++ b/engines/scumm/boxes.cpp @@ -445,7 +445,7 @@ byte ScummEngine::getNumBoxes() { return 0; if (_game.version == 8) return (byte)READ_LE_UINT32(ptr); - else if (_game.features >= 5) + else if (_game.version >= 5) return (byte)READ_LE_UINT16(ptr); else return ptr[0]; diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 82497de87a..57b793d579 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -1040,26 +1040,25 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { if (limb >= 8) return 0; + if (a->_cost.start[limb] == 0xFFFF) + return 0; + if (limb == 0) { _draw_top = 200; _draw_bottom = 0; } + + bool flipped = (a->_cost.start[limb] & 0x80) != 0; + byte frameStart = _loaded._frameOffsets[a->_cost.frame[limb]]; + byte frame = _loaded._frameOffsets[frameStart + a->_cost.curpos[limb]]; + if (frame == 0xFF) + return 0; - // TODO: - // get out how animations are handled - byte state = a->_moving != 0 ? 0 : 1; - byte unk1 = (_loaded._animCmds + (state*32) + newDirToOldDir(a->getFacing()) * 8)[limb]; - byte unk2 = _loaded._frameOffsets[_loaded._frameOffsets[limb] + (unk1 & 0x7f)]; - bool flipped = (unk1 & 0x80) != 0; - - byte p1 = _loaded._frameOffsets[unk2]; - byte temp1 = _loaded._baseptr[p1]; - byte temp2 = temp1 + _loaded._dataOffsets[4]; - int offL = _loaded._baseptr[temp1 + 2]; - int offH = _loaded._baseptr[temp2]; - int off = (offH << 8) + offL; + byte ptrLow = _loaded._baseptr[frame]; + byte ptrHigh = ptrLow + _loaded._dataOffsets[4]; + int frameOffset = (_loaded._baseptr[ptrHigh] << 8) + _loaded._baseptr[ptrLow + 2]; // 0x23EF / 0x2400 - const byte *data = _loaded._baseptr + off; + const byte *data = _loaded._baseptr + frameOffset; // Set up the palette data byte palette[4] = { 0, 0, 0, 0 }; @@ -1077,8 +1076,8 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { int offsetY = *data++; // these two fields seems to be most times zero // byte6 was one time 255 in one costume I tried -// int byte5 = *data++; -// int byte6 = *data++; +// int byte5 = *data++; // 0x1F80 // This value is never used +// int byte6 = *data++; // 0x1F86 // This value is subtracted from ?actor drawy? at 0x2383 // debug(3, "byte5: %d", byte5); // debug(3, "byte6: %d", byte6); data += 2; @@ -1091,17 +1090,13 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { if (flipped) { if (offsetX) - xpos += (offsetX-1) * 8; + xpos += (offsetX - 1) * 8; } else { xpos += offsetX * 8; } - // + 4 could be commented, because maybe the _actorX position is - // wrong, I looked at the scumm-c64 interpreter by lloyd - // and there Bernhard is directly on the right in the intro - // but here in ScummVM he is 4 pixel left of the other position. - xpos += _actorX - (a->_width / 2) + 4; - ypos += _actorY - _loaded._maxHeight; + xpos += _actorX - (a->_width / 2); + ypos += (_actorY - _loaded._maxHeight) + 1; // +1 as we appear to be 1 pixel away from the original interpreter // This code is very similar to procC64() for (int y = 0; y < height; ++y) { @@ -1111,9 +1106,9 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { int realX = 0; if (flipped) { if (offsetX == 0||offsetX == 1) { - realX = width-(x+1); + realX = width-(x + 1); } else if (offsetX == 2) { - realX = width-(x+2); + realX = width-(x + 2); } } else { realX = x; @@ -1134,10 +1129,8 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { } _draw_top = MIN(_draw_top, ypos); - _draw_bottom = MAX(_draw_bottom, ypos+height); - // if +4 above is NOT commented, here "+(flipped ? 4 : 0)" can be commented out - // and other way round - _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos+(width*8)/*+(flipped ? 4 : 0)*/, ypos, ypos+height, _actorID); + _draw_bottom = MAX(_draw_bottom, ypos + height); + _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos + (width * 8), ypos, ypos + height, _actorID); return 0; } @@ -1151,6 +1144,7 @@ void C64CostumeRenderer::setCostume(int costume, int shadow) { void C64CostumeLoader::loadCostume(int id) { const byte *ptr = _vm->getResourceAddress(rtCostume, id); + _id = id; _baseptr = ptr + 9; @@ -1165,33 +1159,152 @@ void C64CostumeLoader::loadCostume(int id) { _animCmds = _baseptr + READ_LE_UINT16(ptr + 7); _maxHeight = 0; - for (int i = 0; i < 8; ++i) { - int pid = _frameOffsets[_frameOffsets[i]]; - byte p1 = _frameOffsets[pid]; - byte b = _baseptr[p1]; - byte c = b + _dataOffsets[4]; - int offL = _baseptr[b + 2]; - int offH = _baseptr[c]; - int off = (offH << 8) + offL; - const byte *data = _baseptr + off; - - if (data[3] > _maxHeight) { - _maxHeight = data[3]; // data[3] is libs's Y offset +} + +void C64CostumeLoader::frameUpdate(ActorC64 *a, int cmd ) { + byte limbFrames = 0; + + // Each costume-command has 8 limbs (0x2622) + cmd <<= 3; + + for (int limb = 0, pos = 0; limb < 8; ++limb, pos = 0) { + // get a limb frames ptr from the costume command + limbFrames = ((_animCmds + cmd)[limb]); + + // Dont change limb if entry is invalid + if (limbFrames == 0xFF) + continue; + + // Has limb frames ptr changed since last update? + if (a->_cost.start[limb] == limbFrames) + continue; + + // Set new limb command addresses + a->_cost.start[limb] = limbFrames; + a->_cost.frame[limb] = _frameOffsets[limb] + (limbFrames & 0x7f); // limb animation-frames ptr + + // Get first entry of a limbs' frames + byte frameStart = _frameOffsets[ a->_cost.frame[limb]]; + + // Loop each frame in this limb until we reach the end marker + while (pos != 0xFF) { // This is just so we dont overflow + byte frame = _frameOffsets[frameStart + pos]; + + // Each animation-frame until we find end + if (frame == 0xFF) + break; + + byte ptrLow = _baseptr[frame]; + byte ptrHigh = ptrLow + _dataOffsets[4]; + int frameOffset = (_baseptr[ptrHigh] << 8) + _baseptr[ptrLow + 2]; // 0x23EF / 0x2400 + + const byte *data = _baseptr + frameOffset; + + if (data[3] > _maxHeight) + _maxHeight = data[3] + 1; + + ++pos; } + + // Set ending position of limb frames + a->_cost.end[limb] = pos - 1; + a->_cost.curpos[limb] = 0; } - ++_maxHeight; } -void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { +// based on 0x2BCA, doesn't match disassembly because 'oldDir' variable +// is not the same value as stored in the original interpreter +int C64CostumeLoader::dirToDirStop(int oldDir) { + switch (oldDir) { + case 0: + return 4; // Left + case 1: + return 5; // Right + case 2: + return 6; // Face Camera + case 3: + return 7; // Face Away + } + // shouldnt' be reached + return 4; } -byte C64CostumeLoader::increaseAnims(Actor *a) { - return 0; +void C64CostumeLoader::actorSpeak(ActorC64 *a, int &cmd) { + if ((a->_speaking & 0x80)) + cmd += 0x0C; + else + cmd += 0x10; } -byte C64CostumeLoader::increaseAnim(Actor *a, int slot) { - return 0; +void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { + ActorC64 *A = (ActorC64 *)a; + int dir = newDirToOldDir(a->getFacing()); + int command = dir; + + loadCostume(a->_costume); + + // Enable/Disable speaking flag + if (frame == a->_talkStartFrame) { + A->_speaking = 1; + return; + } + if (frame == a->_talkStopFrame) { + A->_speaking = 0; + return; + } + + // Different command for stand frame + if (frame == a->_standFrame) + command = dirToDirStop(dir); + + // Update the limb frames + frameUpdate(A, command); + + // Keep current command/frame mode + A->_costCommand = dir; + A->_costFrame = frame; + + // Update 'speaking' frames? + if (A->_speaking) { + command = dir; // Incase standing frame was set as cmd + actorSpeak(A, command); + + // Update the limb speak frames + frameUpdate(A, command); + } } +byte C64CostumeLoader::increaseAnims(Actor *a) { + ActorC64 *A = (ActorC64 *)a; + + // check if the actor speak flag has changed since last frame increase + if (A->_speaking != A->_speakingPrev) { + int cmd = A->_costCommand; + A->_speakingPrev = A->_speaking; + + // Update to use speak frame + if (A->_speaking & 0x80) { + actorSpeak(A, cmd); + + } else { + // Update to use stand frame + if (A->_costFrame == A->_standFrame) + cmd = dirToDirStop(cmd); + } + + // Update the limb frames + frameUpdate(A, cmd); + } + + // increase each frame pos + for (int limb = 0; limb < 8; ++limb) { + if (a->_cost.curpos[limb] < a->_cost.end[limb]) + a->_cost.curpos[limb]++; + else + a->_cost.curpos[limb] = 0; + } + + return 1; +} } // End of namespace Scumm diff --git a/engines/scumm/costume.h b/engines/scumm/costume.h index 003bd6ce2b..8e1910abcf 100644 --- a/engines/scumm/costume.h +++ b/engines/scumm/costume.h @@ -79,8 +79,12 @@ public: byte increaseAnims(Actor *a); int _maxHeight; + protected: - byte increaseAnim(Actor *a, int slot); + void actorSpeak(ActorC64 *a, int &cmd); + int dirToDirStop(int oldDir); + void frameUpdate(ActorC64 *A, int cmd); + }; class ClassicCostumeRenderer : public BaseCostumeRenderer { diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 5fa74d22c3..8beb2ef720 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -723,6 +723,32 @@ GameDescriptor ScummMetaEngine::findGame(const char *gameid) const { return AdvancedDetector::findGameID(gameid, gameDescriptions, obsoleteGameIDsTable); } +static Common::String generatePreferredTarget(const DetectorResult &x) { + Common::String res(x.game.gameid); + + if (x.game.preferredTag) { + res = res + "-" + x.game.preferredTag; + } + + if (x.game.features & GF_DEMO) { + res = res + "-demo"; + } + + // Append the platform, if a non-standard one has been specified. + if (x.game.platform != Common::kPlatformPC && x.game.platform != Common::kPlatformUnknown) { + // HACK: For CoMI, it's pointless to encode the fact that it's for Windows + if (x.game.id != GID_CMI) + res = res + "-" + Common::getPlatformAbbrev(x.game.platform); + } + + // Append the language, if a non-standard one has been specified + if (x.language != Common::EN_ANY && x.language != Common::UNK_LANG) { + res = res + "-" + Common::getLanguageCode(x.language); + } + + return res; +} + GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const { GameList detectedGames; Common::List<DetectorResult> results; @@ -737,34 +763,34 @@ GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const { const PlainGameDescriptor *g = findPlainGameDescriptor(x->game.gameid, gameDescriptions); assert(g); GameDescriptor dg(x->game.gameid, g->description, x->language, x->game.platform); - dg.updateDesc(x->extra); // Append additional information, if set, to the description. + + // Append additional information, if set, to the description. + dg.updateDesc(x->extra); // Compute and set the preferred target name for this game. // Based on generateComplexID() in advancedDetector.cpp. - Common::String res(x->game.gameid); - - if (x->game.preferredTag) { - res = res + "-" + x->game.preferredTag; - } - - if (x->game.features & GF_DEMO) { - res = res + "-demo"; - } - - // Append the platform, if a non-standard one has been specified. - if (x->game.platform != Common::kPlatformPC && x->game.platform != Common::kPlatformUnknown) { - // HACK: For CoMI, it's pointless to encode the fact that it's for Windows - if (x->game.id != GID_CMI) - res = res + "-" + Common::getPlatformAbbrev(x->game.platform); - } - - // Append the language, if a non-standard one has been specified - if (x->language != Common::EN_ANY && x->language != Common::UNK_LANG) { - res = res + "-" + Common::getLanguageCode(x->language); + dg["preferredtarget"] = generatePreferredTarget(*x); + + // HACK: Detect and distinguish the FM-TOWNS demos + if (x->game.platform == Common::kPlatformFMTowns && (x->game.features & GF_DEMO)) { + if (x->md5 == "2d388339d6050d8ccaa757b64633954e") { + // Indy + Loom demo + dg.description() = "Indiana Jones and the Last Crusade & Loom"; + dg.updateDesc(x->extra); + dg["preferredtarget"] = "indyloom"; + } else if (x->md5 == "77f5c9cc0986eb729c1a6b4c8823bbae") { + // Zak + Loom demo + dg.description() = "Zak McKracken & Loom"; + dg.updateDesc(x->extra); + dg["preferredtarget"] = "zakloom"; + } else if (x->md5 == "3938ee1aa4433fca9d9308c9891172b1") { + // Indy + Zak demo + dg.description() = "Indiana Jones and the Last Crusade & Zak McKracken"; + dg.updateDesc(x->extra); + dg["preferredtarget"] = "indyzak"; + } } - dg["preferredtarget"] = res; - dg.setGUIOptions(x->game.guioptions); detectedGames.push_back(dg); diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index 92024a21cc..5054bffd30 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -230,14 +230,14 @@ static const GameSettings gameVariantsTable[] = { {"monkey2", 0, 0, GID_MONKEY2, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NOSPEECH}, - {"atlantis", "", 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NOSPEECH}, - {"atlantis", "CD" , 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NONE}, + {"atlantis", "" , 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NONE}, + {"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_ADLIB | MDT_MIDI, 0, UNK, GUIO_NOSPEECH}, - {"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, - {"tentacle", "CD", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, - {"samnmax", "", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, - {"samnmax", "CD", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"samnmax", "", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NONE}, + {"samnmax", "Floppy", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO_NOSPEECH}, #ifdef ENABLE_SCUMM_7_8 {"ft", 0, 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO_NOMIDI}, diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 880fab04a5..42e49afcc1 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -439,7 +439,7 @@ ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm) new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P'); new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L'); - new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S'); + _saveButton = new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S'); new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O'); #ifndef DISABLE_HELP @@ -471,6 +471,13 @@ ScummMenuDialog::~ScummMenuDialog() { delete _loadDialog; } +void ScummMenuDialog::reflowLayout() { + if (!_vm->canSaveGameStateCurrently()) + _saveButton->setEnabled(false); + + Dialog::reflowLayout(); +} + void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { switch (cmd) { case kSaveCmd: diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index af844272fa..d4ecbde534 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -88,6 +88,8 @@ public: ~ScummMenuDialog(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); + virtual void reflowLayout(); + protected: ScummEngine *_vm; @@ -99,6 +101,8 @@ protected: SaveLoadChooser *_saveDialog; SaveLoadChooser *_loadDialog; + GUI::ButtonWidget *_saveButton; + void save(); void load(); }; diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index 3f101691c7..6dc31b09ef 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -126,7 +126,7 @@ bool ScummFile::openSubFile(const Common::String &filename) { bool ScummFile::eos() const { - return _subFileLen ? (pos() >= _subFileLen) : File::eos(); // FIXME + return _subFileLen ? _myEos : File::eos(); } int32 ScummFile::pos() const { @@ -154,7 +154,10 @@ bool ScummFile::seek(int32 offs, int whence) { assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen)); whence = SEEK_SET; } - return File::seek(offs, whence); + bool ret = File::seek(offs, whence); + if (ret) + _myEos = false; + return ret; } uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { @@ -167,7 +170,7 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { int32 newPos = curPos + dataSize; if (newPos > _subFileLen) { dataSize = _subFileLen - curPos; - _myIoFailed = true; + _myEos = true; } } diff --git a/engines/scumm/file.h b/engines/scumm/file.h index aa52dd069f..c37c2f036e 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -55,7 +55,7 @@ private: byte _encbyte; int32 _subFileStart; int32 _subFileLen; - bool _myIoFailed; + bool _myEos; // Have we read past the end of the subfile? void setSubfileRange(int32 start, int32 len); void resetSubfile(); @@ -67,8 +67,7 @@ public: bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); - bool ioFailed() const { return _myIoFailed || BaseScummFile::ioFailed(); } - void clearIOFailed() { _myIoFailed = false; BaseScummFile::clearIOFailed(); } + void clearErr() { _myEos = false; BaseScummFile::clearErr(); } bool eos() const; int32 pos() const; diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 5961ec4013..18cba0ab4a 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -758,18 +758,18 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid } void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { - byte *dstL1 = dst; - byte *dstL2 = dst + dstPitch; + uint16 *dstL1 = (uint16 *)dst; + uint16 *dstL2 = (uint16 *)(dst + dstPitch); - int dstAdd = dstPitch * 2 - w * 2; - int srcAdd = srcPitch - w; + const int dstAdd = dstPitch - w; + const int srcAdd = srcPitch - w; while (h--) { - for (int x = 0; x < w; ++x, dstL1 += 2, dstL2 += 2) { + for (int x = 0; x < w; ++x) { uint16 col = *src++; col |= col << 8; - *(uint16*)(dstL1) = col; - *(uint16*)(dstL2) = col; + *dstL1++ = col; + *dstL2++ = col; } dstL1 += dstAdd; dstL2 += dstAdd; src += srcAdd; diff --git a/engines/scumm/he/cup_player_he.cpp b/engines/scumm/he/cup_player_he.cpp index 51176c5df9..39615edb6a 100644 --- a/engines/scumm/he/cup_player_he.cpp +++ b/engines/scumm/he/cup_player_he.cpp @@ -91,20 +91,19 @@ void CUP_Player::close() { } void CUP_Player::play() { - while (parseNextHeaderTag(_fileStream)) { - if (_fileStream.ioFailed()) { - return; - } - } + while (parseNextHeaderTag(_fileStream)) { } + + if (_fileStream.eos() || _fileStream.err()) + return; + debug(1, "rate %d width %d height %d", _playbackRate, _width, _height); int ticks = _system->getMillis(); while (_dataSize != 0 && !_vm->shouldQuit()) { - while (parseNextBlockTag(_fileStream)) { - if (_fileStream.ioFailed()) { - return; - } - } + while (parseNextBlockTag(_fileStream)) { } + if (_fileStream.eos() || _fileStream.err()) + return; + int diff = _system->getMillis() - ticks; if (diff >= 0 && diff <= _playbackRate) { _system->delayMillis(_playbackRate - diff); @@ -200,6 +199,10 @@ void CUP_Player::waitForSfxChannel(int channel) { bool CUP_Player::parseNextHeaderTag(Common::SeekableReadStream &dataStream) { uint32 tag = dataStream.readUint32BE(); uint32 size = dataStream.readUint32BE() - 8; + + if (dataStream.eos()) + return false; + uint32 next = dataStream.pos() + size; debug(1, "New header tag %s %d dataSize %d", tag2str(tag), size, _dataSize); switch (tag) { diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index 4c2da19cc5..9e905b0e79 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -78,7 +78,7 @@ protected: int virtScreenSave(byte *dst, int x1, int y1, int x2, int y2); void virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2); - int convertFilePath(byte *dst); + int convertFilePath(byte *dst, int dstSize); virtual void decodeParseString(int a, int b); void swapObjects(int object1, int object2); diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index fe0904d632..84fec085cc 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -1621,7 +1621,7 @@ void ScummEngine_v100he::o100_roomOps() { copyScriptString((byte *)buffer, sizeof(buffer)); - r = convertFilePath(buffer); + r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o100_roomOps: case 137: filename %s", _saveLoadFileName); @@ -2239,7 +2239,7 @@ void ScummEngine_v100he::o100_videoOps() { if (_videoParams.flags == 0) _videoParams.flags = 4; - const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename); + const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename, sizeof(_videoParams.filename)); if (_videoParams.flags == 2) { VAR(119) = _moviePlay->load(filename, _videoParams.flags, _videoParams.wizResNum); } else { diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index 5ad447b1c7..f186495f81 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -93,7 +93,7 @@ void ScummEngine_v60he::setupOpcodes() { _opcodes[0xed].setProc(0, 0); } -int ScummEngine_v60he::convertFilePath(byte *dst) { +int ScummEngine_v60he::convertFilePath(byte *dst, int dstSize) { debug(1, "convertFilePath: original filePath is %s", dst); int len = resStrLen(dst); @@ -113,16 +113,25 @@ int ScummEngine_v60he::convertFilePath(byte *dst) { // Strip path int r = 0; - if (dst[0] == '.' && dst[1] == '/') { // Game Data Path + if (dst[len - 3] == 's' && dst[len - 2] == 'g') { // Save Game File + // Change filename prefix to target name, for save game files. + char saveName[20]; + sprintf(saveName, "%s.sg%c", _targetName.c_str(), dst[len - 1]); + memcpy(dst, saveName, 20); + } else if (dst[0] == '.' && dst[1] == '/') { // Game Data Path + // The default game data path is set to './' by ScummVM r = 2; } else if (dst[0] == '*' && dst[1] == '/') { // Save Game Path (HE72 - HE100) + // The default save game path is set to '*/' by ScummVM r = 2; } else if (dst[0] == 'c' && dst[1] == ':') { // Save Game Path (HE60 - HE71) + // The default save path is game path (DOS) or 'c:/hegames/' (Windows) for (r = len; r != 0; r--) { if (dst[r - 1] == '/') break; } } else if (dst[0] == 'u' && dst[1] == 's') { // Save Game Path (Moonbase Commander) + // The default save path is 'user/' r = 5; } @@ -269,7 +278,7 @@ void ScummEngine_v60he::o60_roomOps() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - r = convertFilePath(buffer); + r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o60_roomOps: case 221: filename %s", _saveLoadFileName); @@ -684,7 +693,7 @@ void ScummEngine_v60he::o60_openFile() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - filename = (char *)buffer + convertFilePath(buffer); + filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "Final filename to %s", filename); mode = pop(); @@ -738,7 +747,7 @@ void ScummEngine_v60he::o60_deleteFile() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - filename = (char *)buffer + convertFilePath(buffer); + filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "o60_deleteFile (\"%s\")", filename); @@ -760,8 +769,8 @@ void ScummEngine_v60he::o60_rename() { len = resStrLen(_scriptPointer); _scriptPointer += len + 1; - oldFilename = (char *)buffer1 + convertFilePath(buffer1); - newFilename = (char *)buffer2 + convertFilePath(buffer2); + oldFilename = (char *)buffer1 + convertFilePath(buffer1, sizeof(buffer1)); + newFilename = (char *)buffer2 + convertFilePath(buffer2, sizeof(buffer2)); debug(1, "o60_rename (\"%s\" to \"%s\")", oldFilename, newFilename); diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 64c63baa9d..6224ef5b47 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -713,7 +713,7 @@ void ScummEngine_v72he::o72_roomOps() { copyScriptString((byte *)buffer, sizeof(buffer)); - r = convertFilePath(buffer); + r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o72_roomOps: case 221: filename %s", _saveLoadFileName); @@ -1401,7 +1401,7 @@ void ScummEngine_v72he::o72_openFile() { strcpy((char *)buffer, "moonbase.ini"); } - const char *filename = (char *)buffer + convertFilePath(buffer); + const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "Final filename to %s", filename); slot = -1; @@ -1547,7 +1547,7 @@ void ScummEngine_v72he::o72_deleteFile() { byte buffer[256]; copyScriptString(buffer, sizeof(buffer)); - const char *filename = (char *)buffer + convertFilePath(buffer); + const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); debug(1, "o72_deleteFile(%s)", filename); @@ -1562,8 +1562,8 @@ void ScummEngine_v72he::o72_rename() { copyScriptString(buffer1, sizeof(buffer1)); copyScriptString(buffer2, sizeof(buffer2)); - const char *newFilename = (char *)buffer1 + convertFilePath(buffer1); - const char *oldFilename = (char *)buffer2 + convertFilePath(buffer2); + const char *newFilename = (char *)buffer1 + convertFilePath(buffer1, sizeof(buffer1)); + const char *oldFilename = (char *)buffer2 + convertFilePath(buffer2, sizeof(buffer2)); _saveFileMan->renameSavefile(oldFilename, newFilename); diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index b71a0f9e10..d7e36106ea 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -89,7 +89,7 @@ void ScummEngine_v80he::o80_getFileSize() { byte buffer[256]; copyScriptString(buffer, sizeof(buffer)); - const char *filename = (char *)buffer + convertFilePath(buffer); + const char *filename = (char *)buffer + convertFilePath(buffer, sizeof(buffer)); Common::SeekableReadStream *f = 0; if (!_saveFileMan->listSavefiles(filename).empty()) { @@ -154,7 +154,7 @@ void ScummEngine_v80he::o80_readConfigFile() { copyScriptString(section, sizeof(section)); copyScriptString(filename, sizeof(filename)); - r = convertFilePath(filename); + r = convertFilePath(filename, sizeof(filename)); if (_game.id == GID_TREASUREHUNT) { // WORKAROUND: Remove invalid characters @@ -222,7 +222,7 @@ void ScummEngine_v80he::o80_writeConfigFile() { error("o80_writeConfigFile: default type %d", subOp); } - r = convertFilePath(filename); + r = convertFilePath(filename, sizeof(filename)); if (_game.id == GID_TREASUREHUNT) { // WORKAROUND: Remove invalid characters diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index f97771a4f8..2da58b4480 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1426,7 +1426,7 @@ void ScummEngine_v90he::o90_videoOps() { if (_videoParams.flags == 0) _videoParams.flags = 4; - const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename); + const char *filename = (char *)_videoParams.filename + convertFilePath(_videoParams.filename, sizeof(_videoParams.filename)); if (_videoParams.flags & 2) { VAR(119) = _moviePlay->load(filename, _videoParams.flags, _videoParams.wizResNum); } else { diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index 4c20ed7835..6b1db38b23 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -2083,7 +2083,7 @@ void Wiz::processWizImage(const WizParameters *params) { Common::File f; memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); + _vm->convertFilePath(filename, sizeof(filename)); if (f.open((const char *)filename)) { uint32 id = f.readUint32BE(); @@ -2126,7 +2126,7 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 0: memcpy(filename, params->filename, 260); - _vm->convertFilePath(filename); + _vm->convertFilePath(filename, sizeof(filename)); if (!f.open((const char *)filename)) { debug(0, "Unable to open for write '%s'", filename); diff --git a/engines/scumm/imuse_digi/dimuse_bndmgr.cpp b/engines/scumm/imuse_digi/dimuse_bndmgr.cpp index 4577a11fe1..be5f7623ca 100644 --- a/engines/scumm/imuse_digi/dimuse_bndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_bndmgr.cpp @@ -225,7 +225,7 @@ bool BundleMgr::loadCompTable(int32 index) { _file->seek(8, SEEK_CUR); if (tag != MKID_BE('COMP')) { - error("BundleMgr::loadCompTable() Compressed sound %d invalid (%s)", index, tag2str(tag)); + error("BundleMgr::loadCompTable() Compressed sound %d (%s:%d) invalid (%s)", index, _file->getName(), _bundleTable[index].offset, tag2str(tag)); return false; } diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 61b714a3e2..ab32992b03 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -110,9 +110,9 @@ void ScummEngine_v80he::parseEvent(Common::Event event) { void ScummEngine::parseEvent(Common::Event event) { switch (event.type) { case Common::EVENT_KEYDOWN: - if (event.kbd.keycode >= '0' && event.kbd.keycode <= '9' - && (event.kbd.flags == Common::KBD_ALT || - event.kbd.flags == Common::KBD_CTRL)) { + if (event.kbd.keycode >= '0' && event.kbd.keycode <= '9' && + ((event.kbd.flags == Common::KBD_ALT && canSaveGameStateCurrently()) || + (event.kbd.flags == Common::KBD_CTRL && canLoadGameStateCurrently()))) { _saveLoadSlot = event.kbd.keycode - '0'; // don't overwrite autosave (slot 0) @@ -302,17 +302,6 @@ void ScummEngine::processInput() { // _mouseAndKeyboardStat = 0; - // Interpret 'return' as left click and 'tab' as right click - if (lastKeyHit.keycode && _cursor.state > 0) { - if (lastKeyHit.keycode == Common::KEYCODE_TAB) { - _mouseAndKeyboardStat = MBS_RIGHT_CLICK; - lastKeyHit.reset(); - } else if (lastKeyHit.keycode == Common::KEYCODE_RETURN) { - _mouseAndKeyboardStat = MBS_LEFT_CLICK; - lastKeyHit.reset(); - } - } - if ((_leftBtnPressed & msClicked) && (_rightBtnPressed & msClicked) && _game.version >= 4) { // Pressing both mouse buttons is treated as if you pressed // the cutscene exit key (ESC) in V4+ games. That mimicks diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index f29be071e0..2eab2cfa3a 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -181,7 +181,11 @@ void ScummEngine::clearOwnerOf(int obj) { // Alternatively, scan the inventory to see if the object is in there... for (i = 0; i < _numInventory; i++) { if (_inventory[i] == obj) { - assert(WIO_INVENTORY == whereIsObject(obj)); + if (_game.version == 0) + assert(WIO_INVENTORY == whereIsObjectInventory(obj)); + else + assert(WIO_INVENTORY == whereIsObject(obj)); + // Found the object! Nuke it from the inventory. _res->nukeResource(rtInventory, i); _inventory[i] = 0; @@ -286,7 +290,7 @@ int ScummEngine::getState(int obj) { // it. Fortunately this does not prevent frustrated players from // blowing up the mansion, should they feel the urge to. - if (_game.id == GID_MANIAC && (obj == 182 || obj == 193)) + if (_game.id == GID_MANIAC && _game.version != 0 && (obj == 182 || obj == 193)) _objectStateTable[obj] |= kObjectState_08; } @@ -317,6 +321,15 @@ int ScummEngine::getObjectIndex(int object) const { return -1; } +int ScummEngine::whereIsObjectInventory(int object) { + int res = 0; + _v0ObjectInInventory = true; + res = whereIsObject(object); + _v0ObjectInInventory = false; + + return res; +} + int ScummEngine::whereIsObject(int object) const { int i; @@ -326,7 +339,7 @@ int ScummEngine::whereIsObject(int object) const { if (object < 1) return WIO_NOT_FOUND; - if (_objectOwnerTable[object] != OF_OWNER_ROOM) { + if ((_objectOwnerTable[object] != OF_OWNER_ROOM && _game.version != 0) || _v0ObjectInInventory) { for (i = 0; i < _numInventory; i++) if (_inventory[i] == object) return WIO_INVENTORY; @@ -334,7 +347,7 @@ int ScummEngine::whereIsObject(int object) const { } for (i = (_numLocalObjects-1); i > 0; i--) - if (_objs[i].obj_nr == object) { + if ((_objs[i].obj_nr == object && !_v0ObjectIndex) || (_v0ObjectIndex && i == object)) { if (_objs[i].fl_object_index) return WIO_FLOBJECT; return WIO_ROOM; @@ -379,7 +392,7 @@ int ScummEngine::getObjectOrActorXY(int object, int &x, int &y) { * Returns X, Y and direction in angles */ void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) { - int idx = getObjectIndex(object); + int idx = (_v0ObjectIndex) ? object : getObjectIndex(object); assert(idx >= 0); ObjectData &od = _objs[idx]; int state; @@ -434,7 +447,7 @@ void ScummEngine::getObjectXYPos(int object, int &x, int &y, int &dir) { dir = oldDirToNewDir(od.actordir & 3); } -static int getDist(int x, int y, int x2, int y2) { +int ScummEngine::getDist(int x, int y, int x2, int y2) { int a = ABS(y - y2); int b = ABS(x - x2); return MAX(a, b); @@ -475,6 +488,14 @@ int ScummEngine::getObjActToObjActDist(int a, int b) { return getDist(x, y, x2, y2); } +int ScummEngine_v0::findObjectIndex(int x, int y) { + int objIdx; + _v0ObjectIndex = true; + objIdx = findObject(x, y); + _v0ObjectIndex = false; + return objIdx; +} + int ScummEngine::findObject(int x, int y) { int i, b; byte a; @@ -504,8 +525,12 @@ int ScummEngine::findObject(int x, int y) { } #endif if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x && - _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) - return _objs[i].obj_nr; + _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) { + if (_game.version == 0 && _v0ObjectIndex) + return i; + else + return _objs[i].obj_nr; + } break; } } while ((_objs[b].state & mask) == a); @@ -811,6 +836,9 @@ void ScummEngine_v3old::resetRoomObjects() { if (_dumpScripts) { char buf[32]; sprintf(buf, "roomobj-%d-", _roomResource); + if (_game.version == 0) + sprintf(buf + 11, "%d-", od->flags); + dumpResource(buf, od->obj_nr, room + od->OBCDoffset); } } @@ -1033,6 +1061,10 @@ void ScummEngine::updateObjectStates() { int i; ObjectData *od = &_objs[1]; for (i = 1; i < _numLocalObjects; i++, od++) { + // V0 MM, Room objects with Flag == 1 are objects with 'no-state' (room specific objects, non-pickup) + if (_game.version == 0 && od->flags == 1) + continue; + if (od->obj_nr > 0) od->state = getState(od->obj_nr); } @@ -1155,7 +1187,7 @@ const byte *ScummEngine::getObjOrActorName(int obj) { void ScummEngine::setObjectName(int obj) { int i; - if (obj < _numActors) + if (obj < _numActors && _game.version != 0) error("Can't set actor %d name with new-name-of", obj); for (i = 0; i < _numNewNames; i++) { @@ -1181,8 +1213,13 @@ void ScummEngine::setObjectName(int obj) { uint32 ScummEngine::getOBCDOffs(int object) const { int i; - if (_objectOwnerTable[object] != OF_OWNER_ROOM) + if ((_objectOwnerTable[object] != OF_OWNER_ROOM && (_game.version != 0)) || _v0ObjectInInventory) return 0; + + // V0 MM Return by Index + if (_v0ObjectIndex) + return _objs[object].OBCDoffset; + for (i = (_numLocalObjects-1); i > 0; i--) { if (_objs[i].obj_nr == object) { if (_objs[i].fl_object_index != 0) @@ -1194,17 +1231,20 @@ uint32 ScummEngine::getOBCDOffs(int object) const { } byte *ScummEngine::getOBCDFromObject(int obj) { + bool useInventory = _v0ObjectInInventory; int i; byte *ptr; - if (_objectOwnerTable[obj] != OF_OWNER_ROOM) { + _v0ObjectInInventory = false; + + if ((_objectOwnerTable[obj] != OF_OWNER_ROOM && (_game.version != 0)) || useInventory) { for (i = 0; i < _numInventory; i++) { if (_inventory[i] == obj) return getResourceAddress(rtInventory, i); } } else { for (i = (_numLocalObjects-1); i > 0; --i) { - if (_objs[i].obj_nr == obj) { + if ((_objs[i].obj_nr == obj && !_v0ObjectIndex) || (_v0ObjectIndex && i == obj)) { if (_objs[i].fl_object_index) { assert(_objs[i].OBCDoffset == 8); ptr = getResourceAddress(rtFlObject, _objs[i].fl_object_index); diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 88802a205f..67baff97b3 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -229,7 +229,7 @@ void ScummEngine::askForDisk(const char *filename, int disknum) { sprintf(buf, "Cannot find file: '%s'\nInsert disc %d into drive %s\nPress OK to retry, Quit to exit", filename, disknum, _gameDataDir.getPath().c_str()); #endif - result = displayMessage("Quit", buf); + result = displayMessage("Quit", "%s", buf); if (!result) { error("Cannot find file: '%s'", filename); } @@ -253,10 +253,10 @@ void ScummEngine::readIndexFile() { if (_game.version <= 5) { // Figure out the sizes of various resources - while (!_fileHandle->eos()) { + while (true) { blocktype = _fileHandle->readUint32BE(); itemsize = _fileHandle->readUint32BE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; switch (blocktype) { case MKID_BE('DOBJ'): @@ -285,7 +285,6 @@ void ScummEngine::readIndexFile() { } _fileHandle->seek(itemsize - 8, SEEK_CUR); } - _fileHandle->clearIOFailed(); _fileHandle->seek(0, SEEK_SET); } @@ -300,7 +299,7 @@ void ScummEngine::readIndexFile() { blocktype = _fileHandle->readUint32BE(); itemsize = _fileHandle->readUint32BE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; numblock++; @@ -689,7 +688,7 @@ int ScummEngine::loadResource(int type, int idx) { dumpResource("script-", idx, getResourceAddress(rtScript, idx)); } - if (!_fileHandle->ioFailed()) { + if (!_fileHandle->err() && !_fileHandle->eos()) { return 1; } diff --git a/engines/scumm/resource_v2.cpp b/engines/scumm/resource_v2.cpp index 184f3d94df..e469c721b1 100644 --- a/engines/scumm/resource_v2.cpp +++ b/engines/scumm/resource_v2.cpp @@ -138,7 +138,7 @@ void ScummEngine_v2::readEnhancedIndexFile() { _fileHandle->seek(_numScripts * 3, SEEK_CUR); _numSounds = _fileHandle->readByte(); - _fileHandle->clearIOFailed(); + _fileHandle->clearErr(); _fileHandle->seek(0, SEEK_SET); readMAXS(0); diff --git a/engines/scumm/resource_v3.cpp b/engines/scumm/resource_v3.cpp index 420f71cf03..0728395055 100644 --- a/engines/scumm/resource_v3.cpp +++ b/engines/scumm/resource_v3.cpp @@ -80,7 +80,7 @@ void ScummEngine_v3old::readIndexFile() { _fileHandle->seek(_numScripts * 3, SEEK_CUR); _numSounds = _fileHandle->readByte(); - _fileHandle->clearIOFailed(); + _fileHandle->clearErr(); _fileHandle->seek(0, SEEK_SET); readMAXS(0); diff --git a/engines/scumm/resource_v4.cpp b/engines/scumm/resource_v4.cpp index 28e0fb05b5..75858f7b42 100644 --- a/engines/scumm/resource_v4.cpp +++ b/engines/scumm/resource_v4.cpp @@ -61,11 +61,11 @@ void ScummEngine_v4::readIndexFile() { closeRoom(); openRoom(0); - while (!_fileHandle->eos()) { + while (true) { // Figure out the sizes of various resources itemsize = _fileHandle->readUint32LE(); blocktype = _fileHandle->readUint16LE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; switch (blocktype) { @@ -95,16 +95,15 @@ void ScummEngine_v4::readIndexFile() { _fileHandle->seek(itemsize - 8, SEEK_CUR); } - _fileHandle->clearIOFailed(); _fileHandle->seek(0, SEEK_SET); readMAXS(0); allocateArrays(); - while (1) { + while (true) { itemsize = _fileHandle->readUint32LE(); - if (_fileHandle->ioFailed()) + if (_fileHandle->eos() || _fileHandle->err()) break; blocktype = _fileHandle->readUint16LE(); diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index d474a43b05..aa4dce470e 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -86,6 +86,19 @@ bool ScummEngine::canLoadGameStateCurrently() { // FIXME: Actually, we might wish to support loading in more places. // As long as we are sure it won't cause any problems... Are we // aware of *any* spots where loading is not supported? + + // HE games are limited to original load and save interface only, + // due to numerous glitches (see bug #1726909) that can occur. + if (_game.heversion >= 60) + return false; + + // COMI always disables saving/loading (to tell the truth: + // the main menu) via its scripts, thus we need to make an + // exception here. This the same forced overwriting of the + // script decisions as in ScummEngine::processKeyboard. + if (_game.id == GID_CMI) + return true; + return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0); } @@ -99,7 +112,22 @@ bool ScummEngine::canSaveGameStateCurrently() { // TODO: Should we disallow saving in some more places, // e.g. when a SAN movie is playing? Not sure whether the // original EXE allowed this. - return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0); + + // HE games are limited to original load and save interface only, + // due to numerous glitches (see bug #1726909) that can occur. + if (_game.heversion >= 60) + return false; + + // COMI always disables saving/loading (to tell the truth: + // the main menu) via its scripts, thus we need to make an + // exception here. This the same forced overwriting of the + // script decisions as in ScummEngine::processKeyboard. + if (_game.id == GID_CMI) + return true; + + // SCUMM v4+ doesn't allow saving in room 0 or if + // VAR(VAR_MAINMENU_KEY) to set to zero. + return (VAR_MAINMENU_KEY == 0xFF || (VAR(VAR_MAINMENU_KEY) != 0 && _currentRoom != 0)); } @@ -1368,11 +1396,31 @@ void ScummEngine::saveOrLoad(Serializer *s) { } void ScummEngine_v0::saveOrLoad(Serializer *s) { + ScummEngine_v2::saveOrLoad(s); + + const SaveLoadEntry v0Entrys[] = { + MKLINE(ScummEngine_v0, _currentMode, sleByte, VER(78)), + MKLINE(ScummEngine_v0, _currentLights, sleByte, VER(78)), + MKEND() + }; + s->saveLoadEntries(this, v0Entrys); +} + + +void ScummEngine_v2::saveOrLoad(Serializer *s) { ScummEngine::saveOrLoad(s); - // TODO: Save additional variables - // _currentMode - // _currentLights + const SaveLoadEntry v2Entrys[] = { + MKLINE(ScummEngine_v2, _inventoryOffset, sleUint16, VER(79)), + MKEND() + }; + s->saveLoadEntries(this, v2Entrys); + + // In old saves we didn't store _inventoryOffset -> reset it to + // a sane default when loading one of those. + if (s->getVersion() < 79 && s->isLoading()) { + _inventoryOffset = 0; + } } void ScummEngine_v5::saveOrLoad(Serializer *s) { diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 29184ad023..4f6adc5570 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 77 +#define CURRENT_VER 79 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index 4d9447bee5..2c3fe09db2 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -23,10 +23,9 @@ * */ - - #include "common/config-manager.h" #include "common/util.h" +#include "common/system.h" #include "scumm/actor.h" #include "scumm/object.h" @@ -133,6 +132,8 @@ void ScummEngine::runObjectScript(int object, int entry, bool freezeResistant, b initializeLocals(slot, vars); + // V0 Ensure we don't try and access objects via index inside the script + _v0ObjectIndex = false; runScriptNested(slot); } @@ -786,92 +787,65 @@ void ScummEngine::runInventoryScript(int i) { } void ScummEngine::inventoryScriptIndy3Mac() { - VerbSlot *vs; - int args[24]; - int j, slot; + int slot; - memset(args, 0, sizeof(args)); + // VAR(67) controls the scroll offset of the inventory in Indy3 for Macintosh. + // The inventory consists of two columns with three items visible in each, + // so a maximum of six items are visible at once. - if (VAR(67) < 0) { - VAR(67) = 0; - } - args[5] = getInventoryCount(VAR(VAR_EGO)); - if (args[5] <= 6) { + // The scroll offset must be non-negative and if there are six or less items + // in the inventory, the inventory is fixed in the top position. + const int invCount = getInventoryCount(VAR(VAR_EGO)); + if (VAR(67) < 0 || invCount <= 6) { VAR(67) = 0; } - if (args[5] >= 6) { - args[5] -= 6; - } - args[6] = 0; - if (VAR(67) >= args[5]) { - VAR(67) = args[5]; - args[4] = args[5]; - args[5] /= 2; - args[5] *= 2; - args[4] -= args[5]; - if (args[4]) { + + // If there are more than six items in the inventory, clamp the scroll position + // to be at most invCount-6, rounded up to the next even integer. + bool scrolledToBottom = false; + if (invCount > 6 && VAR(67) >= invCount - 6) { + VAR(67) = invCount - 6; + // Odd number of inventory items? -> increment VAR(67) to make it even + if (invCount & 1) { VAR(67)++; } - args[6]++; - } - args[2] = 1; - for (j = 1; j < 7; j++) { - args[1] = (VAR(67) + args[2]); - args[3] = findInventory(VAR(VAR_EGO),args[1]); - VAR(82 + args[2]) = args[3]; - args[2]++; + scrolledToBottom = true; } - byte tmp[6]; - - tmp[0] = 0xFF; - tmp[1] = 0x06; - tmp[3] = 0x00; - tmp[4] = 0x00; - - for (j = 0; j < 6; j++) { - tmp[2] = 0x53 + j; - - slot = getVerbSlot(101 + j, 0); - vs = &_verbs[slot]; + // Now update var 83 till 89 to contain the inventory IDs of the + // corresponding inventory slots. + // Also setup fake verbs for the inventory + byte tmp[6] = { 0xFF, 0x06, 0x52, 0x00, 0x00, 0x00 }; + for (int j = 1; j < 7; j++) { + int tmpA = (VAR(67) + j); + int tmpB = findInventory(VAR(VAR_EGO), tmpA); + VAR(82 + j) = tmpB; + + // Setup fake verb + tmp[2] = 0x52 + j; + slot = getVerbSlot(100 + j, 0); loadPtrToResource(rtVerb, slot, tmp); + + VerbSlot *vs = &_verbs[slot]; vs->type = kTextVerbType; vs->imgindex = 0; vs->curmode = 1; drawVerb(slot, 0); } - args[5] = getInventoryCount(VAR(VAR_EGO)); - if (args[5] > 6) { - slot = getVerbSlot(107, 0); - if (VAR(67)) { - vs = &_verbs[slot]; - vs->curmode = 1; - } else { - vs = &_verbs[slot]; - vs->curmode = 0; - } - drawVerb(slot, 0); - slot = getVerbSlot(108, 0); - if (!args[6]) { - vs = &_verbs[slot]; - vs->curmode = 1; - } else { - vs = &_verbs[slot]; - vs->curmode = 0; - } - drawVerb(slot, 0); - } else { - slot = getVerbSlot(107, 0); - vs = &_verbs[slot]; - vs->curmode = 0; - drawVerb(slot, 0); - slot = getVerbSlot(108, 0); - vs = &_verbs[slot]; - vs->curmode = 0; - drawVerb(slot, 0); - } + // Enable up arrow if there are more than six items and we are not already + // scrolled all the way up. + slot = getVerbSlot(107, 0); + _verbs[slot].curmode = (invCount > 6 && VAR(67)) ? 1 : 0; + drawVerb(slot, 0); + + // Enable down arrow if there are more than six items and we are not already + // scrolled all the way down. + slot = getVerbSlot(108, 0); + _verbs[slot].curmode = (invCount > 6 && !scrolledToBottom) ? 1 : 0; + drawVerb(slot, 0); + // Redraw! verbMouseOver(0); } @@ -1204,7 +1178,7 @@ void ScummEngine::runInputScript(int clickArea, int val, int mode) { args[4] = VAR(VAR_VIRT_MOUSE_Y); } - // Macintosh verison of indy3ega used different interface, so adjust values. + // Macintosh version of indy3ega used different interface, so adjust values. if (_game.id == GID_INDY3 && _game.platform == Common::kPlatformMacintosh) { if (clickArea == kVerbClickArea && (val >= 101 && val <= 108)) { if (val == 107) { @@ -1216,10 +1190,16 @@ void ScummEngine::runInputScript(int clickArea, int val, int mode) { inventoryScriptIndy3Mac(); return; } else { - args[0] = 3; - args[1] = VAR(83 + (val - 101)); + args[0] = kInventoryClickArea; + args[1] = VAR(82 + (val - 100)); } } + + // Clicks are handled differently in Indy3 mac: param 2 of the + // input script is set to 0 for normal clicks, and to 1 for double clicks. + uint32 time = _system->getMillis(); + args[2] = (time < _lastInputScriptTime + 500); // 500 ms double click delay + _lastInputScriptTime = time; } if (verbScript) diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp index 1b8368d636..873f2fa281 100644 --- a/engines/scumm/script_v0.cpp +++ b/engines/scumm/script_v0.cpp @@ -410,41 +410,43 @@ void ScummEngine_v0::decodeParseString() { actorTalk(buffer); } -void ScummEngine_v0::drawSentence() { - Common::Rect sentenceline; +void ScummEngine_v0::drawSentenceWord(int object, bool usePrep, bool objInInventory) { const byte *temp; int sentencePrep = 0; + + // If object not in inventory, we except an index + if (!objInInventory) + _v0ObjectIndex = true; + else + _v0ObjectInInventory = true; - if (!(_userState & 32)) - return; + temp = getObjOrActorName(object); - if (getResourceAddress(rtVerb, _activeVerb)) { - strcpy(_sentenceBuf, (char*)getResourceAddress(rtVerb, _activeVerb)); - } else { - return; + _v0ObjectInInventory = false; + _v0ObjectIndex = false; + + // Append the 'object-name' + if (temp) { + strcat(_sentenceBuf, " "); + strcat(_sentenceBuf, (const char*)temp); } - if (_activeObject > 0) { - temp = getObjOrActorName(_activeObject); - if (temp) { - strcat(_sentenceBuf, " "); - strcat(_sentenceBuf, (const char*)temp); - } + // Append the modifier? (With / On / To / In) + if (!usePrep) + return; - if (_verbs[_activeVerb].prep == 0xFF) { - byte *ptr = getOBCDFromObject(_activeObject); - assert(ptr); - sentencePrep = (*(ptr + 11) >> 5); - } else { - sentencePrep = _verbs[_activeVerb].prep; - } + if (_verbs[_activeVerb].prep == 0xFF) { + _v0ObjectInInventory = objInInventory; + sentencePrep = verbPrep(object); + } else { + sentencePrep = _verbs[_activeVerb].prep; } if (sentencePrep > 0 && sentencePrep <= 4) { // The prepositions, like the fonts, were hard code in the engine. Thus // we have to do that, too, and provde localized versions for all the // languages MM/Zak are available in. - const char *prepositions[][5] = { + static const char *prepositions[][5] = { { " ", " in", " with", " on", " to" }, // English { " ", " mit", " mit", " mit", " zu" }, // German { " ", " dans", " avec", " sur", " <" }, // French @@ -471,13 +473,65 @@ void ScummEngine_v0::drawSentence() { strcat(_sentenceBuf, prepositions[lang][sentencePrep]); } +} + +void ScummEngine_v0::drawSentence() { + Common::Rect sentenceline; + bool inventoryFirst = false; + + if (!(_userState & 32)) + return; + + // Current Verb, Walk/Use + if (getResourceAddress(rtVerb, _activeVerb)) { + strcpy(_sentenceBuf, (char*)getResourceAddress(rtVerb, _activeVerb)); + } else { + return; + } - if (_activeInventory > 0) { - temp = getObjOrActorName(_activeInventory); - if (temp) { - strcat(_sentenceBuf, " "); - strcat(_sentenceBuf, (const char*)temp); + // If using inventory first, draw it first + if (_activeInvExecute && _activeInventory) { + drawSentenceWord(_activeInventory, true, true); + } else { + // Not using inventory, use selected object + if (_activeObject) + drawSentenceWord(_activeObjectIndex, true, false); + else + inventoryFirst = true; + } + + + // Draw the inventory? + if (_activeInventory > 0 && _activeObject2 == 0) { + // Only if inventory isnt first (it will already be drawn by now) + if (!_activeInvExecute) { + drawSentenceWord(_activeInventory, inventoryFirst, true); + } else { + // Draw the active object, which could be inventory based, or room based + if (_activeObject && !_activeObjectIndex) { + drawSentenceWord(_activeObject, inventoryFirst, true); + } else // Room based + drawSentenceWord(_activeObjectIndex, inventoryFirst, false); } + + // Draw the 2nd active object + } else if (_activeObject2) { + + // 2nd Object is in inventory + if (_activeObject2Inv) { + _v0ObjectInInventory = true; + drawSentenceWord(_activeObject2, inventoryFirst, true); + } else { + drawSentenceWord(_activeObject2Index, inventoryFirst, false); + } + } + + // Draw the active actor + if (_activeActor) { + Actor *a = derefActor(_activeActor, ""); + + strcat(_sentenceBuf, " "); + strcat(_sentenceBuf, (const char*)a->getActorName()); } _string[2].charset = 1; @@ -664,9 +718,22 @@ void ScummEngine_v0::o_animateActor() { int act = getVarOrDirectByte(PARAM_1); int anim = getVarOrDirectByte(PARAM_2); int unk = fetchScriptByte(); + debug(0,"o_animateActor: unk %d", unk); - Actor *a = derefActor(act, "o_animateActor"); + ActorC64 *a = (ActorC64*) derefActor(act, "o_animateActor"); + + // 0x6993 + if (anim == 0xFE) { + a->_speaking = 0x80; // Enabled, but not switching + return; + } + // 0x69A3 + if (anim == 0xFD) { + a->_speaking = 0x00; + return; + } + a->animateActor(anim); } @@ -713,9 +780,9 @@ void ScummEngine_v0::o_pickupObject() { if (getObjectIndex(obj) == -1) return; - if (whereIsObject(obj) == WIO_INVENTORY) /* Don't take an */ + if (whereIsObjectInventory(_activeObject2) == WIO_INVENTORY) /* Don't take an */ return; /* object twice */ - + addObjectToInventory(obj, _roomResource); markObjectRectAsDirty(obj); putOwner(obj, VAR(VAR_EGO)); @@ -738,8 +805,13 @@ void ScummEngine_v0::o_setActorBitVar() { byte act = getVarOrDirectByte(PARAM_1); byte mask = getVarOrDirectByte(PARAM_2); byte mod = getVarOrDirectByte(PARAM_3); + + // 0x63ED + if (act >= _numActors) + return; ActorC64 *a = (ActorC64 *)derefActor(act, "o_setActorBitVar"); + if (mod) a->_miscflags |= mask; else @@ -900,10 +972,25 @@ void ScummEngine_v0::o_setOwnerOf() { setOwnerOf(obj, owner); } -void ScummEngine_v0::resetSentence() { - _activeInventory = 0; - _activeObject = 0; +void ScummEngine_v0::resetSentence(bool walking) { _activeVerb = 13; + + if (!walking) { + _activeInventory = 0; + _activeObject = 0; + _activeObject2 = 0; + _activeObjectIndex = 0; + _activeObject2Index = 0; + } + + _verbExecuting = false; + _verbPickup = false; + + _activeActor = 0; + _activeInvExecute = false; + _activeObject2Inv = false; + _activeObjectObtained = false; + _activeObject2Obtained = false; } } // End of namespace Scumm diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index 1ce38fd800..f83e7f2879 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -1138,9 +1138,19 @@ void ScummEngine_v5::o5_ifClassOfIs() { while ((_opcode = fetchScriptByte()) != 0xFF) { cls = getVarOrDirectWord(PARAM_1); - b = getClass(obj, cls); - if (((cls & 0x80) && !b) || (!(cls & 0x80) && b)) - cond = false; + + // WORKAROUND bug #1668393: Due to a script bug, the wrong opcode is used + // to check the state of the inside door (object 465) of the Hostel on Mars, + // when opening the Hostel door from the outside. + if (_game.id == GID_ZAK && _game.platform == Common::kPlatformFMTowns && + vm.slot[_currentScript].number == 205 && _currentRoom == 185 && + obj == 465 && cls == 0) { + cond = (getState(obj) == 0); + } else { + b = getClass(obj, cls); + if (((cls & 0x80) && !b) || (!(cls & 0x80) && b)) + cond = false; + } } jumpRelative(cond); } @@ -1775,7 +1785,7 @@ void ScummEngine_v5::o5_roomOps() { while ((chr = fetchScriptByte())) filename += chr; - if (filename.hasPrefix("iq-") || filename.hasPrefix("IQ-") || filename.hasSuffix("-iq")) { + if (filename.hasPrefix("iq-") || filename.hasPrefix("IQ-") || filename.hasSuffix("-iq") || filename.hasSuffix("-IQ")) { filename = _targetName + ".iq"; } else { error("SO_LOAD_STRING: Unsupported filename %s", filename.c_str()); diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index dcd60352c7..6df3c0c494 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -701,6 +701,14 @@ void ScummEngine_v6::o6_ifNot() { void ScummEngine_v6::o6_jump() { int offset = fetchScriptWordSigned(); + + // WORKAROUND bug #2826144: Talking to the guard at the bigfoot party, after + // he's let you inside, will cause the game to hang, if you end the conversation. + // This is a script bug, due to a missing jump in one segment of the script. + if (_game.id == GID_SAMNMAX && vm.slot[_currentScript].number == 101 && readVar(0x8000 + 97) == 1 && offset == 1) { + offset = -18; + } + _scriptPointer += offset; } diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 5bb0e097dc..cb7f906f13 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Sat Jul 11 01:37:44 2009 + This file was generated by the md5table tool on Thu Jul 30 10:23:41 2009 DO NOT EDIT MANUALLY! */ @@ -17,20 +17,20 @@ static const MD5Table md5table[] = { { "008e76ec3ae58d0add637ea7aa299a2c", "freddi3", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "02cae0e7ff8504f73618391873d5781a", "freddi3", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "0305e850382b812fec6e5998ef88a966", "pajama", "", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "037385a953789190298494d92b89b3d0", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows }, - { "0425954a9db5c340861672892c3e678d", "samnmax", "CD", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, + { "0425954a9db5c340861672892c3e678d", "samnmax", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "04401d747f1a2c1c4b388daff71ed378", "ft", "", "", 535405461, Common::DE_DEU, Common::kPlatformMacintosh }, { "04687cdf7f975a89d2474929f7b80946", "indy3", "FM-TOWNS", "", 7552, Common::EN_ANY, Common::kPlatformFMTowns }, { "0557df19f046a84c2fdc63507c6616cb", "farm", "HE 72", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "055ffe4f47753e47594ac67823220c54", "puttrace", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "057c9b456dedcc4d71b991a3072a20b3", "monkey", "SEGA", "", 9465, Common::JA_JPN, Common::kPlatformSegaCD }, { "0650e8ab1432564607cd651c0fa3f344", "loom", "PC-Engine", "", -1, Common::EN_ANY, Common::kPlatformPCEngine }, - { "06b187468113f9ae5a400b148a847fac", "atlantis", "", "Floppy", 12075, Common::EN_ANY, Common::kPlatformMacintosh }, + { "06b187468113f9ae5a400b148a847fac", "atlantis", "Floppy", "Floppy", 12075, Common::EN_ANY, Common::kPlatformMacintosh }, { "06c3cf4f31daad8b1cd93153491db9e6", "pajama3", "", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, { "07433205acdca3bc553d0e731588b35f", "airport", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "07a1eefd8ca95d77310311446c0f53d0", "brstorm", "", "Demo", 5433, Common::EN_ANY, Common::kPlatformUnknown }, + { "07a1eefd8ca95d77310311446c0f53d0", "brstorm", "", "", 5433, Common::EN_ANY, Common::kPlatformUnknown }, { "07b810e37be7489263f7bc7627d4765d", "freddi4", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows }, { "084ed0fa98a6d1e9368d67fe9cfbd417", "freddi", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "0855496dde35356b1a9691e22ba84cdc", "freddi", "HE 73", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -49,14 +49,14 @@ static const MD5Table md5table[] = { { "0c45eb4baff0c12c3d9dfa889c8070ab", "pajama3", "", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "0cccfa5223099a60e76cfcca57a1a141", "freddi3", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "0d1b69471605201ef2fa9cec1f5f02d2", "maniac", "V2", "V2", -1, Common::ES_ESP, Common::kPlatformPC }, - { "0e4c5d54a0ad4b26132e78b5ea76642a", "samnmax", "", "Demo", 6485, Common::EN_ANY, Common::kPlatformPC }, + { "0e4c5d54a0ad4b26132e78b5ea76642a", "samnmax", "Floppy", "Demo", 6485, Common::EN_ANY, Common::kPlatformPC }, { "0e96ab45a4eb72acc1b46813976589fd", "activity", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "0e9b01430e31d9fcd94071d433bbc6bf", "loom", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST }, { "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", 30919, Common::EN_USA, Common::kPlatformWindows }, - { "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "CD", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, + { "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, { "0f9c7a76657f0840b8f7ccb5bffeb9f4", "indy3", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST }, { "0f9d3317910ac7a9f449243118884ada", "puttzoo", "", "", 42070, Common::DE_DEU, Common::kPlatformWindows }, - { "0fb73eddfcf584c02ba097984df131ba", "samnmax", "CD", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown }, + { "0fb73eddfcf584c02ba097984df131ba", "samnmax", "", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown }, { "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "100b4c8403ad6a83d4bf7dbf83e44dc4", "spyfox", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "10d8e66cd11049ce64815ebb9fd76eb3", "spyozon", "", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, @@ -72,22 +72,22 @@ static const MD5Table md5table[] = { { "15240c59d3681ed53f714f8d925cb2d6", "maniac", "V2", "V2", -1, Common::ES_ESP, Common::kPlatformAtariST }, { "157367c3c21e0d03a0cba44361b4cf65", "indy3", "No Adlib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, { "15e03ffbfeddb9c2aebc13dcb2a4a8f4", "monkey", "VGA", "VGA", 8357, Common::EN_ANY, Common::kPlatformPC }, - { "15f588e887e857e8c56fe6ade4956168", "atlantis", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformAmiga }, + { "15f588e887e857e8c56fe6ade4956168", "atlantis", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformAmiga }, { "16542a7342a918bfe4ba512007d36c47", "FreddisFunShop", "HE 99L", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "166553538ff320c69edafeee29525419", "samnmax", "CD", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "166553538ff320c69edafeee29525419", "samnmax", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "16effd200aa6b8abe9c569c3e578814d", "freddi4", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "179879b6e35c1ead0d93aab26db0951b", "fbear", "HE 70", "", 13381, Common::EN_ANY, Common::kPlatformWindows }, { "17b5d5e6af4ae89d62631641d66d5a05", "indy3", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformPC }, { "17f7296f63c78642724f057fd8e736a7", "maniac", "NES", "extracted", -1, Common::EN_GRB, Common::kPlatformNES }, - { "17fa250eb72dae2dad511ba79c0b6b0a", "tentacle", "CD", "Demo", -1, Common::FR_FRA, Common::kPlatformPC }, - { "182344899c2e2998fca0bebcd82aa81a", "atlantis", "CD", "CD", 12035, Common::EN_ANY, Common::kPlatformPC }, + { "17fa250eb72dae2dad511ba79c0b6b0a", "tentacle", "", "Demo", -1, Common::FR_FRA, Common::kPlatformPC }, + { "182344899c2e2998fca0bebcd82aa81a", "atlantis", "", "CD", 12035, Common::EN_ANY, Common::kPlatformPC }, { "183d7464902d40d00800e8ee1f04117c", "maniac", "V2", "V2", 1988, Common::DE_DEU, Common::kPlatformPC }, { "1875b90fade138c9253a8e967007031a", "indy3", "VGA", "VGA", 6295, Common::EN_ANY, Common::kPlatformPC }, { "187d315f6b5168f68680dfe8c3d76a3e", "loom", "EGA", "EGA", -1, Common::HB_ISR, Common::kPlatformPC }, { "1900e501a52fbf55bde6e4196f6d2aa6", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "19263586f749a560c1adf8b3393a9593", "socks", "HE 85", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "19bf6938a94698296bcb0c99c31c91a7", "spyfox2", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows }, - { "1a6e5ae2777a6a33f06ffc0226210934", "atlantis", "CD", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "1a6e5ae2777a6a33f06ffc0226210934", "atlantis", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "1c792d28376d45e145cb916bca0400a2", "spyfox2", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "1c7e7db2cfab1ad62746ab680a634204", "maniac", "NES", "extracted", -1, Common::FR_FRA, Common::kPlatformNES }, { "1ca86e2cf9aaa2068738a1e5ba477e60", "zak", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, @@ -97,12 +97,12 @@ static const MD5Table md5table[] = { { "1dd7aa088e09f96d06818aa9a9deabe0", "indy3", "No Adlib", "EGA", 5361, Common::EN_ANY, Common::kPlatformMacintosh }, { "1ed22f601f8b3695804a6583cc3083f1", "puttrace", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "1f2e62b5a9c50589fc342285a6bb3a27", "freddi", "HE 73", "", -1, Common::HB_ISR, Common::kPlatformWindows }, - { "1fbebd7b2b692df5297870447a80cfed", "atlantis", "", "Floppy", 12030, Common::DE_DEU, Common::kPlatformPC }, + { "1fbebd7b2b692df5297870447a80cfed", "atlantis", "Floppy", "Floppy", 12030, Common::DE_DEU, Common::kPlatformPC }, { "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "Red", -1, Common::EN_ANY, Common::kPlatformWindows }, { "2012f854d83d9cc6f73b2b544cd8bbf8", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "20176076d708bf14407bcc9bdcd7a418", "pajama3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "204453e33456c4faa26e276229fe5b76", "spyfox2", "", "Demo", 14689, Common::DE_DEU, Common::kPlatformWindows }, - { "20da6fce37805423966aaa8f3c2426aa", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga }, + { "20da6fce37805423966aaa8f3c2426aa", "atlantis", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "21abe302e1b1e2b66d6f5c12e241ebfd", "freddicove", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows }, @@ -114,14 +114,14 @@ static const MD5Table md5table[] = { { "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "23394c8d29cc63c61313959431a12476", "spyfox", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", 262144, Common::DE_DEU, Common::kPlatformNES }, - { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "", "Floppy", 7932, Common::EN_ANY, Common::kPlatformPC }, + { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "Floppy", "Floppy", 7932, Common::EN_ANY, Common::kPlatformPC }, { "27b2ef1653089fe5b897d9cc89ce784f", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "27b3a4224ad63d5b04627595c1c1a025", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformAmiga }, - { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "CD", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, + { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, { "28ef68ee3ed76d7e2ee8ee13c15fbd5b", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformPC }, { "28f07458f1b6c24e118a1ea056827701", "lost", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "2a208ffbcd0e83e86f4356e6f64aa6e1", "loom", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformPC }, - { "2a41b53cf1a90b6e6f26c10cc6041084", "tentacle", "CD", "Demo", 2439158, Common::EN_ANY, Common::kPlatformMacintosh }, + { "2a41b53cf1a90b6e6f26c10cc6041084", "tentacle", "", "Demo", 2439158, Common::EN_ANY, Common::kPlatformMacintosh }, { "2a446817ffcabfef8716e0c456ecaf81", "puttzoo", "", "Demo", -1, Common::DE_DEU, Common::kPlatformWindows }, { "2a8658dbd13d84d1bce64a71a35995eb", "pajama2", "HE 99", "Demo", -1, Common::HB_ISR, Common::kPlatformWindows }, { "2c04aacffb8428f30ccf4f734fbe3adc", "activity", "", "", -1, Common::EN_ANY, Common::kPlatformPC }, @@ -130,7 +130,7 @@ static const MD5Table md5table[] = { { "2d388339d6050d8ccaa757b64633954e", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "2d4536a56e01da4b02eb021e7770afa2", "zak", "FM-TOWNS", "", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "2d4acbdcfd8e374c9da8c2e7303a5cd0", "BluesBirthday", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "2d9d46f23cb07bbc90b8ad464d3e4ff8", "atlantis", "CD", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "2d9d46f23cb07bbc90b8ad464d3e4ff8", "atlantis", "", "CD", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "2e85f7aa054930c692a5b1bed1dfc295", "football2002", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "2e8a1f76ea33bc5e04347646feee173d", "pajama3", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "2fe369ad70f52a8cf7ad6077ee64f81a", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformAmiga }, @@ -157,18 +157,18 @@ static const MD5Table md5table[] = { { "3824e60cdf639d22f6df92a03dc4b131", "fbear", "HE 61", "", 7732, Common::EN_ANY, Common::kPlatformPC }, { "387a544b8b10b26912d8413bab63a853", "monkey2", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "3905799e081b80a61d4460b7b733c206", "maniac", "NES", "", 262144, Common::EN_USA, Common::kPlatformNES }, - { "3938ee1aa4433fca9d9308c9891172b1", "zak", "FM-TOWNS", "Demo", -1, Common::EN_ANY, Common::kPlatformFMTowns }, + { "3938ee1aa4433fca9d9308c9891172b1", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "399b217b0c8d65d0398076da486363a9", "indy3", "VGA", "VGA", 6295, Common::DE_DEU, Common::kPlatformPC }, { "39cb9dec16fa16f38d79acd80effb059", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "39cb9dec16fa16f38d79acd80effb059", "loom", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "39fd6db10d0222d817025c4d3346e3b4", "farm", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "3a03dab514e4038df192d8a8de469788", "atlantis", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformAmiga }, + { "3a03dab514e4038df192d8a8de469788", "atlantis", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "3a0c35f3c147b98a2bdf8d400cfc4ab5", "indy3", "FM-TOWNS", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, { "3a3e592b074f595489f7f11e150c398d", "puttzoo", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformWindows }, - { "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "CD", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "3a5ec90d556d4920976c5578bfbfaf79", "maniac", "NES", "extracted", -1, Common::DE_DEU, Common::kPlatformNES }, { "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HB_ISR, Common::kPlatformWindows }, - { "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, + { "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, { "3cce1913a3bc586b51a75c3892ff18dd", "indy3", "VGA", "VGA", -1, Common::RU_RUS, Common::kPlatformPC }, { "3d219e7546039543307b55a91282bf18", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC }, @@ -176,7 +176,7 @@ static const MD5Table md5table[] = { { "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 61", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "3e48298920fab9b7aec5a971e1bd1fab", "pajama3", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows }, { "40564ec47da48a67787d1f9bd043902a", "maniac", "V2 Demo", "V2 Demo", 1988, Common::EN_ANY, Common::kPlatformPC }, - { "4167a92a1d46baa4f4127d918d561f88", "tentacle", "CD", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown }, + { "4167a92a1d46baa4f4127d918d561f88", "tentacle", "", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown }, { "41958e24d03181ff9a381a66d048a581", "ft", "", "", -1, Common::PT_BRA, Common::kPlatformUnknown }, { "425205754fa749f4f0b0dd9d09fa45fd", "football", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "430bc518017b6fac046f58bab6baad5d", "monkey2", "", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, @@ -195,13 +195,13 @@ static const MD5Table md5table[] = { { "4aa93cb30e485b728504ba3a693f12bf", "pajama", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "4af4a6b248103c1fe9edef619677f540", "puttmoon", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "4ba37f835be11a59d969f90f272f575b", "water", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "4ba7fb331296c283e73d8f5b2096e551", "samnmax", "CD", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, + { "4ba7fb331296c283e73d8f5b2096e551", "samnmax", "", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, { "4bedb49943df95a9c900a5a82ccbe9de", "ft", "", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "4bfa4a43684bcb437f7fb47f457a0aa5", "socks", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "4c4820518e16e1a0e3616a3b021a04f3", "catalog", "HE CUP", "Preview", 10927456, Common::DE_DEU, Common::kPlatformUnknown }, { "4cb9c3618f71668f8e4346c8f323fa82", "monkey2", "", "", 10700, Common::EN_ANY, Common::kPlatformMacintosh }, { "4ce2d5b355964bbcb5e5ce73236ef868", "freddicove", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, - { "4d34042713958b971cb139fba4658586", "atlantis", "CD", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, + { "4d34042713958b971cb139fba4658586", "atlantis", "", "", -1, Common::JA_JPN, Common::kPlatformFMTowns }, { "4dbff3787aedcd96b0b325f2d92d7ad9", "maze", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "4dc780f1bc587a193ce8a97652791438", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "4e5867848ee61bc30d157e2c94eee9b4", "PuttTime", "HE 90", "Demo", 18394, Common::EN_USA, Common::kPlatformUnknown }, @@ -209,15 +209,15 @@ static const MD5Table md5table[] = { { "4f04b321a95d4315ce6d65f8e1dd0368", "maze", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "4f1d6f8b38343dba405472538b5037ed", "fbear", "HE 61", "", 7717, Common::EN_ANY, Common::kPlatformPC }, - { "4f267a901719623de7dde83e47d5b474", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, + { "4f267a901719623de7dde83e47d5b474", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, { "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "4fbbe9f64b8bc547503a379a301183ce", "tentacle", "CD", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, + { "4fbbe9f64b8bc547503a379a301183ce", "tentacle", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, { "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, { "5057fb0e99e5aa29df1836329232f101", "freddi2", "HE 80", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "507bb360688dc4180fdf0d7597352a69", "freddi", "HE 73", "", 26402, Common::SE_SWE, Common::kPlatformWindows }, { "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, - { "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, + { "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "513f91a9dbe8d5490b39e56a3ac5bbdf", "pajama2", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, { "5262a27afcaee04e5c4900220bd463e7", "PuttsFunShop", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -229,10 +229,10 @@ static const MD5Table md5table[] = { { "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "566165a7338fa11029e7c14d94fa70d0", "freddi", "HE 73", "Demo", 9800, Common::EN_ANY, Common::kPlatformWindows }, { "5719fc8a13b4638b78d9d8d12f091f94", "puttrace", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, - { "5798972220cd458be2626d54c80f71d7", "atlantis", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformAmiga }, + { "5798972220cd458be2626d54c80f71d7", "atlantis", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "57a17febe2183f521250e55d55b83e60", "PuttTime", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "57a5cfec9ef231a007043cc1917e8988", "freddi", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, - { "57b0d89af79befe1cabce3bece869e7f", "tentacle", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, + { "57b0d89af79befe1cabce3bece869e7f", "tentacle", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, { "58436e634f4fae1d9973591c2ffa1fcb", "spyfox", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "589601b676c98b1c0c987bc031ab68b3", "chase", "HE 95", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "58fdf4c7ad13540a734e18f8584cad89", "puttzoo", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, @@ -289,9 +289,9 @@ static const MD5Table md5table[] = { { "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows }, { "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, - { "6dead580b0ff14d5f7b33b4219f04159", "samnmax", "CD", "Demo", 16556335, Common::EN_ANY, Common::kPlatformMacintosh }, + { "6dead580b0ff14d5f7b33b4219f04159", "samnmax", "", "Demo", 16556335, Common::EN_ANY, Common::kPlatformMacintosh }, { "6df20c50c1ab19799de9be7ae7716881", "fbear", "HE 61", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "6e959d65358eedf9b68b81e304b97fa4", "tentacle", "CD", "CD", 7932, Common::DE_DEU, Common::kPlatformUnknown }, + { "6e959d65358eedf9b68b81e304b97fa4", "tentacle", "", "CD", 7932, Common::DE_DEU, Common::kPlatformUnknown }, { "6ea966b4d660c870b9ee790d1fbfc535", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformAmiga }, { "6f0be328c64d689bb606d22a389e1b0f", "loom", "No Adlib", "EGA", 5748, Common::EN_ANY, Common::kPlatformMacintosh }, { "6f6ef668c608c7f534fea6e6d3878dde", "indy3", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformPC }, @@ -332,7 +332,7 @@ static const MD5Table md5table[] = { { "7ddeaf52c8b9a50551ce0aa2ac811d07", "BluesABCTime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "7e151c17adf624f1966c8fc5827c95e9", "puttputt", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "7ea2da67ebabea4ac20cee9f4f9d2934", "airport", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "CD", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7f45ddd6dbfbf8f80c0c0efea4c295bc", "maniac", "V1", "V1", 1972, Common::EN_ANY, Common::kPlatformPC }, { "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -354,12 +354,12 @@ static const MD5Table md5table[] = { { "87df3e0074624040407764b7c5e710b9", "pajama", "", "Demo", 18354, Common::NL_NLD, Common::kPlatformWindows }, { "87f6e8037b7cc996e13474b491a7a98e", "maniac", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "8801fb4a1200b347f7a38523339526dd", "jungle", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "CD", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, + { "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, { "898ce8eb1234a955ef75e87141902bb3", "freddi3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "898eaa21f79cf8d4f08db856244689ff", "pajama", "HE 99", "Updated", 66505, Common::EN_ANY, Common::kPlatformWindows }, { "89cfc425566003ff74b7dc7b3e6fd469", "indy3", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformPC }, { "8a484262363a8e18be87112454f1456b", "pjgames", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "8aa05d3cdb0e795436043f0546af2da2", "tentacle", "CD", "CD?", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "8aa05d3cdb0e795436043f0546af2da2", "tentacle", "", "CD?", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "8aed489aba45d2b9fb8a04079c9c6e6a", "baseball", "HE CUP", "Preview", 12876596, Common::UNK_LANG, Common::kPlatformUnknown }, { "8afb3cf9f95abf208358e984f0c9e738", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "8bdb0bf87b5e303dd35693afb9351215", "ft", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, @@ -367,11 +367,11 @@ static const MD5Table md5table[] = { { "8de13897f0121c79d29a2377159f9ad0", "socks", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "8e3241ddd6c8dadf64305e8740d45e13", "balloon", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "8e4ee4db46954bfe2912e259a16fad82", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformPC }, - { "8e9417564f33790815445b2136efa667", "atlantis", "CD", "CD", 11915, Common::JA_JPN, Common::kPlatformMacintosh }, + { "8e9417564f33790815445b2136efa667", "atlantis", "", "CD", 11915, Common::JA_JPN, Common::kPlatformMacintosh }, { "8e9830a6f2702be5b22c8fa0a6aaf977", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, { "8eb84cee9b429314c7f0bdcf560723eb", "monkey", "FM-TOWNS", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, { "8ee63cafb1fe9d62aa0d5a23117e70e7", "freddi2", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, + { "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "8fec68383202d38c0d25e9e3b757c5df", "comi", "Demo", "Demo", 18041, Common::UNK_LANG, Common::kPlatformWindows }, { "8ffd618a776a4c0d8922bb28b09f8ce8", "airport", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "90a329d8ad5b7ce0690429e98cfbb32f", "funpack", "", "", -1, Common::HB_ISR, Common::kPlatformPC }, @@ -381,10 +381,10 @@ static const MD5Table md5table[] = { { "91469353f7be1b122fa88d23480a1320", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "91d5db93187fab54d823f73bd6441cb6", "maniac", "NES", "extracted", -1, Common::EN_USA, Common::kPlatformNES }, { "927a764615c7fcdd72f591355e089d8c", "monkey", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, - { "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "92e7727e67f5cd979d8a1070e4eb8cb3", "puttzoo", "HE 98.5", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "92fc0073a4cf259ff36070ecb8628ba8", "thinkerk", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "94aaedbb8f26d71ed3ad6dd34490e29e", "tentacle", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "94aaedbb8f26d71ed3ad6dd34490e29e", "tentacle", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "94db6519da85b8d08c976d8e9a858ea7", "baseball", "HE CUP", "Preview", 10044774, Common::UNK_LANG, Common::kPlatformUnknown }, { "95818b178d473c989ac753574e8892aa", "readtime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "95b3806e043be08668c54c3ffe98650f", "BluesABCTime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -392,13 +392,13 @@ static const MD5Table md5table[] = { { "9708cf716ed8bcc9ff3fcfc69413b746", "puttputt", "HE 61", "", -1, Common::EN_ANY, Common::kPlatformPC }, { "9781422e4288dbc090720e4563168ba7", "puttzoo", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "981e1e1891f2be7e25a01f50ae55a5af", "puttrace", "HE 98", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "98744fe66ff730e8c2b3b1f58803ab0b", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "98744fe66ff730e8c2b3b1f58803ab0b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "99128b6a5bdd9831d9682fb8b5cbf8d4", "BluesBirthday", "", "Yellow", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "99a3699f80b8f776efae592b44b9b991", "maniac", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformPC }, - { "99b6f822b0b2612415407865438697d6", "atlantis", "CD", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "99b6f822b0b2612415407865438697d6", "atlantis", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "9b7452b5cd6d3ffb2b2f5118010af84f", "ft", "Demo", "Demo", 116463537, Common::EN_ANY, Common::kPlatformMacintosh }, { "9bc548e179cdb0767009401c094d0895", "maniac", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformAmiga }, - { "9bd2a8f72613e715c199246dd511e10f", "atlantis", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, + { "9bd2a8f72613e715c199246dd511e10f", "atlantis", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, { "9bda5fee51d2fda5253d02c642016bf4", "spyfox", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "9c0ee9c252785e9fca0143e42ac4b256", "freddi2", "HE 99", "Updated", -1, Common::DE_DEU, Common::kPlatformWindows }, { "9c0fee288ad564a7d25ec3e841810d79", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, @@ -420,7 +420,7 @@ static const MD5Table md5table[] = { { "a2386da005672cbd5136f4f27a626c5f", "farm", "", "", 87061, Common::NL_NLD, Common::kPlatformWindows }, { "a28135a7ade38cc0208b04507c46efd1", "spyfox", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "a2bb6aa0537402c1b3c2ea899ccef64b", "lost", "HE 99", "Demo", 15540, Common::EN_ANY, Common::kPlatformWindows }, - { "a3036878840720fbefa41e6965fa4a0a", "samnmax", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, + { "a3036878840720fbefa41e6965fa4a0a", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "a336134914eaab4892d35625aa15ad1d", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "a525c1753c1db5011c00417da37887ef", "PuttTime", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "a561d2e2413cc1c71d5a1bf87bf493ea", "lost", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -441,16 +441,16 @@ static const MD5Table md5table[] = { { "aaa587701cde7e74692c68c1024b85eb", "puttrace", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "aaa7f36a253f277dd29dd1c051b0e4b9", "indy3", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "ac1642b6edfb8521ca03760126f1c250", "tentacle", "CD", "Demo", -1, Common::DE_DEU, Common::kPlatformPC }, + { "ac1642b6edfb8521ca03760126f1c250", "tentacle", "", "Demo", -1, Common::DE_DEU, Common::kPlatformPC }, { "ac62d50e39492ee3738b4e83a5ac780f", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "ae94f110a14ce71fc515d5b648827a8f", "tentacle", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, + { "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformUnknown }, + { "ae94f110a14ce71fc515d5b648827a8f", "tentacle", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, { "aefa244ea034b7cd2041f0a44be7d9ba", "pajama3", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "af2bd1a43b50b55915d87994e093203d", "freddi", "HE 99", "Updated", 34829, Common::DE_DEU, Common::kPlatformWindows }, { "b100abf7ff83146df50db78dbd5e9cfa", "freddicove", "HE 100", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "b23f7cd7c304d7dff08e92a96120d5b4", "zak", "V1", "V1", -1, Common::EN_ANY, Common::kPlatformPC }, { "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "V2", "V2", 1988, Common::EN_ANY, Common::kPlatformPC }, - { "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, + { "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "b47be81e39a9710f6f595f7b527b60f8", "puttrace", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, { "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", 5361, Common::EN_ANY, Common::kPlatformPC }, @@ -479,7 +479,7 @@ static const MD5Table md5table[] = { { "c24c490373aeb48fbd54caa8e7ae376d", "loom", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "c25755b08a8d0d47695e05f1e2111bfc", "freddi4", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, { "c30ef068add4277104243c31ce46c12b", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformAmiga }, - { "c3196c5349e53e387aaff1533d95e53a", "samnmax", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, + { "c3196c5349e53e387aaff1533d95e53a", "samnmax", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, { "c3b22fa4654bb580b20325ebf4174841", "puttzoo", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "c3df37df9d3b481b45f75283a9907c47", "loom", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformPC }, { "c4787c3e8b5e2dfda90850ee800af00f", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformPC }, @@ -487,22 +487,22 @@ static const MD5Table md5table[] = { { "c4ffae9fac495475d6bc3343ccc8faf9", "Soccer2004", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "c5cc7cba02a2fbd539c4439e775b0536", "puttzoo", "HE 99", "Updated", 43470, Common::DE_DEU, Common::kPlatformWindows }, { "c5d10e190d4b4d59114b824f2fdbd00e", "loom", "FM-TOWNS", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, - { "c63ee46143ba65f9ce14cf539ca51bd7", "atlantis", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, + { "c63ee46143ba65f9ce14cf539ca51bd7", "atlantis", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "c666a998af90d81db447eccba9f72c8d", "monkey", "No Adlib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, { "c6907d44f1166941d982864cd42cdc89", "pajama2", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "c782fbbe74a987c3df8ac73cd3e289ed", "freddi", "HE 73", "", -1, Common::SE_SWE, Common::kPlatformMacintosh }, { "c7890e038806df2bb5c0c8c6f1986ea2", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformPC }, - { "c7be10f775404fd9785a8b92a06d240c", "atlantis", "CD", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, + { "c7be10f775404fd9785a8b92a06d240c", "atlantis", "", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, { "c7c492a107ec520d7a7943037d0ca54a", "freddi", "HE 71", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, - { "c83079157ec765a28de445aec9768d60", "tentacle", "CD", "Demo", 7477, Common::EN_ANY, Common::kPlatformUnknown }, + { "c83079157ec765a28de445aec9768d60", "tentacle", "", "Demo", 7477, Common::EN_ANY, Common::kPlatformUnknown }, { "c8575e0b973ff1723aba6cd92c642db2", "puttrace", "HE 99", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, { "c8aac5e3e701874e2fa4117896f9e1b1", "freddi", "HE 73", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "c8c5baadcbfc8d0372ed4335abace8a7", "pajama3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, { "c9717ee6059f1e43b768b464493d2fba", "fbpack", "", "", -1, Common::JA_JPN, Common::kPlatform3DO }, { "cb1559e8405d17a5a278a6b5ad9338d1", "freddi3", "", "Demo", 22718, Common::EN_ANY, Common::kPlatformUnknown }, - { "cc04a076779379524ed4d9c5ee3c6fb1", "tentacle", "CD", "CD", 282467632, Common::EN_ANY, Common::kPlatformMacintosh }, + { "cc04a076779379524ed4d9c5ee3c6fb1", "tentacle", "", "CD", 282467632, Common::EN_ANY, Common::kPlatformMacintosh }, { "cc0c4111449054f1692bb3c0c5e04629", "BluesBirthday", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "cc8ba2b0df2f9c450bcf055fe2711979", "samnmax", "", "Demo", 7485, Common::DE_DEU, Common::kPlatformPC }, + { "cc8ba2b0df2f9c450bcf055fe2711979", "samnmax", "Floppy", "Demo", 7485, Common::DE_DEU, Common::kPlatformPC }, { "cd424f143a141bc59226ad83a6e40f51", "maze", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "cd46c9f122272d02bbf79332ff521898", "loom", "EGA", "EGA", 5748, Common::RU_RUS, Common::kPlatformPC }, { "cd9c05e755d7bf8e9b9590ad1ebe273e", "dig", "Demo", "Demo", 45156007, Common::EN_ANY, Common::kPlatformMacintosh }, @@ -525,7 +525,7 @@ static const MD5Table md5table[] = { { "d220d154aafbfa12bd6f3ab1b2dae420", "puttzoo", "", "Demo", -1, Common::DE_DEU, Common::kPlatformMacintosh }, { "d2cc8e31bce61e6cf2951249e10638fe", "basketball", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "d37c55388294b66e53e7ced3af88fa68", "freddi2", "HE 100", "Updated Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "d43352a805d78b5f4936c6d7779bf575", "samnmax", "CD", "CD", -1, Common::RU_RUS, Common::kPlatformPC }, + { "d43352a805d78b5f4936c6d7779bf575", "samnmax", "", "CD", -1, Common::RU_RUS, Common::kPlatformPC }, { "d4aac997e2f4e15341f0bfbf905419bd", "PuttTime", "HE 99", "", 62698, Common::EN_GRB, Common::kPlatformWindows }, { "d4b8ee426b1afd3e53bc0cf020418cf6", "dog", "HE 99", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "d4cccb5af88f3e77f370896e9ba8c5f9", "freddi", "HE 71", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, @@ -535,7 +535,7 @@ static const MD5Table md5table[] = { { "d62047a6729349ab36f7ee065bf26509", "dig", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "d62d248c3df6ec177405e2cb23d923b2", "indy3", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformPC }, { "d6334a5a9b61afe18c368540fdf522ca", "airport", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, - { "d6dd0646404768a63e963891a96daadd", "atlantis", "", "Floppy", 12035, Common::EN_ANY, Common::kPlatformMacintosh }, + { "d6dd0646404768a63e963891a96daadd", "atlantis", "Floppy", "Floppy", 12035, Common::EN_ANY, Common::kPlatformMacintosh }, { "d73c851b942af44deb9b6d5f416a0972", "freddi3", "HE 99", "Demo", -1, Common::HB_ISR, Common::kPlatformWindows }, { "d74122362a77ec24525fdd50297dfd82", "freddi4", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "d7ab7cd6105546016e6a0d46fb36b964", "pajama", "HE 100", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -543,8 +543,8 @@ static const MD5Table md5table[] = { { "d831f7c048574dd9d5d85db2a1468099", "maniac", "C64", "", -1, Common::EN_ANY, Common::kPlatformC64 }, { "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", 16304, Common::UNK_LANG, Common::kPlatformUnknown }, { "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", 262144, Common::EN_GRB, Common::kPlatformNES }, - { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "CD", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, - { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "CD", "Demo", 6478, Common::EN_ANY, Common::kPlatformPC }, + { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, + { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformPC }, { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns }, { "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", 8955, Common::IT_ITA, Common::kPlatformPC }, { "da669b20271b85182e9c17a2a37ea02e", "monkey2", "", "", -1, Common::DE_DEU, Common::kPlatformAmiga }, @@ -566,7 +566,7 @@ static const MD5Table md5table[] = { { "e361a7058ed8e8ebb462663c0a3ae8d6", "puttputt", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, { "e41de1c2a15abbcdbf9977e2d7e8a340", "freddi2", "HE 100", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, { "e44ea295a3f8fe4f41983080dab1e9ce", "freddi", "HE 90", "Updated", -1, Common::FR_FRA, Common::kPlatformMacintosh }, - { "e534d29afb3c6e0ee9dc3d53c5956714", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, + { "e534d29afb3c6e0ee9dc3d53c5956714", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "e5563c8358443c4352fcddf7402a5e0a", "pajama2", "HE 98.5", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "e5c112140ad6574997de033a8e2a2964", "readtime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "e62056ba675ad65d8854ab3c5ad4b3c0", "spyfox2", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -584,11 +584,11 @@ static const MD5Table md5table[] = { { "ecc4340c2b801f5af8da4e00c0e432d9", "puttcircus", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "ed2b074bc3166087a747acb2a3c6abb0", "freddi3", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, - { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "CD", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, - { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO }, { "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, - { "ef347474f3c7be3b29584eaa133cca05", "samnmax", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "ef347474f3c7be3b29584eaa133cca05", "samnmax", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "ef71a322b6530ac45b1a070f7c0795f7", "moonbase", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, { "efe0a04a703e765ebebe92b6c8aa6b86", "baseball2003", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -598,11 +598,11 @@ static const MD5Table md5table[] = { { "f163cf53f7850e43fb482471e5c52e1a", "maniac", "NES", "", 262144, Common::ES_ESP, Common::kPlatformNES }, { "f1b0e0d587b85052de5534a3847e68fe", "water", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown }, - { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, + { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, { "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows }, { "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, - { "f73883f13b5a302749a5bad31d909780", "tentacle", "CD", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh }, + { "f73883f13b5a302749a5bad31d909780", "tentacle", "", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh }, { "f7711f9264d4d43c2a1518ec7c10a607", "pajama3", "", "", 79382, Common::EN_USA, Common::kPlatformUnknown }, { "f79e60c17cca601e411f1f75e8ee9b5a", "spyfox2", "", "", 51286, Common::UNK_LANG, Common::kPlatformUnknown }, { "f8be685007a8b425ba2a455da732f59f", "pajama2", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, @@ -613,7 +613,7 @@ static const MD5Table md5table[] = { { "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "fbbbb38a81fc9d6a61d509278390a290", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "fbdd947d21e8f5bac6d6f7a316af1c5a", "spyfox", "", "Demo", 15693, Common::EN_ANY, Common::kPlatformUnknown }, - { "fc53ce0e5f6562b1c1e1b4b8203acafb", "samnmax", "", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, + { "fc53ce0e5f6562b1c1e1b4b8203acafb", "samnmax", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformPC }, { "fc6b6148e80d67939d9a18697c0f626a", "monkey", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformPC }, { "fc8d197a22146e74766e9cb0cfcaf1da", "freddi2", "HE 80", "Demo", 27298, Common::EN_ANY, Common::kPlatformUnknown }, { "fcb78ebecab2757264c590890c319cc5", "PuttTime", "HE 85", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index abf9848451..9d6673d308 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -26,6 +26,7 @@ #include "common/config-manager.h" #include "common/md5.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "gui/message.h" @@ -135,6 +136,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) // Init all vars + _v0ObjectIndex = false; + _v0ObjectInInventory = false; _imuse = NULL; _imuseDigital = NULL; _musicEngine = NULL; @@ -182,6 +185,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _mouseAndKeyboardStat = 0; _leftBtnPressed = 0; _rightBtnPressed = 0; + _lastInputScriptTime = 0; _bootParam = 0; _dumpScripts = false; _debugMode = 0; @@ -215,7 +219,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _roomResource = 0; OF_OWNER_ROOM = 0; _verbMouseOver = 0; - _inventoryOffset = 0; _classData = NULL; _actorToPrintStrFor = 0; _sentenceNum = 0; @@ -539,7 +542,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) for (int i = 0; i < ARRAYSIZE(debugChannels); ++i) Common::addDebugChannel(debugChannels[i].flag, debugChannels[i].channel, debugChannels[i].desc); - syst->getEventManager()->registerRandomSource(_rnd, "scumm"); + g_eventRec.registerRandomSource(_rnd, "scumm"); } @@ -645,6 +648,8 @@ ScummEngine_v3old::ScummEngine_v3old(OSystem *syst, const DetectorResult &dr) ScummEngine_v2::ScummEngine_v2(OSystem *syst, const DetectorResult &dr) : ScummEngine_v3old(syst, dr) { + _inventoryOffset = 0; + _activeInventory = 0; _activeObject = 0; _activeVerb = 0; @@ -663,7 +668,17 @@ ScummEngine_v2::ScummEngine_v2(OSystem *syst, const DetectorResult &dr) ScummEngine_v0::ScummEngine_v0(OSystem *syst, const DetectorResult &dr) : ScummEngine_v2(syst, dr) { + _verbExecuting = false; + _verbPickup = false; _currentMode = 0; + + _activeObject2 = 0; + _activeObjectIndex = 0; + _activeObject2Index = 0; + _activeInvExecute = false; + _activeObject2Inv = false; + _activeObjectObtained = false; + _activeObject2Obtained = false; } ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr) @@ -1883,7 +1898,7 @@ void ScummEngine::scummLoop(int delta) { } // Trigger autosave if necessary. - if (!_saveLoadFlag && shouldPerformAutoSave(_lastSaveTime)) { + if (!_saveLoadFlag && shouldPerformAutoSave(_lastSaveTime) && canSaveGameStateCurrently()) { _saveLoadSlot = 0; sprintf(_saveLoadName, "Autosave %d", _saveLoadSlot); _saveLoadFlag = 1; diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 4ed8cf57eb..f0f2521225 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -565,6 +565,9 @@ protected: int32 *_scummVars; byte *_bitVars; + bool _v0ObjectIndex; // V0 Use object index, instead of object number + bool _v0ObjectInInventory; // V0 Use object number from inventory + /* Global resource tables */ int _numVariables, _numBitVariables, _numLocalObjects; int _numGlobalObjects, _numArray, _numVerbs, _numFlObject; @@ -612,6 +615,12 @@ protected: uint16 _mouseAndKeyboardStat; byte _leftBtnPressed, _rightBtnPressed; + /** + * Last time runInputScript was run (measured in terms of OSystem::getMillis()). + * This is currently only used for Indy3 mac to detect "double clicks". + */ + uint32 _lastInputScriptTime; + /** The bootparam, to be passed to the script 1, the bootscript. */ int _bootParam; @@ -858,12 +867,14 @@ protected: int getObjNewDir(int obj); int getObjectIndex(int object) const; int getObjectImageCount(int object); + int whereIsObjectInventory(int object); int whereIsObject(int object) const; int findObject(int x, int y); void findObjectInRoom(FindObjectInRoom *fo, byte findWhat, uint object, uint room); public: int getObjectOrActorXY(int object, int &x, int &y); // Used in actor.cpp, hence public protected: + int getDist(int x, int y, int x2, int y2); int getObjActToObjActDist(int a, int b); // Not sure how to handle const byte *getObjOrActorName(int obj); // these three.. void setObjectName(int obj); @@ -884,7 +895,6 @@ protected: protected: /* Should be in Verb class */ uint16 _verbMouseOver; - int _inventoryOffset; int8 _userPut; uint16 _userState; diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h index ccca5df0d3..19260b6429 100644 --- a/engines/scumm/scumm_v0.h +++ b/engines/scumm/scumm_v0.h @@ -35,7 +35,20 @@ namespace Scumm { */ class ScummEngine_v0 : public ScummEngine_v2 { protected: - int _currentMode; + byte _currentMode; + bool _verbExecuting; // is a verb executing + bool _verbPickup; // are we picking up an object during a verb execute + + int _activeActor; // Actor Number + int _activeObject2; // 2nd Object Number + + bool _activeInvExecute; // is activeInventory first to be executed + bool _activeObject2Inv; // is activeobject2 in the inventory + bool _activeObjectObtained; // collected _activeobject? + bool _activeObject2Obtained; // collected _activeObject2? + + int _activeObjectIndex; + int _activeObject2Index; public: ScummEngine_v0(OSystem *syst, const DetectorResult &dr); @@ -53,12 +66,25 @@ protected: virtual void processInput(); + virtual void runObject(int obj, int entry); virtual void saveOrLoad(Serializer *s); + // V0 MM Verb commands + int verbPrep(int object); + bool verbMove(int object, int objectIndex, bool invObject); + bool verbMoveToActor(int actor); + bool verbObtain(int object, int objIndex); + bool verbExecutes(int object, bool inventory = false); + bool verbExec(); + + int findObjectIndex(int x, int y); + virtual void checkExecVerbs(); virtual void handleMouseOver(bool updateInventory); void resetVerbs(); void setNewKidVerbs(); + + void drawSentenceWord(int object, bool usePrep, bool objInInventory); void drawSentence(); void switchActor(int slot); @@ -68,7 +94,7 @@ protected: virtual int getActiveObject(); - virtual void resetSentence(); + virtual void resetSentence(bool walking = false); /* Version C64 script opcodes */ void o_stopCurrentScript(); diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h index 338b5f6167..ee9591bc45 100644 --- a/engines/scumm/scumm_v2.h +++ b/engines/scumm/scumm_v2.h @@ -45,6 +45,7 @@ protected: int8 _mouseOverBoxV2; char _sentenceBuf[256]; + uint16 _inventoryOffset; int _activeInventory; int _activeObject; @@ -66,6 +67,8 @@ protected: virtual void resetScummVars(); virtual void decodeParseString(); + virtual void saveOrLoad(Serializer *s); + virtual void processKeyboard(Common::KeyState lastKeyHit); virtual void readIndexFile(); @@ -100,7 +103,7 @@ protected: virtual void setBuiltinCursor(int index); - void runObject(int obj, int entry); + virtual void runObject(int obj, int entry); /* Version 2 script opcodes */ void o2_actorFromPos(); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 2a681ffd62..d1676772a8 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -23,6 +23,9 @@ * */ +#include "common/config-manager.h" +#include "common/timer.h" +#include "common/util.h" #include "scumm/actor.h" #include "scumm/file.h" @@ -32,10 +35,6 @@ #include "scumm/sound.h" #include "scumm/util.h" -#include "common/config-manager.h" -#include "common/timer.h" -#include "common/util.h" - #include "sound/adpcm.h" #include "sound/audiocd.h" #include "sound/flac.h" @@ -46,8 +45,6 @@ #include "sound/vorbis.h" #include "sound/wave.h" - - namespace Scumm { struct MP3OffsetTable { /* Compressed Sound (.SO3) */ @@ -420,17 +417,16 @@ void Sound::playSound(int soundID) { sound = (char *)malloc(size); int vol = ptr[24] * 4; int loopStart = 0, loopEnd = 0; -#if 0 // Disabling this until after 0.11.0 int loopcount = ptr[27]; if (loopcount > 1) { // TODO: We can only loop once, or infinitely many times, but // have no support for a finite number of repetitions. - // This is + // So far, I have seen only 1 and 255 (for infinite repetitions), + // so maybe this is not really a problem. loopStart = READ_BE_UINT16(ptr + 10) - READ_BE_UINT16(ptr + 8); loopEnd = READ_BE_UINT16(ptr + 14); flags |= Audio::Mixer::FLAG_LOOP; } -#endif memcpy(sound, ptr + READ_BE_UINT16(ptr + 8), size); _mixer->playRaw(Audio::Mixer::kSFXSoundType, NULL, sound, size, rate, diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp index f00f4ff33b..e99bea87de 100644 --- a/engines/scumm/string.cpp +++ b/engines/scumm/string.cpp @@ -995,6 +995,11 @@ void ScummEngine::drawString(int a, const byte *msg) { } _string[a].xpos = _charset->_str.right; + + if (_game.heversion >= 60) { + _string[a]._default.xpos = _string[a].xpos; + _string[a]._default.ypos = _string[a].ypos; + } } int ScummEngine::convertMessageToString(const byte *msg, byte *dst, int dstSize) { diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 22487b43a3..98e088365e 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -538,9 +538,7 @@ void ScummEngine_v8::setupScummVars() { #endif void ScummEngine_v0::resetScummVars() { - _activeInventory = 0; - _activeObject = 0; - _activeVerb = 13; + resetSentence(); VAR(VAR_EGO) = 3; diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp index 81b28ce563..1ab9d72a58 100644 --- a/engines/scumm/verbs.cpp +++ b/engines/scumm/verbs.cpp @@ -155,6 +155,7 @@ void ScummEngine_v0::switchActor(int slot) { VAR(VAR_EGO) = VAR(97 + slot); actorFollowCamera(VAR(VAR_EGO)); resetVerbs(); + resetSentence(false); setUserState(247); } @@ -376,14 +377,8 @@ void ScummEngine_v2::checkV2Inventory(int x, int y) { if (object > 0) { if (_game.version == 0) { - if (_activeInventory != object) { - _activeInventory = object; - } else if (_activeVerb != 3 && _activeVerb != 13) { - if (_activeObject) - runObject(_activeObject, _activeVerb); - else - runObject(_activeInventory, _activeVerb); - } + _activeInventory = object; + } else { runInputScript(kInventoryClickArea, object, 0); } @@ -425,7 +420,9 @@ void ScummEngine_v2::redrawV2Inventory() { _string[1].right = _mouseOverBoxesV2[i].rect.right - 1; _string[1].color = _mouseOverBoxesV2[i].color; + _v0ObjectInInventory = true; const byte *tmp = getObjOrActorName(obj); + _v0ObjectInInventory = false; assert(tmp); // Prevent inventory entries from overflowing by truncating the text @@ -629,14 +626,14 @@ void ScummEngine_v2::checkExecVerbs() { if (vs->verbid && vs->saveid == 0 && vs->curmode == 1) { if (_mouseAndKeyboardStat == vs->key) { // Trigger verb as if the user clicked it - runInputScript(1, vs->verbid, 1); + runInputScript(kVerbClickArea, vs->verbid, 1); return; } } } // Generic keyboard input - runInputScript(4, _mouseAndKeyboardStat, 1); + runInputScript(kKeyClickArea, _mouseAndKeyboardStat, 1); } else if (_mouseAndKeyboardStat & MBS_MOUSE_MASK) { VirtScreen *zone = findVirtScreen(_mouse.y); const byte code = _mouseAndKeyboardStat & MBS_LEFT_CLICK ? 1 : 2; @@ -649,7 +646,7 @@ void ScummEngine_v2::checkExecVerbs() { if (zone->number == kVerbVirtScreen && _mouse.y <= zone->topline + 8) { // Click into V2 sentence line - runInputScript(5, 0, 0); + runInputScript(kSentenceClickArea, 0, 0); } else if (zone->number == kVerbVirtScreen && _mouse.y > zone->topline + inventoryArea) { // Click into V2 inventory checkV2Inventory(_mouse.x, _mouse.y); @@ -657,7 +654,7 @@ void ScummEngine_v2::checkExecVerbs() { over = findVerbAtPos(_mouse.x, _mouse.y); if (over != 0) { // Verb was clicked - runInputScript(1, _verbs[over].verbid, code); + runInputScript(kVerbClickArea, _verbs[over].verbid, code); } else { // Scene was clicked runInputScript((zone->number == kMainVirtScreen) ? kSceneClickArea : kVerbClickArea, 0, code); @@ -666,6 +663,25 @@ void ScummEngine_v2::checkExecVerbs() { } } +void ScummEngine_v0::runObject(int obj, int entry) { + int prev = _v0ObjectInInventory; + + if (getVerbEntrypoint(obj, entry) != 0) { + _v0ObjectInInventory = prev; + runObjectScript(obj, entry, false, false, NULL); + } else if (entry != 13 && entry != 15) { + if (_activeVerb != 3) { + VAR(9) = entry; + runScript(3, 0, 0, 0); + + // For some reasons, certain objects don't have a "give" script + } else if (VAR(5) > 0 && VAR(5) < 8) { + if (_activeInventory) + setOwnerOf(_activeInventory, VAR(5)); + } + } +} + void ScummEngine_v2::runObject(int obj, int entry) { if (getVerbEntrypoint(obj, entry) != 0) { runObjectScript(obj, entry, false, false, NULL); @@ -679,10 +695,293 @@ void ScummEngine_v2::runObject(int obj, int entry) { _activeVerb = 13; } +bool ScummEngine_v0::verbMoveToActor(int actor) { + Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + Actor *a2 =derefActor(actor, "checkExecVerbs"); + + if (!a->_moving) { + int dist = getDist(a->getRealPos().x, a->getRealPos().y, a2->getRealPos().x, a2->getRealPos().y); + if (dist > 5) + a->startWalkActor(a2->getRealPos().x, a2->getRealPos().y, 1); + else + return false; + + return true; + } + + return true; +} + +bool ScummEngine_v0::verbMove(int object, int objectIndex, bool invObject) { + int x, y, dir; + Actor *a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + + if (_currentMode != 3 && _currentMode != 2) + return false; + + if (a->_moving) + return true; + + _v0ObjectIndex = true; + getObjectXYPos(objectIndex, x, y, dir); + _v0ObjectIndex = false; + // Detect distance from target object + int dist = getDist(a->getRealPos().x, a->getRealPos().y, x, y); + + // FIXME: This should be changed once the walkbox problem is fixed + if (dist > 0x5) { + a->startWalkActor(x, y, dir); + VAR(6) = x; + VAR(7) = y; + return true; + } else { + // Finished walk, are we picking up the item? + if (_verbPickup) { + int oldActive = _activeObject, oldIndex = _activeObjectIndex; + _activeObject = object; + _activeObjectIndex = objectIndex; + + _v0ObjectIndex = true; + // Execute pickup + runObject(objectIndex, 14); + _v0ObjectIndex = false; + + _activeObject = oldActive; + _activeObjectIndex = oldIndex; + + // Finished picking up + _verbPickup = false; + } + } + + return false; +} + +bool ScummEngine_v0::verbObtain(int obj, int objIndex) { + bool didPickup = false; + + int prep, where = whereIsObjectInventory(obj); + + if (objIndex == 0) + return false; + + if (where != WIO_INVENTORY) { + _v0ObjectIndex = true; + prep = verbPrep(objIndex); + + if (prep == 1 || prep == 4) { + if (_activeVerb != 13 && _activeVerb != 14) { + _verbPickup = true; + didPickup = true; + } + } else { + _verbPickup = false; + } + + if (verbMove(obj, objIndex, false)) + return true; + + if (didPickup && (prep == 1 || prep == 4)) + if (_activeVerb != 13 && _activeVerb != 14) + _activeInventory = obj; + } + + return false; +} + +int ScummEngine_v0::verbPrep(int object) { + if (!_v0ObjectInInventory) + _v0ObjectIndex = true; + else + _v0ObjectIndex = false; + byte *ptr = getOBCDFromObject(object); + _v0ObjectIndex = false; + assert(ptr); + return (*(ptr + 11) >> 5); +} + +bool ScummEngine_v0::verbExecutes(int object, bool inventory) { + _v0ObjectInInventory = inventory; + int prep = verbPrep(object); + + if (prep == 2 || prep == 0) { + return true; + } + + return false; +} + +bool ScummEngine_v0::verbExec() { + int prep = 0; + int entry = (_currentMode != 0 && _currentMode != 1) ? _activeVerb : 15; + + if ((!_activeInvExecute && _activeObject && getObjectIndex(_activeObject) == -1)) { + resetSentence(); + return false; + } + + // Lets try walk to the object + if (_activeObject && _activeObjectIndex && !_activeObjectObtained && _currentMode != 0) { + prep = verbPrep(_activeObjectIndex); + + if (verbObtain(_activeObject, _activeObjectIndex)) + return true; + + _activeObjectObtained = true; + } + + if (_activeObject2 && _activeObject2Index && !_activeObject2Obtained && _currentMode != 0) { + prep = verbPrep(_activeObject2Index); + + _v0ObjectInInventory = false; + if (verbObtain(_activeObject2, _activeObject2Index)) + return true; + + if (prep != 1 && prep != 4) { + _activeInventory = _activeObject; + _activeObject = _activeObject2; + _activeObjectIndex = _activeObject2Index; + _activeObject2 = 0; + _activeObject2Index = 0; + } + + _activeObject2Obtained = true; + } + + // Give-To + if (_activeVerb == 3 && _activeInventory && _activeActor) { + // FIXME: Actors need to turn and face each other + // And walk to each other + if (verbMoveToActor(_activeActor)) + return true; + + _v0ObjectInInventory = true; + VAR(5) = _activeActor; + runObject(_activeInventory , 3); + _v0ObjectInInventory = false; + + resetSentence(); + return false; + } + + if (_activeActor) { + _v0ObjectIndex = true; + runObject(_activeActor, entry); + _v0ObjectIndex = false; + _verbExecuting = false; + + resetSentence(); + return false; + } + + // If we've finished walking (now near target), execute the action + if (_activeObject && _activeObjectIndex && verbPrep(_activeObjectIndex) == 2) { + _v0ObjectIndex = true; + runObject(_activeObjectIndex, entry); + _v0ObjectIndex = false; + _verbExecuting = false; + + if ((_currentMode == 3 || _currentMode == 2) && _activeVerb == 13) + return false; + + resetSentence(); + return false; + } + + // We acted on an inventory item + if (_activeInventory && verbExecutes(_activeInventory, true) && _activeVerb != 3) { + _v0ObjectInInventory = true; + runObject(_activeInventory, _activeVerb); + + _verbExecuting = false; + + if (_currentMode == 3 && _activeVerb == 13) { + resetSentence(true); + return false; + } + + resetSentence(); + return false; + } + + if (_activeObject) { + _v0ObjectIndex = true; + runObject(_activeObjectIndex, entry); + _v0ObjectIndex = false; + } else if (_activeInventory) { + if (verbExecutes(_activeInventory, true) == false) { + if (_activeObject2 && verbExecutes(_activeObject2, true)) { + _v0ObjectInInventory = true; + + _activeObject = _activeInventory; + _activeInventory = _activeObject2; + + runObject(_activeObject, _activeVerb); + } else { + _v0ObjectInInventory = true; + runObject(_activeInventory, _activeVerb); + } + } else { + runObject(_activeInventory, _activeVerb); + _v0ObjectInInventory = true; + } + } + + _verbExecuting = false; + + if (_activeVerb == 13) { + resetSentence(true); + return false; + } + + resetSentence(); + + return false; +} + void ScummEngine_v0::checkExecVerbs() { Actor *a; VirtScreen *zone = findVirtScreen(_mouse.y); + // Is a verb currently executing + if (_verbExecuting) { + // Check if mouse click + if (_mouseAndKeyboardStat & MBS_MOUSE_MASK) { + int over = findVerbAtPos(_mouse.x, _mouse.y); + int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + + if (over && over != _activeVerb) { + _activeVerb = over; + _verbExecuting = false; + return; + } + + if (!obj && !act && !over) { + resetSentence(false); + } else { + a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + a->stopActorMoving(); + } + } else { + if (_verbExecuting && !verbExec()) + return; + } + } + + // What-Is selected, any object we hover over is selected, on mouse press we set to WalkTo + if (_activeVerb == 15) { + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + int objIdx = findObjectIndex(_virtualMouse.x, _virtualMouse.y); + _activeObject = obj; + _activeObjectIndex = objIdx; + + if ((_mouseAndKeyboardStat & MBS_MOUSE_MASK)) + _activeVerb = 13; // Walk-To + + return; + } + if (_userPut <= 0 || _mouseAndKeyboardStat == 0) return; @@ -693,61 +992,147 @@ void ScummEngine_v0::checkExecVerbs() { if (zone->number == kVerbVirtScreen && _mouse.y <= zone->topline + 8) { // TODO } else if (zone->number == kVerbVirtScreen && _mouse.y > zone->topline + 32) { + int prevInventory = _activeInventory; + // Click into V2 inventory checkV2Inventory(_mouse.x, _mouse.y); + if (!_activeInventory) + return; + + // Did we just change the selected inventory item? + if (prevInventory && prevInventory != _activeInventory && _activeInventory != _activeObject2) { + _activeObject = 0; + _activeInvExecute = true; + _activeObject2Inv = true; + _activeObject2 = _activeInventory; + _activeInventory = prevInventory; + return; + } + + // is the new selected inventory the same as the last selected?, reset to previous if it is + if (_activeInventory == _activeObject2) + _activeInventory = prevInventory; + + // Inventory Selected changed + if (prevInventory != _activeInventory) + if (!_activeObject2 || prevInventory != _activeObject2) + return; + + if (_activeVerb == 11 && !((!(_activeObject || _activeInventory)) || !_activeObject2)) + return; } else { int over = findVerbAtPos(_mouse.x, _mouse.y); + int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); + int obj = findObject(_virtualMouse.x, _virtualMouse.y); + int objIdx = findObjectIndex(_virtualMouse.x, _virtualMouse.y); + + if ((_activeObject || _activeInventory) && act) { + obj = 0; + objIdx = 0; + } // Handle New Kid verb options - if (_activeVerb == 7) { + if (_activeVerb == 7 || over == 7) { + // Disable New-Kid (in the secret lab) + if (_currentMode == 2 || _currentMode == 0) + return; + + if (_activeVerb != 7) { + _activeVerb = over; + over = 0; + } + if (over) { _activeVerb = 13; switchActor(_verbs[over].verbid - 1); + return; } + + setNewKidVerbs(); + return; } + + // Clicked on nothing, walk here? + if (!over && !act && _activeVerb == 13 && !obj && _currentMode != 0) { + // Clear all selected + resetSentence(); - if (over) { - _activeVerb = _verbs[over].verbid; - // Selected New Kid verb - if (_activeVerb == 7) - setNewKidVerbs(); + // 0xB31 + VAR(6) = _virtualMouse.x / V12_X_MULTIPLIER; + VAR(7) = _virtualMouse.y / V12_Y_MULTIPLIER; + if (zone->number == kMainVirtScreen) { + a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); + a->stopActorMoving(); + a->startWalkActor(_virtualMouse.x / V12_X_MULTIPLIER, _virtualMouse.y / V12_Y_MULTIPLIER, -1); + } return; } - int act = getActorFromPos(_virtualMouse.x, _virtualMouse.y); - int obj = findObject(_virtualMouse.x, _virtualMouse.y); - if (act != 0 && _activeVerb == 3 && _activeInventory != 0) { - // Give inventory item to actor - VAR(5) = act; - runObject(_activeInventory, _activeVerb); - } else if (obj) { - if (_currentMode == 3 && _activeVerb != 13 && obj != _activeObject) { - _activeObject = obj; - return; - } + // No new verb, use previous + if (over == 0) + over = _activeVerb; - _activeObject = obj; - if (_currentMode == 3) { - int x, y, dir; - a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); - getObjectXYPos(obj, x, y, dir); - a->startWalkActor(x, y, dir); + // No verb selected, use walk-to + if (!_activeVerb) + _activeVerb = over = 13; // Walk-To + + // New verb selected + if (_activeVerb != over) { + _activeVerb = over; + if (_activeVerb == 13) { + resetSentence(); } + return; + } - int entry = (_currentMode == 3) ? _activeVerb : 15; - runObject(_activeObject, entry); - } else if (zone->number == kMainVirtScreen) { - a = derefActor(VAR(VAR_EGO), "checkExecVerbs"); - a->startWalkActor(_virtualMouse.x / V12_X_MULTIPLIER, _virtualMouse.y / V12_Y_MULTIPLIER, -1); + // Only allowing targetting actors if its the GIVE/USE verb + if (_activeVerb == 3 || _activeVerb == 11) { + // Different actor selected? + if (act) { + if (_activeActor != act) { + _activeActor = act; + return; + } + } } - _activeInventory = 0; - _activeObject = 0; - _activeVerb = 13; + if (obj && obj != _activeObject) { + if (!_activeObject) + if (_activeInventory) + _activeInvExecute = true; + + // USE + if (_activeVerb == 11 || _activeVerb == 8) { + if (obj != _activeObject || obj != _activeObject2) { + if (!_activeObject || _activeInventory) { + _activeObject = obj; + _activeObjectIndex = objIdx; + return; + } else { + if (_activeObject2 != obj) { + _activeObject2 = obj; + _activeObject2Index = objIdx; + return; + } + } + } + } else { + _activeObject = obj; + _activeObjectIndex = objIdx; + + if (_activeVerb != 13) + return; + + //return; + } + } } - } + + _verbExecuting = true; + + } // mouse k/b action } void ScummEngine::verbMouseOver(int verb) { diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp index 991fbe19d0..5924197d96 100644 --- a/engines/sky/logic.cpp +++ b/engines/sky/logic.cpp @@ -27,6 +27,7 @@ #include "common/endian.h" #include "common/rect.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "sky/autoroute.h" @@ -73,7 +74,7 @@ void Logic::setupLogicTable() { } Logic::Logic(SkyCompact *skyCompact, Screen *skyScreen, Disk *skyDisk, Text *skyText, MusicBase *skyMusic, Mouse *skyMouse, Sound *skySound) { - g_system->getEventManager()->registerRandomSource(_rnd, "sky"); + g_eventRec.registerRandomSource(_rnd, "sky"); _skyCompact = skyCompact; _skyScreen = skyScreen; diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 2d0d081ef6..7ed50461af 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -160,6 +160,9 @@ void MoviePlayer::play(void) { stopEvent.kbd = Common::KEYCODE_ESCAPE; stopEvents.push_back(stopEvent); + _textX = 0; + _textY = 0; + terminated = !playVideo(stopEvents); if (terminated) @@ -200,12 +203,15 @@ void MoviePlayer::performPostProcessing(byte *screen) { } } + byte *src, *dst; + int x, y; + if (_textMan->giveSpriteData(2)) { - byte *src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader); - byte *dst = screen + _textY * _decoder->getWidth() + _textX * 1; + src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader); + dst = screen + _textY * SCREEN_WIDTH + _textX * 1; - for (int y = 0; y < _textHeight; y++) { - for (int x = 0; x < _textWidth; x++) { + for (y = 0; y < _textHeight; y++) { + for (x = 0; x < _textWidth; x++) { switch (src[x]) { case BORDER_COL: dst[x] = _decoder->getBlack(); @@ -216,8 +222,34 @@ void MoviePlayer::performPostProcessing(byte *screen) { } } src += _textWidth; - dst += _decoder->getWidth(); + dst += SCREEN_WIDTH; + } + } else if (_textX && _textY) { + // If the frame doesn't cover the entire screen, we have to + // erase the subtitles manually. + + int frameWidth = _decoder->getWidth(); + int frameHeight = _decoder->getHeight(); + int frameX = (_system->getWidth() - frameWidth) / 2; + int frameY = (_system->getHeight() - frameHeight) / 2; + + dst = screen + _textY * _system->getWidth(); + + for (y = 0; y < _textHeight; y++) { + if (_textY + y < frameY || _textY + y >= frameY + frameHeight) { + memset(dst + _textX, _decoder->getBlack(), _textWidth); + } else { + if (frameX > _textX) + memset(dst + _textX, _decoder->getBlack(), frameX - _textX); + if (frameX + frameWidth < _textX + _textWidth) + memset(dst + frameX + frameWidth, _decoder->getBlack(), _textX + _textWidth - (frameX + frameWidth)); + } + + dst += _system->getWidth(); } + + _textX = 0; + _textY = 0; } } diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp index 756ce3a5cc..09d2197f2a 100644 --- a/engines/sword1/control.cpp +++ b/engines/sword1/control.cpp @@ -1207,7 +1207,7 @@ bool Control::restoreGameFromFile(uint8 slot) { for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++) playerBuf[cnt2] = inf->readUint32LE(); - if (inf->ioFailed()) { + if (inf->err() || inf->eos()) { displayMessage(0, "Can't read from file '%s'. (%s)", fName, _saveFileMan->popErrorDesc().c_str()); delete inf; free(_restoreBuf); diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 7e911bd197..be3797b0bd 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -28,6 +28,7 @@ #include "common/util.h" #include "common/system.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "sword1/logic.h" #include "sword1/text.h" @@ -55,7 +56,7 @@ namespace Sword1 { uint32 Logic::_scriptVars[NUM_SCRIPT_VARS]; Logic::Logic(SwordEngine *vm, ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Music *pMusic, Menu *pMenu, OSystem *system, Audio::Mixer *mixer) { - g_system->getEventManager()->registerRandomSource(_rnd, "sword1"); + g_eventRec.registerRandomSource(_rnd, "sword1"); _vm = vm; _objMan = pObjMan; diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp index 979bd3210a..90ea5fe677 100644 --- a/engines/sword1/resman.cpp +++ b/engines/sword1/resman.cpp @@ -263,9 +263,9 @@ void ResMan::resOpen(uint32 id) { // load resource ID into memory _memMan->alloc(memHandle, size); Common::File *clusFile = resFile(id); assert(clusFile); - clusFile->seek( resOffset(id) ); - clusFile->read( memHandle->data, size); - if (clusFile->ioFailed()) { + clusFile->seek(resOffset(id)); + clusFile->read(memHandle->data, size); + if (clusFile->err() || clusFile->eos()) { error("Can't read %d bytes from offset %d from cluster file %s\nResource ID: %d (%08X)", size, resOffset(id), _prj.clu[(id >> 24) - 1].label, id, id); } } else diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp index b23bf71445..6ad946b28d 100644 --- a/engines/sword1/sound.cpp +++ b/engines/sword1/sound.cpp @@ -28,6 +28,7 @@ #include "common/util.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "sword1/sound.h" @@ -47,7 +48,7 @@ namespace Sword1 { #define SPEECH_FLAGS (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_LITTLE_ENDIAN) Sound::Sound(const char *searchPath, Audio::Mixer *mixer, ResMan *pResMan) { - g_system->getEventManager()->registerRandomSource(_rnd, "sword1sound"); + g_eventRec.registerRandomSource(_rnd, "sword1sound"); strcpy(_filePath, searchPath); _mixer = mixer; _resMan = pResMan; diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 21ab645bfe..4a235315b6 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -116,7 +116,7 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI terminated = !playVideo(stopEvents); - closeTextObject(_currentMovieText); + closeTextObject(_currentMovieText, NULL); if (terminated) { _snd->stopHandle(*_bgSoundHandle); @@ -171,7 +171,7 @@ void MoviePlayer::openTextObject(uint32 index) { } } -void MoviePlayer::closeTextObject(uint32 index) { +void MoviePlayer::closeTextObject(uint32 index, byte *screen) { if (index < _numMovieTexts) { MovieText *text = &_movieTexts[index]; @@ -179,6 +179,32 @@ void MoviePlayer::closeTextObject(uint32 index) { text->_textMem = NULL; if (_textSurface) { + if (screen) { + // If the frame doesn't cover the entire + // screen, we have to erase the subtitles + // manually. + + int frameWidth = _decoder->getWidth(); + int frameHeight = _decoder->getHeight(); + int frameX = (_system->getWidth() - frameWidth) / 2; + int frameY = (_system->getHeight() - frameHeight) / 2; + + byte *dst = screen + _textY * _system->getWidth(); + + for (int y = 0; y < text->_textSprite.h; y++) { + if (_textY + y < frameY || _textY + y >= frameY + frameHeight) { + memset(dst + _textX, _decoder->getBlack(), text->_textSprite.w); + } else { + if (frameX > _textX) + memset(dst + _textX, _decoder->getBlack(), frameX - _textX); + if (frameX + frameWidth < _textX + text->_textSprite.w) + memset(dst + frameX + frameWidth, _decoder->getBlack(), _textX + text->_textSprite.w - (frameX + frameWidth)); + } + + dst += _system->getWidth(); + } + } + _vm->_screen->deleteSurface(_textSurface); _textSurface = NULL; } @@ -204,7 +230,7 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) { src = buffer; } - byte *dst = screen + _textY * _decoder->getWidth() + _textX; + byte *dst = screen + _textY * RENDERWIDE + _textX; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { @@ -214,15 +240,11 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) { dst[x] = white; } src += width; - dst += _decoder->getWidth(); + dst += RENDERWIDE; } } } -// FIXME: This assumes that the subtitles always fit within the frame of the -// movie. In Broken Sword 2, that's a fairly safe assumption, but not -// necessarily in all other games. - void MoviePlayer::performPostProcessing(byte *screen) { MovieText *text; int frame = _decoder->getCurFrame(); @@ -247,6 +269,7 @@ void MoviePlayer::performPostProcessing(byte *screen) { if (frame <= text->_endFrame) { drawTextObject(_currentMovieText, screen); } else { + closeTextObject(_currentMovieText, screen); _currentMovieText++; } } diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index 032350d2d6..f2b44baaa0 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -98,7 +98,7 @@ protected: void performPostProcessing(byte *screen); void openTextObject(uint32 index); - void closeTextObject(uint32 index); + void closeTextObject(uint32 index, byte *screen); void drawTextObject(uint32 index, byte *screen); }; diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp index 6741be33f1..c49fb8e786 100644 --- a/engines/sword2/resman.cpp +++ b/engines/sword2/resman.cpp @@ -151,7 +151,7 @@ bool ResourceManager::init() { for (i = 0; i < size / 2; i++) _resConvTable[i] = file.readUint16LE(); - if (file.ioFailed()) { + if (file.eos() || file.err()) { file.close(); GUIErrorMessage("Broken Sword 2: Cannot read resource.tab"); return false; @@ -178,7 +178,7 @@ bool ResourceManager::init() { cdInf[i].cd = file.readByte(); - if (file.ioFailed()) { + if (file.eos() || file.err()) { delete cdInf; file.close(); GUIErrorMessage("Broken Sword 2: Cannot read cd.inf"); @@ -477,7 +477,7 @@ void ResourceManager::readCluIndex(uint16 fileNum, Common::File *file) { _resFiles[fileNum].entryTab = (uint32*)malloc(tableSize); _resFiles[fileNum].numEntries = tableSize / 8; file->read(_resFiles[fileNum].entryTab, tableSize); - if (file->ioFailed()) + if (file->eos() || file->err()) error("unable to read index table from file %s", _resFiles[fileNum].fileName); #ifdef SCUMM_BIG_ENDIAN diff --git a/engines/sword2/startup.cpp b/engines/sword2/startup.cpp index 09bf65bf75..e4572d3c1a 100644 --- a/engines/sword2/startup.cpp +++ b/engines/sword2/startup.cpp @@ -66,7 +66,7 @@ bool Sword2Engine::initStartMenu() { int start_ids[MAX_starts]; int lineno = 0; - while (!fp.eos() && !fp.ioFailed()) { + while (!fp.eos() && !fp.err()) { Common::String line = fp.readLine(); // Skip empty lines or, more likely, the end of the stream. @@ -103,7 +103,7 @@ bool Sword2Engine::initStartMenu() { } // An I/O error before EOS? That's bad, but this is not a vital file. - if (fp.ioFailed() && !fp.eos()) + if (fp.err() && !fp.eos()) warning("I/O error while reading startup.inf"); fp.close(); diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index cf44b4c99c..e368f257a2 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -33,6 +33,7 @@ #include "common/file.h" #include "common/fs.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/savefile.h" #include "common/system.h" @@ -305,7 +306,7 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) { _gmmLoadSlot = -1; // Used to manage GMM Loading - syst->getEventManager()->registerRandomSource(_rnd, "sword2"); + g_eventRec.registerRandomSource(_rnd, "sword2"); } Sword2Engine::~Sword2Engine() { diff --git a/engines/tinsel/background.cpp b/engines/tinsel/background.cpp index 94525e33dd..583b9817a9 100644 --- a/engines/tinsel/background.cpp +++ b/engines/tinsel/background.cpp @@ -249,6 +249,8 @@ void DrawBackgnd(void) { UpdateScreenRect(*r); } + g_system->updateScreen(); + // delete all the clipping rectangles ResetClipRect(); } diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp index 1df932f1af..1e9693542e 100644 --- a/engines/tinsel/bmv.cpp +++ b/engines/tinsel/bmv.cpp @@ -1118,6 +1118,7 @@ void CopyMovieToScreen(void) { BmvDrawText(true); PalettesToVideoDAC(); // Keep palette up-to-date UpdateScreenRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)); + g_system->updateScreen(); BmvDrawText(false); } diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index a3f921505a..df3f95ca13 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -79,6 +79,8 @@ namespace Tinsel { using Common::GUIO_NONE; using Common::GUIO_NOSPEECH; +using Common::GUIO_NOSFX; +using Common::GUIO_NOMUSIC; static const TinselGameDescription gameDescriptions[] = { @@ -101,7 +103,7 @@ static const TinselGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSPEECH | GUIO_NOSFX | GUIO_NOMUSIC }, GID_DW1, 0, diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h index 826c0e38ba..943d728354 100644 --- a/engines/tinsel/dw.h +++ b/engines/tinsel/dw.h @@ -100,7 +100,7 @@ typedef int HPOLYGON; #define NO_ENTRY_NUM (-3458) // Magic unlikely number -#define SAMPLETIMEOUT (15*ONE_SECOND) +#define SAMPLETIMEOUT (20*ONE_SECOND) // Language for the resource strings enum LANGUAGE { diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp index cb334d96b0..0b3f2e6e24 100644 --- a/engines/tinsel/graphics.cpp +++ b/engines/tinsel/graphics.cpp @@ -713,7 +713,6 @@ void UpdateScreenRect(const Common::Rect &pClip) { byte *pSrc = (byte *)_vm->screen().getBasePtr(pClip.left, pClip.top); g_system->copyRectToScreen(pSrc, _vm->screen().pitch, pClip.left, pClip.top + yOffset, pClip.width(), pClip.height()); - g_system->updateScreen(); } /** diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp index e77f505edb..5db2918d2f 100644 --- a/engines/tinsel/heapmem.cpp +++ b/engines/tinsel/heapmem.cpp @@ -285,7 +285,8 @@ MEM_NODE *MemoryAlloc(int flags, long size) { } #ifdef SCUMM_NEED_ALIGNMENT - size = (size + 3) & ~3; //round up to nearest multiple of 4, this ensures the addresses that are returned are 4-byte aligned as well. + const int alignPadding = sizeof(void*) - 1; + size = (size + alignPadding) & ~alignPadding; //round up to nearest multiple of sizeof(void*), this ensures the addresses that are returned are alignment-safe. #endif while ((flags & DWM_NOALLOC) == 0 && bCompacted) { @@ -521,7 +522,7 @@ MEM_NODE *MemoryReAlloc(MEM_NODE *pMemNode, long size, int flags) { assert(flags & (DWM_FIXED | DWM_MOVEABLE)); // align the size to machine boundary requirements - size = (size + sizeof(int) - 1) & ~(sizeof(int) - 1); + size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1); // validate the size assert(size); diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 12d9f0393a..6ce1ea7288 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -189,7 +189,7 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { } // the index and length of the last tune loaded - static uint32 dwLastMidiIndex; + static uint32 dwLastMidiIndex = 0; //static uint32 dwLastSeqLen; uint32 dwSeqLen = 0; // length of the sequence @@ -256,6 +256,23 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { midiStream.close(); + // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii", + // which actually affects all ports, since it's specific to the GRA version. + // + // The GRA version does not seem to set the channel volume at all for the first + // intro track, thus we need to do that here. We only initialize the channels + // used in that sequence. And we are using 127 as default channel volume. + // + // Only in the GRA version dwFileOffset can be "38888", just to be sure, we + // check for the SCN files feature flag not being set though. + if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) { + _vm->_midiMusic->send(0x7F07B0 | 3); + _vm->_midiMusic->send(0x7F07B0 | 5); + _vm->_midiMusic->send(0x7F07B0 | 8); + _vm->_midiMusic->send(0x7F07B0 | 10); + _vm->_midiMusic->send(0x7F07B0 | 13); + } + _vm->_midiMusic->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop); // Store the length @@ -303,6 +320,8 @@ int GetMidiVolume() { return volMusic; } +static int priorVolMusic = 0; + /** * Sets the volume of the MIDI music. * @param vol New volume - 0..MAXMIDIVOL @@ -310,23 +329,24 @@ int GetMidiVolume() { void SetMidiVolume(int vol) { assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume); - if (vol == 0 && volMusic == 0) { + if (vol == 0 && priorVolMusic == 0) { // Nothing to do - } else if (vol == 0 && volMusic != 0) { + } else if (vol == 0 && priorVolMusic != 0) { // Stop current midi sequence StopMidi(); - } else if (vol != 0 && volMusic == 0) { + _vm->_midiMusic->setVolume(vol); + } else if (vol != 0 && priorVolMusic == 0) { // Perhaps restart last midi sequence - if (currentLoop) { + if (currentLoop) PlayMidiSequence(currentMidi, true); - _vm->_midiMusic->setVolume(vol); - } - } else if (vol != 0 && volMusic != 0) { + + _vm->_midiMusic->setVolume(vol); + } else if (vol != 0 && priorVolMusic != 0) { // Alter current volume _vm->_midiMusic->setVolume(vol); } - volMusic = vol; + priorVolMusic = vol; } /** @@ -374,6 +394,7 @@ void DeleteMidiBuffer() { MidiMusicPlayer::MidiMusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false) { memset(_channel, 0, sizeof(_channel)); + memset(_channelVolume, 0, sizeof(_channelVolume)); _masterVolume = 0; this->open(); _xmidiParser = MidiParser::createParser_XMIDI(); diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp index 8df9e9a375..84e88fe06b 100644 --- a/engines/tinsel/palette.cpp +++ b/engines/tinsel/palette.cpp @@ -133,7 +133,6 @@ void psxPaletteMapper(PALQ *originalPal, uint8 *psxClut, byte *mapperTable) { void PalettesToVideoDAC(void) { PALQ *pPalQ; // palette Q iterator VIDEO_DAC_Q *pDACtail = vidDACdata; // set tail pointer - bool needUpdate = false; // while Q is not empty while (pDAChead != pDACtail) { @@ -162,9 +161,6 @@ void PalettesToVideoDAC(void) { pColours = pDACtail->pal.pRGBarray; } - if (pDACtail->numColours > 0) - needUpdate = true; - // update the system palette g_system->setPalette((byte *)pColours, pDACtail->destDACindex, pDACtail->numColours); @@ -179,9 +175,6 @@ void PalettesToVideoDAC(void) { // clear all palette moved bits for (pPalQ = palAllocData; pPalQ < palAllocData + NUM_PALETTES; pPalQ++) pPalQ->posInDAC &= ~PALETTE_MOVED; - - if (needUpdate) - g_system->updateScreen(); } /** diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index 1d73411e13..e6ed9df5c9 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -120,6 +120,12 @@ const byte fragment2[] = {OP_LIBCALL | OPSIZE8, 110}; const int fragment2_size = 2; const byte fragment3[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 490 % 256, 490 / 256}; const int fragment3_size = 4; +const byte fragment4[] = {OP_IMM | OPSIZE16, 900 % 256, 900 / 256, OP_JUMP, 466 % 256, 466 / 256}; +const int fragment4_size = 6; +const byte fragment5[] = {OP_IMM | OPSIZE16, 901 % 256, 901 / 256, OP_JUMP, 488 % 256, 488 / 256}; +const int fragment5_size = 6; +const byte fragment6[] = {OP_IMM | OPSIZE16, 903 % 256, 903 / 256, OP_JUMP, 516 % 256, 516 / 256}; +const int fragment6_size = 6; const WorkaroundEntry workaroundList[] = { // DW1-SCN: Global 206 is whether Rincewind is trying to take the book back to the present. @@ -135,6 +141,12 @@ const WorkaroundEntry workaroundList[] = { // Present Outside Inn {TINSEL_V1, false, 352600876, 0, fragment2_size, fragment2}, + // DW1-GRA: Talking to palace guards in Act 2 gives !!!HIGH STRING||| - this happens if you initiate dialog + // with one of the guards, but not the other. So this fix routes the talk parameters of the broken one + {TINSEL_V1, false, 310506872, 463, fragment4_size, fragment4}, + {TINSEL_V1, false, 310506872, 485, fragment5_size, fragment5}, + {TINSEL_V1, false, 310506872, 513, fragment6_size, fragment6}, + // DW2: In the garden, global #490 is set when the bees begin their 'out of hive' animation, and reset when done. // But if the game is saved/restored during it, the animation sequence is reset without the global being cleared. // This causes bugs in several actions which try to disable the bees animation, since they wait indefinitely for @@ -636,6 +648,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_JUMP: // unconditional jump ip = Fetch(opcode, ic->code, wkEntry, ip); + wkEntry = NULL; // In case a jump occurs from a workaround break; case OP_JMPFALSE: // conditional jump @@ -644,6 +657,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { if (ic->stack[ic->sp--] == 0) { // condition satisfied - do the jump ip = tmp; + wkEntry = NULL; // In case a jump occurs from a workaround } break; @@ -653,6 +667,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { if (ic->stack[ic->sp--] != 0) { // condition satisfied - do the jump ip = tmp; + wkEntry = NULL; // In case a jump occurs from a workaround } break; diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index 62bcc732a8..0069778531 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -37,6 +37,8 @@ #include "common/serializer.h" #include "common/savefile.h" +#include "gui/message.h" + namespace Tinsel { @@ -84,6 +86,8 @@ extern void syncGlobInfo(Common::Serializer &s); // in POLYGONS.C extern void syncPolyInfo(Common::Serializer &s); +extern int sceneCtr; + //----------------- LOCAL DEFINES -------------------- struct SaveGameHeader { @@ -450,6 +454,11 @@ static bool DoRestore() { delete f; + if (failed) { + GUI::MessageDialog dialog("Failed to load game state from file."); + dialog.runModal(); + } + return !failed; } @@ -471,11 +480,11 @@ static void DoSave(void) { fname = SaveSceneName; f = _vm->getSaveFileMan()->openForSaving(fname); - if (f == NULL) - return; - Common::Serializer s(0, f); + if (f == NULL) + goto save_failure; + // Write out a savegame header SaveGameHeader hdr; hdr.id = SAVEGAME_ID; @@ -500,8 +509,12 @@ static void DoSave(void) { return; save_failure: - delete f; - _vm->getSaveFileMan()->removeSavefile(fname); + if (f) { + delete f; + _vm->getSaveFileMan()->removeSavefile(fname); + } + GUI::MessageDialog dialog("Failed to save game state to file."); + dialog.runModal(); } /** @@ -510,6 +523,10 @@ save_failure: void ProcessSRQueue(void) { switch (SRstate) { case SR_DORESTORE: + // If a load has been done directly from title screens, set a larger value for scene ctr so the + // code used to skip the title screens in Discworld 1 gets properly disabled + if (sceneCtr < 10) sceneCtr = 10; + if (DoRestore()) { DoRestoreScene(srsd, false); } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 95541e3287..5f056351b6 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -26,6 +26,7 @@ #include "common/endian.h" #include "common/error.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/keyboard.h" #include "common/file.h" #include "common/savefile.h" @@ -934,7 +935,7 @@ Common::Error TinselEngine::run() { _screenSurface.create(320, 200, 1); } - g_system->getEventManager()->registerRandomSource(_random, "tinsel"); + g_eventRec.registerRandomSource(_random, "tinsel"); _console = new Console(); diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index 5d79e0fb9a..1a6546cb4c 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -26,6 +26,7 @@ #include "common/config-manager.h" #include "common/events.h" +#include "common/EventRecorder.h" #include "common/system.h" #include "graphics/cursorman.h" @@ -73,7 +74,7 @@ ToucheEngine::ToucheEngine(OSystem *system, Common::Language language) Common::addDebugChannel(kDebugOpcodes, "Opcodes", "Opcodes debug level"); Common::addDebugChannel(kDebugMenu, "Menu", "Menu debug level"); - _eventMan->registerRandomSource(_rnd, "touche"); + g_eventRec.registerRandomSource(_rnd, "touche"); } ToucheEngine::~ToucheEngine() { diff --git a/engines/tucker/locations.cpp b/engines/tucker/locations.cpp index 4117391cdf..011410fe07 100644 --- a/engines/tucker/locations.cpp +++ b/engines/tucker/locations.cpp @@ -1671,7 +1671,7 @@ void TuckerEngine::execData3PreUpdate_locationNum26() { void TuckerEngine::updateSprite_locationNum27(int i) { int state; - if (_flagsTable[155] < 3 || _flagsTable[125] == 5) { + if (_flagsTable[155] < 3 || _flagsTable[155] == 5) { state = -1; } else if (_flagsTable[155] == 3) { state = 1; diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index b68f4822d8..a575ee8b94 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -366,22 +366,24 @@ applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) { uint8 r, g, b; uint lum; - const uint32 shiftMask = (uint32)~( - (1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) | (_format.aLoss == 8 ? 0 : (1 << _format.aShift))) >> 1; + // Mask to clear the last bit of every color component and all unused bits + const uint32 colorMask = ~((1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) // R/G/B components + | (_format.aLoss == 8 ? 0 : (1 << _format.aShift)) // Alpha component + | ~(_alphaMask | _redMask | _greenMask | _blueMask)); // All unused bits if (shadingStyle == GUI::ThemeEngine::kShadingDim) { int n = (pixels + 7) >> 3; switch (pixels % 8) { case 0: do { - *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 7: *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 6: *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 5: *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 4: *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 3: *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 2: *ptr = (*ptr >> 1) & shiftMask; ++ptr; - case 1: *ptr = (*ptr >> 1) & shiftMask; ++ptr; + *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 7: *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 6: *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 5: *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 4: *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 3: *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 2: *ptr = (*ptr & colorMask) >> 1; ++ptr; + case 1: *ptr = (*ptr & colorMask) >> 1; ++ptr; } while (--n > 0); } @@ -421,10 +423,10 @@ calcGradient(uint32 pos, uint32 max) { PixelType output = 0; pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max; - output |= ((_gradientStart&_redMask) + ((Base::_gradientBytes[0] * pos) >> 12)) & _redMask; - output |= ((_gradientStart&_greenMask) + ((Base::_gradientBytes[1] * pos) >> 12)) & _greenMask; - output |= ((_gradientStart&_blueMask) + ((Base::_gradientBytes[2] * pos) >> 12)) & _blueMask; - output |= ~(_redMask | _greenMask | _blueMask); + output |= ((_gradientStart & _redMask) + ((Base::_gradientBytes[0] * pos) >> 12)) & _redMask; + output |= ((_gradientStart & _greenMask) + ((Base::_gradientBytes[1] * pos) >> 12)) & _greenMask; + output |= ((_gradientStart & _blueMask) + ((Base::_gradientBytes[2] * pos) >> 12)) & _blueMask; + output |= _alphaMask; return output; } diff --git a/graphics/module.mk b/graphics/module.mk index de386c18fe..46ed564e1e 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -35,6 +35,12 @@ MODULE_OBJS += \ scaler/scale3x.o \ scaler/scalebit.o +ifdef USE_ARM_SCALER_ASM +MODULE_OBJS += \ + scaler/scale2xARM.o \ + scaler/Normal2xARM.o +endif + ifndef DISABLE_HQ_SCALERS MODULE_OBJS += \ scaler/hq2x.o \ diff --git a/graphics/scaler.cpp b/graphics/scaler.cpp index 11767848ed..a3aaaa121d 100644 --- a/graphics/scaler.cpp +++ b/graphics/scaler.cpp @@ -187,6 +187,57 @@ void Normal1x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPit } #ifndef DISABLE_SCALERS +#ifdef USE_ARM_SCALER_ASM +extern "C" void Normal2xAspectMask(const uint8 *srcPtr, + uint32 srcPitch, + uint8 *dstPtr, + uint32 dstPitch, + int width, + int height, + uint32 mask); + +void Normal2xAspect(const uint8 *srcPtr, + uint32 srcPitch, + uint8 *dstPtr, + uint32 dstPitch, + int width, + int height) { + if (gBitFormat == 565) { + Normal2xAspectMask(srcPtr, + srcPitch, + dstPtr, + dstPitch, + width, + height, + 0x07e0F81F); + } else { + Normal2xAspectMask(srcPtr, + srcPitch, + dstPtr, + dstPitch, + width, + height, + 0x03e07C1F); + } +} + +extern "C" void Normal2xARM(const uint8 *srcPtr, + uint32 srcPitch, + uint8 *dstPtr, + uint32 dstPitch, + int width, + int height); + +void Normal2x(const uint8 *srcPtr, + uint32 srcPitch, + uint8 *dstPtr, + uint32 dstPitch, + int width, + int height) { + Normal2xARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height); +} + +#else /** * Trivial nearest-neighbour 2x scaler. */ @@ -210,6 +261,7 @@ void Normal2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPit dstPtr += dstPitch << 1; } } +#endif /** * Trivial nearest-neighbour 3x scaler. diff --git a/graphics/scaler.h b/graphics/scaler.h index 4cea9ee2fb..bdae161bd1 100644 --- a/graphics/scaler.h +++ b/graphics/scaler.h @@ -45,6 +45,9 @@ DECLARE_SCALER(AdvMame2x); DECLARE_SCALER(AdvMame3x); DECLARE_SCALER(Normal1x); DECLARE_SCALER(Normal2x); +#ifdef USE_ARM_SCALER_ASM +DECLARE_SCALER(Normal2xAspect); +#endif DECLARE_SCALER(Normal3x); DECLARE_SCALER(Normal1o5x); DECLARE_SCALER(TV2x); diff --git a/graphics/scaler/Normal2xARM.s b/graphics/scaler/Normal2xARM.s new file mode 100755 index 0000000000..5de50d9c17 --- /dev/null +++ b/graphics/scaler/Normal2xARM.s @@ -0,0 +1,171 @@ +@ ScummVM Scumm Interpreter +@ Copyright (C) 2009 The ScummVM project +@ +@ 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$ +@ +@ @author Robin Watts (robin@wss.co.uk) + + .text + + .global Normal2xARM + .global Normal2xAspectMask + + + @ Assumes dst is aligned (so did the C) + @ Assumes 16bit (so did the C) +Normal2xARM: + @ r0 = src + @ r1 = srcPitch + @ r2 = dst + @ r3 = dstPitch + @ r4 = w + @ r5 = h + STMFD r13!,{r4-r11,r14} + LDR r4, [r13,#4*9] @ r4 = w + LDR r5, [r13,#4*10] @ r5 = h + ADD r12,r2, r3 + SUB r1, r1, r4, LSL #1 + SUB r6, r3, r4, LSL #2 + ADD r3, r3, r6 +yloop: + SUBS r14,r4, #4 + BLT thin +xloop: + LDRH r6, [r0], #2 + LDRH r7, [r0], #2 + LDRH r8, [r0], #2 + LDRH r9, [r0], #2 + ORR r6, r6, r6, LSL #16 + ORR r7, r7, r7, LSL #16 + ORR r8, r8, r8, LSL #16 + ORR r9, r9, r9, LSL #16 + STMIA r2!, {r6-r9} + STMIA r12!,{r6-r9} + SUBS r14,r14,#4 + BGE xloop + ADDS r14,r14,#4 + BNE thin + ADD r0, r0, r1 + ADD r2, r2, r3 + ADD r12,r12,r3 + SUBS r5, r5, #1 + BGT yloop + + LDMFD r13!,{r4-r11,PC} +thin: + LDRH r6, [r0], #2 + ORR r6, r6, r6, LSL #16 + STR r6, [r2], #4 + STR r6, [r12],#4 + SUBS r14,r14,#1 + BGT thin + ADD r0, r0, r1 + ADD r2, r2, r3 + ADD r12,r12,r3 + SUBS r5, r5, #1 + BGT yloop + + LDMFD r13!,{r4-r11,PC} + + + @ Horrid filter calculations + @ AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDDDDDDDDDDDDEEEEEEEEEEEE + @ <-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-> + @ Ideal: A,A,(A*2+B*3)/5,B,(B*4+C)/5,C,C,(C+D*4)/5,D,(D*3+E*2)/5,E,E + @ Actual: A,A,(A*3+B*5)/8,B,(B*7+C)/8,C,C,(C+D*7)/8,D,(D*5+E*3)/8,E,E + + @ Assumes dst is aligned (so did the C) + @ Assumes 16bit (so did the C) +Normal2xAspectMask: + @ r0 = src + @ r1 = srcPitch + @ r2 = dst + @ r3 = dstPitch + @ r4 = w + @ r5 = h + @ r12= mask + STMFD r13!,{r4-r11,r14} + LDR r4, [r13,#4*9] @ r4 = w + LDR r5, [r13,#4*10] @ r5 = h + LDR r12,[r13,#4*11] @ r12= mask + MOV r11,#2 + SUB r11,r11,r1, LSL #2 @ r11= 2-srcPitch*4 + MOV r14,#4 + SUB r14,r14,r3, LSL #3 + SUB r14,r14,r3, LSL #1 + SUB r14,r14,r3 @ r14 = 4-dstPitch*11 +yloop_aspect: +xloop_aspect: + LDRH r6, [r0], r1 @ r6 = A + LDRH r7, [r0], r1 @ r7 = B + LDRH r8, [r0], r1 @ r8 = C + LDRH r9, [r0], r1 @ r9 = D + LDRH r10,[r0], r11 @ r10= E + ORR r6, r6, r6, LSL #16 @ r6 = output 0, 1 + ORR r7, r7, r7, LSL #16 @ r7 = output 3 + ORR r8, r8, r8, LSL #16 @ r8 = output 5,6 + ORR r9, r9, r9, LSL #16 @ r9 = output 8 + ORR r10,r10,r10,LSL #16 @ r10= output 10, 11 + STR r6, [r2], r3 @ output 0 (A) + STR r6, [r2], r3 @ output 1 (A) + AND r6, r6, r12 @ r6 = A split + ADD r6, r6, r6, LSL #1 @ r6 = A*3 + STR r7, [r2, r3] @ output 3 (B) + AND r7, r7, r12 @ r7 = B split + ADD r6, r6, r7 @ r6 = A*3 + B + ADD r6, r6, r7, LSL #2 @ r6 = A*3 + B*5 + AND r6, r12,r6, LSR #3 @ r6 = (A*3 + B*5)>>3 + ORR r6, r6, r6, ROR #16 @ r6 = output 2 + STR r6, [r2], r3, LSL #1 @ output 2 (A*3+B*5)>>3 + RSB r7, r7, r7, LSL #3 @ r7 = B*7 + AND r6, r8, r12 @ r6 = C split + ADD r7, r7, r6 @ r7 = B*7+C + AND r7, r12,r7, LSR #3 @ r7 = (B*7 + C)>>3 + ORR r7, r7, r7, ROR #16 @ r7 = output 4 + STR r7, [r2], r3 @ output 4 (B*7+C)>>3 + STR r8, [r2], r3 @ output 5 (C) + STR r8, [r2], r3 @ output 6 (C) + STR r9, [r2, r3] @ output 8 (D) + AND r9, r9, r12 @ r9 = D split + RSB r7, r9, r9, LSL #3 @ r7 = D*7 + ADD r6, r6, r7 @ r6 = C+D*7 + AND r6, r12,r6, LSR #3 @ r6 = (C + D*7)>>3 + ORR r6, r6, r6, ROR #16 @ r6 = output 7 + STR r6, [r2], r3, LSL #1 @ output 7 (C+D*7)>>3 + ADD r9, r9, r9, LSL #2 @ r9 = D*5 + AND r6, r10,r12 @ r6 = E split + ADD r9, r9, r6 @ r9 = D*5+E + ADD r9, r9, r6, LSL #1 @ r9 = D*5+E*3 + AND r9, r12,r9, LSR #3 @ r9 = (D*5 + E*3)>>3 + ORR r9, r9, r9, ROR #16 @ r9 = output 9 + STR r9, [r2], r3 @ output 9 (D*5+E*3)>>3 + STR r10,[r2], r3 @ output 10 (E) + STR r10,[r2], r14 @ output 11 (E) + SUBS r4, r4, #1 + BGT xloop_aspect + LDR r4, [r13,#4*9] @ r4 = w + ADD r0, r0, r1, LSL #2 + ADD r0, r0, r1 + SUB r0, r0, r4, LSL #1 + ADD r2, r2, r3, LSL #3 + ADD r2, r2, r3, LSL #2 + SUB r2, r2, r4, LSL #2 + SUBS r5, r5, #5 + BGT yloop_aspect + + LDMFD r13!,{r4-r11,PC} diff --git a/graphics/scaler/scale2x.cpp b/graphics/scaler/scale2x.cpp index 226d379c91..877bbb9509 100644 --- a/graphics/scaler/scale2x.cpp +++ b/graphics/scaler/scale2x.cpp @@ -158,7 +158,7 @@ void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_ui /***************************************************************************/ /* Scale2x MMX implementation */ -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) /* * Apply the Scale2x effect at a single row. @@ -205,7 +205,7 @@ static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* __asm__ __volatile__( /* central runs */ - "shrl $3, %4\n" + "shr $3, %4\n" "jz 1f\n" "0:\n" @@ -261,12 +261,12 @@ static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* "movq %%mm3, 8(%3)\n" /* next */ - "addl $8, %0\n" - "addl $8, %1\n" - "addl $8, %2\n" - "addl $16, %3\n" + "add $8, %0\n" + "add $8, %1\n" + "add $8, %2\n" + "add $16, %3\n" - "decl %4\n" + "dec %4\n" "jnz 0b\n" "1:\n" @@ -283,7 +283,7 @@ static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint __asm__ __volatile__( /* central runs */ - "shrl $2, %4\n" + "shr $2, %4\n" "jz 1f\n" "0:\n" @@ -339,12 +339,12 @@ static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint "movq %%mm3, 8(%3)\n" /* next */ - "addl $8, %0\n" - "addl $8, %1\n" - "addl $8, %2\n" - "addl $16, %3\n" + "add $8, %0\n" + "add $8, %1\n" + "add $8, %2\n" + "add $16, %3\n" - "decl %4\n" + "dec %4\n" "jnz 0b\n" "1:\n" @@ -361,7 +361,7 @@ static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint __asm__ __volatile__( /* central runs */ - "shrl $1, %4\n" + "shr $1, %4\n" "jz 1f\n" "0:\n" @@ -417,12 +417,12 @@ static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint "movq %%mm3, 8(%3)\n" /* next */ - "addl $8, %0\n" - "addl $8, %1\n" - "addl $8, %2\n" - "addl $16, %3\n" + "add $8, %0\n" + "add $8, %1\n" + "add $8, %2\n" + "add $16, %3\n" - "decl %4\n" + "dec %4\n" "jnz 0b\n" "1:\n" diff --git a/graphics/scaler/scale2x.h b/graphics/scaler/scale2x.h index 2101790905..cefa14f22a 100644 --- a/graphics/scaler/scale2x.h +++ b/graphics/scaler/scale2x.h @@ -33,7 +33,7 @@ void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8 void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); @@ -52,5 +52,13 @@ static inline void scale2x_mmx_emms(void) #endif +#if defined(USE_ARM_SCALER_ASM) + +extern "C" void scale2x_8_arm(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +extern "C" void scale2x_16_arm(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); +extern "C" void scale2x_32_arm(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); + +#endif + #endif diff --git a/graphics/scaler/scale2xARM.s b/graphics/scaler/scale2xARM.s new file mode 100755 index 0000000000..3ca237e02d --- /dev/null +++ b/graphics/scaler/scale2xARM.s @@ -0,0 +1,182 @@ +@ ScummVM Scumm Interpreter +@ Copyright (C) 2009 The ScummVM project +@ +@ 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$ +@ +@ @author Robin Watts (robin@wss.co.uk) + + .text + + .global scale2x_8_arm + .global scale2x_16_arm + .global scale2x_32_arm + + @ r0 = dst0 + @ r1 = dst1 + @ r2 = src + @ r3 = src_prev + @ r4 = src_next + @ r5 = len + + + @ We hold: r10 B + @ r8 r14 r7 D E F + @ r12 H +scale2x_8_arm: + STMFD r13!,{r4-r5,r7-r8,r10-r11,r14} + LDR r4, [r13,#4*7] + LDR r5, [r13,#4*8] + + LDRB r14,[r2], #1 + CMP r3, #0 @ Set NE + @ Stall on Xscale + MOV r8, r14 + B loop8 +same8: + STRB r14,[r0], #1 + STRB r14,[r0], #1 + STRB r14,[r1], #1 + STRB r14,[r1], #1 + SUBS r5, r5, #1 + MOV r8, r14 + MOV r14,r7 + BLT end8 +loop8: + LDRNEB r7, [r3], #1 @ As long as we aren't on the last pixel + LDRB r10,[r2], #1 + LDRB r12,[r4], #1 + @ Stall on Xscale + CMP r7, r8 + CMPNE r10,r12 + BEQ same8 + CMP r8, r10 + STREQB r8, [r0], #1 + STRNEB r14,[r0], #1 + CMP r10,r7 + STREQB r7, [r0], #1 + STRNEB r14,[r0], #1 + CMP r8, r12 + STREQB r8, [r1], #1 + STRNEB r14,[r1], #1 + CMP r12,r7 + STREQB r7, [r1], #1 + STRNEB r14,[r1], #1 + + SUBS r5, r5, #1 + MOV r8, r14 + MOV r14,r7 + BGE loop8 +end8: + + LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC} + +scale2x_16_arm: + STMFD r13!,{r4-r5,r7-r8,r10-r11,r14} + LDR r4, [r13,#4*7] + LDR r5, [r13,#4*8] + + LDRH r14,[r3], #2 + CMP r3, #0 @ Set NE + @ Stall on Xscale + MOV r8, r14 + B loop16 +same16: + STRH r14,[r0], #2 + STRH r14,[r0], #2 + STRH r14,[r1], #2 + STRH r14,[r1], #2 + SUBS r5, r5, #1 + MOV r8, r14 + MOV r14,r7 + BLT end16 +loop16: + LDRNEH r7, [r3], #2 @ As long as we aren't on the last pixel + LDRH r10,[r2], #2 + LDRH r12,[r4], #2 + @ Stall on Xscale + CMP r7, r8 + CMPNE r10,r12 + BEQ same16 + CMP r8, r10 + STREQH r8, [r0], #2 + STRNEH r14,[r0], #2 + CMP r10,r7 + STREQH r7, [r0], #2 + STRNEH r14,[r0], #2 + CMP r8, r12 + STREQH r8, [r1], #2 + STRNEH r14,[r1], #2 + CMP r12,r7 + STREQH r7, [r1], #2 + STRNEH r14,[r1], #2 + + SUBS r5, r5, #1 + MOV r8, r14 + MOV r14,r7 + BGE loop16 +end16: + + LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC} + +scale2x_32_arm: + STMFD r13!,{r4-r5,r7-r8,r10-r11,r14} + LDR r4, [r13,#4*7] + LDR r5, [r13,#4*8] + + LDR r14,[r3], #4 + CMP r3, #0 @ Set NE + @ Stall on Xscale + MOV r8, r14 + B loop32 +same32: + STR r14,[r0], #4 + STR r14,[r0], #4 + STR r14,[r1], #4 + STR r14,[r1], #4 + SUBS r5, r5, #1 + MOV r8, r14 + MOV r14,r7 + BLT end32 +loop32: + LDRNE r7, [r3], #4 @ As long as we aren't on the last pixel + LDR r10,[r2], #4 + LDR r12,[r4], #4 + @ Stall on Xscale + CMP r7, r8 + CMPNE r10,r12 + BEQ same32 + CMP r8, r10 + STREQ r8, [r0], #4 + STRNE r14,[r0], #4 + CMP r10,r7 + STREQ r7, [r0], #4 + STRNE r14,[r0], #4 + CMP r8, r12 + STREQ r8, [r1], #4 + STRNE r14,[r1], #4 + CMP r12,r7 + STREQ r7, [r1], #4 + STRNE r14,[r1], #4 + + SUBS r5, r5, #1 + MOV r8, r14 + MOV r14,r7 + BGE loop32 +end32: + + LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC} diff --git a/graphics/scaler/scalebit.cpp b/graphics/scaler/scalebit.cpp index a6fd8df58f..6a3b47b0f5 100644 --- a/graphics/scaler/scalebit.cpp +++ b/graphics/scaler/scalebit.cpp @@ -55,10 +55,14 @@ static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) { switch (pixel) { -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) case 1 : scale2x_8_mmx(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break; case 2 : scale2x_16_mmx(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break; case 4 : scale2x_32_mmx(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break; +#elif defined(USE_ARM_SCALER_ASM) + case 1 : scale2x_8_arm(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break; + case 2 : scale2x_16_arm(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break; + case 4 : scale2x_32_arm(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break; #else case 1 : scale2x_8_def(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break; case 2 : scale2x_16_def(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break; @@ -125,7 +129,7 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un --count; } -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) scale2x_mmx_emms(); #endif } @@ -225,7 +229,7 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi --count; } -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) scale2x_mmx_emms(); #endif } @@ -303,7 +307,7 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned break; } -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) switch (scale) { case 2 : case 4 : diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp index 5392a1c9a4..405d8622c2 100644 --- a/graphics/sjis.cpp +++ b/graphics/sjis.cpp @@ -27,17 +27,33 @@ #ifdef GRAPHICS_SJIS_H #include "common/debug.h" +#include "common/archive.h" +#include "common/endian.h" namespace Graphics { -bool FontTowns::loadFromStream(Common::ReadStream &stream) { - for (uint i = 0; i < (kFontRomSize / 2); ++i) - _fontData[i] = stream.readUint16BE(); - return !stream.err(); +FontSJIS *FontSJIS::createFont(const Common::Platform platform) { + FontSJIS *ret = 0; + + // Try the font ROM of the specified platform + if (platform == Common::kPlatformFMTowns) { + ret = new FontTowns(); + if (ret && ret->loadData()) + return ret; + delete ret; + } + + // Try ScummVM's font. + ret = new FontSjisSVM(); + if (ret && ret->loadData()) + return ret; + delete ret; + + return 0; } template<typename Color> -void FontTowns::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch, Color c1, Color c2) const { +void FontSJIS16x16::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch, Color c1, Color c2) const { uint32 outlineGlyph[18]; memset(outlineGlyph, 0, sizeof(outlineGlyph)); @@ -72,7 +88,7 @@ void FontTowns::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch } template<typename Color> -void FontTowns::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const { +void FontSJIS16x16::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const { for (int y = 0; y < 16; ++y) { Color *lineBuf = (Color *)dst; uint16 line = *glyph++; @@ -88,8 +104,12 @@ void FontTowns::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color } } -void FontTowns::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const { - const uint16 *glyphSource = _fontData + sjisToChunk(ch & 0xFF, ch >> 8) * 16; +void FontSJIS16x16::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const { + const uint16 *glyphSource = getCharData(ch); + if (!glyphSource) { + warning("FontSJIS16x16::drawChar: Font does not offer data for %02X %02X", ch & 0xFF, ch >> 8); + return; + } if (bpp == 1) { if (!_outlineEnabled) @@ -106,7 +126,25 @@ void FontTowns::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, ui } } -uint FontTowns::sjisToChunk(uint8 f, uint8 s) { +// FM-TOWNS ROM font + +bool FontTowns::loadData() { + Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("FMT_FNT.ROM"); + if (!data) + return false; + + for (uint i = 0; i < (kFontRomSize / 2); ++i) + _fontData[i] = data->readUint16BE(); + + bool retValue = !data->err(); + delete data; + return retValue; +} + +const uint16 *FontTowns::getCharData(uint16 ch) const { + uint8 f = ch & 0xFF; + uint8 s = ch >> 8; + // copied from scumm\charset.cpp enum { KANA = 0, @@ -188,7 +226,61 @@ uint FontTowns::sjisToChunk(uint8 f, uint8 s) { } debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr); - return ((chunk_f + chunk) * 32 + (s - base)) + cr; + return _fontData + (((chunk_f + chunk) * 32 + (s - base)) + cr) * 16; +} + +// ScummVM SJIS font + +bool FontSjisSVM::loadData() { + Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("SJIS.FNT"); + if (!data) + return false; + + uint32 magic1 = data->readUint32BE(); + uint32 magic2 = data->readUint32BE(); + + if (magic1 != MKID_BE('SCVM') || magic2 != MKID_BE('SJIS')) { + delete data; + return false; + } + + uint32 version = data->readUint32BE(); + if (version != 1) { + delete data; + return false; + } + uint numChars = data->readUint16BE(); + + _fontData = new uint16[numChars * 16]; + assert(_fontData); + + for (uint i = 0; i < numChars * 16; ++i) + _fontData[i] = data->readUint16BE(); + + bool retValue = !data->err(); + delete data; + return retValue; +} + +const uint16 *FontSjisSVM::getCharData(uint16 c) const { + const uint8 fB = c & 0xFF; + const uint8 sB = c >> 8; + + // We only allow 2 byte SJIS characters. + if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F) + return 0; + + int base = fB; + base -= 0x81; + if (base >= 0x5F) + base -= 0x40; + + int index = sB; + index -= 0x40; + if (index >= 0x3F) + --index; + + return _fontData + (base * 0xBC + index) * 16; } } // end of namespace Graphics diff --git a/graphics/sjis.h b/graphics/sjis.h index f7321742af..b5d997a19a 100644 --- a/graphics/sjis.h +++ b/graphics/sjis.h @@ -35,6 +35,7 @@ #include "common/scummsys.h" #include "common/stream.h" +#include "common/util.h" #include "graphics/surface.h" @@ -50,6 +51,24 @@ public: virtual ~FontSJIS() {} /** + * Creates the first SJIS font, which ROM/font file is present. + * It will also call loadData, so the user can just start + * using the font. + * + * It'll prefer the platform specific ROM file, when platform + * is set to a value, which's font ROM is supported. + * So far that is only kPlatformFMTowns. + * + * The last file tried is ScummVM's SJIS.FNT file. + */ + static FontSJIS *createFont(const Common::Platform platform = Common::kPlatformUnknown); + + /** + * Load the font data. + */ + virtual bool loadData() = 0; + + /** * Enable outline drawing. * * After changing outline state, getFontHeight and getFontWidth might return @@ -69,6 +88,10 @@ public: /** * Draws a SJIS encoded character on the given surface. + * + * TODO: Currently there is no assurance, that this method will only draw within + * the surface boundaries. Thus the caller has to assure the glyph will fit at + * the specified position. */ void drawChar(Graphics::Surface &dst, uint16 ch, int x, int y, uint32 c1, uint32 c2) const { drawChar(dst.getBasePtr(x, y), ch, c1, c2, dst.pitch, dst.bytesPerPixel); @@ -78,7 +101,7 @@ public: * Draws a SJIS char on the given raw buffer. * * @param dst pointer to the destination - * @param ch character to draw + * @param ch character to draw (in little endian) * @param pitch pitch of the destination buffer (size in *bytes*) * @param bpp bytes per pixel of the destination buffer * @param c1 forground color @@ -88,18 +111,11 @@ public: }; /** - * FM-TOWNS ROM based SJIS compatible font. - * - * This is used in KYRA and SCI. + * A base class to render 16x16 monochrome SJIS fonts. */ -class FontTowns : public FontSJIS { +class FontSJIS16x16 : public FontSJIS { public: - FontTowns() : _outlineEnabled(false) {} - - /** - * Loads the ROM data from the given read stream. - */ - bool loadFromStream(Common::ReadStream &stream); + FontSJIS16x16() : _outlineEnabled(false) {} void enableOutline(bool enable) { _outlineEnabled = enable; } @@ -115,14 +131,51 @@ private: template<typename Color> void drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const; + bool _outlineEnabled; +protected: + + virtual const uint16 *getCharData(uint16 c) const = 0; +}; + +/** + * FM-TOWNS ROM based SJIS compatible font. + * + * This is used in KYRA and SCI. + */ +class FontTowns : public FontSJIS16x16 { +public: + /** + * Loads the ROM data from "FMT_FNT.ROM". + */ + bool loadData(); + +private: enum { kFontRomSize = 262144 }; - bool _outlineEnabled; uint16 _fontData[kFontRomSize / 2]; - static uint sjisToChunk(uint8 low, uint8 high); + const uint16 *getCharData(uint16 c) const; +}; + +/** + * Our custom SJIS FNT. + */ +class FontSjisSVM : public FontSJIS16x16 { +public: + FontSjisSVM() : _fontData(0) {} + ~FontSjisSVM() { delete[] _fontData; } + + /** + * Load the font data from "SJIS.FNT". + */ + bool loadData(); + +private: + uint16 *_fontData; + + const uint16 *getCharData(uint16 c) const; }; // TODO: Consider adding support for PC98 ROM diff --git a/graphics/video/coktelvideo/coktelvideo.cpp b/graphics/video/coktelvideo/coktelvideo.cpp index 39aa8c5d2d..39aeca07bd 100644 --- a/graphics/video/coktelvideo/coktelvideo.cpp +++ b/graphics/video/coktelvideo/coktelvideo.cpp @@ -40,52 +40,79 @@ Imd::~Imd() { clear(); } -bool Imd::load(Common::SeekableReadStream &stream) { - unload(); +uint32 Imd::getFeatures() const { + return _features; +} - _stream = &stream; +uint16 Imd::getFlags() const { + return _flags; +} - // Version - uint16 handle = _stream->readUint16LE(); - _version = _stream->readByte(); +int16 Imd::getX() const { + return _x; +} - // Version checking - if ((handle != 0) || (_version < 2)) { - warning("IMD Version incorrect (%d,%X)", handle, _version); - unload(); - return false; - } +int16 Imd::getY() const { + return _y; +} - // Rest header - _features = _stream->readByte(); - _framesCount = _stream->readUint16LE(); - _x = _stream->readSint16LE(); - _y = _stream->readSint16LE(); - _width = _stream->readSint16LE(); - _height = _stream->readSint16LE(); - _flags = _stream->readUint16LE(); - _firstFramePos = _stream->readUint16LE(); +int16 Imd::getWidth() const { + return _width; +} - // IMDs always have video - _features |= kFeaturesVideo; - // IMDs always have palettes - _features |= kFeaturesPalette; +int16 Imd::getHeight() const { + return _height; +} - // Palette - _stream->read((byte *) _palette, 768); +uint16 Imd::getFramesCount() const { + return _framesCount; +} + +uint16 Imd::getCurrentFrame() const { + return _curFrame; +} + +int16 Imd::getFrameRate() const { + if (!_hasSound) + return _frameRate; + return 1000 / (_soundSliceLength >> 16); +} + +uint32 Imd::getSyncLag() const { + return _skipFrames; +} + +const byte *Imd::getPalette() const { + return _palette; +} + +bool Imd::getFrameCoords(int16 frame, + int16 &x, int16 &y, int16 &width, int16 &height) { + + return false; +} + +bool Imd::hasExtraData(const char *fileName) const { + return false; +} + +Common::MemoryReadStream *Imd::getExtraData(const char *fileName) { + return 0; +} + +bool Imd::loadCoordinates() { // Standard coordinates if (_version >= 3) { _stdX = _stream->readUint16LE(); if (_stdX > 1) { warning("IMD: More than one standard coordinate quad found (%d)", _stdX); - unload(); return false; } if (_stdX != 0) { - _stdX = _stream->readSint16LE(); - _stdY = _stream->readSint16LE(); - _stdWidth = _stream->readSint16LE(); + _stdX = _stream->readSint16LE(); + _stdY = _stream->readSint16LE(); + _stdWidth = _stream->readSint16LE(); _stdHeight = _stream->readSint16LE(); _features |= kFeaturesStdCoords; } else @@ -93,8 +120,14 @@ bool Imd::load(Common::SeekableReadStream &stream) { } else _stdX = -1; - // Offset to frame positions table - uint32 framesPosPos = 0; + return true; +} + +bool Imd::loadFrameTableOffsets(uint32 &framesPosPos, uint32 &framesCoordsPos) { + framesPosPos = 0; + framesCoordsPos = 0; + + // Frame positions if (_version >= 4) { framesPosPos = _stream->readUint32LE(); if (framesPosPos != 0) { @@ -104,15 +137,43 @@ bool Imd::load(Common::SeekableReadStream &stream) { } } - // Offset to frame coordinates - uint32 framesCoordsPos = 0; + // Frame coordinates if (_features & kFeaturesFrameCoords) framesCoordsPos = _stream->readUint32LE(); - // Sound + return true; +} + +bool Imd::assessVideoProperties() { + // Sizes of the frame data and extra video buffer + if (_features & kFeaturesDataSize) { + _frameDataSize = _stream->readUint16LE(); + if (_frameDataSize == 0) { + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + } else + _vidBufferSize = _stream->readUint16LE(); + } else { + _frameDataSize = _width * _height + 500; + if (!(_flags & 0x100) || (_flags & 0x1000)) + _vidBufferSize = _frameDataSize; + } + + // Allocating working memory + _frameData = new byte[_frameDataSize + 500]; + assert(_frameData); + memset(_frameData, 0, _frameDataSize + 500); + _vidBuffer = new byte[_vidBufferSize + 500]; + assert(_vidBuffer); + memset(_vidBuffer, 0, _vidBufferSize + 500); + + return true; +} + +bool Imd::assessAudioProperties() { if (_features & kFeaturesSound) { - _soundFreq = _stream->readSint16LE(); - _soundSliceSize = _stream->readSint16LE(); + _soundFreq = _stream->readSint16LE(); + _soundSliceSize = _stream->readSint16LE(); _soundSlicesCount = _stream->readSint16LE(); if (_soundFreq < 0) @@ -122,8 +183,7 @@ bool Imd::load(Common::SeekableReadStream &stream) { _soundSlicesCount = -_soundSlicesCount - 1; if (_soundSlicesCount > 40) { - warning("IMD: More than 40 sound slices found (%d)", _soundSlicesCount); - unload(); + warning("Imd::load(): More than 40 sound slices found (%d)", _soundSlicesCount); return false; } @@ -132,57 +192,103 @@ bool Imd::load(Common::SeekableReadStream &stream) { _frameLength = _soundSliceLength >> 16; _soundStage = 1; - _hasSound = true; + _hasSound = true; _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); } else _frameLength = 1000 / _frameRate; - // Sizes of the frame data and extra video buffer - if (_features & kFeaturesDataSize) { - _frameDataSize = _stream->readUint16LE(); - if (_frameDataSize == 0) { - _frameDataSize = _stream->readUint32LE(); - _vidBufferSize = _stream->readUint32LE(); - } else - _vidBufferSize = _stream->readUint16LE(); - } else { - _frameDataSize = _width * _height + 500; - if (!(_flags & 0x100) || (_flags & 0x1000)) - _vidBufferSize = _frameDataSize; - } + return true; +} - // Frame positions table +bool Imd::loadFrameTables(uint32 framesPosPos, uint32 framesCoordsPos) { + // Positions table if (_framesPos) { _stream->seek(framesPosPos, SEEK_SET); for (int i = 0; i < _framesCount; i++) _framesPos[i] = _stream->readUint32LE(); } - // Frame coordinates table + // Coordinates table if (_features & kFeaturesFrameCoords) { _stream->seek(framesCoordsPos, SEEK_SET); _frameCoords = new Coord[_framesCount]; assert(_frameCoords); for (int i = 0; i < _framesCount; i++) { - _frameCoords[i].left = _stream->readSint16LE(); - _frameCoords[i].top = _stream->readSint16LE(); - _frameCoords[i].right = _stream->readSint16LE(); + _frameCoords[i].left = _stream->readSint16LE(); + _frameCoords[i].top = _stream->readSint16LE(); + _frameCoords[i].right = _stream->readSint16LE(); _frameCoords[i].bottom = _stream->readSint16LE(); } } + return true; +} + +bool Imd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + uint16 handle; + + handle = _stream->readUint16LE(); + _version = _stream->readByte(); + + // Version checking + if ((handle != 0) || (_version < 2)) { + warning("Imd::load(): Version incorrect (%d,%X)", handle, _version); + unload(); + return false; + } + + // Rest header + _features = _stream->readByte(); + _framesCount = _stream->readUint16LE(); + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); + _flags = _stream->readUint16LE(); + _firstFramePos = _stream->readUint16LE(); + + // IMDs always have video + _features |= kFeaturesVideo; + // IMDs always have palettes + _features |= kFeaturesPalette; + + // Palette + _stream->read((byte *) _palette, 768); + + if (!loadCoordinates()) { + unload(); + return false; + } + + uint32 framesPosPos, frameCoordsPos; + if (!loadFrameTableOffsets(framesPosPos, frameCoordsPos)) { + unload(); + return false; + } + + if (!assessAudioProperties()) { + unload(); + return false; + } + + if (!assessVideoProperties()) { + unload(); + return false; + } + + if (!loadFrameTables(framesPosPos, frameCoordsPos)) { + unload(); + return false; + } + // Seek to the first frame _stream->seek(_firstFramePos, SEEK_SET); - // Allocating working memory - _frameData = new byte[_frameDataSize + 500]; - assert(_frameData); - memset(_frameData, 0, _frameDataSize + 500); - _vidBuffer = new byte[_vidBufferSize + 500]; - assert(_vidBuffer); - memset(_vidBuffer, 0, _vidBufferSize + 500); - return true; } @@ -194,7 +300,7 @@ void Imd::setFrameRate(int16 frameRate) { if (frameRate == 0) frameRate = 1; - _frameRate = frameRate; + _frameRate = frameRate; _frameLength = 1000 / _frameRate; } @@ -212,11 +318,11 @@ void Imd::setXY(int16 x, int16 y) { for (int i = 0; i < _framesCount; i++) { if (_frameCoords[i].left != -1) { if (x >= 0) { - _frameCoords[i].left = _frameCoords[i].left - _x + x; + _frameCoords[i].left = _frameCoords[i].left - _x + x; _frameCoords[i].right = _frameCoords[i].right - _x + x; } if (y >= 0) { - _frameCoords[i].top = _frameCoords[i].top - _y + y; + _frameCoords[i].top = _frameCoords[i].top - _y + y; _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y; } } @@ -233,8 +339,8 @@ void Imd::setVideoMemory(byte *vidMem, uint16 width, uint16 height) { deleteVidMem(); _hasOwnVidMem = false; - _vidMem = vidMem; - _vidMemWidth = width; + _vidMem = vidMem; + _vidMemWidth = width; _vidMemHeight = height; } @@ -244,12 +350,17 @@ void Imd::setVideoMemory() { if ((_width > 0) && (_height > 0)) { setXY(0, 0); _hasOwnVidMem = true; - _vidMem = new byte[_width * _height]; - _vidMemWidth = _width; + _vidMem = new byte[_width * _height]; + _vidMemWidth = _width; _vidMemHeight = _height; + + memset(_vidMem, 0, _width * _height); } } +void Imd::setDoubleMode(bool doubleMode) { +} + void Imd::enableSound(Audio::Mixer &mixer) { // Only possible on the first frame if (_curFrame > 0) @@ -269,7 +380,7 @@ void Imd::disableSound() { delete _audioStream; _audioStream = 0; - _soundStage = 0; + _soundStage = 0; } _soundEnabled = false; _mixer = 0; @@ -312,8 +423,9 @@ void Imd::seekFrame(int32 frame, int16 whence, bool restart) { } else if (restart && (_soundStage == 0)) { for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++) processFrame(i); + return; } else - error("Frame %d is not directly accessible", frame); + error("Imd::seekFrame(): Frame %d is not directly accessible", frame); // Seek _stream->seek(framePos); @@ -325,7 +437,7 @@ CoktelVideo::State Imd::nextFrame() { } void Imd::waitEndFrame() { - if (_soundEnabled && _hasSound) { + if (_soundEnabled && _hasSound) {; if (_soundStage != 2) return; @@ -403,8 +515,9 @@ void Imd::deleteVidMem(bool del) { } _hasOwnVidMem = false; - _vidMem = 0; - _vidMemWidth = _vidMemHeight = 0; + _vidMem = 0; + _vidMemWidth = 0; + _vidMemHeight = 0; } void Imd::clear(bool del) { @@ -419,42 +532,126 @@ void Imd::clear(bool del) { _stream = 0; - _version = 0; + _version = 0; _features = 0; - _flags = 0; - _x = _y = _width = _height = 0; + _flags = 0; + + _x = _y = _width = _height = 0; _stdX = _stdY = _stdWidth = _stdHeight = 0; + _framesCount = _curFrame = 0; - _framesPos = 0; + + _framesPos = 0; _firstFramePos = 0; - _frameCoords = 0; + _frameCoords = 0; _frameDataSize = _vidBufferSize = 0; - _frameData = _vidBuffer = 0; - _frameDataLen = 0; + _frameData = _vidBuffer = 0; + _frameDataLen = 0; memset(_palette, 0, 768); deleteVidMem(del); - _hasSound = false; + _hasSound = false; _soundEnabled = false; - _soundStage = 0; - _skipFrames = 0; + _soundStage = 0; + _skipFrames = 0; - _soundFlags = 0; - _soundFreq = 0; - _soundSliceSize = 0; + _soundFlags = 0; + _soundFreq = 0; + _soundSliceSize = 0; _soundSlicesCount = 0; _soundSliceLength = 0; + _audioStream = 0; - _audioStream = 0; - - _frameRate = 12; - _frameLength = 0; + _frameRate = 12; + _frameLength = 0; _lastFrameTime = 0; } +void Imd::nextSoundSlice(bool hasNextCmd) { + if (hasNextCmd || !_soundEnabled) { + _stream->seek(_soundSliceSize, SEEK_CUR); + return; + } + + byte *soundBuf = new byte[_soundSliceSize]; + + _stream->read(soundBuf, _soundSliceSize); + unsignedToSigned(soundBuf, _soundSliceSize); + + _audioStream->queueBuffer(soundBuf, _soundSliceSize); +} + +bool Imd::initialSoundSlice(bool hasNextCmd) { + int dataLength = _soundSliceSize * _soundSlicesCount; + + if (hasNextCmd || !_soundEnabled) { + _stream->seek(dataLength, SEEK_CUR); + return false; + } + + byte *soundBuf = new byte[dataLength]; + + _stream->read(soundBuf, dataLength); + unsignedToSigned(soundBuf, dataLength); + + _audioStream->queueBuffer(soundBuf, dataLength); + + return _soundStage == 1; +} + +void Imd::emptySoundSlice(bool hasNextCmd) { + if (hasNextCmd || !_soundEnabled) + return; + + byte *soundBuf = new byte[_soundSliceSize]; + + memset(soundBuf, 0, _soundSliceSize); + + _audioStream->queueBuffer(soundBuf, _soundSliceSize); +} + +void Imd::videoData(uint32 size, State &state) { + _stream->read(_frameData, size); + _frameDataLen = size; + + if (_vidMemWidth <= state.right) { + state.left = 0; + state.right -= state.left; + } + if (_vidMemWidth <= state.right) + state.right = _vidMemWidth - 1; + if (_vidMemHeight <= state.bottom) { + state.top = 0; + state.bottom -= state.top; + } + if (_vidMemHeight <= state.bottom) + state.bottom = _vidMemHeight -1; + + state.flags |= renderFrame(state.left, state.top, state.right, state.bottom); + state.flags |= _frameData[0]; +} + +void Imd::calcFrameCoords(uint16 frame, State &state) { + if (_stdX != -1) { + state.left = _stdX; + state.top = _stdY; + state.right = _stdWidth + state.left - 1; + state.bottom = _stdHeight + state.top - 1; + state.flags |= kStateStdCoords; + } + if (_frameCoords && + (_frameCoords[frame].left != -1)) { + state.left = _frameCoords[frame].left; + state.top = _frameCoords[frame].top; + state.right = _frameCoords[frame].right; + state.bottom = _frameCoords[frame].bottom; + state.flags |= kStateFrameCoords; + } +} + CoktelVideo::State Imd::processFrame(uint16 frame) { State state; uint32 cmd = 0; @@ -474,47 +671,35 @@ CoktelVideo::State Imd::processFrame(uint16 frame) { if (!_vidMem) setVideoMemory(); - state.left = _x; - state.top = _y; - state.right = _width + state.left - 1; - state.bottom = _height + state.top - 1; + state.left = _x; + state.top = _y; + state.right = _width + state.left - 1; + state.bottom = _height + state.top - 1; do { - if (frame != 0) { - if (_stdX != -1) { - state.left = _stdX; - state.top = _stdY; - state.right = _stdWidth + state.left - 1; - state.bottom = _stdHeight + state.top - 1; - state.flags |= kStateStdCoords; - } - if (_frameCoords && - (_frameCoords[frame].left != -1)) { - state.left = _frameCoords[frame].left; - state.top = _frameCoords[frame].top; - state.right = _frameCoords[frame].right; - state.bottom = _frameCoords[frame].bottom; - state.flags |= kStateFrameCoords; - } - } + if (frame != 0) + calcFrameCoords(frame, state); cmd = _stream->readUint16LE(); - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { + if ((cmd & kCommandBreakMask) == kCommandBreak) { + // Flow control + + if (cmd == kCommandBreak) { _stream->seek(2, SEEK_CUR); cmd = _stream->readUint16LE(); } - if (cmd == 0xFFF1) { + // Break + if (cmd == kCommandBreakSkip0) { state.flags = kStateBreak; continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) + } else if (cmd == kCommandBreakSkip16) { cmd = _stream->readUint16LE(); _stream->seek(cmd, SEEK_CUR); state.flags = kStateBreak; continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) + } else if (cmd == kCommandBreakSkip32) { cmd = _stream->readUint32LE(); _stream->seek(cmd, SEEK_CUR); state.flags = kStateBreak; @@ -522,57 +707,24 @@ CoktelVideo::State Imd::processFrame(uint16 frame) { } } + // Audio if (_soundStage != 0) { - byte *soundBuf; - - // Next sound slice data - if (cmd == 0xFF00) { - - if (!hasNextCmd && _soundEnabled) { - soundBuf = new byte[_soundSliceSize]; - assert(soundBuf); - - _stream->read(soundBuf, _soundSliceSize); - unsignedToSigned(soundBuf, _soundSliceSize); - _audioStream->queueBuffer(soundBuf, _soundSliceSize); - } else - _stream->seek(_soundSliceSize, SEEK_CUR); + if (cmd == kCommandNextSound) { + nextSoundSlice(hasNextCmd); cmd = _stream->readUint16LE(); - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - int dataLength = _soundSliceSize * _soundSlicesCount; - - if (!hasNextCmd && _soundEnabled) { - soundBuf = new byte[dataLength]; - assert(soundBuf); - - _stream->read(soundBuf, dataLength); - unsignedToSigned(soundBuf, dataLength); - - if (_soundStage == 1) - startSound = true; - - _audioStream->queueBuffer(soundBuf, dataLength); - } else - _stream->seek(dataLength, SEEK_CUR); + } else if (cmd == kCommandStartSound) { + startSound = initialSoundSlice(hasNextCmd); cmd = _stream->readUint16LE(); - // Empty sound slice - } else if (!hasNextCmd && (_soundEnabled)) { - soundBuf = new byte[_soundSliceSize]; - assert(soundBuf); - - memset(soundBuf, 0, _soundSliceSize); - - _audioStream->queueBuffer(soundBuf, _soundSliceSize); - } + } else + emptySoundSlice(hasNextCmd); } // Set palette - if (cmd == 0xFFF4) { + if (cmd == kCommandPalette) { _stream->seek(2, SEEK_CUR); state.flags |= kStatePalette; @@ -582,8 +734,8 @@ CoktelVideo::State Imd::processFrame(uint16 frame) { hasNextCmd = false; - // Jump to frame - if (cmd == 0xFFFD) { + if (cmd == kCommandJump) { + // Jump to frame frame = _stream->readSint16LE(); if (_framesPos) { @@ -594,37 +746,17 @@ CoktelVideo::State Imd::processFrame(uint16 frame) { state.flags |= kStateJump; } - } else if (cmd == 0xFFFC) { + } else if (cmd == kCommandVideoData) { + uint32 size = _stream->readUint32LE() + 2; - state.flags |= 1; - cmd = _stream->readUint32LE(); - _stream->read(_frameData, cmd + 2); - _frameDataLen = cmd + 2; + videoData(size, state); - if (_vidMemWidth <= state.right) { - state.left = 0; - state.right -= state.left; - } - if (_vidMemWidth <= state.right) - state.right = _vidMemWidth - 1; - if (_vidMemHeight <= state.bottom) { - state.top = 0; - state.bottom -= state.top; - } - if (_vidMemHeight <= state.bottom) - state.bottom = _vidMemHeight -1; - - state.flags |= renderFrame(state.left, state.top, state.right, state.bottom); - state.flags |= _frameData[0]; + state.flags |= 1; - // Frame video data } else if (cmd != 0) { + uint32 size = cmd + 2; - _stream->read(_frameData, cmd + 2); - _frameDataLen = cmd + 2; - - state.flags |= renderFrame(state.left, state.top, state.right, state.bottom); - state.flags |= _frameData[0]; + videoData(size, state); } else state.flags |= kStateNoVideoData; @@ -642,24 +774,133 @@ CoktelVideo::State Imd::processFrame(uint16 frame) { _audioStream->finish(); _mixer->stopHandle(_audioHandle); _audioStream = 0; - _soundStage = 0; + _soundStage = 0; } _lastFrameTime = g_system->getMillis(); return state; } +// A whole, completely filled block +void Imd::renderBlockWhole(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight) { + + int16 w = MIN(width, destWidth); + int16 h = MIN(height, destHeight); + + for (int i = 0; i < h; i++) { + memcpy(dest, src, w); + + src += width; + dest += destWidth; + } +} + +// A quarter-wide whole, completely filled block +void Imd::renderBlockWhole4X(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight) { + + for (int i = 0; i < height; i++) { + byte *destBak = dest; + + for (int j = 0; j < width; j += 4, dest += 4, src++) + memset(dest, *src, 4); + + dest = destBak + destWidth; + } +} + +// A half-high whole, completely filled block +void Imd::renderBlockWhole2Y(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight) { + + while (height > 1) { + memcpy(dest , src, width); + memcpy(dest + destWidth, src, width); + + height -= 2; + dest += 2 * destWidth; + src += width; + } + + if (height == 1) + memcpy(dest, src, width); +} + +// A sparse block +void Imd::renderBlockSparse(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight) { + + for (int i = 0; i < height; i++) { + byte *destBak = dest; + uint16 pixWritten = 0; + + while (pixWritten < width) { + uint16 pixCount = *src++; + + if (pixCount & 0x80) { // Data + pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); + memcpy(dest, src, pixCount); + + pixWritten += pixCount; + dest += pixCount; + src += pixCount; + } else { // "Hole" + pixWritten += pixCount + 1; + dest += pixCount + 1; + } + + } + + dest = destBak + destWidth; + } +} + +// A half-high sparse block +void Imd::renderBlockSparse2Y(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight) { + + for (int i = 0; i < height; i += 2) { + byte *destBak = dest; + uint16 pixWritten = 0; + + while (pixWritten < width) { + uint16 pixCount = *src++; + + if (pixCount & 0x80) { // Data + pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); + memcpy(dest , src, pixCount); + memcpy(dest + destWidth, src, pixCount); + + pixWritten += pixCount; + dest += pixCount; + src += pixCount; + } else { // "Hole" + pixWritten += pixCount + 1; + dest += pixCount + 1; + } + + } + + dest = destBak + destWidth; + } +} + uint32 Imd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) { if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0)) return 0; uint32 retVal = 0; - int16 width = right - left + 1; - int16 height = bottom - top + 1; - int16 sW = _vidMemWidth; - byte *dataPtr = _frameData; + + int16 width = right - left + 1; + int16 height = bottom - top + 1; + int16 sW = _vidMemWidth; + int16 sH = _vidMemHeight; + + byte *dataPtr = _frameData; byte *imdVidMem = _vidMem + sW * top + left; byte *srcPtr; + uint8 type = *dataPtr++; if (type & 0x10) { // Palette data @@ -675,88 +916,30 @@ uint32 Imd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) { srcPtr = dataPtr; - if (type & 0x80) { // Frame data is compressed + if (type & 0x80) { + // Frame data is compressed + srcPtr = _vidBuffer; type &= 0x7F; if ((type == 2) && (width == sW)) { + // Directly uncompress onto the video surface deLZ77(imdVidMem, dataPtr); return retVal; } else deLZ77(srcPtr, dataPtr); } - uint16 pixCount, pixWritten; - byte *imdVidMemBak; - - if (type == 2) { // Whole block - for (int i = 0; i < height; i++) { - memcpy(imdVidMem, srcPtr, width); - srcPtr += width; - imdVidMem += sW; - } - } else if (type == 1) { // Sparse block - imdVidMemBak = imdVidMem; - for (int i = 0; i < height; i++) { - pixWritten = 0; - while (pixWritten < width) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // Data - pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); - memcpy(imdVidMem, srcPtr, pixCount); - - pixWritten += pixCount; - imdVidMem += pixCount; - srcPtr += pixCount; - } else { // "Hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - imdVidMem += pixCount; - } - } - imdVidMemBak += sW; - imdVidMem = imdVidMemBak; - } - } else if (type == 0x42) { // Whole quarter-wide block - for (int i = 0; i < height; i++) { - imdVidMemBak = imdVidMem; - - for (int j = 0; j < width; j += 4, imdVidMem += 4, srcPtr++) - memset(imdVidMem, *srcPtr, 4); - - imdVidMemBak += sW; - imdVidMem = imdVidMemBak; - } - } else if ((type & 0xF) == 2) { // Whole half-high block - for (; height > 1; height -= 2, imdVidMem += sW + sW, srcPtr += width) { - memcpy(imdVidMem, srcPtr, width); - memcpy(imdVidMem + sW, srcPtr, width); - } - if (height == -1) - memcpy(imdVidMem, srcPtr, width); - } else { // Sparse half-high block - imdVidMemBak = imdVidMem; - for (int i = 0; i < height; i += 2) { - pixWritten = 0; - while (pixWritten < width) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // Data - pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); - memcpy(imdVidMem, srcPtr, pixCount); - memcpy(imdVidMem + sW, srcPtr, pixCount); - - pixWritten += pixCount; - imdVidMem += pixCount; - srcPtr += pixCount; - } else { // "Hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - imdVidMem += pixCount; - } - } - imdVidMemBak += sW + sW; - imdVidMem = imdVidMemBak; - } - } + // Evaluate the block type + if (type == 0x01) + renderBlockSparse (imdVidMem, srcPtr, width, height, sW, sH); + else if (type == 0x02) + renderBlockWhole (imdVidMem, srcPtr, width, height, sW, sH); + else if (type == 0x42) + renderBlockWhole4X (imdVidMem, srcPtr, width, height, sW, sH); + else if ((type & 0x0F) == 0x02) + renderBlockWhole2Y (imdVidMem, srcPtr, width, height, sW, sH); + else + renderBlockSparse2Y(imdVidMem, srcPtr, width, height, sW, sH); return retVal; } @@ -848,7 +1031,45 @@ void Imd::deLZ77(byte *dest, byte *src) { } } -const uint16 Vmd::_tableADPCM[128] = { +inline void Imd::unsignedToSigned(byte *buffer, int length) { + while (length-- > 0) *buffer++ ^= 0x80; +} + + +Vmd::ExtraData::ExtraData() { + memset(name, 0, 16); + + offset = 0; + size = 0; + realSize = 0; +} + + +Vmd::Part::Part() { + type = kPartTypeSeparator; + field_1 = 0; + field_E = 0; + size = 0; + left = 0; + top = 0; + right = 0; + bottom = 0; + id = 0; + flags = 0; +} + + +Vmd::Frame::Frame() { + parts = 0; + offset = 0; +} + +Vmd::Frame::~Frame() { + delete[] parts; +} + + +const uint16 Vmd::_tableDPCM[128] = { 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, @@ -864,6 +1085,26 @@ const uint16 Vmd::_tableADPCM[128] = { 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 }; +const int32 Vmd::_tableADPCM[] = { + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767, 0 +}; + +const int32 Vmd::_tableADPCMStep[] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + Vmd::Vmd(Graphics::PaletteLUT *palLUT) : _palLUT(palLUT) { clear(false); } @@ -872,84 +1113,11 @@ Vmd::~Vmd() { clear(); } -bool Vmd::load(Common::SeekableReadStream &stream) { - unload(); - - _stream = &stream; - - uint16 headerLength = _stream->readUint16LE(); - uint16 handle = _stream->readUint16LE(); - _version = _stream->readUint16LE(); - - if (!(_version & 2)) - _features |= kFeaturesPalette; - else - _features |= kFeaturesFullColor; - - // 0x4 (4) - - // Version checking - if (headerLength != 814) { - warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); - unload(); - return false; - } - - _framesCount = _stream->readUint16LE(); - - // 0x6 (6) - - _x = _stream->readSint16LE(); - _y = _stream->readSint16LE(); - _width = _stream->readSint16LE(); - _height = _stream->readSint16LE(); - - // 0xE (14) - - if ((_width != 0) && (_height != 0)) { - _hasVideo = true; - _features |= kFeaturesVideo; - if (_features & kFeaturesFullColor) - _codecIndeo3 = new Indeo3(_width, _height, _palLUT); - } else - _hasVideo = false; - - if (_width > 320) { - if (!(_version & 4)) { - _version |= 4; - handle = 0; - } - } - - if (handle > 2) { - warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); - unload(); - return false; - } - - _bytesPerPixel = handle + 1; - - if (_bytesPerPixel > 1) { +bool Vmd::assessVideoProperties() { + if (_bytesPerPixel > 1) _features |= kFeaturesFullColor; - _features &= ~kFeaturesPalette; - } - - _flags = _stream->readUint16LE(); - - _partsPerFrame = _stream->readUint16LE(); - _firstFramePos = _stream->readUint32LE(); - _stream->skip(4); // Unknown - - // 0x1A (26) - - _stream->read((byte *) _palette, 768); - - // 0x31A (794) - - _frameDataSize = _stream->readUint32LE(); - _vidBufferSize = _stream->readUint32LE(); - - _doubleMode = false; + else + _features |= kFeaturesPalette; if ((_version & 2) && !(_version & 8)) { _externalCodec = true; @@ -957,7 +1125,21 @@ bool Vmd::load(Common::SeekableReadStream &stream) { } else _externalCodec = false; - _preScaleX = 1; + if (_externalCodec) { + if (_videoCodec == MKID_BE('iv32')) { + _features &= ~kFeaturesPalette; + _features |= kFeaturesFullColor; + _codecIndeo3 = new Indeo3(_width, _height, _palLUT); + } else { + char *fourcc = (char *) &_videoCodec; + + warning("Vmd::assessVideoProperties(): Unknow video codec FourCC \'%c%c%c%c\'", + fourcc[3], fourcc[2], fourcc[1], fourcc[0]); + return false; + } + } + + _preScaleX = 1; _postScaleX = 1; if (_externalCodec) @@ -970,10 +1152,10 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _blitMode = n - 1; if (_bytesPerPixel == 2) { - _preScaleX = n; + _preScaleX = n; _postScaleX = 1; } else if (_bytesPerPixel == 3) { - _preScaleX = 1; + _preScaleX = 1; _postScaleX = n; } @@ -984,8 +1166,6 @@ bool Vmd::load(Common::SeekableReadStream &stream) { if (!_externalCodec && !(_flags & 0x1000)) _scaleExternalX = _bytesPerPixel; - // 0x322 (802) - if (_hasVideo) { if ((_frameDataSize == 0) || (_frameDataSize > 1048576)) _frameDataSize = _width * _height + 1000; @@ -1009,42 +1189,75 @@ bool Vmd::load(Common::SeekableReadStream &stream) { if (_externalCodec && _codecIndeo3) _features |= kFeaturesSupportsDouble; - _soundFreq = _stream->readSint16LE(); - _soundSliceSize = _stream->readSint16LE(); - _soundSlicesCount = _stream->readSint16LE(); - _soundFlags = _stream->readUint16LE(); - _hasSound = (_soundFreq != 0); + return true; +} - // 0x32A (810) +bool Vmd::assessAudioProperties() { + bool supportedFormat = true; - if (_hasSound) { - _features |= kFeaturesSound; + _features |= kFeaturesSound; - _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0); - if (_soundStereo > 0) { - warning("TODO: VMD stereo"); - unload(); - return false; - } + _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0); + + if (_soundSliceSize < 0) { + _soundBytesPerSample = 2; + _soundSliceSize = -_soundSliceSize; + + if (_soundFlags & 0x10) { + _audioFormat = kAudioFormat16bitADPCM; + _soundHeaderSize = 3; + _soundDataSize = _soundSliceSize >> 1; + + if (_soundStereo > 0) + supportedFormat = false; + + } else { + _audioFormat = kAudioFormat16bitDPCM; + _soundHeaderSize = 1; + _soundDataSize = _soundSliceSize; + + if (_soundStereo == 1) { + supportedFormat = false; + } else if (_soundStereo == 2) { + _soundDataSize = 2 * _soundDataSize + 2; + _soundHeaderSize = 4; + } - if (_soundSliceSize < 0) { - _soundBytesPerSample = 2; - _soundSliceSize = -_soundSliceSize; } + } else { + _soundBytesPerSample = 1; + _audioFormat = kAudioFormat8bitDirect; + _soundHeaderSize = 0; + _soundDataSize = _soundSliceSize; - _soundSliceLength = (uint32) (((double) (1000 << 16)) / - ((double) _soundFreq / (double) _soundSliceSize)); - _frameLength = _soundSliceLength >> 16; + if (_soundStereo > 0) + supportedFormat = false; + } - _soundStage = 1; - _audioStream = Audio::makeAppendableAudioStream(_soundFreq, - (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0); - } else - _frameLength = 1000 / _frameRate; + if (!supportedFormat) { + warning("Vmd::assessAudioProperties(): Unsupported audio format: %d bits, encoding %d, stereo %d", + _soundBytesPerSample * 8, _audioFormat, _soundStereo); + return false; + } - _frameInfoOffset = _stream->readUint32LE(); + _soundSliceLength = (uint32) (((double) (1000 << 16)) / + ((double) _soundFreq / (double) _soundSliceSize)); + _frameLength = _soundSliceLength >> 16; + + _soundStage = 1; + + uint32 flags = 0; + + flags |= (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0; + flags |= (_soundStereo > 0) ? Audio::Mixer::FLAG_STEREO : 0; + + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, flags); - int numExtraData = 0; + return true; +} + +void Vmd::readFrameTable(int &numExtraData) { + numExtraData = 0; _stream->seek(_frameInfoOffset); _frames = new Frame[_framesCount]; @@ -1053,14 +1266,15 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _stream->skip(2); // Unknown _frames[i].offset = _stream->readUint32LE(); } + for (uint16 i = 0; i < _framesCount; i++) { bool separator = false; for (uint16 j = 0; j < _partsPerFrame; j++) { - _frames[i].parts[j].type = (PartType) _stream->readByte(); + _frames[i].parts[j].type = (PartType) _stream->readByte(); _frames[i].parts[j].field_1 = _stream->readByte(); - _frames[i].parts[j].size = _stream->readUint32LE(); + _frames[i].parts[j].size = _stream->readUint32LE(); if (_frames[i].parts[j].type == kPartTypeAudio) { @@ -1069,13 +1283,17 @@ bool Vmd::load(Common::SeekableReadStream &stream) { } else if (_frames[i].parts[j].type == kPartTypeVideo) { - _frames[i].parts[j].left = _stream->readUint16LE(); - _frames[i].parts[j].top = _stream->readUint16LE(); - _frames[i].parts[j].right = _stream->readUint16LE(); - _frames[i].parts[j].bottom = _stream->readUint16LE(); + _frames[i].parts[j].left = _stream->readUint16LE(); + _frames[i].parts[j].top = _stream->readUint16LE(); + _frames[i].parts[j].right = _stream->readUint16LE(); + _frames[i].parts[j].bottom = _stream->readUint16LE(); _frames[i].parts[j].field_E = _stream->readByte(); - _frames[i].parts[j].flags = _stream->readByte(); + _frames[i].parts[j].flags = _stream->readByte(); + } else if (_frames[i].parts[j].type == kPartTypeSpeech) { + _frames[i].parts[j].id = _stream->readUint16LE(); + // Speech text file name + _stream->skip(8); } else if (_frames[i].parts[j].type == kPartTypeExtraData) { if (!separator) numExtraData++; @@ -1090,16 +1308,9 @@ bool Vmd::load(Common::SeekableReadStream &stream) { } } +} - _stream->seek(_firstFramePos); - - if (numExtraData == 0) - return true; - - _extraData.reserve(numExtraData); - - numExtraData = 0; - +void Vmd::readExtraData() { uint32 ssize = _stream->size(); for (uint16 i = 0; i < _framesCount; i++) { _stream->seek(_frames[i].offset); @@ -1111,9 +1322,10 @@ bool Vmd::load(Common::SeekableReadStream &stream) { if (_frames[i].parts[j].type == kPartTypeExtraData) { ExtraData data; - data.offset = _stream->pos() + 20; - data.size = _frames[i].parts[j].size; + data.offset = _stream->pos() + 20; + data.size = _frames[i].parts[j].size; data.realSize = _stream->readUint32LE(); + _stream->read(data.name, 16); data.name[15] = '\0'; @@ -1128,6 +1340,110 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _stream->skip(_frames[i].parts[j].size); } } +} + +bool Vmd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + uint16 headerLength; + uint16 handle; + + headerLength = _stream->readUint16LE(); + handle = _stream->readUint16LE(); + _version = _stream->readUint16LE(); + + bool readPalette; + + // Version checking + if (headerLength == 50) { + // Newer version, used in Addy 5 upwards + warning("Vmd::load(): TODO: Addy 5 videos"); + readPalette = false; + } else if (headerLength == 814) { + // Old version + readPalette = true; + } else { + warning("Vmd::load(): Version incorrect (%d, %d, %d)", headerLength, handle, _version); + unload(); + return false; + } + + _framesCount = _stream->readUint16LE(); + + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); + + if ((_width != 0) && (_height != 0)) { + + _hasVideo = true; + _features |= kFeaturesVideo; + + } else + _hasVideo = false; + + _bytesPerPixel = 1; + if (_version & 4) + _bytesPerPixel = handle + 1; + + if (_bytesPerPixel > 3) { + warning("Vmd::load(): Requested %d bytes per pixel (%d, %d, %d)", _bytesPerPixel, headerLength, handle, _version); + unload(); + return false; + } + + _flags = _stream->readUint16LE(); + + _partsPerFrame = _stream->readUint16LE(); + _firstFramePos = _stream->readUint32LE(); + + _videoCodec = _stream->readUint32BE(); + + if (readPalette) + _stream->read((byte *) _palette, 768); + + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + + _doubleMode = false; + + if (_hasVideo) { + if (!assessVideoProperties()) { + unload(); + return false; + } + } + + _soundFreq = _stream->readSint16LE(); + _soundSliceSize = _stream->readSint16LE(); + _soundSlicesCount = _stream->readSint16LE(); + _soundFlags = _stream->readUint16LE(); + + _hasSound = (_soundFreq != 0); + + if (_hasSound) { + if (!assessAudioProperties()) { + unload(); + return false; + } + } else + _frameLength = 1000 / _frameRate; + + _frameInfoOffset = _stream->readUint32LE(); + + int numExtraData; + readFrameTable(numExtraData); + + _stream->seek(_firstFramePos); + + if (numExtraData == 0) + return true; + + _extraData.reserve(numExtraData); + readExtraData(); _stream->seek(_firstFramePos); return true; @@ -1150,11 +1466,11 @@ void Vmd::setXY(int16 x, int16 y) { if (_frames[i].parts[j].type == kPartTypeVideo) { if (x >= 0) { - _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x; + _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x; _frames[i].parts[j].right = _frames[i].parts[j].right - _x + x; } if (y >= 0) { - _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y; + _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y; _frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y; } } @@ -1242,7 +1558,8 @@ void Vmd::clear(bool del) { delete[] _vidMemBuffer; } - _hasVideo = true; + _hasVideo = true; + _videoCodec = 0; _codecIndeo3 = 0; @@ -1252,16 +1569,19 @@ void Vmd::clear(bool del) { _extraData.clear(); _soundBytesPerSample = 1; - _soundStereo = 0; - - _externalCodec = false; - _doubleMode = false; - _blitMode = 0; - _bytesPerPixel = 1; - _preScaleX = 1; - _postScaleX = 1; + _soundStereo = 0; + _soundHeaderSize = 0; + _soundDataSize = 0; + _audioFormat = kAudioFormat8bitDirect; + + _externalCodec = false; + _doubleMode = false; + _blitMode = 0; + _bytesPerPixel = 1; + _preScaleX = 1; + _postScaleX = 1; _scaleExternalX = 1; - _vidMemBuffer = 0; + _vidMemBuffer = 0; } CoktelVideo::State Vmd::processFrame(uint16 frame) { @@ -1271,15 +1591,17 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { seekFrame(frame); state.flags |= kStateNoVideoData; - state.left = 0x7FFF; - state.top = 0x7FFF; - state.right = 0; + state.left = 0x7FFF; + state.top = 0x7FFF; + state.right = 0; state.bottom = 0; if (!_vidMem) setVideoMemory(); for (uint16 i = 0; (i < _partsPerFrame) && (frame < _framesCount); i++) { + uint32 pos = _stream->pos(); + Part &part = _frames[frame].parts[i]; if (part.type == kPartTypeAudio) { @@ -1312,20 +1634,27 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { } else if (part.flags == 3) { if (_soundEnabled) { - emptySoundSlice(_soundSliceSize * _soundBytesPerSample); + emptySoundSlice(_soundDataSize * _soundBytesPerSample); if (_soundStage == 1) startSound = true; } _stream->skip(part.size); + } else if (part.flags == 4) { + warning("Vmd::processFrame(): TODO: Addy 5 sound type 4 (%d)", part.size); + disableSound(); + _stream->skip(part.size); } else { - warning("Unknown sound part type %d", part.flags); + warning("Vmd::processFrame(): Unknown sound type %d", part.flags); _stream->skip(part.size); } + _stream->seek(pos + part.size); + } else if ((part.type == kPartTypeVideo) && !_hasVideo) { - warning("Header claims there's no video, but video frame part found"); + warning("Vmd::processFrame(): Header claims there's no video, but video found (%d)", part.size); + _stream->skip(part.size); } else if ((part.type == kPartTypeVideo) && _hasVideo) { state.flags &= ~kStateNoVideoData; @@ -1360,12 +1689,19 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { state.bottom = MAX(state.bottom, b); } - } else if (part.type == 4) { + } else if (part.type == kPartTypeSeparator) { + } else if (part.type == kPartTypeExtraData) { + _stream->skip(part.size); + } else if (part.type == kPartType4) { // Unknown _stream->skip(part.size); + } else if (part.type == kPartTypeSpeech) { + state.flags |= kStateSpeech; + state.speechId = part.id; + // Always triggers when speech starts + _stream->skip(part.size); } else { - // Unknow type -// warning("Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame); + warning("Vmd::processFrame(): Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame); } } @@ -1379,7 +1715,7 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { _audioStream->finish(); _mixer->stopHandle(_audioHandle); _audioStream = 0; - _soundStage = 0; + _soundStage = 0; } // If these are still 0x7FFF, no video data has been processed @@ -1390,7 +1726,7 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { return state; } -void Vmd::deRLE(byte *&srcPtr, byte *&destPtr, int16 len) { +void Vmd::deRLE(byte *&destPtr, const byte *&srcPtr, int16 len) { srcPtr++; if (len & 1) @@ -1417,23 +1753,60 @@ void Vmd::deRLE(byte *&srcPtr, byte *&destPtr, int16 len) { } } +// A run-length-encoded sparse block +void Vmd::renderBlockRLE(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight) { + + for (int i = 0; i < height; i++) { + byte *destBak = dest; + uint16 pixWritten = 0; + + while (pixWritten < width) { + uint16 pixCount = *src++; + + if (pixCount & 0x80) { + pixCount = (pixCount & 0x7F) + 1; + + if (*src != 0xFF) { // Normal copy + memcpy(dest, src, pixCount); + dest += pixCount; + src += pixCount; + } else + deRLE(dest, src, pixCount); + + pixWritten += pixCount; + } else { // "Hole" + dest += pixCount + 1; + pixWritten += pixCount + 1; + } + + } + + dest = destBak + destWidth; + } + +} + uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) { if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0)) return 0; - int16 width = right - left + 1; - int16 height = bottom - top + 1; - int16 sW = _vidMemWidth; - int16 sH = _vidMemHeight; + int16 width = right - left + 1; + int16 height = bottom - top + 1; + int16 sW = _vidMemWidth; + int16 sH = _vidMemHeight; uint32 dataLen = _frameDataLen; - byte *dataPtr = _frameData; + + byte *dataPtr = _frameData; byte *imdVidMem = _vidMem + sW * top + left; byte *srcPtr; - uint8 type; - if ((width < 0) || (height < 0)) + if ((left < 0) || (top < 0) || (right < 0) || (bottom < 0)) + return 1; + if ((width <= 0) || (height <= 0)) return 1; + uint8 type; byte *dest = imdVidMem; if (Indeo3::isIndeo3(dataPtr, dataLen)) { @@ -1444,12 +1817,12 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) { width * (_doubleMode ? 2 : 1), height * (_doubleMode ? 2 : 1))) return 0; - type = 2; + type = 2; srcPtr = _vidBuffer; - width = _width * (_doubleMode ? 2 : 1); + width = _width * (_doubleMode ? 2 : 1); height = _height * (_doubleMode ? 2 : 1); - right = left + width - 1; - bottom = top + height - 1; + right = left + width - 1; + bottom = top + height - 1; } else { @@ -1458,8 +1831,8 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) { return 0; } - type = *dataPtr++; - srcPtr = dataPtr; + type = *dataPtr++; + srcPtr = dataPtr; if (_blitMode > 0) { dest = _vidMemBuffer + postScaleX(_width) * (top - _y) + postScaleX((left - _x)); @@ -1468,10 +1841,13 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) { sH = _height; } - if (type & 0x80) { // Frame data is compressed + if (type & 0x80) { + // Frame data is compressed + srcPtr = _vidBuffer; type &= 0x7F; if ((type == 2) && (postScaleX(width) == sW)) { + // Directly uncompress onto the video surface deLZ77(dest, dataPtr); blit(imdVidMem, dest, width, height); return 1; @@ -1481,109 +1857,22 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) { } - uint16 pixCount, pixWritten; - byte *destBak; - - if (type == 1) { // Sparse block - destBak = dest; - for (int i = 0; i < height; i++) { - pixWritten = 0; - while (pixWritten < postScaleX(width)) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // Data - pixCount = MIN<int>((pixCount & 0x7F) + 1, postScaleX(width) - pixWritten); - memcpy(dest, srcPtr, pixCount); - - pixWritten += pixCount; - dest += pixCount; - srcPtr += pixCount; - } else { // "Hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - dest += pixCount; - } - } - destBak += sW; - dest = destBak; - } - } else if (type == 2) { // Whole block - int16 w = MIN<int32>(postScaleX(width), sW); - int16 h = MIN(height, sH); - - for (int i = 0; i < h; i++) { - memcpy(dest, srcPtr, w); - srcPtr += postScaleX(width); - dest += sW; - } - - } else if (type == 3) { // RLE block - for (int i = 0; i < height; i++) { - destBak = dest; - - pixWritten = 0; - while (pixWritten < width) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { - pixCount = (pixCount & 0x7F) + 1; - - if (*srcPtr != 0xFF) { // Normal copy - memcpy(dest, srcPtr, pixCount); - dest += pixCount; - srcPtr += pixCount; - } else - deRLE(srcPtr, dest, pixCount); - - pixWritten += pixCount; - } else { // "Hole" - dest += pixCount + 1; - pixWritten += pixCount + 1; - } - - } - destBak += sW; - dest = destBak; - } - } else if (type == 0x42) { // Whole quarter-wide block - for (int i = 0; i < height; i++) { - destBak = dest; + width = postScaleX(width); + + // Evaluate the block type + if (type == 0x01) + renderBlockSparse (dest, srcPtr, width, height, sW, sH); + else if (type == 0x02) + renderBlockWhole (dest, srcPtr, width, height, sW, sH); + else if (type == 0x03) + renderBlockRLE (dest, srcPtr, width, height, sW, sH); + else if (type == 0x42) + renderBlockWhole4X (dest, srcPtr, width, height, sW, sH); + else if ((type & 0x0F) == 0x02) + renderBlockWhole2Y (dest, srcPtr, width, height, sW, sH); + else + renderBlockSparse2Y(dest, srcPtr, width, height, sW, sH); - for (int j = 0; j < width; j += 4, dest += 4, srcPtr++) - memset(dest, *srcPtr, 4); - - destBak += sW; - dest = destBak; - } - } else if ((type & 0xF) == 2) { // Whole half-high block - for (; height > 1; height -= 2, dest += sW + sW, srcPtr += width) { - memcpy(dest, srcPtr, width); - memcpy(dest + sW, srcPtr, width); - } - if (height == -1) - memcpy(dest, srcPtr, width); - } else { // Sparse half-high block - destBak = dest; - for (int i = 0; i < height; i += 2) { - pixWritten = 0; - while (pixWritten < width) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // Data - pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); - memcpy(dest, srcPtr, pixCount); - memcpy(dest + sW, srcPtr, pixCount); - - pixWritten += pixCount; - dest += pixCount; - srcPtr += pixCount; - } else { // "Hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - dest += pixCount; - } - } - destBak += sW + sW; - dest = destBak; - } - } dest = _vidMemBuffer + postScaleX(_width) * (top - _y) + postScaleX(left - _x); blit(imdVidMem, dest, width, height); @@ -1672,129 +1961,278 @@ void Vmd::blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 heigh dither->nextLine(); dest += _vidMemWidth; - src += 3 * srcPitch; + src += 3 * srcPitch; } delete dither; } -void Vmd::emptySoundSlice(uint32 size) { - if (!_audioStream) - return; +byte *Vmd::deDPCM(const byte *data, uint32 &size, int32 init[2]) { + if (!data || (size == 0)) + return 0; - byte *soundBuf = new byte[size]; - assert(soundBuf); + int channels = (_soundStereo > 0) ? 2 : 1; - memset(soundBuf, 0, size); + uint32 inSize = size; + uint32 outSize = size + channels; + + int16 *out = new int16[outSize]; + byte *sound = (byte *) out; + + int channel = 0; + + for (int i = 0; i < channels; i++) { + *out++ = TO_BE_16(init[channel]); - _audioStream->queueBuffer(soundBuf, size); + channel = (channel + 1) % channels; + } + + while (inSize-- > 0) { + if (*data & 0x80) + init[channel] -= _tableDPCM[*data++ & 0x7F]; + else + init[channel] += _tableDPCM[*data++]; + + init[channel] = CLIP<int32>(init[channel], -32768, 32767); + *out++ = TO_BE_16(init[channel]); + + channel = (channel + 1) % channels; + } + + size = outSize * 2; + return sound; } -void Vmd::soundSlice8bit(uint32 size) { +// Yet another IMA ADPCM variant +byte *Vmd::deADPCM(const byte *data, uint32 &size, int32 init, int32 index) { + if (!data || (size == 0)) + return 0; + + uint32 outSize = size * 2; + + int16 *out = new int16[outSize]; + byte *sound = (byte *) out; + + index = CLIP<int32>(index, 0, 88); + + int32 predictor = _tableADPCM[index]; + + uint32 dataByte = 0; + bool newByte = true; + + size *= 2; + while (size -- > 0) { + byte code = 0; + + if (newByte) { + dataByte = *data++; + code = (dataByte >> 4) & 0xF; + } else + code = dataByte & 0xF; + + newByte = !newByte; + + index += _tableADPCMStep[code]; + index = CLIP<int32>(index, 0, 88); + + int32 value = predictor / 8; + + if (code & 4) + value += predictor; + if (code & 2) + value += predictor / 2; + if (code & 1) + value += predictor / 4; + + if (code & 8) + init -= value; + else + init += value; + + init = CLIP<int32>(init, -32768, 32767); + + predictor = _tableADPCM[index]; + + *out++ = TO_BE_16(init); + } + + size = outSize * 2; + return sound; +} + +byte *Vmd::soundEmpty(uint32 &size) { if (!_audioStream) - return; + return 0; byte *soundBuf = new byte[size]; - assert(soundBuf); + memset(soundBuf, 0, size); + + return soundBuf; +} +byte *Vmd::sound8bitDirect(uint32 &size) { + if (!_audioStream) { + _stream->skip(size); + return 0; + } + + byte *soundBuf = new byte[size]; _stream->read(soundBuf, size); unsignedToSigned(soundBuf, size); - _audioStream->queueBuffer(soundBuf, size); + return soundBuf; } -void Vmd::soundSlice16bit(uint32 size, int16 &init) { - if (!_audioStream) - return; +byte *Vmd::sound16bitDPCM(uint32 &size) { + if (!_audioStream) { + _stream->skip(size); + return 0; + } - byte *dataBuf = new byte[size]; - byte *soundBuf = new byte[size * 2]; + int32 init[2]; - _stream->read(dataBuf, size); - deADPCM(soundBuf, dataBuf, init, size); - _audioStream->queueBuffer(soundBuf, size * 2); + init[0] = _stream->readSint16LE(); + size -= 2; + + if (_soundStereo > 0) { + init[1] = _stream->readSint16LE(); + size -= 2; + } - delete[] dataBuf; + byte *data = new byte[size]; + byte *sound = 0; + + if (_stream->read(data, size) == size) + sound = deDPCM(data, size, init); + + delete[] data; + + return sound; } -void Vmd::filledSoundSlice(uint32 size) { - if (_soundBytesPerSample == 1) { - soundSlice8bit(size); - } else if (_soundBytesPerSample == 2) { - int16 init = _stream->readSint16LE(); - soundSlice16bit(size - 2, init); +byte *Vmd::sound16bitADPCM(uint32 &size) { + if (!_audioStream) { + _stream->skip(size); + return 0; } + + int32 init = _stream->readSint16LE(); + size -= 2; + + int32 index = _stream->readByte(); + size--; + + byte *data = new byte[size]; + byte *sound = 0; + + if (_stream->read(data, size) == size) + sound = deADPCM(data, size, init, index); + + delete[] data; + + return sound; } -void Vmd::filledSoundSlices(uint32 size, uint32 mask) { - int n = MIN<int>(_soundSlicesCount - 1, 31); - for (int i = 0; i < n; i++) { +void Vmd::emptySoundSlice(uint32 size) { + byte *sound = soundEmpty(size); - if (mask & 1) - emptySoundSlice(_soundSliceSize * _soundBytesPerSample); - else - filledSoundSlice(_soundSliceSize + 1); + if (sound) + _audioStream->queueBuffer(sound, size); +} + +void Vmd::filledSoundSlice(uint32 size) { + byte *sound = 0; + if (_audioFormat == kAudioFormat8bitDirect) + sound = sound8bitDirect(size); + else if (_audioFormat == kAudioFormat16bitDPCM) + sound = sound16bitDPCM(size); + else if (_audioFormat == kAudioFormat16bitADPCM) + sound = sound16bitADPCM(size); + + if (sound) + _audioStream->queueBuffer(sound, size); +} + +uint8 Vmd::evaluateMask(uint32 mask, bool *fillInfo, uint8 &max) { + max = MIN<int>(_soundSlicesCount - 1, 31); + + uint8 n = 0; + for (int i = 0; i < max; i++) { + + if (!(mask & 1)) { + n++; + *fillInfo++ = true; + } else + *fillInfo++ = false; mask >>= 1; } - if (_soundSlicesCount > 32) - filledSoundSlice((_soundSlicesCount - 32) * _soundSliceSize); + + return n; } -void Vmd::deADPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) { - int16 *out = (int16 *) soundBuf; +void Vmd::filledSoundSlices(uint32 size, uint32 mask) { + bool fillInfo[32]; + + uint8 max; + uint8 n = evaluateMask(mask, fillInfo, max); + + int32 extraSize; + + extraSize = size - n * _soundDataSize; + + if (_soundSlicesCount > 32) + extraSize -= (_soundSlicesCount - 32) * _soundDataSize; + + if (n > 0) + extraSize /= n; - int32 s = init; - for (uint32 i = 0; i < n; i++) { - if (dataBuf[i] & 0x80) - s -= _tableADPCM[dataBuf[i] & 0x7F]; + for (uint8 i = 0; i < max; i++) + if (fillInfo[i]) + filledSoundSlice(_soundDataSize + extraSize); else - s += _tableADPCM[dataBuf[i]]; + emptySoundSlice(_soundDataSize * _soundBytesPerSample); - s = CLIP<int32>(s, -32768, 32767); - *out++ = TO_BE_16(s); - } + if (_soundSlicesCount > 32) + filledSoundSlice((_soundSlicesCount - 32) * _soundDataSize + _soundHeaderSize); } -bool Vmd::getAnchor(int16 frame, uint16 partType, +bool Vmd::getPartCoords(int16 frame, PartType type, int16 &x, int16 &y, int16 &width, int16 &height) { - uint32 pos = _stream->pos(); + if (frame >= _framesCount) + return false; - _stream->seek(_frameInfoOffset); - // Offsets to frames - _stream->skip(_framesCount * 6); - // Jump to the specified frame - _stream->skip(_partsPerFrame * frame * 16); + Frame &f = _frames[frame]; - // Find the anchor part - uint16 i; - for (i = 0; i < _partsPerFrame; i++) { - byte type = _stream->readByte(); + // Look for a part matching the requested type, stopping at a separator + Part *part = 0; + for (int i = 0; i < _partsPerFrame; i++) { + Part &p = f.parts[i]; - if ((type == kPartTypeSeparator) || (type == partType)) + if ((p.type == kPartTypeSeparator) || (p.type == type)) { + part = &p; break; - - _stream->skip(15); + } } - if (i == _partsPerFrame) { - // No anchor - - _stream->seek(pos); + if (!part) return false; - } - _stream->skip(5); - x = _stream->readSint16LE(); - y = _stream->readSint16LE(); - width = _stream->readSint16LE() - x + 1; - height = _stream->readSint16LE() - y + 1; + x = part->left; + y = part->top; + width = part->right - part->left + 1; + height = part->bottom - part->top + 1; - _stream->seek(pos); return true; } +bool Vmd::getFrameCoords(int16 frame, + int16 &x, int16 &y, int16 &width, int16 &height) { + + return getPartCoords(frame, kPartTypeVideo, x, y, width, height); +} + bool Vmd::hasExtraData(const char *fileName) const { for (uint i = 0; i < _extraData.size(); i++) if (!scumm_stricmp(_extraData[i].name, fileName)) diff --git a/graphics/video/coktelvideo/coktelvideo.h b/graphics/video/coktelvideo/coktelvideo.h index 58b56e18ec..db80b4c43d 100644 --- a/graphics/video/coktelvideo/coktelvideo.h +++ b/graphics/video/coktelvideo/coktelvideo.h @@ -76,7 +76,9 @@ public: /** Had to explicitely seek to the frame. */ kStateSeeked = 0x2000, /** Reached a break-point. */ - kStateBreak = 0x8000 + kStateBreak = 0x8000, + /** Frame marks the beginning of speech. */ + kStateSpeech = 0x4000000 }; struct State { @@ -90,8 +92,10 @@ public: int16 bottom; /** Set accordingly to what was done. */ uint32 flags; + /** The id of the spoken words. */ + uint16 speechId; - State() : left(0), top(0), right(0), bottom(0), flags(0) { } + State() : left(0), top(0), right(0), bottom(0), flags(0), speechId(0) { } }; virtual ~CoktelVideo() { } @@ -123,8 +127,8 @@ public: /** Returns the current frame's palette. */ virtual const byte *getPalette() const = 0; - /** Reads the video's anchor pointer */ - virtual bool getAnchor(int16 frame, uint16 partType, + /** Returns the frame's coordinates */ + virtual bool getFrameCoords(int16 frame, int16 &x, int16 &y, int16 &width, int16 &height) = 0; /** Returns whether that extra data file exists */ @@ -171,9 +175,6 @@ public: /** Wait for the frame to end. */ virtual void waitEndFrame() = 0; - /** Notifies the video that it was paused for duration ms. */ - virtual void notifyPaused(uint32 duration) = 0; - /** Copy the current frame. * * @param dest The memory to which to copy the current frame. @@ -198,29 +199,26 @@ public: Imd(); ~Imd(); - uint32 getFeatures() const { return _features; } - uint16 getFlags() const { return _flags; } - int16 getX() const { return _x; } - int16 getY() const { return _y; } - int16 getWidth() const { return _width; } - int16 getHeight() const { return _height; } - uint16 getFramesCount() const { return _framesCount; } - uint16 getCurrentFrame() const { return _curFrame; } - int16 getFrameRate() const { - if (_hasSound) - return 1000 / (_soundSliceLength >> 16); - return _frameRate; - } - uint32 getSyncLag() const { return _skipFrames; } - const byte *getPalette() const { return _palette; } - - bool getAnchor(int16 frame, uint16 partType, - int16 &x, int16 &y, int16 &width, int16 &height) { return false; } - - bool hasExtraData(const char *fileName) const { return false; } - Common::MemoryReadStream *getExtraData(const char *fileName) { return 0; } - - void notifyPaused(uint32 duration) { } + uint32 getFeatures() const; + uint16 getFlags() const; + + int16 getX() const; + int16 getY() const; + int16 getWidth() const; + int16 getHeight() const; + + uint16 getFramesCount() const; + uint16 getCurrentFrame() const; + int16 getFrameRate() const; + uint32 getSyncLag() const; + + const byte *getPalette() const; + + bool getFrameCoords(int16 frame, + int16 &x, int16 &y, int16 &width, int16 &height); + + bool hasExtraData(const char *fileName) const; + Common::MemoryReadStream *getExtraData(const char *fileName); void setFrameRate(int16 frameRate); @@ -231,7 +229,7 @@ public: void setVideoMemory(byte *vidMem, uint16 width, uint16 height); void setVideoMemory(); - void setDoubleMode(bool doubleMode) { } + void setDoubleMode(bool doubleMode); void enableSound(Audio::Mixer &mixer); void disableSound(); @@ -248,6 +246,22 @@ public: uint16 x, uint16 y, uint16 pitch, int16 transp = -1); protected: + enum Command { + kCommandNextSound = 0xFF00, + kCommandStartSound = 0xFF01, + + kCommandBreak = 0xFFF0, + kCommandBreakSkip0 = 0xFFF1, + kCommandBreakSkip16 = 0xFFF2, + kCommandBreakSkip32 = 0xFFF3, + kCommandBreakMask = 0xFFF8, + + kCommandPalette = 0xFFF4, + kCommandVideoData = 0xFFFC, + + kCommandJump = 0xFFFD + }; + struct Coord { int16 left; int16 top; @@ -256,56 +270,104 @@ protected: } PACKED_STRUCT; Common::SeekableReadStream *_stream; + + // Properties uint16 _version; uint32 _features; uint16 _flags; - int16 _x, _y, _width, _height; - int16 _stdX, _stdY, _stdWidth, _stdHeight; - uint16 _framesCount, _curFrame; + + // Current coordinates + int16 _x; + int16 _y; + int16 _width; + int16 _height; + + // Standard coordinates gives by the header + int16 _stdX; + int16 _stdY; + int16 _stdWidth; + int16 _stdHeight; + + uint16 _framesCount; + uint16 _curFrame; + uint32 *_framesPos; - uint32 _firstFramePos; + uint32 _firstFramePos; Coord *_frameCoords; - uint32 _frameDataSize, _vidBufferSize; - byte *_frameData, *_vidBuffer; + // Buffer for raw frame data + byte *_frameData; + uint32 _frameDataSize; uint32 _frameDataLen; - byte _palette[768]; + // Buffer for uncompressed raw frame data + byte *_vidBuffer; + uint32 _vidBufferSize; - bool _hasOwnVidMem; - byte *_vidMem; - uint16 _vidMemWidth, _vidMemHeight; + byte _palette[768]; - bool _hasSound; - bool _soundEnabled; - uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing) - uint32 _skipFrames; + // Video memory + bool _hasOwnVidMem; + byte *_vidMem; + uint16 _vidMemWidth; + uint16 _vidMemHeight; + // Sound properties uint16 _soundFlags; - int16 _soundFreq; - int16 _soundSliceSize; - int16 _soundSlicesCount; + int16 _soundFreq; + int16 _soundSliceSize; + int16 _soundSlicesCount; uint32 _soundSliceLength; + // Current sound state + bool _hasSound; + bool _soundEnabled; + uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing) + uint32 _skipFrames; + Audio::AppendableAudioStream *_audioStream; Audio::SoundHandle _audioHandle; - int16 _frameRate; + // Current video state + int16 _frameRate; uint32 _frameLength; uint32 _lastFrameTime; Audio::Mixer *_mixer; - void unsignedToSigned(byte *buffer, int length) { - while (length-- > 0) *buffer++ ^= 0x80; - } + void unsignedToSigned(byte *buffer, int length); void deleteVidMem(bool del = true); void clear(bool del = true); + bool loadCoordinates(); + bool loadFrameTableOffsets(uint32 &framesPosPos, uint32 &framesCoordsPos); + bool assessVideoProperties(); + bool assessAudioProperties(); + bool loadFrameTables(uint32 framesPosPos, uint32 framesCoordsPos); + State processFrame(uint16 frame); uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom); void deLZ77(byte *dest, byte *src); + + void renderBlockWhole (byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight); + void renderBlockWhole4X (byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight); + void renderBlockWhole2Y (byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight); + void renderBlockSparse (byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight); + void renderBlockSparse2Y(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight); + + void calcFrameCoords(uint16 frame, State &state); + + void nextSoundSlice(bool hasNextCmd); + bool initialSoundSlice(bool hasNextCmd); + void emptySoundSlice(bool hasNextCmd); + + void videoData(uint32 size, State &state); }; class Vmd : public Imd { @@ -313,7 +375,7 @@ public: Vmd(Graphics::PaletteLUT *palLUT = 0); ~Vmd(); - bool getAnchor(int16 frame, uint16 partType, + bool getFrameCoords(int16 frame, int16 &x, int16 &y, int16 &width, int16 &height); bool hasExtraData(const char *fileName) const; @@ -335,38 +397,58 @@ public: protected: enum PartType { kPartTypeSeparator = 0, - kPartTypeAudio = 1, - kPartTypeVideo = 2, - kPartTypeExtraData = 3 + kPartTypeAudio = 1, + kPartTypeVideo = 2, + kPartTypeExtraData = 3, + kPartType4 = 4, + kPartTypeSpeech = 5 }; + + enum AudioFormat { + kAudioFormat8bitDirect = 0, + kAudioFormat16bitDPCM = 1, + kAudioFormat16bitADPCM = 2 + }; + struct ExtraData { - char name[16]; + char name[16]; uint32 offset; uint32 size; uint32 realSize; + + ExtraData(); } PACKED_STRUCT; + struct Part { PartType type; - byte field_1; - byte field_E; - uint32 size; - int16 left; - int16 top; - int16 right; - int16 bottom; - byte flags; + byte field_1; + byte field_E; + uint32 size; + int16 left; + int16 top; + int16 right; + int16 bottom; + uint16 id; + byte flags; + + Part(); } PACKED_STRUCT; + struct Frame { uint32 offset; - Part *parts; + Part *parts; - Frame() : parts(0) { } - ~Frame() { delete[] parts; } + Frame(); + ~Frame(); } PACKED_STRUCT; - static const uint16 _tableADPCM[128]; + // Tables for the audio decompressors + static const uint16 _tableDPCM[128]; + static const int32 _tableADPCM[]; + static const int32 _tableADPCMStep[]; - bool _hasVideo; + bool _hasVideo; + uint32 _videoCodec; uint32 _frameInfoOffset; uint16 _partsPerFrame; @@ -374,9 +456,14 @@ protected: Common::Array<ExtraData> _extraData; - byte _soundBytesPerSample; - byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo) + // Sound properties + byte _soundBytesPerSample; + byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo) + uint32 _soundHeaderSize; + uint32 _soundDataSize; + AudioFormat _audioFormat; + // Video properties bool _externalCodec; byte _blitMode; byte _bytesPerPixel; @@ -392,10 +479,21 @@ protected: void clear(bool del = true); + bool getPartCoords(int16 frame, PartType type, + int16 &x, int16 &y, int16 &width, int16 &height); + + bool assessVideoProperties(); + bool assessAudioProperties(); + void readFrameTable(int &numExtraData); + void readExtraData(); + State processFrame(uint16 frame); uint32 renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom); - void deRLE(byte *&srcPtr, byte *&destPtr, int16 len); + void renderBlockRLE(byte *dest, const byte *src, int16 width, int16 height, + int16 destWidth, int16 destHeight); + + void deRLE(byte *&destPtr, const byte *&srcPtr, int16 len); inline int32 preScaleX(int32 x) const; inline int32 postScaleX(int32 x) const; @@ -404,12 +502,18 @@ protected: void blit16(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height); void blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height); + byte *deDPCM(const byte *data, uint32 &size, int32 init[2]); + byte *deADPCM(const byte *data, uint32 &size, int32 init, int32 v28); + + byte *soundEmpty(uint32 &size); + byte *sound8bitDirect(uint32 &size); + byte *sound16bitDPCM(uint32 &size); + byte *sound16bitADPCM(uint32 &size); + + uint8 evaluateMask(uint32 mask, bool *fillInfo, uint8 &max); void emptySoundSlice(uint32 size); - void soundSlice8bit(uint32 size); - void soundSlice16bit(uint32 size, int16 &init); void filledSoundSlice(uint32 size); void filledSoundSlices(uint32 size, uint32 mask); - void deADPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n); }; } // End of namespace Graphics diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp index 9db8f0c730..8952f553b7 100644 --- a/graphics/video/smk_decoder.cpp +++ b/graphics/video/smk_decoder.cpp @@ -348,8 +348,8 @@ uint32 BigHuffmanTree::getCode(BitStream &bs) { return v; } -SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer) - : _audioStarted(false), _audioStream(0), _mixer(mixer) { +SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) + : _audioStarted(false), _audioStream(0), _mixer(mixer), _soundType(soundType) { } SmackerDecoder::~SmackerDecoder() { @@ -583,7 +583,7 @@ bool SmackerDecoder::decodeNextFrame() { } if (!_audioStarted) { - _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_audioHandle, _audioStream, -1, 255); + _mixer->playInputStream(_soundType, &_audioHandle, _audioStream, -1, 255); _audioStarted = true; } } else { diff --git a/graphics/video/smk_decoder.h b/graphics/video/smk_decoder.h index e70d0e6454..e28d85119d 100644 --- a/graphics/video/smk_decoder.h +++ b/graphics/video/smk_decoder.h @@ -55,7 +55,8 @@ class BigHuffmanTree; */ class SmackerDecoder : public VideoDecoder { public: - SmackerDecoder(Audio::Mixer *mixer); + SmackerDecoder(Audio::Mixer *mixer, + Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); virtual ~SmackerDecoder(); int getHeight(); @@ -113,6 +114,7 @@ private: // The RGB palette byte *_palette; + Audio::Mixer::SoundType _soundType; Audio::Mixer *_mixer; bool _audioStarted; Audio::AppendableAudioStream *_audioStream; diff --git a/gui/ListWidget.cpp b/gui/ListWidget.cpp index 3d4c10859f..7551acac48 100644 --- a/gui/ListWidget.cpp +++ b/gui/ListWidget.cpp @@ -24,6 +24,8 @@ #include "common/system.h" #include "common/events.h" +#include "common/frac.h" + #include "gui/ListWidget.h" #include "gui/ScrollBarWidget.h" #include "gui/dialog.h" @@ -538,13 +540,15 @@ void ListWidget::reflowLayout() { // of the list. // We do a rough rounding on the decimal places of Entries Per Page, // to add another entry even if it goes a tad over the padding. - _entriesPerPage = ((_h - _topPadding - _bottomPadding) << 16) / kLineHeight; + frac_t entriesPerPage = intToFrac(_h - _topPadding - _bottomPadding) / kLineHeight; - if ((uint)(_entriesPerPage & 0xFFFF) >= 0xF000) - _entriesPerPage += (1 << 16); + // Our threshold before we add another entry is 0.9375 (0xF000 with FRAC_BITS being 16). + const frac_t threshold = intToFrac(15) / 16; - _entriesPerPage >>= 16; + if ((frac_t)(entriesPerPage & FRAC_LO_MASK) >= threshold) + entriesPerPage += FRAC_ONE; + _entriesPerPage = fracToInt(entriesPerPage); assert(_entriesPerPage > 0); delete[] _textWidth; diff --git a/gui/ScrollBarWidget.cpp b/gui/ScrollBarWidget.cpp index 6e27535bfd..f6b36b3aa0 100644 --- a/gui/ScrollBarWidget.cpp +++ b/gui/ScrollBarWidget.cpp @@ -63,9 +63,9 @@ void ScrollBarWidget::handleMouseDown(int x, int y, int button, int clickCount) _currentPos++; _draggingPart = kDownArrowPart; } else if (y < _sliderPos) { - _currentPos -= _entriesPerPage; + _currentPos -= _entriesPerPage - 1; } else if (y >= _sliderPos + _sliderHeight) { - _currentPos += _entriesPerPage; + _currentPos += _entriesPerPage - 1; } else { _draggingPart = kSliderPart; _sliderDeltaMouseDownPos = y - _sliderPos; diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 75f42618a6..c2b6db7119 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -32,7 +32,7 @@ #include "graphics/surface.h" #include "graphics/fontman.h" -#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.5" +#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.6" namespace Graphics { struct DrawStep; diff --git a/gui/browser.cpp b/gui/browser.cpp index 48382e880b..f4719f4850 100644 --- a/gui/browser.cpp +++ b/gui/browser.cpp @@ -43,7 +43,7 @@ enum { */ BrowserDialog::BrowserDialog(const char *title, bool dirBrowser) - : Dialog("browser") { + : Dialog("Browser") { _titleRef = CFStringCreateWithCString(0, title, CFStringGetSystemEncoding()); _isDirBrowser = dirBrowser; } diff --git a/gui/credits.h b/gui/credits.h index 172d44603d..5ddae4ea37 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -16,6 +16,12 @@ static const char *credits[] = { "C1""Engine Teams", "C1""SCUMM", "C0""Torbj\366rn Andersson", +"C0""James Brown", +"C2""(retired)", +"C0""Jonathan Gray", +"C2""(retired)", +"C0""Vincent Hamm", +"C2""(retired)", "C0""Max Horn", "C0""Travis Howell", "C0""Pawel Kolodziejski", @@ -23,8 +29,12 @@ static const char *credits[] = { "C0""Gregory Montoir", "C0""Eugene Sandulenko", "C2""FT INSANE, MM NES, MM C64, game detection, Herc/CGA", +"C0""Ludvig Strigeus", +"C2""(retired)", "", "C1""HE", +"C0""Jonathan Gray", +"C2""(retired)", "C0""Travis Howell", "C0""Gregory Montoir", "C0""Eugene Sandulenko", @@ -37,44 +47,65 @@ static const char *credits[] = { "C0""Walter van Niftrik", "C0""Kari Salminen", "C0""Eugene Sandulenko", +"C0""David Symonds", +"C2""(retired)", "", "C1""AGOS", "C0""Torbj\366rn Andersson", "C0""Paul Gilbert", "C0""Travis Howell", +"C0""Oliver Kiehl", +"C2""(retired)", +"C0""Ludvig Strigeus", +"C2""(retired)", "", "C1""BASS", +"C0""Robert G\366ffringmann", +"C2""(retired)", +"C0""Oliver Kiehl", +"C2""(retired)", "C0""Joost Peters", "", "C1""Broken Sword 1", +"C0""Fabio Battaglia", +"C2""PSX version support", +"C0""Robert G\366ffringmann", +"C2""(retired)", "", "C1""Broken Sword 2", "C0""Torbj\366rn Andersson", +"C0""Fabio Battaglia", +"C2""PSX version support", +"C0""Jonathan Gray", +"C2""(retired)", "", "C1""Cinematique evo 1", "C0""Vincent Hamm", -"C2""original CinE engine author", +"C2""(retired)", "C0""Pawel Kolodziejski", "C0""Gregory Montoir", +"C0""Kari Salminen", "C0""Eugene Sandulenko", "", "C1""Cinematique evo 2", -"C0""Vincent Hamm", -"C2""original CruisE engine author", "C0""Paul Gilbert", +"C0""Vincent Hamm", +"C2""(retired)", "", "C1""Drascula", "C0""Filippos Karapetis", "C0""Pawel Kolodziejski", "", "C1""FOTAQ", +"C0""David Eriksson", +"C2""(retired)", "C0""Gregory Montoir", "C0""Joost Peters", "", "C1""Gob", "C0""Torbj\366rn Andersson", +"C0""Arnaud Boutonn\351", "C0""Sven Hesse", -"C0""Willem Jan Palenstijn", "C0""Eugene Sandulenko", "", "C1""Groovie", @@ -108,7 +139,6 @@ static const char *credits[] = { "", "C1""SAGA", "C0""Torbj\366rn Andersson", -"C0""Sven Hesse", "C0""Filippos Karapetis", "C0""Andrew Kurushin", "C0""Eugene Sandulenko", @@ -119,11 +149,14 @@ static const char *credits[] = { "C0""Max Horn", "C0""Filippos Karapetis", "C0""Walter van Niftrik", +"C0""Willem Jan Palenstijn", "C0""Jordi Vilalta Prat", "C0""Lars Skovlund", "", "C1""Tinsel", "C0""Torbj\366rn Andersson", +"C0""Fabio Battaglia", +"C2""PSX version support", "C0""Paul Gilbert", "C0""Sven Hesse", "C0""Max Horn", @@ -157,9 +190,13 @@ static const char *credits[] = { "C0""Chris Apers", "", "C1""PocketPC / WinCE", +"C0""Nicolas Bacca", +"C2""(retired)", "C0""Kostas Nakos", "", "C1""PlayStation 2", +"C0""Robert G\366ffringmann", +"C2""(retired)", "C0""Max Lingua", "", "C1""PSP (PlayStation Portable)", @@ -185,22 +222,28 @@ static const char *credits[] = { "C0""Eugene Sandulenko", "", "C1""GUI", +"C0""Vicent Marti", "C0""Eugene Sandulenko", "C0""Johannes Schickel", "", "C1""Miscellaneous", "C0""David Corrales-Lopez", -"C2""Filesystem access improvements (GSoC 2007 task)", +"C2""Filesystem access improvements (GSoC 2007 task) (retired)", "C0""Jerome Fisher", -"C2""MT-32 emulator", +"C2""MT-32 emulator (retired)", +"C0""Benjamin Haisch", +"C2""Heavily improved de-/encoder for DXA videos", "C0""Jochen Hoenicke", -"C2""Speaker & PCjr sound support, AdLib work", +"C2""Speaker & PCjr sound support, AdLib work (retired)", "C0""Chris Page", -"C2""Return to launcher, savestate improvements, leak fixes, ... (GSoC 2008 task)", +"C2""Return to launcher, savestate improvements, leak fixes, ... (GSoC 2008 task) (retired)", "C0""Robin Watts", "C2""ARM assembly routines for nice speedups on several ports; improvements to the sound mixer", "", "", +"C1""Website (code)", +"C0""Fredrik Wendel", +"", "C1""Website (content)", "C0""All active team members", "C0""", @@ -211,126 +254,34 @@ static const char *credits[] = { "C0""Matthew Hoops", "C2""Wiki editor", "", -"C1""FreeSCI Contributors", -"C0""Anders Baden Nielsen", -"C2""PPC testing", -"C0""Bas Zoetekouw", -"C2""Man pages, debian package management, CVS maintenance", -"C0""Carl Muckenhoupt", -"C2""Sources to the SCI resource viewer tools that started it all", -"C0""Chris Kehler", -"C2""Makefile enhancements", -"C0""Christoph Reichenbach", -"C2""UN*X code, VM/Graphics/Sound/other infrastructure", -"C0""Christopher T. Lansdown", -"C2""Original CVS maintainer, Alpha compatibility fixes", -"C0""Claudio Matsuoka", -"C2""CVS snapshots, daily builds, BeOS and cygwin ports", -"C0""Dark Minister", -"C2""SCI research (bytecode and parser)", -"C0""Dmitry Jemerov", -"C2""Port to the Win32 platform, numerous bugfixes", -"C0""Emmanuel Jeandel", -"C2""Bugfixes and bug reports", -"C0""Francois-R Boyer", -"C2""MT-32 information and mapping code", -"C0""George Reid", -"C2""FreeBSD package management", -"C0""Hubert Maier", -"C2""AmigaOS 4 port", -"C0""Hugues Valois", -"C2""Game selection menu", -"C0""Johannes Manhave", -"C2""Document format translation", -"C0""Jordi Vilalta", -"C2""Numerous code and website clean-up patches", -"C0""Lars Skovlund", -"C2""Project maintenance, most documentation, bugfixes, SCI1 support", -"C0""Magnus Reftel", -"C2""Heap implementation, Python class viewer, bugfixes", -"C0""Matt Hargett", -"C2""Clean-ups, bugfixes, Hardcore QA, Win32", -"C0""Max Horn", -"C2""SetJump implementation", -"C0""Paul David Doherty", -"C2""Game version information", -"C0""Petr Vyhnak", -"C2""The DCL-INFLATE algorithm, many Win32 improvements", -"C0""Rainer Canavan", -"C2""IRIX MIDI driver and bug fixes", -"C0""Rainer De Temple", -"C2""SCI research", -"C0""Ravi I.", -"C2""SCI0 sound resource specification", -"C0""Ruediger Hanke", -"C2""Port to the MorphOS platform", -"C0""Rune Orsval", -"C2""Configuration file editor", -"C0""Rickard Lind", -"C2""MT32->GM MIDI mapping magic, sound research", -"C0""Rink Springer", -"C2""Port to the DOS platform, several bug fixes", -"C0""Robey Pointer", -"C2""Bug tracking system hosting", -"C0""Sergey Lapin", -"C2""Port of Carl's type 2 decompression code", -"C0""Solomon Peachy", -"C2""SDL ports and much of the sound subsystem", -"C0""Vyacheslav Dikonov", -"C2""Config script improvements", -"C0""Walter van Niftrik", -"C2""Ports to the Dreamcast and GP32 platforms", -"C0""Xiaojun Chen", -"C0""Sean Terrell", -"C0""Special thanks to Prof. Dr. Gary Nutt for allowing the FreeSCI VM extension as a course project in his Advanced OS course", -"C0""", -"C0""Special thanks to Bob Heitman and Corey Cole for their support of FreeSCI", -"C0""", -"", "C1""Retired Team Members", -"C0""Tore Anderson", -"C2""Former Debian GNU/Linux maintainer", -"C0""Nicolas Bacca", -"C2""Former WinCE porter", "C0""Ralph Brorsen", "C2""Help with GUI implementation", "C0""Jamieson Christian", "C2""iMUSE, MIDI, all things musical", -"C0""David Eriksson", -"C2""Engines: FOTAQ", -"C0""Hans-J\366rg Frieden", -"C2""Former AmigaOS 4 packager", -"C0""Robert G\366ffringmann", -"C2""Original PS2 porter; Engines: BASS, BS1", -"C0""Jonathan Gray", -"C2""Engines: SCUMM, HE, BS2", -"C0""R\374diger Hanke", -"C2""Port: MorphOS", "C0""Felix Jakschitsch", "C2""Zak256 reverse engineering", -"C0""Oliver Kiehl", -"C2""Engines: AGOS, BASS", "C0""Mutwin Kraus", "C2""Original MacOS porter", "C0""Peter Moraliyski", "C2""Port: GP32", -"C0""Juha Niemim\344ki", -"C2""Former AmigaOS 4 packager", "C0""Jeremy Newman", "C2""Former webmaster", "C0""Lionel Ulmer", "C2""Port: X11", "C0""Won Star", "C2""Former GP32 porter", -"C0""David Symonds", -"C2""Engines: AGI", "", "", "C1""Other contributions", "", "C1""Packages", "C1""AmigaOS 4", +"C0""Hans-J\366rg Frieden", +"C2""(retired)", "C0""Hubert Maier", +"C0""Juha Niemim\344ki", +"C2""(retired)", "", "C1""Atari/FreeMiNT", "C0""Keith Scroggins", @@ -340,6 +291,8 @@ static const char *credits[] = { "C0""Luc Schrijvers", "", "C1""Debian GNU/Linux", +"C0""Tore Anderson", +"C2""(retired)", "C0""David Weinehall", "", "C1""Fedora / RedHat", @@ -354,6 +307,8 @@ static const char *credits[] = { "", "C1""MorphOS", "C0""Fabien Coeurjoly", +"C0""R\374diger Hanke", +"C2""(retired)", "", "C1""OS/2", "C0""Paul Smedley", @@ -399,8 +354,6 @@ static const char *credits[] = { "C2""CinE engine objectification", "C0""Thomas Fach-Pedersen", "C2""ProTracker module player", -"C0""Benjamin Haisch", -"C2""Heavily improved de-/encoder for DXA videos", "C0""Janne Huttunen", "C2""V3 actor mask support, Dig/FT SMUSH audio", "C0""Kov\341cs Endre J\341nos", @@ -425,6 +378,8 @@ static const char *credits[] = { "C2""Initial MI1 CD music support", "C0""Quietust", "C2""Sound support for Amiga SCUMM V2/V3 games, MM NES support", +"C0""segra", +"C2""Improved support for Apple II/C64 versions of MM", "C0""Andreas R\366ver", "C2""Broken Sword 1/2 MPEG2 cutscene support", "C0""Edward Rudd", @@ -434,6 +389,82 @@ static const char *credits[] = { "C0""Andr\351 Souza", "C2""SDL-based OpenGL renderer", "", +"C1""FreeSCI Contributors", +"C0""Anders Baden Nielsen", +"C2""PPC testing", +"C0""Bas Zoetekouw", +"C2""Man pages, debian package management, CVS maintenance", +"C0""Carl Muckenhoupt", +"C2""Sources to the SCI resource viewer tools that started it all", +"C0""Chris Kehler", +"C2""Makefile enhancements", +"C0""Christoph Reichenbach", +"C2""UN*X code, VM/Graphics/Sound/other infrastructure", +"C0""Christopher T. Lansdown", +"C2""Original CVS maintainer, Alpha compatibility fixes", +"C0""Claudio Matsuoka", +"C2""CVS snapshots, daily builds, BeOS and cygwin ports", +"C0""Dark Minister", +"C2""SCI research (bytecode and parser)", +"C0""Dmitry Jemerov", +"C2""Port to the Win32 platform, numerous bugfixes", +"C0""Emmanuel Jeandel", +"C2""Bugfixes and bug reports", +"C0""Francois-R Boyer", +"C2""MT-32 information and mapping code", +"C0""George Reid", +"C2""FreeBSD package management", +"C0""Hubert Maier", +"C2""AmigaOS 4 port", +"C0""Hugues Valois", +"C2""Game selection menu", +"C0""Johannes Manhave", +"C2""Document format translation", +"C0""Jordi Vilalta", +"C2""Numerous code and website clean-up patches", +"C0""Lars Skovlund", +"C2""Project maintenance, most documentation, bugfixes, SCI1 support", +"C0""Magnus Reftel", +"C2""Heap implementation, Python class viewer, bugfixes", +"C0""Matt Hargett", +"C2""Clean-ups, bugfixes, Hardcore QA, Win32", +"C0""Max Horn", +"C2""SetJump implementation", +"C0""Paul David Doherty", +"C2""Game version information", +"C0""Petr Vyhnak", +"C2""The DCL-INFLATE algorithm, many Win32 improvements", +"C0""Rainer Canavan", +"C2""IRIX MIDI driver and bug fixes", +"C0""Rainer De Temple", +"C2""SCI research", +"C0""Ravi I.", +"C2""SCI0 sound resource specification", +"C0""Ruediger Hanke", +"C2""Port to the MorphOS platform", +"C0""Rune Orsval", +"C2""Configuration file editor", +"C0""Rickard Lind", +"C2""MT32->GM MIDI mapping magic, sound research", +"C0""Rink Springer", +"C2""Port to the DOS platform, several bug fixes", +"C0""Robey Pointer", +"C2""Bug tracking system hosting", +"C0""Sergey Lapin", +"C2""Port of Carl's type 2 decompression code", +"C0""Solomon Peachy", +"C2""SDL ports and much of the sound subsystem", +"C0""Vyacheslav Dikonov", +"C2""Config script improvements", +"C0""Walter van Niftrik", +"C2""Ports to the Dreamcast and GP32 platforms", +"C0""Xiaojun Chen", +"C0""Sean Terrell", +"C0""Special thanks to Prof. Dr. Gary Nutt for allowing the FreeSCI VM extension as a course project in his Advanced OS course.", +"C0""", +"C0""Special thanks to Bob Heitman and Corey Cole for their support of FreeSCI.", +"C0""", +"", "C0""And to all the contributors, users, and beta testers we've missed. Thanks!", "C0""", "", diff --git a/gui/debugger.cpp b/gui/debugger.cpp index 181403484b..78ada04cd6 100644 --- a/gui/debugger.cpp +++ b/gui/debugger.cpp @@ -27,10 +27,14 @@ #include "common/system.h" #include "gui/debugger.h" -#if USE_CONSOLE +#ifndef USE_TEXT_CONSOLE #include "gui/console.h" +#elif defined(USE_READLINE) + #include <readline/readline.h> + #include <readline/history.h> #endif + namespace GUI { Debugger::Debugger() { @@ -39,9 +43,11 @@ Debugger::Debugger() { _isAttached = false; _errStr = NULL; _firstTime = true; +#ifndef USE_TEXT_CONSOLE _debuggerDialog = new GUI::ConsoleDialog(1.0f, 0.67f); _debuggerDialog->setInputCallback(debuggerInputCallback, this); _debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this); +#endif //DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); DCmd_Register("exit", WRAP_METHOD(Debugger, Cmd_Exit)); @@ -55,7 +61,9 @@ Debugger::Debugger() { } Debugger::~Debugger() { +#ifndef USE_TEXT_CONSOLE delete _debuggerDialog; +#endif } @@ -65,7 +73,7 @@ int Debugger::DebugPrintf(const char *format, ...) { va_start(argptr, format); int count; -#if USE_CONSOLE +#ifndef USE_TEXT_CONSOLE count = _debuggerDialog->vprintf(format, argptr); #else count = ::vprintf(format, argptr); @@ -112,9 +120,22 @@ void Debugger::onFrame() { } } +#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE) +namespace { +Debugger *g_readline_debugger; + +char *readline_completionFunction(const char *text, int state) { + return g_readline_debugger->readlineComplete(text, state); +} +} // end of anonymous namespace +#endif + // Main Debugger Loop void Debugger::enter() { -#if USE_CONSOLE + // TODO: Having three I/O methods #ifdef-ed in this file is not the + // cleanest approach to this... + +#ifndef USE_TEXT_CONSOLE if (_firstTime) { DebugPrintf("Debugger started, type 'exit' to return to the game.\n"); DebugPrintf("Type 'help' to see a little list of commands and variables.\n"); @@ -129,18 +150,28 @@ void Debugger::enter() { _debuggerDialog->runModal(); #else - // TODO: compared to the console input, this here is very bare bone. - // For example, no support for tab completion and no history. At least - // we should re-add (optional) support for the readline library. - // Or maybe instead of choosing between a console dialog and stdio, - // we should move that choice into the ConsoleDialog class - that is, - // the console dialog code could be #ifdef'ed to not print to the dialog - // but rather to stdio. This way, we could also reuse the command history - // and tab completion of the console. It would still require a lot of - // work, but at least no dependency on a 3rd party library... - printf("Debugger entered, please switch to this console for input.\n"); +#ifdef USE_READLINE + // TODO: add support for saving/loading history? + + g_readline_debugger = this; + rl_completion_entry_function = &readline_completionFunction; + + char *line_read = 0; + do { + free(line_read); + line_read = readline("debug> "); + + if (line_read && line_read[0]) + add_history(line_read); + + } while (line_read && parseCommand(line_read)); + + free(line_read); + line_read = 0; + +#else int i; char buf[256]; @@ -156,6 +187,7 @@ void Debugger::enter() { if (i == 0) continue; } while (parseCommand(buf)); +#endif #endif } @@ -307,7 +339,8 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const } else { // take common prefix of previous match and this command for (uint j = 0; j < completion.size(); j++) { - if (completion[j] != i->_key[inputlen + j]) { + if (inputlen + j >= i->_key.size() || + completion[j] != i->_key[inputlen + j]) { completion = Common::String(completion.begin(), completion.begin() + j); // If there is no unambiguous completion, abort if (completion.empty()) @@ -325,6 +358,29 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const return true; } +#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE) +char *Debugger::readlineComplete(const char *input, int state) { + static CommandsMap::const_iterator iter; + + // We assume that _cmds isn't changed between calls to readlineComplete, + // unless state is 0. + if (state == 0) { + iter = _cmds.begin(); + } else { + ++iter; + } + + for (; iter != _cmds.end(); ++iter) { + if (iter->_key.hasPrefix(input)) { + char *ret = (char *)malloc(iter->_key.size() + 1); + strcpy(ret, iter->_key.c_str()); + return ret; + } + } + return 0; +} +#endif + // Variable registration function void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) { // TODO: Filter out duplicates @@ -356,8 +412,15 @@ bool Debugger::Cmd_Exit(int argc, const char **argv) { // Print a list of all registered commands (and variables, if any), // nicely word-wrapped. bool Debugger::Cmd_Help(int argc, const char **argv) { - +#ifndef USE_TEXT_CONSOLE const int charsPerLine = _debuggerDialog->getCharsPerLine(); +#elif defined(USE_READLINE) + int charsPerLine, rows; + rl_get_screen_size(&rows, &charsPerLine); +#else + // Can we do better? + const int charsPerLine = 80; +#endif int width, size; uint i; @@ -452,7 +515,7 @@ bool Debugger::Cmd_DebugFlagDisable(int argc, const char **argv) { } // Console handler -#if USE_CONSOLE +#ifndef USE_TEXT_CONSOLE bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) { Debugger *debugger = (Debugger *)refCon; diff --git a/gui/debugger.h b/gui/debugger.h index e84da594be..07fdddb808 100644 --- a/gui/debugger.h +++ b/gui/debugger.h @@ -32,10 +32,7 @@ namespace GUI { -// Choose between text console or ScummConsole -#define USE_CONSOLE 1 - -#ifdef USE_CONSOLE +#ifndef USE_TEXT_CONSOLE class ConsoleDialog; #endif @@ -86,7 +83,9 @@ private: bool _isAttached; char *_errStr; bool _firstTime; +#ifndef USE_TEXT_CONSOLE GUI::ConsoleDialog *_debuggerDialog; +#endif protected: // Hook for subclasses: Called just before enter() is run @@ -118,11 +117,15 @@ protected: bool Cmd_DebugFlagEnable(int argc, const char **argv); bool Cmd_DebugFlagDisable(int argc, const char **argv); -#if USE_CONSOLE +#ifndef USE_TEXT_CONSOLE private: static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon); static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon); +#elif defined(USE_READLINE) +public: + char *readlineComplete(const char *input, int state); #endif + }; } // End of namespace GUI diff --git a/gui/options.cpp b/gui/options.cpp index 5991a204e9..e941cd6244 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -48,6 +48,7 @@ enum { kMidiGainChanged = 'mgch', kMusicVolumeChanged = 'muvc', kSfxVolumeChanged = 'sfvc', + kMuteAllChanged = 'mute', kSubtitleToggle = 'sttg', kSubtitleSpeedChanged = 'stsc', kSpeechVolumeChanged = 'vcvc', @@ -68,8 +69,8 @@ enum { static const char *savePeriodLabels[] = { "Never", "every 5 mins", "every 10 mins", "every 15 mins", "every 30 mins", 0 }; static const int savePeriodValues[] = { 0, 5 * 60, 10 * 60, 15 * 60, 30 * 60, -1 }; -static const char *outputRateLabels[] = { "<default>", "22 kHz", "8 kHz", "11kHz", "44 kHz", "48 kHz", 0 }; -static const int outputRateValues[] = { 0, 22050, 8000, 11025, 44100, 48000, -1 }; +static const char *outputRateLabels[] = { "<default>", "8 kHz", "11kHz", "22 kHz", "44 kHz", "48 kHz", 0 }; +static const int outputRateValues[] = { 0, 8000, 11025, 22050, 44100, 48000, -1 }; @@ -454,6 +455,10 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data _speechVolumeLabel->setValue(_speechVolumeSlider->getValue()); _speechVolumeLabel->draw(); break; + case kMuteAllChanged: + // 'true' because if control is disabled then event do not pass + setVolumeSettingsState(true); + break; case kSubtitleToggle: if (_subMode < 2) _subMode++; @@ -535,7 +540,7 @@ void OptionsDialog::setVolumeSettingsState(bool enabled) { _enableVolumeSettings = enabled; - ena = enabled; + ena = enabled && !_muteCheckbox->getState(); if (_guioptions & Common::GUIO_NOMUSIC) ena = false; @@ -543,7 +548,7 @@ void OptionsDialog::setVolumeSettingsState(bool enabled) { _musicVolumeSlider->setEnabled(ena); _musicVolumeLabel->setEnabled(ena); - ena = enabled; + ena = enabled && !_muteCheckbox->getState(); if (_guioptions & Common::GUIO_NOSFX) ena = false; @@ -551,7 +556,7 @@ void OptionsDialog::setVolumeSettingsState(bool enabled) { _sfxVolumeSlider->setEnabled(ena); _sfxVolumeLabel->setEnabled(ena); - ena = enabled; + ena = enabled && !_muteCheckbox->getState(); if (_guioptions & Common::GUIO_NOSPEECH) ena = false; @@ -701,7 +706,7 @@ void OptionsDialog::addVolumeControls(GuiObject *boss, const String &prefix) { _musicVolumeSlider->setMaxValue(Audio::Mixer::kMaxMixerVolume); _musicVolumeLabel->setFlags(WIDGET_CLEARBG); - _muteCheckbox = new CheckboxWidget(boss, prefix + "vcMuteCheckbox", "Mute All", 0, 0); + _muteCheckbox = new CheckboxWidget(boss, prefix + "vcMuteCheckbox", "Mute All", kMuteAllChanged, 0); _sfxVolumeDesc = new StaticTextWidget(boss, prefix + "vcSfxText", "SFX volume:"); diff --git a/gui/themes/default.inc b/gui/themes/default.inc index 0331c90fbb..64fb0e517a 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -1,5 +1,5 @@ "<?xml version = '1.0'?>" -"<layout_info resolution='-320xY,-256x240'> " +"<layout_info resolution='-320xY,-256x240,-Xx272'> " "<globals> " "<def var='Line.Height' value='16' /> " "<def var='Font.Height' value='16' /> " @@ -1492,7 +1492,7 @@ "</layout> " "</dialog> " "<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> " "<widget name='EnableTabCheckbox' " "type='Checkbox' " "/> " @@ -1500,7 +1500,7 @@ "</layout> " "</dialog> " "<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> " "<widget name='EnableTabCheckbox' " "type='Checkbox' " "/> " @@ -1508,7 +1508,7 @@ "</layout> " "</dialog> " "<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> " "<widget name='EnableTabCheckbox' " "type='Checkbox' " "/> " @@ -1516,7 +1516,7 @@ "</layout> " "</dialog> " "<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> " "<widget name='EnableTabCheckbox' " "type='Checkbox' " "/> " @@ -1524,7 +1524,7 @@ "</layout> " "</dialog> " "<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " +"<layout type='vertical' padding='8,8,8,8'> " "<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " "<widget name='Id' " "width='35' " @@ -1569,7 +1569,7 @@ "</layout> " "</dialog> " "<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " +"<layout type='vertical' padding='8,8,8,8'> " "<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " "<widget name='Savepath' " "type='Button' " diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differindex ce21ea5487..0e1d8c539d 100644 --- a/gui/themes/scummclassic.zip +++ b/gui/themes/scummclassic.zip diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC index 0593de00d4..4dc5cc5982 100644 --- a/gui/themes/scummclassic/THEMERC +++ b/gui/themes/scummclassic/THEMERC @@ -1 +1 @@ -[SCUMMVM_STX0.5:ScummVM Classic Theme:No Author] +[SCUMMVM_STX0.6:ScummVM Classic Theme:No Author] diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx index e886a1a2f0..029c7479ac 100644 --- a/gui/themes/scummclassic/classic_layout.stx +++ b/gui/themes/scummclassic/classic_layout.stx @@ -23,7 +23,7 @@ - $Id$ - --> -<layout_info resolution = '-320xY, -256x240'> +<layout_info resolution = '-320xY, -256x240, -Xx272'> <globals> <def var = 'Line.Height' value = '16' /> <def var = 'Font.Height' value = '16' /> diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index b4143964af..da56f0178a 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -454,7 +454,7 @@ </dialog> <dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -463,7 +463,7 @@ </dialog> <dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -472,7 +472,7 @@ </dialog> <dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -481,7 +481,7 @@ </dialog> <dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -490,7 +490,7 @@ </dialog> <dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> - <layout type = 'vertical' padding = '16, 16, 16, 16'> + <layout type = 'vertical' padding = '8, 8, 8, 8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'> <widget name = 'Id' width = '35' @@ -536,7 +536,7 @@ </dialog> <dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> - <layout type = 'vertical' padding = '16, 16, 16, 16'> + <layout type = 'vertical' padding = '8, 8, 8, 8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> <widget name = 'Savepath' type = 'Button' diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip Binary files differindex b38ee79e84..fb3a0b1c2d 100644 --- a/gui/themes/scummmodern.zip +++ b/gui/themes/scummmodern.zip diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC index 32b51c573d..3fbbdf8d46 100644 --- a/gui/themes/scummmodern/THEMERC +++ b/gui/themes/scummmodern/THEMERC @@ -1 +1 @@ -[SCUMMVM_STX0.5:ScummVM Modern Theme:No Author] +[SCUMMVM_STX0.6:ScummVM Modern Theme:No Author] diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx index 8c13217c65..e6a01d12a1 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -23,7 +23,7 @@ - $Id$ - --> -<layout_info resolution = '-320xY, -256x240'> +<layout_info resolution = '-320xY, -256x240, -Xx272'> <globals> <def var = 'Line.Height' value = '16' /> <def var = 'Font.Height' value = '16' /> diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index 693efaaca9..c514ccc458 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -450,7 +450,7 @@ </dialog> <dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -459,7 +459,7 @@ </dialog> <dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -468,7 +468,7 @@ </dialog> <dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -477,7 +477,7 @@ </dialog> <dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'> - <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'> <widget name = 'EnableTabCheckbox' type = 'Checkbox' /> @@ -486,7 +486,7 @@ </dialog> <dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> - <layout type = 'vertical' padding = '16, 16, 16, 16'> + <layout type = 'vertical' padding = '8, 8, 8, 8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'> <widget name = 'Id' width = '35' @@ -532,7 +532,7 @@ </dialog> <dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> - <layout type = 'vertical' padding = '16, 16, 16, 16'> + <layout type = 'vertical' padding = '8, 8, 8, 8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> <widget name = 'Savepath' type = 'Button' @@ -42,7 +42,7 @@ deb: # Special target to create a application wrapper for Mac OS X bundle_name = ScummVM.app -bundle: scummvm-static $(srcdir)/dists/macosx/Info.plist +bundle: scummvm-static mkdir -p $(bundle_name)/Contents/MacOS mkdir -p $(bundle_name)/Contents/Resources echo "APPL????" > $(bundle_name)/Contents/PkgInfo @@ -57,7 +57,7 @@ bundle: scummvm-static $(srcdir)/dists/macosx/Info.plist chmod 755 $(bundle_name)/Contents/MacOS/scummvm $(STRIP) $(bundle_name)/Contents/MacOS/scummvm -iphonebundle: iphone $(srcdir)/dists/iphone/Info.plist +iphonebundle: iphone mkdir -p $(bundle_name) cp $(srcdir)/dists/iphone/Info.plist $(bundle_name)/ cp $(DIST_FILES_DOCS) $(bundle_name)/ @@ -205,3 +205,31 @@ endif $(CP) $(srcdir)/backends/vkeybd/packs/vkeybd_default.zip wiidist/scummvm/ .PHONY: deb bundle osxsnap win32dist wiidist install uninstall + +# +# ARM specific +# +ifdef USE_TREMOLO +DEFINES += -DUSE_TREMOR -DUSE_VORBIS -DUSE_TREMOLO +LIBS += -ltremolo +endif + +ifdef USE_ARM_SMUSH_ASM +DEFINES += -DUSE_ARM_SMUSH_ASM +endif + +ifdef USE_ARM_SOUND_ASM +DEFINES += -DUSE_ARM_SOUND_ASM +endif + +ifdef USE_ARM_GFX_ASM +DEFINES += -DUSE_ARM_GFX_ASM +endif + +ifdef USE_ARM_COSTUME_ASM +DEFINES += -DUSE_ARM_COSTUME_ASM +endif + +ifdef USE_ARM_SCALER_ASM +DEFINES += -DUSE_ARM_SCALER_ASM +endif diff --git a/sound/fmopl.h b/sound/fmopl.h index d0b15368e0..688da4f1ba 100644 --- a/sound/fmopl.h +++ b/sound/fmopl.h @@ -94,7 +94,7 @@ private: // TODO: This is part of a temporary HACK to allow only 1 instance static bool _hasInstance; public: - OPL() { _hasInstance = true; } + OPL() { assert(!_hasInstance); _hasInstance = true; } virtual ~OPL() { _hasInstance = false; } /** diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp index f7d5e9c32a..343ca34659 100644 --- a/sound/midiparser_xmidi.cpp +++ b/sound/midiparser_xmidi.cpp @@ -115,6 +115,8 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { byte *pos = _position._play_pos; if (_loopCount < ARRAYSIZE(_loop) - 1) _loopCount++; + else + warning("XMIDI: Exceeding maximum loop count %d", ARRAYSIZE(_loop)); _loop[_loopCount].pos = pos; _loop[_loopCount].repeat = info.basic.param2; @@ -127,11 +129,14 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { // End the current loop. _loopCount--; } else { - _position._play_pos = _loop[_loopCount].pos; // Repeat 0 means "loop forever". if (_loop[_loopCount].repeat) { if (--_loop[_loopCount].repeat == 0) _loopCount--; + else + _position._play_pos = _loop[_loopCount].pos; + } else { + _position._play_pos = _loop[_loopCount].pos; } } } @@ -155,7 +160,6 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { warning("Unsupported XMIDI controller %d (0x%2x)", info.basic.param1, info.basic.param1); } - break; } // Should we really keep passing the XMIDI controller events to diff --git a/sound/softsynth/mt32/partial.cpp b/sound/softsynth/mt32/partial.cpp index 871eff03d2..f016084d8c 100644 --- a/sound/softsynth/mt32/partial.cpp +++ b/sound/softsynth/mt32/partial.cpp @@ -36,7 +36,7 @@ // Hence we re-define them here. The only potential drawback is that it // might be a little bit slower this way. #define powf(x,y) ((float)pow(x,y)) -#define floorf(x) ((float)floorf(x)) +#define floorf(x) ((float)floor(x)) #define fabsf(x) ((float)fabs(x)) #endif diff --git a/sound/softsynth/mt32/synth.cpp b/sound/softsynth/mt32/synth.cpp index 547b2bb9b3..c8b7abdf67 100644 --- a/sound/softsynth/mt32/synth.cpp +++ b/sound/softsynth/mt32/synth.cpp @@ -36,7 +36,7 @@ // Hence we re-define them here. The only potential drawback is that it // might be a little bit slower this way. #define powf(x,y) ((float)pow(x,y)) -#define floorf(x) ((float)floorf(x)) +#define floorf(x) ((float)floor(x)) #define fabsf(x) ((float)fabs(x)) #endif diff --git a/sound/softsynth/mt32/tables.cpp b/sound/softsynth/mt32/tables.cpp index 16fc4f71e5..571750ee99 100644 --- a/sound/softsynth/mt32/tables.cpp +++ b/sound/softsynth/mt32/tables.cpp @@ -36,7 +36,7 @@ // Hence we re-define them here. The only potential drawback is that it // might be a little bit slower this way. #define powf(x,y) ((float)pow(x,y)) -#define floorf(x) ((float)floorf(x)) +#define floorf(x) ((float)floor(x)) #define fabsf(x) ((float)fabs(x)) #endif diff --git a/test/common/str.h b/test/common/str.h index bf0db98b09..f65b078bdc 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -285,4 +285,12 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT(!Common::matchString("monkey.s99", "monkey.s*1")); TS_ASSERT(Common::matchString("monkey.s101", "monkey.s*1")); } + + void test_string_printf() { + TS_ASSERT( Common::String::printf("") == "" ); + TS_ASSERT( Common::String::printf("%s", "test") == "test" ); + TS_ASSERT( Common::String::printf("%s.s%.02d", "monkey", 1) == "monkey.s01" ); + TS_ASSERT( Common::String::printf("%s%X", "test", 1234) == "test4D2" ); + TS_ASSERT( Common::String::printf("Some %s to make this string longer than the default built-in %s %d", "text", "capacity", 123456) == "Some text to make this string longer than the default built-in capacity 123456" ); + } }; diff --git a/tools/credits.pl b/tools/credits.pl index 3b297e961b..2b1b93e87b 100755 --- a/tools/credits.pl +++ b/tools/credits.pl @@ -475,14 +475,19 @@ begin_credits("Credits"); begin_section("Engine Teams"); begin_section("SCUMM"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); + add_person("James Brown", "ender", "(retired)"); + add_person("Jonathan Gray", "khalek", "(retired)"); + add_person("Vincent Hamm", "yaz0r", "(retired)"); add_person("Max Horn", "Fingolfin", ""); add_person("Travis Howell", "Kirben", ""); add_person("Paweł Kołodziejski", "aquadran", "Codecs, iMUSE, Smush, etc."); add_person("Gregory Montoir", "cyx", ""); add_person("Eugene Sandulenko", "sev", "FT INSANE, MM NES, MM C64, game detection, Herc/CGA"); + add_person("Ludvig Strigeus", "ludde", "(retired)"); end_section(); begin_section("HE"); + add_person("Jonathan Gray", "khalek", "(retired)"); add_person("Travis Howell", "Kirben", ""); add_person("Gregory Montoir", "cyx", ""); add_person("Eugene Sandulenko", "sev", ""); @@ -496,35 +501,45 @@ begin_credits("Credits"); add_person("Walter van Niftrik", "waltervn", ""); add_person("Kari Salminen", "Buddha^", ""); add_person("Eugene Sandulenko", "sev", ""); + add_person("David Symonds", "dsymonds", "(retired)"); end_section(); begin_section("AGOS"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); add_person("Paul Gilbert", "dreammaster", ""); add_person("Travis Howell", "Kirben", ""); + add_person("Oliver Kiehl", "olki", "(retired)"); + add_person("Ludvig Strigeus", "ludde", "(retired)"); end_section(); begin_section("BASS"); # Beneath a Steel Sky + add_person("Robert Göffringmann", "lavosspawn", "(retired)"); + add_person("Oliver Kiehl", "olki", "(retired)"); add_person("Joost Peters", "joostp", ""); end_section(); begin_section("Broken Sword 1"); + add_person("Fabio Battaglia", "Hkz", "PSX version support"); + add_person("Robert Göffringmann", "lavosspawn", "(retired)"); end_section(); begin_section("Broken Sword 2"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); + add_person("Fabio Battaglia", "Hkz", "PSX version support"); + add_person("Jonathan Gray", "khalek", "(retired)"); end_section(); begin_section("Cinematique evo 1"); - add_person("Vincent Hamm", "yazoo", "original CinE engine author"); + add_person("Vincent Hamm", "yaz0r", "(retired)"); add_person("Paweł Kołodziejski", "aquadran", ""); add_person("Gregory Montoir", "cyx", ""); + add_person("Kari Salminen", "Buddha^", ""); add_person("Eugene Sandulenko", "sev", ""); end_section(); begin_section("Cinematique evo 2"); - add_person("Vincent Hamm", "yazoo", "original CruisE engine author"); add_person("Paul Gilbert", "dreammaster", ""); + add_person("Vincent Hamm", "yaz0r", "(retired)"); end_section(); begin_section("Drascula"); @@ -533,14 +548,15 @@ begin_credits("Credits"); end_section(); begin_section("FOTAQ"); # Flight of the Amazon Queen + add_person("David Eriksson", "twogood", "(retired)"); add_person("Gregory Montoir", "cyx", ""); add_person("Joost Peters", "joostp", ""); end_section(); begin_section("Gob"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); + add_person("Arnaud Boutonné", "Strangerke", ""); add_person("Sven Hesse", "DrMcCoy", ""); - add_person("Willem Jan Palenstijn", "wjp", ""); add_person("Eugene Sandulenko", "sev", ""); end_section(); @@ -565,12 +581,12 @@ begin_credits("Credits"); begin_section("M4"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); add_person("Paul Gilbert", "dreammaster", ""); - add_person("Benjamin Haisch", "johndoe", ""); + add_person("Benjamin Haisch", "john_doe", ""); add_person("Filippos Karapetis", "[md5]", ""); end_section(); begin_section("MADE"); - add_person("Benjamin Haisch", "johndoe", ""); + add_person("Benjamin Haisch", "john_doe", ""); add_person("Filippos Karapetis", "[md5]", ""); end_section(); @@ -580,7 +596,6 @@ begin_credits("Credits"); begin_section("SAGA"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); - add_person("Sven Hesse", "DrMcCoy", ""); add_person("Filippos Karapetis", "[md5]", ""); add_person("Andrew Kurushin", "ajax16384", ""); add_person("Eugene Sandulenko", "sev", ""); @@ -592,12 +607,14 @@ begin_credits("Credits"); add_person("Max Horn", "Fingolfin", ""); add_person("Filippos Karapetis", "[md5]", ""); add_person("Walter van Niftrik", "waltervn", ""); + add_person("Willem Jan Palenstijn", "wjp", ""); add_person("Jordi Vilalta Prat", "jvprat", ""); add_person("Lars Skovlund", "lskovlun", ""); end_section(); begin_section("Tinsel"); add_person("Torbjörn Andersson", "eriktorbjorn", ""); + add_person("Fabio Battaglia", "Hkz", "PSX version support"); add_person("Paul Gilbert", "dreammaster", ""); add_person("Sven Hesse", "DrMcCoy", ""); add_person("Max Horn", "Fingolfin", ""); @@ -642,10 +659,12 @@ begin_credits("Credits"); end_section(); begin_section("PocketPC / WinCE"); + add_person("Nicolas Bacca", "arisme", "(retired)"); add_person("Kostas Nakos", "Jubanka", ""); end_section(); begin_section("PlayStation 2"); + add_person("Robert Göffringmann", "lavosspawn", "(retired)"); add_person("Max Lingua", "sunmax", ""); end_section(); @@ -676,95 +695,48 @@ begin_credits("Credits"); end_section(); begin_section("GUI"); + add_person("Vicent Marti", "tanoku", ""); add_person("Eugene Sandulenko", "sev", ""); add_person("Johannes Schickel", "LordHoto", ""); end_section(); begin_section("Miscellaneous"); - add_person("David Corrales-Lopez", "david_corrales", "Filesystem access improvements (GSoC 2007 task)"); - add_person("Jerome Fisher", "KingGuppy", "MT-32 emulator"); - add_person("Jochen Hoenicke", "hoenicke", "Speaker & PCjr sound support, AdLib work"); - add_person("Chris Page", "cp88", "Return to launcher, savestate improvements, leak fixes, ... (GSoC 2008 task)"); + add_person("David Corrales-Lopez", "david_corrales", "Filesystem access improvements (GSoC 2007 task) (retired)"); + add_person("Jerome Fisher", "KingGuppy", "MT-32 emulator (retired)"); + add_person("Benjamin Haisch", "john_doe", "Heavily improved de-/encoder for DXA videos"); + add_person("Jochen Hoenicke", "hoenicke", "Speaker & PCjr sound support, AdLib work (retired)"); + add_person("Chris Page", "cp88", "Return to launcher, savestate improvements, leak fixes, ... (GSoC 2008 task) (retired)"); add_person("Robin Watts", "robinwatts", "ARM assembly routines for nice speedups on several ports; improvements to the sound mixer"); end_section(); end_section(); + begin_section("Website (code)"); + begin_persons(); + add_person("Fredrik Wendel", "", ""); + end_persons(); + end_section(); + begin_section("Website (content)"); add_paragraph("All active team members"); end_section(); begin_section("Documentation"); - begin_persons(); + begin_persons(); add_person("Joachim Eberhard", "joachimeberhard", "Numerous contributions to documentation"); add_person("Matthew Hoops", "clone2727", "Wiki editor"); - end_persons(); - end_section(); - - begin_section("FreeSCI Contributors"); - begin_persons(); - add_person("Anders Baden Nielsen", "", "PPC testing"); - add_person("Bas Zoetekouw", "", "Man pages, debian package management, CVS maintenance"); - add_person("Carl Muckenhoupt", "", "Sources to the SCI resource viewer tools that started it all"); - add_person("Chris Kehler", "", "Makefile enhancements"); - add_person("Christoph Reichenbach", "", "UN*X code, VM/Graphics/Sound/other infrastructure"); - add_person("Christopher T. Lansdown", "", "Original CVS maintainer, Alpha compatibility fixes"); - add_person("Claudio Matsuoka", "", "CVS snapshots, daily builds, BeOS and cygwin ports"); - add_person("Dark Minister", "", "SCI research (bytecode and parser)"); - add_person("Dmitry Jemerov", "", "Port to the Win32 platform, numerous bugfixes"); - add_person("Emmanuel Jeandel", "", "Bugfixes and bug reports"); - add_person("Francois-R Boyer", "", "MT-32 information and mapping code"); - add_person("George Reid", "", "FreeBSD package management"); - add_person("Hubert Maier", "", "AmigaOS 4 port"); - add_person("Hugues Valois", "", "Game selection menu"); - add_person("Johannes Manhave", "", "Document format translation"); - add_person("Jordi Vilalta", "", "Numerous code and website clean-up patches"); - add_person("Lars Skovlund", "", "Project maintenance, most documentation, bugfixes, SCI1 support"); - add_person("Magnus Reftel", "", "Heap implementation, Python class viewer, bugfixes"); - add_person("Matt Hargett", "", "Clean-ups, bugfixes, Hardcore QA, Win32"); - add_person("Max Horn", "", "SetJump implementation"); - add_person("Paul David Doherty", "", "Game version information"); - add_person("Petr Vyhnak", "", "The DCL-INFLATE algorithm, many Win32 improvements"); - add_person("Rainer Canavan", "", "IRIX MIDI driver and bug fixes"); - add_person("Rainer De Temple", "", "SCI research"); - add_person("Ravi I.", "", "SCI0 sound resource specification"); - add_person("Ruediger Hanke", "", "Port to the MorphOS platform"); - add_person("Rune Orsval", "", "Configuration file editor"); - add_person("Rickard Lind", "", "MT32->GM MIDI mapping magic, sound research"); - add_person("Rink Springer", "", "Port to the DOS platform, several bug fixes"); - add_person("Robey Pointer", "", "Bug tracking system hosting"); - add_person("Sergey Lapin", "", "Port of Carl's type 2 decompression code"); - add_person("Solomon Peachy", "", "SDL ports and much of the sound subsystem"); - add_person("Vyacheslav Dikonov", "", "Config script improvements"); - add_person("Walter van Niftrik", "", "Ports to the Dreamcast and GP32 platforms"); - add_person("Xiaojun Chen", "", ""); - add_person("Sean Terrell", "", ""); - end_persons(); - add_paragraph("Special thanks to Prof. Dr. Gary Nutt ". - "for allowing the FreeSCI VM extension as a ". - "course project in his Advanced OS course"); - add_paragraph("Special thanks to Bob Heitman and Corey Cole for their support of FreeSCI"); + end_persons(); end_section(); begin_section("Retired Team Members"); begin_persons(); - add_person("Tore Anderson", "tore", "Former Debian GNU/Linux maintainer"); - add_person("Nicolas Bacca", "arisme", "Former WinCE porter"); - add_person("Ralph Brorsen", "painelf", "Help with GUI implementation"); - add_person("Jamieson Christian", "jamieson630", "iMUSE, MIDI, all things musical"); - add_person("David Eriksson", "twogood", "Engines: FOTAQ"); - add_person("Hans-Jörg Frieden", "", "Former AmigaOS 4 packager"); - add_person("Robert Göffringmann", "lavosspawn", "Original PS2 porter; Engines: BASS, BS1"); - add_person("Jonathan Gray", "khalek", "Engines: SCUMM, HE, BS2"); - add_person("Rüdiger Hanke", "", "Port: MorphOS"); - add_person("Felix Jakschitsch", "yot", "Zak256 reverse engineering"); - add_person("Oliver Kiehl", "olki", "Engines: AGOS, BASS"); - add_person("Mutwin Kraus", "mutle", "Original MacOS porter"); - add_person("Peter Moraliyski", "ph0x", "Port: GP32"); - add_person("Juha Niemimäki", "", "Former AmigaOS 4 packager"); - add_person("Jeremy Newman", "laxdragon", "Former webmaster"); - add_person("Lionel Ulmer", "bbrox", "Port: X11"); - add_person("Won Star", "wonst719", "Former GP32 porter"); - add_person("David Symonds", "dsymonds", "Engines: AGI"); + add_person("Ralph Brorsen", "painelf", "Help with GUI implementation"); + add_person("Jamieson Christian", "jamieson630", "iMUSE, MIDI, all things musical"); + add_person("Felix Jakschitsch", "yot", "Zak256 reverse engineering"); + add_person("Mutwin Kraus", "mutle", "Original MacOS porter"); + add_person("Peter Moraliyski", "ph0x", "Port: GP32"); + add_person("Jeremy Newman", "laxdragon", "Former webmaster"); + add_person("Lionel Ulmer", "bbrox", "Port: X11"); + add_person("Won Star", "wonst719", "Former GP32 porter"); end_persons(); end_section(); end_section(); @@ -774,7 +746,9 @@ begin_credits("Credits"); begin_section("Packages"); begin_section("AmigaOS 4"); + add_person("Hans-Jörg Frieden", "", "(retired)"); add_person("Hubert Maier", "Raziel_AOne", ""); + add_person("Juha Niemimäki", "", "(retired)"); end_section(); begin_section("Atari/FreeMiNT"); @@ -787,6 +761,7 @@ begin_credits("Credits"); end_section(); begin_section("Debian GNU/Linux"); + add_person("Tore Anderson", "tore", "(retired)"); add_person("David Weinehall", "tao", ""); end_section(); @@ -805,6 +780,7 @@ begin_credits("Credits"); begin_section("MorphOS"); add_person("Fabien Coeurjoly", "fab1", ""); + add_person("Rüdiger Hanke", "", "(retired)"); end_section(); begin_section("OS/2"); @@ -850,7 +826,6 @@ begin_credits("Credits"); add_person("Thierry Crozat", "criezy", "Support for Broken Sword 1 Macintosh version"); add_person("Martin Doucha", "next_ghost", "CinE engine objectification"); add_person("Thomas Fach-Pedersen", "madmoose", "ProTracker module player"); - add_person("Benjamin Haisch", "john_doe", "Heavily improved de-/encoder for DXA videos"); add_person("Janne Huttunen", "", "V3 actor mask support, Dig/FT SMUSH audio"); add_person("Kovács Endre János", "", "Several fixes for Simon1"); add_person("Jeroen Janssen", "japj", "Numerous readability and bugfix patches"); @@ -863,6 +838,7 @@ begin_credits("Credits"); add_person("Nicolas Noble", "pixels", "Config file and ALSA support"); add_person("Tim Phillips", "realmz", "Initial MI1 CD music support"); add_person("", "Quietust", "Sound support for Amiga SCUMM V2/V3 games, MM NES support"); + add_person("", "segra", "Improved support for Apple II/C64 versions of MM"); add_person("Andreas Röver", "", "Broken Sword 1/2 MPEG2 cutscene support"); add_person("Edward Rudd", "urkle", "Fixes for playing MP3 versions of MI1/Loom audio"); add_person("Daniel Schepler", "dschepler", "Final MI1 CD music support, initial Ogg Vorbis support"); @@ -870,6 +846,51 @@ begin_credits("Credits"); end_persons(); end_section(); + begin_section("FreeSCI Contributors"); + begin_persons(); + add_person("Anders Baden Nielsen", "", "PPC testing"); + add_person("Bas Zoetekouw", "", "Man pages, debian package management, CVS maintenance"); + add_person("Carl Muckenhoupt", "", "Sources to the SCI resource viewer tools that started it all"); + add_person("Chris Kehler", "", "Makefile enhancements"); + add_person("Christoph Reichenbach", "", "UN*X code, VM/Graphics/Sound/other infrastructure"); + add_person("Christopher T. Lansdown", "", "Original CVS maintainer, Alpha compatibility fixes"); + add_person("Claudio Matsuoka", "", "CVS snapshots, daily builds, BeOS and cygwin ports"); + add_person("Dark Minister", "", "SCI research (bytecode and parser)"); + add_person("Dmitry Jemerov", "", "Port to the Win32 platform, numerous bugfixes"); + add_person("Emmanuel Jeandel", "", "Bugfixes and bug reports"); + add_person("Francois-R Boyer", "", "MT-32 information and mapping code"); + add_person("George Reid", "", "FreeBSD package management"); + add_person("Hubert Maier", "", "AmigaOS 4 port"); + add_person("Hugues Valois", "", "Game selection menu"); + add_person("Johannes Manhave", "", "Document format translation"); + add_person("Jordi Vilalta", "", "Numerous code and website clean-up patches"); + add_person("Lars Skovlund", "", "Project maintenance, most documentation, bugfixes, SCI1 support"); + add_person("Magnus Reftel", "", "Heap implementation, Python class viewer, bugfixes"); + add_person("Matt Hargett", "", "Clean-ups, bugfixes, Hardcore QA, Win32"); + add_person("Max Horn", "", "SetJump implementation"); + add_person("Paul David Doherty", "", "Game version information"); + add_person("Petr Vyhnak", "", "The DCL-INFLATE algorithm, many Win32 improvements"); + add_person("Rainer Canavan", "", "IRIX MIDI driver and bug fixes"); + add_person("Rainer De Temple", "", "SCI research"); + add_person("Ravi I.", "", "SCI0 sound resource specification"); + add_person("Ruediger Hanke", "", "Port to the MorphOS platform"); + add_person("Rune Orsval", "", "Configuration file editor"); + add_person("Rickard Lind", "", "MT32->GM MIDI mapping magic, sound research"); + add_person("Rink Springer", "", "Port to the DOS platform, several bug fixes"); + add_person("Robey Pointer", "", "Bug tracking system hosting"); + add_person("Sergey Lapin", "", "Port of Carl's type 2 decompression code"); + add_person("Solomon Peachy", "", "SDL ports and much of the sound subsystem"); + add_person("Vyacheslav Dikonov", "", "Config script improvements"); + add_person("Walter van Niftrik", "", "Ports to the Dreamcast and GP32 platforms"); + add_person("Xiaojun Chen", "", ""); + add_person("Sean Terrell", "", ""); + end_persons(); + add_paragraph("Special thanks to Prof. Dr. Gary Nutt ". + "for allowing the FreeSCI VM extension as a ". + "course project in his Advanced OS course."); + add_paragraph("Special thanks to Bob Heitman and Corey Cole for their support of FreeSCI."); + end_section(); + add_paragraph("And to all the contributors, users, and beta testers we've missed. Thanks!"); end_section(); diff --git a/tools/module.mk b/tools/module.mk index f20273f7bc..9ad972f477 100644 --- a/tools/module.mk +++ b/tools/module.mk @@ -54,10 +54,10 @@ tools/make-scumm-fontdata$(EXEEXT): $(srcdir)/tools/make-scumm-fontdata.c credits: $(srcdir)/tools/credits.pl --text > AUTHORS - $(srcdir)/tools/credits.pl --rtf > Credits.rtf +# $(srcdir)/tools/credits.pl --rtf > Credits.rtf $(srcdir)/tools/credits.pl --cpp > gui/credits.h $(srcdir)/tools/credits.pl --xml-website > ../../web/trunk/data/credits.xml - $(srcdir)/tools/credits.pl --xml-docbook > ../../docs/trunk/docbook/credits.xml +# $(srcdir)/tools/credits.pl --xml-docbook > ../../docs/trunk/docbook/credits.xml md5scumm: tools/md5table$(EXEEXT) tools/md5table$(EXEEXT) --c++ < $(srcdir)/tools/scumm-md5.txt > engines/scumm/scumm-md5.h diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt index 56b1334b3e..2b937136ad 100644 --- a/tools/scumm-md5.txt +++ b/tools/scumm-md5.txt @@ -239,7 +239,7 @@ pass Passport to Adventure zak Misc FM-TOWNS demos 2d388339d6050d8ccaa757b64633954e 7520 en FM-TOWNS FM-TOWNS Demo indy/loom (non-interactive) khalek 77f5c9cc0986eb729c1a6b4c8823bbae 7520 en FM-TOWNS FM-TOWNS Demo zak/loom (non-interactive) khalek, Fingolfin - 3938ee1aa4433fca9d9308c9891172b1 -1 en FM-TOWNS FM-TOWNS Demo indy/zak (non-interactive) khalek + 3938ee1aa4433fca9d9308c9891172b1 7520 en FM-TOWNS FM-TOWNS Demo indy/zak (non-interactive) khalek monkey2 Monkey Island 2: LeChuck's Revenge 132bff65e6367c09cc69318ce1b59333 11155 en Amiga - - v1.0 4/8/92 Fingolfin @@ -262,79 +262,79 @@ monkey2 Monkey Island 2: LeChuck's Revenge 387a544b8b10b26912d8413bab63a853 -1 en DOS - Demo non-interactive khalek atlantis Indiana Jones and the Fate of Atlantis - 3a03dab514e4038df192d8a8de469788 -1 en Amiga - Floppy - dhewg - 20da6fce37805423966aaa8f3c2426aa -1 fr Amiga - Floppy - Joachim Eberhard - 4f267a901719623de7dde83e47d5b474 -1 de Amiga - Floppy - ghoostkilla - e534d29afb3c6e0ee9dc3d53c5956714 -1 de Amiga - Floppy alt? Tobias Fleischer - 5798972220cd458be2626d54c80f71d7 -1 it Amiga - Floppy - Andrea Petrucci - 15f588e887e857e8c56fe6ade4956168 -1 es Amiga - Floppy - VooD - c63ee46143ba65f9ce14cf539ca51bd7 -1 en DOS - Floppy - Andrea Petrucci - edfdb24a499d92c59f824c52987c0eec -1 fr DOS - Floppy - Nicolas Sauzède, Andrea Petrucci - 1fbebd7b2b692df5297870447a80cfed 12030 de DOS - Floppy - Fingolfin - 8f3758ff98c9c5d78e5d635222cad026 -1 it DOS - Floppy - Andrea Petrucci - 9bd2a8f72613e715c199246dd511e10f -1 es DOS - Floppy - abnog, Andrea Petrucci - 06b187468113f9ae5a400b148a847fac 12075 en Mac - Floppy six data files Lars N sbye Christensen - d6dd0646404768a63e963891a96daadd 12035 en Mac - Floppy two data files Fingolfin - - 182344899c2e2998fca0bebcd82aa81a 12035 en DOS CD CD - Fingolfin - 1a6e5ae2777a6a33f06ffc0226210934 -1 en Mac CD CD - Scott Summers - 2d9d46f23cb07bbc90b8ad464d3e4ff8 -1 en Mac CD CD Mac bundle Joachim Eberhard - 8e9417564f33790815445b2136efa667 11915 jp Mac CD CD - Petr Maruska - - c7be10f775404fd9785a8b92a06d240c -1 en FM-TOWNS CD - - dhewg, Andrea Petrucci - 4d34042713958b971cb139fba4658586 -1 jp FM-TOWNS CD - - Andrea Petrucci - - 035deab53b47bc43abc763560d0f8d4b -1 en DOS - Demo - - 98744fe66ff730e8c2b3b1f58803ab0b -1 en DOS - Demo - Simon Krumrein, sev - 99b6f822b0b2612415407865438697d6 -1 en DOS CD Demo non-interactive - 28d24a33448fab6795850bc9f159a4a2 11170 jp FM-TOWNS CD Demo non-interactive khalek, Fingolfin + 3a03dab514e4038df192d8a8de469788 -1 en Amiga Floppy Floppy - dhewg + 20da6fce37805423966aaa8f3c2426aa -1 fr Amiga Floppy Floppy - Joachim Eberhard + 4f267a901719623de7dde83e47d5b474 -1 de Amiga Floppy Floppy - ghoostkilla + e534d29afb3c6e0ee9dc3d53c5956714 -1 de Amiga Floppy Floppy alt? Tobias Fleischer + 5798972220cd458be2626d54c80f71d7 -1 it Amiga Floppy Floppy - Andrea Petrucci + 15f588e887e857e8c56fe6ade4956168 -1 es Amiga Floppy Floppy - VooD + c63ee46143ba65f9ce14cf539ca51bd7 -1 en DOS Floppy Floppy - Andrea Petrucci + edfdb24a499d92c59f824c52987c0eec -1 fr DOS Floppy Floppy - Nicolas Sauzède, Andrea Petrucci + 1fbebd7b2b692df5297870447a80cfed 12030 de DOS Floppy Floppy - Fingolfin + 8f3758ff98c9c5d78e5d635222cad026 -1 it DOS Floppy Floppy - Andrea Petrucci + 9bd2a8f72613e715c199246dd511e10f -1 es DOS Floppy Floppy - abnog, Andrea Petrucci + 06b187468113f9ae5a400b148a847fac 12075 en Mac Floppy Floppy six data files Lars N sbye Christensen + d6dd0646404768a63e963891a96daadd 12035 en Mac Floppy Floppy two data files Fingolfin + + 182344899c2e2998fca0bebcd82aa81a 12035 en DOS - CD - Fingolfin + 1a6e5ae2777a6a33f06ffc0226210934 -1 en Mac - CD - Scott Summers + 2d9d46f23cb07bbc90b8ad464d3e4ff8 -1 en Mac - CD Mac bundle Joachim Eberhard + 8e9417564f33790815445b2136efa667 11915 jp Mac - CD - Petr Maruska + + c7be10f775404fd9785a8b92a06d240c -1 en FM-TOWNS - - - dhewg, Andrea Petrucci + 4d34042713958b971cb139fba4658586 -1 jp FM-TOWNS - - - Andrea Petrucci + + 035deab53b47bc43abc763560d0f8d4b -1 en DOS Floppy Demo - + 98744fe66ff730e8c2b3b1f58803ab0b -1 en DOS Floppy Demo - Simon Krumrein, sev + 99b6f822b0b2612415407865438697d6 -1 en DOS - Demo non-interactive + 28d24a33448fab6795850bc9f159a4a2 11170 jp FM-TOWNS - Demo non-interactive khalek, Fingolfin tentacle Day of the Tentacle - acad97ab1c6fc2a5b2d98abf6db4a190 -1 en All? - Floppy Version A ? - 2723fea3dae0cb47768c424b145ae0e7 7932 en DOS - Floppy Version B ? Andrej Sinicyn, Andrea Petrucci, Fingolfin - 92b078d9d6d9d751da9c26b8b3075779 -1 fr DOS - Floppy - Nicolas Sauzède, Andrea Petrucci - 94aaedbb8f26d71ed3ad6dd34490e29e -1 fr DOS - Floppy alt? Nicolas Joly - 57b0d89af79befe1cabce3bece869e7f -1 de DOS - Floppy - Andrej Sinicyn, Andrea Petrucci - 50fcdc982a25063b78ad46bf389b8e8d -1 it DOS - Floppy - Andrea Petrucci - ae94f110a14ce71fc515d5b648827a8f -1 es DOS - Floppy - abnog, Andrea Petrucci - - 4167a92a1d46baa4f4127d918d561f88 7932 en All? CD CD - Fingolfin - 8aa05d3cdb0e795436043f0546af2da2 -1 fr All? CD CD? - Andrea Petrucci - 6e959d65358eedf9b68b81e304b97fa4 7932 de All? CD CD - Fingolfin - 4fbbe9f64b8bc547503a379a301183ce -1 it All? CD CD - Andrea Petrucci - 883af4b0af4f77a92f1dcf1d0a283140 -1 es All? CD CD - Andrea Petrucci - cc04a076779379524ed4d9c5ee3c6fb1 282467632 en Mac CD CD Mac bundle Fingolfin, Joachim Eberhard - ede149fda3edfc1dbd7347e0737cb583 -1 fr Mac CD CD Mac bundle ThierryFR - f73883f13b5a302749a5bad31d909780 -1 de Mac CD CD Mac bundle morrissey - - c83079157ec765a28de445aec9768d60 7477 en All CD Demo - Fingolfin - 17fa250eb72dae2dad511ba79c0b6b0a -1 fr DOS CD Demo - cyx - ac1642b6edfb8521ca03760126f1c250 -1 de DOS CD Demo - Simon Krumrein, sev - 2a41b53cf1a90b6e6f26c10cc6041084 2439158 en Mac CD Demo Mac bundle Fingolfin + acad97ab1c6fc2a5b2d98abf6db4a190 -1 en All? Floppy Floppy Version A ? + 2723fea3dae0cb47768c424b145ae0e7 7932 en DOS Floppy Floppy Version B ? Andrej Sinicyn, Andrea Petrucci, Fingolfin + 92b078d9d6d9d751da9c26b8b3075779 -1 fr DOS Floppy Floppy - Nicolas Sauzède, Andrea Petrucci + 94aaedbb8f26d71ed3ad6dd34490e29e -1 fr DOS Floppy Floppy alt? Nicolas Joly + 57b0d89af79befe1cabce3bece869e7f -1 de DOS Floppy Floppy - Andrej Sinicyn, Andrea Petrucci + 50fcdc982a25063b78ad46bf389b8e8d -1 it DOS Floppy Floppy - Andrea Petrucci + ae94f110a14ce71fc515d5b648827a8f -1 es DOS Floppy Floppy - abnog, Andrea Petrucci + + 4167a92a1d46baa4f4127d918d561f88 7932 en All? - CD - Fingolfin + 8aa05d3cdb0e795436043f0546af2da2 -1 fr All? - CD? - Andrea Petrucci + 6e959d65358eedf9b68b81e304b97fa4 7932 de All? - CD - Fingolfin + 4fbbe9f64b8bc547503a379a301183ce -1 it All? - CD - Andrea Petrucci + 883af4b0af4f77a92f1dcf1d0a283140 -1 es All? - CD - Andrea Petrucci + cc04a076779379524ed4d9c5ee3c6fb1 282467632 en Mac - CD Mac bundle Fingolfin, Joachim Eberhard + ede149fda3edfc1dbd7347e0737cb583 -1 fr Mac - CD Mac bundle ThierryFR + f73883f13b5a302749a5bad31d909780 -1 de Mac - CD Mac bundle morrissey + + c83079157ec765a28de445aec9768d60 7477 en All - Demo - Fingolfin + 17fa250eb72dae2dad511ba79c0b6b0a -1 fr DOS - Demo - cyx + ac1642b6edfb8521ca03760126f1c250 -1 de DOS - Demo - Simon Krumrein, sev + 2a41b53cf1a90b6e6f26c10cc6041084 2439158 en Mac - Demo Mac bundle Fingolfin samnmax Sam & Max Hit the Road - 3b301b7892f883ce42ab4be6a274fea6 -1 en DOS - Floppy - Andrea Petrucci - a3036878840720fbefa41e6965fa4a0a -1 en DOS - Floppy alt? Andrea Petrucci - ef347474f3c7be3b29584eaa133cca05 -1 fr DOS - Floppy - Nicolas Sauzède, Andrea Petrucci - f27b1ba0eadaf2a6617b2b58192d1dbf -1 de DOS - Floppy - dhewg, Andrea Petrucci - b289a2a8cbedbf45786e0b4ad2f510f1 -1 it DOS - Floppy - Andrea Petrucci - fc53ce0e5f6562b1c1e1b4b8203acafb -1 es DOS - Floppy - Andrea Petrucci - - d917f311a448e3cc7239c31bddb00dd2 9080 en All? CD CD - Fingolfin - 7edd665bbede7ea8b7233f8e650be6f8 -1 fr All? CD CD - Andrea Petrucci - 0fb73eddfcf584c02ba097984df131ba 9080 de All? CD CD - Fingolfin - 0f6f2e716ba896a44e5059bba1de7ca9 -1 it All? CD CD - Andrea Petrucci - 4ba7fb331296c283e73d8f5b2096e551 -1 es All? CD CD - Andrea Petrucci - d43352a805d78b5f4936c6d7779bf575 -1 ru DOS CD CD - - 166553538ff320c69edafeee29525419 -1 en Mac CD CD Mac bundle Joachim Eberhard - 3a5d13675e9a23aedac0bac7730f0ac1 -1 fr Mac CD CD Mac bundle ThierryFR - - c3196c5349e53e387aaff1533d95e53a -1 en DOS - Demo - - 0e4c5d54a0ad4b26132e78b5ea76642a 6485 en DOS - Demo WIP Fingolfin - d9d0dd93d16ab4dec55cabc2b86bbd17 6478 en DOS CD Demo non-interactive Fingolfin - cc8ba2b0df2f9c450bcf055fe2711979 7485 de DOS - Demo - Simon Krumrein, sev, Fingolfin - 0425954a9db5c340861672892c3e678d -1 en All CD Demo - Kirben - 6dead580b0ff14d5f7b33b4219f04159 16556335 en Mac CD Demo Mac bundle Fingolfin + 3b301b7892f883ce42ab4be6a274fea6 -1 en DOS Floppy Floppy - Andrea Petrucci + a3036878840720fbefa41e6965fa4a0a -1 en DOS Floppy Floppy alt? Andrea Petrucci + ef347474f3c7be3b29584eaa133cca05 -1 fr DOS Floppy Floppy - Nicolas Sauzède, Andrea Petrucci + f27b1ba0eadaf2a6617b2b58192d1dbf -1 de DOS Floppy Floppy - dhewg, Andrea Petrucci + b289a2a8cbedbf45786e0b4ad2f510f1 -1 it DOS Floppy Floppy - Andrea Petrucci + fc53ce0e5f6562b1c1e1b4b8203acafb -1 es DOS Floppy Floppy - Andrea Petrucci + + d917f311a448e3cc7239c31bddb00dd2 9080 en All? - CD - Fingolfin + 7edd665bbede7ea8b7233f8e650be6f8 -1 fr All? - CD - Andrea Petrucci + 0fb73eddfcf584c02ba097984df131ba 9080 de All? - CD - Fingolfin + 0f6f2e716ba896a44e5059bba1de7ca9 -1 it All? - CD - Andrea Petrucci + 4ba7fb331296c283e73d8f5b2096e551 -1 es All? - CD - Andrea Petrucci + d43352a805d78b5f4936c6d7779bf575 -1 ru DOS - CD - + 166553538ff320c69edafeee29525419 -1 en Mac - CD Mac bundle Joachim Eberhard + 3a5d13675e9a23aedac0bac7730f0ac1 -1 fr Mac - CD Mac bundle ThierryFR + + c3196c5349e53e387aaff1533d95e53a -1 en DOS Floppy Demo - + 0e4c5d54a0ad4b26132e78b5ea76642a 6485 en DOS Floppy Demo WIP Fingolfin + d9d0dd93d16ab4dec55cabc2b86bbd17 6478 en DOS - Demo non-interactive Fingolfin + cc8ba2b0df2f9c450bcf055fe2711979 7485 de DOS Floppy Demo - Simon Krumrein, sev, Fingolfin + 0425954a9db5c340861672892c3e678d -1 en All - Demo - Kirben + 6dead580b0ff14d5f7b33b4219f04159 16556335 en Mac - Demo Mac bundle Fingolfin ft Full Throttle 41958e24d03181ff9a381a66d048a581 -1 br All? - - - Danilo E.S. @@ -405,7 +405,7 @@ Soccer2004 Backyard Soccer 2004 c4ffae9fac495475d6bc3343ccc8faf9 -1 en All - - - Kirben, sev brstorm Bear Stormin' - 07a1eefd8ca95d77310311446c0f53d0 5433 en All - Demo - sev + 07a1eefd8ca95d77310311446c0f53d0 5433 en All - - - sev thinker1 Big Thinkers First Grade 5c21fc49aee8f46e58fef21579e614a1 -1 us All - - - Kirben diff --git a/tools/update-version.pl b/tools/update-version.pl index ec0249c872..406f8bf045 100755 --- a/tools/update-version.pl +++ b/tools/update-version.pl @@ -35,6 +35,8 @@ my @subs_files = qw( dists/redhat/scummvm.spec dists/scummvm.rc dists/slackware/scummvm.SlackBuild + dists/macosx/Info.plist + dists/iphone/Info.plist dists/wii/meta.xml backends/platform/psp/README.PSP ); |