diff options
236 files changed, 8058 insertions, 4670 deletions
@@ -25,7 +25,7 @@ CXXFLAGS:= -Wall $(CXXFLAGS) CXXFLAGS+= -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder # Enable even more warnings... CXXFLAGS+= -pedantic -Wpointer-arith -Wcast-qual -Wcast-align -CXXFLAGS+= -Wshadow -Wimplicit -Wundef -Wnon-virtual-dtor -Wwrite-strings +CXXFLAGS+= -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings # Disable RTTI and exceptions, and enabled checking of pointers returned by "new" CXXFLAGS+= -fno-rtti -fno-exceptions -fcheck-new @@ -2,25 +2,31 @@ For a more comprehensive changelog for the latest experimental SVN code, see: http://scummvm.sourceforge.net/daily/ChangeLog 0.13.0 (????-??-??) + General: + - Added MIDI driver for Atari ST / FreeMint. + New Games: - Added support for Discworld. 0.12.0 (????-??-??) New Games: - - Added support for The Legend of Kyrandia: Book Two: Hand of Fate - - Added support for The Legend of Kyrandia: Book Three: Malcolm's Revenge - - Added support for Lost in Time - - Added support for The Bizarre Adventures of Woodruff and the Schnibble - - Added support for the PC version of Waxworks + - Added support for The Legend of Kyrandia: Book Two: Hand of Fate. + - Added support for The Legend of Kyrandia: Book Three: Malcolm's Revenge. + - Added support for Lost in Time. + - Added support for The Bizarre Adventures of Woodruff and the Schnibble. + - Added support for the PC version of Waxworks. - Added support for the Macintosh version of I Have no Mouth, and I - must Scream - - Added support for Drascula: The Vampire Strikes Back + must Scream. + - Added support for Drascula: The Vampire Strikes Back. General: - Added CAMD MIDI driver for AmigaOS4. - Revived the PS2 port (was already in 0.11.1 but was forgotten in the release notes). - - Plugged numerous memory leaks in all engines (part of GSoC'08 task) + - Plugged numerous memory leaks in all engines (part of GSoC'08 task), + - Added audio double buffering to the SDL backend, which fixes the + problems with the MT-32 emulator on Mac OS X (for now only enabled + on Mac OS X). AGOS: - Fixed crashes during certain music in Amiga versions of Elvira 1 and @@ -1017,7 +1017,7 @@ other games. Common: F6 - Displays the Global Menu - Cmd-q - Quit (Mac OS X) + Cmd-q - Quit (Mac OS X) Ctrl-q - Quit (other unices including Linux) Ctrl-z OR Alt-x - Quit (other platforms) Ctrl-m - Toggle mouse capture diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index b070fb89ef..65b375605b 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -392,11 +392,23 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { _keyRepeatTime = time + kKeyRepeatInitialDelay; #endif // Global Main Menu - if (event.kbd.keycode == Common::KEYCODE_MAINMENU) + // FIXME: F6 is not the best trigger, it conflicts with some games!!! + if (event.kbd.keycode == Common::KEYCODE_F6) if (g_engine && !g_engine->isPaused()) { Common::Event menuEvent; menuEvent.type = Common::EVENT_MAINMENU; - pushEvent(menuEvent); + + // FIXME: GSoC RTL branch passes the F6 key event to the + // engine, and also enqueues a EVENT_MAINMENU. For now, + // we just drop the key event and return an EVENT_MAINMENU + // instead. This way, we don't have to add special cases + // to engines (like it was the case for LURE in the RTL branch). + // + // However, this has other consequences, possibly negative ones. + // Like, what happens with key repeat for the trigger key? + + //pushEvent(menuEvent); + event = menuEvent; } break; diff --git a/backends/fs/abstract-fs.cpp b/backends/fs/abstract-fs.cpp new file mode 100644 index 0000000000..f6dc8f1891 --- /dev/null +++ b/backends/fs/abstract-fs.cpp @@ -0,0 +1,39 @@ +/* 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 "backends/fs/abstract-fs.h" + +const char *AbstractFilesystemNode::lastPathComponent(const Common::String &str, const char sep) { + if(str.empty()) + return ""; + + const char *start = str.c_str(); + const char *cur = start + str.size() - 2; + + while (cur >= start && *cur != sep) { + --cur; + } + + return cur + 1; +} diff --git a/backends/fs/abstract-fs.h b/backends/fs/abstract-fs.h index 97de40a2fc..d81e7f36b0 100644 --- a/backends/fs/abstract-fs.h +++ b/backends/fs/abstract-fs.h @@ -72,6 +72,19 @@ protected: */ virtual AbstractFilesystemNode *getParent() const = 0; + /** + * Returns the last component of a given path. + * + * Examples: + * /foo/bar.txt would return /bar.txt + * /foo/bar/ would return /bar/ + * + * @param str String containing the path. + * @param sep character used to separate path components + * @return Pointer to the first char of the last component inside str. + */ + static const char *lastPathComponent(const Common::String &str, const char sep); + public: /** * Destructor. @@ -154,4 +167,6 @@ public: */ }; + + #endif //BACKENDS_ABSTRACT_FS_H diff --git a/backends/fs/amigaos4/amigaos4-fs-factory.cpp b/backends/fs/amigaos4/amigaos4-fs-factory.cpp index af843b7c78..2b0b2f1908 100644 --- a/backends/fs/amigaos4/amigaos4-fs-factory.cpp +++ b/backends/fs/amigaos4/amigaos4-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/amigaos4/amigaos4-fs-factory.h" #include "backends/fs/amigaos4/amigaos4-fs.cpp" -DECLARE_SINGLETON(AmigaOSFilesystemFactory); - AbstractFilesystemNode *AmigaOSFilesystemFactory::makeRootFileNode() const { return new AmigaOSFilesystemNode(); } @@ -36,7 +34,7 @@ AbstractFilesystemNode *AmigaOSFilesystemFactory::makeCurrentDirectoryFileNode() return new AmigaOSFilesystemNode(); } -AbstractFilesystemNode *AmigaOSFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *AmigaOSFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new AmigaOSFilesystemNode(path); } #endif diff --git a/backends/fs/amigaos4/amigaos4-fs-factory.h b/backends/fs/amigaos4/amigaos4-fs-factory.h index 58a7dcd372..03af6e95b9 100644 --- a/backends/fs/amigaos4/amigaos4-fs-factory.h +++ b/backends/fs/amigaos4/amigaos4-fs-factory.h @@ -25,7 +25,6 @@ #ifndef AMIGAOS_FILESYSTEM_FACTORY_H #define AMIGAOS_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,11 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class AmigaOSFilesystemFactory : public FilesystemFactory, public Common::Singleton<AmigaOSFilesystemFactory> { +class AmigaOSFilesystemFactory : public FilesystemFactory { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - AmigaOSFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*AMIGAOS_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/ds/ds-fs.cpp b/backends/fs/ds/ds-fs.cpp index cffe4c118d..d206941ab9 100644 --- a/backends/fs/ds/ds-fs.cpp +++ b/backends/fs/ds/ds-fs.cpp @@ -798,25 +798,3 @@ int std_ferror(FILE* handle) { } } // namespace DS - -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/' && *cur != '\\') { - --cur; - } - - return cur + 1; -} - diff --git a/backends/fs/palmos/palmos-fs.cpp b/backends/fs/palmos/palmos-fs.cpp index 5edb6c2d26..69d9f350f5 100644 --- a/backends/fs/palmos/palmos-fs.cpp +++ b/backends/fs/palmos/palmos-fs.cpp @@ -80,30 +80,6 @@ private: static void addFile(AbstractFSList &list, ListMode mode, const Char *base, FileInfoType* find_data); }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - void PalmOSFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, FileInfoType* find_data) { PalmOSFilesystemNode entry; bool isDir; @@ -138,7 +114,7 @@ PalmOSFilesystemNode::PalmOSFilesystemNode() { PalmOSFilesystemNode::PalmOSFilesystemNode(const String &p) { _path = p; - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); UInt32 attr; FileRef handle; @@ -215,13 +191,13 @@ AbstractFilesystemNode *PalmOSFilesystemNode::getParent() const { if (!_isPseudoRoot) { const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); p = new PalmOSFilesystemNode(); p->_path = String(start, end - start); p->_isValid = true; p->_isDirectory = true; - p->_displayName = lastPathComponent(p->_path); + p->_displayName = lastPathComponent(p->_path, '/'); p->_isPseudoRoot =(p->_path == "/"); } diff --git a/backends/fs/posix/posix-fs-factory.cpp b/backends/fs/posix/posix-fs-factory.cpp index 0a1160ff8f..da73738287 100644 --- a/backends/fs/posix/posix-fs-factory.cpp +++ b/backends/fs/posix/posix-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/posix/posix-fs-factory.h" #include "backends/fs/posix/posix-fs.cpp" -DECLARE_SINGLETON(POSIXFilesystemFactory); - AbstractFilesystemNode *POSIXFilesystemFactory::makeRootFileNode() const { return new POSIXFilesystemNode(); } @@ -38,7 +36,7 @@ AbstractFilesystemNode *POSIXFilesystemFactory::makeCurrentDirectoryFileNode() c return new POSIXFilesystemNode(buf, true); } -AbstractFilesystemNode *POSIXFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *POSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new POSIXFilesystemNode(path, true); } #endif diff --git a/backends/fs/posix/posix-fs-factory.h b/backends/fs/posix/posix-fs-factory.h index d8eecda6ef..c697679814 100644 --- a/backends/fs/posix/posix-fs-factory.h +++ b/backends/fs/posix/posix-fs-factory.h @@ -25,7 +25,6 @@ #ifndef POSIX_FILESYSTEM_FACTORY_H #define POSIX_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,10 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class POSIXFilesystemFactory : public FilesystemFactory, public Common::Singleton<POSIXFilesystemFactory> { -public: - typedef Common::String String; - +class POSIXFilesystemFactory : public FilesystemFactory { virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - POSIXFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*POSIX_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp index 10782a9057..5cd6a909d6 100644 --- a/backends/fs/posix/posix-fs.cpp +++ b/backends/fs/posix/posix-fs.cpp @@ -24,85 +24,18 @@ #if defined(UNIX) -#include "backends/fs/abstract-fs.h" +#include "backends/fs/posix/posix-fs.h" -#ifdef MACOSX -#include <sys/types.h> -#endif #include <sys/param.h> #include <sys/stat.h> #include <dirent.h> #include <stdio.h> -#include <unistd.h> -/** - * Implementation of the ScummVM file system API based on POSIX. - * - * Parts of this class are documented in the base interface class, AbstractFilesystemNode. - */ -class POSIXFilesystemNode : public AbstractFilesystemNode { -protected: - Common::String _displayName; - Common::String _path; - bool _isDirectory; - bool _isValid; - -public: - /** - * Creates a POSIXFilesystemNode with the root node as path. - */ - POSIXFilesystemNode(); - - /** - * Creates a POSIXFilesystemNode for a given path. - * - * @param path String with the path the new node should point to. - * @param verify true if the isValid and isDirectory flags should be verified during the construction. - */ - POSIXFilesystemNode(const Common::String &path, bool verify); - - virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } - virtual Common::String getDisplayName() const { return _displayName; } - virtual Common::String getName() const { return _displayName; } - virtual Common::String getPath() const { return _path; } - virtual bool isDirectory() const { return _isDirectory; } - virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } - virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } - - virtual AbstractFilesystemNode *getChild(const Common::String &n) const; - virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; - virtual AbstractFilesystemNode *getParent() const; - -private: - /** - * Tests and sets the _isValid and _isDirectory flags, using the stat() function. - */ - virtual void setFlags(); -}; - -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } +#ifdef __OS2__ +#define INCL_DOS +#include <os2.h> +#endif - return cur + 1; -} void POSIXFilesystemNode::setFlags() { struct stat st; @@ -135,7 +68,7 @@ POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p, bool verify) { _path = p; } - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); if (verify) { setFlags(); @@ -158,6 +91,38 @@ AbstractFilesystemNode *POSIXFilesystemNode::getChild(const Common::String &n) c bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { assert(_isDirectory); +#ifdef __OS2__ + if (_path == "/") { + ULONG ulDrvNum; + ULONG ulDrvMap; + + DosQueryCurrentDisk(&ulDrvNum, &ulDrvMap); + + for (int i = 0; i < 26; i++) { + if (ulDrvMap & 1) { + char drive_root[4]; + + drive_root[0] = i + 'A'; + drive_root[1] = ':'; + drive_root[2] = '/'; + drive_root[3] = 0; + + POSIXFilesystemNode entry; + + entry._isDirectory = true; + entry._isValid = true; + entry._path = drive_root; + entry._displayName = "[" + Common::String(drive_root, 2) + "]"; + myList.push_back(new POSIXFilesystemNode(entry)); + } + + ulDrvMap >>= 1; + } + + return true; + } +#endif + DIR *dirp = opendir(_path.c_str()); struct dirent *dp; @@ -234,9 +199,14 @@ AbstractFilesystemNode *POSIXFilesystemNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); + +#ifdef __OS2__ + if (end == start) + return new POSIXFilesystemNode(); +#endif - return new POSIXFilesystemNode(Common::String(start, end - start), true); + return new POSIXFilesystemNode(Common::String(start, end), true); } #endif //#if defined(UNIX) diff --git a/backends/fs/posix/posix-fs.h b/backends/fs/posix/posix-fs.h new file mode 100644 index 0000000000..df50fc16af --- /dev/null +++ b/backends/fs/posix/posix-fs.h @@ -0,0 +1,80 @@ +/* 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 POSIX_FILESYSTEM_H +#define POSIX_FILESYSTEM_H + +#include "backends/fs/abstract-fs.h" + +#ifdef MACOSX +#include <sys/types.h> +#endif +#include <unistd.h> + +/** + * Implementation of the ScummVM file system API based on POSIX. + * + * Parts of this class are documented in the base interface class, AbstractFilesystemNode. + */ +class POSIXFilesystemNode : public AbstractFilesystemNode { +protected: + Common::String _displayName; + Common::String _path; + bool _isDirectory; + bool _isValid; + +public: + /** + * Creates a POSIXFilesystemNode with the root node as path. + */ + POSIXFilesystemNode(); + + /** + * Creates a POSIXFilesystemNode for a given path. + * + * @param path String with the path the new node should point to. + * @param verify true if the isValid and isDirectory flags should be verified during the construction. + */ + POSIXFilesystemNode(const Common::String &path, bool verify); + + virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } + virtual bool isDirectory() const { return _isDirectory; } + virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } + virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } + + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; + virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; + virtual AbstractFilesystemNode *getParent() const; + +private: + /** + * Tests and sets the _isValid and _isDirectory flags, using the stat() function. + */ + virtual void setFlags(); +}; + +#endif /*POSIX_FILESYSTEM_H*/ diff --git a/backends/fs/ps2/ps2-fs.cpp b/backends/fs/ps2/ps2-fs.cpp index 782e97b959..b0f1ddbafb 100644 --- a/backends/fs/ps2/ps2-fs.cpp +++ b/backends/fs/ps2/ps2-fs.cpp @@ -100,28 +100,6 @@ public: virtual AbstractFilesystemNode *getParent() const; }; -/** - * Returns the last component of a given path. - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if (str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/' && *cur != ':') { - --cur; - } - - printf("romeo : lastPathComponent = %s\n", cur + 1); - - return cur + 1; -} - Ps2FilesystemNode::Ps2FilesystemNode() { _isDirectory = true; _isRoot = true; diff --git a/backends/fs/psp/psp-fs.cpp b/backends/fs/psp/psp-fs.cpp index 3fe6060928..aa3e253782 100644 --- a/backends/fs/psp/psp-fs.cpp +++ b/backends/fs/psp/psp-fs.cpp @@ -71,30 +71,6 @@ public: virtual AbstractFilesystemNode *getParent() const; }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - PSPFilesystemNode::PSPFilesystemNode() { _isDirectory = true; _displayName = "Root"; @@ -106,7 +82,7 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) { assert(p.size() > 0); _path = p; - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); _isValid = true; _isDirectory = true; @@ -176,7 +152,7 @@ AbstractFilesystemNode *PSPFilesystemNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); return new PSPFilesystemNode(String(start, end - start), false); } diff --git a/backends/fs/symbian/symbian-fs-factory.cpp b/backends/fs/symbian/symbian-fs-factory.cpp index 0a1bd62134..c31dfb594a 100644 --- a/backends/fs/symbian/symbian-fs-factory.cpp +++ b/backends/fs/symbian/symbian-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/symbian/symbian-fs-factory.h" #include "backends/fs/symbian/symbian-fs.cpp" -DECLARE_SINGLETON(SymbianFilesystemFactory); - AbstractFilesystemNode *SymbianFilesystemFactory::makeRootFileNode() const { return new SymbianFilesystemNode(true); } @@ -38,7 +36,7 @@ AbstractFilesystemNode *SymbianFilesystemFactory::makeCurrentDirectoryFileNode() return new SymbianFilesystemNode(path); } -AbstractFilesystemNode *SymbianFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *SymbianFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new SymbianFilesystemNode(path); } #endif diff --git a/backends/fs/symbian/symbian-fs-factory.h b/backends/fs/symbian/symbian-fs-factory.h index 502fba2930..ef5a231e72 100644 --- a/backends/fs/symbian/symbian-fs-factory.h +++ b/backends/fs/symbian/symbian-fs-factory.h @@ -25,7 +25,6 @@ #ifndef SYMBIAN_FILESYSTEM_FACTORY_H #define SYMBIAN_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,11 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class SymbianFilesystemFactory : public FilesystemFactory, public Common::Singleton<SymbianFilesystemFactory> { +class SymbianFilesystemFactory : public FilesystemFactory { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - SymbianFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*SYMBIAN_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/symbian/symbian-fs.cpp b/backends/fs/symbian/symbian-fs.cpp index 85fc58179a..af963dda0c 100644 --- a/backends/fs/symbian/symbian-fs.cpp +++ b/backends/fs/symbian/symbian-fs.cpp @@ -24,6 +24,7 @@ #if defined (__SYMBIAN32__) #include "backends/fs/abstract-fs.h" +#include "backends/platform/symbian/src/SymbianOS.h" #include <dirent.h> #include <eikenv.h> @@ -62,7 +63,7 @@ public: TFileName fname; TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size()); fname.Copy(ptr); - TBool fileExists = BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), fname); + TBool fileExists = BaflUtils::FileExists(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), fname); return fileExists; } virtual String getDisplayName() const { return _displayName; } @@ -78,30 +79,6 @@ public: }; /** - * Returns the last component of a given path. - * - * Examples: - * c:\foo\bar.txt would return "\bar.txt" - * c:\foo\bar\ would return "\bar\" - * - * @param str Path to obtain the last component from. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '\\') { - --cur; - } - - return cur + 1; -} - -/** * Fixes the path by changing all slashes to backslashes. * * @param path String with the path to be fixed. @@ -135,14 +112,14 @@ SymbianFilesystemNode::SymbianFilesystemNode(const String &path) { fixFilePath(_path); - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '\\'); TEntry fileAttribs; TFileName fname; TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size()); fname.Copy(ptr); - if (CEikonEnv::Static()->FsSession().Entry(fname, fileAttribs) == KErrNone) { + if (static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession().Entry(fname, fileAttribs) == KErrNone) { _isValid = true; _isDirectory = fileAttribs.IsDir(); } else { @@ -163,7 +140,7 @@ AbstractFilesystemNode *SymbianFilesystemNode::getChild(const String &n) const { TFileName fname; fname.Copy(ptr); TBool isFolder = EFalse; - BaflUtils::IsFolder(CEikonEnv::Static()->FsSession(), fname, isFolder); + BaflUtils::IsFolder(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), fname, isFolder); if (!isFolder) return 0; @@ -177,7 +154,7 @@ bool SymbianFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b if (_isPseudoRoot) { // Drives enumeration - RFs fs = CEikonEnv::Static()->FsSession(); + RFs& fs = static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(); TInt driveNumber; TChar driveLetter; TUint driveLetterValue; @@ -218,7 +195,7 @@ bool SymbianFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b fname.Copy(ptr); TBuf8<256>nameBuf; CDir* dirPtr; - if (CEikonEnv::Static()->FsSession().GetDir(fname,KEntryAttNormal|KEntryAttDir,0,dirPtr)==KErrNone) { + if (static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession().GetDir(fname,KEntryAttNormal|KEntryAttDir,0,dirPtr)==KErrNone) { CleanupStack::PushL(dirPtr); TInt cnt=dirPtr->Count(); for (TInt loop=0;loop<cnt;loop++) { @@ -256,12 +233,12 @@ AbstractFilesystemNode *SymbianFilesystemNode::getParent() const { if (!_isPseudoRoot && _path.size() > 3) { p = new SymbianFilesystemNode(false); const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '\\'); p->_path = String(start, end - start); p->_isValid = true; p->_isDirectory = true; - p->_displayName = lastPathComponent(p->_path); + p->_displayName = lastPathComponent(p->_path, '\\'); } else { diff --git a/backends/fs/wii/wii-fs.cpp b/backends/fs/wii/wii-fs.cpp index e6d0cf4c7e..4272ffb380 100644 --- a/backends/fs/wii/wii-fs.cpp +++ b/backends/fs/wii/wii-fs.cpp @@ -71,30 +71,6 @@ private: virtual void setFlags(); }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - void WiiFilesystemNode::setFlags() { struct stat st; @@ -123,7 +99,7 @@ WiiFilesystemNode::WiiFilesystemNode(const String &p, bool verify) { _path = p; - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); if (verify) setFlags(); @@ -187,7 +163,7 @@ AbstractFilesystemNode *WiiFilesystemNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); return new WiiFilesystemNode(String(start, end - start), true); } diff --git a/backends/fs/windows/windows-fs-factory.cpp b/backends/fs/windows/windows-fs-factory.cpp index 7fbf4f7fff..ed273bb746 100644 --- a/backends/fs/windows/windows-fs-factory.cpp +++ b/backends/fs/windows/windows-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/windows/windows-fs-factory.h" #include "backends/fs/windows/windows-fs.cpp" -DECLARE_SINGLETON(WindowsFilesystemFactory); - AbstractFilesystemNode *WindowsFilesystemFactory::makeRootFileNode() const { return new WindowsFilesystemNode(); } @@ -36,7 +34,7 @@ AbstractFilesystemNode *WindowsFilesystemFactory::makeCurrentDirectoryFileNode() return new WindowsFilesystemNode("", true); } -AbstractFilesystemNode *WindowsFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *WindowsFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new WindowsFilesystemNode(path, false); } #endif diff --git a/backends/fs/windows/windows-fs-factory.h b/backends/fs/windows/windows-fs-factory.h index 0745b286a8..3c7b80942d 100644 --- a/backends/fs/windows/windows-fs-factory.h +++ b/backends/fs/windows/windows-fs-factory.h @@ -25,7 +25,6 @@ #ifndef WINDOWS_FILESYSTEM_FACTORY_H #define WINDOWS_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,11 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class WindowsFilesystemFactory : public FilesystemFactory, public Common::Singleton<WindowsFilesystemFactory> { +class WindowsFilesystemFactory : public FilesystemFactory { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - WindowsFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*WINDOWS_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/windows/windows-fs.cpp b/backends/fs/windows/windows-fs.cpp index 2105317a96..b06581047c 100644 --- a/backends/fs/windows/windows-fs.cpp +++ b/backends/fs/windows/windows-fs.cpp @@ -135,30 +135,6 @@ private: static const TCHAR* toUnicode(const char *str); }; -/** - * Returns the last component of a given path. - * - * Examples: - * c:\foo\bar.txt would return "\bar.txt" - * c:\foo\bar\ would return "\bar\" - * - * @param str Path to obtain the last component from. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '\\') { - --cur; - } - - return cur + 1; -} - void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data) { WindowsFilesystemNode entry; char *asciiName = toAscii(find_data->cFileName); @@ -232,7 +208,7 @@ WindowsFilesystemNode::WindowsFilesystemNode(const String &p, const bool current _path = p; } - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '\\'); // Check whether it is a directory, and whether the file actually exists DWORD fileAttribs = GetFileAttributes(toUnicode(_path.c_str())); @@ -322,13 +298,13 @@ AbstractFilesystemNode *WindowsFilesystemNode::getParent() const { WindowsFilesystemNode *p = new WindowsFilesystemNode(); if (_path.size() > 3) { const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '\\'); p = new WindowsFilesystemNode(); p->_path = String(start, end - start); p->_isValid = true; p->_isDirectory = true; - p->_displayName = lastPathComponent(p->_path); + p->_displayName = lastPathComponent(p->_path, '\\'); p->_isPseudoRoot = false; } diff --git a/backends/midi/seq.cpp b/backends/midi/seq.cpp index 57a5a1ea32..9e86181674 100644 --- a/backends/midi/seq.cpp +++ b/backends/midi/seq.cpp @@ -28,7 +28,7 @@ * both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html) */ -#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) +#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__) #include "common/util.h" #include "sound/musicplugin.h" diff --git a/backends/midi/stmidi.cpp b/backends/midi/stmidi.cpp new file mode 100644 index 0000000000..addb23c6bd --- /dev/null +++ b/backends/midi/stmidi.cpp @@ -0,0 +1,155 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 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. + */ + +/* + * Raw MIDI output for the Atari ST line of computers. + * Based on the ScummVM SEQ & CoreMIDI drivers. + * Atari code by Keith Scroggins + * We, unfortunately, could not use the SEQ driver because the /dev/midi under + * FreeMiNT (and hence in libc) is considered to be a serial port for machine + * access. So, we just use OS calls then to send the data to the MIDI ports + * directly. The current implementation is sending 1 byte at a time because + * in most cases we are only sending up to 3 bytes, I believe this saves a few + * cycles. I might change so sysex messages are sent the other way later. + */ + +#if defined __MINT__ + +#include <osbind.h> +#include "sound/mpu401.h" +#include "common/util.h" +#include "sound/musicplugin.h" + +class MidiDriver_STMIDI : public MidiDriver_MPU401 { +public: + MidiDriver_STMIDI() : _isOpen (false) { } + int open(); + void close(); + void send(uint32 b); + void sysEx(const byte *msg, uint16 length); + +private: + bool _isOpen; +}; + +int MidiDriver_STMIDI::open() { + if ((_isOpen) && (!Bcostat(4))) + return MERR_ALREADY_OPEN; + warning("ST Midi Port Open"); + _isOpen = true; + return 0; +} + +void MidiDriver_STMIDI::close() { + MidiDriver_MPU401::close(); + _isOpen = false; +} + +void MidiDriver_STMIDI::send(uint32 b) { + + byte status_byte = (b & 0x000000FF); + byte first_byte = (b & 0x0000FF00) >> 8; + byte second_byte = (b & 0x00FF0000) >> 16; + +// warning("ST MIDI Packet sent"); + + switch (b & 0xF0) { + case 0x80: // Note Off + case 0x90: // Note On + case 0xA0: // Polyphonic Key Pressure + case 0xB0: // Controller + case 0xE0: // Pitch Bend + Bconout(3, status_byte); + Bconout(3, first_byte); + Bconout(3, second_byte); + break; + case 0xC0: // Program Change + case 0xD0: // Aftertouch + Bconout(3, status_byte); + Bconout(3, first_byte); + break; + default: + fprintf(stderr, "Unknown : %08x\n", (int)b); + break; + } +} + +void MidiDriver_STMIDI::sysEx (const byte *msg, uint16 length) { + if (length > 254) { + warning ("Cannot send SysEx block - data too large"); + return; + } + + const byte *chr = msg; + warning("Sending SysEx Message"); + + Bconout(3, '0xF0'); + for (; length; --length, ++chr) { + Bconout(3,((unsigned char) *chr & 0x7F)); + } + Bconout(3, '0xF7'); +} + +// Plugin interface + +class StMidiMusicPlugin : public MusicPluginObject { +public: + const char *getName() const { + return "STMIDI"; + } + + const char *getId() const { + return "stmidi"; + } + + MusicDevices getDevices() const; + PluginError createInstance(Audio::Mixer *mixer, MidiDriver **mididriver) + const; +}; + +MusicDevices StMidiMusicPlugin::getDevices() const { + MusicDevices devices; + // TODO: Return a different music type depending on the configuration + // TODO: List the available devices + devices.push_back(MusicDevice(this, "", MT_GM)); + return devices; +} + +PluginError StMidiMusicPlugin::createInstance(Audio::Mixer *mixer, MidiDriver **mididriver) const { + *mididriver = new MidiDriver_STMIDI(); + + return kNoError; +} + +MidiDriver *MidiDriver_STMIDI_create(Audio::Mixer *mixer) { + MidiDriver *mididriver; + + StMidiMusicPlugin p; + p.createInstance(mixer, &mididriver); + + return mididriver; +} + +//#if PLUGIN_ENABLED_DYNAMIC(STMIDI) + //REGISTER_PLUGIN_DYNAMIC(STMIDI, PLUGIN_TYPE_MUSIC, StMidiMusicPlugin); +//#else + REGISTER_PLUGIN_STATIC(STMIDI, PLUGIN_TYPE_MUSIC, StMidiMusicPlugin); +//#endif + +#endif diff --git a/backends/module.mk b/backends/module.mk index 6642a3a281..9e66fba4af 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -1,6 +1,7 @@ MODULE := backends MODULE_OBJS := \ + fs/abstract-fs.o \ fs/amigaos4/amigaos4-fs-factory.o \ fs/ds/ds-fs-factory.o \ fs/palmos/palmos-fs-factory.o \ @@ -17,6 +18,7 @@ MODULE_OBJS := \ midi/coremidi.o \ midi/quicktime.o \ midi/seq.o \ + midi/stmidi.o \ midi/timidity.o \ midi/dmedia.o \ midi/windows.o \ diff --git a/backends/platform/dc/Makefile b/backends/platform/dc/Makefile index 56848504e1..db5861903b 100644 --- a/backends/platform/dc/Makefile +++ b/backends/platform/dc/Makefile @@ -75,7 +75,7 @@ SCUMMVM.BIN : scummvm.bin plugin_dist : for p in plugins/*.plg; do \ - sh-elf-strip -g -o "`basename \"$$p\" | tr '[:lower:]' '[:upper:]'`" "$$p"; \ + sh-elf-strip -g -o "`basename \"$$p\" | LC_CTYPE=C tr '[:lower:]' '[:upper:]'`" "$$p"; \ done dist : SCUMMVM.BIN plugins plugin_dist diff --git a/backends/platform/dc/dc-fs.cpp b/backends/platform/dc/dc-fs.cpp index f4dc4037df..0da77e317e 100644 --- a/backends/platform/dc/dc-fs.cpp +++ b/backends/platform/dc/dc-fs.cpp @@ -34,18 +34,15 @@ * * Parts of this class are documented in the base interface class, AbstractFilesystemNode. */ - -/* A file */ class RoninCDFileNode : public AbstractFilesystemNode { protected: String _path; - static const char *lastPathComponent(const Common::String &str); public: RoninCDFileNode(const String &path) : _path(path) {}; virtual bool exists() const { return true; } - virtual String getName() const { return lastPathComponent(_path); } + virtual String getName() const { return lastPathComponent(_path, '/'); } virtual String getPath() const { return _path; } virtual bool isDirectory() const { return false; } virtual bool isReadable() const { return true; } @@ -61,7 +58,7 @@ public: /* A directory */ class RoninCDDirectoryNode : public RoninCDFileNode { public: - RoninCDDirectoryNode(const String &path) : RoninCDFileNode(path) {}; + RoninCDDirectoryNode(const String &path) : RoninCDFileNode(path) {}; virtual bool isDirectory() const { return true; } virtual AbstractFilesystemNode *getChild(const String &n) const; @@ -77,32 +74,7 @@ public: virtual bool isReadable() const { return false; } }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *RoninCDFileNode::lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - -AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &path) -{ +AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &path) { assert(path.size() > 0); int fd; @@ -110,12 +82,10 @@ AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String & if ((fd = open(path.c_str(), O_RDONLY)) >= 0) { close(fd); return new RoninCDFileNode(path); - } - else if ((fd = open(path.c_str(), O_DIR|O_RDONLY)) >= 0) { + } else if ((fd = open(path.c_str(), O_DIR|O_RDONLY)) >= 0) { close(fd); return new RoninCDDirectoryNode(path); - } - else { + } else { return NULL; } } @@ -168,7 +138,7 @@ AbstractFilesystemNode *RoninCDFileNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); return new RoninCDDirectoryNode(String(start, end - start)); } diff --git a/backends/platform/ds/arm9/source/blitters_arm.s b/backends/platform/ds/arm9/source/blitters_arm.s index 5f7df298b4..48ec316675 100644 --- a/backends/platform/ds/arm9/source/blitters_arm.s +++ b/backends/platform/ds/arm9/source/blitters_arm.s @@ -20,149 +20,12 @@ @ @ @author Robin Watts (robin@wss.co.uk) - .global asmDrawStripToScreen - .global asmCopy8Col .global Rescale_320x256xPAL8_To_256x256x1555 .global Rescale_320x256x1555_To_256x256x1555 .section .itcm,"ax", %progbits .align 2 .code 32 - @ ARM implementation of asmDrawStripToScreen. - @ - @ C prototype would be: - @ - @ extern "C" void asmDrawStripToScreen(int height, - @ int width, - @ byte const *text, - @ byte const *src, - @ byte *dst, - @ int vsPitch, - @ int vsScreenWidth, - @ int textSurfacePitch); - @ - @ In addition, we assume that text, src and dst are all word (4 byte) - @ aligned. This is the same assumption that the old 'inline' version - @ made. -asmDrawStripToScreen: - @ r0 = height - @ r1 = width - @ r2 = text - @ r3 = src - MOV r12,r13 - STMFD r13!,{r4-r7,r9-r11,R14} - LDMIA r12,{r4,r5,r6,r7} - @ r4 = dst - @ r5 = vsPitch - @ r6 = vmScreenWidth - @ r7 = textSurfacePitch - - CMP r0,#0 @ If height<=0 - MOVLE r0,#1 @ height=1 - CMP r1,#4 @ If width<4 - BLT end @ return - - @ Width &= ~4 ? What's that about then? Width &= ~3 I could have - @ understood... - BIC r1,r1,#4 - - SUB r5,r5,r1 @ vsPitch -= width - SUB r6,r6,r1 @ vmScreenWidth -= width - SUB r7,r7,r1 @ textSurfacePitch -= width - MOV r10,#253 - ORR r10,r10,r10,LSL #8 - ORR r10,r10,r10,LSL #16 @ r10 = mask -yLoop: - MOV r14,r1 @ r14 = width -xLoop: - LDR r12,[r2],#4 @ r12 = [text] - LDR r11,[r3],#4 @ r11 = [src] - CMP r12,r10 - BNE singleByteCompare - SUBS r14,r14,#4 - STR r11,[r4], #4 @ r4 = [dst] - BGT xLoop - - ADD r2,r2,r7 @ text += textSurfacePitch - ADD r3,r3,r5 @ src += vsPitch - ADD r4,r4,r6 @ dst += vmScreenWidth - SUBS r0,r0,#1 - BGT yLoop - LDMFD r13!,{r4-r7,r9-r11,PC} - -singleByteCompare: - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - STR r12,[r4],#4 - SUBS r14,r14,#4 - BGT xLoop - - ADD r2,r2,r7 @ text += textSurfacePitch - ADD r3,r3,r5 @ src += vsPitch - ADD r4,r4,r6 @ dst += vmScreenWidth - SUBS r0,r0,#1 - BGT yLoop -end: - LDMFD r13!,{r4-r7,r9-r11,PC} - - - @ ARM implementation of asmCopy8Col - @ - @ C prototype would be: - @ - @ extern "C" void asmCopy8Col(byte *dst, - @ int dstPitch, - @ const byte *src, - @ int height); - @ - @ In addition, we assume that src and dst are both word (4 byte) - @ aligned. This is the same assumption that the old 'inline' version - @ made. -asmCopy8Col: - @ r0 = dst - @ r1 = dstPitch - @ r2 = src - @ r3 = height - STMFD r13!,{r14} - SUB r1,r1,#4 - - TST r3,#1 - ADDNE r3,r3,#1 - BNE roll2 -yLoop2: - LDR r12,[r2],#4 - LDR r14,[r2],r1 - STR r12,[r0],#4 - STR r14,[r0],r1 -roll2: - LDR r12,[r2],#4 - LDR r14,[r2],r1 - SUBS r3,r3,#2 - STR r12,[r0],#4 - STR r14,[r0],r1 - BNE yLoop2 - - LDMFD r13!,{PC} - - @ ARM implementation of Rescale_320x256x1555_To_256x256x1555 @ @ C prototype would be: diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 5c3b87309d..9abaa3c6fb 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -196,6 +196,7 @@ OSystem_SDL::OSystem_SDL() _soundMutex(0), _soundCond(0), _soundThread(0), _soundThreadIsRunning(false), _soundThreadShouldQuit(false), #endif + _fsFactory(0), _savefile(0), _mixer(0), _timer(0), @@ -213,6 +214,19 @@ OSystem_SDL::OSystem_SDL() memset(&_mouseCurState, 0, sizeof(_mouseCurState)); _inited = false; + + + #if defined(__amigaos4__) + _fsFactory = new AmigaOSFilesystemFactory(); + #elif defined(UNIX) + _fsFactory = new POSIXFilesystemFactory(); + #elif defined(WIN32) + _fsFactory = new WindowsFilesystemFactory(); + #elif defined(__SYMBIAN32__) + // Do nothing since its handled by the Symbian SDL inheritance + #else + #error Unknown and unsupported FS backend + #endif } OSystem_SDL::~OSystem_SDL() { @@ -254,17 +268,8 @@ Common::SaveFileManager *OSystem_SDL::getSavefileManager() { } FilesystemFactory *OSystem_SDL::getFilesystemFactory() { - #if defined(__amigaos4__) - return &AmigaOSFilesystemFactory::instance(); - #elif defined(UNIX) - return &POSIXFilesystemFactory::instance(); - #elif defined(WIN32) - return &WindowsFilesystemFactory::instance(); - #elif defined(__SYMBIAN32__) - // Do nothing since its handled by the Symbian SDL inheritance - #else - #error Unknown and unsupported backend in OSystem_SDL::getFilesystemFactory - #endif + assert(_fsFactory); + return _fsFactory; } static Common::String getDefaultConfigFileName() { @@ -292,20 +297,19 @@ static Common::String getDefaultConfigFileName() { CreateDirectory(configFile, NULL); strcat(configFile, "\\" DEFAULT_CONFIG_FILE); - if (fopen(configFile, "r") == NULL) { + FILE *tmp = NULL; + if ((tmp = fopen(configFile, "r")) == NULL) { // Check windows directory char oldConfigFile[MAXPATHLEN]; GetWindowsDirectory(oldConfigFile, MAXPATHLEN); strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE); - if (fopen(oldConfigFile, "r")) { - printf("The default location of the config file (scummvm.ini) in ScummVM has changed,\n"); - printf("under Windows NT4/2000/XP/Vista. You may want to consider moving your config\n"); - printf("file from the old default location:\n"); - printf("%s\n", oldConfigFile); - printf("to the new default location:\n"); - printf("%s\n\n", configFile); + if ((tmp = fopen(oldConfigFile, "r"))) { strcpy(configFile, oldConfigFile); + + fclose(tmp); } + } else { + fclose(tmp); } } else { // Check windows directory @@ -334,23 +338,13 @@ static Common::String getDefaultConfigFileName() { } Common::SeekableReadStream *OSystem_SDL::openConfigFileForReading() { - Common::File *confFile = new Common::File(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + FilesystemNode file(getDefaultConfigFileName()); + return file.openForReading(); } Common::WriteStream *OSystem_SDL::openConfigFileForWriting() { - Common::DumpFile *confFile = new Common::DumpFile(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + FilesystemNode file(getDefaultConfigFileName()); + return file.openForWriting(); } void OSystem_SDL::setWindowCaption(const char *caption) { @@ -435,15 +429,21 @@ void OSystem_SDL::quit() { } void OSystem_SDL::setupIcon() { - int w, h, ncols, nbytes, i; - unsigned int rgba[256], icon[32 * 32]; - unsigned char mask[32][4]; + int x, y, w, h, ncols, nbytes, i; + unsigned int rgba[256]; + unsigned int *icon; sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); - if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { - warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); + if ((w > 512) || (h > 512) || (ncols > 255) || (nbytes > 1)) { + warning("Could not load the built-in icon (%d %d %d %d)", w, h, ncols, nbytes); + return; + } + icon = (unsigned int*)malloc(w*h*sizeof(unsigned int)); + if (!icon) { + warning("Could not allocate temp storage for the built-in icon"); return; } + for (i = 0; i < ncols; i++) { unsigned char code; char color[32]; @@ -457,26 +457,27 @@ void OSystem_SDL::setupIcon() { sscanf(color + 1, "%06x", &col); col |= 0xFF000000; } else { - warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); + warning("Could not load the built-in icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); + free(icon); return; } rgba[code] = col; } - memset(mask, 0, sizeof(mask)); - for (h = 0; h < 32; h++) { - const char *line = scummvm_icon[1 + ncols + h]; - for (w = 0; w < 32; w++) { - icon[w + 32 * h] = rgba[(int)line[w]]; - if (rgba[(int)line[w]] & 0xFF000000) { - mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); - } + for (y = 0; y < h; y++) { + const char *line = scummvm_icon[1 + ncols + y]; + for (x = 0; x < w; x++) { + icon[x + w * y] = rgba[(int)line[x]]; } } - SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); - SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); + SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, w, h, 32, w * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); + if (!sdl_surf) { + warning("SDL_CreateRGBSurfaceFrom(icon) failed"); + } + SDL_WM_SetIcon(sdl_surf, NULL); SDL_FreeSurface(sdl_surf); + free(icon); } OSystem::MutexRef OSystem_SDL::createMutex(void) { diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 1c1381ec5c..d07dcee679 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -400,14 +400,13 @@ protected: void deinitThreadedMixer(); #endif - + FilesystemFactory *_fsFactory; Common::SaveFileManager *_savefile; Audio::MixerImpl *_mixer; SDL_TimerID _timerID; Common::TimerManager *_timer; - protected: void addDirtyRgnAuto(const byte *buf); void makeChecksums(const byte *buf); diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl index 12e5f8f0c4..d575a1de38 100644 --- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl +++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl @@ -3,10 +3,10 @@ @WorkingEngines = qw( scumm agos sky queen gob saga drascula - kyra lure agi touche parallaction + kyra lure agi touche parallaction cine ); @TestingEngines = qw( - cruise igor made m4 cine + cruise igor made m4 ); @BrokenEngines = qw( sword1 diff --git a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg index 67d9d83160..bf3c69ae08 100644 --- a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg +++ b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg @@ -16,7 +16,7 @@ ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ; ; $URL:$ -; $Id$ +; $Id:$ ; ; diff --git a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg index 3afb7a094c..3f88ec918c 100644 --- a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg +++ b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg @@ -52,6 +52,7 @@ "..\..\..\..\dists\engine-data\sky.cpt"-"!:\system\apps\scummvm\sky.cpt" "..\..\..\..\dists\engine-data\igor.tbl"-"!:\system\apps\scummvm\igor.tbl" "..\..\..\..\dists\engine-data\lure.dat"-"!:\system\apps\scummvm\lure.dat" +"..\..\..\..\dists\engine-data\drascula.dat"-"!:\system\apps\scummvm\drascula.dat" ; Config/log files: 'empty' will automagically be removed on uninstall ""-"!:\system\apps\ScummVM\scummvm.ini",FILENULL diff --git a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg index 32df2aee8b..6bd1fbd047 100644 --- a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg +++ b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg @@ -63,6 +63,7 @@ "..\..\..\..\dists\engine-data\sky.cpt"-"c:\data\scummvm\sky.cpt" "..\..\..\..\dists\engine-data\igor.tbl"-"c:\data\scummvm\igor.tbl" "..\..\..\..\dists\engine-data\lure.dat"-"c:\data\scummvm\lure.dat" +"..\..\..\..\dists\engine-data\drascula.dat"-"c:\data\drascula.dat" ; Config/log files: 'empty' will automagically be removed on uninstall ""-"c:\data\scummvm\scummvm.ini",FILENULL diff --git a/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg b/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg index 94d457b93a..29e318a479 100644 --- a/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg +++ b/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg @@ -53,6 +53,7 @@ "..\..\..\..\dists\engine-data\sky.cpt"-"!:\system\apps\scummvm\sky.cpt" "..\..\..\..\dists\engine-data\igor.tbl"-"!:\system\apps\scummvm\igor.tbl" "..\..\..\..\dists\engine-data\lure.dat"-"!:\system\apps\scummvm\lure.dat" +"..\..\..\..\dists\engine-data\drascula.dat"-"!:\system\apps\scummvm\drascula.dat" ; Config/log files: 'empty' will automagically be removed on uninstall ""-"!:\system\apps\ScummVM\scummvm.ini",FILENULL diff --git a/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg b/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg index ca7f08d85f..0173da7699 100644 --- a/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg +++ b/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg @@ -53,6 +53,7 @@ "..\..\..\..\dists\engine-data\sky.cpt"-"!:\system\apps\scummvm\sky.cpt" "..\..\..\..\dists\engine-data\igor.tbl"-"!:\system\apps\scummvm\igor.tbl" "..\..\..\..\dists\engine-data\lure.dat"-"!:\system\apps\scummvm\lure.dat" +"..\..\..\..\dists\engine-data\drascula.dat"-"!:\system\apps\scummvm\drascula.dat" ; Config/log files: 'empty' will automagically be removed on uninstall ""-"!:\system\apps\ScummVM\scummvm.ini",FILENULL diff --git a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg index 8a121227bc..aca927eadd 100644 --- a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg +++ b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg @@ -16,7 +16,7 @@ ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ; ; $URL:$ -; $Id$ +; $Id:$ ; ; diff --git a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg index 5aad403074..0883c88a21 100644 --- a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg +++ b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg @@ -61,6 +61,7 @@ "..\..\..\..\dists\engine-data\sky.cpt"-"c:\shared\scummvm\sky.cpt" "..\..\..\..\dists\engine-data\igor.tbl"-"c:\shared\scummvm\igor.tbl" "..\..\..\..\dists\engine-data\lure.dat"-"c:\shared\scummvm\lure.dat" +"..\..\..\..\dists\engine-data\drascula.dat"-"c:\shared\scummvm\drascula.dat" ; Config/log files: 'empty' will automagically be removed on uninstall ""-"c:\shared\scummvm\scummvm.ini",FILENULL diff --git a/backends/platform/symbian/src/SymbianActions.cpp b/backends/platform/symbian/src/SymbianActions.cpp index 60e402632f..e71b242329 100644 --- a/backends/platform/symbian/src/SymbianActions.cpp +++ b/backends/platform/symbian/src/SymbianActions.cpp @@ -153,7 +153,7 @@ void SymbianActions::initInstanceGame() { // Save - if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble) + if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble) _action_enabled[ACTION_SAVE] = false; else { _action_enabled[ACTION_SAVE] = true; diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index 0ce44d1704..90bd99fa7d 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -123,10 +123,6 @@ void OSystem_SDL_Symbian::setFeatureState(Feature f, bool enable) { } } -FilesystemFactory *OSystem_SDL_Symbian::getFilesystemFactory() { - return &SymbianFilesystemFactory::instance(); -} - static Common::String getDefaultConfigFileName() { char configFile[MAXPATHLEN]; strcpy(configFile, Symbian::GetExecutablePath()); @@ -134,33 +130,13 @@ static Common::String getDefaultConfigFileName() { return configFile; } -Common::SeekableReadStream *OSystem_SDL_Symbian::openConfigFileForReading() { - Common::File *confFile = new Common::File(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; -} - -Common::WriteStream *OSystem_SDL_Symbian::openConfigFileForWriting() { - Common::DumpFile *confFile = new Common::DumpFile(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; -} - - OSystem_SDL_Symbian::zoneDesc OSystem_SDL_Symbian::_zones[TOTAL_ZONES] = { { 0, 0, 320, 145 }, { 0, 145, 150, 55 }, { 150, 145, 170, 55 } }; OSystem_SDL_Symbian::OSystem_SDL_Symbian() :_channels(0),_stereo_mix_buffer(0) { + _RFs = &CEikonEnv::Static()->FsSession(); } void OSystem_SDL_Symbian::initBackend() { @@ -184,6 +160,8 @@ void OSystem_SDL_Symbian::initBackend() { actions->initInstanceMain(this); actions->loadMapping(); initZones(); + + _fsFactory = new SymbianFilesystemFactory(); } OSystem_SDL_Symbian::~OSystem_SDL_Symbian() { @@ -488,6 +466,10 @@ void OSystem_SDL_Symbian::initZones() { } } +RFs& OSystem_SDL_Symbian::FsSession() { + return *_RFs; +} + FILE* symbian_fopen(const char* name, const char* mode) { TSymbianFileEntry* fileEntry = new TSymbianFileEntry; fileEntry->iInputPos = KErrNotFound; @@ -516,22 +498,22 @@ FILE* symbian_fopen(const char* name, const char* mode) { switch(mode[0]) { case 'a': - if (fileEntry->iFileHandle.Open(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { - if (fileEntry->iFileHandle.Create(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { + if (fileEntry->iFileHandle.Open(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { + if (fileEntry->iFileHandle.Create(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { delete fileEntry; fileEntry = NULL; } } break; case 'r': - if (fileEntry->iFileHandle.Open(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { + if (fileEntry->iFileHandle.Open(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { delete fileEntry; fileEntry = NULL; } break; case 'w': - if (fileEntry->iFileHandle.Replace(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { + if (fileEntry->iFileHandle.Replace(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { delete fileEntry; fileEntry = NULL; } diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h index 68a6fb492f..80329d984e 100644 --- a/backends/platform/symbian/src/SymbianOS.h +++ b/backends/platform/symbian/src/SymbianOS.h @@ -33,6 +33,7 @@ #endif #define TOTAL_ZONES 3 +class RFs; class OSystem_SDL_Symbian : public OSystem_SDL { public: @@ -70,10 +71,6 @@ protected: // static void symbianMixCallback(void *s, byte *samples, int len); - virtual FilesystemFactory *getFilesystemFactory(); - - virtual Common::SeekableReadStream *openConfigFileForReading(); - virtual Common::WriteStream *openConfigFileForWriting(); public: // vibration support #ifdef USE_VIBRA_SE_PXXX @@ -134,6 +131,7 @@ protected: } zoneDesc; static zoneDesc _zones[TOTAL_ZONES]; + RFs* _RFs; }; #endif diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h index 4577824b33..02436d7c35 100644 --- a/backends/platform/symbian/src/portdefs.h +++ b/backends/platform/symbian/src/portdefs.h @@ -134,7 +134,6 @@ #ifndef __WINS__ #define USE_ARM_GFX_ASM -#define ARM_USE_GFX_ASM #define USE_ARM_SMUSH_ASM #define USE_ARM_COSTUME_ASM #define USE_ARM_SOUND_ASM diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 3626c4c10b..7f78517762 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -147,7 +147,7 @@ void CEActionsPocket::initInstanceGame() { _key_action[POCKET_ACTION_PAUSE].setKey(VK_SPACE); _action_enabled[POCKET_ACTION_PAUSE] = true; // Save - if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble) + if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble) _action_enabled[POCKET_ACTION_SAVE] = false; else if (is_queen) { _action_enabled[POCKET_ACTION_SAVE] = true; diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index 87f73f5a66..0c4113cc0c 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -130,7 +130,7 @@ void CEActionsSmartphone::initInstanceGame() { // Initialize keys for different actions // Save - if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble) + if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble) _action_enabled[SMARTPHONE_ACTION_SAVE] = false; else if (is_queen) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile index 4400d50e3a..9f040bbed1 100644 --- a/backends/platform/wince/Makefile +++ b/backends/platform/wince/Makefile @@ -45,8 +45,8 @@ ENABLE_DRASCULA = STATIC_PLUGIN USE_MAD = 1 USE_MPEG2 = 1 -USE_TREMOR = 1 -#USE_TREMOLO = 1 +#USE_TREMOR = 1 +USE_TREMOLO = 1 USE_FLAC = 1 USE_ZLIB = 1 @@ -139,7 +139,7 @@ LIBS += -ltremorce endif ifdef USE_TREMOLO -DEFINES += -DUSE_TREMOR -DUSE_VORBIS +DEFINES += -DUSE_TREMOR -DUSE_VORBIS -DUSE_TREMOLO INCLUDES += -Ilibs/include/tremolo LIBS += -llibTremolo endif diff --git a/backends/platform/wince/README-WinCE.txt b/backends/platform/wince/README-WinCE.txt index f4cb00dcfa..86c627d764 100644 --- a/backends/platform/wince/README-WinCE.txt +++ b/backends/platform/wince/README-WinCE.txt @@ -1,29 +1,28 @@ ScummVM Windows CE FAQ Last updated: $Date$ -Release version: 0.11.0 +Release version: 0.12.0 ------------------------------------------------------------------------ New in this version ------------------- -0.11.0 -- Redesigned 'Free Look' action (Pocket PCs) -In order to accommodate for the requirements of the lure engine, the -usage characteristics of the 'Free Look' action have been improved. The -new behavior is available for use in all engines, but is is *strongly* -recommended for at least when playing 'Lure of the Temptress'. By using -the new scheme, when in 'Free Look' mode, it is now possible to enter -left clicks by clicking a second time near the current location of the -mouse pointer. Left and Right clicks at the current point location -are also available by using the respective actions' bound key. +0.12.0: +- Improved SMUSH support (deprecated 'Smush_force_redraw' option) +No skipped frames in Full Throttle action sequences. The 'Smush_force_redraw' +option is not needed/honored anymore. -- Reduced optimization build -The ScummVM executable has grown quite large, prohibiting some devices -from running memory demanding games (or any games at all). Code -optimization level has been reduced to offset the growth of the executable. -Games run slightly slower. This will be addressed before next release. +- Fixed MultiFuntion key in Full Throttle -- Several bugfixes +- Improved sound output +Fixed a long standing bug which led to distorted sound output in all games. + +- Switched to faster ogg vorbis library +Robin Watts' libTremolo is used for ogg vorbis (tremor) replay. Info patch +by Lostech. + +- New right click through double tap inhibiting option +Check out the 'no_doubletap_rightclick' option if double-tapping as a right +click input method annoys you. Patch by spookypeanut. ------------------------------------------------------------------------ @@ -109,10 +108,10 @@ and report your success ... How do I install ScummVM for Windows CE ? ----------------------------------------- -Simple! Unpack the release package on your desktop pc, then copy all its contents -to a folder on your device. Typically, you should at least have scummvm.exe, -modern.ini and modern.zip in the same directory. Finally, upload your beloved games -and fire it up :-) +Simple! Unpack the release package on your desktop pc, then copy all its +contents to a folder on your device. Typically, you should at least have +scummvm.exe, modern.ini and modern.zip in the same directory. Finally, upload +your beloved games and fire it up :-) Some devices (like Pocket PC 2000) require GAPI to be present. @@ -184,18 +183,19 @@ The following actions are available : * Right click : acts as a right mouse button click * Cursor : hide or display the mouse cursor * Free look : go in or out of free-look mode. In this mode, you can tap - the screen to look for interesting locations without walking. - Cling a second time near the pointer's location equals to left click. + the screen to look for interesting locations without + walking. Click a second time near the pointer's location + equals to a left click. * Zoom up : magnify the upper part of the screen for 640x480 games rendered on a QVGA device. * Zoom down : magnify the lower part of the screen for 640x480 games rendered on a QVGA device. - * Multi Function : this key performs a different function depending on the game - : Full Throttle -> win an action sequence (cheat) - : Fate of Atlantis -> sucker punch (cheat) - : Bargon -> F1 (start the game) - : All AGI games -> bring up the predictive input dialog - * Bind keys : map a key action to a device button + * Multi Function : performs a different function depending on the game : + Full Throttle -> win an action sequence (cheat) + Fate of Atlantis -> sucker punch (cheat) + Bargon -> F1 (start the game) + All AGI games -> bring up the predictive input dialog + * Bind keys map a key action to a device button * Up,Down,Left : Right, : emulate mouse/stylus behavior Left Click : @@ -245,11 +245,11 @@ the list of available actions for Smartphones: * Skip : skip a non interactive sequence, the current dialog or behaves like the ESC key on a regular keyboard * Zone : switch between the 3 different mouse zones - * Multi Function : this key performs a different function depending on the game - : Full Throttle -> win an action sequence (cheat) - : Fate of Atlantis -> sucker punch (cheat) - : Bargon -> F1 (start the game) - : All AGI games -> bring up the predictive input dialog + * Multi Function : performs a different function depending on the game + Full Throttle -> win an action sequence (cheat) + Fate of Atlantis -> sucker punch (cheat) + Bargon -> F1 (start the game) + All AGI games -> bring up the predictive input dialog * Bind keys : map a key action to a device button * Keyboard : hide or display the virtual keyboard * Rotate : rotate the screen (also rotates dpad keys) @@ -287,32 +287,34 @@ Some parameters are specific to this port : Game specific sections (f.e. [monkey2]) - performance options - * high_sample_rate bool Desktop quality (22 kHz) sound output if set. - 11 kHz otherwise. The default is 11 kHz. - If you have a fast device, you can set this to - true to enjoy better sound effects and music. + * high_sample_rate bool Desktop quality (22 kHz) sound output if + set. The default is 11 kHz. + If you have a fast device, you can set this + to true to enjoy better sound effects and + music. * FM_high_quality bool Desktop quality FM synthesis if set. Lower - quality otherwise. The default is low quality. - You can change this if you have a fast device. - * sound_thread_priority int Set the priority of the sound thread (0, 1, 2). - Depending on the release, this is set to 1 - internally (above normal). If you get sound - stuttering try setting this to a higher value. + quality otherwise. The default is low + quality. You can change this if you have a + fast device. + * sound_thread_priority int Set the priority of the sound thread (0, 1, + 2). Depending on the release, this is set + to 1 internally (above normal). + If you get sound stuttering try setting + this to a higher value. Set to 0 if your device is fast enough or if - you prefer better audio/video synchronization. - * Smush_force_redraw int Force a Smush frame redraw every X missed - frames. Mainly used for Full Throttle action - sequences. Setting it lower gives more - priority to screen redraws. Setting it higher - gives more priority to stylus/keyboard input. - The default is 30. + you prefer better audio/video sync. Game specific sections (f.e. [monkey2]) - game options - * landscape int 0: Portrait, 1: Landscape, 2: Inverse Landscape - You can also use this in the [scummvm] section - in QVGA Pocket PCs to display the launcher in - landscape, for example, at startup. + * landscape int 0: Portrait, 1: Landscape, + 2: Inverse Landscape. + You can also use this in the [scummvm] + section to display the launcher in landscape + for example, at startup. + * no_doubletap_rightclick int 1: Turn off the default behavior of + simulating a right-click when the screen is + double-tapped. + [scummvm] section - keys definition @@ -335,18 +337,18 @@ You can tweak these parameters to customize how the cursor is handled. consider being repeated. * repeatX int Number of key repeat events before changing horizontal cursor behaviour. - * stepX1 int Horizontal cursor offset value when the key is - not repeated. - * stepX2 int Horizontal cursor offset value when the key is - repeated less than repeatX. - * stepX3 int Horizontal cursor offset value when the key is - repeated more than repeatX. + * stepX1 int Horizontal cursor offset value when the key + is not repeated. + * stepX2 int Horizontal cursor offset value when the key + is repeated less than repeatX. + * stepX3 int Horizontal cursor offset value when the key + is repeated more than repeatX. * repeatY int Number of key repeat events before changing - vertical cursor behaviour. + vertical cursor behavior. * stepY1 int Vertical cursor offset value when the key is not repeated. - * stepY2 int Horizontal cursor offset value when the key is - repeated less than repeatY. + * stepY2 int Horizontal cursor offset value when the key + is repeated less than repeatY. * stepY3 int Vertical cursor offset value when the key is repeated more than repeatY. @@ -361,8 +363,8 @@ Game specific questions I need to press a special key ----------------------------- -Bring up the virtual keyboard. On Smartphones take a look at the Keyboard action above. -On Pocket PCs it's easier to double-tap at the top of the screen. +Bring up the virtual keyboard. On Smartphones take a look at the Keyboard +action above. On Pocket PCs it's easier to double-tap at the top of the screen. The panel is obscuring the playfield area ----------------------------------------- @@ -383,17 +385,18 @@ Bind and use the quit action to quit. I cannot rotate the screen to landscape/inverse landscape --------------------------------------------------------- -Depending on the video driver, ScummVM may opt to not provide such functionality. -In general, when ScummVM starts in normal "portrait" orientation, the device driver -reports better display characteristics and you should consider launching from portrait. +Depending on the video driver, ScummVM may opt to not provide such +functionality. In general, when ScummVM starts in normal "portrait" +orientation, the device driver reports better display characteristics and you +should consider launching from portrait. I'm having problems. Is there diagnostic output available ? ----------------------------------------------------------- Insert a line in the [scummvm] section of scummvm.ini with the following: debuglevel=1 -Run ScummVM. When it closes scummvm_stdout.txt and scummvm_stderr.txt files will be -available at the program directory (see section above). +Run ScummVM. When it closes scummvm_stdout.txt and scummvm_stderr.txt files +will be available at the program directory (see section above). ScummVM crashes and returns to desktop -------------------------------------- @@ -548,18 +551,19 @@ Use the Multi Function action. -- AGI engine games -- ---------------------- -Do you expect me to play these games on keyboard less devices ? +Do you expect me to play these games on keyboard-less devices ? --------------------------------------------------------------- Sure we do :-) -If you want to get some mileage on your stylus you can use the virtual keyboard. -There is a very useful alternative though, the AGI engine's predictive input dialog. -It requires a dictionary to be present. Just tap on the command line or use the -Multi Function action to bring it up. On Smartphones, when the dialog is shown -all key mapping is disabled temporarily (including mouse emulation). Input is -performed either by pressing the phone's numeric keypad keys and dpad enter to -close the dialog, or by navigating the buttons using the dpad arrows and pressing -with dpad enter. Check the main Readme file for more information on this. +If you want to get some mileage on your stylus you can use the virtual +keyboard. There is a very useful alternative though, the AGI engine's +predictive input dialog. It requires a dictionary to be present. Just tap on +the command line or use the Multi Function action to bring it up. On +Smartphones, when the dialog is shown all key mapping is disabled temporarily +(including mouse emulation). Input is performed either by pressing the phone's +numeric keypad keys and dpad enter to close the dialog, or by navigating the +buttons using the dpad arrows and pressing with dpad enter. Check the main +Readme file for more information on this. --------------------------- -- Lure of the Temptress -- @@ -595,8 +599,9 @@ I think I found a bug, ScummVM crashes in ... See the "Reporting Bugs" section in ScummVM readme. -If you have a Pocket PC or Handheld PC, be sure to include its resolution (obtained -on the second dialog displayed on the "About" menu) in your bug report. +If you have a Pocket PC or Handheld PC, be sure to include its resolution +(obtained on the second dialog displayed on the "About" menu) in your bug +report. If you cannot reproduce this bug on another ScummVM version, you can cross post your bug report on ScummVM forums. @@ -619,6 +624,26 @@ http://www.scummvm.org/ Old news follow ... ------------------------------------------------------------------------ +0.11.0: +- Redesigned 'Free Look' action (Pocket PCs) +In order to accommodate for the requirements of the lure engine, the +usage characteristics of the 'Free Look' action have been improved. The +new behavior is available for use in all engines, but is is *strongly* +recommended for at least when playing 'Lure of the Temptress'. By using +the new scheme, when in 'Free Look' mode, it is now possible to enter +left clicks by clicking a second time near the current location of the +mouse pointer. Left and Right clicks at the current point location +are also available by using the respective actions' bound key. + +- Reduced optimization build +The ScummVM executable has grown quite large, prohibiting some devices +from running memory demanding games (or any games at all). Code +optimization level has been reduced to offset the growth of the executable. +Games run slightly slower. This will be addressed before next release. + +- Several bugfixes + + 0.10.0: Major improvements have taken place in this version, mostly for behind- the-scenes stuff. First, we have migrated to GCC for building the Windows diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 48f157f6ff..f09a483086 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -461,7 +461,7 @@ OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(), _orientationLandscape(0), _newOrientation(0), _panelInitialized(false), _panelVisible(true), _panelStateForced(false), _forceHideMouse(false), _unfilteredkeys(false), _freeLook(false), _forcePanelInvisible(false), _toolbarHighDrawn(false), _zoomUp(false), _zoomDown(false), - _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), + _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), _noDoubleTapRMB(false), _saveToolbarState(false), _saveActiveToolbar(NAME_MAIN_PANEL), _rbutton(false), _hasfocus(true), _usesEmulatedMouse(false), _mouseBackupOld(NULL), _mouseBackupToolbar(NULL), _mouseBackupDim(0) { @@ -1059,14 +1059,11 @@ void OSystem_WINCE3::update_game_settings() { panel->setVisible(false); _saveToolbarState = true; - - // Set Smush Force Redraw rate for Full Throttle - if (!ConfMan.hasKey("Smush_force_redraw")) { - ConfMan.setInt("Smush_force_redraw", 30); - ConfMan.flushToDisk(); - } } + if (ConfMan.hasKey("no_doubletap_rightclick")) + _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick"); + compute_sample_rate(); } @@ -2340,7 +2337,7 @@ bool OSystem_WINCE3::pollEvent(Common::Event &event) { if (_closeClick && (GetTickCount() - _tapTime < 1000)) { if (event.mouse.y <= 20 && _panelInitialized) { // top of screen (show panel) swap_panel_visibility(); - } else { // right click + } else if (!_noDoubleTapRMB) { // right click event.type = Common::EVENT_RBUTTONDOWN; _rbutton = true; } diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h index 8853c156d8..ece8c9b7b1 100644 --- a/backends/platform/wince/wince-sdl.h +++ b/backends/platform/wince/wince-sdl.h @@ -200,6 +200,7 @@ private: bool _zoomUp; // zooming up mode bool _zoomDown; // zooming down mode + bool _noDoubleTapRMB; // disable double tap -> rmb click bool _rbutton; // double tap -> right button simulation bool _closeClick; // flag when taps are spatially close together diff --git a/backends/saves/compressed/compressed-saves.cpp b/backends/saves/compressed/compressed-saves.cpp index 150cf5c47d..0c4fec0e24 100644 --- a/backends/saves/compressed/compressed-saves.cpp +++ b/backends/saves/compressed/compressed-saves.cpp @@ -62,7 +62,7 @@ public: _stream.zfree = Z_NULL; _stream.opaque = Z_NULL; - // Verify file header is correct once more + // Verify file header is correct w->seek(0, SEEK_SET); uint16 header = w->readUint16BE(); assert(header == 0x1F8B || @@ -133,27 +133,34 @@ public: } void seek(int32 offset, int whence = SEEK_SET) { int32 newPos = 0; + assert(whence != SEEK_END); // SEEK_END not supported switch(whence) { - case SEEK_END: - newPos = size() - offset; - break; case SEEK_SET: newPos = offset; break; case SEEK_CUR: newPos = _pos + offset; } - offset = newPos - _pos; - - if (offset < 0) - error("Backward seeking not supported in compressed savefiles"); + + assert(newPos >= 0); + + if ((uint32)newPos < _pos) { + // To search backward, we have to restart the whole decompression + // from the start of the file. A rather wasteful operation, best + // to avoid it. :/ +#if DEBUG + warning("Backward seeking in CompressedInSaveFile detected"); +#endif + _pos = 0; + _wrapped->seek(0, SEEK_SET); + _zlibErr = inflateReset(&_stream); + if (_zlibErr != Z_OK) + return; + _stream.next_in = _buf; + _stream.avail_in = 0; + } - // We could implement backward seeking, but it is tricky to do efficiently. - // A simple solution would be to restart the whole decompression from the - // start of the file. Or we could decompress the whole file in one go - // in the constructor, and wrap it into a MemoryReadStream -- but that - // would be rather wasteful. As long as we don't need it, I'd rather not - // implement this at all. -- Fingolfin + offset = newPos - _pos; // Skip the given amount of data (very inefficient if one tries to skip // huge amounts of data, but usually client code will only skip a few diff --git a/base/plugins.cpp b/base/plugins.cpp index 216c6ef1af..90e615e709 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -157,9 +157,12 @@ public: #if defined(UNIX) && defined(USE_ALSA) LINK_PLUGIN(ALSA) #endif - #if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) + #if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__) LINK_PLUGIN(SEQ) #endif + #if defined(__MINT__) + LINK_PLUGIN(STMIDI) + #endif #if defined(IRIX) LINK_PLUGIN(DMEDIA) #endif diff --git a/base/version.cpp b/base/version.cpp index 8de96d0b78..3f41e4febe 100644 --- a/base/version.cpp +++ b/base/version.cpp @@ -62,7 +62,12 @@ const char *gScummVMVersionDate = SCUMMVM_VERSION " (" __DATE__ " " __TIME__ ")" const char *gScummVMFullVersion = "ScummVM " SCUMMVM_VERSION " (" __DATE__ " " __TIME__ ")"; const char *gScummVMFeatures = "" #ifdef USE_TREMOR +#ifdef USE_TREMOLO + // libTremolo is used on WinCE for better ogg performance + "Tremolo " +#else "Tremor " +#endif #else #ifdef USE_VORBIS "Vorbis " diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp index 522b24163e..1b0db4755a 100644 --- a/common/advancedDetector.cpp +++ b/common/advancedDetector.cpp @@ -82,12 +82,12 @@ static void upgradeTargetIfNecessary(const Common::ADParams ¶ms) { if (params.obsoleteList == 0) return; - const char *gameid = ConfMan.get("gameid").c_str(); + String gameid = ConfMan.get("gameid"); for (const Common::ADObsoleteGameID *o = params.obsoleteList; o->from; ++o) { - if (!scumm_stricmp(gameid, o->from)) { + if (gameid.equalsIgnoreCase(o->from)) { gameid = o->to; - ConfMan.set("gameid", o->to); + ConfMan.set("gameid", gameid); if (o->platform != Common::kPlatformUnknown) ConfMan.set("platform", Common::getPlatformCode(o->platform)); diff --git a/common/archive.cpp b/common/archive.cpp new file mode 100644 index 0000000000..b963cf4ceb --- /dev/null +++ b/common/archive.cpp @@ -0,0 +1,288 @@ +/* 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/archive.h" +#include "common/fs.h" +#include "common/file.h" +#include "common/util.h" + +namespace Common { + + +FSDirectory::FSDirectory(const FilesystemNode &node, int depth) + : _node(node), _cached(false), _depth(depth) { +} + +FSDirectory::FSDirectory(const String &name, int depth) + : _node(name), _cached(false), _depth(depth) { +} + +FSDirectory::~FSDirectory() { +} + +FilesystemNode FSDirectory::getFSNode() const { + return _node; +} + +FilesystemNode FSDirectory::lookupCache(NodeCache &cache, const String &name) { + // make caching as lazy as possible + if (!name.empty()) { + if (!_cached) { + cacheDirectoryRecursive(_node, _depth, ""); + _cached = true; + } + + if (cache.contains(name)) + return cache[name]; + } + + return FilesystemNode(); +} + +bool FSDirectory::hasFile(const String &name) { + if (name.empty() || !_node.isDirectory()) { + return false; + } + + FilesystemNode node = lookupCache(_fileCache, name); + return node.exists(); +} + +FilePtr FSDirectory::openFile(const String &name) { + if (name.empty() || !_node.isDirectory()) { + return FilePtr(); + } + + FilesystemNode node = lookupCache(_fileCache, name); + + if (!node.exists()) { + warning("FSDirectory::openFile: Trying to open a FilesystemNode which does not exist"); + return FilePtr(); + } else if (node.isDirectory()) { + warning("FSDirectory::openFile: Trying to open a FilesystemNode which is a directory"); + return FilePtr(); + } + + SeekableReadStream *stream = node.openForReading(); + if (!stream) { + warning("FSDirectory::openFile: Can't create stream for file '%s'", name.c_str()); + } + + return FilePtr(stream); +} + +SharedPtr<FSDirectory> FSDirectory::getSubDirectory(const String &name) { + if (name.empty() || !_node.isDirectory()) { + // return a null SharedPtr + return SharedPtr<FSDirectory>(); + } + + FilesystemNode node = lookupCache(_subDirCache, name); + return SharedPtr<FSDirectory>(new FSDirectory(node)); +} + +void FSDirectory::cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix) { + if (depth <= 0) { + return; + } + + FSList list; + node.getChildren(list, FilesystemNode::kListAll, false); + + FSList::iterator it = list.begin(); + for ( ; it != list.end(); it++) { + String name = prefix + (*it).getName(); + + // don't touch name as it might be used for warning messages + String lowercaseName = name; + lowercaseName.toLowercase(); + + // since the hashmap is case insensitive, we need to check for clashes when caching + if ((*it).isDirectory()) { + if (_subDirCache.contains(lowercaseName)) { + warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring sub-directory '%s'", name.c_str()); + } else { + cacheDirectoryRecursive(*it, depth - 1, lowercaseName + "/"); + _subDirCache[lowercaseName] = *it; + } + } else { + if (_fileCache.contains(lowercaseName)) { + warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring file '%s'", name.c_str()); + } else { + _fileCache[lowercaseName] = *it; + } + } + } + +} + +int FSDirectory::matchPattern(StringList &list, const String &pattern) { + if (pattern.empty() || !_node.isDirectory()) { + return 0; + } + + if (!_cached) { + cacheDirectoryRecursive(_node, _depth, ""); + _cached = true; + } + + int matches = 0; + + // need to match lowercase key + String lowercasePattern = pattern; + lowercasePattern.toLowercase(); + + // Full *key* match, with path separators (backslashes) considered + // as normal characters. + NodeCache::iterator it = _fileCache.begin(); + for ( ; it != _fileCache.end(); it++) { + if (matchString((*it)._key.c_str(), lowercasePattern.c_str())) { + list.push_back((*it)._key.c_str()); + } + } + + return matches; +} + + + + + +SearchSet::SearchSet() { + +} + +SearchSet::~SearchSet() { + +} + +SearchSet::ArchiveList::iterator SearchSet::find(const String &name) const { + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._name == name) { + break; + } + } + return it; +} + +/* + Keep the nodes sorted according to descending priorities. + In case two or node nodes have the same priority, insertion + order prevails. +*/ +void SearchSet::insert(const Node &node) { + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._priority < node._priority) { + break; + } + } + _list.insert(it, node); +} + +void SearchSet::add(const String& name, ArchivePtr archive, uint priority) { + if (find(name) == _list.end()) { + Node node = { priority, name, archive }; + insert(node); + } else { + warning("SearchSet::add: archive '%s' already present", name.c_str()); + } + +} + +void SearchSet::remove(const String& name) { + ArchiveList::iterator it = find(name); + if (it != _list.end()) { + _list.erase(it); + } +} + +void SearchSet::clear() { + _list.clear(); +} + +void SearchSet::setPriority(const String& name, uint priority) { + ArchiveList::iterator it = find(name); + if (it == _list.end()) { + warning("SearchSet::setPriority: archive '%s' is not present", name.c_str()); + return; + } + + if (priority == (*it)._priority) { + return; + } + + Node node(*it); + _list.erase(it); + node._priority = priority; + insert(node); +} + +bool SearchSet::hasFile(const String &name) { + if (name.empty()) { + return false; + } + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._arc->hasFile(name)) { + return true; + } + } + + return false; +} + +int SearchSet::matchPattern(StringList &list, const String &pattern) { + // Shall we short circuit out if pattern is empty? + + int matches = 0; + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + matches += (*it)._arc->matchPattern(list, pattern); + } + + return matches; +} + +FilePtr SearchSet::openFile(const String &name) { + if (name.empty()) { + return FilePtr(); + } + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._arc->hasFile(name)) { + return (*it)._arc->openFile(name); + } + } + + return FilePtr(); +} + + +} // namespace Common diff --git a/common/archive.h b/common/archive.h new file mode 100644 index 0000000000..636fb6383f --- /dev/null +++ b/common/archive.h @@ -0,0 +1,201 @@ +/* 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_ARCHIVES_H +#define COMMON_ARCHIVES_H + +#include "common/fs.h" +#include "common/str.h" +#include "common/hash-str.h" +#include "common/list.h" +#include "common/ptr.h" +#include "common/stream.h" + +namespace Common { + +typedef SharedPtr<SeekableReadStream> FilePtr; + +/** + * Archive allows searches of (file)names into an arbitrary container. + * It also supports opening a file and returning an usable input stream. + */ +class Archive { +public: + virtual ~Archive() { } + + /** + * Check if a name is present in the Archive. Patterns are not allowed, + * as this is meant to be a quick File::exists() replacement. + */ + virtual bool hasFile(const String &name) = 0; + + /** + * Add names to the provided list according to the pattern. Returned + * names can be used as parameters to fileOpen. + * Must not remove elements from the list. + * + * @return The number of names added to list. + */ + virtual int matchPattern(StringList &list, const String &pattern) = 0; + + /** + * Add all the names present in the Archive. Returned + * names can be used as parameters to fileOpen. + * Must not remove elements from the list. + * + * @return The number of names added to list. + */ + virtual int getAllNames(StringList &list) { + return matchPattern(list, "*"); + } + + /** + * Create a stream bound to a file in the archive. + * @return The newly created input stream. + */ + virtual FilePtr openFile(const String &name) = 0; +}; + + +typedef SharedPtr<Archive> ArchivePtr; + + +/** + * FSDirectory models a directory tree from the filesystem and allows users + * to access it through the Archive interface. FSDirectory can represent a + * single directory, or a tree with specified depth, rooted in a 'base' + * directory. + * Searching is case-insensitive, as the main intended goal is supporting + * retrieval of game data. First case-insensitive match is returned when + * searching, thus making FSDirectory heavily dependant on the underlying + * FilesystemNode implementation. + */ +class FSDirectory : public Archive { + FilesystemNode _node; + + // Caches are case insensitive, clashes are dealt with when creating + // Key is stored in lowercase. + typedef HashMap<String, FilesystemNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache; + NodeCache _fileCache, _subDirCache; + + // look for a match + FilesystemNode lookupCache(NodeCache &cache, const String &name); + + // cache management + void cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix); + bool _cached; + int _depth; + +public: + /** + * Create a FSDirectory representing a tree with the specified depth. Will result in an + * unbound FSDirectory if name is not found on the filesystem or is not a directory. + */ + FSDirectory(const String &name, int depth = 1); + + /** + * Create a FSDirectory representing a tree with the specified depth. Will result in an + * unbound FSDirectory if node does not exist or is not a directory. + */ + FSDirectory(const FilesystemNode &node, int depth = 1); + + virtual ~FSDirectory(); + + /** + * This return the underlying FSNode of the FSDirectory. + */ + FilesystemNode getFSNode() const; + + /** + * Create a new FSDirectory pointing to a sub directory of the instance. + * @return A new FSDirectory instance conveniently wrapped in a SharedPtr. + */ + SharedPtr<FSDirectory> getSubDirectory(const String &name); + + virtual bool hasFile(const String &name); + virtual int matchPattern(StringList &list, const String &pattern); + virtual FilePtr openFile(const String &name); +}; + + + +/** + * SearchSet enables access to a group of Archives through the Archive interface. + * Its intended usage is a situation in which there are no name clashes among names in the + * contained Archives, hence the simplistic policy of always looking for the first + * match. SearchSet *DOES* guarantee that searches are performed in *DESCENDING* + * priority order. In case of conflicting priorities, insertion order prevails. + */ + class SearchSet : public Archive { + struct Node { + uint _priority; + String _name; + ArchivePtr _arc; + }; + typedef List<Node> ArchiveList; + ArchiveList _list; + + ArchiveList::iterator find(const String &name) const; + + // Add an archive keeping the list sorted by ascending priorities. + void insert(const Node& node); + +public: + SearchSet(); + virtual ~SearchSet(); + + /** + * Add a new Archive to the searchable set. + */ + void add(const String& name, ArchivePtr archive, uint priority = 0); + + /** + * Remove an Archive from the searchable set. + */ + void remove(const String& name); + + /** + * Empties the searchable set. + */ + void clear(); + + /** + * Change the order of searches. + */ + void setPriority(const String& name, uint priority); + + virtual bool hasFile(const String &name); + virtual int matchPattern(StringList &list, const String &pattern); + + /** + * Implements openFile from Archive base class. The current policy is + * opening the first file encountered that matches the name. + */ + virtual FilePtr openFile(const String &name); +}; + +} // namespace Common + +#endif diff --git a/common/array.h b/common/array.h index 854ce5b91d..693c024d11 100644 --- a/common/array.h +++ b/common/array.h @@ -35,7 +35,7 @@ class Array { protected: uint _capacity; uint _size; - T *_data; + T *_storage; public: typedef T *iterator; @@ -44,41 +44,41 @@ public: typedef T value_type; public: - Array() : _capacity(0), _size(0), _data(0) {} - Array(const Array<T> &array) : _capacity(0), _size(0), _data(0) { + Array() : _capacity(0), _size(0), _storage(0) {} + Array(const Array<T> &array) : _capacity(0), _size(0), _storage(0) { _size = array._size; _capacity = _size + 32; - _data = new T[_capacity]; - copy(array._data, array._data + _size, _data); + _storage = new T[_capacity]; + copy(array._storage, array._storage + _size, _storage); } ~Array() { - delete[] _data; + delete[] _storage; } void push_back(const T &element) { ensureCapacity(_size + 1); - _data[_size++] = element; + _storage[_size++] = element; } void push_back(const Array<T> &array) { ensureCapacity(_size + array._size); - copy(array._data, array._data + array._size, _data + _size); + copy(array._storage, array._storage + array._size, _storage + _size); _size += array._size; } void insert_at(int idx, const T &element) { assert(idx >= 0 && (uint)idx <= _size); ensureCapacity(_size + 1); - copy_backward(_data + idx, _data + _size, _data + _size + 1); - _data[idx] = element; + copy_backward(_storage + idx, _storage + _size, _storage + _size + 1); + _storage[idx] = element; _size++; } T remove_at(int idx) { assert(idx >= 0 && (uint)idx < _size); - T tmp = _data[idx]; - copy(_data + idx + 1, _data + _size, _data + idx); + T tmp = _storage[idx]; + copy(_storage + idx + 1, _storage + _size, _storage + idx); _size--; return tmp; } @@ -87,23 +87,23 @@ public: T& operator[](int idx) { assert(idx >= 0 && (uint)idx < _size); - return _data[idx]; + return _storage[idx]; } const T& operator[](int idx) const { assert(idx >= 0 && (uint)idx < _size); - return _data[idx]; + return _storage[idx]; } Array<T>& operator=(const Array<T> &array) { if (this == &array) return *this; - delete[] _data; + delete[] _storage; _size = array._size; _capacity = _size + 32; - _data = new T[_capacity]; - copy(array._data, array._data + _size, _data); + _storage = new T[_capacity]; + copy(array._storage, array._storage + _size, _storage); return *this; } @@ -113,8 +113,8 @@ public: } void clear() { - delete[] _data; - _data = 0; + delete[] _storage; + _storage = 0; _size = 0; _capacity = 0; } @@ -125,33 +125,33 @@ public: iterator begin() { - return _data; + return _storage; } iterator end() { - return _data + _size; + return _storage + _size; } const_iterator begin() const { - return _data; + return _storage; } const_iterator end() const { - return _data + _size; + return _storage + _size; } void reserve(uint newCapacity) { if (newCapacity <= _capacity) return; - T *old_data = _data; + T *old_storage = _storage; _capacity = newCapacity; - _data = new T[newCapacity]; + _storage = new T[newCapacity]; - if (old_data) { + if (old_storage) { // Copy old data - copy(old_data, old_data + _size, _data); - delete[] old_data; + copy(old_storage, old_storage + _size, _storage); + delete[] old_storage; } } @@ -159,14 +159,14 @@ public: if (newSize == _size) return; - T *old_data = _data; + T *old_storage = _storage; _capacity = newSize; - _data = new T[newSize]; - if (old_data) { + _storage = new T[newSize]; + if (old_storage) { // Copy old data int cnt = (_size < newSize ? _size : newSize); - copy(old_data, old_data + cnt, _data); - delete[] old_data; + copy(old_storage, old_storage + cnt, _storage); + delete[] old_storage; } _size = newSize; } diff --git a/common/config-file.cpp b/common/config-file.cpp index 9f54c9ddde..42d67109fa 100644 --- a/common/config-file.cpp +++ b/common/config-file.cpp @@ -225,7 +225,7 @@ bool ConfigFile::saveToStream(WriteStream &stream) { void ConfigFile::removeSection(const String §ion) { assert(isValidName(section)); for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { - if (!scumm_stricmp(section.c_str(), i->name.c_str())) { + if (section.equalsIgnoreCase(i->name)) { _sections.erase(i); return; } @@ -318,7 +318,7 @@ const ConfigFile::SectionKeyList ConfigFile::getKeys(const String §ion) cons ConfigFile::Section *ConfigFile::getSection(const String §ion) { for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { - if (!scumm_stricmp(section.c_str(), i->name.c_str())) { + if (section.equalsIgnoreCase(i->name)) { return &(*i); } } @@ -327,7 +327,7 @@ ConfigFile::Section *ConfigFile::getSection(const String §ion) { const ConfigFile::Section *ConfigFile::getSection(const String §ion) const { for (List<Section>::const_iterator i = _sections.begin(); i != _sections.end(); ++i) { - if (!scumm_stricmp(section.c_str(), i->name.c_str())) { + if (section.equalsIgnoreCase(i->name)) { return &(*i); } } @@ -340,7 +340,7 @@ bool ConfigFile::Section::hasKey(const String &key) const { const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const { for (List<KeyValue>::const_iterator i = keys.begin(); i != keys.end(); ++i) { - if (!scumm_stricmp(key.c_str(), i->key.c_str())) { + if (key.equalsIgnoreCase(i->key)) { return &(*i); } } @@ -349,7 +349,7 @@ const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const void ConfigFile::Section::setKey(const String &key, const String &value) { for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) { - if (!scumm_stricmp(key.c_str(), i->key.c_str())) { + if (key.equalsIgnoreCase(i->key)) { i->value = value; return; } @@ -363,7 +363,7 @@ void ConfigFile::Section::setKey(const String &key, const String &value) { void ConfigFile::Section::removeKey(const String &key) { for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) { - if (!scumm_stricmp(key.c_str(), i->key.c_str())) { + if (key.equalsIgnoreCase(i->key)) { keys.erase(i); return; } diff --git a/common/fs.cpp b/common/fs.cpp index 3f585c6038..429d388ad1 100644 --- a/common/fs.cpp +++ b/common/fs.cpp @@ -52,7 +52,7 @@ bool FilesystemNode::operator<(const FilesystemNode& node) const { if (isDirectory() != node.isDirectory()) return isDirectory(); - return scumm_stricmp(getDisplayName().c_str(), node.getDisplayName().c_str()) < 0; + return getDisplayName().compareToIgnoreCase(node.getDisplayName()) < 0; } bool FilesystemNode::exists() const { diff --git a/common/hash-str.h b/common/hash-str.h index f64b62daed..40557037e7 100644 --- a/common/hash-str.h +++ b/common/hash-str.h @@ -39,7 +39,7 @@ inline uint hashit_lower(const String &str) { return hashit_lower(str.c_str()); // FIXME: The following functors obviously are not consistently named struct CaseSensitiveString_EqualTo { - bool operator()(const String& x, const String& y) const { return strcmp(x.c_str(), y.c_str()) == 0; } + bool operator()(const String& x, const String& y) const { return x.equals(y); } }; struct CaseSensitiveString_Hash { @@ -48,7 +48,7 @@ struct CaseSensitiveString_Hash { struct IgnoreCase_EqualTo { - bool operator()(const String& x, const String& y) const { return scumm_stricmp(x.c_str(), y.c_str()) == 0; } + bool operator()(const String& x, const String& y) const { return x.equalsIgnoreCase(y); } }; struct IgnoreCase_Hash { diff --git a/common/hashmap.cpp b/common/hashmap.cpp index 4749234740..99ca0713ee 100644 --- a/common/hashmap.cpp +++ b/common/hashmap.cpp @@ -89,5 +89,36 @@ uint nextTableSize(uint x) { return primes[i]; } +#ifdef DEBUG_HASH_COLLISIONS +static double + g_collisions = 0, + g_lookups = 0, + g_collPerLook = 0, + g_capacity = 0, + g_size = 0; +static int g_max_capacity = 0, g_max_size = 0; +static int g_totalHashmaps = 0; + +void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele) { + g_collisions += collisions; + g_lookups += lookups; + if (lookups) + g_collPerLook += (double)collisions / (double)lookups; + g_capacity += arrsize; + g_size += nele; + g_totalHashmaps++; + + g_max_capacity = MAX(g_max_capacity, arrsize); + g_max_size = MAX(g_max_size, nele); + + fprintf(stdout, "%d hashmaps: colls %.1f; lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n", + g_totalHashmaps, + g_collisions / g_totalHashmaps, + g_lookups / g_totalHashmaps, + 100 * g_collPerLook / g_totalHashmaps, + g_size / g_totalHashmaps, g_max_size, + g_capacity / g_totalHashmaps, g_max_capacity); +} +#endif } // End of namespace Common diff --git a/common/hashmap.h b/common/hashmap.h index 69f367de97..980e03aa6e 100644 --- a/common/hashmap.h +++ b/common/hashmap.h @@ -136,8 +136,9 @@ public: } #endif - Node **_arr; // hashtable of size arrsize. - uint _arrsize, _nele; + Node **_storage; // hashtable of size arrsize. + uint _capacity; + uint _size; HashFunc _hash; EqualFunc _equal; @@ -174,8 +175,8 @@ public: NodeType *deref() const { assert(_hashmap != 0); - assert(_idx < _hashmap->_arrsize); - Node *node = _hashmap->_arr[_idx]; + assert(_idx < _hashmap->_capacity); + Node *node = _hashmap->_storage[_idx]; assert(node != 0); return node; } @@ -195,8 +196,8 @@ public: assert(_hashmap); do { _idx++; - } while (_idx < _hashmap->_arrsize && _hashmap->_arr[_idx] == 0); - if (_idx >= _hashmap->_arrsize) + } while (_idx < _hashmap->_capacity && _hashmap->_storage[_idx] == 0); + if (_idx >= _hashmap->_capacity) _idx = (uint)-1; return *this; @@ -223,7 +224,7 @@ public: // Remove the previous content and ... clear(); - delete[] _arr; + delete[] _storage; // ... copy the new stuff. assign(map); return *this; @@ -242,12 +243,12 @@ public: void erase(const Key &key); - uint size() const { return _nele; } + uint size() const { return _size; } iterator begin() { // Find and return the _key non-empty entry - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (_arr[ctr]) + for (uint ctr = 0; ctr < _capacity; ++ctr) { + if (_storage[ctr]) return iterator(ctr, this); } return end(); @@ -258,8 +259,8 @@ public: const_iterator begin() const { // Find and return the first non-empty entry - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (_arr[ctr]) + for (uint ctr = 0; ctr < _capacity; ++ctr) { + if (_storage[ctr]) return const_iterator(ctr, this); } return end(); @@ -270,14 +271,14 @@ public: iterator find(const Key &key) { uint ctr = lookup(key); - if (_arr[ctr]) + if (_storage[ctr]) return iterator(ctr, this); return end(); } const_iterator find(const Key &key) const { uint ctr = lookup(key); - if (_arr[ctr]) + if (_storage[ctr]) return const_iterator(ctr, this); return end(); } @@ -285,7 +286,7 @@ public: // TODO: insert() method? bool empty() const { - return (_nele == 0); + return (_size == 0); } }; @@ -301,12 +302,12 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap() : _nodePool(sizeof(Node)), #endif _defaultVal() { - _arrsize = nextTableSize(0); - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _capacity = nextTableSize(0); + _storage = new Node *[_capacity]; + assert(_storage != NULL); + memset(_storage, 0, _capacity * sizeof(Node *)); - _nele = 0; + _size = 0; #ifdef DEBUG_HASH_COLLISIONS _collisions = 0; @@ -333,11 +334,15 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) : */ template<class Key, class Val, class HashFunc, class EqualFunc> HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() { - for (uint ctr = 0; ctr < _arrsize; ++ctr) - if (_arr[ctr] != NULL) - freeNode(_arr[ctr]); + for (uint ctr = 0; ctr < _capacity; ++ctr) + if (_storage[ctr] != NULL) + freeNode(_storage[ctr]); - delete[] _arr; + delete[] _storage; +#ifdef DEBUG_HASH_COLLISIONS + extern void updateHashCollisionStats(int, int, int, int); + updateHashCollisionStats(_collisions, _lookups, _capacity, _size); +#endif } /** @@ -349,95 +354,95 @@ HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() { */ template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) { - _arrsize = map._arrsize; - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _capacity = map._capacity; + _storage = new Node *[_capacity]; + assert(_storage != NULL); + memset(_storage, 0, _capacity * sizeof(Node *)); // Simply clone the map given to us, one by one. - _nele = 0; - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (map._arr[ctr] != NULL) { - _arr[ctr] = allocNode(map._arr[ctr]->_key); - _arr[ctr]->_value = map._arr[ctr]->_value; - _nele++; + _size = 0; + for (uint ctr = 0; ctr < _capacity; ++ctr) { + if (map._storage[ctr] != NULL) { + _storage[ctr] = allocNode(map._storage[ctr]->_key); + _storage[ctr]->_value = map._storage[ctr]->_value; + _size++; } } // Perform a sanity check (to help track down hashmap corruption) - assert(_nele == map._nele); + assert(_size == map._size); } template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) { - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (_arr[ctr] != NULL) { - freeNode(_arr[ctr]); - _arr[ctr] = NULL; + for (uint ctr = 0; ctr < _capacity; ++ctr) { + if (_storage[ctr] != NULL) { + freeNode(_storage[ctr]); + _storage[ctr] = NULL; } } - if (shrinkArray && _arrsize > nextTableSize(0)) { - delete[] _arr; + if (shrinkArray && _capacity > nextTableSize(0)) { + delete[] _storage; - _arrsize = nextTableSize(0); - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _capacity = nextTableSize(0); + _storage = new Node *[_capacity]; + assert(_storage != NULL); + memset(_storage, 0, _capacity * sizeof(Node *)); } - _nele = 0; + _size = 0; } template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::expand_array(uint newsize) { - assert(newsize > _arrsize); + assert(newsize > _capacity); uint ctr, dex; - const uint old_nele = _nele; - const uint old_arrsize = _arrsize; - Node **old_arr = _arr; + const uint old_size = _size; + const uint old_capacity = _capacity; + Node **old_storage = _storage; // allocate a new array - _nele = 0; - _arrsize = newsize; - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _size = 0; + _capacity = newsize; + _storage = new Node *[_capacity]; + assert(_storage != NULL); + memset(_storage, 0, _capacity * sizeof(Node *)); // rehash all the old elements - for (ctr = 0; ctr < old_arrsize; ++ctr) { - if (old_arr[ctr] == NULL) + for (ctr = 0; ctr < old_capacity; ++ctr) { + if (old_storage[ctr] == NULL) continue; // Insert the element from the old table into the new table. // Since we know that no key exists twice in the old table, we // can do this slightly better than by calling lookup, since we // don't have to call _equal(). - dex = _hash(old_arr[ctr]->_key) % _arrsize; - while (_arr[dex] != NULL) { - dex = (dex + 1) % _arrsize; + dex = _hash(old_storage[ctr]->_key) % _capacity; + while (_storage[dex] != NULL) { + dex = (dex + 1) % _capacity; } - _arr[dex] = old_arr[ctr]; - _nele++; + _storage[dex] = old_storage[ctr]; + _size++; } // Perform a sanity check: Old number of elements should match the new one! // This check will fail if some previous operation corrupted this hashmap. - assert(_nele == old_nele); + assert(_size == old_size); - delete[] old_arr; + delete[] old_storage; return; } template<class Key, class Val, class HashFunc, class EqualFunc> int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const { - uint ctr = _hash(key) % _arrsize; + uint ctr = _hash(key) % _capacity; - while (_arr[ctr] != NULL && !_equal(_arr[ctr]->_key, key)) { - ctr = (ctr + 1) % _arrsize; + while (_storage[ctr] != NULL && !_equal(_storage[ctr]->_key, key)) { + ctr = (ctr + 1) % _capacity; #ifdef DEBUG_HASH_COLLISIONS _collisions++; @@ -448,7 +453,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const { _lookups++; fprintf(stderr, "collisions %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n", _collisions, _lookups, ((double) _collisions / (double)_lookups), - (const void *)this, _arrsize, _nele); + (const void *)this, _capacity, _size); #endif return ctr; @@ -458,13 +463,13 @@ template<class Key, class Val, class HashFunc, class EqualFunc> int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) { uint ctr = lookup(key); - if (_arr[ctr] == NULL) { - _arr[ctr] = allocNode(key); - _nele++; + if (_storage[ctr] == NULL) { + _storage[ctr] = allocNode(key); + _size++; // Keep the load factor below 75%. - if (_nele > _arrsize * 75 / 100) { - expand_array(nextTableSize(_arrsize)); + if (_size > _capacity * 75 / 100) { + expand_array(nextTableSize(_capacity)); ctr = lookup(key); } } @@ -476,7 +481,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key & template<class Key, class Val, class HashFunc, class EqualFunc> bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const { uint ctr = lookup(key); - return (_arr[ctr] != NULL); + return (_storage[ctr] != NULL); } template<class Key, class Val, class HashFunc, class EqualFunc> @@ -492,15 +497,15 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) co template<class Key, class Val, class HashFunc, class EqualFunc> Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) { uint ctr = lookupAndCreateIfMissing(key); - assert(_arr[ctr] != NULL); - return _arr[ctr]->_value; + assert(_storage[ctr] != NULL); + return _storage[ctr]->_value; } template<class Key, class Val, class HashFunc, class EqualFunc> const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const { uint ctr = lookup(key); - if (_arr[ctr] != NULL) - return _arr[ctr]->_value; + if (_storage[ctr] != NULL) + return _storage[ctr]->_value; else return _defaultVal; } @@ -508,38 +513,38 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) { uint ctr = lookupAndCreateIfMissing(key); - assert(_arr[ctr] != NULL); - _arr[ctr]->_value = val; + assert(_storage[ctr] != NULL); + _storage[ctr]->_value = val; } template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) { // This is based on code in the Wikipedia article on Hash tables. uint i = lookup(key); - if (_arr[i] == NULL) + if (_storage[i] == NULL) return; // key wasn't present, so no work has to be done // If we remove a key, we must check all subsequent keys and possibly // reinsert them. uint j = i; - freeNode(_arr[i]); - _arr[i] = NULL; + freeNode(_storage[i]); + _storage[i] = NULL; while (true) { // Look at the next table slot - j = (j + 1) % _arrsize; + j = (j + 1) % _capacity; // If the next slot is empty, we are done - if (_arr[j] == NULL) + if (_storage[j] == NULL) break; // Compute the slot where the content of the next slot should normally be, // assuming an empty table, and check whether we have to move it. - uint k = _hash(_arr[j]->_key) % _arrsize; + uint k = _hash(_storage[j]->_key) % _capacity; if ((j > i && (k <= i || k > j)) || (j < i && (k <= i && k > j)) ) { - _arr[i] = _arr[j]; + _storage[i] = _storage[j]; i = j; } } - _arr[i] = NULL; - _nele--; + _storage[i] = NULL; + _size--; return; } diff --git a/common/keyboard.h b/common/keyboard.h index fbbc289a3b..93579cbed6 100644 --- a/common/keyboard.h +++ b/common/keyboard.h @@ -178,10 +178,7 @@ enum KeyCode { KEYCODE_MENU = 319, KEYCODE_POWER = 320, // Power Macintosh power key KEYCODE_EURO = 321, // Some european keyboards - KEYCODE_UNDO = 322, // Atari keyboard has Undo - - // Global Main Menu key - KEYCODE_MAINMENU = KEYCODE_F6 + KEYCODE_UNDO = 322 // Atari keyboard has Undo }; /** diff --git a/common/module.mk b/common/module.mk index c3f2a38c3f..599ffcf8a6 100644 --- a/common/module.mk +++ b/common/module.mk @@ -2,6 +2,7 @@ MODULE := common MODULE_OBJS := \ advancedDetector.o \ + archive.o \ config-file.o \ config-manager.o \ file.o \ diff --git a/common/queue.h b/common/queue.h index 51d56ed54b..f1881345e8 100644 --- a/common/queue.h +++ b/common/queue.h @@ -31,39 +31,62 @@ namespace Common { /** - * Variable size Queue class, implemented using our Array class. + * Variable size Queue class, implemented using our List class. */ template<class T> class Queue { -protected: - List<T> _queue; public: - Queue<T>() {} - Queue<T>(const List<T> &queueContent) : _queue(queueContent) {} + typedef T value_type; + +public: + Queue<T>() : _impl() {} + Queue<T>(const Queue<T> &queue) : _impl(queue._impl) {} + + Queue<T> &operator=(const Queue<T> &queue) { + _impl = queue._impl; + return *this; + } bool empty() const { - return _queue.empty(); + return _impl.empty(); } + void clear() { - _queue.clear(); + _impl.clear(); } + void push(const T &x) { - _queue.push_back(x); + _impl.push_back(x); } - T back() const { - return _queue.reverse_begin().operator*(); + + T &front() { + return *_impl.begin(); } - T front() const { - return _queue.begin().operator*(); + + const T &front() const { + return *_impl.begin(); } + + T &back() { + return *_impl.reverse_begin(); + } + + const T &back() const { + return *_impl.reverse_begin(); + } + T pop() { T tmp = front(); - _queue.pop_front(); + _impl.pop_front(); return tmp; } + int size() const { - return _queue.size(); + return _impl.size(); } + +private: + List<T> _impl; }; } // End of namespace Common diff --git a/common/str.cpp b/common/str.cpp index 5f8d4ffb7e..c254d4bbc8 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -43,19 +43,19 @@ static int computeCapacity(int len) { return ((len + 32 - 1) & ~0x1F) - 1; } -String::String(const char *str) : _len(0), _str(_storage) { +String::String(const char *str) : _size(0), _str(_storage) { if (str == 0) { _storage[0] = 0; - _len = 0; + _size = 0; } else initWithCStr(str, strlen(str)); } -String::String(const char *str, uint32 len) : _len(0), _str(_storage) { +String::String(const char *str, uint32 len) : _size(0), _str(_storage) { initWithCStr(str, len); } -String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) { +String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) { assert(endP >= beginP); initWithCStr(beginP, endP - beginP); } @@ -67,7 +67,7 @@ void String::initWithCStr(const char *str, uint32 len) { // for GCC 2.95.x compatibility (see also tracker item #1602879). _storage[0] = 0; - _len = len; + _size = len; if (len >= _builtinCapacity) { // Not enough internal storage, so allocate more @@ -83,7 +83,7 @@ void String::initWithCStr(const char *str, uint32 len) { } String::String(const String &str) - : _len(str._len), _str(str.isStorageIntern() ? _storage : str._str) { + : _size(str._size), _str(str.isStorageIntern() ? _storage : str._str) { if (str.isStorageIntern()) { // String in internal storage: just copy it memcpy(_storage, str._storage, _builtinCapacity); @@ -97,14 +97,14 @@ String::String(const String &str) } String::String(char c) -: _len(0), _str(_storage) { +: _size(0), _str(_storage) { _storage[0] = c; _storage[1] = 0; // TODO/FIXME: There is no reason for the following check -- we *do* // allow strings to contain 0 bytes! - _len = (c == 0) ? 0 : 1; + _size = (c == 0) ? 0 : 1; } String::~String() { @@ -112,16 +112,16 @@ String::~String() { } void String::makeUnique() { - ensureCapacity(_len, true); + ensureCapacity(_size, true); } /** - * Ensure that enough storage is available to store at least new_len + * Ensure that enough storage is available to store at least new_size * characters plus a null byte. In addition, if we currently share * the storage with another string, unshare it, so that we can safely * write to the storage. */ -void String::ensureCapacity(uint32 new_len, bool keep_old) { +void String::ensureCapacity(uint32 new_size, bool keep_old) { bool isShared; uint32 curCapacity, newCapacity; char *newStorage; @@ -137,10 +137,10 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) { // Special case: If there is enough space, and we do not share // the storage, then there is nothing to do. - if (!isShared && new_len <= curCapacity) + if (!isShared && new_size <= curCapacity) return; - if (isShared && new_len <= _builtinCapacity - 1) { + if (isShared && new_size <= _builtinCapacity - 1) { // We share the storage, but there is enough internal storage: Use that. newStorage = _storage; newCapacity = _builtinCapacity - 1; @@ -148,7 +148,7 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) { // We need to allocate storage on the heap! // Compute a suitable new capacity limit - newCapacity = computeCapacity(new_len); + newCapacity = computeCapacity(new_size); // Allocate new storage newStorage = (char *)malloc(newCapacity+1); @@ -157,10 +157,10 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) { // Copy old data if needed, elsewise reset the new storage. if (keep_old) { - assert(_len <= newCapacity); - memcpy(newStorage, _str, _len + 1); + assert(_size <= newCapacity); + memcpy(newStorage, _str, _size + 1); } else { - _len = 0; + _size = 0; newStorage[0] = 0; } @@ -210,7 +210,7 @@ void String::decRefCount(int *oldRefCount) { String& String::operator =(const char *str) { uint32 len = strlen(str); ensureCapacity(len, false); - _len = len; + _size = len; memmove(_str, str, len + 1); return *this; } @@ -221,16 +221,16 @@ String &String::operator =(const String &str) { if (str.isStorageIntern()) { decRefCount(_extern._refCount); - _len = str._len; + _size = str._size; _str = _storage; - memcpy(_str, str._str, _len + 1); + memcpy(_str, str._str, _size + 1); } else { str.incRefCount(); decRefCount(_extern._refCount); _extern._refCount = str._extern._refCount; _extern._capacity = str._extern._capacity; - _len = str._len; + _size = str._size; _str = str._str; } @@ -240,7 +240,7 @@ String &String::operator =(const String &str) { String& String::operator =(char c) { decRefCount(_extern._refCount); _str = _storage; - _len = 1; + _size = 1; _str[0] = c; _str[1] = 0; return *this; @@ -249,30 +249,30 @@ String& String::operator =(char c) { String &String::operator +=(const char *str) { int len = strlen(str); if (len > 0) { - ensureCapacity(_len + len, true); + ensureCapacity(_size + len, true); - memcpy(_str + _len, str, len + 1); - _len += len; + memcpy(_str + _size, str, len + 1); + _size += len; } return *this; } String &String::operator +=(const String &str) { - int len = str._len; + int len = str._size; if (len > 0) { - ensureCapacity(_len + len, true); + ensureCapacity(_size + len, true); - memcpy(_str + _len, str._str, len + 1); - _len += len; + memcpy(_str + _size, str._str, len + 1); + _size += len; } return *this; } String &String::operator +=(char c) { - ensureCapacity(_len + 1, true); + ensureCapacity(_size + 1, true); - _str[_len++] = c; - _str[_len] = 0; + _str[_size++] = c; + _str[_size] = 0; return *this; } @@ -293,10 +293,10 @@ bool String::hasPrefix(const char *x) const { bool String::hasSuffix(const char *x) const { assert(x != 0); // Compare x with the end of _str. - const uint32 x_len = strlen(x); - if (x_len > _len) + const uint32 x_size = strlen(x); + if (x_size > _size) return false; - const char *y = c_str() + _len - x_len; + const char *y = c_str() + _size - x_size; while (*x && *x == *y) { ++x; ++y; @@ -316,65 +316,65 @@ bool String::contains(char x) const { } void String::deleteLastChar() { - deleteChar(_len - 1); + deleteChar(_size - 1); } void String::deleteChar(uint32 p) { - assert(p < _len); + assert(p < _size); makeUnique(); - while (p++ < _len) + while (p++ < _size) _str[p-1] = _str[p]; - _len--; + _size--; } void String::clear() { decRefCount(_extern._refCount); - _len = 0; + _size = 0; _str = _storage; _storage[0] = 0; } void String::setChar(char c, uint32 p) { - assert(p <= _len); + assert(p <= _size); makeUnique(); _str[p] = c; } void String::insertChar(char c, uint32 p) { - assert(p <= _len); + assert(p <= _size); - ensureCapacity(_len + 1, true); - _len++; - for (uint32 i = _len; i > p; --i) + ensureCapacity(_size + 1, true); + _size++; + for (uint32 i = _size; i > p; --i) _str[i] = _str[i-1]; _str[p] = c; } void String::toLowercase() { makeUnique(); - for (uint32 i = 0; i < _len; ++i) + for (uint32 i = 0; i < _size; ++i) _str[i] = tolower(_str[i]); } void String::toUppercase() { makeUnique(); - for (uint32 i = 0; i < _len; ++i) + for (uint32 i = 0; i < _size; ++i) _str[i] = toupper(_str[i]); } void String::trim() { - if (_len == 0) + if (_size == 0) return; makeUnique(); // Trim trailing whitespace - while (_len >= 1 && isspace(_str[_len-1])) - _len--; - _str[_len] = 0; + while (_size >= 1 && isspace(_str[_size-1])) + _size--; + _str[_size] = 0; // Trim leading whitespace char *t = _str; @@ -382,8 +382,8 @@ void String::trim() { t++; if (t != _str) { - _len -= t - _str; - memmove(_str, t, _len + 1); + _size -= t - _str; + memmove(_str, t, _size + 1); } } diff --git a/common/str.h b/common/str.h index 3479fee8e4..663a819e70 100644 --- a/common/str.h +++ b/common/str.h @@ -61,7 +61,7 @@ protected: * a lot. Yes, we limit ourselves to strings shorter than 4GB -- * on purpose :-). */ - uint32 _len; + uint32 _size; /** * Pointer to the actual string storage. Either points to _storage, @@ -97,7 +97,7 @@ public: #endif /** Construct a new empty string. */ - String() : _len(0), _str(_storage) { _storage[0] = 0; } + String() : _size(0), _str(_storage) { _storage[0] = 0; } /** Construct a new string from the given NULL-terminated C string. */ String(const char *str); @@ -150,13 +150,13 @@ public: bool contains(char x) const; inline const char *c_str() const { return _str; } - inline uint size() const { return _len; } + inline uint size() const { return _size; } - inline bool empty() const { return (_len == 0); } - char lastChar() const { return (_len > 0) ? _str[_len-1] : 0; } + inline bool empty() const { return (_size == 0); } + char lastChar() const { return (_size > 0) ? _str[_size-1] : 0; } char operator [](int idx) const { - assert(_str && idx >= 0 && idx < (int)_len); + assert(_str && idx >= 0 && idx < (int)_size); return _str[idx]; } @@ -203,7 +203,7 @@ public: protected: void makeUnique(); - void ensureCapacity(uint32 new_len, bool keep_old); + void ensureCapacity(uint32 new_size, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); void initWithCStr(const char *str, uint32 len); @@ -218,7 +218,7 @@ String operator +(const String &x, const char *y); String operator +(const String &x, char y); String operator +(char x, const String &y); -// Some useful additional comparision operators for Strings +// Some useful additional comparison operators for Strings bool operator == (const char *x, const String &y); bool operator != (const char *x, const String &y); @@ -230,13 +230,11 @@ extern char *trim(char *t); class StringList : public Array<String> { public: void push_back(const char *str) { - ensureCapacity(_size + 1); - _data[_size++] = str; + Array<String>::push_back(str); } void push_back(const String &str) { - ensureCapacity(_size + 1); - _data[_size++] = str; + Array<String>::push_back(str); } }; diff --git a/common/util.cpp b/common/util.cpp index 6f0fdcb233..316f2e39c3 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -237,10 +237,9 @@ Language parseLanguage(const String &str) { if (str.empty()) return UNK_LANG; - const char *s = str.c_str(); const LanguageDescription *l = g_languages; for (; l->code; ++l) { - if (!scumm_stricmp(l->code, s)) + if (str.equalsIgnoreCase(l->code)) return l->id; } @@ -299,20 +298,18 @@ Platform parsePlatform(const String &str) { if (str.empty()) return kPlatformUnknown; - const char *s = str.c_str(); - // Handle some special case separately, for compatibility with old config // files. - if (!strcmp(s, "1")) + if (str == "1") return kPlatformAmiga; - else if (!strcmp(s, "2")) + else if (str == "2") return kPlatformAtariST; - else if (!strcmp(s, "3")) + else if (str == "3") return kPlatformMacintosh; const PlatformDescription *l = g_platforms; for (; l->code; ++l) { - if (!scumm_stricmp(l->code, s) || !scumm_stricmp(l->code2, s) || !scumm_stricmp(l->abbrev, s)) + if (str.equalsIgnoreCase(l->code) || str.equalsIgnoreCase(l->code2) || str.equalsIgnoreCase(l->abbrev)) return l->id; } @@ -364,10 +361,9 @@ RenderMode parseRenderMode(const String &str) { if (str.empty()) return kRenderDefault; - const char *s = str.c_str(); const RenderModeDescription *l = g_renderModes; for (; l->code; ++l) { - if (!scumm_stricmp(l->code, s)) + if (str.equalsIgnoreCase(l->code)) return l->id; } @@ -904,7 +904,7 @@ if test "$?" -gt 0; then fi case $cxx_version in - 2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9].[0-9]|4.[0-9].[0-9][-.]*) + 2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9]|4.[0-9].[0-9]|4.[0-9].[0-9][-.]*) _cxx_major=`echo $cxx_version | cut -d '.' -f 1` _cxx_minor=`echo $cxx_version | cut -d '.' -f 2` cxx_version="$cxx_version, ok" @@ -1030,7 +1030,6 @@ echo "$_have_x86" # # Determine build settings # -# TODO - also add an command line option to override this?!? echo_n "Checking hosttype... " echo $_host_os case $_host_os in @@ -1046,7 +1045,7 @@ case $_host_os in type_4_byte='long' ;; solaris*) - DEFINES="$DEFINES -DUNIX -DSYSTEM_NOT_SUPPORTING_D_TYPE" + DEFINES="$DEFINES -DUNIX -DSOLARIS -DSYSTEM_NOT_SUPPORTING_D_TYPE" # Needs -lbind -lsocket for the timidity MIDI driver LIBS="$LIBS -lnsl -lsocket" ;; @@ -1074,7 +1073,6 @@ case $_host_os in ;; mint*) DEFINES="$DEFINES -DUNIX -DSYSTEM_NOT_SUPPORTING_D_TYPE" - LIBS="$LIBS -lsocket" ;; amigaos*) # TODO: anything to be added here? diff --git a/dists/engine-data/drascula.dat b/dists/engine-data/drascula.dat Binary files differindex 321e63c277..cfedb8604b 100644 --- a/dists/engine-data/drascula.dat +++ b/dists/engine-data/drascula.dat diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat Binary files differindex 5cb5373f45..572106f4a4 100644 --- a/dists/engine-data/kyra.dat +++ b/dists/engine-data/kyra.dat diff --git a/dists/msvc7/gob.vcproj b/dists/msvc7/gob.vcproj index bb7eac35e0..2d985476fd 100644 --- a/dists/msvc7/gob.vcproj +++ b/dists/msvc7/gob.vcproj @@ -268,6 +268,9 @@ RelativePath="..\..\engines\gob\inter_v4.cpp"> </File> <File + RelativePath="..\..\engines\gob\inter_v5.cpp"> + </File> + <File RelativePath="..\..\engines\gob\map.cpp"> </File> <File diff --git a/dists/msvc7/parallaction.vcproj b/dists/msvc7/parallaction.vcproj index 2dac8737c2..fd4fe26ecc 100644 --- a/dists/msvc7/parallaction.vcproj +++ b/dists/msvc7/parallaction.vcproj @@ -205,6 +205,9 @@ RelativePath="..\..\engines\parallaction\saveload.cpp"> </File> <File + RelativePath="..\..\engines\parallaction\saveload.h"> + </File> + <File RelativePath="..\..\engines\parallaction\sound.cpp"> </File> <File diff --git a/dists/msvc7/scumm.vcproj b/dists/msvc7/scumm.vcproj index 56f78692cc..1e37b19cc6 100644 --- a/dists/msvc7/scumm.vcproj +++ b/dists/msvc7/scumm.vcproj @@ -553,9 +553,6 @@ RelativePath="..\..\engines\scumm\string.cpp"> </File> <File - RelativePath="..\..\engines\scumm\thumbnail.cpp"> - </File> - <File RelativePath="..\..\engines\scumm\usage_bits.cpp"> </File> <File diff --git a/dists/msvc7/scummvm.vcproj b/dists/msvc7/scummvm.vcproj index 884cd58a5a..e1208df5ef 100644 --- a/dists/msvc7/scummvm.vcproj +++ b/dists/msvc7/scummvm.vcproj @@ -50,8 +50,6 @@ <Tool Name="VCMIDLTool"/> <Tool - Name="VCWebDeploymentTool"/> - <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> @@ -107,8 +105,6 @@ <Tool Name="VCMIDLTool"/> <Tool - Name="VCWebDeploymentTool"/> - <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> @@ -680,6 +676,9 @@ <Filter Name="fs"> <File + RelativePath="..\..\backends\fs\abstract-fs.cpp"> + </File> + <File RelativePath="..\..\backends\fs\abstract-fs.h"> </File> <File @@ -965,6 +964,12 @@ <File RelativePath="..\..\graphics\surface.h"> </File> + <File + RelativePath="..\..\graphics\thumbnail.cpp"> + </File> + <File + RelativePath="..\..\graphics\thumbnail.h"> + </File> <Filter Name="scaler"> <File @@ -1041,7 +1046,7 @@ RelativePath="..\..\graphics\scaler\scalebit.h"> </File> <File - RelativePath="..\..\graphics\scaler\thumbnail.cpp"> + RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp"> </File> </Filter> <Filter diff --git a/dists/msvc71/gob.vcproj b/dists/msvc71/gob.vcproj index 3d6408cdf5..8516d489fe 100644 --- a/dists/msvc71/gob.vcproj +++ b/dists/msvc71/gob.vcproj @@ -282,6 +282,9 @@ RelativePath="..\..\engines\gob\inter_v4.cpp"> </File> <File + RelativePath="..\..\engines\gob\inter_v5.cpp"> + </File> + <File RelativePath="..\..\engines\gob\map.cpp"> </File> <File diff --git a/dists/msvc71/parallaction.vcproj b/dists/msvc71/parallaction.vcproj index c72fb68234..50e277e9fb 100644 --- a/dists/msvc71/parallaction.vcproj +++ b/dists/msvc71/parallaction.vcproj @@ -219,6 +219,9 @@ RelativePath="..\..\engines\parallaction\saveload.cpp"> </File> <File + RelativePath="..\..\engines\parallaction\saveload.h"> + </File> + <File RelativePath="..\..\engines\parallaction\sound.cpp"> </File> <File diff --git a/dists/msvc71/scumm.vcproj b/dists/msvc71/scumm.vcproj index 661cc1fa19..dcd6583461 100644 --- a/dists/msvc71/scumm.vcproj +++ b/dists/msvc71/scumm.vcproj @@ -567,9 +567,6 @@ RelativePath="..\..\engines\scumm\string.cpp"> </File> <File - RelativePath="..\..\engines\scumm\thumbnail.cpp"> - </File> - <File RelativePath="..\..\engines\scumm\usage_bits.cpp"> </File> <File diff --git a/dists/msvc71/scummvm.vcproj b/dists/msvc71/scummvm.vcproj index 6234c89dd5..fc6f9aa517 100644 --- a/dists/msvc71/scummvm.vcproj +++ b/dists/msvc71/scummvm.vcproj @@ -50,8 +50,6 @@ <Tool Name="VCMIDLTool"/> <Tool - Name="VCWebDeploymentTool"/> - <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> @@ -113,8 +111,6 @@ <Tool Name="VCMIDLTool"/> <Tool - Name="VCWebDeploymentTool"/> - <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> @@ -694,6 +690,9 @@ <Filter Name="fs"> <File + RelativePath="..\..\backends\fs\abstract-fs.cpp"> + </File> + <File RelativePath="..\..\backends\fs\abstract-fs.h"> </File> <File @@ -979,6 +978,12 @@ <File RelativePath="..\..\graphics\surface.h"> </File> + <File + RelativePath="..\..\graphics\thumbnail.cpp"> + </File> + <File + RelativePath="..\..\graphics\thumbnail.h"> + </File> <Filter Name="scaler"> <File @@ -1055,7 +1060,7 @@ RelativePath="..\..\graphics\scaler\scalebit.h"> </File> <File - RelativePath="..\..\graphics\scaler\thumbnail.cpp"> + RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp"> </File> </Filter> <Filter diff --git a/dists/msvc8/gob.vcproj b/dists/msvc8/gob.vcproj index c178caf8be..6e034367ec 100644 --- a/dists/msvc8/gob.vcproj +++ b/dists/msvc8/gob.vcproj @@ -389,6 +389,10 @@ > </File> <File + RelativePath="..\..\engines\gob\inter_v5.cpp" + > + </File> + <File RelativePath="..\..\engines\gob\map.cpp" > </File> diff --git a/dists/msvc8/parallaction.vcproj b/dists/msvc8/parallaction.vcproj index e268fe1e6b..60b3968e61 100644 --- a/dists/msvc8/parallaction.vcproj +++ b/dists/msvc8/parallaction.vcproj @@ -305,6 +305,10 @@ > </File> <File + RelativePath="..\..\engines\parallaction\saveload.h" + > + </File> + <File RelativePath="..\..\engines\parallaction\sound.cpp" > </File> diff --git a/dists/msvc8/scumm.vcproj b/dists/msvc8/scumm.vcproj index 42a4ff6993..ba253627be 100644 --- a/dists/msvc8/scumm.vcproj +++ b/dists/msvc8/scumm.vcproj @@ -770,10 +770,6 @@ > </File> <File - RelativePath="..\..\engines\scumm\thumbnail.cpp" - > - </File> - <File RelativePath="..\..\engines\scumm\usage_bits.cpp" > </File> diff --git a/dists/msvc8/scummvm.vcproj b/dists/msvc8/scummvm.vcproj index 8b10a22eb6..16c6980767 100644 --- a/dists/msvc8/scummvm.vcproj +++ b/dists/msvc8/scummvm.vcproj @@ -97,9 +97,6 @@ Name="VCAppVerifierTool" /> <Tool - Name="VCWebDeploymentTool" - /> - <Tool Name="VCPostBuildEventTool" /> </Configuration> @@ -189,9 +186,6 @@ Name="VCAppVerifierTool" /> <Tool - Name="VCWebDeploymentTool" - /> - <Tool Name="VCPostBuildEventTool" /> </Configuration> @@ -941,6 +935,10 @@ Name="fs" > <File + RelativePath="..\..\backends\fs\abstract-fs.cpp" + > + </File> + <File RelativePath="..\..\backends\fs\abstract-fs.h" > </File> @@ -1321,6 +1319,14 @@ RelativePath="..\..\graphics\surface.h" > </File> + <File + RelativePath="..\..\graphics\thumbnail.cpp" + > + </File> + <File + RelativePath="..\..\graphics\thumbnail.h" + > + </File> <Filter Name="scaler" > @@ -1421,7 +1427,7 @@ > </File> <File - RelativePath="..\..\graphics\scaler\thumbnail.cpp" + RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp" > </File> </Filter> diff --git a/dists/msvc9/gob.vcproj b/dists/msvc9/gob.vcproj index e6c55519b0..e12d48cc83 100644 --- a/dists/msvc9/gob.vcproj +++ b/dists/msvc9/gob.vcproj @@ -390,6 +390,10 @@ > </File> <File + RelativePath="..\..\engines\gob\inter_v5.cpp" + > + </File> + <File RelativePath="..\..\engines\gob\map.cpp" > </File> diff --git a/dists/msvc9/parallaction.vcproj b/dists/msvc9/parallaction.vcproj index f901976c37..41d65c5726 100644 --- a/dists/msvc9/parallaction.vcproj +++ b/dists/msvc9/parallaction.vcproj @@ -306,6 +306,10 @@ > </File> <File + RelativePath="..\..\engines\parallaction\saveload.h" + > + </File> + <File RelativePath="..\..\engines\parallaction\sound.cpp" > </File> diff --git a/dists/msvc9/scumm.vcproj b/dists/msvc9/scumm.vcproj index 230102db35..b968f4df62 100644 --- a/dists/msvc9/scumm.vcproj +++ b/dists/msvc9/scumm.vcproj @@ -771,10 +771,6 @@ > </File> <File - RelativePath="..\..\engines\scumm\thumbnail.cpp" - > - </File> - <File RelativePath="..\..\engines\scumm\usage_bits.cpp" > </File> diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj index 31270652df..baa6157bd5 100644 --- a/dists/msvc9/scummvm.vcproj +++ b/dists/msvc9/scummvm.vcproj @@ -100,9 +100,6 @@ Name="VCAppVerifierTool" /> <Tool - Name="VCWebDeploymentTool" - /> - <Tool Name="VCPostBuildEventTool" /> </Configuration> @@ -194,9 +191,6 @@ Name="VCAppVerifierTool" /> <Tool - Name="VCWebDeploymentTool" - /> - <Tool Name="VCPostBuildEventTool" /> </Configuration> @@ -946,6 +940,10 @@ Name="fs" > <File + RelativePath="..\..\backends\fs\abstract-fs.cpp" + > + </File> + <File RelativePath="..\..\backends\fs\abstract-fs.h" > </File> @@ -1326,6 +1324,14 @@ RelativePath="..\..\graphics\surface.h" > </File> + <File + RelativePath="..\..\graphics\thumbnail.cpp" + > + </File> + <File + RelativePath="..\..\graphics\thumbnail.h" + > + </File> <Filter Name="scaler" > @@ -1426,7 +1432,7 @@ > </File> <File - RelativePath="..\..\graphics\scaler\thumbnail.cpp" + RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp" > </File> </Filter> diff --git a/dists/redhat/scummvm-tools.spec b/dists/redhat/scummvm-tools.spec index 5ca5fe9cf8..564fc17274 100644 --- a/dists/redhat/scummvm-tools.spec +++ b/dists/redhat/scummvm-tools.spec @@ -19,6 +19,7 @@ Source : %{name}-%{version}.tar.bz2 BuildRoot : %{_tmppath}/%{name}-%{version}-root BuildRequires : zlib-devel +BuildRequires : wxGTK-devel #------------------------------------------------------------------------------ # Description #------------------------------------------------------------------------------ @@ -36,10 +37,12 @@ make echo -e "\t\tThis script is installed as\n\t\t"%{_datadir}/scummvm-tools/convert_dxa.sh.sample >> README %install -install -m755 -D encode_dxa %{buildroot}%{_bindir}/encode_dxa +install -m755 -d %{buildroot}%{_bindir} install -m755 -D compress_{agos,kyra,queen,saga,scumm_bun,scumm_san,scumm_sou,sword1,sword2,touche} %{buildroot}%{_bindir} -install -m755 -D de{kyra,scumm,sword2} %{buildroot}%{_bindir} -install -m755 -D extract_{agos,kyra,loom_tg16,mm_apple,mm_c64,mm_nes,scumm_mac,parallaction,zak_c64} %{buildroot}%{_bindir} +install -m755 -D de{kyra,scumm,sword2,gob} %{buildroot}%{_bindir} +install -m755 -D encode_dxa %{buildroot}%{_bindir}/encode_dxa +install -m755 -D extract_{agos,kyra,loom_tg16,mm_apple,mm_c64,mm_nes,scumm_mac,parallaction,zak_c64,gob_stk} %{buildroot}%{_bindir} +install -m755 -D tools_gui %{buildroot}%{_bindir}/scummvm_tools_gui install -m644 -D convert_dxa.sh %{buildroot}%{_datadir}/scummvm-tools/convert_dxa.sh.sample %clean @@ -54,6 +57,7 @@ rm -Rf ${RPM_BUILD_ROOT} %attr(0755,root,root)%{_bindir}/de* %attr(0755,root,root)%{_bindir}/extract_* %attr(0755,root,root)%{_bindir}/encode_dxa +%attr(0755,root,root)%{_bindir}/scummvm_tools_gui %attr(0644,root,root)%{_datadir}/scummvm-tools/convert_dxa.sh.sample #------------------------------------------------------------------------------ diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h index 500f98546b..d95035a073 100644 --- a/engines/agi/preagi.h +++ b/engines/agi/preagi.h @@ -73,7 +73,7 @@ public: // Keyboard int getSelection(SelectionTypes type); - int rnd(int hi) { return (_rnd->getRandomNumber(hi) + 1); } + int rnd(int hi) { return (_rnd->getRandomNumber(hi - 1) + 1); } // Text void drawStr(int row, int col, int attr, const char *buffer); diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index df7f32b432..f643ab9cfc 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -932,10 +932,17 @@ bool Mickey::loadGame() { if (_vm->getSelection(kSelAnyKey) == 0) return false; } else { - if (infile->readUint32BE() != MKID_BE('MICK')) - error("Mickey::loadGame wrong save game format"); + if (infile->readUint32BE() != MKID_BE('MICK')) { + warning("Mickey::loadGame wrong save game format"); + return false; + } saveVersion = infile->readByte(); + if (saveVersion < 2) { + warning("The planet data in this save game is corrupted. Load aborted"); + return false; + } + if (saveVersion != MSA_SAVEGAME_VERSION) warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, MSA_SAVEGAME_VERSION); @@ -953,7 +960,7 @@ bool Mickey::loadGame() { _game.iPlanetXtal[i] = infile->readByte(); for(i = 0; i < IDI_MSA_MAX_PLANET; i++) - _game.iClue[i] = infile->readByte(); + _game.iClue[i] = infile->readUint16LE(); infile->read(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); @@ -1058,7 +1065,7 @@ void Mickey::saveGame() { outfile->writeByte(_game.iPlanetXtal[i]); for(i = 0; i < IDI_MSA_MAX_PLANET; i++) - outfile->writeByte(_game.iClue[i]); + outfile->writeUint16LE(_game.iClue[i]); outfile->write(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h index 8d982dc401..f29d2fbccd 100644 --- a/engines/agi/preagi_mickey.h +++ b/engines/agi/preagi_mickey.h @@ -30,7 +30,7 @@ namespace Agi { -#define MSA_SAVEGAME_VERSION 1 +#define MSA_SAVEGAME_VERSION 2 // strings #define IDS_MSA_PATH_DAT "dat/%s" @@ -637,7 +637,7 @@ const int IDO_MSA_NEXT_PIECE[IDI_MSA_MAX_PLANET][5] = { {0x5B78, 0x5BB6, 0x5C29, 0x5C76, 0x5CE1}, // pluto {0x526B, 0x52DA, 0x5340, 0x53A1, 0x540C}, // jupiter {0x50F6, 0x512C, 0x5170, 0x51D5, 0x5228}, // mars - {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus + {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus }; // message offsets @@ -697,7 +697,7 @@ struct MSA_GAME { uint8 nXtals; uint8 iPlanetXtal[IDI_MSA_MAX_DAT]; - uint8 iClue[IDI_MSA_MAX_PLANET]; + uint16 iClue[IDI_MSA_MAX_PLANET]; char szAddr[IDI_MSA_MAX_BUTTON + 1]; // Flags diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index c2c815596e..f5cde579e6 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -53,7 +53,6 @@ Common::Array<AnimData> animDataTable; static const AnimDataEntry transparencyData[] = { {"ALPHA", 0xF}, - {"TITRE", 0xF}, {"TITRE2", 0xF}, {"ET", 0xC}, {"L311", 0x3}, @@ -586,6 +585,14 @@ int loadAni(const char *resourceName, int16 idx) { transparentColor = getAnimTransparentColor(resourceName); + // TODO: Merge this special case hack into getAnimTransparentColor somehow. + // HACK: Versions of TITRE.ANI with height 37 use color 0xF for transparency. + // Versions of TITRE.ANI with height 57 use color 0x0 for transparency. + // Fixes bug #2057619: FW: Glitches in title display of demo (regression). + if (scumm_stricmp(resourceName, "TITRE.ANI") == 0 && animHeader.frameHeight == 37) { + transparentColor = 0xF; + } + entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp index 45bfae7925..cc7e843c2b 100644 --- a/engines/cine/bg.cpp +++ b/engines/cine/bg.cpp @@ -41,10 +41,18 @@ byte loadCtFW(const char *ctName) { uint16 header[32]; byte *ptr, *dataPtr; + int16 foundFileIdx = findFileInBundle(ctName); + if (foundFileIdx == -1) { + warning("loadCtFW: Unable to find collision data file '%s'", ctName); + // FIXME: Rework this function's return value policy and return an appropriate value here. + // The return value isn't yet used for anything so currently it doesn't really matter. + return 0; + } + if (currentCtName != ctName) strcpy(currentCtName, ctName); - ptr = dataPtr = readBundleFile(findFileInBundle(ctName)); + ptr = dataPtr = readBundleFile(foundFileIdx); loadRelatedPalette(ctName); diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index cb900e8850..e24b23f7f0 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -200,9 +200,15 @@ void FWRenderer::incrustSprite(const objectStruct &obj) { width = animDataTable[obj.frame]._realWidth; height = animDataTable[obj.frame]._height; - assert(mask); - - drawSpriteRaw(data, mask, width, height, _background, x, y); + // There was an assert(mask) here before but it made savegame loading + // in Future Wars sometimes fail the assertion (e.g. see bug #2055912). + // Not drawing sprites that have no mask seems to work, but not sure + // if this is really a correct way to fix this. + if (mask) { + drawSpriteRaw(data, mask, width, height, _background, x, y); + } else { // mask == NULL + warning("FWRenderer::incrustSprite: Skipping maskless sprite (frame=%d)", obj.frame); + } } /*! \brief Draw command box on screen @@ -368,7 +374,7 @@ int FWRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) { idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); + drawSpriteRaw(g_cine->_textHandler.textTable[idx][FONT_DATA], g_cine->_textHandler.textTable[idx][FONT_MASK], FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y); x += width + 1; } @@ -436,6 +442,9 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { switch (it->type) { // color sprite case 0: + if (objectTable[it->objIdx].frame < 0) { + return; + } sprite = &animDataTable[objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; @@ -1037,7 +1046,7 @@ int OSRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) { idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); + drawSpriteRaw2(g_cine->_textHandler.textTable[idx][FONT_DATA], 0, FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y); x += width + 1; } @@ -1664,6 +1673,16 @@ void gfxResetRawPage(byte *pageRaw) { } void gfxConvertSpriteToRaw(byte *dst, const byte *src, uint16 w, uint16 h) { + // Output is 4 bits per pixel. + // Pixels are in 16 pixel chunks (8 bytes of source per 16 pixels of output). + // The source data is interleaved so that + // 1st big-endian 16-bit value contains all bit position 0 values for 16 pixels, + // 2nd big-endian 16-bit value contains all bit position 1 values for 16 pixels, + // 3rd big-endian 16-bit value contains all bit position 2 values for 16 pixels, + // 4th big-endian 16-bit value contains all bit position 3 values for 16 pixels. + // 1st pixel's bits are in the 16th bits, + // 2nd pixel's bits are in the 15th bits, + // 3rd pixel's bits are in the 14th bits etc. for (int y = 0; y < h; ++y) { for (int x = 0; x < w / 8; ++x) { for (int bit = 0; bit < 16; ++bit) { diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp index 657471be4e..7679d9d380 100644 --- a/engines/cine/part.cpp +++ b/engines/cine/part.cpp @@ -123,13 +123,13 @@ void CineEngine::readVolCnf() { unpackedSize = packedSize = f.size(); } uint8 *buf = new uint8[unpackedSize]; - f.read(buf, packedSize); - if (packedSize != unpackedSize) { - CineUnpacker cineUnpacker; - if (!cineUnpacker.unpack(buf, packedSize, buf, unpackedSize)) { - error("Error while unpacking 'vol.cnf' data"); - } + uint8 *packedBuf = new uint8[packedSize]; + f.read(packedBuf, packedSize); + CineUnpacker cineUnpacker; + if (!cineUnpacker.unpack(packedBuf, packedSize, buf, unpackedSize)) { + error("Error while unpacking 'vol.cnf' data"); } + delete[] packedBuf; uint8 *p = buf; int resourceFilesCount = READ_BE_UINT16(p); p += 2; int entrySize = READ_BE_UINT16(p); p += 2; @@ -211,26 +211,23 @@ int16 findFileInBundle(const char *fileName) { } void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize) { + assert(maxSize >= partBuffer[idx].packedSize); setMouseCursor(MOUSE_CURSOR_DISK); g_cine->_partFileHandle.seek(partBuffer[idx].offset, SEEK_SET); - g_cine->_partFileHandle.read(dataPtr, MIN(partBuffer[idx].packedSize, maxSize)); + g_cine->_partFileHandle.read(dataPtr, partBuffer[idx].packedSize); } byte *readBundleFile(int16 foundFileIdx, uint32 *size) { assert(foundFileIdx >= 0 && foundFileIdx < (int32)partBuffer.size()); bool error = false; byte *dataPtr = (byte *)calloc(partBuffer[foundFileIdx].unpackedSize, 1); - readFromPart(foundFileIdx, dataPtr, partBuffer[foundFileIdx].unpackedSize); - if (partBuffer[foundFileIdx].unpackedSize > partBuffer[foundFileIdx].packedSize) { - CineUnpacker cineUnpacker; - error = !cineUnpacker.unpack(dataPtr, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); - } else if (partBuffer[foundFileIdx].unpackedSize < partBuffer[foundFileIdx].packedSize) { - // Unpacked size of a file should never be less than its packed size - error = true; - } else { // partBuffer[foundFileIdx].unpackedSize == partBuffer[foundFileIdx].packedSize - debugC(5, kCineDebugPart, "Loaded non-compressed file '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); - } + byte *packedData = (byte *)calloc(partBuffer[foundFileIdx].packedSize, 1); + assert(dataPtr && packedData); + readFromPart(foundFileIdx, packedData, partBuffer[foundFileIdx].packedSize); + CineUnpacker cineUnpacker; + error = !cineUnpacker.unpack(packedData, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); + free(packedData); if (error) { warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 97f45488f2..6c13647ff3 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1501,7 +1501,18 @@ int FWScript::o1_compareGlobalVar() { debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value); - _compare = compareVars(_globalVars[varIdx], value); + // WORKAROUND for bug #2054882. Without this, the monks will always + // kill you as an impostor, even if you enter the monastery in disguise. + // + // TODO: Check whether this might be worked around in some other way + // like setting global variable 255 to 143 in Future Wars (This is + // supposedly what Future Wars checks for from time to time during + // gameplay to verify that copy protection was successfully passed). + if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) { + _compare = kCmpEQ; + } else { + _compare = compareVars(_globalVars[varIdx], value); + } } return 0; diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index 3618350476..164c5a9ca5 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -79,13 +79,13 @@ const int PCSoundDriver::_noteTable[] = { const int PCSoundDriver::_noteTableCount = ARRAYSIZE(_noteTable); struct AdlibRegisterSoundInstrument { - uint16 vibrato; - uint16 attackDecay; - uint16 sustainRelease; - uint16 feedbackStrength; - uint16 keyScaling; - uint16 outputLevel; - uint16 freqMod; + uint8 vibrato; + uint8 attackDecay; + uint8 sustainRelease; + uint8 feedbackStrength; + uint8 keyScaling; + uint8 outputLevel; + uint8 freqMod; }; struct AdlibSoundInstrument { diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index 33c16159ec..c8d48d3a06 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -39,6 +39,13 @@ const char **commandPrepositionTable; void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); +/*! \brief Loads font data from the given file. + * The number of characters used in the font varies between game versions: + * 78 (Most PC, Amiga and Atari ST versions of Future Wars, but also Operation Stealth's Amiga demo), + * 85 (All observed versions of German Future Wars (Amiga and PC), possibly Spanish Future Wars too), + * 90 (Most PC, Amiga and Atari ST versions of Operation Stealth), + * 93 (All observed versions of German Operation Stealth (Amiga and PC)). + */ void loadTextData(const char *filename) { Common::File fileHandle; assert(filename); @@ -46,30 +53,29 @@ void loadTextData(const char *filename) { if (!fileHandle.open(filename)) error("loadTextData(): Cannot open file %s", filename); - uint entrySize = fileHandle.readUint16BE(); - uint numEntry = fileHandle.readUint16BE(); + static const uint headerSize = 2 + 2; // The entry size (16-bit) and entry count (16-bit). + const uint entrySize = fileHandle.readUint16BE(); // Observed values: 8. + const uint entryCount = fileHandle.readUint16BE(); // Observed values: 624, 680, 720, 744. + const uint fontDataSize = entryCount * entrySize; // Observed values: 4992, 5440, 5760, 5952. + const uint numChars = entryCount / entrySize; // Observed values: 78, 85, 90, 93. + const uint bytesPerChar = fontDataSize / numChars; // Observed values: 64. + static const uint bytesPerRow = FONT_WIDTH / 2; // The input font data is 4-bit so it takes only half the space + + if (headerSize + fontDataSize != fileHandle.size()) { + warning("loadTextData: file '%s' (entrySize = %d, entryCount = %d) is of incorrect size %d", filename, entrySize, entryCount, fileHandle.size()); + } - uint sourceSize = numEntry * entrySize; Common::Array<byte> source; - source.resize(sourceSize); - fileHandle.read(source.begin(), sourceSize); + source.resize(fontDataSize); + fileHandle.read(source.begin(), fontDataSize); - const int fontHeight = 8; - const int fontWidth = (g_cine->getGameType() == Cine::GType_FW) ? 16 : 8; - uint numCharacters; - uint bytesPerCharacter; if (g_cine->getGameType() == Cine::GType_FW) { - numCharacters = (g_cine->getFeatures() & GF_ALT_FONT) ? 85 : 78; - bytesPerCharacter = sourceSize / numCharacters; // TODO: Check if this could be replaced with fontWidth * fontHeight loadRelatedPalette(filename); - } else { - numCharacters = 90; - bytesPerCharacter = fontWidth * fontHeight; } - for (uint i = 0; i < numCharacters; i++) { - gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], &source[i * bytesPerCharacter], fontWidth, fontHeight); - generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], fontWidth * fontHeight, 0); + for (uint i = 0; i < numChars; i++) { + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][FONT_DATA], &source[i * bytesPerChar], bytesPerRow, FONT_HEIGHT); + generateMask(g_cine->_textHandler.textTable[i][FONT_DATA], g_cine->_textHandler.textTable[i][FONT_MASK], FONT_WIDTH * FONT_HEIGHT, 0); } fileHandle.close(); diff --git a/engines/cine/texte.h b/engines/cine/texte.h index bc4beac492..0b1fc88e86 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -36,13 +36,20 @@ typedef char CommandeType[20]; // Number of characters in a font #define NUM_FONT_CHARS 256 +#define FONT_WIDTH 16 +#define FONT_HEIGHT 8 + +// Used for choosing between font's data and font's mask +#define FONT_DATA 0 +#define FONT_MASK 1 + struct CharacterEntry { byte characterIdx; byte characterWidth; }; struct TextHandler { - byte textTable[NUM_FONT_CHARS][2][16 * 8]; + byte textTable[NUM_FONT_CHARS][2][FONT_WIDTH * FONT_HEIGHT]; CharacterEntry fontParamTable[NUM_FONT_CHARS]; }; diff --git a/engines/cine/unpack.cpp b/engines/cine/unpack.cpp index 5d85ff6cab..7915fd1cf8 100644 --- a/engines/cine/unpack.cpp +++ b/engines/cine/unpack.cpp @@ -100,6 +100,14 @@ bool CineUnpacker::unpack(const byte *src, uint srcLen, byte *dst, uint dstLen) _dstBegin = dst; _dstEnd = dst + dstLen; + // Handle already unpacked data here + if (srcLen == dstLen) { + // Source length is same as destination length so the source + // data is already unpacked. Let's just copy it then. + memcpy(dst, src, srcLen); + return true; + } + // Initialize other variables _src = _srcBegin + srcLen - 4; uint32 unpackedLength = readSource(); // Unpacked length in bytes diff --git a/engines/cine/unpack.h b/engines/cine/unpack.h index e16cb594a9..2355df5ee1 100644 --- a/engines/cine/unpack.h +++ b/engines/cine/unpack.h @@ -35,14 +35,14 @@ namespace Cine { * A LZ77 style decompressor for Delphine's data files * used in at least Future Wars and Operation Stealth. * @note Works backwards in the source and destination buffers. - * @note Can work with source and destination in the same buffer if there's space. + * @warning Having the source and destination in the same buffer when unpacking can cause errors! */ class CineUnpacker { public: /** * Unpacks packed data from the source buffer to the destination buffer. - * @warning Do NOT call this on data that is not packed. - * @note Source and destination buffer pointers can be the same as long as there's space for the unpacked data. + * @note You may call this on already unpacked data but then source length must be equal to destination length. + * @warning The source and destination should not point to the same buffer. If they do, errors may occur! * @param src Pointer to the source buffer. * @param srcLen Length of the source buffer. * @param dst Pointer to the destination buffer. diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 5e4c0eee30..2621278c59 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1092,7 +1092,7 @@ bool CineEngine::makeLoad(char *saveName) { // that's not implemented here because it was never used in a stable // release of ScummVM but only during development (From revision 31453, // which introduced the problem, until revision 32073, which fixed it). - // Therefore be bail out if we detect this particular savegame format. + // Therefore we bail out if we detect this particular savegame format. warning("Detected a known broken savegame format, not loading savegame"); load = false; // Don't load the savegame } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index 06868494b5..954181d327 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -134,7 +134,7 @@ void DrasculaEngine::animation_1_1() { for (l2 = 0; l2 < 3; l2++) for (l = 0; l < 7; l++) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface); updateScreen(); if (getScan() == Common::KEYCODE_ESCAPE) { @@ -177,7 +177,7 @@ void DrasculaEngine::animation_1_1() { break; copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface); - talk_dr_grande(1); + talk_drascula_big(1); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; @@ -193,14 +193,14 @@ void DrasculaEngine::animation_1_1() { igorX = 66; igorY = 97; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); talk_igor(8, kIgorDch); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -297,13 +297,13 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; trackDrascula = 3; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); pause(1); trackDrascula = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -311,13 +311,13 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; trackDrascula = 3; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); pause(1); trackDrascula = 1; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -329,13 +329,13 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; trackDrascula = 3; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); pause(1); trackDrascula = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -596,6 +596,7 @@ void DrasculaEngine::animation_2_1() { } } +// John Hacker talks with the bartender to book a room void DrasculaEngine::animation_3_1() { if (_lang == kSpanish) textSurface = frontSurface; @@ -631,6 +632,7 @@ void DrasculaEngine::animation_3_1() { loadPic(97, extraSurface); } +// John Hacker talks with the pianist void DrasculaEngine::animation_4_1() { if (_lang == kSpanish) textSurface = frontSurface; @@ -680,14 +682,14 @@ void DrasculaEngine::animation_1_2() { void DrasculaEngine::animation_2_2() { trackProtagonist = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); moveCharacters(); updateRefresh(); updateScreen(); loadPic("an2_1.alg", frontSurface); loadPic("an2_2.alg", extraSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(1, 1, 201, 87, 50, 52, frontSurface, screenSurface); updateScreen(); @@ -701,7 +703,7 @@ void DrasculaEngine::animation_2_2() { updateAnim(55, 201, 87, 50, 52, 6, extraSurface); updateAnim(109, 201, 87, 50, 52, 2, extraSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); finishSound(); @@ -724,7 +726,7 @@ void DrasculaEngine::animation_4_2() { flags[9] = 1; pause(12); - talk(56); + talk(60); pause(8); clearRoom(); @@ -737,7 +739,7 @@ void DrasculaEngine::animation_4_2() { if (_lang == kSpanish) textSurface = frontSurface; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(10); @@ -761,13 +763,13 @@ void DrasculaEngine::animation_4_2() { talk_blind(7); talk_hacker(63); talk_blind(8); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); _system->delayMillis(1000); talk_hacker(64); talk_blind(9); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(14); @@ -822,7 +824,7 @@ void DrasculaEngine::animation_14_2() { loadPic("an14_2.alg", backSurface); for (int n = -160; n <= 0; n = n + 5 + l) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); moveCharacters(); moveVonBraun(); @@ -876,7 +878,7 @@ void DrasculaEngine::animation_16_2() { if (_lang == kSpanish) black(); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (_lang != kSpanish) centerText(_texthis[_lang][1], 180, 180); @@ -906,7 +908,7 @@ void DrasculaEngine::animation_16_2() { clearRoom(); loadPic("his2.alg", bgSurface, HALF_PAL); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (_lang != kSpanish) centerText(_texthis[_lang][2], 180, 180); @@ -932,7 +934,7 @@ void DrasculaEngine::animation_16_2() { clearRoom(); loadPic("his3.alg", bgSurface, HALF_PAL); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (_lang != kSpanish) centerText(_texthis[_lang][3], 180, 180); @@ -1009,24 +1011,24 @@ void DrasculaEngine::animation_17_2() { } void DrasculaEngine::animation_19_2() { - talk_vonBraunpuerta(5); + talk_vonBraun(5, kVonBraunDoor); } void DrasculaEngine::animation_20_2() { - talk_vonBraunpuerta(7); - talk_vonBraunpuerta(8); + talk_vonBraun(7, kVonBraunDoor); + talk_vonBraun(8, kVonBraunDoor); talk(383); - talk_vonBraunpuerta(9); + talk_vonBraun(9, kVonBraunDoor); talk(384); - talk_vonBraunpuerta(10); + talk_vonBraun(10, kVonBraunDoor); talk(385); - talk_vonBraunpuerta(11); + talk_vonBraun(11, kVonBraunDoor); if (flags[23] == 0) { talk(350); - talk_vonBraunpuerta(57); + talk_vonBraun(57, kVonBraunDoor); } else { talk(386); - talk_vonBraunpuerta(12); + talk_vonBraun(12, kVonBraunDoor); flags[18] = 0; flags[14] = 1; openDoor(15, 1); @@ -1043,7 +1045,7 @@ void DrasculaEngine::animation_20_2() { } void DrasculaEngine::animation_21_2() { - talk_vonBraunpuerta(6); + talk_vonBraun(6, kVonBraunDoor); } void DrasculaEngine::animation_23_2() { @@ -1052,26 +1054,26 @@ void DrasculaEngine::animation_23_2() { flags[21] = 1; if (flags[25] == 0) { - talk_vonBraun(13); - talk_vonBraun(14); + talk_vonBraun(13, kVonBraunDoor); + talk_vonBraun(14, kVonBraunDoor); pause(10); talk(387); } - talk_vonBraun(15); + talk_vonBraun(15, kVonBraunNormal); placeVonBraun(42); trackVonBraun = 1; - talk_vonBraun(16); + talk_vonBraun(16, kVonBraunNormal); trackVonBraun = 2; gotoObject(157, 147); gotoObject(131, 149); trackProtagonist = 0; animation_14_2(); if (flags[25] == 0) - talk_vonBraun(17); + talk_vonBraun(17, kVonBraunNormal); pause(8); trackVonBraun = 1; - talk_vonBraun(18); + talk_vonBraun(18, kVonBraunNormal); if (flags[29] == 0) animation_23_joined(); @@ -1083,9 +1085,9 @@ void DrasculaEngine::animation_23_2() { placeVonBraun(99); if (flags[29] == 0) { - talk_vonBraun(19); + talk_vonBraun(19, kVonBraunNormal); if (flags[25] == 0) { - talk_vonBraun(20); + talk_vonBraun(20, kVonBraunNormal); if (removeObject(kItemMoney) == 0) flags[30] = 1; if (removeObject(kItemTwoCoins) == 0) @@ -1093,7 +1095,7 @@ void DrasculaEngine::animation_23_2() { if (removeObject(kItemOneCoin) == 0) flags[32] = 1; } - talk_vonBraun(21); + talk_vonBraun(21, kVonBraunNormal); } else animation_27_2(); @@ -1152,7 +1154,7 @@ void DrasculaEngine::animation_25_2() { playSound(6); for (int n = 0; n >= -160; n = n - 8) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); moveCharacters(); @@ -1178,46 +1180,46 @@ void DrasculaEngine::animation_27_2() { removeObject(kItemEarWithEarPlug); addObject(kItemEarplugs); - talk_vonBraun(23); - talk_vonBraun(24); + talk_vonBraun(23, kVonBraunNormal); + talk_vonBraun(24, kVonBraunNormal); if (flags[30] == 1) addObject(kItemMoney); if (flags[31] == 1) addObject(kItemTwoCoins); if (flags[32] == 1) addObject(kItemOneCoin); - talk_vonBraun(25); - talk_vonBraun(26); + talk_vonBraun(25, kVonBraunNormal); + talk_vonBraun(26, kVonBraunNormal); } void DrasculaEngine::animation_28_2() { for(int i = 27; i <= 30; i++) - talk_vonBraun(i); + talk_vonBraun(i, kVonBraunNormal); } void DrasculaEngine::animation_29_2() { if (flags[33] == 0) { - talk_vonBraun(32); + talk_vonBraun(32, kVonBraunNormal); talk(398); - talk_vonBraun(33); + talk_vonBraun(33, kVonBraunNormal); talk(399); - talk_vonBraun(34); - talk_vonBraun(35); + talk_vonBraun(34, kVonBraunNormal); + talk_vonBraun(35, kVonBraunNormal); talk(400); - talk_vonBraun(36); - talk_vonBraun(37); + talk_vonBraun(36, kVonBraunNormal); + talk_vonBraun(37, kVonBraunNormal); talk(386); - talk_vonBraun(38); - talk_vonBraun(39); + talk_vonBraun(38, kVonBraunNormal); + talk_vonBraun(39, kVonBraunNormal); talk(401); - talk_vonBraun(40); - talk_vonBraun(41); + talk_vonBraun(40, kVonBraunNormal); + talk_vonBraun(41, kVonBraunNormal); flags[33] = 1; } else - talk_vonBraun(43); + talk_vonBraun(43, kVonBraunNormal); talk(402); - talk_vonBraun(42); + talk_vonBraun(42, kVonBraunNormal); if (flags[38] == 0) { talk(403); @@ -1227,12 +1229,12 @@ void DrasculaEngine::animation_29_2() { } void DrasculaEngine::animation_30_2() { - talk_vonBraun(31); + talk_vonBraun(31, kVonBraunNormal); talk(396); } void DrasculaEngine::animation_31_2() { - talk_vonBraun(44); + talk_vonBraun(44, kVonBraunNormal); placeVonBraun(-50); pause(15); gotoObject(159, 140); @@ -1247,23 +1249,23 @@ void DrasculaEngine::animation_31_2() { pause(22); talk(406); placeVonBraun(98); - talk_vonBraun(45); - talk_vonBraun(46); - talk_vonBraun(47); + talk_vonBraun(45, kVonBraunNormal); + talk_vonBraun(46, kVonBraunNormal); + talk_vonBraun(47, kVonBraunNormal); talk(407); - talk_vonBraun(48); - talk_vonBraun(49); + talk_vonBraun(48, kVonBraunNormal); + talk_vonBraun(49, kVonBraunNormal); talk(408); - talk_vonBraun(50); - talk_vonBraun(51); + talk_vonBraun(50, kVonBraunNormal); + talk_vonBraun(51, kVonBraunNormal); talk(409); - talk_vonBraun(52); - talk_vonBraun(53); + talk_vonBraun(52, kVonBraunNormal); + talk_vonBraun(53, kVonBraunNormal); pause(12); - talk_vonBraun(54); - talk_vonBraun(55); + talk_vonBraun(54, kVonBraunNormal); + talk_vonBraun(55, kVonBraunNormal); talk(410); - talk_vonBraun(56); + talk_vonBraun(56, kVonBraunNormal); breakOut = 1; @@ -1293,7 +1295,7 @@ void DrasculaEngine::animation_35_2() { updateAnim(1, 70, 90, 46, 80, 6, frontSurface); updateAnim(82, 70, 90, 46, 80, 2, frontSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); @@ -1396,7 +1398,7 @@ void DrasculaEngine::animation_6_3() { for (frame = 0; frame < 6; frame++) { pause(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(yoda_x[frame], yoda_y[frame], px, py, 78, 90, frontSurface, screenSurface); updateScreen(px, py, px, py, 78, 90, screenSurface); } @@ -1564,7 +1566,7 @@ void DrasculaEngine::animation_5_5(){ for (frame = 0; frame < 9; frame++) { pause(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, backSurface, screenSurface); updateScreen(pixelX, pixelY, pixelX,pixelY, 97,64, screenSurface); } @@ -1574,7 +1576,7 @@ void DrasculaEngine::animation_5_5(){ for (frame = 0; frame < 9; frame++) { pause(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, frontSurface, screenSurface); updateScreen(pixelX, pixelY, pixelX,pixelY, 97, 64, screenSurface); } @@ -1935,7 +1937,7 @@ void DrasculaEngine::animation_5_6() { animate("man.bin", 14); for (int n = -125; n <= 0; n = n + 2) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); pos_pen[3] = n; copyRectClip(pos_pen, drawSurface3, screenSurface); @@ -2056,7 +2058,7 @@ void DrasculaEngine::animation_9_6() { void DrasculaEngine::animation_10_6() { playSound(14); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyBackground(164, 85, 155, 48, 113, 114, drawSurface3, screenSurface); updateScreen(); @@ -2101,7 +2103,7 @@ void DrasculaEngine::animation_18_6() { } void DrasculaEngine::animation_19_6() { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(140, 23, 161, 69, 35, 80, drawSurface3, screenSurface); updateRefresh_pre(); @@ -2258,7 +2260,7 @@ void DrasculaEngine::animation_13_2() { void DrasculaEngine::animation_18_2() { talk(378); - talk_vonBraunpuerta(4); + talk_vonBraun(4, kVonBraunDoor); converse(3); } @@ -2272,11 +2274,11 @@ void DrasculaEngine::animation_22_2() { finishSound(); trackProtagonist = 1; - talk_vonBraunpuerta(1); + talk_vonBraun(1, kVonBraunDoor); talk(375); - talk_vonBraunpuerta(2); + talk_vonBraun(2, kVonBraunDoor); talk(376); - talk_vonBraunpuerta(3); + talk_vonBraun(3, kVonBraunDoor); flags[18] = 1; } @@ -2297,7 +2299,7 @@ void DrasculaEngine::animation_24_2() { flags[21] = 1; - talk_vonBraun(22); + talk_vonBraun(22, kVonBraunNormal); if (flags[22] == 0) converse(4); @@ -2387,7 +2389,7 @@ void DrasculaEngine::animation_7_2() { if (flags[3] == 1) copyBackground(258, 110, 85, 44, 23, 53, drawSurface3, bgSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); @@ -2485,7 +2487,7 @@ void DrasculaEngine::animation_6_2() { loadPic("ciego4.alg", backSurface); loadPic("ciego5.alg", frontSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(1); @@ -2497,7 +2499,7 @@ void DrasculaEngine::animation_6_2() { pause(4); talk_hacker(67); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(10); @@ -2536,7 +2538,7 @@ void DrasculaEngine::animation_33_2() { if (_lang == kSpanish) textSurface = frontSurface; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(10); @@ -2549,7 +2551,7 @@ void DrasculaEngine::animation_33_2() { talk_blind(10); talk_hacker(65); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(14); @@ -2663,7 +2665,7 @@ void DrasculaEngine::animation_6_4() { loadPic(26, bgSurface, HALF_PAL); loadPic("aux26.alg", drawSurface3); loadPic("auxigor.alg", frontSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); update_26_pre(); igorX = 104; igorY = 71; diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index 9832d58294..81c8d9a62a 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -218,7 +218,7 @@ static const DrasculaGameDescription gameDescriptions[] = { 0, { {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563}, - {"packet.005", 0, "f80e10e37000a2201eabf8dad82c7f64", 16184223}, + {"packet.005", 0, "58caac54b891f5d7f335e710e45e5d29", 16209623}, {NULL, 0, NULL, 0} }, Common::IT_ITA, diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 2d24978f21..ac402c82ba 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -181,6 +181,8 @@ int DrasculaEngine::go() { currentChapter = 1; // values from 1 to 6 will start each part of game hay_que_load = 0; + checkCD(); + for (;;) { int i; @@ -224,41 +226,35 @@ int DrasculaEngine::go() { if (currentChapter != 6) loadPic(95, tableSurface); - if (currentChapter == 1) { + if (currentChapter != 3) loadPic(96, frontSurface, COMPLETE_PAL); - loadPic(99, backSurface); - loadPic(97, extraSurface); + + if (currentChapter == 1) { } else if (currentChapter == 2) { - loadPic(96, frontSurface, COMPLETE_PAL); loadPic("pts.alg", drawSurface2); } else if (currentChapter == 3) { loadPic("aux13.alg", bgSurface, COMPLETE_PAL); loadPic(96, frontSurface); - loadPic(97, extraSurface); - loadPic(99, backSurface); } else if (currentChapter == 4) { - loadPic(96, frontSurface, COMPLETE_PAL); if (hay_que_load == 0) animation_ray(); loadPic(96, frontSurface); clearRoom(); - loadPic(99, backSurface); - loadPic(97, extraSurface); } else if (currentChapter == 5) { - loadPic(96, frontSurface, COMPLETE_PAL); - loadPic(97, extraSurface); - loadPic(99, backSurface); } else if (currentChapter == 6) { igorX = 105, igorY = 85, trackIgor = 1; drasculaX = 62, drasculaY = 99, trackDrascula = 1; actorFrames[kFramePendulum] = 0; flag_tv = 0; - loadPic(96, frontSurface, COMPLETE_PAL); + loadPic(95, tableSurface); + } + + if (currentChapter != 2) { loadPic(99, backSurface); loadPic(97, extraSurface); - loadPic(95, tableSurface); } + memset(iconName, 0, sizeof(iconName)); for (i = 0; i < 6; i++) @@ -485,6 +481,7 @@ bool DrasculaEngine::runCurrentChapter() { #else if (rightMouseButton == 1 && menuScreen == 1) { #endif + delay(100); if (currentChapter == 2) loadPic(menuBackground, backSurface); else @@ -502,8 +499,14 @@ bool DrasculaEngine::runCurrentChapter() { } else { #else } - if (rightMouseButton == 1 && menuScreen == 0) { + + // Do not show the inventory screen in chapter 5, if the right mouse button is clicked + // while the plug (object 16) is held + // Fixes bug #2059621 - "DRASCULA: Plug bug" + if (rightMouseButton == 1 && menuScreen == 0 && + !(currentChapter == 5 && pickedObject == 16)) { #endif + delay(100); characterMoved = 0; if (trackProtagonist == 2) trackProtagonist = 1; @@ -523,8 +526,10 @@ bool DrasculaEngine::runCurrentChapter() { } if (leftMouseButton == 1 && menuBar == 1) { + delay(100); selectVerbFromBar(); } else if (leftMouseButton == 1 && takeObject == 0) { + delay(100); if (verify1()) return true; } else if (leftMouseButton == 1 && takeObject == 1) { @@ -796,7 +801,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){ do { counter--; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (currentChapter == 3) updateScreen(0, 0, 0, y, 320, 200, screenSurface); else @@ -820,7 +825,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){ } } while (counter > 0); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); } diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index 8bb73d8dd1..2eb7a19559 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -135,6 +135,11 @@ enum IgorTalkerTypes { kIgorWig = 4 }; +enum VonBraunTalkerTypes { + kVonBraunNormal = 0, + kVonBraunDoor = 1 +}; + enum AnimFrameTypes { kFrameBlind = 0, kFrameSnore = 1, @@ -252,6 +257,11 @@ public: void setPalette(byte *PalBuf); void copyBackground(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *src, byte *dest); + + void copyBackground() { + copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + } + void copyRect(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *src, byte *dest); void copyRectClip(int *Array, byte *src, byte *dest); @@ -417,7 +427,7 @@ public: void talk_bj_bed(int); void talk_htel(int); void talk_bj(int); - void talk_baul(int); + void talk_trunk(int); void talk(int); void talk(const char *, const char *); void talk_sync(const char *, const char *, const char *); @@ -425,9 +435,8 @@ public: void talk_pianist(int); void talk_werewolf(int); void talk_mus(int); - void talk_dr_grande(int); - void talk_vonBraun(int); - void talk_vonBraunpuerta(int); + void talk_drascula_big(int); + void talk_vonBraun(int, int); void talk_blind(int); void talk_hacker(int); void talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface); diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 67993bfb6c..cde9dcca4d 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -61,7 +61,7 @@ void DrasculaEngine::freeMemory() { } void DrasculaEngine::moveCursor() { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); moveCharacters(); @@ -621,12 +621,11 @@ void DrasculaEngine::decodeRLE(byte* srcPtr, byte* dstPtr) { pixel = *srcPtr++; } for (uint j = 0; j < repeat; j++) { - curByte++; - if (curByte > 64000) { + *dstPtr++ = pixel; + if (++curByte >= 64000) { stopProcessing = true; break; } - *dstPtr++ = pixel; } } } diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 37dddf4b7e..0693b342da 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -252,7 +252,7 @@ bool DrasculaEngine::room_6(int fl) { else if (pickedObject == kVerbClose && fl == 138) closeDoor(0, 1); else if (pickedObject == kVerbOpen && fl == 143 && flags[2] == 0) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface); updateScreen(); @@ -263,7 +263,7 @@ bool DrasculaEngine::room_6(int fl) { updateScreen(); finishSound(); } else if (pickedObject == kVerbClose && fl == 143 && flags[2] == 1) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); flags[2] = 0; updateRefresh_pre(); copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface); @@ -274,7 +274,7 @@ bool DrasculaEngine::room_6(int fl) { updateScreen(); finishSound(); } else if (pickedObject == kVerbOpen && fl == 139 && flags[1] == 0) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface); updateScreen(); @@ -287,7 +287,7 @@ bool DrasculaEngine::room_6(int fl) { updateScreen(); finishSound(); } else if (pickedObject == kVerbPick && fl == 140) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface); updateScreen(); @@ -407,7 +407,7 @@ bool DrasculaEngine::room_15(int fl) { talk_sync(_text[_lang][46], "46.als", "4442444244244"); trackProtagonist = 1; } else if (pickedObject == 18 && fl == 188 && flags[26] == 0) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(133, 135, curX + 6, curY, 39, 63, drawSurface3, screenSurface); updateScreen(); playSound(8); @@ -440,7 +440,7 @@ bool DrasculaEngine::room_16(int fl) { pause(10); talk_sync(_text[_lang][50], "50.als", "11111111111144432554433"); pause(3); - talk_baul(83); + talk_trunk(83); } else if (pickedObject == kVerbOpen && fl == 183) { openDoor(19, NO_DOOR); if (flags[20] == 0) { @@ -497,7 +497,7 @@ bool DrasculaEngine::room_18(int fl) { else if (pickedObject == kVerbTalk && fl == 55 && flags[36] == 1) talk(109); else if (pickedObject == kVerbPick && fl == 182) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(44, 1, curX, curY, 41, 70, drawSurface2, screenSurface); updateRefresh(); @@ -519,7 +519,7 @@ bool DrasculaEngine::room_18(int fl) { trackProtagonist = 3; updateRoom(); updateScreen(); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(1, 1, curX - 1, curY + 3, 42, 67, drawSurface2, screenSurface); updateRefresh(); @@ -815,10 +815,11 @@ bool DrasculaEngine::room_53(int fl) { flags[2] = 1; withoutVerb(); updateVisible(); + pickedObject = kVerbMove; } else if (pickedObject == 16) { - talk(439); - withoutVerb(); + // Wall plug in chapter 5 visible[3] = 1; + hasAnswer = 0; } else hasAnswer = 0; @@ -1976,7 +1977,7 @@ bool DrasculaEngine::exitRoom(int l) { } void DrasculaEngine::updateRoom() { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (currentChapter == 3) { if (flags[0] == 0) diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp index 6f88a58fbb..d3e4d0dd31 100644 --- a/engines/drascula/saveload.cpp +++ b/engines/drascula/saveload.cpp @@ -63,7 +63,7 @@ bool DrasculaEngine::saveLoadScreen() { for (;;) { y = 27; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); for (n = 0; n < NUM_SAVES; n++) { print_abc(names[n], 116, y); y = y + 9; diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index a89c5ff734..5ee7f13a25 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -70,11 +70,11 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { do { if (talkerType == kIgorDch || talkerType == kIgorFront) { face = _rnd->getRandomNumber(7); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); } else if (talkerType == kIgorSeated || talkerType == kIgorWig) { face = _rnd->getRandomNumber(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); } @@ -127,7 +127,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { } if (talkerType == kIgorDch || (talkerType == kIgorFront && currentChapter == 1)) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); } @@ -152,7 +152,7 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) { do { face = _rnd->getRandomNumber(7); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -179,7 +179,7 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) { } while (!isTalkFinished(&length)); if (talkerType == 0) - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (talkerType == 1 && currentChapter == 6) updateRoom(); @@ -193,6 +193,41 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) { updateScreen(); } +void DrasculaEngine::talk_drascula_big(int index) { + char filename[20]; + sprintf(filename, "d%i.als", index); + const char *said = _textd[_lang][index]; + int x_talk[4] = {47, 93, 139, 185}; + int face; + int l = 0; + int length = strlen(said); + + color_abc(kColorRed); + + talkInit(filename); + + do { + face = _rnd->getRandomNumber(3); + copyBackground(); + copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface); + copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface); + l++; + if (l == 7) + l = 0; + + if (withVoices == 0) + centerText(said, 191, 69); + + updateScreen(); + + pause(3); + + byte key = getScan(); + if (key == Common::KEYCODE_ESCAPE) + term_int = 1; + } while (!isTalkFinished(&length)); +} + void DrasculaEngine::talk_solo(const char *said, const char *filename) { int length = strlen(said); @@ -204,7 +239,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) { talkInit(filename); if (currentChapter == 6) - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); do { if (withVoices == 0) { @@ -219,7 +254,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) { } while (!isTalkFinished(&length)); if (currentChapter == 6) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); } } @@ -260,7 +295,7 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) { face = _rnd->getRandomNumber(5); } - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -299,7 +334,7 @@ void DrasculaEngine::talk_bj(int index) { if (currentChapter != 5) { face = _rnd->getRandomNumber(4); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -375,7 +410,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) { do { face = _rnd->getRandomNumber(5); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (currentChapter == 2) @@ -498,7 +533,10 @@ void DrasculaEngine::talk_drunk(int index) { } } -void DrasculaEngine::talk_vonBraun(int index) { +// talker types: +// 0: kVonBraunNormal +// 1: KVonBraunDoor +void DrasculaEngine::talk_vonBraun(int index, int talkerType) { char filename[20]; sprintf(filename, "VB%i.als", index); const char *said = _textvb[_lang][index]; @@ -513,49 +551,32 @@ void DrasculaEngine::talk_vonBraun(int index) { copyBackground(vonBraunX + 5, 64, OBJWIDTH + 1, 0, 25, 27, bgSurface, drawSurface3); do { - if (trackVonBraun == 1) { - face = _rnd->getRandomNumber(5); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - - moveCharacters(); - moveVonBraun(); - - copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface); - copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface); - updateRefresh(); - } - - if (withVoices == 0) - centerText(said, vonBraunX, 66); - - updateScreen(); - - pause(3); - } while (!isTalkFinished(&length)); - - updateRoom(); - updateScreen(); - if (musicStatus() == 0 && flags[11] == 0 && roomMusic != 0) - playMusic(roomMusic); -} + if (talkerType == kVonBraunNormal) { + if (trackVonBraun == 1) { + face = _rnd->getRandomNumber(5); + copyBackground(); -void DrasculaEngine::talk_vonBraunpuerta(int index) { - char filename[20]; - sprintf(filename, "VB%i.als", index); - const char *said = _textvb[_lang][index]; - int length = strlen(said); + moveCharacters(); + moveVonBraun(); - color_abc(kColorBrown); + copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface); + copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface); + updateRefresh(); + } - talkInit(filename); + if (withVoices == 0) + centerText(said, vonBraunX, 66); - do { - updateRoom(); + updateScreen(); + pause(3); + } else { + updateRoom(); - if (withVoices == 0) - centerText(said, 150, 80); + if (withVoices == 0) + centerText(said, 150, 80); - updateScreen(); + updateScreen(); + } } while (!isTalkFinished(&length)); updateRoom(); @@ -580,13 +601,13 @@ void DrasculaEngine::talk_blind(int index) { color_abc(kColorBrown); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); talkInit(filename); do { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); pos_blind[5] = 149; char c = toupper(syncChar[p]); @@ -623,7 +644,7 @@ void DrasculaEngine::talk_hacker(int index) { const char *said = _textd[_lang][index]; int length = strlen(said); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); color_abc(kColorYellow); @@ -683,7 +704,7 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker else face = _rnd->getRandomNumber(4); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (talkerType == 0) @@ -706,7 +727,7 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker } while (!isTalkFinished(&length)); flags[1] = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); updateScreen(); } @@ -726,7 +747,7 @@ void DrasculaEngine::talk_bj_bed(int index) { do { face = _rnd->getRandomNumber(4); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -771,7 +792,7 @@ void DrasculaEngine::talk_htel(int index) { else faceBuffer = (char *)backSurface; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(x_talk[face], 1, 45, 24, 92, 108, (byte *)faceBuffer, screenSurface); @@ -782,7 +803,7 @@ void DrasculaEngine::talk_htel(int index) { pause(3); } while (!isTalkFinished(&length)); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); } @@ -808,7 +829,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha strncpy(buf, &syncChar[p], 1); face = atoi(buf); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (currentChapter == 2) @@ -871,7 +892,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha playMusic(roomMusic); } -void DrasculaEngine::talk_baul(int index) { +void DrasculaEngine::talk_trunk(int index) { char filename[20]; sprintf(filename, "d%i.als", index); const char *said = _text[_lang][index]; @@ -903,41 +924,6 @@ void DrasculaEngine::talk_baul(int index) { updateScreen(); } -void DrasculaEngine::talk_dr_grande(int index) { - char filename[20]; - sprintf(filename, "D%i.als", index); - const char *said = _textd[_lang][index]; - int x_talk[4] = {47, 93, 139, 185}; - int face; - int l = 0; - int length = strlen(said); - - color_abc(kColorRed); - - talkInit(filename); - - do { - face = _rnd->getRandomNumber(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface); - copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface); - l++; - if (l == 7) - l = 0; - - if (withVoices == 0) - centerText(said, 191, 69); - - updateScreen(); - - pause(3); - - byte key = getScan(); - if (key == Common::KEYCODE_ESCAPE) - term_int = 1; - } while (!isTalkFinished(&length)); -} - void DrasculaEngine::talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface) { int face; int length = strlen(said); @@ -946,7 +932,7 @@ void DrasculaEngine::talk_generic(const char* said, const char* filename, int* f do { face = _rnd->getRandomNumber(faceCount - 1); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyBackground(faces[face], coords[0], coords[1], coords[2], coords[3], coords[4], surface, screenSurface); diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 15e343c8cc..2de645ad76 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -57,6 +57,7 @@ static const PlainGameDescriptor gobGames[] = { {"inca2", "Inca II: Wiracocha"}, {"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble"}, {"dynasty", "The Last Dynasty"}, + {"urban", "Urban Runner"}, {0, 0} }; @@ -1771,7 +1772,7 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - kGameTypeWoodruff, + kGameTypeDynasty, kFeatures640, "intro" }, @@ -1784,7 +1785,20 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - kGameTypeWoodruff, + kGameTypeDynasty, + kFeatures640, + "intro" + }, + { + { + "urban", + "", + AD_ENTRY1s("intro.stk", "3ab2c542bd9216ae5d02cc6f45701ae1", 1252436), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeDynasty, kFeatures640, "intro" }, diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index 8a7de9bdaa..7136646018 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -323,7 +323,38 @@ void Draw::adjustCoords(char adjust, int16 *coord1, int16 *coord2) { } } -void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, +int Draw::stringLength(const char *str, int16 fontIndex) { + static const int8 dword_8F74C[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if ((fontIndex < 0) || (fontIndex > 7) || !_fonts[fontIndex]) + return 0; + + int len = 0; + + if (_vm->_global->_language == 10) { + + for (int i = 0; str[i] != 0; i++) { + if (((unsigned char) str[i+1]) < 128) { + len += dword_8F74C[4]; + i++; + } else + len += _fonts[fontIndex]->itemWidth; + } + + } else { + + if (_fonts[fontIndex]->extraData) + while (*str != 0) + len += *(_fonts[fontIndex]->extraData + (*str++ - _fonts[fontIndex]->startItem)); + else + len = (strlen(str) * _fonts[fontIndex]->itemWidth); + + } + + return len; +} + +void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2, int16 transp, SurfaceDesc *dest, Video::FontDesc *font) { while (*str != '\0') { @@ -337,7 +368,7 @@ void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, } void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right, - int16 bottom, char *str, int16 fontIndex, int16 color) { + int16 bottom, const char *str, int16 fontIndex, int16 color) { adjustCoords(1, &left, &top); adjustCoords(1, &right, &bottom); diff --git a/engines/gob/draw.h b/engines/gob/draw.h index 9ba589aa53..897208a42d 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -69,7 +69,7 @@ public: int16 _destSurface; char _letterToPrint; - char *_textToPrint; + const char *_textToPrint; int16 _backDeltaX; int16 _backDeltaY; @@ -146,10 +146,11 @@ public: void adjustCoords(char adjust, uint16 *coord1, uint16 *coord2) { adjustCoords(adjust, (int16 *) coord1, (int16 *) coord2); } - void drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, + int stringLength(const char *str, int16 fontIndex); + void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2, int16 transp, SurfaceDesc *dest, Video::FontDesc *font); void printTextCentered(int16 id, int16 left, int16 top, int16 right, - int16 bottom, char *str, int16 fontIndex, int16 color); + int16 bottom, const char *str, int16 fontIndex, int16 color); int32 getSpriteRectSize(int16 index); void forceBlit(bool backwards = false); diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index d64ce3c9cc..8057402985 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -61,7 +61,9 @@ const Common::Language GobEngine::_gobToScummVMLang[] = { Common::EN_USA, Common::NL_NLD, Common::KO_KOR, - Common::HB_ISR + Common::HB_ISR, + Common::PT_BRA, + Common::JA_JPN }; GobEngine::GobEngine(OSystem *syst) : Engine(syst) { @@ -114,7 +116,7 @@ int GobEngine::go() { } const char *GobEngine::getLangDesc(int16 language) const { - if ((language < 0) || (language > 8)) + if ((language < 0) || (language > 10)) language = 2; return Common::getLanguageDescription(_gobToScummVMLang[language]); } @@ -238,6 +240,12 @@ int GobEngine::init() { case Common::HB_ISR: _global->_language = 8; break; + case Common::PT_BRA: + _global->_language = 9; + break; + case Common::JA_JPN: + _global->_language = 10; + break; default: // Default to English _global->_language = 2; @@ -381,6 +389,20 @@ bool GobEngine::initGameParts() { _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); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v4(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); + break; + default: deinitGameParts(); return false; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 485389f990..a48a99ec42 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -93,7 +93,8 @@ enum GameType { kGameTypeBargon, kGameTypeWeen, kGameTypeLostInTime, - kGameTypeInca2 + kGameTypeInca2, + kGameTypeDynasty }; enum Features { diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index 5add0b9cea..55758cdfdc 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -652,7 +652,7 @@ void Goblin::adjustDest(int16 posX, int16 posY) { if ((_vm->_map->getPass(_pressedMapX, _pressedMapY) == 0) && ((_gobAction == 0) || - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0))) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0))) { resDelta = -1; resDeltaDir = 0; @@ -727,17 +727,17 @@ void Goblin::adjustDest(int16 posX, int16 posY) { void Goblin::adjustTarget(void) { if ((_gobAction == 4) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0)) { if ((_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) { _pressedMapY--; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) { _pressedMapX++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && (_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) { _pressedMapY--; _pressedMapX++; } @@ -747,7 +747,7 @@ void Goblin::adjustTarget(void) { } void Goblin::targetDummyItem(Gob_Object *gobDesc) { - if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 && + if (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0 && _vm->_map->getPass(_pressedMapX, _pressedMapY) == 1) { if (gobDesc->curLookDir == 0) { _vm->_map->_itemPoses[0].x = _pressedMapX; @@ -771,7 +771,7 @@ void Goblin::targetItem(void) { Gob_Object *itemDesc; if ((_gobAction == 3) || (_gobAction == 4)) { - items = _vm->_map->_itemsMap[_pressedMapY][_pressedMapX]; + items = _vm->_map->getItem(_pressedMapX, _pressedMapY); if ((_gobAction == 4) && ((items & 0xFF00) != 0) && (_objects[_itemToObject[(items & 0xFF00) >> 8]]->pickable == 1)) { _destItemId = (items & 0xFF00) >> 8; @@ -802,40 +802,40 @@ void Goblin::targetItem(void) { _gobDestX = _vm->_map->_itemPoses[_destItemId].x; } else if ((items & 0xFF00) != 0) { if (_vm->_map->_itemPoses[_destItemId].orient == 4) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] & 0xFF00) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { + if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) & 0xFF00) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) { _pressedMapX--; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] & 0xFF00) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { + if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) & 0xFF00) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) { _pressedMapX++; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } - if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] & 0xFF00) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { + if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) & 0xFF00) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) { _pressedMapY++; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; } } else { if (_vm->_map->_itemPoses[_destItemId].orient == 4) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1]) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { + if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY)) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY))) { _pressedMapX--; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1]) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { + if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY)) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY))) { _pressedMapX++; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; @@ -843,8 +843,8 @@ void Goblin::targetItem(void) { } if (_pressedMapY < (_vm->_map->_mapHeight-1)) { - if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX]) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { + if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1)) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY))) { _pressedMapY++; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; @@ -931,37 +931,37 @@ void Goblin::moveFindItem(int16 posX, int16 posY) { _pressedMapX = CLIP(posX / 12, 0, _vm->_map->_mapWidth - 1); _pressedMapY = CLIP(posY / 6, 0, _vm->_map->_mapHeight - 1); - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0) && (i < 20)) { + if ((_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0) && (i < 20)) { if ((_pressedMapY < (_vm->_map->_mapHeight - 1)) && - (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] != 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) != 0)) { _pressedMapY++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && (_pressedMapY < (_vm->_map->_mapHeight - 1)) && - (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY + 1) != 0)) { _pressedMapX++; _pressedMapY++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) { _pressedMapX++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && (_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) { _pressedMapX++; _pressedMapY--; } else if ((_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) { _pressedMapY--; } else if ((_pressedMapY > 0) && (_pressedMapX > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX - 1] != 0)) { + (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY - 1) != 0)) { _pressedMapY--; _pressedMapX--; } else if ((_pressedMapX > 0) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] != 0)) { + (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) != 0)) { _pressedMapX--; } else if ((_pressedMapX > 0) && (_pressedMapY < (_vm->_map->_mapHeight - 1)) && - (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX - 1] != 0)) { + (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY + 1) != 0)) { _pressedMapX--; _pressedMapY++; } @@ -1384,11 +1384,11 @@ void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) { for (int y = 0; y < _vm->_map->_mapHeight; y++) { for (int x = 0; x < _vm->_map->_mapWidth; x++) { if (_itemByteFlag == 1) { - if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPocket) - _vm->_map->_itemsMap[y][x] &= 0xFF; + if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPocket) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF); } else { - if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPocket) - _vm->_map->_itemsMap[y][x] &= 0xFF00; + if ((_vm->_map->getItem(x, y) & 0xFF) == idToPocket) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00); } } } @@ -1494,18 +1494,16 @@ void Goblin::swapItems(int16 indexToPick, int16 idToPick) { if (_itemByteFlag == 0) { for (y = 0; y < _vm->_map->_mapHeight; y++) { for (x = 0; x < _vm->_map->_mapWidth; x++) { - if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPick) - _vm->_map->_itemsMap[y][x] = - (_vm->_map->_itemsMap[y][x] & 0xFF00) + idToPlace; + if ((_vm->_map->getItem(x, y) & 0xFF) == idToPick) + _vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF00) + idToPlace); } } } else { for (y = 0; y < _vm->_map->_mapHeight; y++) { for (x = 0; x < _vm->_map->_mapWidth; x++) { - if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPick) - _vm->_map->_itemsMap[y][x] = - (_vm->_map->_itemsMap[y][x] & 0xFF) + (idToPlace << 8); + if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPick) + _vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF) + (idToPlace << 8)); } } } diff --git a/engines/gob/inter.h b/engines/gob/inter.h index b684be6c07..ad59d0d15a 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -529,6 +529,64 @@ protected: void o4_playVmdOrMusic(); }; +class Inter_v5 : public Inter_v4 { +public: + Inter_v5(GobEngine *vm); + virtual ~Inter_v5() {} + +protected: + typedef void (Inter_v5::*OpcodeDrawProcV5)(); + typedef bool (Inter_v5::*OpcodeFuncProcV5)(OpFuncParams &); + typedef void (Inter_v5::*OpcodeGoblinProcV5)(OpGobParams &); + struct OpcodeDrawEntryV5 { + OpcodeDrawProcV5 proc; + const char *desc; + }; + struct OpcodeFuncEntryV5 { + OpcodeFuncProcV5 proc; + const char *desc; + }; + struct OpcodeGoblinEntryV5 { + OpcodeGoblinProcV5 proc; + const char *desc; + }; + const OpcodeDrawEntryV5 *_opcodesDrawV5; + const OpcodeFuncEntryV5 *_opcodesFuncV5; + const OpcodeGoblinEntryV5 *_opcodesGoblinV5; + static const int _goblinFuncLookUp[][2]; + + virtual void setupOpcodes(); + virtual void executeDrawOpcode(byte i); + virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); + virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); + virtual const char *getOpcodeDrawDesc(byte i); + virtual const char *getOpcodeFuncDesc(byte i, byte j); + virtual const char *getOpcodeGoblinDesc(int i); + + byte _byte_8AA14; + + void o5_deleteFile(); + + bool o5_istrlen(OpFuncParams ¶ms); + + void o5_spaceShooter(OpGobParams ¶ms); + void o5_getSystemCDSpeed(OpGobParams ¶ms); + void o5_getSystemRAM(OpGobParams ¶ms); + void o5_getSystemCPUSpeed(OpGobParams ¶ms); + void o5_getSystemDrawSpeed(OpGobParams ¶ms); + void o5_totalSystemSpecs(OpGobParams ¶ms); + void o5_saveSystemSpecs(OpGobParams ¶ms); + void o5_loadSystemSpecs(OpGobParams ¶ms); + + void o5_gob92(OpGobParams ¶ms); + void o5_gob95(OpGobParams ¶ms); + void o5_gob96(OpGobParams ¶ms); + void o5_gob97(OpGobParams ¶ms); + void o5_gob98(OpGobParams ¶ms); + void o5_gob100(OpGobParams ¶ms); + void o5_gob200(OpGobParams ¶ms); +}; + } // End of namespace Gob #endif // GOB_INTER_H diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index cc114f0afc..1e01cd9048 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -2443,10 +2443,10 @@ void Inter_v1::o1_getItem(OpGobParams ¶ms) { int16 xPos = load16(); int16 yPos = load16(); - if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); + if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) + params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8); else - params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos); } void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { @@ -2468,10 +2468,10 @@ void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) { xPos = VAR(xPos); yPos = VAR(yPos); - if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); + if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) + params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8); else - params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos); } void Inter_v1::o1_setPassMap(OpGobParams ¶ms) { @@ -3025,88 +3025,88 @@ void Inter_v1::animPalette() { void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) { for (int y = 0; y < _vm->_map->_mapHeight; y++) { for (int x = 0; x < _vm->_map->_mapWidth; x++) { - if ((_vm->_map->_itemsMap[y][x] & 0xFF) == item) - _vm->_map->_itemsMap[y][x] &= 0xFF00; - else if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == item) - _vm->_map->_itemsMap[y][x] &= 0xFF; + if ((_vm->_map->getItem(x, y) & 0xFF) == item) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00); + else if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == item) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF); } } if (xPos < _vm->_map->_mapWidth - 1) { if (yPos > 0) { - if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) != 0)) { + if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) != 0)) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item; + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos - 1][xPos + 1] = - (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) + item; + _vm->_map->setItem(xPos + 1, yPos - 1, + (_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos - 1][xPos + 1] = - (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos + 1, yPos - 1, + (_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF) + (item << 8)); } } else { - if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0)) { + if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0)) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item; + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8)); } } } else { if (yPos > 0) { - if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0)) { + if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0)) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8)); } } else { - if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) { + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); } } } diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp new file mode 100644 index 0000000000..6df76bda4a --- /dev/null +++ b/engines/gob/inter_v5.cpp @@ -0,0 +1,1040 @@ +/* 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/file.h" + +#include "gob/gob.h" +#include "gob/inter.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/parse.h" +#include "gob/draw.h" + +namespace Gob { + +#define OPCODE(x) _OPCODE(Inter_v5, x) + +const int Inter_v5::_goblinFuncLookUp[][2] = { + {0, 0}, + {1, 0}, + {80, 1}, + {81, 2}, + {82, 3}, + {83, 4}, + {84, 5}, + {85, 6}, + {86, 7}, + {87, 0}, + {88, 0}, + {89, 0}, + {90, 0}, + {91, 0}, + {92, 8}, + {93, 0}, + {94, 0}, + {95, 9}, + {96, 10}, + {97, 11}, + {98, 12}, + {99, 0}, + {100, 13}, + {200, 14}, + {30, 24}, + {32, 25}, + {33, 26}, + {34, 27}, + {35, 28}, + {36, 29}, + {37, 30}, + {40, 31}, + {41, 32}, + {42, 33}, + {43, 34}, + {44, 35}, + {50, 36}, + {52, 37}, + {53, 38}, + {100, 39}, + {152, 40}, + {200, 41}, + {201, 42}, + {202, 43}, + {203, 44}, + {204, 45}, + {250, 46}, + {251, 47}, + {252, 48}, + {500, 49}, + {502, 50}, + {503, 51}, + {600, 52}, + {601, 53}, + {602, 54}, + {603, 55}, + {604, 56}, + {605, 57}, + {1000, 58}, + {1001, 59}, + {1002, 60}, + {1003, 61}, + {1004, 62}, + {1005, 63}, + {1006, 64}, + {1008, 65}, + {1009, 66}, + {1010, 67}, + {1011, 68}, + {1015, 69}, + {2005, 70} +}; + +Inter_v5::Inter_v5(GobEngine *vm) : Inter_v4(vm) { + setupOpcodes(); +} + +void Inter_v5::setupOpcodes() { + static const OpcodeDrawEntryV5 opcodesDraw[256] = { + /* 00 */ + OPCODE(o1_loadMult), + OPCODE(o2_playMult), + OPCODE(o2_freeMultKeys), + {NULL, ""}, + /* 04 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_initCursor), + /* 08 */ + OPCODE(o1_initCursorAnim), + OPCODE(o1_clearCursorAnim), + OPCODE(o2_setRenderFlags), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + OPCODE(o1_loadAnim), + OPCODE(o1_freeAnim), + OPCODE(o1_updateAnim), + OPCODE(o2_multSub), + /* 14 */ + OPCODE(o2_initMult), + OPCODE(o1_freeMult), + OPCODE(o1_animate), + OPCODE(o2_loadMultObject), + /* 18 */ + OPCODE(o1_getAnimLayerInfo), + OPCODE(o1_getObjAnimSize), + OPCODE(o1_loadStatic), + OPCODE(o1_freeStatic), + /* 1C */ + OPCODE(o2_renderStatic), + OPCODE(o2_loadCurLayer), + {NULL, ""}, + {NULL, ""}, + /* 20 */ + OPCODE(o2_playCDTrack), + OPCODE(o2_waitCDTrackEnd), + OPCODE(o2_stopCD), + OPCODE(o2_readLIC), + /* 24 */ + OPCODE(o2_freeLIC), + OPCODE(o2_getCDTrackPos), + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o2_loadFontToSprite), + OPCODE(o1_freeFontToSprite), + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + OPCODE(o2_totSub), + OPCODE(o2_switchTotSub), + OPCODE(o2_copyVars), + OPCODE(o2_pasteVars), + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 48 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 4C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 50 */ + OPCODE(o2_loadMapObjects), + OPCODE(o2_freeGoblins), + OPCODE(o2_moveGoblin), + OPCODE(o2_writeGoblinPos), + /* 54 */ + OPCODE(o2_stopGoblin), + OPCODE(o2_setGoblinState), + OPCODE(o2_placeGoblin), + {NULL, ""}, + /* 58 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 5C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 60 */ + {NULL, ""}, + OPCODE(o5_deleteFile), + {NULL, ""}, + {NULL, ""}, + /* 64 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 68 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 6C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 70 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 74 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 78 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 7C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 80 */ + OPCODE(o4_initScreen), + OPCODE(o2_scroll), + OPCODE(o2_setScrollOffset), + OPCODE(o4_playVmdOrMusic), + /* 84 */ + OPCODE(o2_getImdInfo), + OPCODE(o2_openItk), + OPCODE(o2_closeItk), + OPCODE(o2_setImdFrontSurf), + /* 88 */ + OPCODE(o2_resetImdFrontSurf), + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 8C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 90 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 94 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 98 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 9C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* AC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* BC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* CC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* DC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* EC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* FC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""} + }; + + static const OpcodeFuncEntryV5 opcodesFunc[80] = { + /* 00 */ + OPCODE(o1_callSub), + OPCODE(o1_callSub), + OPCODE(o1_printTotText), + OPCODE(o1_loadCursor), + /* 04 */ + {NULL, ""}, + OPCODE(o1_switch), + OPCODE(o1_repeatUntil), + OPCODE(o1_whileDo), + /* 08 */ + OPCODE(o1_if), + OPCODE(o2_evaluateStore), + OPCODE(o1_loadSpriteToPos), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + {NULL, ""}, + OPCODE(o2_printText), + OPCODE(o1_loadTot), + OPCODE(o1_palLoad), + /* 14 */ + OPCODE(o1_keyFunc), + OPCODE(o1_capturePush), + OPCODE(o1_capturePop), + OPCODE(o2_animPalInit), + /* 18 */ + OPCODE(o2_addCollision), + OPCODE(o2_freeCollision), + OPCODE(o3_getTotTextItemPart), + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_drawOperations), + OPCODE(o1_setcmdCount), + /* 20 */ + OPCODE(o1_return), + OPCODE(o1_renewTimeInVars), + OPCODE(o1_speakerOn), + OPCODE(o1_speakerOff), + /* 24 */ + OPCODE(o1_putPixel), + OPCODE(o2_goblinFunc), + OPCODE(o2_createSprite), + OPCODE(o1_freeSprite), + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o1_returnTo), + OPCODE(o1_loadSpriteContent), + OPCODE(o1_copySprite), + OPCODE(o1_fillRect), + /* 34 */ + OPCODE(o1_drawLine), + OPCODE(o1_strToLong), + OPCODE(o1_invalidate), + OPCODE(o1_setBackDelta), + /* 38 */ + OPCODE(o1_playSound), + OPCODE(o2_stopSound), + OPCODE(o2_loadSound), + OPCODE(o1_freeSoundSlot), + /* 3C */ + OPCODE(o1_waitEndPlay), + OPCODE(o1_playComposition), + OPCODE(o2_getFreeMem), + OPCODE(o2_checkData), + /* 40 */ + {NULL, ""}, + OPCODE(o1_prepareStr), + OPCODE(o1_insertStr), + OPCODE(o1_cutStr), + /* 44 */ + OPCODE(o1_strstr), + OPCODE(o5_istrlen), + OPCODE(o1_setMousePos), + OPCODE(o1_setFrameRate), + /* 48 */ + OPCODE(o1_animatePalette), + OPCODE(o1_animateCursor), + OPCODE(o1_blitCursor), + OPCODE(o1_loadFont), + /* 4C */ + OPCODE(o1_freeFont), + OPCODE(o2_readData), + OPCODE(o2_writeData), + OPCODE(o1_manageDataFile), + }; + + static const OpcodeGoblinEntryV5 opcodesGoblin[71] = { + /* 00 */ + OPCODE(o5_spaceShooter), + OPCODE(o5_getSystemCDSpeed), + OPCODE(o5_getSystemRAM), + OPCODE(o5_getSystemCPUSpeed), + /* 04 */ + OPCODE(o5_getSystemDrawSpeed), + OPCODE(o5_totalSystemSpecs), + OPCODE(o5_saveSystemSpecs), + OPCODE(o5_loadSystemSpecs), + /* 08 */ + OPCODE(o5_gob92), + OPCODE(o5_gob95), + OPCODE(o5_gob96), + OPCODE(o5_gob97), + /* 0C */ + OPCODE(o5_gob98), + OPCODE(o5_gob100), + OPCODE(o5_gob200), + {NULL, ""}, + /* 10 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 14 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 18 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 20 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 24 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + }; + + _opcodesDrawV5 = opcodesDraw; + _opcodesFuncV5 = opcodesFunc; + _opcodesGoblinV5 = opcodesGoblin; +} + +void Inter_v5::executeDrawOpcode(byte i) { + debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", + i, i, getOpcodeDrawDesc(i)); + + OpcodeDrawProcV5 op = _opcodesDrawV5[i].proc; + + if (op == NULL) + warning("unimplemented opcodeDraw: %d", i); + else + (this->*op) (); +} + +bool Inter_v5::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { + debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", + i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); + + if ((i > 4) || (j > 15)) { + warning("unimplemented opcodeFunc: %d.%d", i, j); + return false; + } + + OpcodeFuncProcV5 op = _opcodesFuncV5[i*16 + j].proc; + + if (op == NULL) + warning("unimplemented opcodeFunc: %d.%d", i, j); + else + return (this->*op) (params); + + return false; +} + +void Inter_v5::executeGoblinOpcode(int i, OpGobParams ¶ms) { + debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", + i, i, getOpcodeGoblinDesc(i)); + + OpcodeGoblinProcV5 op = NULL; + + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) { + op = _opcodesGoblinV5[_goblinFuncLookUp[j][1]].proc; + break; + } + + _vm->_global->_inter_execPtr -= 2; + + if (op == NULL) { + warning("unimplemented opcodeGoblin: %d", i); + + int16 paramCount = load16(); + _vm->_global->_inter_execPtr += paramCount * 2; + } else { + params.extraData = i; + + (this->*op) (params); + } +} + +const char *Inter_v5::getOpcodeDrawDesc(byte i) { + return _opcodesDrawV5[i].desc; +} + +const char *Inter_v5::getOpcodeFuncDesc(byte i, byte j) { + if ((i > 4) || (j > 15)) + return ""; + + return _opcodesFuncV5[i*16 + j].desc; +} + +const char *Inter_v5::getOpcodeGoblinDesc(int i) { + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) + return _opcodesGoblinV5[_goblinFuncLookUp[j][1]].desc; + return ""; +} + +void Inter_v5::o5_deleteFile() { + evalExpr(0); + + warning("Dynasty Stub: deleteFile \"%s\"", _vm->_global->_inter_resStr); +} + +bool Inter_v5::o5_istrlen(OpFuncParams ¶ms) { + int16 strVar1, strVar2; + int16 len; + + if (*_vm->_global->_inter_execPtr == 0x80) { + _vm->_global->_inter_execPtr++; + + strVar1 = _vm->_parse->parseVarIndex(); + strVar2 = _vm->_parse->parseVarIndex(); + + len = _vm->_draw->stringLength(GET_VARO_STR(strVar1), READ_VARO_UINT16(strVar2)); + + } else { + + strVar1 = _vm->_parse->parseVarIndex(); + strVar2 = _vm->_parse->parseVarIndex(); + + if (_vm->_global->_language == 10) { + // Extra handling for Japanese strings + + for (len = 0; READ_VARO_UINT8(strVar1) != 0; strVar1++, len++) + if (READ_VARO_UINT8(strVar1) >= 128) + strVar1++; + + } else + len = strlen(GET_VARO_STR(strVar1)); + } + + WRITE_VAR_OFFSET(strVar2, len); + return false; +} + +void Inter_v5::o5_spaceShooter(OpGobParams ¶ms) { + int16 paramCount = load16(); + + warning("Dynasty Stub: Space shooter: %d, %d, %s", + params.extraData, paramCount, _vm->_game->_curTotFile); + + if (paramCount < 4) { + warning("Space shooter variable counter < 4"); + _vm->_global->_inter_execPtr += paramCount * 2; + return; + } + + uint32 var1 = load16() * 4; + uint32 var2 = load16() * 4; +#if 1 + load16(); + load16(); +#else + uint32 var3 = load16() * 4; + uint16 var4 = load16(); +#endif + + if (params.extraData != 0) { + WRITE_VARO_UINT32(var1, 0); + WRITE_VARO_UINT32(var2, 0); + } else { + if (paramCount < 5) { + warning("Space shooter variable counter < 5"); + return; + } + + _vm->_global->_inter_execPtr += (paramCount - 4) * 2; + } +} + +void Inter_v5::o5_getSystemCDSpeed(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_getSystemRAM(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_getSystemCPUSpeed(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_getSystemDrawSpeed(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_totalSystemSpecs(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_saveSystemSpecs(OpGobParams ¶ms) { + warning("Dynasty Stub: Saving system specifications"); + + _vm->_global->_inter_execPtr += 2; + +/* + FILE *f = fopen("SAVE\\SPEED.INF", w); + fwrite(&_cdSpeed, sizeof(_cdSpeed), 1, f); + fwrite(&_ram, sizeof(_ram), 1, f); + fwrite(&_cpuSpeed, sizeof(_cpuSpeed), 1, f); + fwrite(&_drawSpeed, sizeof(_drawSpeed), 1, f); + fwrite(&_total, sizeof(_total), 1, f); + fclose(f); +*/ +} + +void Inter_v5::o5_loadSystemSpecs(OpGobParams ¶ms) { + warning("Dynasty Stub: Loading system specifications"); + + _vm->_global->_inter_execPtr += 2; + +/* + FILE *f = fopen("SAVE\\SPEED.INF", r); + fread(&_cdSpeed, sizeof(_cdSpeed), 1, f); + fread(&_ram, sizeof(_ram), 1, f); + fread(&_cpuSpeed, sizeof(_cpuSpeed), 1, f); + fread(&_drawSpeed, sizeof(_drawSpeed), 1, f); + fread(&_total, sizeof(_total), 1, f); + fclose(f); +*/ + +/* + // Calculating whether speed throttling is necessary? + + var_E = MAX(_cdSpeed, 150); + var_E += (_ram << 3); + var_E += (_cpuSpeed << 3); + var_E /= 17; + + byte_8A61E = (var_E > 81) ? 1 : 0; + byte_8A5E0 = (_total >= 95) ? 1 : 0; + + if (byte_8A5E0 == 1) { + word_8AEE2 = 100; + byte_8AEE4 = 1; + byte_8AEE5 = 1; + word_8AEE6 = 0; + } else { + word_8AEE2 = 0; + byte_8AEE4 = 0; + byte_8AEE5 = 0; + word_8AEE6 = 40; + } +*/ +} + +void Inter_v5::o5_gob92(OpGobParams ¶ms) { + warning("Dynasty Stub: GobFunc 92"); + + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_86B9E)) */); +} + +void Inter_v5::o5_gob95(OpGobParams ¶ms) { + warning("Dynasty Stub: GobFunc 95"); + + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE6)) */); + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_8AEE5)) */); + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_8AEE4)) */); + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE2)) */); +} + +void Inter_v5::o5_gob96(OpGobParams ¶ms) { + int16 word_8AEE6, word_85B50, word_8AEE2; + byte byte_8AEE5, byte_8AEE4; + + _vm->_global->_inter_execPtr += 2; + + word_8AEE6 = word_85B50 = READ_VAR_UINT16(load16()); + byte_8AEE5 = READ_VAR_UINT8(load16()); + byte_8AEE4 = READ_VAR_UINT8(load16()); + word_8AEE2 = READ_VAR_UINT16(load16()); + + warning("Dynasty Stub: GobFunc 96: %d, %d, %d, %d", + word_8AEE6, byte_8AEE5, byte_8AEE4, word_8AEE2); + + // .--- sub_194B0 --- + + int16 word_8A8F0, word_8A8F2, word_8A8F4, word_8A8F6, word_8A8F8, word_8A8FA; + + int16 word_8A62C = 1; + int16 word_8A63C, word_8A640, word_8B464, word_8B466; + + byte byte_8A62E; + + int16 var_2, var_4; + + var_2 = word_85B50 + 31; + word_8A8F0 = word_8A8F2 = var_2; + word_8A8F4 = word_85B50; + + var_4 = 315 - word_85B50; + word_8A8F6 = word_8A8F8 = var_4; + + word_8A8FA = 479 - word_85B50; + + if (word_8A62C == 0) { + word_8A63C = word_8A8F0; + word_8A640 = word_8A8F6; + word_8B464 = word_8A8F0; + word_8B466 = word_8A8F6; + } else if (word_8A62C == 1) { + word_8A63C = word_85B50; + word_8A640 = word_8A8FA; + word_8B464 = word_85B50; + word_8B466 = word_8A8FA; + } else if (word_8A62C == 2) { + word_8A63C = word_8A8F4; + word_8A640 = word_8A8FA; + word_8B464 = word_8A8F4; + word_8B466 = word_8A8FA; + } else if (word_8A62C == 3) { + word_8A63C = word_8A8F4; + word_8A640 = word_8A8FA; + word_8B464 = word_8A8F4; + word_8B466 = word_8A8FA; + } else if (word_8A62C == 4) { + word_8A63C = word_8A8F4; + word_8A640 = word_8A8FA; + word_8B464 = word_8A8F4; + word_8B466 = word_8A8FA; + } + + byte_8A62E = 1; + +// '--- --- + +} + +void Inter_v5::o5_gob97(OpGobParams ¶ms) { + _byte_8AA14 = 1; + + _vm->_global->_inter_execPtr += 2; +} + +void Inter_v5::o5_gob98(OpGobParams ¶ms) { + _byte_8AA14 = 0; + + _vm->_global->_inter_execPtr += 2; +} + +void Inter_v5::o5_gob100(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + uint16 var1 = READ_VAR_UINT16(load16()); + uint16 var2 = READ_VAR_UINT16(load16()); + uint16 var3 = READ_VAR_UINT16(load16()); + uint16 var4 = READ_VAR_UINT16(load16()); + + warning("Dynasty Stub: GobFunc 100: %d, %d, %d, %d", var1, var2, var3, var4); + + var3 = (var3 + var1) - 1; + var4 = (var4 + var2) - 1; +} + +void Inter_v5::o5_gob200(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + uint16 var1 = load16(); // index into the spritesArray + uint16 var2 = load16(); + uint16 var3 = load16(); + + warning("Dynasty Stub: GobFunc 200: %d, %d, %d", var1, var2, var3); +} + +} // End of namespace Gob diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp index 75867aaa6c..bb259800c0 100644 --- a/engines/gob/map.cpp +++ b/engines/gob/map.cpp @@ -77,10 +77,10 @@ Map::~Map() { } void Map::placeItem(int16 x, int16 y, int16 id) { - if ((_itemsMap[y][x] & 0xFF00) != 0) - _itemsMap[y][x] = (_itemsMap[y][x] & 0xFF00) | id; + if ((getItem(x, y) & 0xFF00) != 0) + setItem(x, y, (getItem(x, y) & 0xFF00) | id); else - _itemsMap[y][x] = (_itemsMap[y][x] & 0x00FF) | (id << 8); + setItem(x, y, (getItem(x, y) & 0x00FF) | (id << 8)); } enum { diff --git a/engines/gob/map.h b/engines/gob/map.h index 8a94de8da9..4a211f205d 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -101,6 +101,9 @@ public: void loadMapsInitGobs(void); + virtual int16 getItem(int x, int y) = 0; + virtual void setItem(int x, int y, int16 item) = 0; + virtual int8 getPass(int x, int y, int heightOff = -1) = 0; virtual void setPass(int x, int y, int8 pass, int heightOff = -1) = 0; @@ -127,6 +130,23 @@ public: virtual void findNearestToDest(Mult::Mult_Object *obj); virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y); + virtual int16 getItem(int x, int y) { + assert(_itemsMap); + + x = CLIP<int>(x, 0, _mapWidth - 1); + y = CLIP<int>(y, 0, _mapHeight - 1); + + return _itemsMap[y][x]; + } + virtual void setItem(int x, int y, int16 item) { + assert(_itemsMap); + + x = CLIP<int>(x, 0, _mapWidth - 1); + y = CLIP<int>(y, 0, _mapHeight - 1); + + _itemsMap[y][x] = item; + } + virtual int8 getPass(int x, int y, int heightOff = -1) { if (!_passMap) return 0; diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 45048a0899..c69f76b2c3 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -30,6 +30,7 @@ MODULE_OBJS := \ inter_bargon.o \ inter_v3.o \ inter_v4.o \ + inter_v5.o \ map.o \ map_v1.o \ map_v2.o \ diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp index a2e6b8fb37..f26d051ab5 100644 --- a/engines/gob/parse_v2.cpp +++ b/engines/gob/parse_v2.cpp @@ -116,6 +116,7 @@ int16 Parse_v2::parseValExpr(byte stopToken) { int16 brackPos; static int16 flag = 0; int16 oldflag; + uint32 varPos = 0; memset(values, 0, 20 * sizeof(int16)); @@ -130,11 +131,61 @@ int16 Parse_v2::parseValExpr(byte stopToken) { valPtr = values - 1; while (1) { + operation = *_vm->_global->_inter_execPtr++; + + while ((operation == 14) || (operation == 15)) { + if (operation == 14) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + _vm->_global->_inter_execPtr += 2; + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } else if (operation == 15) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + uint16 var_0C = _vm->_inter->load16(); + uint8 var_A = *_vm->_global->_inter_execPtr++; + + byte *var_12 = _vm->_global->_inter_execPtr; + _vm->_global->_inter_execPtr += var_A; + + uint16 var_6 = 0; + + for (int i = 0; i < var_A; i++) { + temp2 = parseValExpr(12); + + //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + + uint16 ax; + + if (temp2 < 0) { + ax = 0; + } else if (var_12[i] > temp2) { + ax = temp2; + } else { + ax = var_12[i] - 1; + } + + var_6 = var_6 * var_12[i] + ax; + } + + varPos += var_6 * var_0C * 4; + + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } + + warning("v5+ Stub: parseValExpr operation %d, offset %d", operation, varPos); + + operation = *_vm->_global->_inter_execPtr++; + } + stkPos++; operPtr++; valPtr++; - operation = *_vm->_global->_inter_execPtr++; if ((operation >= 16) && (operation <= 29)) { *operPtr = 20; switch (operation) { @@ -373,6 +424,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { bool var_1A; int16 stkPos; int16 brackStart; + uint32 varPos = 0; memset(operStack, 0, 20); @@ -381,10 +433,61 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { valPtr = values - 1; while (1) { + operation = *_vm->_global->_inter_execPtr++; + + while ((operation == 14) || (operation == 15)) { + if (operation == 14) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + _vm->_global->_inter_execPtr += 2; + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } else if (operation == 15) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + uint16 var_0C = _vm->_inter->load16(); + uint8 var_A = *_vm->_global->_inter_execPtr++; + + byte *var_12 = _vm->_global->_inter_execPtr; + _vm->_global->_inter_execPtr += var_A; + + uint16 var_6 = 0; + + for (int i = 0; i < var_A; i++) { + temp2 = parseValExpr(12); + + //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + + uint16 ax; + + if (temp2 < 0) { + ax = 0; + } else if (var_12[i] > temp2) { + ax = temp2; + } else { + ax = var_12[i] - 1; + } + + var_6 = var_6 * var_12[i] + ax; + } + + varPos += var_6 * var_0C * 4; + + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } + + warning("v5+ Stub: parseExpr operation %d, offset %d", operation, varPos); + + operation = *_vm->_global->_inter_execPtr++; + } + stkPos++; operPtr++; valPtr++; - operation = *_vm->_global->_inter_execPtr++; + if ((operation >= 16) && (operation <= 29)) { switch (operation) { case 16: diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index f5b3f582f4..c19db16d36 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -397,6 +397,18 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_FLOPPY_FLAGS }, + { // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("FATE.PAK", "e0a70c31b022cb4bb3061890020fc27c"), + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_FLAGS + }, + { // CD version { "kyra2", @@ -1052,9 +1064,9 @@ public: return "The Legend of Kyrandia (C) Westwood Studios"; } - virtual bool hasFeature(MetaEngineFeature f) const; - virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - virtual SaveStateList listSaves(const char *target) const; + bool hasFeature(MetaEngineFeature f) const; + bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + SaveStateList listSaves(const char *target) const; }; bool KyraMetaEngine::hasFeature(MetaEngineFeature f) const { @@ -1125,7 +1137,7 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError) + if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError) saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file)); delete in; } @@ -1140,3 +1152,4 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { #else REGISTER_PLUGIN_STATIC(KYRA, PLUGIN_TYPE_ENGINE, KyraMetaEngine); #endif + diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h index 1361bdb399..7db8f52f16 100644 --- a/engines/kyra/gui.h +++ b/engines/kyra/gui.h @@ -32,6 +32,8 @@ #include "common/array.h" #include "common/func.h" +#include "graphics/surface.h" + namespace Kyra { #define BUTTON_FUNCTOR(type, x, y) Button::Callback(new Common::Functor1Mem<Button*, int, type>(x, y)) @@ -153,6 +155,8 @@ public: void processHighlights(Menu &menu, int mouseX, int mouseY); + // utilities for thumbnail creation + virtual void createScreenThumbnail(Graphics::Surface &dst) = 0; protected: KyraEngine_v1 *_vm; Screen *_screen; diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index cb3cef2fb3..0d7b4d973d 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -33,6 +33,8 @@ #include "common/savefile.h" +#include "graphics/scaler.h" + namespace Kyra { void KyraEngine_HoF::loadButtonShapes() { @@ -793,6 +795,10 @@ int GUI_HoF::optionsButton(Button *button) { #pragma mark - +void GUI_HoF::createScreenThumbnail(Graphics::Surface &dst) { + ::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(1)); +} + void GUI_HoF::setupPalette() { memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); @@ -996,7 +1002,7 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) { if (_vm->_lang != lang) { _reloadTemporarySave = true; - _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame"); + _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame", 0); _vm->loadCCodeBuffer("C_CODE.XXX"); if (_vm->_flags.isTalkie) _vm->loadOptionsBuffer("OPTIONS.XXX"); diff --git a/engines/kyra/gui_hof.h b/engines/kyra/gui_hof.h index f64336a8f6..a9c0426a2b 100644 --- a/engines/kyra/gui_hof.h +++ b/engines/kyra/gui_hof.h @@ -41,6 +41,8 @@ public: void initStaticData(); int optionsButton(Button *button); + + void createScreenThumbnail(Graphics::Surface &dst); private: const char *getMenuTitle(const Menu &menu); const char *getMenuItemTitle(const MenuItem &menuItem); diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 818d2f9b4e..4d13512751 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -36,6 +36,8 @@ #include "common/savefile.h" #include "common/system.h" +#include "graphics/scaler.h" + namespace Kyra { void KyraEngine_LoK::initMainButtonList() { @@ -198,6 +200,15 @@ GUI_LoK::~GUI_LoK() { delete[] _menu; } +void GUI_LoK::createScreenThumbnail(Graphics::Surface &dst) { + uint8 *screen = new uint8[Screen::SCREEN_W*Screen::SCREEN_H]; + if (screen) { + _screen->queryPageFromDisk("SEENPAGE.TMP", 0, screen); + ::createThumbnail(&dst, screen, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(2)); + } + delete[] screen; +} + int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) { while (list) { if (list->flags & 8) { @@ -732,8 +743,12 @@ int GUI_LoK::saveGame(Button *button) { } else { if (_savegameOffset == 0 && _vm->_gameToLoad == 0) _vm->_gameToLoad = getNextSavegameSlot(); - if (_vm->_gameToLoad > 0) - _vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName); + if (_vm->_gameToLoad > 0) { + Graphics::Surface thumb; + createScreenThumbnail(thumb); + _vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName, &thumb); + thumb.free(); + } } return 0; diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 16b7ef9183..0ce718d7a7 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -103,6 +103,8 @@ public: int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel); int buttonMenuCallback(Button *caller); + + void createScreenThumbnail(Graphics::Surface &dst); private: void initStaticResource(); diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index 40fe78c439..11e6f6f1f4 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -33,6 +33,8 @@ #include "common/savefile.h" +#include "graphics/scaler.h" + namespace Kyra { void KyraEngine_MR::loadButtonShapes() { @@ -1138,6 +1140,10 @@ int KyraEngine_MR::albumClose(Button *caller) { GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) { } +void GUI_MR::createScreenThumbnail(Graphics::Surface &dst) { + ::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(0)); +} + void GUI_MR::flagButtonEnable(Button *button) { if (!button) return; @@ -1450,7 +1456,7 @@ int GUI_MR::gameOptions(Button *caller) { if (_vm->_lang != lang) { _reloadTemporarySave = true; - _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame"); + _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame", 0); if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile)) error("Couldn't load ITEMS"); if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile)) diff --git a/engines/kyra/gui_mr.h b/engines/kyra/gui_mr.h index 5bd3569031..a78d0559a6 100644 --- a/engines/kyra/gui_mr.h +++ b/engines/kyra/gui_mr.h @@ -47,6 +47,8 @@ public: int redrawButtonCallback(Button *button); int optionsButton(Button *button); + + void createScreenThumbnail(Graphics::Surface &dst); private: void getInput(); diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index a7ae2a6c44..077e49ebcf 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -35,6 +35,7 @@ namespace Kyra { GUI_v2::GUI_v2(KyraEngine_v2 *vm) : GUI(vm), _vm(vm), _screen(vm->screen_v2()) { _backUpButtonList = _unknownButtonList = 0; _buttonListChanged = false; + _lastScreenUpdate = 0; _currentMenu = 0; _isDeathMenu = false; @@ -618,7 +619,12 @@ int GUI_v2::saveMenu(Button *caller) { restorePage1(_vm->_screenBuffer); restorePalette(); - _vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription); + + Graphics::Surface thumb; + createScreenThumbnail(thumb); + _vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription, &thumb); + thumb.free(); + _displayMenu = false; _madeSave = true; @@ -762,6 +768,7 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 x2 -= getCharWidth(buffer[curPos]); drawTextfieldBlock(x2, y2, c3); _screen->updateScreen(); + _lastScreenUpdate = _vm->_system->getMillis(); } else if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127 && curPos < bufferSize) { if (x2 + getCharWidth(_keyPressed.ascii) + 7 < 0x11F) { buffer[curPos] = _keyPressed.ascii; @@ -771,6 +778,7 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 drawTextfieldBlock(x2, y2, c3); ++curPos; _screen->updateScreen(); + _lastScreenUpdate = _vm->_system->getMillis(); } } @@ -818,6 +826,8 @@ int GUI_v2::getCharWidth(uint8 c) { void GUI_v2::checkTextfieldInput() { Common::Event event; + uint32 now = _vm->_system->getMillis(); + bool running = true; int keys = 0; while (_vm->_eventMan->pollEvent(event) && running) { @@ -844,6 +854,7 @@ void GUI_v2::checkTextfieldInput() { _vm->_mouseX = pos.x; _vm->_mouseY = pos.y; _screen->updateScreen(); + _lastScreenUpdate = now; } break; default: @@ -851,7 +862,13 @@ void GUI_v2::checkTextfieldInput() { } } + if (now - _lastScreenUpdate > 50) { + _vm->_system->updateScreen(); + _lastScreenUpdate = now; + } + processButtonList(_menuButtonList, keys | 0x8000, 0); + _vm->_system->delayMillis(3); } void GUI_v2::drawTextfieldBlock(int x, int y, uint8 c) { diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h index 60b7f0ab86..88861ff905 100644 --- a/engines/kyra/gui_v2.h +++ b/engines/kyra/gui_v2.h @@ -213,6 +213,7 @@ protected: // savename menu bool _finishNameInput, _cancelNameInput; Common::KeyState _keyPressed; + uint32 _lastScreenUpdate; const char *nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 c2, uint8 c3, int bufferSize); int finishSavename(Button *caller); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 0722fb262b..086d8d6913 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -306,8 +306,10 @@ int KyraEngine_HoF::go() { _res->loadFileList(_ingamePakList, _ingamePakListSize); } - if (_flags.platform == Common::kPlatformPC98) + if (_flags.platform == Common::kPlatformPC98) { _res->loadPakFile("AUDIO.PAK"); + _sound->loadSoundFile("sound.dat"); + } } _menuDirectlyToLoad = (_menuChoice == 3) ? true : false; @@ -434,7 +436,7 @@ void KyraEngine_HoF::startup() { if (_gameToLoad == -1) { snd_playWanderScoreViaMap(52, 1); enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1); - saveGame(getSavegameFilename(0), "New Game"); + saveGame(getSavegameFilename(0), "New Game", 0); } else { loadGame(getSavegameFilename(_gameToLoad)); } @@ -1577,10 +1579,14 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) { int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]); if (vocIndex != -1) _sound->voicePlay(_ingameSoundList[vocIndex], true); - else if (_flags.platform != Common::kPlatformFMTowns) + else if (_flags.platform == Common::kPlatformPC) + KyraEngine_v1::snd_playSoundEffect(track); + // TODO ?? Maybe there is a way to let users select whether they want // voc, midi or adl sfx (even though it makes no sense to choose anything but voc). - KyraEngine_v1::snd_playSoundEffect(track); + // The PC-98 version has support for non-pcm sound effects, but only for tracks + // which also have voc files. The syntax would be: + // KyraEngine_v1::snd_playSoundEffect(vocIndex); } #pragma mark - diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index f6e887c648..dc4161f0c1 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -907,7 +907,7 @@ protected: int _dbgPass; // save/load specific - void saveGame(const char *fileName, const char *saveName); + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail); void loadGame(const char *fileName); }; diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index 2ce8af4a81..b6c874339c 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -391,7 +391,7 @@ void KyraEngine_LoK::startup() { _gui->buttonMenuCallback(0); _menuDirectlyToLoad = false; } else - saveGame(getSavegameFilename(0), "New game"); + saveGame(getSavegameFilename(0), "New game", 0); } else { _screen->setFont(Screen::FID_8_FNT); loadGame(getSavegameFilename(_gameToLoad)); @@ -473,7 +473,7 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) { else { char savegameName[14]; sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); - saveGame(saveLoadSlot, savegameName); + saveGame(saveLoadSlot, savegameName, 0); } } else if (event.kbd.flags == Common::KBD_CTRL) { if (event.kbd.keycode == 'd') diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index 1def95ddbf..e6fc0dc774 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -214,7 +214,7 @@ public: protected: int32 _speechPlayTime; - void saveGame(const char *fileName, const char *saveName); + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail); void loadGame(const char *fileName); protected: diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 45a277c400..5bc843d8a8 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -684,7 +684,7 @@ void KyraEngine_MR::startup() { assert(_invWsa); _invWsa->open("MOODOMTR.WSA", 1, 0); _invWsaFrame = 6; - saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33)); + saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33), 0); _soundDigital->beginFadeOut(_musicSoundChannel, 60); delayWithTicks(60); if (_gameToLoad == -1) diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 5f9f6f91a3..a6fb9af20c 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -583,7 +583,7 @@ private: int albumClose(Button *caller); // save/load - void saveGame(const char *fileName, const char *saveName); + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail); void loadGame(const char *fileName); // opcodes diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index f4f845c5f7..761724fa2f 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -285,6 +285,8 @@ protected: bool originalSave; // savegame from original interpreter bool oldHeader; // old scummvm save header + + Graphics::Surface *thumbnail; }; enum kReadSaveHeaderError { @@ -294,10 +296,10 @@ protected: kRSHEIoError = 3 }; - static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header); + static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header); Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header); - Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName) const; + Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const; }; } // End of namespace Kyra diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 08a4e9f4c5..e9ed91b539 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -186,7 +186,7 @@ int KyraEngine_v2::checkInput(Button *buttonList, bool mainLoop) { } else { char savegameName[14]; sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); - saveGame(saveLoadSlot, savegameName); + saveGame(saveLoadSlot, savegameName, 0); } } else if (event.kbd.flags == Common::KBD_CTRL) { if (event.kbd.keycode == 'd') diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 6fdf30fff8..e7f9634fc6 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -419,7 +419,7 @@ protected: int o2_getVocHigh(EMCState *script); // save/load specific - virtual void saveGame(const char *fileName, const char *saveName) = 0; + virtual void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) = 0; virtual void loadGame(const char *fileName) = 0; }; diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 5da6bb3873..946169ddd4 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -150,7 +150,7 @@ bool Resource::reset() { } bool Resource::loadPakFile(const Common::String &filename) { - if (!isAccessable(filename)) + if (!isAccessible(filename)) return false; ResFileMap::iterator iter = _map.find(filename); @@ -201,18 +201,18 @@ bool Resource::loadPakFile(const Common::String &filename) { // If the old parent is not protected we mark it as not preload anymore, // since now no longer all of its embedded files are in the filemap. oldParent->_value.preload = false; - _map[i->filename] = i->entry; + iter->_value = i->entry; } } else { // Old parent not found? That's strange... But we just overwrite the old // entry. - _map[i->filename] = i->entry; + iter->_value = i->entry; } } else { // The old parent has the same filenames as the new archive, we are sure and overwrite the // old file entry, could be afterall that the preload flag of the new archive was // just unflagged. - _map[i->filename] = i->entry; + iter->_value = i->entry; } } // 'else' case would mean here overwriting an existing file entry in the map without parent. @@ -244,7 +244,7 @@ bool Resource::loadFileList(const Common::String &filedata) { filename.toUppercase(); if (filename.hasSuffix(".PAK")) { - if (!isAccessable(filename) && _vm->gameFlags().isDemo) { + if (!isAccessible(filename) && _vm->gameFlags().isDemo) { // the demo version supplied with Kyra3 does not // contain all pak files listed in filedata.fdt // so we don't do anything here if they are non @@ -289,7 +289,7 @@ void Resource::clearCompFileList() { } bool Resource::isInPakList(const Common::String &filename) { - if (!isAccessable(filename)) + if (!isAccessible(filename)) return false; ResFileMap::iterator iter = _map.find(filename); if (iter == _map.end()) @@ -320,7 +320,7 @@ uint8 *Resource::fileData(const char *file, uint32 *size) { bool Resource::exists(const char *file, bool errorOutOnFail) { if (Common::File::exists(file)) return true; - else if (isAccessable(file)) + else if (isAccessible(file)) return true; else if (errorOutOnFail) error("File '%s' can't be found", file); @@ -335,7 +335,7 @@ uint32 Resource::getFileSize(const char *file) { if (f.open(file)) return f.size(); } else { - if (!isAccessable(file)) + if (!isAccessible(file)) return 0; ResFileMap::const_iterator iter = _map.find(file); @@ -362,7 +362,7 @@ Common::SeekableReadStream *Resource::getFileStream(const Common::String &file) if ((compEntry = _compFiles.find(file)) != _compFiles.end()) return new Common::MemoryReadStream(compEntry->_value.data, compEntry->_value.size, false); - if (!isAccessable(file)) + if (!isAccessible(file)) return 0; ResFileMap::const_iterator iter = _map.find(file); @@ -381,8 +381,8 @@ Common::SeekableReadStream *Resource::getFileStream(const Common::String &file) Common::SeekableReadStream *parent = getFileStream(iter->_value.parent); assert(parent); - ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent); - const ResArchiveLoader *loader = getLoader(parentIter->_value.type); + ResFileEntry* parentEntry = getParentEntry(&iter->_value); + const ResArchiveLoader *loader = getLoader(parentEntry->type); assert(loader); return loader->loadFileFromArchive(file, parent, iter->_value); @@ -391,26 +391,65 @@ Common::SeekableReadStream *Resource::getFileStream(const Common::String &file) return 0; } -bool Resource::isAccessable(const Common::String &file) { +bool Resource::isAccessible(const Common::String &file) { checkFile(file); ResFileMap::const_iterator iter = _map.find(file); - while (iter != _map.end()) { - if (!iter->_value.parent.empty()) { - iter = _map.find(iter->_value.parent); - if (iter != _map.end()) { - // parent can never be a non archive file - if (iter->_value.type == ResFileEntry::kRaw) - return false; - // not mounted parent means not accessable - else if (!iter->_value.mounted) - return false; - } + if (iter == _map.end()) + return false; + + return isAccessible(&iter->_value); +} + +bool Resource::isAccessible(const ResFileEntry *fileEntry) { + assert(fileEntry); + + const ResFileEntry* currentEntry = fileEntry; + while (!currentEntry->parent.empty()) { + if (currentEntry->parentEntry) { + currentEntry = currentEntry->parentEntry; } else { - return true; + ResFileMap::iterator it = _map.find(currentEntry->parent); + if (it == _map.end()) + return false; + else + currentEntry->parentEntry = &it->_value; } + // parent can never be a non archive file + if (currentEntry->type == ResFileEntry::kRaw) + return false; + // not mounted parent means not accessable + else if (!currentEntry->mounted) + return false; } - return false; + + return true; +} + +ResFileEntry *Resource::getParentEntry(const ResFileEntry *entry) const { + assert(entry); + if (entry->parent.empty()) { + return 0; + } else if (entry->parentEntry) { + assert(_map.find(entry->parent) != _map.end()); // If some day the hash map implementations changes and moves nodes around, + // this assumption would fail and the whole system would need a refactoring + assert(entry->parentEntry == &_map.find(entry->parent)->_value); + return entry->parentEntry; + } else { + ResFileMap::iterator it = _map.find(entry->parent); + if (it == _map.end()) + return 0; // If it happens often, the structure maybe deserves a flag to avoid rechecking the map + else { + entry->parentEntry = &it->_value; + return entry->parentEntry; + } + } +} + +ResFileEntry *Resource::getParentEntry(const Common::String &filename) const { + ResFileMap::iterator it = _map.find(filename); + assert(it != _map.end()); + return getParentEntry(&it->_value); } void Resource::checkFile(const Common::String &file) { @@ -418,67 +457,72 @@ void Resource::checkFile(const Common::String &file) { CompFileMap::const_iterator iter; if ((iter = _compFiles.find(file)) != _compFiles.end()) { - ResFileEntry entry; + ResFileEntry& entry = _map[file]; entry.parent = ""; + entry.parentEntry = 0; entry.size = iter->_value.size; entry.mounted = false; entry.preload = false; entry.prot = false; entry.type = ResFileEntry::kAutoDetect; entry.offset = 0; - _map[file] = entry; - - detectFileTypes(); + + detectFileType(file, &entry); } else if (Common::File::exists(file)) { Common::File temp; if (temp.open(file)) { - ResFileEntry entry; + ResFileEntry& entry = _map[file]; entry.parent = ""; + entry.parentEntry = 0; entry.size = temp.size(); entry.mounted = file.compareToIgnoreCase(StaticResource::staticDataFilename()) != 0; entry.preload = false; entry.prot = false; entry.type = ResFileEntry::kAutoDetect; entry.offset = 0; - _map[file] = entry; temp.close(); - detectFileTypes(); + detectFileType(file, &entry); } } } } -void Resource::detectFileTypes() { - for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) { - if (!isAccessable(i->_key)) - continue; +void Resource::detectFileType(const Common::String &filename, ResFileEntry *fileEntry) { + assert(fileEntry); + + if (!isAccessible(fileEntry)) + return; - if (i->_value.type == ResFileEntry::kAutoDetect) { - Common::SeekableReadStream *stream = 0; - for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) { - if (!(*l)->checkFilename(i->_key)) - continue; - - if (!stream) - stream = getFileStream(i->_key); - - if ((*l)->isLoadable(i->_key, *stream)) { - i->_value.type = (*l)->getType(); - i->_value.mounted = false; - i->_value.preload = false; - break; - } - } - delete stream; - stream = 0; + if (fileEntry->type == ResFileEntry::kAutoDetect) { + Common::SeekableReadStream *stream = 0; + for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) { + if (!(*l)->checkFilename(filename)) + continue; + + if (!stream) + stream = getFileStream(filename); - if (i->_value.type == ResFileEntry::kAutoDetect) - i->_value.type = ResFileEntry::kRaw; + if ((*l)->isLoadable(filename, *stream)) { + fileEntry->type = (*l)->getType(); + fileEntry->mounted = false; + fileEntry->preload = false; + break; + } } + delete stream; + stream = 0; + + if (fileEntry->type == ResFileEntry::kAutoDetect) + fileEntry->type = ResFileEntry::kRaw; } } +void Resource::detectFileTypes() { + for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) + detectFileType(i->_key, &i->_value); +} + void Resource::tryLoadCompFiles() { for (CCompLoaderIterator i = _compLoaders.begin(); i != _compLoaders.end(); ++i) { if ((*i)->checkForFiles()) @@ -620,6 +664,7 @@ bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableRead entry.size = endoffset - startoffset; entry.offset = startoffset; entry.parent = filename; + entry.parentEntry = 0; entry.type = ResFileEntry::kAutoDetect; entry.mounted = false; entry.prot = false; @@ -738,6 +783,7 @@ bool ResLoaderInsMalcolm::loadFile(const Common::String &filename, Common::Seeka for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) { ResFileEntry entry; entry.parent = filename; + entry.parentEntry = 0; entry.type = ResFileEntry::kAutoDetect; entry.mounted = false; entry.preload = false; @@ -807,6 +853,7 @@ bool ResLoaderTlk::loadFile(const Common::String &filename, Common::SeekableRead for (uint i = 0; i < entries; ++i) { ResFileEntry entry; entry.parent = filename; + entry.parentEntry = 0; entry.type = ResFileEntry::kAutoDetect; entry.mounted = false; entry.preload = false; diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index d43f730e6b..5ecbd145fe 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -43,6 +43,9 @@ namespace Kyra { struct ResFileEntry { Common::String parent; + mutable ResFileEntry *parentEntry; // Cache to avoid lookup by string in the map + // No smart invalidation is needed because the map is cleared globally + // or expanded but no element is ever removed uint32 size; bool preload; @@ -128,9 +131,11 @@ public: bool loadFileToBuf(const char *file, void *buf, uint32 maxSize); protected: void checkFile(const Common::String &file); - bool isAccessable(const Common::String &file); + bool isAccessible(const Common::String &file); + bool isAccessible(const ResFileEntry *fileEntry); void detectFileTypes(); + void detectFileType(const Common::String &filename, ResFileEntry *fileEntry); void initializeLoaders(); const ResArchiveLoader *getLoader(ResFileEntry::kType type) const; @@ -140,6 +145,9 @@ protected: LoaderList _loaders; ResFileMap _map; + ResFileEntry *getParentEntry(const ResFileEntry *entry) const; + ResFileEntry *getParentEntry(const Common::String &filename) const; + typedef Common::List<Common::SharedPtr<CompArchiveLoader> > CompLoaderList; typedef CompLoaderList::iterator CompLoaderIterator; typedef CompLoaderList::const_iterator CCompLoaderIterator; diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index cffd0c7800..da0fd731da 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -26,10 +26,11 @@ #include "common/endian.h" #include "common/savefile.h" #include "common/system.h" +#include "graphics/thumbnail.h" #include "kyra/kyra_v1.h" -#define CURRENT_SAVE_VERSION 13 +#define CURRENT_SAVE_VERSION 14 #define GF_FLOPPY (1 << 0) #define GF_TALKIE (1 << 1) @@ -37,7 +38,7 @@ namespace Kyra { -KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header) { +KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) { uint32 type = in->readUint32BE(); header.originalSave = false; header.oldHeader = false; @@ -108,6 +109,19 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab if (header.version >= 2) header.flags = in->readUint32BE(); + if (header.version >= 14) { + if (loadThumbnail) { + header.thumbnail = new Graphics::Surface(); + assert(header.thumbnail); + if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { + delete header.thumbnail; + header.thumbnail = 0; + } + } else { + Graphics::skipThumbnailHeader(*in); + } + } + return (in->ioFailed() ? kRSHEIoError : kRSHENoError); } @@ -118,7 +132,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena if (!(in = _saveFileMan->openForLoading(filename))) return 0; - kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header); + kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header); if (errorCode != kRSHENoError) { if (errorCode == kRSHEInvalidType) warning("No ScummVM Kyra engine savefile header."); @@ -162,8 +176,8 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena return in; } -Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const { - debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s')", filename, saveName); +Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const { + debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s', %p)", filename, saveName, (const void *)thumbnail); if (quit()) return 0; @@ -191,6 +205,11 @@ Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, con return 0; } + if (thumbnail) + Graphics::saveThumbnail(*out, *thumbnail); + else + Graphics::saveThumbnail(*out); + return out; } diff --git a/engines/kyra/saveload_hof.cpp b/engines/kyra/saveload_hof.cpp index 954cbccfa9..2b245f6167 100644 --- a/engines/kyra/saveload_hof.cpp +++ b/engines/kyra/saveload_hof.cpp @@ -35,10 +35,10 @@ namespace Kyra { -void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "KyraEngine_HoF::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); - Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) { warning("Can't open file '%s', game not loadable", fileName); return; diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp index 74cf26646c..257d762ce8 100644 --- a/engines/kyra/saveload_lok.cpp +++ b/engines/kyra/saveload_lok.cpp @@ -218,13 +218,13 @@ void KyraEngine_LoK::loadGame(const char *fileName) { delete in; } -void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); if (quit()) return; - Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) return; diff --git a/engines/kyra/saveload_mr.cpp b/engines/kyra/saveload_mr.cpp index 51efc33723..8849f99523 100644 --- a/engines/kyra/saveload_mr.cpp +++ b/engines/kyra/saveload_mr.cpp @@ -32,10 +32,10 @@ namespace Kyra { -void KyraEngine_MR::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "KyraEngine_MR::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_MR::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); - Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) { warning("Can't open file '%s', game not loadable", fileName); return; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 0cde066cc0..68faaf6177 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -554,19 +554,16 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag copyOverlayRegion(x1, y1, x2, y2, w, h, srcPage, dstPage); - if (flags & CR_X_FLIPPED) { + if (flags & CR_NO_P_CHECK) { while (h--) { - for (int i = 0; i < w; ++i) { - if (src[i] || (flags & CR_NO_P_CHECK)) - dst[w-i] = src[i]; - } + memcpy(dst, src, w); src += SCREEN_W; dst += SCREEN_W; } } else { while (h--) { for (int i = 0; i < w; ++i) { - if (src[i] || (flags & CR_NO_P_CHECK)) + if (src[i]) dst[i] = src[i]; } src += SCREEN_W; diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 99ba2d7c5f..8623856878 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -74,8 +74,7 @@ public: }; enum CopyRegionFlags { - CR_X_FLIPPED = 0x01, - CR_NO_P_CHECK = 0x02 + CR_NO_P_CHECK = 0x01 }; enum DrawShapeFlags { diff --git a/engines/kyra/screen_lok.cpp b/engines/kyra/screen_lok.cpp index 011c90dde9..da88abc61f 100644 --- a/engines/kyra/screen_lok.cpp +++ b/engines/kyra/screen_lok.cpp @@ -147,8 +147,14 @@ void Screen_LoK::savePageToDisk(const char *file, int page) { void Screen_LoK::loadPageFromDisk(const char *file, int page) { debugC(9, kDebugLevelScreen, "Screen_LoK::loadPageFromDisk('%s', %d)", file, page); + if (!_saveLoadPage[page/2]) { + warning("trying to restore page %d, but no backup found", page); + return; + } + copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]); delete[] _saveLoadPage[page/2]; + _saveLoadPage[page/2] = 0; if (_saveLoadPageOvl[page/2]) { uint8 *dstPage = getOverlayPtr(page); @@ -160,7 +166,17 @@ void Screen_LoK::loadPageFromDisk(const char *file, int page) { memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE); delete[] _saveLoadPageOvl[page/2]; _saveLoadPageOvl[page/2] = 0; - } _saveLoadPage[page/2] = 0; + } +} + +void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) { + debugC(9, kDebugLevelScreen, "Screen_LoK::queryPageFromDisk('%s', %d, %p)", file, page, (const void *)buffer); + if (!_saveLoadPage[page/2]) { + warning("trying to query page %d, but no backup found", page); + return; + } + + memcpy(buffer, _saveLoadPage[page/2], SCREEN_W*SCREEN_H); } void Screen_LoK::deletePageFromDisk(int page) { diff --git a/engines/kyra/screen_lok.h b/engines/kyra/screen_lok.h index 74df23a543..5b4b8a9266 100644 --- a/engines/kyra/screen_lok.h +++ b/engines/kyra/screen_lok.h @@ -50,6 +50,7 @@ public: void savePageToDisk(const char *file, int page); void loadPageFromDisk(const char *file, int page); + void queryPageFromDisk(const char *file, int page, uint8 *buffer); void deletePageFromDisk(int page); void copyBackgroundBlock(int x, int page, int flag); diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index 6dda6c8bd7..dad870a5f4 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -293,7 +293,7 @@ int KyraEngine_MR::o3_updateScore(EMCState *script) { int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script); - saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME"); + saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0); return 0; } diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index b42374f44f..7915a33996 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -2830,6 +2830,9 @@ void KyraEngine_HoF::seq_init() { _res->unloadAllPakFiles(); _res->loadPakFile(StaticResource::staticDataFilename()); _res->loadFileList(_sequencePakList, _sequencePakListSize); + + if (_flags.platform == Common::kPlatformPC98) + _sound->loadSoundFile("sound.dat"); int numShp = -1; diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index e5294eb15d..2f7ac27ac5 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -429,7 +429,7 @@ public: MidiChannel *allocateChannel() { return 0; } MidiChannel *getPercussionChannel() { return 0; } - static float semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, + static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey, uint32 sampleRate, uint32 outputRate, int32 pitchWheel); private: @@ -492,7 +492,7 @@ public: void process(); void loadSoundFile(uint file) {} - void loadSoundFile(Common::String) {} + void loadSoundFile(Common::String file); void playTrack(uint8 track); void haltTrack(); @@ -507,6 +507,7 @@ protected: bool _useFmSfx; uint8 *_musicTrackData; + uint8 *_sfxTrackData; TownsPC98_OpnDriver *_driver; }; diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index ec1962a58f..abda839ab4 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -23,7 +23,6 @@ * */ - #include "common/system.h" #include "kyra/resource.h" #include "kyra/sound.h" @@ -64,13 +63,13 @@ public: MidiDriver *device() { return 0; } byte getNumber() { return 0; } void release() { } - void send(uint32 b) { } + void send(uint32) { } void noteOff(byte note); void noteOn(byte note, byte onVelo); - void programChange(byte program) {} + void programChange(byte) {} void pitchBend(int16 value); void controlChange(byte control, byte value); - void pitchBendFactor(byte value) { } + void pitchBendFactor(byte) { } void sysEx_customInstrument(uint32 unused, const byte *instr); protected: @@ -427,7 +426,7 @@ void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) { return; } - float phaseStep = SoundTowns::semitoneAndSampleRate_to_sampleStep(_note, _voice->_snd[_current]->keyNote - + float phaseStep = SoundTowns::calculatePhaseStep(_note, _voice->_snd[_current]->keyNote - _voice->_env[_current]->rootKeyOffset, _voice->_snd[_current]->samplingRate, _rate, _frequencyOffs); int32 looplength = _voice->_snd[_current]->loopLength; @@ -819,7 +818,8 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { } } - while (true) { + bool loop = true; + while (loop) { byte cmd = *pos; byte evt = (cmd & 0xF0); @@ -853,7 +853,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { info.basic.param2 = onVelo; pos += 12; - break; + loop = false; } else { pos += 6; } @@ -870,7 +870,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { info.basic.param1 = pos[4]; info.basic.param2 = pos[5]; pos += 6; - break; + loop = false; } else { pos += 6; } @@ -889,7 +889,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { _tempo[2] = tempo & 0xff; info.ext.data = (byte*) _tempo; pos += 6; - break; + loop = false; } else if (cmd == 0xFD || cmd == 0xFE) { // End of track. if (_autoLoop) { @@ -906,12 +906,12 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { info.event = 0xFF; info.ext.type = 0x2F; info.ext.data = pos; - break; + loop = false; } else { error("Unknown Euphony music event 0x%02X", (int)cmd); memset(&info, 0, sizeof(info)); pos = 0; - break; + loop = false; } } _position._play_pos = pos; @@ -1085,7 +1085,7 @@ void Towns_EuphonyTrackQueue::initDriver() { class TownsPC98_OpnOperator { public: - TownsPC98_OpnOperator(double rate, const uint8 *rateTable, + TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); ~TownsPC98_OpnOperator() {} @@ -1095,7 +1095,7 @@ public: void frequency(int freq); void updatePhaseIncrement(); void recalculateRates(); - void generateOutput(int phasebuf, int *_feedbuf, int &out); + void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } void detune(int value) { _detn = &_detnTbl[value << 5]; } @@ -1111,6 +1111,7 @@ public: protected: EnvelopeState _state; + bool _playing; uint32 _feedbackLevel; uint32 _multiple; uint32 _totalLevel; @@ -1137,8 +1138,8 @@ protected: const int32 *_tLvlTbl; const int32 *_detnTbl; - const double _tickLength; - double _tick; + const uint32 _tickLength; + uint32 _timer; int32 _currentLevel; struct EvpState { @@ -1147,23 +1148,31 @@ protected: } fs_a, fs_d, fs_s, fs_r; }; -TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, const uint8 *rateTable, +TownsPC98_OpnOperator::TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), - _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0), + _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2), _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), _phase(0), _state(s_ready) { - + reset(); } void TownsPC98_OpnOperator::keyOn() { + if (_playing) + return; + + _playing = true; _state = s_attacking; _phase = 0; } void TownsPC98_OpnOperator::keyOff() { + if (!_playing) + return; + + _playing = false; if (_state != s_ready) _state = s_releasing; } @@ -1172,6 +1181,7 @@ void TownsPC98_OpnOperator::frequency(int freq) { uint8 block = (freq >> 11); uint16 pos = (freq & 0x7ff); uint8 c = pos >> 7; + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); _frequency = _fTbl[pos << 1] >> (7 - block); } @@ -1204,44 +1214,44 @@ void TownsPC98_OpnOperator::recalculateRates() { fs_r.shift = _rshiftTbl[r + k]; } -void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) { +void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) { if (_state == s_ready) return; - _tick += _tickLength; - while (_tick > 0x30000) { - _tick -= 0x30000; + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; ++_tickCount; int32 levelIncrement = 0; uint32 targetTime = 0; int32 targetLevel = 0; - EnvelopeState next_state = s_ready; + EnvelopeState nextState = s_ready; switch (_state) { case s_ready: return; case s_attacking: - next_state = s_decaying; + nextState = s_decaying; targetTime = (1 << fs_a.shift) - 1; targetLevel = 0; levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; break; case s_decaying: targetTime = (1 << fs_d.shift) - 1; - next_state = s_sustaining; + nextState = s_sustaining; targetLevel = _sustainLevel; levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; break; case s_sustaining: targetTime = (1 << fs_s.shift) - 1; - next_state = s_ready; + nextState = s_sustaining; targetLevel = 1023; levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; break; case s_releasing: targetTime = (1 << fs_r.shift) - 1; - next_state = s_ready; + nextState = s_ready; targetLevel = 1023; levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; break; @@ -1249,31 +1259,31 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out if (!(_tickCount & targetTime)) { _currentLevel += levelIncrement; - if ((!targetLevel && _currentLevel <= targetLevel) || (targetLevel && _currentLevel >= targetLevel)) { + if ((_state == s_attacking && _currentLevel <= targetLevel) || (_state != s_attacking && _currentLevel >= targetLevel)) { if (_state != s_decaying) _currentLevel = targetLevel; - if (_state != s_sustaining) - _state = next_state; + _state = nextState; } } } uint32 lvlout = _totalLevel + (uint32) _currentLevel; - int outp = 0; - int *i = &outp, *o = &outp; + + int32 outp = 0; + int32 *i = &outp, *o = &outp; int phaseShift = 0; - if (_feedbuf) { - o = &_feedbuf[0]; - i = &_feedbuf[1]; - phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0; + if (feed) { + o = &feed[0]; + i = &feed[1]; + phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0; if (phasebuf == -1) *i = 0; *o = *i; } else { phaseShift = phasebuf << 15; - } + } if (lvlout < 832) { uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) @@ -1285,15 +1295,11 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out _phase += _phaseIncrement; out += *o; - if (out > 32767) - out = 32767; - if (out < -32767) - out = -32767; } void TownsPC98_OpnOperator::reset(){ keyOff(); - _tick = 0; + _timer = 0; _keyScale2 = 0; _currentLevel = 1023; @@ -1306,7 +1312,7 @@ void TownsPC98_OpnOperator::reset(){ decayRate(0); releaseRate(0); sustainRate(0); - feedbackLevel(0); + feedbackLevel(0); totalLevel(127); } @@ -1332,40 +1338,42 @@ public: virtual ~TownsPC98_OpnChannel(); virtual void init(); - typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); - typedef enum channelState { CHS_RECALCFREQ = 0x01, CHS_KEYOFF = 0x02, - CHS_SSG = 0x04, + CHS_SSGOFF = 0x04, CHS_PITCHWHEELOFF = 0x08, CHS_ALL_BUT_EOT = 0x0f, + CHS_PROTECT = 0x40, CHS_EOT = 0x80 } ChannelState; virtual void loadData(uint8 *data); virtual void processEvents(); virtual void processFrequency(); - bool processControlEvent(uint8 cmd); - void writeReg(uint8 regAdress, uint8 value); + virtual bool processControlEvent(uint8 cmd); + void writeReg(uint8 regAddress, uint8 value); virtual void keyOn(); - virtual void keyOff(); - + void keyOff(); + void setOutputLevel(); - void fadeStep(); - void reset(); + virtual void fadeStep(); + virtual void reset(); void updateEnv(); - void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed); + void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed); bool _enableLeft; bool _enableRight; - bool _updateEnvelopes; + bool _updateEnvelopeParameters; const uint8 _idFlag; - int _feedbuf[3]; + int32 _feedbuf[3]; protected: + void setupPitchWheel(); + bool processPitchWheel(); + bool control_dummy(uint8 para); bool control_f0_setPatch(uint8 para); bool control_f1_presetOutputLevel(uint8 para); @@ -1377,40 +1385,36 @@ protected: bool control_f7_setupPitchWheel(uint8 para); bool control_f8_togglePitchWheel(uint8 para); bool control_fa_writeReg(uint8 para); - bool control_fb_incOutLevel(uint8 para); - bool control_fc_decOutLevel(uint8 para); + virtual bool control_fb_incOutLevel(uint8 para); + virtual bool control_fc_decOutLevel(uint8 para); bool control_fd_jump(uint8 para); - bool control_ff_endOfTrack(uint8 para); - - bool control_f0_setPatchSSG(uint8 para); - bool control_f1_setTotalLevel(uint8 para); - bool control_f4_setAlgorithm(uint8 para); - bool control_f9_unkSSG(uint8 para); - bool control_fb_incOutLevelSSG(uint8 para); - bool control_fc_decOutLevelSSG(uint8 para); - bool control_ff_endOfTrackSSG(uint8 para); + virtual bool control_ff_endOfTrack(uint8 para); uint8 _ticksLeft; uint8 _algorithm; - uint8 _instrID; + uint8 _instr; uint8 _totalLevel; uint8 _frqBlockMSB; int8 _frqLSB; uint8 _keyOffTime; - bool _protect; + bool _hold; uint8 *_dataPtr; - uint8 _ptchWhlInitDelayLo; uint8 _ptchWhlInitDelayHi; + uint8 _ptchWhlInitDelayLo; int16 _ptchWhlModInitVal; uint8 _ptchWhlDuration; uint8 _ptchWhlCurDelay; int16 _ptchWhlModCurVal; uint8 _ptchWhlDurLeft; - uint16 frequency; + uint16 _frequency; + uint8 _block; uint8 _regOffset; uint8 _flags; - uint8 _ssg1; - uint8 _ssg2; + uint8 _ssgTl; + uint8 _ssgStep; + uint8 _ssgTicksLeft; + uint8 _ssgTargetLvl; + uint8 _ssgStartLvl; const uint8 _chanNum; const uint8 _keyNum; @@ -1420,6 +1424,7 @@ protected: TownsPC98_OpnOperator **_opr; uint16 _frqTemp; + typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); const ControlEventFunc *controlEvents; }; @@ -1427,24 +1432,161 @@ class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel { public: TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); - ~TownsPC98_OpnChannelSSG() {} + virtual ~TownsPC98_OpnChannelSSG() {} void init(); + virtual void loadData(uint8 *data); void processEvents(); void processFrequency(); + bool processControlEvent(uint8 cmd); void keyOn(); - void keyOff(); + void nextShape(); + + void protect(); + void restore(); + + void fadeStep(); + +protected: + void setOutputLevel(uint8 lvl); + + bool control_f0_setInstr(uint8 para); + bool control_f1_setTotalLevel(uint8 para); + bool control_f4_setAlgorithm(uint8 para); + bool control_f9_loadCustomPatch(uint8 para); + bool control_fb_incOutLevel(uint8 para); + bool control_fc_decOutLevel(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_OpnChannelSSG::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnSfxChannel : public TownsPC98_OpnChannelSSG { +public: + TownsPC98_OpnSfxChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_OpnChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} + ~TownsPC98_OpnSfxChannel() {} + + void loadData(uint8 *data); +}; + +class TownsPC98_OpnChannelPCM : public TownsPC98_OpnChannel { +public: + TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + ~TownsPC98_OpnChannelPCM() {} + void init(); + void loadData(uint8 *data); + void processEvents(); + bool processControlEvent(uint8 cmd); + + void reset(); + +private: + bool control_f1_pcmStart(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_OpnChannelPCM::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnSquareSineSource { +public: + TownsPC98_OpnSquareSineSource(const uint32 timerbase); + ~TownsPC98_OpnSquareSineSource(); + + void init(const int *rsTable, const int *rseTable); + void reset(); + uint8 readReg(uint8 address); + void writeReg(uint8 address, uint8 value, bool force = false); + + void nextTick(int32 *buffer, uint32 bufferSize); private: - void opn_SSG_UNK(uint8 a); + void updatesRegs(); + + uint8 _reg[16]; + uint8 _updateRequestBuf[32]; + int _updateRequest; + uint8 *_regIndex; + int _rand; + + int8 _evpTimer; + uint32 _pReslt; + uint8 _attack; + + bool _evpUpdate, _cont; + + int _evpUpdateCnt; + uint8 _outN; + int _nTick; + + int32 *_tlTable; + int32 *_tleTable; + + const uint32 _tickLength; + uint32 _timer; + + struct Channel { + int tick; + uint8 smp; + uint8 out; + } _channels[3]; + + bool _ready; }; +class TownsPC98_OpnPercussionSource { +public: + TownsPC98_OpnPercussionSource(const uint32 timerbase); + ~TownsPC98_OpnPercussionSource() {} + + void init(const uint8 *pcmData = 0); + void reset(); + void writeReg(uint8 address, uint8 value); + + void nextTick(int32 *buffer, uint32 bufferSize); + +private: + struct PcmInstrument { + const uint8 *data; + + const uint8 *start; + const uint8 *end; + const uint8 *pos; + uint32 size; + bool active; + uint8 level; + + int8 decState; + uint8 decStep; + + int16 samples[2]; + int out; + }; + + void recalcOuput(PcmInstrument *ins); + void advanceInput(PcmInstrument *ins); + + PcmInstrument _pcmInstr[6]; + uint8 _regs[48]; + + uint8 _totalLevel; + + const uint32 _tickLength; + uint32 _timer; + bool _ready; +}; class TownsPC98_OpnDriver : public Audio::AudioStream { friend class TownsPC98_OpnChannel; friend class TownsPC98_OpnChannelSSG; +friend class TownsPC98_OpnSfxChannel; +friend class TownsPC98_OpnChannelPCM; public: enum OpnType { OD_TOWNS, @@ -1456,17 +1598,21 @@ public: ~TownsPC98_OpnDriver(); bool init(); - void loadData(uint8 *data, bool loadPaused = false); + + void loadMusicData(uint8 *data, bool loadPaused = false); + void loadSoundEffectData(uint8 *data, uint8 trackNum); void reset(); - void fadeOut(); - - void pause() { _playing = false; } - void cont() { _playing = true; } + void fadeStep(); + + void pause() { _musicPlaying = false; } + void cont() { _musicPlaying = true; } - void callback(); - void nextTick(int16 *buffer, uint32 bufferSize); + void musicCallback(); + void sfxCallback(); + void nextTick(int32 *buffer, uint32 bufferSize); bool looping() { return _looping == _updateChannelsFlag ? true : false; } + bool musicPlaying() { return _musicPlaying; } // AudioStream interface int inline readBuffer(int16 *buffer, const int numSamples); @@ -1479,9 +1625,16 @@ protected: TownsPC98_OpnChannel **_channels; TownsPC98_OpnChannelSSG **_ssgChannels; - //TownsPC98_OpnChannel *_adpcmChannel; + TownsPC98_OpnSfxChannel **_sfxChannels; + TownsPC98_OpnChannelPCM *_pcmChannel; - void setTempo(uint8 tempo); + TownsPC98_OpnSquareSineSource *_ssg; + TownsPC98_OpnPercussionSource *_pcm; + + void startSoundEffect(); + + void setMusicTempo(uint8 tempo); + void setSfxTempo(uint16 tempo); void lock() { _mutex.lock(); } void unlock() { _mutex.unlock(); } @@ -1492,6 +1645,7 @@ protected: const uint8 *_opnCarrier; const uint8 *_opnFreqTable; + const uint8 *_opnFreqTableSSG; const uint8 *_opnFxCmdLen; const uint8 *_opnLvlPresets; @@ -1503,34 +1657,54 @@ protected: int32 *_oprLevelOut; int32 *_oprDetune; - uint8 *_trackData; + uint8 *_musicBuffer; + uint8 *_sfxBuffer; + uint8 *_trackPtr; uint8 *_patches; + uint8 *_ssgPatches; - uint8 _cbCounter; uint8 _updateChannelsFlag; + uint8 _updateSSGFlag; + uint8 _updatePCMFlag; + uint8 _updateSfxFlag; uint8 _finishedChannelsFlag; - uint16 _tempo; - bool _playing; - bool _fading; + uint8 _finishedSSGFlag; + uint8 _finishedPCMFlag; + uint8 _finishedSfxFlag; + + bool _musicPlaying; + bool _sfxPlaying; + uint8 _fading; uint8 _looping; - uint32 _tickCounter; + uint32 _musicTickCounter; - bool _updateEnvelopes; - int _ssgFlag; + bool _updateEnvelopeParameters; - int32 _samplesTillCallback; - int32 _samplesTillCallbackRemainder; - int32 _samplesPerCallback; - int32 _samplesPerCallbackRemainder; + bool _regProtectionFlag; + int _sfxOffs; + uint8 *_sfxData; + uint16 _sfxOffsets[2]; + + int32 _samplesTillMusicCallback; + uint32 _samplesTillMusicCallbackRemainder; + int32 _samplesPerMusicCallback; + uint32 _samplesPerMusicCallbackRemainder; + int32 _samplesTillSfxCallback; + uint32 _samplesTillSfxCallbackRemainder; + int32 _samplesPerSfxCallback; + uint32 _samplesPerSfxCallbackRemainder; const int _numChan; const int _numSSG; - const bool _hasADPCM; - const bool _hasStereo; + const bool _hasPCM; - double _baserate; static const uint8 _drvTables[]; static const uint32 _adtStat[]; + static const int _ssgTables[]; + + const float _baserate; + uint32 _timerbase; + bool _ready; }; @@ -1538,14 +1712,15 @@ TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 re uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), _part(prt), _idFlag(id) { - _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _ssg1 = _ssg2 = 0; - _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0; + _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0; + _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0; + _ptchWhlInitDelayHi = _ptchWhlInitDelayLo = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0; _frqLSB = 0; - _protect = _updateEnvelopes = false; + _hold = _updateEnvelopeParameters = false; _enableLeft = _enableRight = true; - _dataPtr = 0; + _dataPtr = 0; _ptchWhlModInitVal = _ptchWhlModCurVal = 0; - frequency = _frqTemp = 0; + _frequency = _frqTemp = 0; memset(&_feedbuf, 0, sizeof(int) * 3); _opr = 0; } @@ -1559,10 +1734,9 @@ TownsPC98_OpnChannel::~TownsPC98_OpnChannel() { } void TownsPC98_OpnChannel::init() { - _opr = new TownsPC98_OpnOperator*[4]; for (int i = 0; i < 4; i++) - _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, + _opr[i] = new TownsPC98_OpnOperator(_drv->_timerbase, _drv->_oprRates, _drv->_oprRateshift, _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); #define Control(x) &TownsPC98_OpnChannel::control_##x @@ -1592,16 +1766,16 @@ void TownsPC98_OpnChannel::init() { void TownsPC98_OpnChannel::keyOff() { // all operators off uint8 value = _keyNum & 0x0f; - uint8 regAdress = 0x28; - writeReg(regAdress, value); + uint8 regAddress = 0x28; + writeReg(regAddress, value); _flags |= CHS_KEYOFF; } void TownsPC98_OpnChannel::keyOn() { // all operators on uint8 value = _keyNum | 0xf0; - uint8 regAdress = 0x28; - writeReg(regAdress, value); + uint8 regAddress = 0x28; + writeReg(regAddress, value); } void TownsPC98_OpnChannel::loadData(uint8 *data) { @@ -1645,13 +1819,13 @@ void TownsPC98_OpnChannel::processEvents() { if (_flags & CHS_EOT) return; - if (_protect == false && _ticksLeft == _keyOffTime) + if (!_hold && _ticksLeft == _keyOffTime) keyOff(); if (--_ticksLeft) return; - if (_protect == false) + if (!_hold) keyOff(); uint8 cmd = 0; @@ -1669,14 +1843,14 @@ void TownsPC98_OpnChannel::processEvents() { if (cmd == 0x80) { keyOff(); - _protect = false; + _hold = false; } else { keyOn(); - if (_protect == false || cmd != _frqBlockMSB) + if (_hold == false || cmd != _frqBlockMSB) _flags |= CHS_RECALCFREQ; - - _protect = (para & 0x80) ? true : false; + + _hold = (para & 0x80) ? true : false; _frqBlockMSB = cmd; } @@ -1687,35 +1861,46 @@ void TownsPC98_OpnChannel::processFrequency() { if (_flags & CHS_RECALCFREQ) { uint8 block = (_frqBlockMSB & 0x70) >> 1; uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; - frequency = (bfreq + _frqLSB) | (block << 8); - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); + _frequency = (bfreq + _frqLSB) | (block << 8); + writeReg(_regOffset + 0xa4, (_frequency >> 8)); + writeReg(_regOffset + 0xa0, (_frequency & 0xff)); - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - if (_flags & CHS_KEYOFF) { - _ptchWhlModCurVal = _ptchWhlModInitVal; - _ptchWhlCurDelay += _ptchWhlInitDelayLo; - } - - _ptchWhlDurLeft = (_ptchWhlDuration >> 1); - _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + setupPitchWheel(); } if (!(_flags & CHS_PITCHWHEELOFF)) { - if (--_ptchWhlCurDelay) + if (!processPitchWheel()) return; - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - frequency += _ptchWhlModCurVal; - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); + writeReg(_regOffset + 0xa4, (_frequency >> 8)); + writeReg(_regOffset + 0xa0, (_frequency & 0xff)); + } +} - if(!--_ptchWhlDurLeft) { - _ptchWhlDurLeft = _ptchWhlDuration; - _ptchWhlModCurVal = -_ptchWhlModCurVal; - } +void TownsPC98_OpnChannel::setupPitchWheel() { + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + if (_flags & CHS_KEYOFF) { + _ptchWhlModCurVal = _ptchWhlModInitVal; + _ptchWhlCurDelay += _ptchWhlInitDelayLo; } + _ptchWhlDurLeft = (_ptchWhlDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +} + +bool TownsPC98_OpnChannel::processPitchWheel() { + if (--_ptchWhlCurDelay) + return false; + + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + _frequency += _ptchWhlModCurVal; + + if(!--_ptchWhlDurLeft) { + _ptchWhlDurLeft = _ptchWhlDuration; + _ptchWhlModCurVal = -_ptchWhlModCurVal; + } + + return true; } bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) { @@ -1743,10 +1928,24 @@ void TownsPC98_OpnChannel::fadeStep() { } void TownsPC98_OpnChannel::reset() { - for (int i = 0; i < 4; i++) - _opr[i]->reset(); + if (_opr) { + for (int i = 0; i < 4; i++) + _opr[i]->reset(); + } - _updateEnvelopes = false; + _block = 0; + _frequency = 0; + _hold = false; + _frqTemp = 0; + _ssgTl = 0; + _ssgStartLvl = 0; + _ssgTargetLvl = 0; + _ssgStep = 0; + _ssgTicksLeft = 0; + _totalLevel = 0; + _flags |= CHS_EOT; + + _updateEnvelopeParameters = false; _enableLeft = _enableRight = true; memset(&_feedbuf, 0, sizeof(int) * 3); } @@ -1756,10 +1955,10 @@ void TownsPC98_OpnChannel::updateEnv() { _opr[i]->updatePhaseIncrement(); } -void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) { - int phbuf1, phbuf2, output; +void TownsPC98_OpnChannel::generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed) { + int32 phbuf1, phbuf2, output; phbuf1 = phbuf2 = output = 0; - + switch (_algorithm) { case 0: _opr[0]->generateOutput(0, feed, phbuf1); @@ -1771,7 +1970,7 @@ void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, case 1: _opr[0]->generateOutput(0, feed, phbuf1); _opr[2]->generateOutput(*del, 0, phbuf2); - _opr[1]->generateOutput(0, 0, phbuf1); + _opr[1]->generateOutput(0, 0, phbuf1); _opr[3]->generateOutput(phbuf2, 0, output); *del = phbuf1; break; @@ -1792,7 +1991,7 @@ void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, case 4: _opr[0]->generateOutput(0, feed, phbuf1); _opr[2]->generateOutput(0, 0, phbuf2); - _opr[1]->generateOutput(phbuf1, 0, output); + _opr[1]->generateOutput(phbuf1, 0, output); _opr[3]->generateOutput(phbuf2, 0, output); *del = 0; break; @@ -1819,39 +2018,34 @@ void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, break; }; - if (_enableLeft) { - int l = output + leftSample; - if (l > 32767) - l = 32767; - if (l < -32767) - l = -32767; - leftSample = (int16) l; - } + int32 finOut = ((output * 7) / 2); - if (_enableRight) { - int r = output + rightSample; - if (r > 32767) - r = 32767; - if (r < -32767) - r = -32767; - rightSample = (int16) r; - } + if (_enableLeft) + leftSample += finOut; + + if (_enableRight) + rightSample += finOut; } -void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { - uint8 h = regAdress & 0xf0; - uint8 l = (regAdress & 0x0f); +void TownsPC98_OpnChannel::writeReg(uint8 regAddress, uint8 value) { + if (_drv->_regProtectionFlag) + return; + + uint8 h = regAddress & 0xf0; + uint8 l = (regAddress & 0x0f); static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; uint8 o = oprOrdr[(l - _regOffset) >> 2]; - + switch (h) { case 0x00: // ssg - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + if (_drv->_ssg) + _drv->_ssg->writeReg(regAddress, value); break; case 0x10: - // adpcm - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + // pcm rhythm channel + if (_drv->_pcm) + _drv->_pcm->writeReg(regAddress - 0x10, value); break; case 0x20: if (l == 8) { @@ -1884,7 +2078,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { // detune, multiple _opr[o]->detune((value >> 4) & 7); _opr[o]->multiple(value & 0x0f); - _updateEnvelopes = true; + _updateEnvelopeParameters = true; break; case 0x40: @@ -1896,7 +2090,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { // rate scaling, attack rate _opr[o]->attackRate(value & 0x1f); if (_opr[o]->scaleRate(value >> 6)) - _updateEnvelopes = true; + _updateEnvelopeParameters = true; break; case 0x60: @@ -1904,7 +2098,6 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { _opr[o]->decayRate(value & 0x1f); if (value & 0x80) warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); - break; case 0x70: @@ -1919,8 +2112,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { break; case 0x90: - // ssg - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress); break; case 0xa0: @@ -1928,7 +2120,7 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { l -= _regOffset; if (l == 0) { _frqTemp = (_frqTemp & 0xff00) | value; - _updateEnvelopes = true; + _updateEnvelopeParameters = true; for (int i = 0; i < 4; i++) _opr[i]->frequency(_frqTemp); } else if (l == 4) { @@ -1964,13 +2156,13 @@ void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { break; default: - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress); break; } } bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { - _instrID = para; + _instr = para; uint8 reg = _regOffset + 0x80; for (int i = 0; i < 4; i++) { @@ -1979,7 +2171,7 @@ bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { reg += 4; } - const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5); + const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5); reg = _regOffset + 0x30; // write registers 0x30 to 0x8f @@ -2033,7 +2225,7 @@ bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) { } bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) { - _drv->setTempo(para); + _drv->setMusicTempo(para); return true; } @@ -2043,7 +2235,7 @@ bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { if (*_dataPtr) { // repeat section until counter has reached zero - _dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2); + _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2); } else { // reset counter, advance to next section _dataPtr[0] = _dataPtr[1]; @@ -2053,8 +2245,8 @@ bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { } bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) { - _ptchWhlInitDelayLo = _dataPtr[0]; - _ptchWhlInitDelayHi = para; + _ptchWhlInitDelayHi = _dataPtr[0]; + _ptchWhlInitDelayLo = para; _ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); _ptchWhlDuration = _dataPtr[3]; _dataPtr += 4; @@ -2070,11 +2262,12 @@ bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) { _flags |= CHS_PITCHWHEELOFF; } } else { - //uint8 skipChannels = para / 36; - //uint8 entry = para % 36; - //TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; - ////// NOT IMPLEMENTED - //t->unnamedEntries[entry] = *_dataPtr++; + /* NOT IMPLEMENTED + uint8 skipChannels = para / 36; + uint8 entry = para % 36; + TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; + + t->unnamedEntries[entry] = *_dataPtr++;*/ } return true; } @@ -2113,7 +2306,7 @@ bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) { } bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) { - uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1); + uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1); _dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr; return true; } @@ -2127,7 +2320,7 @@ bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { uint16 val = READ_LE_UINT16(--_dataPtr); if (val) { // loop - _dataPtr = _drv->_trackData + val; + _dataPtr = _drv->_trackPtr + val; return true; } else { // quit parsing for active channel @@ -2139,31 +2332,248 @@ bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { } } -bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) { - _instrID = para << 4; +TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { +} + +void TownsPC98_OpnChannelSSG::init() { + _algorithm = 0x80; + + #define Control(x) &TownsPC98_OpnChannelSSG::control_##x + static const ControlEventFunc ctrlEventsSSG[] = { + Control(f0_setInstr), + Control(f1_setTotalLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setAlgorithm), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupPitchWheel), + Control(f8_togglePitchWheel), + Control(f9_loadCustomPatch), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control + + controlEvents = ctrlEventsSSG; +} + +void TownsPC98_OpnChannelSSG::processEvents() { + if (_flags & CHS_EOT) + return; + + _drv->_regProtectionFlag = (_flags & CHS_PROTECT) ? true : false; + + if (!_hold && _ticksLeft == _keyOffTime) + nextShape(); + + if (!--_ticksLeft) { + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + nextShape(); + _hold = false; + } else { + if (!_hold) { + _instr &= 0xf0; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + _ssgStartLvl = _drv->_ssgPatches[_instr + 3]; + _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF; + } + + keyOn(); + + if (_hold == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _hold = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; + } + + if (!(_flags & CHS_SSGOFF)) { + if (--_ssgTicksLeft) { + if (!_drv->_fading) + setOutputLevel(_ssgStartLvl); + return; + } + + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + + if (_drv->_ssgPatches[_instr + 1] & 0x80) { + uint8 t = _ssgStartLvl - _ssgStep; + + if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) { + if (!_drv->_fading) + setOutputLevel(t); + return; + } + } else { + int t = _ssgStartLvl + _ssgStep; + uint8 p = (uint8) (t & 0xff); + + if (t < 256 && _ssgTargetLvl > p) { + if (!_drv->_fading) + setOutputLevel(p); + return; + } + } + + setOutputLevel(_ssgTargetLvl); + if (_ssgStartLvl && !(_instr & 8)){ + _instr += 4; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + } else { + _flags |= CHS_SSGOFF; + setOutputLevel(0); + } + } +} + +void TownsPC98_OpnChannelSSG::processFrequency() { + if (_algorithm & 0x40) + return; + + if (_flags & CHS_RECALCFREQ) { + _block = _frqBlockMSB >> 4; + _frequency = ((const uint16*)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB; + + uint16 f = _frequency >> _block; + writeReg(_regOffset << 1, f & 0xff); + writeReg((_regOffset << 1) + 1, f >> 8); + + setupPitchWheel(); + } + + if (!(_flags & (CHS_EOT | CHS_PITCHWHEELOFF | CHS_SSGOFF))) { + if (!processPitchWheel()) + return; + + uint16 f = _frequency >> _block; + writeReg(_regOffset << 1, f & 0xff); + writeReg((_regOffset << 1) + 1, f >> 8); + } +} + +bool TownsPC98_OpnChannelSSG::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +void TownsPC98_OpnChannelSSG::nextShape() { + _instr = (_instr & 0xf0) + 0x0c; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; +} + +void TownsPC98_OpnChannelSSG::keyOn() { + uint8 c = 0x7b; + uint8 t = (_algorithm & 0xC0) << 1; + if (_algorithm & 0x80) + t |= 4; + + c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset)); + t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset)); + + if (!(_algorithm & 0x80)) + writeReg(6, _algorithm & 0x7f); + + uint8 e = (_drv->_ssg->readReg(7) & c) | t; + writeReg(7, e); +} + +void TownsPC98_OpnChannelSSG::protect() { + _flags |= CHS_PROTECT; +} + +void TownsPC98_OpnChannelSSG::restore() { + _flags &= ~CHS_PROTECT; + keyOn(); + writeReg(8 + _regOffset, _ssgTl); + uint16 f = _frequency >> _block; + writeReg(_regOffset << 1, f & 0xff); + writeReg((_regOffset << 1) + 1, f >> 8); +} + +void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { + _drv->_regProtectionFlag = (_flags & CHS_PROTECT) ? true : false; + TownsPC98_OpnChannel::loadData(data); + setOutputLevel(0); + _algorithm = 0x80; +} + +void TownsPC98_OpnChannelSSG::setOutputLevel(uint8 lvl) { + _ssgStartLvl = lvl; + uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8; + if (newTl == _ssgTl) + return; + _ssgTl = newTl; + writeReg(8 + _regOffset, _ssgTl); +} + +void TownsPC98_OpnChannelSSG::fadeStep() { + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + setOutputLevel(_ssgStartLvl); +} + +bool TownsPC98_OpnChannelSSG::control_f0_setInstr(uint8 para) { + _instr = para << 4; para = (para >> 3) & 0x1e; if (para) return control_f4_setAlgorithm(para | 0x40); return true; } -bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_f1_setTotalLevel(uint8 para) { if (!_drv->_fading) _totalLevel = para; return true; } -bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_f4_setAlgorithm(uint8 para) { _algorithm = para; return true; } -bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) { - _dataPtr += 5; +bool TownsPC98_OpnChannelSSG::control_f9_loadCustomPatch(uint8 para) { + _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4; + _drv->_ssgPatches[_instr] = *_dataPtr++; + _drv->_ssgPatches[_instr + 3] = para; + _drv->_ssgPatches[_instr + 4] = *_dataPtr++; + _drv->_ssgPatches[_instr + 6] = *_dataPtr++; + _drv->_ssgPatches[_instr + 8] = *_dataPtr++; + _drv->_ssgPatches[_instr + 12] = *_dataPtr++; return true; } -bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_fb_incOutLevel(uint8 para) { _dataPtr--; if (_drv->_fading) return true; @@ -2175,7 +2585,7 @@ bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { return true; } -bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_fc_decOutLevel(uint8 para) { _dataPtr--; if (_drv->_fading) return true; @@ -2186,184 +2596,481 @@ bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { return true; } -bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) { - uint16 val = READ_LE_UINT16(--_dataPtr); - if (val) { - // loop - _dataPtr = _drv->_trackData + val; - return true; +bool TownsPC98_OpnChannelSSG::control_ff_endOfTrack(uint8 para) { + if (!_drv->_sfxOffs) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // stop parsing + if (!_drv->_fading) + setOutputLevel(0); + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedSSGFlag |= _idFlag; + } } else { - // quit parsing for active channel - --_dataPtr; + // end of sfx track - restore ssg music channel _flags |= CHS_EOT; - //_finishedChannelsFlag |= _idFlag; - keyOff(); - return false; + _drv->_finishedSfxFlag |= _idFlag; + _drv->_ssgChannels[_chanNum]->restore(); } + + return false; } -TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, +void TownsPC98_OpnSfxChannel::loadData(uint8 *data) { + _flags = CHS_ALL_BUT_EOT; + _ticksLeft = 1; + _dataPtr = data; + _ssgTl = 0xff; + _algorithm = 0x80; +} + +TownsPC98_OpnChannelPCM::TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { } -void TownsPC98_OpnChannelSSG::init() { +void TownsPC98_OpnChannelPCM::init() { _algorithm = 0x80; - - _opr = new TownsPC98_OpnOperator*[4]; - for (int i = 0; i < 4; i++) - _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, - _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); - #define Control(x) &TownsPC98_OpnChannelSSG::control_##x - static const ControlEventFunc ctrlEventsSSG[] = { - Control(f0_setPatchSSG), - Control(f1_setTotalLevel), - Control(f2_setKeyOffTime), - Control(f3_setFreqLSB), - Control(f4_setOutputLevel), - Control(f5_setTempo), + #define Control(x) &TownsPC98_OpnChannelPCM::control_##x + static const ControlEventFunc ctrlEventsPCM[] = { + Control(dummy), + Control(f1_pcmStart), + Control(dummy), + Control(dummy), + Control(dummy), + Control(dummy), Control(f6_repeatSection), - Control(f7_setupPitchWheel), - Control(f8_togglePitchWheel), - Control(f9_unkSSG), + Control(dummy), + Control(dummy), + Control(dummy), Control(fa_writeReg), - Control(fb_incOutLevelSSG), - Control(fc_decOutLevelSSG), - Control(fd_jump), Control(dummy), - Control(ff_endOfTrackSSG) + Control(dummy), + Control(dummy), + Control(dummy), + Control(ff_endOfTrack) }; #undef Control - controlEvents = ctrlEventsSSG; + controlEvents = ctrlEventsPCM; } -void TownsPC98_OpnChannelSSG::processEvents() { +void TownsPC98_OpnChannelPCM::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; +} + +void TownsPC98_OpnChannelPCM::processEvents() { if (_flags & CHS_EOT) return; - _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; - - if (_protect == false && _ticksLeft == _keyOffTime) - keyOff(); - if (--_ticksLeft) return; - if (_protect == false) - keyOff(); - uint8 cmd = 0; bool loop = true; while (loop) { cmd = *_dataPtr++; - if (cmd < 0xf0) + if (cmd == 0x80) { loop = false; - else if (!processControlEvent(cmd)) + } else if (cmd < 0xf0) { + writeReg(0x10, cmd); + } else if (!processControlEvent(cmd)) { return; + } } + _ticksLeft = *_dataPtr++; +} + +bool TownsPC98_OpnChannelPCM::processControlEvent(uint8 cmd) { uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} - if (cmd == 0x80) { - keyOff(); - _protect = false; +void TownsPC98_OpnChannelPCM::reset() { + TownsPC98_OpnChannel::reset(); + + if (_drv->_pcm) + _drv->_pcm->reset(); +} + +bool TownsPC98_OpnChannelPCM::control_f1_pcmStart(uint8 para) { + _totalLevel = para; + writeReg(0x11, para); + return true; +} + +bool TownsPC98_OpnChannelPCM::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; } else { - keyOn(); + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedPCMFlag |= _idFlag; + return false; + } +} - if (_protect == false || cmd != _frqBlockMSB) - _flags |= CHS_RECALCFREQ; - - _protect = (para & 0x80) ? true : false; - _frqBlockMSB = cmd; +TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const uint32 timerbase) : _tlTable(0), + _tleTable(0), _regIndex(_reg), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0) { + memset(_reg, 0, 16); + memset(_channels, 0, sizeof(Channel) * 3); + reset(); +} + +TownsPC98_OpnSquareSineSource::~TownsPC98_OpnSquareSineSource() { + delete [] _tlTable; + delete [] _tleTable; +} + +void TownsPC98_OpnSquareSineSource::init(const int *rsTable, const int *rseTable) { + if (_ready) { + reset(); + return; } - _ticksLeft = para & 0x7f; + delete [] _tlTable; + delete [] _tleTable; + _tlTable = new int32[16]; + _tleTable = new int32[32]; + float a, b, d; + d = 801.0f; + + for (int i = 0; i < 16; i++) { + b = 1.0f / rsTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tlTable[i] = (int32) v; + + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } - if (!(_flags & CHS_SSG)) { + for (int i = 16; i < 32; i++) { + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } + _ready = true; +} + +void TownsPC98_OpnSquareSineSource::reset() { + _rand = 1; + _outN = 1; + _updateRequest = -1; + _nTick = _evpUpdateCnt = 0; + _regIndex = _reg; + _evpTimer = 0x1f; + _pReslt = 0x1f; + _attack = 0; + _cont = false; + _evpUpdate = true; + _timer = 0; + + for (int i = 0; i < 3; i++) { + _channels[i].tick = 0; + _channels[i].smp = _channels[i].out = 0; } + + for (int i = 0; i < 14; i++) + writeReg(i, 0, true); + + writeReg(7, 0xbf, true); } -void TownsPC98_OpnChannelSSG::processFrequency() { - if (_flags & CHS_RECALCFREQ) { - uint8 block = (_frqBlockMSB & 0x70) >> 1; - uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; - frequency = (bfreq + _frqLSB) | (block << 8); +uint8 TownsPC98_OpnSquareSineSource::readReg(uint8 address) { + return _reg[address]; +} - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); +void TownsPC98_OpnSquareSineSource::writeReg(uint8 address, uint8 value, bool force) { + _regIndex = &_reg[address]; + int o = _regIndex - _reg; + if (!force && (o == 13 || *_regIndex != value)) { + if (_updateRequest == 31) { + warning("TownsPC98_OpnSquareSineSource: event buffer overflow"); + _updateRequest = -1; + } + _updateRequestBuf[++_updateRequest] = value; + _updateRequestBuf[++_updateRequest] = o; + return; + } + + *_regIndex = value; +} + +void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + if (++_nTick >= (_reg[6] & 0x1f)) { + if ((_rand + 1) & 2) + _outN ^= 1; + + _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1); + _nTick = 0; + } + + for (int ii = 0; ii < 3; ii++) { + if (++_channels[ii].tick >= (((_reg[ii * 2 + 1] & 0x0f) << 8) | _reg[ii * 2])) { + _channels[ii].tick = 0; + _channels[ii].smp ^= 1; + } + _channels[ii].out = (_channels[ii].smp | ((_reg[7] >> ii) & 1)) & (_outN | ((_reg[7] >> (ii + 3)) & 1)); + } - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - if (_flags & CHS_KEYOFF) { - _ptchWhlModCurVal = _ptchWhlModInitVal; - _ptchWhlCurDelay += _ptchWhlInitDelayLo; + if (_evpUpdate) { + if (++_evpUpdateCnt >= ((_reg[12] << 8) | _reg[11])) { + _evpUpdateCnt = 0; + + if (--_evpTimer < 0) { + if (_cont) { + _evpTimer &= 0x1f; + } else { + _evpUpdate = false; + _evpTimer = 0; + } + } + } + } + _pReslt = _evpTimer ^ _attack; + updatesRegs(); } - _ptchWhlDurLeft = (_ptchWhlDuration >> 1); - _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + int32 finOut = 0; + for (int ii = 0; ii < 3; ii++) { + if ((_reg[ii + 8] >> 4) & 1) + finOut += _tleTable[_channels[ii].out ? _pReslt : 0]; + else + finOut += _tlTable[_channels[ii].out ? (_reg[ii + 8] & 0x0f) : 0]; + } + + finOut /= 2; + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; } +} - if (!(_flags & CHS_PITCHWHEELOFF)) { - if (--_ptchWhlCurDelay) - return; - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - frequency += _ptchWhlModCurVal; +void TownsPC98_OpnSquareSineSource::updatesRegs() { + for (int i = 0; i < _updateRequest;) { + uint8 b = _updateRequestBuf[i++]; + uint8 a = _updateRequestBuf[i++]; + writeReg(a, b, true); + } + _updateRequest = -1; +} - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); +TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const uint32 timerbase) : + _tickLength(timerbase * 2), _timer(0), _ready(false) { + memset(_pcmInstr, 0, sizeof(PcmInstrument) * 6); +} - if(!--_ptchWhlDurLeft) { - _ptchWhlDurLeft = _ptchWhlDuration; - _ptchWhlModCurVal = -_ptchWhlModCurVal; +void TownsPC98_OpnPercussionSource::init(const uint8 *pcmData) { + if (_ready) { + reset(); + return; + } + + const uint8 *start = pcmData; + const uint8 *pos = start; + + if (pcmData) { + for (int i = 0; i < 6; i++) { + _pcmInstr[i].data = start + READ_BE_UINT16(pos); + pos += 2; + _pcmInstr[i].size = READ_BE_UINT16(pos); + pos += 2; } + reset(); + _ready = true; + } else { + memset(_pcmInstr, 0, sizeof(PcmInstrument) * 6); + _ready = false; } } -void TownsPC98_OpnChannelSSG::keyOff() { - // all operators off - uint8 value = _keyNum & 0x0f; - uint8 regAdress = 0x28; - writeReg(regAdress, value); - _flags |= CHS_KEYOFF; -} +void TownsPC98_OpnPercussionSource::reset() { + _timer = 0; + _totalLevel = 63; -void TownsPC98_OpnChannelSSG::keyOn() { - // all operators on - uint8 value = _keyNum | 0xf0; - uint8 regAdress = 0x28; - writeReg(regAdress, value); + memset(_regs, 0, 48); + + for (int i = 0; i < 6; i++) { + PcmInstrument *s = &_pcmInstr[i]; + s->pos = s->start = s->data; + s->end = s->data + s->size; + s->active = false; + s->level = 0; + s->out = 0; + s->decStep = 1; + s->decState = 0; + s->samples[0] = s->samples[1] = 0; + } } -void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { - _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; - opn_SSG_UNK(0); - TownsPC98_OpnChannel::loadData(data); - _algorithm = 0x80; +void TownsPC98_OpnPercussionSource::writeReg(uint8 address, uint8 value) { + if (!_ready) + return; + + uint8 h = address >> 4; + uint8 l = address & 15; + + _regs[address] = value; + + if (address == 0) { + if (value & 0x80) { + //key off + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) + _pcmInstr[i].active = false; + } + } else { + //key on + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) { + PcmInstrument *s = &_pcmInstr[i]; + s->pos = s->start; + s->active = true; + s->out = 0; + s->samples[0] = s->samples[1] = 0; + s->decStep = 1; + s->decState = 0; + } + } + } + } else if (address == 1) { + // total level + _totalLevel = (value & 63) ^ 63; + for (int i = 0; i < 6; i++) + recalcOuput(&_pcmInstr[i]); + } else if (!h && l & 8) { + // instrument level + l &= 7; + _pcmInstr[l].level = (value & 0x1f) ^ 0x1f; + recalcOuput(&_pcmInstr[l]); + } else if (h & 3) { + l &= 7; + if (h == 1) { + // set start offset + _pcmInstr[l].start = _pcmInstr[l].data + ((_regs[24 + l] * 256 + _regs[16 + l]) << 8); + } else if (h == 2) { + // set end offset + _pcmInstr[l].end = _pcmInstr[l].data + ((_regs[40 + l] * 256 + _regs[32 + l]) << 8) + 255; + } + } } -void TownsPC98_OpnChannelSSG::opn_SSG_UNK(uint8 a) { - _ssg1 = a; - uint16 h = (_totalLevel + 1) * a; - if ((h >> 8) == _ssg2) +void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) return; - _ssg2 = (h >> 8); - writeReg(8 + _regOffset, _ssg2); + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + for (int ii = 0; ii < 6; ii++) { + PcmInstrument *s = &_pcmInstr[ii]; + if (s->active) { + recalcOuput(s); + if (s->decStep) { + advanceInput(s); + if (s->pos == s->end) + s->active = false; + } + s->decStep ^= 1; + } + } + } + + int32 finOut = 0; + + for (int ii = 0; ii < 6; ii++) { + if (_pcmInstr[ii].active) + finOut += _pcmInstr[ii].out; + } + + finOut = (finOut * 7); + + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; + } +} + +void TownsPC98_OpnPercussionSource::recalcOuput(PcmInstrument *ins) { + uint32 s = _totalLevel + ins->level; + uint32 x = s > 62 ? 0 : (1 + (s >> 3)); + int32 y = s > 62 ? 0 : (15 - (s & 7)); + ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3; +} + +void TownsPC98_OpnPercussionSource::advanceInput(PcmInstrument *ins) { + static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; + + static const int16 stepTable[] = { 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 + }; + + uint8 cur = (int8) *ins->pos++; + + for (int i = 0; i < 2; i++) { + int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; + ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047); + ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48); + cur >>= 4; + } } TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : - _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0), - _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), - _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , - _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), - _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), - _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false), - _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), - _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { - setTempo(84); - _baserate = (486202500.0 / (double)getRate()) / 10368.0; + _mixer(mixer), + + _channels(0), _ssgChannels(0), _sfxChannels(0), _pcmChannel(0), _ssg(0), _pcm(0), + + _trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0), + + _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), _opnFreqTableSSG(_drvTables + 252), + _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 228)), + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), + + _numChan(type == OD_TYPE26 ? 3 : 6), _numSSG(type == OD_TOWNS ? 0 : 3), _hasPCM(type == OD_TYPE86 ? true : false), + _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), + _updateSSGFlag(type == OD_TOWNS ? 0x00 : 0x07), _finishedSSGFlag(0), + _updatePCMFlag(type == OD_TYPE86 ? 0x01 : 0x00), _finishedPCMFlag(0), + _updateSfxFlag(type == OD_TOWNS ? 0x00 : 0x06), _finishedSfxFlag(0), + + _baserate(55125.0f / (float)getRate()), + _samplesTillMusicCallback(0), _samplesTillSfxCallback(0), + _samplesTillMusicCallbackRemainder(0), _samplesTillSfxCallbackRemainder(0), + _musicTickCounter(0), + + _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) { + + _timerbase = (uint32)(_baserate * 1000000.0f); + setMusicTempo(84); + setSfxTempo(654); } TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { @@ -2381,13 +3088,26 @@ TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { delete [] _ssgChannels; } + if (_sfxChannels) { + for (int i = 0; i < 2; i++) + delete _sfxChannels[i]; + delete [] _sfxChannels; + } + + if (_pcmChannel) + delete _pcmChannel; + + delete _ssg; + delete _pcm; + delete [] _oprRates; delete [] _oprRateshift; delete [] _oprFrq; delete [] _oprAttackDecay; delete [] _oprSinTbl; delete [] _oprLevelOut; - delete [] _oprDetune; + delete [] _oprDetune; + delete [] _ssgPatches; } bool TownsPC98_OpnDriver::init() { @@ -2420,7 +3140,21 @@ bool TownsPC98_OpnDriver::init() { } delete [] _ssgChannels; } + + if (_sfxChannels) { + for (int i = 0; i < 2; i++) { + if (_sfxChannels[i]) + delete _sfxChannels[i]; + } + delete [] _sfxChannels; + } + if (_numSSG) { + _ssg = new TownsPC98_OpnSquareSineSource(_timerbase); + _ssg->init(&_ssgTables[0], &_ssgTables[16]); + _ssgPatches = new uint8[256]; + memcpy(_ssgPatches, _drvTables + 244, 256); + _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG]; for (int i = 0; i < _numSSG; i++) { int ii = i * 6; @@ -2428,6 +3162,23 @@ bool TownsPC98_OpnDriver::init() { _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); _ssgChannels[i]->init(); } + + _sfxChannels = new TownsPC98_OpnSfxChannel*[2]; + for (int i = 0; i < 2; i++) { + int ii = (i + 1) * 6; + _sfxChannels[i] = new TownsPC98_OpnSfxChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _sfxChannels[i]->init(); + } + } + + if (_hasPCM) { + _pcm = new TownsPC98_OpnPercussionSource(_timerbase); + _pcm->init(); + + delete _pcmChannel; + _pcmChannel = new TownsPC98_OpnChannelPCM(this, 0, 0, 0, 0, 0, 1); + _pcmChannel->init(); } _mixer->playInputStream(Audio::Mixer::kMusicSoundType, @@ -2439,36 +3190,63 @@ bool TownsPC98_OpnDriver::init() { int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) { memset(buffer, 0, sizeof(int16) * numSamples); + int32 *tmp = new int32[numSamples]; + int32 *tmpStart = tmp; + memset(tmp, 0, sizeof(int32) * numSamples); int32 samplesLeft = numSamples >> 1; + while (samplesLeft) { - if (!_samplesTillCallback) { - callback(); - _samplesTillCallback = _samplesPerCallback; - _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; - if (_samplesTillCallbackRemainder >= _tempo) { - _samplesTillCallback++; - _samplesTillCallbackRemainder -= _tempo; + if (!_samplesTillMusicCallback) { + musicCallback(); + _samplesTillMusicCallback = _samplesPerMusicCallback; + + _samplesTillMusicCallbackRemainder += _samplesPerMusicCallbackRemainder; + if (_samplesTillMusicCallbackRemainder >= _timerbase) { + _samplesTillMusicCallback++; + _samplesTillMusicCallbackRemainder -= _timerbase; } } - int32 render = MIN(samplesLeft, _samplesTillCallback); + if (!_samplesTillSfxCallback) { + sfxCallback(); + _samplesTillSfxCallback = _samplesPerSfxCallback; + + _samplesTillSfxCallbackRemainder += _samplesPerSfxCallbackRemainder; + if (_samplesTillSfxCallbackRemainder >= _timerbase) { + _samplesTillSfxCallback++; + _samplesTillSfxCallbackRemainder -= _timerbase; + } + } + + int32 render = MIN(samplesLeft, MIN(_samplesTillSfxCallback, _samplesTillMusicCallback)); samplesLeft -= render; - _samplesTillCallback -= render; - nextTick(buffer, render); + _samplesTillMusicCallback -= render; + _samplesTillSfxCallback -= render; + + nextTick(tmp, render); + + if (_ssg) + _ssg->nextTick(tmp, render); + if (_pcm) + _pcm->nextTick(tmp, render); for (int i = 0; i < render; ++i) { - buffer[i << 1] <<= 2; - buffer[(i << 1) + 1] <<= 2; + int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767); + buffer[i << 1] = (int16) l; + int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767); + buffer[(i << 1) + 1] = (int16) r; } buffer += (render << 1); + tmp += (render << 1); } + delete [] tmpStart; return numSamples; } -void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { +void TownsPC98_OpnDriver::loadMusicData(uint8 *data, bool loadPaused) { if (!_ready) { warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); return; @@ -2479,12 +3257,11 @@ void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { return; } + reset(); + lock(); - _trackData = data; - reset(); - - uint8 *src_a = data; + uint8 *src_a = _trackPtr = _musicBuffer = data; for (uint8 i = 0; i < 3; i++) { _channels[i]->loadData(data + READ_LE_UINT16(src_a)); @@ -2501,117 +3278,179 @@ void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { src_a += 2; } - if (_hasADPCM) { - //_adpcmChannel->loadData(data + READ_LE_UINT16(src_a)); + if (_hasPCM) { + _pcmChannel->loadData(data + READ_LE_UINT16(src_a)); src_a += 2; } - _ssgFlag = 0; + _regProtectionFlag = false; _patches = src_a + 4; - _cbCounter = 4; - _finishedChannelsFlag = 0; + _finishedChannelsFlag = _finishedSSGFlag = _finishedPCMFlag = 0; + + _musicPlaying = (loadPaused ? false : true); - // AH 0x17 unlock(); - _playing = (loadPaused ? false : true); +} + +void TownsPC98_OpnDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { + if (!_ready) { + warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); + return; + } + + if (!_sfxChannels) { + warning("TownsPC98_OpnDriver: Sound effects not supported by this configuration"); + return; + } + + if (!data) { + warning("TownsPC98_OpnDriver: Invalid sound effects file data"); + return; + } + + lock(); + _sfxData = _sfxBuffer = data; + _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); + _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); + _sfxPlaying = true; + _finishedSfxFlag = 0; + unlock(); } void TownsPC98_OpnDriver::reset() { - for (int i = 0; i < (_numChan); i++) + lock(); + + for (int i = 0; i < _numChan; i++) _channels[i]->reset(); - for (int i = 0; i < (_numSSG); i++) + for (int i = 0; i < _numSSG; i++) _ssgChannels[i]->reset(); - _playing = _fading = false; + if (_ssg) { + for (int i = 0; i < 2; i++) + _sfxChannels[i]->reset(); + + memcpy(_ssgPatches, _drvTables + 276, 256); + _ssg->reset(); + } + + if (_pcmChannel) + _pcmChannel->reset(); + + _musicPlaying = false; + _sfxPlaying = false; + _fading = false; _looping = 0; - _tickCounter = 0; + _musicTickCounter = 0; + _sfxData = 0; + + unlock(); } -void TownsPC98_OpnDriver::fadeOut() { - if (!_playing) +void TownsPC98_OpnDriver::fadeStep() { + if (!_musicPlaying) return; - _fading = true; + lock(); - for (int i = 0; i < 20; i++) { - lock(); - uint32 dTime = _tickCounter + 2; - for (int j = 0; j < _numChan; j++) { - if (_updateChannelsFlag & _channels[j]->_idFlag) - _channels[j]->fadeStep(); - } - for (int j = 0; j < _numSSG; j++) + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->_idFlag) + _channels[j]->fadeStep(); + } + + for (int j = 0; j < _numSSG; j++) { + if (_updateSSGFlag & _ssgChannels[j]->_idFlag) _ssgChannels[j]->fadeStep(); + } - unlock(); - - while (_playing) { - if (_tickCounter >= dTime) - break; + if (!_fading) { + _fading = 19; + if (_hasPCM) { + if (_updatePCMFlag & _pcmChannel->_idFlag) + _pcmChannel->reset(); } + } else { + if (!--_fading) + reset(); } - _fading = false; - - reset(); + unlock(); } -void TownsPC98_OpnDriver::callback() { - if (!_playing || --_cbCounter) - return; +void TownsPC98_OpnDriver::musicCallback() { + lock(); - _cbCounter = 4; - _tickCounter++; + _sfxOffs = 0; - lock(); + if (_musicPlaying) { + _musicTickCounter++; - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->_idFlag) { - _channels[i]->processEvents(); - _channels[i]->processFrequency(); + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } } - } - if (_numSSG) { for (int i = 0; i < _numSSG; i++) { - _ssgChannels[i]->processEvents(); - _ssgChannels[i]->processFrequency(); + if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } } + + if (_hasPCM) + if (_updatePCMFlag & _pcmChannel->_idFlag) + _pcmChannel->processEvents(); } - - _ssgFlag = 0; - unlock(); + _regProtectionFlag = false; - if (_finishedChannelsFlag == _updateChannelsFlag) - reset(); + if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedPCMFlag == _updatePCMFlag) + _musicPlaying = false; + + unlock(); } -void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { - if (!_playing) - return; +void TownsPC98_OpnDriver::sfxCallback() { + lock(); - for (int i = 0; i < _numChan ; i++) { - if (_channels[i]->_updateEnvelopes) { - _channels[i]->_updateEnvelopes = false; - _channels[i]->updateEnv(); + if (_sfxChannels && _sfxPlaying) { + if (_sfxData) + startSoundEffect(); + + _sfxOffs = 3; + _trackPtr = _sfxBuffer; + + for (int i = 0; i < 2; i++) { + if (_updateSfxFlag & _sfxChannels[i]->_idFlag) { + _sfxChannels[i]->processEvents(); + _sfxChannels[i]->processFrequency(); + } } - - for (uint32 ii = 0; ii < bufferSize ; ii++) - _channels[i]->generateOutput(buffer[ii * 2], - buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf); + + _trackPtr = _musicBuffer; } - for (int i = 0; i < _numSSG ; i++) { - if (_ssgChannels[i]->_updateEnvelopes) { - _ssgChannels[i]->_updateEnvelopes = false; - _ssgChannels[i]->updateEnv(); + if (_finishedSfxFlag == _updateSfxFlag) + _sfxPlaying = false; + + unlock(); +} + +void TownsPC98_OpnDriver::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (int i = 0; i < _numChan; i++) { + if (_channels[i]->_updateEnvelopeParameters) { + _channels[i]->_updateEnvelopeParameters = false; + _channels[i]->updateEnv(); } - + for (uint32 ii = 0; ii < bufferSize ; ii++) - _ssgChannels[i]->generateOutput(buffer[ii * 2], - buffer[ii * 2 + 1], &_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf); + _channels[i]->generateOutput(buffer[ii * 2], + buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf); } } @@ -2641,7 +3480,7 @@ void TownsPC98_OpnDriver::generateTables() { delete [] _oprFrq; _oprFrq = new uint32[0x1000]; for (uint32 i = 0; i < 0x1000; i++) - _oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); + _oprFrq[i] = (uint32)(_baserate * (float)(i << 11)); delete [] _oprAttackDecay; _oprAttackDecay = new uint8[152]; @@ -2680,82 +3519,36 @@ void TownsPC98_OpnDriver::generateTables() { delete [] _oprDetune; _oprDetune = new int32[256]; for (int i = 0; i < 128; i++) { - _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); + _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0); _oprDetune[i + 128] = -_oprDetune[i]; } delete [] dtt; } -void TownsPC98_OpnDriver::setTempo(uint8 tempo) { - _tempo = tempo; - _samplesPerCallback = getRate() / _tempo; - _samplesPerCallbackRemainder = getRate() % _tempo; -} - -const uint8 TownsPC98_OpnDriver::_drvTables[] = { - // channel presets - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, - 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, - 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, - 0x00, 0x80, 0x03, 0x04, 0x01, 0x08, - 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, - 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, - - // control event size - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, - 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, - - // fmt level presets - 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, - 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, - 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, - - // carriers - 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, - - // frequencies - 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, - 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, - 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, - 0x00, 0x00, 0x00, 0x00, - - // unused - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, +void TownsPC98_OpnDriver::startSoundEffect() { + for (int i = 0; i < 2; i++) { + if (_sfxOffsets[i]) { + _ssgChannels[i + 1]->protect(); + _sfxChannels[i]->reset(); + _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]); + } + } - // detune - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, - 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, - 0x16, 0x16, 0x16, 0x16, + _sfxData = 0; +} - // pc98 level presets - 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, - 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, - 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90 -}; +void TownsPC98_OpnDriver::setMusicTempo(uint8 tempo) { + float spc = (float)(0x100 - tempo) * 16.0f / _baserate; + _samplesPerMusicCallback = (int32) spc; + _samplesPerMusicCallbackRemainder = (uint32) ((spc - (float)_samplesPerMusicCallback) * 1000000.0f); +} -const uint32 TownsPC98_OpnDriver::_adtStat[] = { - 0x00010001, 0x00010001, 0x00010001, 0x01010001, - 0x00010101, 0x00010101, 0x00010101, 0x01010101, - 0x01010101, 0x01010101, 0x01010102, 0x01010102, - 0x01020102, 0x01020102, 0x01020202, 0x01020202, - 0x02020202, 0x02020202, 0x02020204, 0x02020204, - 0x02040204, 0x02040204, 0x02040404, 0x02040404, - 0x04040404, 0x04040404, 0x04040408, 0x04040408, - 0x04080408, 0x04080408, 0x04080808, 0x04080808, - 0x08080808, 0x08080808, 0x10101010, 0x10101010 -}; +void TownsPC98_OpnDriver::setSfxTempo(uint16 tempo) { + float spc = (float)(0x400 - tempo) / _baserate; + _samplesPerSfxCallback = (int32) spc; + _samplesPerSfxCallbackRemainder = (uint32) ((spc - (float)_samplesPerSfxCallback) * 1000000.0f); +} SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0), @@ -2916,7 +3709,8 @@ void SoundTowns::playSoundEffect(uint8 track) { } playbackBufferSize -= 0x20; - uint32 outputRate = uint32(11025 * semitoneAndSampleRate_to_sampleStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000)); + + uint32 outputRate = uint32(11025 * calculatePhaseStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000)); _currentSFX = Audio::makeLinearInputStream(sfxPlaybackBuffer, playbackBufferSize, outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); @@ -2995,7 +3789,7 @@ void SoundTowns::onTimer(void *data) { music->_parser->onTimer(); } -float SoundTowns::semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, +float SoundTowns::calculatePhaseStep(int8 semiTone, int8 semiToneRootkey, uint32 sampleRate, uint32 outputRate, int32 pitchWheel) { if (semiTone < 0) semiTone = 0; @@ -3050,18 +3844,18 @@ bool SoundPC98::init() { void SoundPC98::playTrack(uint8 track) { if (--track >= 56) track -= 55; - + if (track == _lastTrack && _musicEnabled) return; - haltTrack(); + beginFadeOut(); char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); delete[] _musicTrackData; _musicTrackData = _vm->resource()->fileData(musicfile, 0); if (_musicEnabled) - _driver->loadData(_musicTrackData); + _driver->loadMusicData(_musicTrackData); _lastTrack = track; } @@ -3074,29 +3868,42 @@ void SoundPC98::haltTrack() { } void SoundPC98::beginFadeOut() { - _driver->fadeOut(); + if (!_driver->musicPlaying()) + return; + + for (int i = 0; i < 20; i++) { + _driver->fadeStep(); + _vm->delay(32); + } haltTrack(); } -void SoundPC98::playSoundEffect(uint8) { - /// TODO /// +void SoundPC98::playSoundEffect(uint8 track) { + if (!_sfxTrackData) + return; + + // This has been disabled for now since I don't know + // how to make up the correct track number. It probably + // needs a map. + //_driver->loadSoundEffectData(_sfxTrackData, track); } // KYRA 2 SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) : - Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { + Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { } SoundTownsPC98_v2::~SoundTownsPC98_v2() { delete[] _musicTrackData; + delete[] _sfxTrackData; delete _driver; } bool SoundTownsPC98_v2::init() { - _driver = new TownsPC98_OpnDriver(_mixer, /*_vm->gameFlags().platform == Common::kPlatformPC98 ? - TownsPC98_OpnDriver::OD_TYPE86 :*/ TownsPC98_OpnDriver::OD_TOWNS); + _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like @@ -3110,9 +3917,15 @@ bool SoundTownsPC98_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; + return _driver->init(); } +void SoundTownsPC98_v2::loadSoundFile(Common::String file) { + delete [] _sfxTrackData; + _sfxTrackData = _vm->resource()->fileData(file.c_str(), 0); +} + void SoundTownsPC98_v2::process() { AudioCD.updateCD(); } @@ -3138,9 +3951,9 @@ void SoundTownsPC98_v2::playTrack(uint8 track) { char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); delete[] _musicTrackData; - + _musicTrackData = _vm->resource()->fileData(musicfile, 0); - _driver->loadData(_musicTrackData, true); + _driver->loadMusicData(_musicTrackData, true); if (_musicEnabled == 2 && trackNum != -1) { AudioCD.play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0); @@ -3160,7 +3973,14 @@ void SoundTownsPC98_v2::haltTrack() { } void SoundTownsPC98_v2::beginFadeOut() { - _driver->fadeOut(); + if (!_driver->musicPlaying()) + return; + + for (int i = 0; i < 20; i++) { + _driver->fadeStep(); + _vm->delay(32); + } + haltTrack(); } @@ -3221,7 +4041,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { sfx[i] = cmd; } - uint32 outputRate = uint32(11025 * SoundTowns::semitoneAndSampleRate_to_sampleStep(0x3c, 0x3c, sfxRate, 11025, 0x2000)); + uint32 outputRate = uint32(11025 * SoundTowns::calculatePhaseStep(0x3c, 0x3c, sfxRate, 11025, 0x2000)); _currentSFX = Audio::makeLinearInputStream(sfx, outsize, outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); @@ -3233,16 +4053,126 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { } void SoundTownsPC98_v2::playSoundEffect(uint8 track) { - if (!_useFmSfx) + if (!_useFmSfx || !_sfxTrackData) return; - uint8 *sd = _vm->resource()->fileData("sound.dat", 0); + _driver->loadSoundEffectData(_sfxTrackData, track); +} + +// static resources + +const uint8 TownsPC98_OpnDriver::_drvTables[] = { + // channel presets + 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, + 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, + 0x00, 0x80, 0x03, 0x04, 0x01, 0x08, + 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, + 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, + // control event size + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, + 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, - //TODO + // fmt level presets + 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, + 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, + 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, - delete [] sd; -} + // carriers + 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, + + // frequencies + 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, + 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, + 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, + 0x00, 0x00, 0x00, 0x00, + + // unused + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // detune + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x16, 0x16, 0x16, 0x16, + + // pc98 level presets + 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, + 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, + 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90, + + // ssg frequencies + 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C, + 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09, + 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07, + + // ssg patch data + 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00, + 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + + 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00, + 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00 +}; + +const uint32 TownsPC98_OpnDriver::_adtStat[] = { + 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010101, 0x00010101, 0x00010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010102, 0x01010102, + 0x01020102, 0x01020102, 0x01020202, 0x01020202, + 0x02020202, 0x02020202, 0x02020204, 0x02020204, + 0x02040204, 0x02040204, 0x02040404, 0x02040404, + 0x04040404, 0x04040404, 0x04040408, 0x04040408, + 0x04080408, 0x04080408, 0x04080808, 0x04080808, + 0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; + +const int TownsPC98_OpnDriver::_ssgTables[] = { + 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C, + 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB, + 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB, + 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C, + 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9, + 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB +}; } // end of namespace Kyra diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 5c0e05f23d..9156fa7e9c 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -43,7 +43,7 @@ namespace Kyra { -#define RESFILE_VERSION 31 +#define RESFILE_VERSION 32 bool StaticResource::checkKyraDat() { Common::File kyraDat; diff --git a/engines/kyra/timer_mr.cpp b/engines/kyra/timer_mr.cpp index 37a910ccf2..ea7f64fed1 100644 --- a/engines/kyra/timer_mr.cpp +++ b/engines/kyra/timer_mr.cpp @@ -65,7 +65,7 @@ void KyraEngine_MR::timerRunSceneScript7(int arg) { void KyraEngine_MR::timerFleaDeath(int arg) { debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg); _timer->setCountdown(4, 5400); - saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME"); + saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0); _screen->hideMouse(); _timer->disable(4); runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1); diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp index 3d5265c90f..f9f53b2806 100644 --- a/engines/lure/animseq.cpp +++ b/engines/lure/animseq.cpp @@ -44,13 +44,18 @@ AnimAbortType AnimationSequence::delay(uint32 milliseconds) { while (g_system->getMillis() < delayCtr) { while (events.pollEvent()) { if ((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) { - if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) return ABORT_END_INTRO; - else if (events.event().kbd.keycode == Common::KEYCODE_MAINMENU) return ABORT_NONE; - else return ABORT_NEXT_SCENE; - } else if (events.type() == Common::EVENT_LBUTTONDOWN) + if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) + return ABORT_END_INTRO; + else + return ABORT_NEXT_SCENE; + } else if (events.type() == Common::EVENT_LBUTTONDOWN) { return ABORT_NEXT_SCENE; - else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) + } else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) { return ABORT_END_INTRO; + } else if (events.type() == Common::EVENT_MAINMENU) { + return ABORT_NONE; + } + } uint32 delayAmount = delayCtr - g_system->getMillis(); diff --git a/engines/lure/events.cpp b/engines/lure/events.cpp index 97da8bdb03..e244f69097 100644 --- a/engines/lure/events.cpp +++ b/engines/lure/events.cpp @@ -214,8 +214,7 @@ bool Events::interruptableDelay(uint32 milliseconds) { if (engine.quit()) return true; if (events.pollEvent()) { - if (((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0) && - events.event().kbd.keycode != KEYCODE_MAINMENU) || + if (((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) || (events.type() == Common::EVENT_LBUTTONDOWN)) return true; } diff --git a/engines/made/music.cpp b/engines/made/music.cpp index c3b36d3b8c..0b58a11774 100644 --- a/engines/made/music.cpp +++ b/engines/made/music.cpp @@ -63,6 +63,8 @@ void MusicPlayer::setVolume(int volume) { _masterVolume = volume; + Common::StackLock lock(_mutex); + for (int i = 0; i < 16; ++i) { if (_channel[i]) { _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp index 222954ec3a..290aa5e625 100644 --- a/engines/parallaction/balloons.cpp +++ b/engines/parallaction/balloons.cpp @@ -246,6 +246,8 @@ class BalloonManager_ns : public BalloonManager { static int16 _dialogueBalloonX[5]; + byte _textColors[2]; + struct Balloon { Common::Rect outerBox; Common::Rect innerBox; @@ -266,16 +268,18 @@ public: void freeBalloons(); int setLocationBalloon(char *text, bool endGame); - int setDialogueBalloon(char *text, uint16 winding, byte textColor); - int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); - void setBalloonText(uint id, char *text, byte textColor); + int setDialogueBalloon(char *text, uint16 winding, TextColor textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor); + void setBalloonText(uint id, char *text, TextColor textColor); int hitTestDialogueBalloon(int x, int y); }; int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 }; BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) { - + _textColors[kSelectedColor] = 0; + _textColors[kUnselectedColor] = 3; + _textColors[kNormalColor] = 0; } BalloonManager_ns::~BalloonManager_ns() { @@ -314,7 +318,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor winding = (winding == 0 ? 1 : 0); Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); s.moveTo(r.width()/2 - 5, r.bottom - 1); - _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS); + _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_NS); } _numBalloons++; @@ -323,7 +327,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor } -int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { +int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) { int16 w, h; @@ -336,7 +340,7 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w Balloon *balloon = &_intBalloons[id]; StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -347,7 +351,7 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w return id; } -int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) { +int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) { int16 w, h; @@ -361,7 +365,7 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC Balloon *balloon = &_intBalloons[id]; StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -377,12 +381,12 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC return id; } -void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) { +void BalloonManager_ns::setBalloonText(uint id, char *text, TextColor textColor) { Balloon *balloon = getBalloon(id); balloon->surface->fillRect(balloon->innerBox, 1); StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface); } @@ -398,7 +402,7 @@ int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) { int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS); Balloon *balloon = &_intBalloons[id]; StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, 0, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[kNormalColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -513,8 +517,6 @@ public: StringWriter_BR(Font *font) : WrappedLineFormatter(font) { } void write(const char *text, uint maxWidth, byte color, Graphics::Surface *surf) { - maxWidth = 216; - StringExtent_BR se(_font); se.calc(text, maxWidth); _width = se.width() + 10; @@ -534,6 +536,8 @@ public: class BalloonManager_br : public BalloonManager { + byte _textColors[2]; + struct Balloon { Common::Rect box; Graphics::Surface *surface; @@ -550,7 +554,7 @@ class BalloonManager_br : public BalloonManager { void cacheAnims(); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); - int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); + int createBalloon(int16 w, int16 h, uint16 borderThickness); Balloon *getBalloon(uint id); Graphics::Surface *expandBalloon(Frames *data, int frameNum); @@ -562,9 +566,9 @@ public: void freeBalloons(); int setLocationBalloon(char *text, bool endGame); - int setDialogueBalloon(char *text, uint16 winding, byte textColor); - int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); - void setBalloonText(uint id, char *text, byte textColor); + int setDialogueBalloon(char *text, uint16 winding, TextColor textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor); + void setBalloonText(uint id, char *text, TextColor textColor); int hitTestDialogueBalloon(int x, int y); }; @@ -585,12 +589,12 @@ Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum) Graphics::Surface *surf = new Graphics::Surface; surf->create(rect.width(), rect.height(), 1); - _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR); + _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_BR); return surf; } -int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { +int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) { cacheAnims(); int id = _numBalloons; @@ -613,7 +617,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w balloon->surface = expandBalloon(src, srcFrame); src->getRect(srcFrame, balloon->box); - _writer.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + _writer.write(text, 216, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -626,7 +630,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w return id; } -int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) { +int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) { cacheAnims(); int id = _numBalloons; @@ -637,11 +641,11 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC if (winding == 0) { src = _rightBalloon; - srcFrame = id; + srcFrame = 0; } else if (winding == 1) { src = _leftBalloon; - srcFrame = 0; + srcFrame = id; } assert(src); @@ -649,7 +653,7 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC balloon->surface = expandBalloon(src, srcFrame); src->getRect(srcFrame, balloon->box); - _writer.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + _writer.write(text, 216, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -657,32 +661,51 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC balloon->obj->y = balloon->box.top; balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; - if (id > 0) { - balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height(); - } - _numBalloons++; return id; } -void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { } +void BalloonManager_br::setBalloonText(uint id, char *text, TextColor textColor) { + Balloon *balloon = getBalloon(id); + + StringWriter_BR sw(_vm->_dialogueFont); + sw.write(text, 216, _textColors[textColor], balloon->surface); +} + +int BalloonManager_br::createBalloon(int16 w, int16 h, uint16 borderThickness) { + assert(_numBalloons < 5); + + int id = _numBalloons; + Balloon *balloon = &_intBalloons[id]; + + balloon->surface = new Graphics::Surface; + balloon->surface->create(w, h, 1); + + Common::Rect rect(w, h); + balloon->surface->fillRect(rect, 1); + rect.grow(-borderThickness); + balloon->surface->fillRect(rect, 15); + + _numBalloons++; + + return id; +} int BalloonManager_br::setLocationBalloon(char *text, bool endGame) { -/* - int16 w, h; + StringExtent_BR se(_vm->_dialogueFont); - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + se.calc(text, 240); - int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); + int id = createBalloon(se.width() + 20, se.height() + 30, 2); Balloon *balloon = &_intBalloons[id]; - drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); - // TODO: extract some text to make a name for obj + _writer.write(text, 240, kNormalColor, balloon->surface); + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); balloon->obj->x = 5; balloon->obj->y = 5; -*/ + return 0; } @@ -691,11 +714,9 @@ int BalloonManager_br::hitTestDialogueBalloon(int x, int y) { Common::Point p; for (uint i = 0; i < _numBalloons; i++) { - p.x = x - _intBalloons[i].obj->x; - p.y = y - _intBalloons[i].obj->y; - - if (_intBalloons[i].box.contains(p)) + if (_intBalloons[i].box.contains(x, y)) { return i; + } } return -1; @@ -723,6 +744,10 @@ void BalloonManager_br::cacheAnims() { BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0), _writer(_vm->_dialogueFont) { + + _textColors[kSelectedColor] = 12; + _textColors[kUnselectedColor] = 0; + _textColors[kNormalColor] = 0; } BalloonManager_br::~BalloonManager_br() { diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 0f89ca22d1..7915daa0b8 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -32,6 +32,7 @@ #include "parallaction/input.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -170,7 +171,7 @@ void Parallaction_ns::_c_fade(void *parm) { _gfx->setPalette(pal); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); } return; @@ -305,7 +306,7 @@ void Parallaction_ns::_c_endComment(void *param) { _gfx->setPalette(_gfx->_palette); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); } _input->waitForButtonEvent(kMouseLeftUp); @@ -324,10 +325,10 @@ void Parallaction_ns::_c_frankenstein(void *parm) { } for (uint16 _di = 0; _di < 30; _di++) { - g_system->delayMillis(20); + _vm->_system->delayMillis(20); _gfx->setPalette(pal0); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); _gfx->setPalette(pal1); _gfx->updateScreen(); } @@ -341,7 +342,7 @@ void Parallaction_ns::_c_frankenstein(void *parm) { void Parallaction_ns::_c_finito(void *parm) { - setPartComplete(_char); + _saveLoad->setPartComplete(_char.getBaseName()); cleanInventory(); cleanupGame(); diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 472fe1fd75..0476b01454 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -243,19 +243,9 @@ public: return "Nippon Safes Inc. (C) Dynabyte"; } - virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - virtual SaveStateList listSaves(const char *target) const; }; -bool ParallactionMetaEngine::hasFeature(MetaEngineFeature f) const { - return - (f == kSupportsRTL) || - (f == kSupportsListSaves) || - (f == kSupportsDirectLoad) || - (f == kSupportsDeleteSave); -} - bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Parallaction::PARALLACTIONGameDescription *gd = (const Parallaction::PARALLACTIONGameDescription *)desc; bool res = true; @@ -275,34 +265,6 @@ bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, cons return res; } -SaveStateList ParallactionMetaEngine::listSaves(const char *target) const { - Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); - Common::StringList filenames; - char saveDesc[200]; - Common::String pattern = target; - pattern += ".0??"; - - filenames = saveFileMan->listSavefiles(pattern.c_str()); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) - - SaveStateList saveList; - for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { - // Obtain the last 2 digits of the filename, since they correspond to the save slot - int slotNum = atoi(file->c_str() + file->size() - 2); - - if (slotNum >= 0 && slotNum <= 99) { - Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); - if (in) { - in->readLine(saveDesc, 199); - saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); - delete in; - } - } - } - - return saveList; -} - #if PLUGIN_ENABLED_DYNAMIC(PARALLACTION) REGISTER_PLUGIN_DYNAMIC(PARALLACTION, PLUGIN_TYPE_ENGINE, ParallactionMetaEngine); #else diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index c94db751e7..a2de3cbbf3 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -173,7 +173,7 @@ bool DialogueManager::displayAnswer(uint16 i) { // display suitable answers if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) { - int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3); + int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, BalloonManager::kUnselectedColor); assert(id >= 0); _visAnswers[id] = i; @@ -203,7 +203,7 @@ bool DialogueManager::displayAnswers() { if (_numVisAnswers == 1) { int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); - _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); + _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, BalloonManager::kNormalColor); } else if (_numVisAnswers > 1) { int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); @@ -218,7 +218,7 @@ bool DialogueManager::displayAnswers() { bool DialogueManager::displayQuestion() { if (!scumm_stricmp(_q->_text, "NULL")) return false; - _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, 0); + _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, BalloonManager::kNormalColor); int id = _vm->_gfx->setItem(_questioner, _ballonPos._questionChar.x, _ballonPos._questionChar.y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); @@ -256,7 +256,7 @@ int16 DialogueManager::askPassword() { } if (_passwordChanged) { - _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, BalloonManager::kNormalColor); _passwordChanged = false; } @@ -286,14 +286,11 @@ int16 DialogueManager::selectAnswerN() { if (_selection != _oldSelection) { if (_oldSelection != -1) { - _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3); + _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, BalloonManager::kUnselectedColor); } - if (_vm->quit()) - return -1; - if (_selection != -1) { - _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0); + _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, BalloonManager::kSelectedColor); _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF); } } @@ -365,6 +362,7 @@ void DialogueManager::nextQuestion() { } } + void DialogueManager::run() { // cache event data diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 2923f239d4..45a2b9d2ef 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -29,10 +29,12 @@ #define PATH_LEN 200 #include "common/fs.h" - #include "common/file.h" + #include "graphics/surface.h" +#include "parallaction/graphics.h" + namespace Parallaction { class Table; diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index fe7b1b2903..bcc4a5b532 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -546,27 +546,4 @@ ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm ProgramExec_br::~ProgramExec_br() { } -#if 0 -void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) { - -} - -void Parallaction_br::jobPauseSfx(void *parm, Job *job) { - -} - - -void Parallaction_br::jobStopFollower(void *parm, Job *job) { - -} - - -void Parallaction_br::jobScroll(void *parm, Job *job) { - -} -#endif - - - - } // namespace Parallaction diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 30790a346f..7262fc0085 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -247,32 +247,6 @@ DECLARE_COMMAND_OPCODE(close) { _vm->updateDoor(_ctxt.cmd->u._zone, true); } -void Parallaction::showZone(ZonePtr z, bool visible) { - if (!z) { - return; - } - - if (visible) { - z->_flags &= ~kFlagsRemove; - z->_flags |= kFlagsActive; - } else { - z->_flags |= kFlagsRemove; - } - - if ((z->_type & 0xFFFF) == kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, visible); - - GetData *data = z->u.get; - if (data->hasMask && _gfx->_backgroundInfo->hasMask) { - if (visible) { - _gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h); - } else { - _gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h); - } - } - } -} - DECLARE_COMMAND_OPCODE(on) { _vm->showZone(_ctxt.cmd->u._zone, true); } @@ -304,8 +278,7 @@ DECLARE_COMMAND_OPCODE(drop){ DECLARE_COMMAND_OPCODE(quit) { - _vm->_quit = true; - _vm->quitGame(); + _engineFlags |= kEngineQuit; } @@ -319,66 +292,6 @@ DECLARE_COMMAND_OPCODE(stop) { } -void Parallaction_ns::drawAnimations() { - debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); - - uint16 layer = 0; - - for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { - - AnimationPtr anim = *it; - GfxObj *obj = anim->gfxobj; - - // Validation is performed here, so that every animation is affected, instead that only the ones - // who *own* a script. In fact, some scripts can change values in other animations. - // The right way to do this would be to enforce validation when any variable is modified from - // a script. - anim->validateScriptVars(); - - if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) { - - if (anim->_flags & kFlagsNoMasked) - layer = LAYER_FOREGROUND; - else { - if (getGameType() == GType_Nippon) { - // Layer in NS depends on where the animation is on the screen, for each animation. - layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height()); - } else { - // Layer in BRA is calculated from Z value. For characters it is the same as NS, - // but other animations can have Z set from scripts independently from their - // position on the screen. - layer = _gfx->_backgroundInfo->getLayer(anim->getZ()); - } - } - - if (obj) { - _gfx->showGfxObj(obj, true); - obj->frame = anim->getF(); - obj->x = anim->getX(); - obj->y = anim->getY(); - obj->z = anim->getZ(); - obj->layer = layer; - } - } - - if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) { - anim->_flags &= ~kFlagsRemove; - } - - if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) { - anim->_flags &= ~kFlagsActive; - anim->_flags |= kFlagsRemove; - if (obj) { - _gfx->showGfxObj(obj, false); - } - } - } - - debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); - - return; -} - void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) { debugC(9, kDebugExec, "runScript(Animation = %s)", a->_name); @@ -443,15 +356,11 @@ void CommandExec::runList(CommandList::iterator first, CommandList::iterator las _ctxt.suspend = false; for ( ; first != last; first++) { - - if (_vm->quit()) + if (_engineFlags & kEngineQuit) break; CommandPtr cmd = *first; - if (_vm->quit()) - break; - if (cmd->_flagsOn & kFlagsGlobal) { useFlags = _globalFlags | kFlagsGlobal; useLocalFlags = false; @@ -537,239 +446,6 @@ CommandExec_ns::~CommandExec_ns() { } -// -// ZONE TYPE: EXAMINE -// - -void Parallaction::enterCommentMode(ZonePtr z) { - if (!z) { - return; - } - - _commentZone = z; - - ExamineData *data = _commentZone->u.examine; - - if (!data->_description) { - return; - } - - // TODO: move this balloons stuff into DialogueManager and BalloonManager - if (getGameType() == GType_Nippon) { - int id; - if (data->_filename) { - if (data->_cnv == 0) { - data->_cnv = _disk->loadStatic(data->_filename); - } - - _gfx->setHalfbriteMode(true); - _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); - Common::Rect r; - data->_cnv->getRect(0, r); - id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); - _gfx->setItemFrame(id, 0); - id = _gfx->setItem(_char._head, 100, 152); - _gfx->setItemFrame(id, 0); - } else { - _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); - id = _gfx->setItem(_char._talk, 190, 80); - _gfx->setItemFrame(id, 0); - } - } else - if (getGameType() == GType_BRA) { - _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, 0); - int id = _gfx->setItem(_char._talk, 10, 80); - _gfx->setItemFrame(id, 0); - } - - _input->_inputMode = Input::kInputModeComment; -} - -void Parallaction::exitCommentMode() { - _input->_inputMode = Input::kInputModeGame; - - hideDialogueStuff(); - _gfx->setHalfbriteMode(false); - - _cmdExec->run(_commentZone->_commands, _commentZone); - _commentZone = nullZonePtr; -} - -void Parallaction::runCommentFrame() { - if (_input->_inputMode != Input::kInputModeComment) { - return; - } - - if (_input->getLastButtonEvent() == kMouseLeftUp) { - exitCommentMode(); - } -} - - -void Parallaction::runZone(ZonePtr z) { - debugC(3, kDebugExec, "runZone (%s)", z->_name); - - uint16 subtype = z->_type & 0xFFFF; - - debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); - switch(subtype) { - - case kZoneExamine: - enterCommentMode(z); - return; - - case kZoneGet: - pickupItem(z); - break; - - case kZoneDoor: - if (z->_flags & kFlagsLocked) break; - updateDoor(z, !(z->_flags & kFlagsClosed)); - break; - - case kZoneHear: - _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping); - break; - - case kZoneSpeak: - enterDialogueMode(z); - return; - } - - debugC(3, kDebugExec, "runZone completed"); - - _cmdExec->run(z->_commands, z); - - return; -} - -// -// ZONE TYPE: DOOR -// -void Parallaction::updateDoor(ZonePtr z, bool close) { - z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed); - - if (z->u.door->gfxobj) { - uint frame = (close ? 0 : 1); -// z->u.door->gfxobj->setFrame(frame); - z->u.door->gfxobj->frame = frame; - } - - return; -} - - - -// -// ZONE TYPE: GET -// - -bool Parallaction::pickupItem(ZonePtr z) { - if (z->_flags & kFlagsFixed) { - return false; - } - - int slot = addInventoryItem(z->u.get->_icon); - if (slot != -1) { - showZone(z, false); - } - - return (slot != -1); -} - - - -ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { -// printf("hitZone(%i, %i, %i)", type, x, y); - - uint16 _di = y; - uint16 _si = x; - - for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) { -// printf("Zone name: %s", z->_name); - - ZonePtr z = *it; - - if (z->_flags & kFlagsRemove) continue; - - Common::Rect r; - z->getBox(r); - r.right++; // adjust border because Common::Rect doesn't include bottom-right edge - r.bottom++; - - r.grow(-1); // allows some tolerance for mouse click - - if (!r.contains(_si, _di)) { - - // out of Zone, so look for special values - if ((z->getX() == -2) || (z->getX() == -3)) { - - // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs - // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, - // but we need to check it separately here. The same workaround is applied in freeZones. - if ((((z->_type & 0xFFFF) == kZoneMerge) && (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) || ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1)))) || - (((z->_type & 0xFFFF) == kZoneGet) && ((_si == z->u.get->_icon) || (_di == z->u.get->_icon)))) { - - // special Zone - if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) - return z; - if (z->_type == type) - return z; - if ((z->_type & 0xFFFF0000) == type) - return z; - - } - } - - if (z->getX() != -1) - continue; - if (_si < _char._ani->getFrameX()) - continue; - if (_si > (_char._ani->getFrameX() + _char._ani->width())) - continue; - if (_di < _char._ani->getFrameY()) - continue; - if (_di > (_char._ani->getFrameY() + _char._ani->height())) - continue; - - } - - // normal Zone - if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) - return z; - if (z->_type == type) - return z; - if ((z->_type & 0xFFFF0000) == type) - return z; - - } - - - int16 _a, _b, _c, _d, _e, _f; - for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) { - - AnimationPtr a = *ait; - - _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation - _e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1; // _e: horizontal range - _f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1; // _f: vertical range - - _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character) - _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object - _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type - - if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { - - return a; - - } - - } - - return nullZonePtr; -} - - void CommandExec_ns::init() { Common::Array<const Opcode*> *table = 0; diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 1c373dda44..8eb9753edd 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -32,7 +32,7 @@ namespace Parallaction { -GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3) { +GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3), scale(100) { if (name) { _name = strdup(name); } else { @@ -180,9 +180,9 @@ void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) { data = obj->getData(obj->frame); if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { - blt(rect, data, &surf, obj->layer, obj->transparentKey); + blt(rect, data, &surf, obj->layer, obj->scale, obj->transparentKey); } else { - unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey); + unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->scale, obj->transparentKey); } } @@ -233,7 +233,7 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf blt(r, _unpackedBitmap, surf, z, transparentColor); } #endif -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { byte *d = _unpackedBitmap; uint pixelsLeftInLine = r.width(); @@ -259,11 +259,154 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf d += repeat; } - blt(r, _unpackedBitmap, surf, z, transparentColor); + blt(r, _unpackedBitmap, surf, z, scale, transparentColor); } -void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { +void Gfx::bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { + if (scale == 100) { + // use optimized path + bltMaskNoScale(r, data, surf, z, transparentColor); + return; + } + + Common::Rect q(r); + Common::Rect clipper(surf->w, surf->h); + q.clip(clipper); + if (!q.isValidRect()) return; + + uint inc = r.width() * (100 - scale); + uint thr = r.width() * 100; + uint xAccum = 0, yAccum = 0; + + Common::Point dp; + dp.x = q.left + (r.width() * (100 - scale)) / 200; + dp.y = q.top + (r.height() * (100 - scale)) / 100; + q.translate(-r.left, -r.top); + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint line = 0, col = 0; + + for (uint16 i = 0; i < q.height(); i++) { + yAccum += inc; + + if (yAccum >= thr) { + yAccum -= thr; + s += r.width(); + continue; + } + + xAccum = 0; + byte *d2 = d; + col = 0; + + for (uint16 j = 0; j < q.width(); j++) { + xAccum += inc; + + if (xAccum >= thr) { + xAccum -= thr; + s++; + continue; + } + + if (*s != transparentColor) { + byte v = _backgroundInfo->mask.getValue(dp.x + col, dp.y + line); + if (z >= v) *d2 = *s; + } + + s++; + d2++; + col++; + } + + s += r.width() - q.width(); + d += surf->w; + line++; + } + +} + +void Gfx::bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { + if (!_backgroundInfo->mask.data || (z == LAYER_FOREGROUND)) { + // use optimized path + bltNoMaskNoScale(r, data, surf, transparentColor); + return; + } + + Common::Point dp; + Common::Rect q(r); + + Common::Rect clipper(surf->w, surf->h); + + q.clip(clipper); + if (!q.isValidRect()) return; + + dp.x = q.left; + dp.y = q.top; + + q.translate(-r.left, -r.top); + + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = surf->w - q.width(); + + for (uint16 i = 0; i < q.height(); i++) { + + for (uint16 j = 0; j < q.width(); j++) { + if (*s != transparentColor) { + byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); + if (z >= v) *d = *s; + } + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + +} + +void Gfx::bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor) { + Common::Point dp; + Common::Rect q(r); + + Common::Rect clipper(surf->w, surf->h); + + q.clip(clipper); + if (!q.isValidRect()) return; + + dp.x = q.left; + dp.y = q.top; + + q.translate(-r.left, -r.top); + + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = surf->w - q.width(); + + for (uint16 i = q.top; i < q.bottom; i++) { + for (uint16 j = q.left; j < q.right; j++) { + if (*s != transparentColor) + *d = *s; + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } +} + + +void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { Common::Point dp; Common::Rect q(r); @@ -308,40 +451,7 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 } } else { - if (_backgroundInfo->mask.data && (z < LAYER_FOREGROUND)) { - - for (uint16 i = 0; i < q.height(); i++) { - - for (uint16 j = 0; j < q.width(); j++) { - if (*s != transparentColor) { - byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); - if (z >= v) *d = *s; - } - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } else { - - for (uint16 i = q.top; i < q.bottom; i++) { - for (uint16 j = q.left; j < q.right; j++) { - if (*s != transparentColor) - *d = *s; - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } + bltMaskScale(r, data, surf, z, scale, transparentColor); } } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 1c2cb58b5b..2bd3935f01 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -34,8 +34,9 @@ namespace Parallaction { // this is the size of the receiving buffer for unpacked frames, -// since BRA uses some insanely big animations. -#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401 +// since BRA uses some insanely big animations (the largest is +// part0/ani/dino.ani). +#define MAXIMUM_UNPACKED_BITMAP_SIZE 641*401 void Gfx::registerVar(const Common::String &name, int32 initialValue) { @@ -251,7 +252,7 @@ void Gfx::setPalette(Palette pal) { byte sysPal[256*4]; uint n = pal.fillRGBA(sysPal); - g_system->setPalette(sysPal, 0, n); + _vm->_system->setPalette(sysPal, 0, n); } void Gfx::setBlackPalette() { @@ -327,7 +328,7 @@ void Gfx::drawInventory() { _vm->_inventoryRenderer->getRect(r); byte *data = _vm->_inventoryRenderer->getData(); - g_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); + _vm->_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); } void Gfx::drawItems() { @@ -335,11 +336,11 @@ void Gfx::drawItems() { return; } - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); for (uint i = 0; i < _numItems; i++) { drawGfxObject(_items[i].data, *surf, false); } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } void Gfx::drawBalloons() { @@ -347,15 +348,15 @@ void Gfx::drawBalloons() { return; } - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); for (uint i = 0; i < _balloons.size(); i++) { drawGfxObject(_balloons[i], *surf, false); } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } void Gfx::clearScreen() { - g_system->clearScreen(); + _vm->_system->clearScreen(); } void Gfx::beginFrame() { @@ -377,7 +378,7 @@ void Gfx::beginFrame() { *data++ = _backgroundInfo->mask.getValue(x, y); } } -#if 1 +#if 0 Common::DumpFile dump; dump.open("maskdump.bin"); dump.write(_bitmapMask.pixels, _bitmapMask.w * _bitmapMask.h); @@ -437,11 +438,11 @@ void Gfx::updateScreen() { backgroundPitch = _bitmapMask.pitch; break; } - g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); + _vm->_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); } if (_varDrawPathZones == 1) { - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); ZoneList::iterator b = _vm->_location._zones.begin(); ZoneList::iterator e = _vm->_location._zones.end(); for (; b != e; b++) { @@ -450,13 +451,13 @@ void Gfx::updateScreen() { surf->frameRect(Common::Rect(z->getX(), z->getY(), z->getX() + z->width(), z->getY() + z->height()), 2); } } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } _varRenderMode = _varAnimRenderMode; // TODO: transform objects coordinates to be drawn with scrolling - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); drawGfxObjects(*surf); if (_halfbrite) { @@ -480,7 +481,7 @@ void Gfx::updateScreen() { } } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); _varRenderMode = _varMiscRenderMode; @@ -489,7 +490,7 @@ void Gfx::updateScreen() { drawBalloons(); drawLabels(); - g_system->updateScreen(); + _vm->_system->updateScreen(); return; } @@ -506,7 +507,7 @@ void Gfx::patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask) r.moveTo(x, y); uint16 z = (mask) ? _backgroundInfo->getLayer(y) : LAYER_FOREGROUND; - blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 0); + blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 100, 0); } void Gfx::fillBackground(const Common::Rect& r, byte color) { @@ -600,30 +601,41 @@ void Gfx::updateFloatingLabel() { return; } - int16 _si, _di; - - Common::Point cursor; - _vm->_input->getCursorPos(cursor); + struct FloatingLabelTraits { + Common::Point _offsetWithItem; + Common::Point _offsetWithoutItem; + int _minX; + int _minY; + int _maxX; + int _maxY; + } *traits; Common::Rect r; _labels[_floatingLabel]->getRect(0, r); - if (_vm->_input->_activeItem._id != 0) { - _si = cursor.x + 16 - r.width()/2; - _di = cursor.y + 34; + if (_vm->getGameType() == GType_Nippon) { + FloatingLabelTraits traits_NS = { + Common::Point(16 - r.width()/2, 34), + Common::Point(8 - r.width()/2, 21), + 0, 0, _vm->_screenWidth - r.width(), 190 + }; + traits = &traits_NS; } else { - _si = cursor.x + 8 - r.width()/2; - _di = cursor.y + 21; + // FIXME: _maxY for BRA is not constant (390), but depends on _vm->_subtitleY + FloatingLabelTraits traits_BR = { + Common::Point(34 - r.width()/2, 70), + Common::Point(16 - r.width()/2, 37), + 0, 0, _vm->_screenWidth - r.width(), 390 + }; + traits = &traits_BR; } - if (_si < 0) _si = 0; - if (_di > 190) _di = 190; - - if (r.width() + _si > _vm->_screenWidth) - _si = _vm->_screenWidth - r.width(); + Common::Point cursor; + _vm->_input->getCursorPos(cursor); + Common::Point offset = (_vm->_input->_activeItem._id) ? traits->_offsetWithItem : traits->_offsetWithoutItem; - _labels[_floatingLabel]->x = _si; - _labels[_floatingLabel]->y = _di; + _labels[_floatingLabel]->x = CLIP(cursor.x + offset.x, traits->_minX, traits->_maxX); + _labels[_floatingLabel]->y = CLIP(cursor.y + offset.y, traits->_minY, traits->_maxY); } @@ -703,13 +715,13 @@ void Gfx::drawLabels() { updateFloatingLabel(); - Graphics::Surface* surf = g_system->lockScreen(); + Graphics::Surface* surf = _vm->_system->lockScreen(); for (uint i = 0; i < _labels.size(); i++) { drawGfxObject(_labels[i], *surf, false); } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } @@ -737,10 +749,10 @@ void Gfx::grabBackground(const Common::Rect& r, Graphics::Surface &dst) { Gfx::Gfx(Parallaction* vm) : _vm(vm), _disk(vm->_disk) { - g_system->beginGFXTransaction(); - g_system->initSize(_vm->_screenWidth, _vm->_screenHeight); + _vm->_system->beginGFXTransaction(); + _vm->_system->initSize(_vm->_screenWidth, _vm->_screenHeight); _vm->initCommonGFX(_vm->getGameType() == GType_BRA); - g_system->endGFXTransaction(); + _vm->_system->endGFXTransaction(); setPalette(_palette); diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 471f71dfa8..ac9f096d7e 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -313,6 +313,7 @@ struct Cnv : public Frames { uint16 _height; // byte** field_8; // unused byte* _data; + bool _freeData; public: Cnv() { @@ -320,12 +321,14 @@ public: _data = NULL; } - Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data) : _count(numFrames), _width(width), _height(height), _data(data) { + Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data, bool freeData = false) + : _count(numFrames), _width(width), _height(height), _data(data), _freeData(freeData) { } ~Cnv() { - free(_data); + if (_freeData) + free(_data); } byte* getFramePtr(uint16 index) { @@ -410,6 +413,7 @@ public: uint frame; uint layer; uint transparentKey; + uint scale; GfxObj(uint type, Frames *frames, const char *name = NULL); virtual ~GfxObj(); @@ -495,13 +499,19 @@ enum { class BalloonManager { public: + enum TextColor { + kSelectedColor = 0, + kUnselectedColor = 1, + kNormalColor = 2 + }; + virtual ~BalloonManager() { } virtual void freeBalloons() = 0; virtual int setLocationBalloon(char *text, bool endGame) = 0; - virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0; - virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0; - virtual void setBalloonText(uint id, char *text, byte textColor) = 0; + virtual int setDialogueBalloon(char *text, uint16 winding, TextColor textColor) = 0; + virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) = 0; + virtual void setBalloonText(uint id, char *text, TextColor textColor) = 0; virtual int hitTestDialogueBalloon(int x, int y) = 0; }; @@ -640,8 +650,12 @@ public: void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene); - void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); - void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor); + void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + + void bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + void bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); + void bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor); }; diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 4343a982bf..4c98cc4634 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -28,6 +28,7 @@ #include "parallaction/gui.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" namespace Parallaction { @@ -40,11 +41,11 @@ protected: Palette blackPal; Palette pal; - Parallaction_br *_vm; + Parallaction *_vm; int _fadeSteps; public: - SplashInputState_BR(Parallaction_br *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { } virtual MenuInputState* run() { @@ -52,8 +53,6 @@ public: pal.fadeTo(blackPal, 1); _vm->_gfx->setPalette(pal); _fadeSteps--; - // TODO: properly implement timers to avoid delay calls - _vm->_system->delayMillis(20); return this; } @@ -75,7 +74,7 @@ public: _vm->showSlide(_slideName.c_str(), CENTER_LABEL_HORIZONTAL, CENTER_LABEL_VERTICAL); _vm->_input->setMouseState(MOUSE_DISABLED); - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); _fadeSteps = -1; } }; @@ -152,6 +151,8 @@ class MainMenuInputState_BR : public MenuInputState { static const char *_menuStrings[NUM_MENULINES]; static const MenuOptions _options[NUM_MENULINES]; + static const char *_firstLocation[]; + int _availItems; int _selection; @@ -166,9 +167,8 @@ class MainMenuInputState_BR : public MenuInputState { void performChoice(int selectedItem) { switch (selectedItem) { - case kMenuQuit: { - _vm->quitGame(); - } + case kMenuQuit: + _engineFlags |= kEngineQuit; break; case kMenuLoadGame: @@ -176,7 +176,7 @@ class MainMenuInputState_BR : public MenuInputState { break; default: - _vm->startPart(selectedItem); + _vm->scheduleLocationSwitch(_firstLocation[selectedItem]); } } @@ -221,9 +221,11 @@ public: } _vm->showSlide("tbra", x, y); - // TODO: load progress from savefile - int progress = 3; - _availItems = 4 + progress; + _availItems = 4; + + bool complete[3]; + _vm->_saveLoad->getGamePartProgress(complete, 3); + for (int i = 0; i < 3 && complete[i]; i++, _availItems++) ; // TODO: keep track of and destroy menu item frames/surfaces int i; @@ -233,12 +235,20 @@ public: _vm->_gfx->setItemFrame(id, 0); } _selection = -1; - _vm->setArrowCursor(); + _vm->_input->setArrowCursor(); _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); } }; +const char *MainMenuInputState_BR::_firstLocation[] = { + "intro.0", + "museo.1", + "start.2", + "bolscoi.3", + "treno.4" +}; + const char *MainMenuInputState_BR::_menuStrings[NUM_MENULINES] = { "SEE INTRO", "NEW GAME", @@ -265,29 +275,24 @@ const MainMenuInputState_BR::MenuOptions MainMenuInputState_BR::_options[NUM_MEN -void Parallaction_br::startGui() { +void Parallaction_br::startGui(bool showSplash) { _menuHelper = new MenuInputHelper; - new SplashInputState0_BR(this, _menuHelper); - new SplashInputState1_BR(this, _menuHelper); - new MainMenuInputState_BR(this, _menuHelper); - _menuHelper->setState("intro0"); - _input->_inputMode = Input::kInputModeMenu; - - do { - _input->readInput(); - if (!_menuHelper->run()) break; - _gfx->beginFrame(); - _gfx->updateScreen(); - } while (true); + new MainMenuInputState_BR(this, _menuHelper); - delete _menuHelper; - _menuHelper = 0; + if (showSplash) { + new SplashInputState0_BR(this, _menuHelper); + new SplashInputState1_BR(this, _menuHelper); + _menuHelper->setState("intro0"); + } else { + _menuHelper->setState("mainmenu"); + } - _input->_inputMode = Input::kInputModeGame; + _input->_inputMode = Input::kInputModeMenu; } + } // namespace Parallaction diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index e6f86a1a0a..d172c30103 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -23,13 +23,13 @@ * */ -#include "common/config-manager.h" #include "common/system.h" #include "common/hashmap.h" #include "parallaction/gui.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -42,14 +42,14 @@ protected: Common::String _nextState; uint32 _startTime; - Parallaction_ns *_vm; + Parallaction *_vm; public: - SplashInputState_NS(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { } virtual MenuInputState* run() { - uint32 curTime = g_system->getMillis(); + uint32 curTime = _vm->_system->getMillis(); if (curTime - _startTime > _timeOut) { _vm->freeBackground(); return _helper->getState(_nextState); @@ -60,14 +60,14 @@ public: virtual void enter() { _vm->_input->setMouseState(MOUSE_DISABLED); _vm->showSlide(_slideName.c_str()); - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); } }; class SplashInputState0_NS : public SplashInputState_NS { public: - SplashInputState0_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) { + SplashInputState0_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) { _slideName = "intro"; _timeOut = 2000; _nextState = "intro1"; @@ -77,7 +77,7 @@ public: class SplashInputState1_NS : public SplashInputState_NS { public: - SplashInputState1_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) { + SplashInputState1_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) { _slideName = "minintro"; _timeOut = 2000; _nextState = "chooselanguage"; @@ -112,14 +112,12 @@ class ChooseLanguageInputState_NS : public MenuInputState { static const Common::Rect _amigaLanguageSelectBlocks[4]; const Common::Rect *_blocks; - Parallaction_ns *_vm; + Parallaction *_vm; public: - ChooseLanguageInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { + ChooseLanguageInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { _allowChoice = false; - - if (ConfMan.getInt("save_slot") < 0 || ConfMan.getInt("save_slot") > 99) - _nextState = "selectgame"; + _nextState = "selectgame"; if (_vm->getPlatform() == Common::kPlatformAmiga) { if (!(_vm->getFeatures() & GF_LANG_MULT)) { @@ -181,7 +179,7 @@ public: uint id = _vm->_gfx->createLabel(_vm->_introFont, "SELECT LANGUAGE", 1); _vm->_gfx->showLabel(id, 60, 30); - _vm->setArrowCursor(); + _vm->_input->setArrowCursor(); } }; @@ -206,13 +204,13 @@ class SelectGameInputState_NS : public MenuInputState { uint _labels[2]; - Parallaction_ns *_vm; + Parallaction *_vm; static const char *newGameMsg[4]; static const char *loadGameMsg[4]; public: - SelectGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { + SelectGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { _choice = 0; _oldChoice = -1; @@ -274,10 +272,10 @@ const char *SelectGameInputState_NS::loadGameMsg[4] = { class LoadGameInputState_NS : public MenuInputState { bool _result; - Parallaction_ns *_vm; + Parallaction *_vm; public: - LoadGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } + LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } virtual MenuInputState* run() { if (!_result) { @@ -287,19 +285,19 @@ public: } virtual void enter() { - _result = _vm->loadGame(); + _result = _vm->_saveLoad->loadGame(); } }; class NewGameInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; static const char *introMsg3[4]; public: - NewGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { + NewGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -347,14 +345,15 @@ const char *NewGameInputState_NS::introMsg3[4] = { class StartDemoInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; public: - StartDemoInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { + StartDemoInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { } virtual MenuInputState* run() { _vm->scheduleLocationSwitch("fognedemo.dough"); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); return 0; } @@ -374,7 +373,7 @@ class SelectCharacterInputState_NS : public MenuInputState { static const Common::Rect codeSelectBlocks[9]; static const Common::Rect codeTrueBlocks[9]; - Parallaction_ns *_vm; + Parallaction *_vm; int guiGetSelectedBlock(const Common::Point &p) { @@ -391,7 +390,7 @@ class SelectCharacterInputState_NS : public MenuInputState { _vm->_gfx->invertBackground(codeTrueBlocks[selection]); _vm->_gfx->updateScreen(); _vm->beep(); - g_system->delayMillis(100); + _vm->_system->delayMillis(100); _vm->_gfx->invertBackground(codeTrueBlocks[selection]); _vm->_gfx->updateScreen(); } @@ -427,7 +426,7 @@ class SelectCharacterInputState_NS : public MenuInputState { public: - SelectCharacterInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { + SelectCharacterInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { _keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys; _block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); } @@ -446,7 +445,7 @@ public: } void delay() { - if (g_system->getMillis() - _startTime < 2000) { + if (_vm->_system->getMillis() - _startTime < 2000) { return; } cleanup(); @@ -488,7 +487,7 @@ public: _vm->_gfx->patchBackground(_emptySlots, SLOT_X, SLOT_Y, false); _vm->_gfx->hideLabel(_labels[0]); _vm->_gfx->showLabel(_labels[1], 60, 30); - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); _state = DELAY; } @@ -511,7 +510,6 @@ public: error("If you read this, either your CPU or transivity is broken (we believe the former)."); } - _vm->_inTestResult = false; _vm->cleanupGame(); _vm->scheduleLocationSwitch(_charStartLocation[character]); } @@ -558,7 +556,7 @@ public: cleanup(); - _vm->setArrowCursor(); + _vm->_input->setArrowCursor(); _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); _state = CHOICE; } @@ -623,7 +621,7 @@ const Common::Rect SelectCharacterInputState_NS::codeTrueBlocks[9] = { class ShowCreditsInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; int _current; uint32 _startTime; @@ -635,7 +633,7 @@ class ShowCreditsInputState_NS : public MenuInputState { static const Credit _credits[6]; public: - ShowCreditsInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { + ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { } void drawCurrentLabel() { @@ -649,14 +647,14 @@ public: virtual MenuInputState* run() { if (_current == -1) { - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); _current = 0; drawCurrentLabel(); return this; } int event = _vm->_input->getLastButtonEvent(); - uint32 curTime = g_system->getMillis(); + uint32 curTime = _vm->_system->getMillis(); if ((event == kMouseLeftUp) || (curTime - _startTime > 5500)) { _current++; _startTime = curTime; @@ -688,11 +686,11 @@ const ShowCreditsInputState_NS::Credit ShowCreditsInputState_NS::_credits[6] = { }; class EndIntroInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; bool _isDemo; public: - EndIntroInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { + EndIntroInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { _isDemo = (_vm->getFeatures() & GF_DEMO) != 0; } @@ -704,7 +702,7 @@ public: } if (_isDemo) { - _vm->quitGame(); + _engineFlags |= kEngineQuit; return 0; } @@ -725,7 +723,7 @@ public: class EndPartInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; bool _allPartsComplete; // part completion messages @@ -741,7 +739,7 @@ class EndPartInputState_NS : public MenuInputState { public: - EndPartInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { + EndPartInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -761,20 +759,23 @@ public: } virtual void enter() { - _allPartsComplete = _vm->allPartsComplete(); + bool completed[3]; + _vm->_saveLoad->getGamePartProgress(completed, 3); + _allPartsComplete = (completed[0] && completed[1] && completed[2]); _vm->_input->setMouseState(MOUSE_DISABLED); + uint16 language = _vm->getInternLanguage(); uint id[4]; if (_allPartsComplete) { - id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[_language], 1); - id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[_language], 1); - id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[_language], 1); - id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[_language], 1); + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[language], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[language], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[language], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[language], 1); } else { - id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[_language], 1); - id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[_language], 1); - id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[_language], 1); - id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[_language], 1); + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[language], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[language], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[language], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[language], 1); } _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 19747c007e..98198b88f7 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -31,6 +31,58 @@ namespace Parallaction { +#define MOUSEARROW_WIDTH_NS 16 +#define MOUSEARROW_HEIGHT_NS 16 + +#define MOUSECOMBO_WIDTH_NS 32 // sizes for cursor + selected inventory item +#define MOUSECOMBO_HEIGHT_NS 32 + +struct MouseComboProperties { + int _xOffset; + int _yOffset; + int _width; + int _height; +}; +/* +// TODO: improve NS's handling of normal cursor before merging cursor code. +MouseComboProperties _mouseComboProps_NS = { + 7, // combo x offset (the icon from the inventory will be rendered from here) + 7, // combo y offset (ditto) + 32, // combo (arrow + icon) width + 32 // combo (arrow + icon) height +}; +*/ +MouseComboProperties _mouseComboProps_BR = { + 8, // combo x offset (the icon from the inventory will be rendered from here) + 8, // combo y offset (ditto) + 68, // combo (arrow + icon) width + 68 // combo (arrow + icon) height +}; + +Input::Input(Parallaction *vm) : _vm(vm) { + _gameType = _vm->getGameType(); + _transCurrentHoverItem = 0; + _hasDelayedAction = false; // actived when the character needs to move before taking an action + _mouseState = MOUSE_DISABLED; + _activeItem._index = 0; + _activeItem._id = 0; + _mouseButtons = 0; + _delayedActionZone = nullZonePtr; + + initCursors(); +} + +Input::~Input() { + if (_gameType == GType_Nippon) { + delete _mouseArrow; + } + + delete _comboArrow; + delete _dinoCursor; + delete _dougCursor; + delete _donnaCursor; +} + // FIXME: the engine has 3 event loops. The following routine hosts the main one, // and it's called from 8 different places in the code. There exist 2 more specialised // loops which could possibly be merged into this one with some effort in changing @@ -78,9 +130,9 @@ void Input::readInput() { case Common::EVENT_MOUSEMOVE: _mousePos = e.mouse; break; - case Common::EVENT_RTL: + case Common::EVENT_QUIT: - _vm->_quit = true; + _engineFlags |= kEngineQuit; return; default: @@ -127,9 +179,9 @@ void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { } -void Input::updateGameInput() { +int Input::updateGameInput() { - readInput(); + int event = kEvNone; if (!isMouseEnabled() || (_engineFlags & kEngineWalking) || @@ -141,44 +193,38 @@ void Input::updateGameInput() { (_engineFlags & kEngineChangeLocation) == 0 ); - return; + return event; } if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) { - if (_keyPressed.keycode == Common::KEYCODE_l) _inputData._event = kEvLoadGame; - if (_keyPressed.keycode == Common::KEYCODE_s) _inputData._event = kEvSaveGame; + if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame; + if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame; } - if (_inputData._event == kEvNone) { - _inputData._mousePos = _mousePos; + if (event == kEvNone) { translateGameInput(); } + return event; } -InputData* Input::updateInput() { +int Input::updateInput() { - _inputData._event = kEvNone; + int event = kEvNone; + readInput(); switch (_inputMode) { - case kInputModeComment: - case kInputModeDialogue: - case kInputModeMenu: - readInput(); - break; - case kInputModeGame: - updateGameInput(); + event = updateGameInput(); break; case kInputModeInventory: - readInput(); updateInventoryInput(); break; } - return &_inputData; + return event; } void Input::trackMouse(ZonePtr z) { @@ -212,7 +258,7 @@ void Input::takeAction(ZonePtr z) { void Input::walkTo(const Common::Point &dest) { stopHovering(); - _vm->setArrowCursor(); + setArrowCursor(); _vm->_char.scheduleWalk(dest.x, dest.y); } @@ -252,7 +298,6 @@ bool Input::translateGameInput() { if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { - _inputData._zone = z; if (z->_flags & kFlagsNoWalk) { // character doesn't need to walk to take specified action takeAction(z); @@ -269,7 +314,7 @@ bool Input::translateGameInput() { } _vm->beep(); - _vm->setArrowCursor(); + setArrowCursor(); return true; } @@ -285,7 +330,7 @@ void Input::enterInventoryMode() { _activeItem._index = (_activeItem._id >> 16) & 0xFFFF; _engineFlags |= kEngineDragging; } else { - _vm->setArrowCursor(); + setArrowCursor(); } } @@ -320,12 +365,12 @@ void Input::exitInventoryMode() { _vm->closeInventory(); if (pos == -1) { - _vm->setArrowCursor(); + setArrowCursor(); } else { const InventoryItem *item = _vm->getInventoryItem(pos); if (item->_index != 0) { _activeItem._id = item->_id; - _vm->setInventoryCursor(item->_index); + setInventoryCursor(item->_index); } } _vm->resumeJobs(); @@ -373,4 +418,96 @@ bool Input::isMouseEnabled() { return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE); } + +void Input::initCursors() { + + _dinoCursor = _donnaCursor = _dougCursor = 0; + + switch (_gameType) { + case GType_Nippon: + _comboArrow = _vm->_disk->loadPointer("pointer"); + _mouseArrow = new Cnv(1, MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, _resMouseArrow_NS, false); + break; + + case GType_BRA: + if (_vm->getPlatform() == Common::kPlatformPC) { + _dinoCursor = _vm->_disk->loadPointer("pointer1"); + _dougCursor = _vm->_disk->loadPointer("pointer2"); + _donnaCursor = _vm->_disk->loadPointer("pointer3"); + + Graphics::Surface *surf = new Graphics::Surface; + surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); + _comboArrow = new SurfaceToFrames(surf); + + // TODO: choose the pointer depending on the active character + // For now, we pick Donna's + _mouseArrow = _donnaCursor; + } else { + // TODO: Where are the Amiga cursors? + _mouseArrow = 0; + } + break; + + default: + warning("Input::initCursors: unknown gametype"); + } + +} + +void Input::setArrowCursor() { + + switch (_gameType) { + case GType_Nippon: + debugC(1, kDebugInput, "setting mouse cursor to arrow"); + // this stuff is needed to avoid artifacts with labels and selected items when switching cursors + stopHovering(); + _activeItem._id = 0; + _vm->_system->setMouseCursor(_mouseArrow->getData(0), MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, 0, 0, 0); + break; + + case GType_BRA: { + if (_vm->getPlatform() == Common::kPlatformAmiga) + return; + + Common::Rect r; + _mouseArrow->getRect(0, r); + _vm->_system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); + _vm->_system->showMouse(true); + _activeItem._id = 0; + break; + } + + default: + warning("Input::setArrowCursor: unknown gametype"); + } + +} + +void Input::setInventoryCursor(ItemName name) { + assert(name > 0); + + switch (_gameType) { + case GType_Nippon: { + byte *v8 = _comboArrow->getData(0); + // FIXME: destination offseting is not clear + _vm->_inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH_NS + 7, MOUSECOMBO_WIDTH_NS); + _vm->_system->setMouseCursor(v8, MOUSECOMBO_WIDTH_NS, MOUSECOMBO_HEIGHT_NS, 0, 0, 0); + break; + } + + case GType_BRA: { + byte *src = _mouseArrow->getData(0); + byte *dst = _comboArrow->getData(0); + memcpy(dst, src, _comboArrow->getSize(0)); + // FIXME: destination offseting is not clear + _vm->_inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); + _vm->_system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); + } + + default: + warning("Input::setInventoryCursor: unknown gametype"); + } + +} + } // namespace Parallaction diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index c1e912db74..e7d20c0d2e 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -41,14 +41,6 @@ enum { kMouseRightDown = 8 }; -struct InputData { - uint16 _event; - Common::Point _mousePos; - int16 _inventoryIndex; - ZonePtr _zone; - uint _label; -}; - enum MouseTriState { MOUSE_ENABLED_SHOW, MOUSE_ENABLED_HIDE, @@ -56,10 +48,7 @@ enum MouseTriState { }; class Input { - void updateGameInput(); - - // input-only - InputData _inputData; + int updateGameInput(); bool _hasKeyPressEvent; Common::KeyState _keyPressed; @@ -69,7 +58,7 @@ class Input { int16 _transCurrentHoverItem; - InputData *translateInput(); + void translateInput(); bool translateGameInput(); bool updateInventoryInput(); void takeAction(ZonePtr z); @@ -85,6 +74,17 @@ class Input { void enterInventoryMode(); void exitInventoryMode(); + int _gameType; + + static byte _resMouseArrow_NS[256]; + Frames *_mouseArrow; + Frames *_comboArrow; + Frames *_dinoCursor; + Frames *_dougCursor; + Frames *_donnaCursor; + + void initCursors(); + public: enum { kInputModeGame = 0, @@ -95,18 +95,8 @@ public: }; - Input(Parallaction *vm) : _vm(vm) { - _transCurrentHoverItem = 0; - _hasDelayedAction = false; // actived when the character needs to move before taking an action - _mouseState = MOUSE_DISABLED; - _activeItem._index = 0; - _activeItem._id = 0; - _mouseButtons = 0; - _delayedActionZone = nullZonePtr; - } - - virtual ~Input() { } - + Input(Parallaction *vm); + virtual ~Input(); void getCursorPos(Common::Point& p) { p = _mousePos; @@ -116,7 +106,7 @@ public: InventoryItem _activeItem; void readInput(); - InputData* updateInput(); + int updateInput(); void trackMouse(ZonePtr z); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } @@ -129,6 +119,9 @@ public: void setMouseState(MouseTriState state); MouseTriState getMouseState(); bool isMouseEnabled(); + + void setArrowCursor(); + void setInventoryCursor(ItemName name); }; } // namespace Parallaction diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index d2332643ed..b4776250c6 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -180,7 +180,6 @@ Zone::~Zone() { case kZoneDoor: free(u.door->_location); - free(u.door->_background); u.door->gfxobj->release(); delete u.door; break; @@ -191,7 +190,6 @@ Zone::~Zone() { break; case kZoneGet: - free(u.get->_backup); u.get->gfxobj->release(); delete u.get; break; diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index f66e602f68..eee69383b6 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -192,23 +192,19 @@ struct Dialogue { ~Dialogue(); }; -struct GetData { // size = 24 +struct GetData { uint32 _icon; GfxObj *gfxobj; - byte *_backup; - uint16 field_14; // unused - uint16 field_16; // unused MaskBuffer _mask[2]; bool hasMask; GetData() { _icon = 0; - _backup = NULL; gfxobj = NULL; hasMask = false; } }; -struct SpeakData { // size = 36 +struct SpeakData { char _name[32]; Dialogue *_dialogue; @@ -217,30 +213,25 @@ struct SpeakData { // size = 36 _dialogue = NULL; } }; -struct ExamineData { // size = 28 +struct ExamineData { GfxObj *_cnv; - uint16 _opBase; // unused - uint16 field_12; // unused char* _description; char* _filename; ExamineData() { - _opBase = 0; _description = NULL; _filename = NULL; _cnv = NULL; } }; -struct DoorData { // size = 28 +struct DoorData { char* _location; GfxObj *gfxobj; - byte* _background; Common::Point _startPos; uint16 _startFrame; DoorData() { _location = NULL; - _background = NULL; _startFrame = 0; gfxobj = NULL; } diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index afa246a9f8..f69e39519c 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -35,6 +35,7 @@ #include "parallaction/input.h" #include "parallaction/parallaction.h" #include "parallaction/debug.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -47,7 +48,6 @@ Parallaction *_vm = NULL; // public stuff char _saveData1[30] = { '\0' }; -uint16 _language = 0; uint32 _engineFlags = 0; uint16 _score = 1; @@ -100,8 +100,6 @@ Parallaction::~Parallaction() { cleanupGui(); - delete _comboArrow; - delete _localFlagNames; delete _gfx; delete _soundMan; @@ -116,17 +114,13 @@ int Parallaction::init() { _objectsNames = NULL; _globalFlagsNames = NULL; _location._hasSound = false; - _baseTime = 0; _numLocations = 0; - _gameToLoad = -1; _location._startPosition.x = -1000; _location._startPosition.y = -1000; _location._startFrame = 0; _location._comment = NULL; _location._endComment = NULL; - _quit = false; - _pathBuffer = 0; _screenSize = _screenWidth * _screenHeight; @@ -137,6 +131,7 @@ int Parallaction::init() { initInventory(); // needs to be pushed into subclass + // this needs _disk to be already setup _input = new Input(this); _gfx = new Gfx(this); @@ -146,19 +141,10 @@ int Parallaction::init() { _menuHelper = 0; setupBalloonManager(); - syncSoundSettings(); return 0; } - -void Parallaction::clearSet(OpcodeSet &opcodes) { - for (Common::Array<const Opcode*>::iterator i = opcodes.begin(); i != opcodes.end(); ++i) - delete *i; - opcodes.clear(); -} - - void Parallaction::updateView() { if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) { @@ -167,7 +153,7 @@ void Parallaction::updateView() { _gfx->animatePalette(); _gfx->updateScreen(); - g_system->delayMillis(30); + _vm->_system->delayMillis(30); } @@ -282,7 +268,15 @@ void Parallaction::freeLocation() { return; } +void Parallaction::showSlide(const char *name, int x, int y) { + BackgroundInfo *info = new BackgroundInfo; + _disk->loadSlide(*info, name); + info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; + info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; + + _gfx->setBackground(kBackgroundSlide, info); +} void Parallaction::freeBackground() { @@ -307,23 +301,19 @@ void Parallaction::showLocationComment(const char *text, bool end) { } -void Parallaction::processInput(InputData *data) { - if (!data) { - return; - } - - switch (data->_event) { +void Parallaction::processInput(int event) { + switch (event) { case kEvSaveGame: _input->stopHovering(); - saveGame(); - setArrowCursor(); + _saveLoad->saveGame(); + _input->setArrowCursor(); break; case kEvLoadGame: _input->stopHovering(); - loadGame(); - setArrowCursor(); + _saveLoad->loadGame(); + _input->setArrowCursor(); break; } @@ -333,22 +323,19 @@ void Parallaction::processInput(InputData *data) { void Parallaction::runGame() { - InputData *data = _input->updateInput(); - if (_vm->quit()) + int event = _input->updateInput(); + if (_engineFlags & kEngineQuit) return; runGuiFrame(); runDialogueFrame(); runCommentFrame(); - if (_vm->quit()) - return; - if (_input->_inputMode == Input::kInputModeGame) { - processInput(data); + processInput(event); runPendingZones(); - if (_vm->quit()) + if (_engineFlags & kEngineQuit) return; if (_engineFlags & kEngineChangeLocation) { @@ -411,7 +398,7 @@ void Parallaction::doLocationEnterTransition() { pal.fadeTo(_gfx->_palette, 4); _gfx->setPalette(pal); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); } _gfx->setPalette(_gfx->_palette); @@ -439,6 +426,387 @@ uint32 Parallaction::getLocationFlags() { +void Parallaction::drawAnimations() { + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); + + uint16 layer = 0, scale = 100; + + for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { + + AnimationPtr anim = *it; + GfxObj *obj = anim->gfxobj; + + // Validation is performed here, so that every animation is affected, instead that only the ones + // who *own* a script. In fact, some scripts can change values in other animations. + // The right way to do this would be to enforce validation when any variable is modified from + // a script. + anim->validateScriptVars(); + + if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) { + + if (anim->_flags & kFlagsNoMasked) + layer = LAYER_FOREGROUND; + else { + if (getGameType() == GType_Nippon) { + // Layer in NS depends on where the animation is on the screen, for each animation. + layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height()); + } else { + // Layer in BRA is calculated from Z value. For characters it is the same as NS, + // but other animations can have Z set from scripts independently from their + // position on the screen. + layer = _gfx->_backgroundInfo->getLayer(anim->getZ()); + } + } + + if (getGameType() == GType_BRA) { + if (anim->_flags & (kFlagsScaled | kFlagsCharacter)) { + if (anim->getZ() <= _location._zeta0) { + if (anim->getZ() >= _location._zeta1) { + scale = ((anim->getZ() - _location._zeta1) * (100 - _location._zeta2)) / (_location._zeta0 - _location._zeta1) + _location._zeta2; + } else { + scale = _location._zeta2; + } + } + } + } + + if (obj) { + _gfx->showGfxObj(obj, true); + obj->frame = anim->getF(); + obj->x = anim->getX(); + obj->y = anim->getY(); + obj->z = anim->getZ(); + obj->layer = layer; + obj->scale = scale; + } + } + + if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) { + anim->_flags &= ~kFlagsRemove; + } + + if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) { + anim->_flags &= ~kFlagsActive; + anim->_flags |= kFlagsRemove; + if (obj) { + _gfx->showGfxObj(obj, false); + } + } + } + + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); + + return; +} + + +void Parallaction::showZone(ZonePtr z, bool visible) { + if (!z) { + return; + } + + if (visible) { + z->_flags &= ~kFlagsRemove; + z->_flags |= kFlagsActive; + } else { + z->_flags |= kFlagsRemove; + } + + if ((z->_type & 0xFFFF) == kZoneGet) { + _gfx->showGfxObj(z->u.get->gfxobj, visible); + + GetData *data = z->u.get; + if (data->hasMask && _gfx->_backgroundInfo->hasMask) { + if (visible) { + _gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h); + } else { + _gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h); + } + } + } +} + + +// +// ZONE TYPE: EXAMINE +// + +void Parallaction::enterCommentMode(ZonePtr z) { + if (!z) { + return; + } + + _commentZone = z; + + ExamineData *data = _commentZone->u.examine; + + if (!data->_description) { + return; + } + + // TODO: move this balloons stuff into DialogueManager and BalloonManager + if (getGameType() == GType_Nippon) { + int id; + if (data->_filename) { + if (data->_cnv == 0) { + data->_cnv = _disk->loadStatic(data->_filename); + } + + _gfx->setHalfbriteMode(true); + _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, BalloonManager::kNormalColor); + Common::Rect r; + data->_cnv->getRect(0, r); + id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); + _gfx->setItemFrame(id, 0); + id = _gfx->setItem(_char._head, 100, 152); + _gfx->setItemFrame(id, 0); + } else { + _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, BalloonManager::kNormalColor); + id = _gfx->setItem(_char._talk, 190, 80); + _gfx->setItemFrame(id, 0); + } + } else + if (getGameType() == GType_BRA) { + _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, BalloonManager::kNormalColor); + int id = _gfx->setItem(_char._talk, 10, 80); + _gfx->setItemFrame(id, 0); + } + + _input->_inputMode = Input::kInputModeComment; +} + +void Parallaction::exitCommentMode() { + _input->_inputMode = Input::kInputModeGame; + + hideDialogueStuff(); + _gfx->setHalfbriteMode(false); + + _cmdExec->run(_commentZone->_commands, _commentZone); + _commentZone = nullZonePtr; +} + +void Parallaction::runCommentFrame() { + if (_input->_inputMode != Input::kInputModeComment) { + return; + } + + if (_input->getLastButtonEvent() == kMouseLeftUp) { + exitCommentMode(); + } +} + + +void Parallaction::runZone(ZonePtr z) { + debugC(3, kDebugExec, "runZone (%s)", z->_name); + + uint16 subtype = z->_type & 0xFFFF; + + debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); + switch(subtype) { + + case kZoneExamine: + enterCommentMode(z); + return; + + case kZoneGet: + pickupItem(z); + break; + + case kZoneDoor: + if (z->_flags & kFlagsLocked) break; + updateDoor(z, !(z->_flags & kFlagsClosed)); + break; + + case kZoneHear: + _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); + break; + + case kZoneSpeak: + enterDialogueMode(z); + return; + } + + debugC(3, kDebugExec, "runZone completed"); + + _cmdExec->run(z->_commands, z); + + return; +} + +// +// ZONE TYPE: DOOR +// +void Parallaction::updateDoor(ZonePtr z, bool close) { + z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed); + + if (z->u.door->gfxobj) { + uint frame = (close ? 0 : 1); +// z->u.door->gfxobj->setFrame(frame); + z->u.door->gfxobj->frame = frame; + } + + return; +} + + + +// +// ZONE TYPE: GET +// + +bool Parallaction::pickupItem(ZonePtr z) { + if (z->_flags & kFlagsFixed) { + return false; + } + + int slot = addInventoryItem(z->u.get->_icon); + if (slot != -1) { + showZone(z, false); + } + + return (slot != -1); +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) { + // not a special zone + if ((z->getX() != -2) && (z->getX() != -3)) { + return false; + } + + // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs + // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, + // but we need to check it separately here. The same workaround is applied in freeZones. + if ((((z->_type & 0xFFFF) == kZoneMerge) && (((x == z->u.merge->_obj1) && (y == z->u.merge->_obj2)) || ((x == z->u.merge->_obj2) && (y == z->u.merge->_obj1)))) || + (((z->_type & 0xFFFF) == kZoneGet) && ((x == z->u.get->_icon) || (y == z->u.get->_icon)))) { + + // WORKAROUND for bug 2070751: special zones are only used in NS, to allow the + // the EXAMINE/USE action to be applied on some particular item in the inventory. + // The usage a verb requires at least an item match, so type can't be 0, as it + // was in the original code. This bug has been here since the beginning, and was + // hidden by label code, which filtered the bogus matches produced here. + + // look for action + item match + if (z->_type == type) + return true; + // look for item match, but don't accept 0 types + if (((z->_type & 0xFFFF0000) == type) && (type)) + return true; + } + + return false; +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) { + if (z->_flags & kFlagsRemove) + return false; + + debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y); + + Common::Rect r; + z->getBox(r); + r.right++; // adjust border because Common::Rect doesn't include bottom-right edge + r.bottom++; + + r.grow(-1); // allows some tolerance for mouse click + + if (!r.contains(x, y)) { + + // check for special zones (items defined in common.loc) + if (checkSpecialZoneBox(z, type, x, y)) + return true; + + if (z->getX() != -1) + return false; + if ((int)x < _char._ani->getFrameX()) + return false; + if ((int)x > (_char._ani->getFrameX() + _char._ani->width())) + return false; + if ((int)y < _char._ani->getFrameY()) + return false; + if ((int)y > (_char._ani->getFrameY() + _char._ani->height())) + return false; + } + + // normal Zone + if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) + return true; + if (z->_type == type) + return true; + if ((z->_type & 0xFFFF0000) == type) + return true; + + return false; +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) { + if (z->_flags & kFlagsRemove) + return false; + + if ((z->_flags & kFlagsAnimLinked) == 0) + return false; + + debugC(5, kDebugExec, "checkLinkedAnimBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y); + + AnimationPtr anim = z->_linkedAnim; + Common::Rect r(anim->getFrameX(), anim->getFrameY(), anim->getFrameX() + anim->width() + 1, anim->getFrameY() + anim->height() + 1); + + if (!r.contains(x, y)) { + return false; + } + + // NOTE: the implementation of the following lines is a different in the + // original... it is working so far, though + if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) + return true; + if (z->_type == type) + return true; + if ((z->_type & 0xFFFF0000) == type) + return true; + + return false; +} + +ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { + uint16 _di = y; + uint16 _si = x; + + for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) { + if (checkLinkedAnimBox(*it, type, x, y)) { + return *it; + } + if (checkZoneBox(*it, type, x, y)) { + return *it; + } + } + + + int16 _a, _b, _c, _d, _e, _f; + for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) { + + AnimationPtr a = *ait; + + _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation + _e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1; // _e: horizontal range + _f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1; // _f: vertical range + + _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character) + _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object + _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type + + if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { + + return a; + + } + + } + + return nullZonePtr; +} + ZonePtr Parallaction::findZone(const char *name) { @@ -451,7 +819,7 @@ ZonePtr Parallaction::findZone(const char *name) { void Parallaction::freeZones() { - debugC(2, kDebugExec, "freeZones: _vm->_quit = %i", _vm->_quit); + debugC(2, kDebugExec, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); ZoneList::iterator it = _location._zones.begin(); @@ -460,8 +828,7 @@ void Parallaction::freeZones() { // NOTE : this condition has been relaxed compared to the original, to allow the engine // to retain special - needed - zones that were lost across location switches. ZonePtr z = *it; - - if (((z->getY() == -1) || (z->getX() == -2)) && ((_vm->quit()) == 0)) { + if (((z->getY() == -1) || (z->getX() == -2)) && ((_engineFlags & kEngineQuit) == 0)) { debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name); it++; } else { @@ -475,11 +842,6 @@ void Parallaction::freeZones() { return; } -void Parallaction::syncSoundSettings() { - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume") / 6); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); -} enum { WALK_LEFT = 0, @@ -528,7 +890,7 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) { _ani->setY(100); _ani->setZ(10); _ani->setF(0); - _ani->_flags = kFlagsActive | kFlagsNoName; + _ani->_flags = kFlagsActive | kFlagsNoName | kFlagsCharacter; _ani->_type = kZoneYou; strncpy(_ani->_name, "yourself", ZONENAME_LENGTH); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index eb7ab2e54b..b8464e7c7a 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -29,6 +29,7 @@ #include "common/str.h" #include "common/stack.h" #include "common/array.h" +#include "common/func.h" #include "common/savefile.h" #include "engines/engine.h" @@ -44,8 +45,6 @@ #define PATH_LEN 200 -extern OSystem *g_system; - namespace Parallaction { enum { @@ -71,34 +70,8 @@ enum { }; -// high values mean high priority - -enum { - kPriority0 = 0, - kPriority1 = 1, - kPriority2 = 2, - kPriority3 = 3, - kPriority4 = 4, - kPriority5 = 5, - kPriority6 = 6, - kPriority7 = 7, - kPriority8 = 8, - kPriority9 = 9, - kPriority10 = 10, - kPriority11 = 11, - kPriority12 = 12, - kPriority13 = 13, - kPriority14 = 14, - kPriority15 = 15, - kPriority16 = 16, - kPriority17 = 17, - kPriority18 = 18, - kPriority19 = 19, - kPriority20 = 20, - kPriority21 = 21 -}; - enum EngineFlags { + kEngineQuit = (1 << 0), kEnginePauseJobs = (1 << 1), kEngineWalking = (1 << 3), kEngineChangeLocation = (1 << 4), @@ -115,10 +88,6 @@ enum { kEvLoadGame = 4000 }; -enum { - kCursorArrow = -1 -}; - enum ParallactionGameType { GType_Nippon = 1, GType_BRA @@ -129,10 +98,8 @@ struct PARALLACTIONGameDescription; -extern uint16 _mouseButtons; extern char _password[8]; extern uint16 _score; -extern uint16 _language; extern uint32 _engineFlags; extern char _saveData1[]; extern uint32 _globalFlags; @@ -237,6 +204,7 @@ public: }; +class SaveLoad; #define NUM_LOCATIONS 120 @@ -244,239 +212,143 @@ class Parallaction : public Engine { friend class Debugger; public: - - Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc); - ~Parallaction(); - - int init(); - - virtual bool loadGame() = 0; - virtual bool saveGame() = 0; - - bool _quit; /* The only reason this flag exists is for freeZones() to properly - * delete all zones when necessary. THIS FLAG IS NOT THE ENGINE QUIT FLAG, - * use _eventMan->shouldQuit() for that. - */ - - Input *_input; - - void processInput(InputData* data); - - void pauseJobs(); - void resumeJobs(); - - virtual void syncSoundSettings(); - - ZonePtr findZone(const char *name); - ZonePtr hitZone(uint32 type, uint16 x, uint16 y); - void runZone(ZonePtr z); - void freeZones(); - - AnimationPtr findAnimation(const char *name); - void freeAnimations(); - - void setBackground(const char *background, const char *mask, const char *path); - void freeBackground(); - - Table *_globalFlagsNames; - Table *_objectsNames; - Table *_callableNames; - Table *_localFlagNames; - -public: int getGameType() const; uint32 getFeatures() const; Common::Language getLanguage() const; Common::Platform getPlatform() const; +protected: // members + bool detectGame(void); + private: const PARALLACTIONGameDescription *_gameDescription; + uint16 _language; public: + Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc); + ~Parallaction(); + + int init(); + // info int32 _screenWidth; int32 _screenHeight; int32 _screenSize; - PathBuffer *_pathBuffer; - + // subsystems + Gfx *_gfx; + Disk *_disk; + Input *_input; SoundMan *_soundMan; + Debugger *_debugger; + SaveLoad *_saveLoad; + MenuInputHelper *_menuHelper; + Common::RandomSource _rnd; - Gfx* _gfx; - Disk* _disk; + // fonts + Font *_labelFont; + Font *_menuFont; + Font *_introFont; + Font *_dialogueFont; - CommandExec* _cmdExec; - ProgramExec* _programExec; + // game utilities + Table *_globalFlagsNames; + Table *_objectsNames; + Table *_callableNames; + Table *_localFlagNames; + CommandExec *_cmdExec; + ProgramExec *_programExec; + PathBuffer *_pathBuffer; + Inventory *_inventory; + BalloonManager *_balloonMan; + DialogueManager *_dialogueMan; + InventoryRenderer *_inventoryRenderer; + + // game data Character _char; - - void setLocationFlags(uint32 flags); - void clearLocationFlags(uint32 flags); - void toggleLocationFlags(uint32 flags); - uint32 getLocationFlags(); - uint32 _localFlags[NUM_LOCATIONS]; char _locationNames[NUM_LOCATIONS][32]; int16 _currentLocationIndex; uint16 _numLocations; Location _location; - ZonePtr _activeZone; + char _characterName1[50]; // only used in changeCharacter + ZonePtr _zoneTrap; + ZonePtr _commentZone; - - Font *_labelFont; - Font *_menuFont; - Font *_introFont; - Font *_dialogueFont; - - Common::RandomSource _rnd; - - Debugger *_debugger; - Frames *_comboArrow; - - -protected: // data - uint32 _baseTime; - char _characterName1[50]; // only used in changeCharacter - - int _gameToLoad; - Common::String _saveFileName; - - -protected: // members - bool detectGame(void); - - void initGlobals(); - void runGame(); - void updateView(); - - void doLocationEnterTransition(); - virtual void changeLocation(char *location) = 0; - virtual void runPendingZones() = 0; - void allocateLocationSlot(const char *name); - void finalizeLocationParsing(); - void freeLocation(); - void showLocationComment(const char *text, bool end); - - void displayComment(ExamineData *data); - - void freeCharacter(); - - bool pickupItem(ZonePtr z); - - void clearSet(OpcodeSet &opcodes); - +protected: + void runGame(); + void runGuiFrame(); + void cleanupGui(); + void runDialogueFrame(); + void exitDialogueMode(); + void runCommentFrame(); + void enterCommentMode(ZonePtr z); + void exitCommentMode(); + void processInput(int event); + void updateView(); + void drawAnimations(); + void freeCharacter(); + void freeLocation(); + void doLocationEnterTransition(); + void allocateLocationSlot(const char *name); + void finalizeLocationParsing(); + void showLocationComment(const char *text, bool end); + void setupBalloonManager(); public: - void scheduleLocationSwitch(const char *location); - virtual void changeCharacter(const char *name) = 0; - - virtual void callFunction(uint index, void* parm) { } - - virtual void setArrowCursor() = 0; - virtual void setInventoryCursor(ItemName name) = 0; - - virtual void parseLocation(const char* name) = 0; - - void updateDoor(ZonePtr z, bool close); - - virtual void drawAnimations() = 0; - - void beep(); - - ZonePtr _zoneTrap; - PathBuilder* getPathBuilder(Character *ch); + void beep(); + void pauseJobs(); + void resumeJobs(); + void hideDialogueStuff(); + uint getInternLanguage(); + void setInternLanguage(uint id); + void enterDialogueMode(ZonePtr z); + void scheduleLocationSwitch(const char *location); + void showSlide(const char *name, int x = 0, int y = 0); public: -// const char **_zoneFlagNamesRes; -// const char **_zoneTypeNamesRes; -// const char **_commandsNamesRes; - const char **_callableNamesRes; - const char **_instructionNamesRes; - - void highlightInventoryItem(ItemPosition pos); - int16 getHoverInventoryItem(int16 x, int16 y); - int addInventoryItem(ItemName item); - int addInventoryItem(ItemName item, uint32 value); - void dropItem(uint16 v); - bool isItemInInventory(int32 v); - const InventoryItem* getInventoryItem(int16 pos); - int16 getInventoryItemIndex(int16 pos); - void initInventory(); - void destroyInventory(); - void cleanInventory(bool keepVerbs = true); - void openInventory(); - void closeInventory(); - - Inventory *_inventory; - InventoryRenderer *_inventoryRenderer; - - BalloonManager *_balloonMan; - - void setupBalloonManager(); - - void hideDialogueStuff(); - DialogueManager *_dialogueMan; - void enterDialogueMode(ZonePtr z); - void exitDialogueMode(); - void runDialogueFrame(); - - MenuInputHelper *_menuHelper; - void runGuiFrame(); - void cleanupGui(); - - ZonePtr _commentZone; - void enterCommentMode(ZonePtr z); - void exitCommentMode(); - void runCommentFrame(); - - void setInternLanguage(uint id); - uint getInternLanguage(); + void setLocationFlags(uint32 flags); + void clearLocationFlags(uint32 flags); + void toggleLocationFlags(uint32 flags); + uint32 getLocationFlags(); + bool checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y); + bool checkZoneBox(ZonePtr z, uint32 type, uint x, uint y); + bool checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y); + ZonePtr findZone(const char *name); + ZonePtr hitZone(uint32 type, uint16 x, uint16 y); + void runZone(ZonePtr z); + void freeZones(); + bool pickupItem(ZonePtr z); + void updateDoor(ZonePtr z, bool close); + void showZone(ZonePtr z, bool visible); + AnimationPtr findAnimation(const char *name); + void freeAnimations(); + void setBackground(const char *background, const char *mask, const char *path); + void freeBackground(); + void highlightInventoryItem(ItemPosition pos); + int16 getHoverInventoryItem(int16 x, int16 y); + int addInventoryItem(ItemName item); + int addInventoryItem(ItemName item, uint32 value); + void dropItem(uint16 v); + bool isItemInInventory(int32 v); + const InventoryItem* getInventoryItem(int16 pos); + int16 getInventoryItemIndex(int16 pos); + void initInventory(); + void destroyInventory(); + void cleanInventory(bool keepVerbs = true); + void openInventory(); + void closeInventory(); - void showZone(ZonePtr z, bool visible); + virtual void parseLocation(const char* name) = 0; + virtual void changeLocation(char *location) = 0; + virtual void changeCharacter(const char *name) = 0; + virtual void callFunction(uint index, void* parm) = 0; + virtual void runPendingZones() = 0; + virtual void cleanupGame() = 0; }; -class LocationName { - - Common::String _slide; - Common::String _character; - Common::String _location; - - bool _hasCharacter; - bool _hasSlide; - char *_buf; - -public: - LocationName(); - ~LocationName(); - - void bind(const char*); - - const char *location() const { - return _location.c_str(); - } - - bool hasCharacter() const { - return _hasCharacter; - } - - const char *character() const { - return _character.c_str(); - } - - bool hasSlide() const { - return _hasSlide; - } - - const char *slide() const { - return _slide.c_str(); - } - - const char *c_str() const { - return _buf; - } -}; - class Parallaction_ns : public Parallaction { @@ -488,70 +360,45 @@ public: int go(); public: - typedef void (Parallaction_ns::*Callable)(void*); - - virtual void callFunction(uint index, void* parm); + virtual void parseLocation(const char *filename); + virtual void changeLocation(char *location); + virtual void changeCharacter(const char *name); + virtual void callFunction(uint index, void* parm); + virtual void runPendingZones(); + virtual void cleanupGame(); - bool loadGame(); - bool saveGame(); - void switchBackground(const char* background, const char* mask); - void showSlide(const char *name, int x = 0, int y = 0); - void setArrowCursor(); - - // TODO: this should be private!!!!!!! - bool _inTestResult; - void cleanupGame(); - bool allPartsComplete(); + void switchBackground(const char* background, const char* mask); private: - LocationParser_ns *_locationParser; - ProgramParser_ns *_programParser; - - void initFonts(); - void freeFonts(); - void renameOldSavefiles(); - Common::String genSaveFileName(uint slot, bool oldStyle = false); - Common::InSaveFile *getInSaveFile(uint slot); - Common::OutSaveFile *getOutSaveFile(uint slot); - void setPartComplete(const Character& character); + bool _inTestResult; + LocationParser_ns *_locationParser; + ProgramParser_ns *_programParser; private: - void changeLocation(char *location); - void changeCharacter(const char *name); - void runPendingZones(); - - void setInventoryCursor(ItemName name); - - - void doLoadGame(uint16 slot); - void doSaveGame(uint16 slot, const char* name); - int buildSaveFileList(Common::StringList& l); - int selectSaveFile(uint16 arg_0, const char* caption, const char* button); - - void initResources(); - void initCursors(); - - static byte _resMouseArrow[256]; - byte *_mouseArrow; - - static const Callable _dosCallables[25]; - static const Callable _amigaCallables[25]; + void initFonts(); + void freeFonts(); + void initResources(); + void startGui(); + void startCreditSequence(); + void startEndPartSequence(); + void loadProgram(AnimationPtr a, const char *filename); - /* - game callables data members - */ + // callables data + typedef void (Parallaction_ns::*Callable)(void*); + const Callable *_callables; ZonePtr _moveSarcZone0; ZonePtr _moveSarcZone1; uint16 num_foglie; int16 _introSarcData1; uint16 _introSarcData2; // sarcophagus stuff to be saved uint16 _introSarcData3; // sarcophagus stuff to be saved - ZonePtr _moveSarcZones[5]; ZonePtr _moveSarcExaZones[5]; AnimationPtr _rightHandAnim; + static const Callable _dosCallables[25]; + static const Callable _amigaCallables[25]; // common callables void _c_play_boogie(void*); @@ -585,20 +432,6 @@ private: void _c_startMusic(void*); void _c_closeMusic(void*); void _c_HBOn(void*); - - const Callable *_callables; - -protected: - void drawAnimations(); - - void parseLocation(const char *filename); - void loadProgram(AnimationPtr a, const char *filename); - - void selectStartLocation(); - - void startGui(); - void startCreditSequence(); - void startEndPartSequence(); }; @@ -607,8 +440,6 @@ protected: class Parallaction_br : public Parallaction_ns { - typedef Parallaction_ns Super; - public: Parallaction_br(OSystem* syst, const PARALLACTIONGameDescription *gameDesc) : Parallaction_ns(syst, gameDesc) { } ~Parallaction_br(); @@ -617,83 +448,55 @@ public: int go(); public: - typedef void (Parallaction_br::*Callable)(void*); + virtual void parseLocation(const char* name); + virtual void changeLocation(char *location); + virtual void changeCharacter(const char *name); virtual void callFunction(uint index, void* parm); - void changeCharacter(const char *name); + virtual void runPendingZones(); + virtual void cleanupGame(); + + void setupSubtitles(char *s, char *s2, int y); void clearSubtitles(); - public: Table *_countersNames; - const char **_audioCommandsNamesRes; - + static const char *_partNames[]; int _part; - int _progress; - #if 0 // disabled since I couldn't find any references to lip sync in the scripts int16 _lipSyncVal; uint _subtitleLipSync; #endif int _subtitleY; int _subtitle[2]; - ZonePtr _activeZone2; - int32 _counters[32]; - uint32 _zoneFlags[NUM_LOCATIONS][NUM_ZONES]; - void startPart(uint part); - void setArrowCursor(); + private: LocationParser_br *_locationParser; ProgramParser_br *_programParser; - void initResources(); - void initFonts(); - void freeFonts(); - - void setInventoryCursor(ItemName name); - - void changeLocation(char *location); - void runPendingZones(); - - void initPart(); - void freePart(); - - void initCursors(); - - Frames *_dinoCursor; - Frames *_dougCursor; - Frames *_donnaCursor; - Frames *_mouseArrow; - - - static const char *_partNames[]; - - void startGui(); +private: + void initResources(); + void initFonts(); + void freeFonts(); + void freeLocation(); + void loadProgram(AnimationPtr a, const char *filename); + void startGui(bool showSplash); + typedef void (Parallaction_br::*Callable)(void*); + const Callable *_callables; static const Callable _dosCallables[6]; + // dos callables void _c_blufade(void*); void _c_resetpalette(void*); void _c_ferrcycle(void*); void _c_lipsinc(void*); void _c_albcycle(void*); void _c_password(void*); - - const Callable *_callables; - - void parseLocation(const char* name); - void loadProgram(AnimationPtr a, const char *filename); - -#if 0 - void jobWaitRemoveLabelJob(void *parm, Job *job); - void jobPauseSfx(void *parm, Job *job); - void jobStopFollower(void *parm, Job *job); - void jobScroll(void *parm, Job *job); -#endif }; // FIXME: remove global diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index e65faaeda2..7c0fa23e15 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -28,31 +28,11 @@ #include "parallaction/parallaction.h" #include "parallaction/input.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" namespace Parallaction { -struct MouseComboProperties { - int _xOffset; - int _yOffset; - int _width; - int _height; -}; -/* -// TODO: improve NS's handling of normal cursor before merging cursor code. -MouseComboProperties _mouseComboProps_NS = { - 7, // combo x offset (the icon from the inventory will be rendered from here) - 7, // combo y offset (ditto) - 32, // combo (arrow + icon) width - 32 // combo (arrow + icon) height -}; -*/ -MouseComboProperties _mouseComboProps_BR = { - 8, // combo x offset (the icon from the inventory will be rendered from here) - 8, // combo y offset (ditto) - 68, // combo (arrow + icon) width - 68 // combo (arrow + icon) height -}; const char *Parallaction_br::_partNames[] = { "PART0", @@ -62,14 +42,6 @@ const char *Parallaction_br::_partNames[] = { "PART4" }; -const char *partFirstLocation[] = { - "intro", - "museo", - "start", - "bolscoi", - "treno" -}; - int Parallaction_br::init() { _screenWidth = 640; @@ -96,7 +68,6 @@ int Parallaction_br::init() { initResources(); initFonts(); - initCursors(); _locationParser = new LocationParser_br(this); _locationParser->init(); _programParser = new ProgramParser_br(this); @@ -112,6 +83,8 @@ int Parallaction_br::init() { _subtitle[0] = -1; _subtitle[1] = -1; + _saveLoad = new SaveLoad_br(this, _saveFileMan); + Parallaction::init(); return 0; @@ -119,12 +92,6 @@ int Parallaction_br::init() { Parallaction_br::~Parallaction_br() { freeFonts(); - - delete _dinoCursor; - delete _dougCursor; - delete _donnaCursor; - - delete _mouseArrow; } void Parallaction_br::callFunction(uint index, void* parm) { @@ -135,28 +102,30 @@ void Parallaction_br::callFunction(uint index, void* parm) { int Parallaction_br::go() { - if (getFeatures() & GF_DEMO) { - startPart(1); - } else { - startGui(); - } + bool splash = true; - while (quit() == 0) { + while ((_engineFlags & kEngineQuit) == 0) { + + if (getFeatures() & GF_DEMO) { + scheduleLocationSwitch("camalb.1"); + _input->_inputMode = Input::kInputModeGame; + } else { + startGui(splash); + // don't show splash after first time + splash = false; + } // initCharacter(); - _input->_inputMode = Input::kInputModeGame; - while (((_engineFlags & kEngineReturn) == 0) && (!quit())) { + while ((_engineFlags & (kEngineReturn | kEngineQuit)) == 0) { runGame(); } _engineFlags &= ~kEngineReturn; - freePart(); -// freeCharacter(); - + cleanupGame(); } - return _eventMan->shouldRTL(); + return 0; } @@ -169,70 +138,6 @@ void Parallaction_br::freeFonts() { return; } -void Parallaction_br::initCursors() { - - if (getPlatform() == Common::kPlatformPC) { - _dinoCursor = _disk->loadPointer("pointer1"); - _dougCursor = _disk->loadPointer("pointer2"); - _donnaCursor = _disk->loadPointer("pointer3"); - - Graphics::Surface *surf = new Graphics::Surface; - surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); - _comboArrow = new SurfaceToFrames(surf); - - // TODO: choose the pointer depending on the active character - // For now, we pick Donna's - _mouseArrow = _donnaCursor; - } else { - // TODO: Where are the Amiga cursors? - } - -} - -void Parallaction_br::initPart() { - - memset(_counters, 0, ARRAYSIZE(_counters)); - - _globalFlagsNames = _disk->loadTable("global"); - _objectsNames = _disk->loadTable("objects"); - _countersNames = _disk->loadTable("counters"); - - // TODO: maybe handle this into Disk - if (getPlatform() == Common::kPlatformPC) { - _char._objs = _disk->loadObjects("icone.ico"); - } else { - _char._objs = _disk->loadObjects("icons.ico"); - } - -} - -void Parallaction_br::freePart() { - - delete _globalFlagsNames; - delete _objectsNames; - delete _countersNames; - - _globalFlagsNames = 0; - _objectsNames = 0; - _countersNames = 0; -} - -void Parallaction_br::startPart(uint part) { - _part = part; - _disk->selectArchive(_partNames[_part]); - - initPart(); - - if (getFeatures() & GF_DEMO) { - strcpy(_location._name, "camalb"); - } else { - strcpy(_location._name, partFirstLocation[_part]); - } - - parseLocation("common"); - changeLocation(_location._name); - -} void Parallaction_br::runPendingZones() { ZonePtr z; @@ -260,8 +165,7 @@ void Parallaction_br::runPendingZones() { } } - -void Parallaction_br::changeLocation(char *location) { +void Parallaction_br::freeLocation() { // free open location stuff clearSubtitles(); @@ -279,27 +183,75 @@ void Parallaction_br::changeLocation(char *location) { _location._animations.push_front(_char._ani); -// free(_location._comment); -// _location._comment = 0; + free(_location._comment); + _location._comment = 0; _location._commands.clear(); _location._aCommands.clear(); +} + +void Parallaction_br::cleanupGame() { + freeLocation(); + +// freeCharacter(); + + delete _globalFlagsNames; + delete _objectsNames; + delete _countersNames; + + _globalFlagsNames = 0; + _objectsNames = 0; + _countersNames = 0; +} + + +void Parallaction_br::changeLocation(char *location) { + char *partStr = strrchr(location, '.'); + if (partStr) { + int n = partStr - location; + strncpy(_location._name, location, n); + _location._name[n] = '\0'; + + _part = atoi(++partStr); + if (getFeatures() & GF_DEMO) { + assert(_part == 1); + } else { + assert(_part >= 0 && _part <= 4); + } + + _disk->selectArchive(_partNames[_part]); + + memset(_counters, 0, ARRAYSIZE(_counters)); + + _globalFlagsNames = _disk->loadTable("global"); + _objectsNames = _disk->loadTable("objects"); + _countersNames = _disk->loadTable("counters"); + + // TODO: maybe handle this into Disk + if (getPlatform() == Common::kPlatformPC) { + _char._objs = _disk->loadObjects("icone.ico"); + } else { + _char._objs = _disk->loadObjects("icons.ico"); + } + + parseLocation("common"); + } + + freeLocation(); // load new location parseLocation(location); - - // kFlagsRemove is cleared because the character defaults to visible on new locations - // script command can hide the character, anyway, so that's why the flag is cleared - // before _location._commands are executed + // kFlagsRemove is cleared because the character is visible by default. + // Commands can hide the character, anyway. _char._ani->_flags &= ~kFlagsRemove; - _cmdExec->run(_location._commands); -// doLocationEnterTransition(); + + doLocationEnterTransition(); + _cmdExec->run(_location._aCommands); _engineFlags &= ~kEngineChangeLocation; } - // FIXME: Parallaction_br::parseLocation() is now a verbatim copy of the same routine from Parallaction_ns. void Parallaction_br::parseLocation(const char *filename) { debugC(1, kDebugParser, "parseLocation('%s')", filename); @@ -359,30 +311,5 @@ void Parallaction_br::changeCharacter(const char *name) { } -void Parallaction_br::setArrowCursor() { - // FIXME: Where are the Amiga cursors? - if (getPlatform() == Common::kPlatformAmiga) - return; - - Common::Rect r; - _mouseArrow->getRect(0, r); - - _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); - _system->showMouse(true); - - _input->_activeItem._id = 0; -} - -void Parallaction_br::setInventoryCursor(ItemName name) { - assert(name > 0); - - byte *src = _mouseArrow->getData(0); - byte *dst = _comboArrow->getData(0); - memcpy(dst, src, _comboArrow->getSize(0)); - - // FIXME: destination offseting is not clear - _inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); - _system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); -} } // namespace Parallaction diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index eab08142d4..85a4689301 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -28,30 +28,62 @@ #include "common/config-manager.h" #include "parallaction/parallaction.h" -#include "parallaction/gui.h" -#include "parallaction/gui_ns.cpp" #include "parallaction/input.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" namespace Parallaction { -#define MOUSEARROW_WIDTH 16 -#define MOUSEARROW_HEIGHT 16 +class LocationName { -#define MOUSECOMBO_WIDTH 32 // sizes for cursor + selected inventory item -#define MOUSECOMBO_HEIGHT 32 + Common::String _slide; + Common::String _character; + Common::String _location; -LocationName::LocationName() { - _buf = 0; - _hasSlide = false; - _hasCharacter = false; -} + bool _hasCharacter; + bool _hasSlide; + char *_buf; + +public: + LocationName() { + _buf = 0; + _hasSlide = false; + _hasCharacter = false; + } + + ~LocationName() { + free(_buf); + } + + void bind(const char*); + + const char *location() const { + return _location.c_str(); + } + + bool hasCharacter() const { + return _hasCharacter; + } + + const char *character() const { + return _character.c_str(); + } + + bool hasSlide() const { + return _hasSlide; + } + + const char *slide() const { + return _slide.c_str(); + } + + const char *c_str() const { + return _buf; + } +}; -LocationName::~LocationName() { - free(_buf); -} /* @@ -137,7 +169,6 @@ int Parallaction_ns::init() { initResources(); initFonts(); - initCursors(); _locationParser = new LocationParser_ns(this); _locationParser->init(); _programParser = new ProgramParser_ns(this); @@ -158,6 +189,8 @@ int Parallaction_ns::init() { _location._animations.push_front(_char._ani); + _saveLoad = new SaveLoad_ns(this, _saveFileMan); + Parallaction::init(); return 0; @@ -183,32 +216,6 @@ void Parallaction_ns::freeFonts() { } -void Parallaction_ns::initCursors() { - _comboArrow = _disk->loadPointer("pointer"); - _mouseArrow = _resMouseArrow; -} - -void Parallaction_ns::setArrowCursor() { - - debugC(1, kDebugInput, "setting mouse cursor to arrow"); - - // this stuff is needed to avoid artifacts with labels and selected items when switching cursors - _input->stopHovering(); - _input->_activeItem._id = 0; - - _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); -} - -void Parallaction_ns::setInventoryCursor(ItemName name) { - assert(name > 0); - - byte *v8 = _comboArrow->getData(0); - - // FIXME: destination offseting is not clear - _inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH); - _system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); -} - void Parallaction_ns::callFunction(uint index, void* parm) { assert(index < 25); // magic value 25 is maximum # of callables for Nippon Safes @@ -218,35 +225,17 @@ void Parallaction_ns::callFunction(uint index, void* parm) { int Parallaction_ns::go() { - renameOldSavefiles(); + _saveLoad->renameOldSavefiles(); _globalFlagsNames = _disk->loadTable("global"); - // If requested, load a savegame instead of showing the intro - if (ConfMan.hasKey("save_slot")) { - _gameToLoad = ConfMan.getInt("save_slot"); - if (_gameToLoad < 0 || _gameToLoad > 99) - _gameToLoad = -1; - } - if (_gameToLoad == -1) { - startGui(); - } else { - _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); - - _menuHelper = new MenuInputHelper; - assert(_menuHelper); - new ChooseLanguageInputState_NS(this, _menuHelper); - _menuHelper->setState("chooselanguage"); - - _input->_inputMode = Input::kInputModeMenu; - doLoadGame(_gameToLoad); - } - - while (!quit()) { + startGui(); + + while ((_engineFlags & kEngineQuit) == 0) { runGame(); } - return _eventMan->shouldRTL(); + return 0; } void Parallaction_ns::switchBackground(const char* background, const char* mask) { @@ -262,7 +251,7 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask) v2 += 4; } - g_system->delayMillis(20); + _vm->_system->delayMillis(20); _gfx->setPalette(pal); _gfx->updateScreen(); } @@ -273,16 +262,6 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask) } -void Parallaction_ns::showSlide(const char *name, int x, int y) { - BackgroundInfo *info = new BackgroundInfo; - _disk->loadSlide(*info, name); - - info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; - info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; - - _gfx->setBackground(kBackgroundSlide, info); -} - void Parallaction_ns::runPendingZones() { if (_activeZone) { ZonePtr z = _activeZone; // speak Zone or sound @@ -307,7 +286,7 @@ void Parallaction_ns::changeLocation(char *location) { _zoneTrap = nullZonePtr; - setArrowCursor(); + _input->setArrowCursor(); _gfx->showGfxObj(_char._ani->gfxobj, false); _location._animations.remove(_char._ani); @@ -448,6 +427,7 @@ void Parallaction_ns::changeCharacter(const char *name) { } void Parallaction_ns::cleanupGame() { + _inTestResult = false; _engineFlags &= ~kEngineTransformedDonna; @@ -460,18 +440,22 @@ void Parallaction_ns::cleanupGame() { memset(_locationNames, 0, sizeof(_locationNames)); // this flag tells freeZones to unconditionally remove *all* Zones - _vm->_quit = true; + _engineFlags |= kEngineQuit; freeZones(); freeAnimations(); // this dangerous flag can now be cleared - _vm->_quit = false; + _engineFlags &= ~kEngineQuit; // main character animation is restored _location._animations.push_front(_char._ani); _score = 0; + _soundMan->stopMusic(); + _introSarcData3 = 200; + _introSarcData2 = 1; + return; } diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index 8e30a631e4..a475f5701a 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -183,13 +183,12 @@ uint16 Script::readLineToken(bool errorOnEOF) { clearTokens(); - bool inBlockComment = false, inLineComment; + bool inBlockComment = false; char buf[200]; char *line = NULL; + char *start; do { - inLineComment = false; - line = readLine(buf, 200); if (line == NULL) { @@ -198,21 +197,27 @@ uint16 Script::readLineToken(bool errorOnEOF) { else return 0; } - line = Common::ltrim(line); + start = Common::ltrim(line); - if (isCommentLine(line)) { - inLineComment = true; + if (isCommentLine(start)) { + // ignore this line + start[0] = '\0'; } else - if (isStartOfCommentBlock(line)) { + if (isStartOfCommentBlock(start)) { + // mark this and the following lines as comment inBlockComment = true; } else - if (isEndOfCommentBlock(line)) { + if (isEndOfCommentBlock(start)) { + // comment is finished, so stop ignoring inBlockComment = false; + // the current line must be skipped, though, + // as it contains the end-of-comment marker + start[0] = '\0'; } - } while (inLineComment || inBlockComment || strlen(line) == 0); + } while (inBlockComment || strlen(start) == 0); - return fillTokens(line); + return fillTokens(start); } @@ -403,7 +408,9 @@ void PreProcessor::preprocessScript(Script &script, StatementList &list) { break; StatementDef *def = findDef(_tokens[0]); - assert(def); + if (!def) { + error("PreProcessor::preprocessScript: unknown statement '%s' found\n", _tokens[0]); + } text = def->makeLine(script); int score = getDefScore(def); diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index e622bfd81f..7bf41b2bea 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -27,6 +27,7 @@ #define PARALLACTION_PARSER_H #include "common/stream.h" +#include "common/stack.h" #include "parallaction/objects.h" #include "parallaction/walk.h" diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 20800abc33..4b11c5caa4 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -497,7 +497,7 @@ DECLARE_LOCATION_PARSER(zeta) { _vm->_location._zeta1 = atoi(_tokens[2]); if (_tokens[3][0] != '\0') { - _vm->_location._zeta2 = atoi(_tokens[1]); + _vm->_location._zeta2 = atoi(_tokens[3]); } else { _vm->_location._zeta2 = 50; } diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index ed3812e5be..5620001d7d 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -31,6 +31,7 @@ #include "gui/message.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -57,12 +58,11 @@ protected: GUI::StaticTextWidget *_time; GUI::StaticTextWidget *_playtime; GUI::ContainerWidget *_container; - Parallaction_ns *_vm; uint8 _fillR, _fillG, _fillB; public: - SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine); + SaveLoadChooser(const String &title, const String &buttonLabel); ~SaveLoadChooser(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); @@ -73,34 +73,39 @@ public: virtual void reflowLayout(); }; -Common::String Parallaction_ns::genSaveFileName(uint slot, bool oldStyle) { +Common::String SaveLoad_ns::genOldSaveFileName(uint slot) { assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); char s[20]; - sprintf(s, (oldStyle ? "game.%i" : "nippon.%.3d"), slot ); + sprintf(s, "game.%i", slot); return Common::String(s); } -Common::InSaveFile *Parallaction_ns::getInSaveFile(uint slot) { + +Common::String SaveLoad::genSaveFileName(uint slot) { + assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); + + char s[20]; + sprintf(s, "%s.%.3d", _saveFilePrefix.c_str(), slot); + + return Common::String(s); +} + +Common::InSaveFile *SaveLoad::getInSaveFile(uint slot) { Common::String name = genSaveFileName(slot); return _saveFileMan->openForLoading(name.c_str()); } -Common::OutSaveFile *Parallaction_ns::getOutSaveFile(uint slot) { +Common::OutSaveFile *SaveLoad::getOutSaveFile(uint slot) { Common::String name = genSaveFileName(slot); return _saveFileMan->openForSaving(name.c_str()); } -void Parallaction_ns::doLoadGame(uint16 slot) { - - _soundMan->stopMusic(); +void SaveLoad_ns::doLoadGame(uint16 slot) { - cleanupGame(); - - _introSarcData3 = 200; - _introSarcData2 = 1; + _vm->cleanupGame(); Common::InSaveFile *f = getInSaveFile(slot); if (!f) return; @@ -116,10 +121,10 @@ void Parallaction_ns::doLoadGame(uint16 slot) { f->readLine(l, 15); f->readLine(s, 15); - _location._startPosition.x = atoi(s); + _vm->_location._startPosition.x = atoi(s); f->readLine(s, 15); - _location._startPosition.y = atoi(s); + _vm->_location._startPosition.y = atoi(s); f->readLine(s, 15); _score = atoi(s); @@ -132,28 +137,26 @@ void Parallaction_ns::doLoadGame(uint16 slot) { // TODO (LIST): unify (and parametrize) calls to freeZones. // We aren't calling freeAnimations because it is not needed, since // kChangeLocation will trigger a complete deletion. Anyway, we still - // need to invoke freeZones here with _quit set, because the + // need to invoke freeZones here with kEngineQuit set, because the // call in changeLocation preserve certain zones. - _quit = true; - - freeZones(); - - _quit = false; + _engineFlags |= kEngineQuit; + _vm->freeZones(); + _engineFlags &= ~kEngineQuit; - _numLocations = atoi(s); + _vm->_numLocations = atoi(s); uint16 _si; - for (_si = 0; _si < _numLocations; _si++) { + for (_si = 0; _si < _vm->_numLocations; _si++) { f->readLine(s, 20); s[strlen(s)] = '\0'; - strcpy(_locationNames[_si], s); + strcpy(_vm->_locationNames[_si], s); f->readLine(s, 15); - _localFlags[_si] = atoi(s); + _vm->_localFlags[_si] = atoi(s); } - cleanInventory(false); + _vm->cleanInventory(false); ItemName name; uint32 value; @@ -164,24 +167,24 @@ void Parallaction_ns::doLoadGame(uint16 slot) { f->readLine(s, 15); name = atoi(s); - addInventoryItem(name, value); + _vm->addInventoryItem(name, value); } delete f; // force reload of character to solve inventory // bugs, but it's a good maneuver anyway - strcpy(_characterName1, "null"); + strcpy(_vm->_characterName1, "null"); char tmp[PATH_LEN]; sprintf(tmp, "%s.%s" , l, n); - scheduleLocationSwitch(tmp); + _vm->scheduleLocationSwitch(tmp); return; } -void Parallaction_ns::doSaveGame(uint16 slot, const char* name) { +void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) { Common::OutSaveFile *f = getOutSaveFile(slot); if (f == 0) { @@ -204,30 +207,30 @@ void Parallaction_ns::doSaveGame(uint16 slot, const char* name) { f->writeString(s); f->writeString("\n"); - sprintf(s, "%s\n", _char.getFullName()); + sprintf(s, "%s\n", _vm->_char.getFullName()); f->writeString(s); sprintf(s, "%s\n", _saveData1); f->writeString(s); - sprintf(s, "%d\n", _char._ani->getX()); + sprintf(s, "%d\n", _vm->_char._ani->getX()); f->writeString(s); - sprintf(s, "%d\n", _char._ani->getY()); + sprintf(s, "%d\n", _vm->_char._ani->getY()); f->writeString(s); sprintf(s, "%d\n", _score); f->writeString(s); sprintf(s, "%u\n", _globalFlags); f->writeString(s); - sprintf(s, "%d\n", _numLocations); + sprintf(s, "%d\n", _vm->_numLocations); f->writeString(s); - for (uint16 _si = 0; _si < _numLocations; _si++) { - sprintf(s, "%s\n%u\n", _locationNames[_si], _localFlags[_si]); + for (uint16 _si = 0; _si < _vm->_numLocations; _si++) { + sprintf(s, "%s\n%u\n", _vm->_locationNames[_si], _vm->_localFlags[_si]); f->writeString(s); } const InventoryItem *item; for (uint16 _si = 0; _si < 30; _si++) { - item = getInventoryItem(_si); + item = _vm->getInventoryItem(_si); sprintf(s, "%u\n%d\n", item->_id, item->_index); f->writeString(s); } @@ -249,8 +252,8 @@ enum { }; -SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine) - : Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) { +SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel) + : Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0) { // _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR; @@ -337,7 +340,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -int Parallaction_ns::buildSaveFileList(Common::StringList& l) { +int SaveLoad_ns::buildSaveFileList(Common::StringList& l) { char buf[200]; @@ -361,9 +364,9 @@ int Parallaction_ns::buildSaveFileList(Common::StringList& l) { } -int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { +int SaveLoad_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { - SaveLoadChooser* slc = new SaveLoadChooser(caption, button, this); + SaveLoadChooser* slc = new SaveLoadChooser(caption, button); Common::StringList l; @@ -382,7 +385,7 @@ int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const cha -bool Parallaction_ns::loadGame() { +bool SaveLoad_ns::loadGame() { int _di = selectSaveFile( 0, "Load file", "Load" ); if (_di == -1) { @@ -394,15 +397,15 @@ bool Parallaction_ns::loadGame() { GUI::TimedMessageDialog dialog("Loading game...", 1500); dialog.runModal(); - setArrowCursor(); + _vm->_input->setArrowCursor(); return true; } -bool Parallaction_ns::saveGame() { +bool SaveLoad_ns::saveGame() { - if (!scumm_stricmp(_location._name, "caveau")) { + if (!scumm_stricmp(_vm->_location._name, "caveau")) { return false; } @@ -420,7 +423,7 @@ bool Parallaction_ns::saveGame() { } -void Parallaction_ns::setPartComplete(const Character& character) { +void SaveLoad_ns::setPartComplete(const char *part) { char buf[30]; bool alreadyPresent = false; @@ -431,7 +434,7 @@ void Parallaction_ns::setPartComplete(const Character& character) { inFile->readLine(buf, 29); delete inFile; - if (strstr(buf, character.getBaseName())) { + if (strstr(buf, part)) { alreadyPresent = true; } } @@ -439,7 +442,7 @@ void Parallaction_ns::setPartComplete(const Character& character) { if (!alreadyPresent) { Common::OutSaveFile *outFile = getOutSaveFile(SPECIAL_SAVESLOT); outFile->writeString(buf); - outFile->writeString(character.getBaseName()); + outFile->writeString(part); outFile->finalize(); delete outFile; } @@ -447,17 +450,20 @@ void Parallaction_ns::setPartComplete(const Character& character) { return; } -bool Parallaction_ns::allPartsComplete() { - char buf[30]; +void SaveLoad_ns::getGamePartProgress(bool *complete, int size) { + assert(complete && size >= 3); + char buf[30]; Common::InSaveFile *inFile = getInSaveFile(SPECIAL_SAVESLOT); inFile->readLine(buf, 29); delete inFile; - return strstr(buf, "dino") && strstr(buf, "donna") && strstr(buf, "dough"); + complete[0] = strstr(buf, "dino"); + complete[1] = strstr(buf, "donna"); + complete[2] = strstr(buf, "dough"); } -void Parallaction_ns::renameOldSavefiles() { +void SaveLoad_ns::renameOldSavefiles() { bool exists[NUM_SAVESLOTS]; uint num = 0; @@ -465,7 +471,7 @@ void Parallaction_ns::renameOldSavefiles() { for (i = 0; i < NUM_SAVESLOTS; i++) { exists[i] = false; - Common::String name = genSaveFileName(i, true); + Common::String name = genOldSaveFileName(i); Common::InSaveFile *f = _saveFileMan->openForLoading(name.c_str()); if (f) { exists[i] = true; @@ -493,8 +499,8 @@ void Parallaction_ns::renameOldSavefiles() { uint success = 0; for (i = 0; i < NUM_SAVESLOTS; i++) { if (exists[i]) { - Common::String oldName = genSaveFileName(i, true); - Common::String newName = genSaveFileName(i, false); + Common::String oldName = genOldSaveFileName(i); + Common::String newName = genSaveFileName(i); if (_saveFileMan->renameSavefile(oldName.c_str(), newName.c_str())) { success++; } else { @@ -520,4 +526,28 @@ void Parallaction_ns::renameOldSavefiles() { } +bool SaveLoad_br::loadGame() { + // TODO: implement loadgame + return false; +} + +bool SaveLoad_br::saveGame() { + // TODO: implement savegame + return false; +} + +void SaveLoad_br::getGamePartProgress(bool *complete, int size) { + assert(complete && size >= 3); + + // TODO: implement progress loading + + complete[0] = true; + complete[1] = true; + complete[2] = true; +} + +void SaveLoad_br::setPartComplete(const char *part) { + // TODO: implement progress saving +} + } // namespace Parallaction diff --git a/engines/parallaction/saveload.h b/engines/parallaction/saveload.h new file mode 100644 index 0000000000..10bb8aafc2 --- /dev/null +++ b/engines/parallaction/saveload.h @@ -0,0 +1,96 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + + +#ifndef PARALLACTION_SAVELOAD_H +#define PARALLACTION_SAVELOAD_H + +namespace Parallaction { + +struct Character; + + +class SaveLoad { + +protected: + Common::SaveFileManager *_saveFileMan; + Common::String _saveFilePrefix; + + Common::String genSaveFileName(uint slot); + Common::InSaveFile *getInSaveFile(uint slot); + Common::OutSaveFile *getOutSaveFile(uint slot); + +public: + SaveLoad(Common::SaveFileManager* saveFileMan, const char *prefix) : _saveFileMan(saveFileMan), _saveFilePrefix(prefix) { } + virtual ~SaveLoad() { } + + virtual bool loadGame() = 0; + virtual bool saveGame() = 0; + virtual void getGamePartProgress(bool *complete, int size) = 0; + virtual void setPartComplete(const char *part) = 0; + + virtual void renameOldSavefiles() { } +}; + +class SaveLoad_ns : public SaveLoad { + + Parallaction_ns *_vm; + + Common::String _saveFileName; + Common::String genOldSaveFileName(uint slot); + +protected: + void renameOldSavefiles(); + void doLoadGame(uint16 slot); + void doSaveGame(uint16 slot, const char* name); + int buildSaveFileList(Common::StringList& l); + int selectSaveFile(uint16 arg_0, const char* caption, const char* button); + +public: + SaveLoad_ns(Parallaction_ns *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "nippon"), _vm(vm) { } + + virtual bool loadGame(); + virtual bool saveGame(); + virtual void getGamePartProgress(bool *complete, int size); + virtual void setPartComplete(const char *part); +}; + +class SaveLoad_br : public SaveLoad { + + Parallaction_br *_vm; + +public: + SaveLoad_br(Parallaction_br *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "bra"), _vm(vm) { } + + virtual bool loadGame(); + virtual bool saveGame(); + virtual void getGamePartProgress(bool *complete, int size); + virtual void setPartComplete(const char *part); +}; + + +} // namespace Parallaction + +#endif diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp index 4ac1399c3a..df6867a90c 100644 --- a/engines/parallaction/sound.cpp +++ b/engines/parallaction/sound.cpp @@ -387,8 +387,7 @@ void AmigaSoundMan::playSfx(const char *filename, uint channel, bool looping, in rate = ch->header.samplesPerSec; } - _mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, rate, flags, -1, - Audio::Mixer::kMaxChannelVolume, 0, loopStart, loopEnd); + _mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, rate, flags, -1, volume, 0, loopStart, loopEnd); } void AmigaSoundMan::stopSfx(uint channel) { diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp index 2c5cf281dd..071495e8f1 100644 --- a/engines/parallaction/staticres.cpp +++ b/engines/parallaction/staticres.cpp @@ -29,7 +29,7 @@ namespace Parallaction { -byte Parallaction_ns::_resMouseArrow[256] = { +byte Input::_resMouseArrow_NS[256] = { 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, @@ -335,12 +335,6 @@ const Parallaction_br::Callable Parallaction_br::_dosCallables[] = { void Parallaction_ns::initResources() { -// _zoneFlagNamesRes = _zoneFlagNamesRes_ns; -// _zoneTypeNamesRes = _zoneTypeNamesRes_ns; -// _commandsNamesRes = _commandsNamesRes_ns; - _callableNamesRes = _callableNamesRes_ns; -// _instructionNamesRes = _instructionNamesRes_ns; - _callableNames = new Table(ARRAYSIZE(_callableNamesRes_ns), _callableNamesRes_ns); _localFlagNames = new FixedTable(NUM_LOCATIONS, 1); @@ -356,13 +350,6 @@ void Parallaction_ns::initResources() { void Parallaction_br::initResources() { -// _zoneFlagNamesRes = _zoneFlagNamesRes_br; -// _zoneTypeNamesRes = _zoneTypeNamesRes_br; -// _commandsNamesRes = _commandsNamesRes_br; - _callableNamesRes = _callableNamesRes_br; -// _instructionNamesRes = _instructionNamesRes_br; -// _audioCommandsNamesRes = _audioCommandsNamesRes_br; - _callableNames = new Table(ARRAYSIZE(_callableNamesRes_br), _callableNamesRes_br); _localFlagNames = new FixedTable(NUM_LOCATIONS, 2); diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index 6513a92018..ccaac8227d 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -54,10 +54,27 @@ namespace Queen { class AudioStreamWrapper : public Audio::AudioStream { protected: Audio::AudioStream *_stream; + int _rate; public: AudioStreamWrapper(Audio::AudioStream *stream) { _stream = stream; + + int rate = _stream->getRate(); + + // A file where the sample rate claims to be 11025 Hz is + // probably compressed with the old tool. We force the real + // sample rate, which is 11840 Hz. + // + // However, a file compressed with the newer tool is not + // guaranteed to have a sample rate of 11840 Hz. LAME will + // automatically resample it to 12000 Hz. So in all other + // cases, we use the rate from the file. + + if (rate == 11025) + _rate = 11840; + else + _rate = rate; } ~AudioStreamWrapper() { delete _stream; @@ -75,7 +92,7 @@ public: return _stream->endOfStream(); } int getRate() const { - return 11840; + return _rate; } int32 getTotalPlayTime() { return _stream->getTotalPlayTime(); @@ -314,10 +331,8 @@ void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *so if (sound) { f->read(sound, size); byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; - if (soundHandle == &_speechHandle) - _mixer->playRaw(Audio::Mixer::kSpeechSoundType, soundHandle, sound, size, 11025, flags); - else - _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11025, flags); + Audio::Mixer::SoundType type = (soundHandle == &_speechHandle) ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType; + _mixer->playRaw(type, soundHandle, sound, size, 11840, flags); } } diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 1005b0ab5f..9b0efad0d5 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -249,6 +249,8 @@ void MusicPlayer::setVolume(int volume) { _masterVolume = volume; + Common::StackLock lock(_mutex); + for (int i = 0; i < 16; ++i) { if (_channel[i]) { _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index a2dbeebda2..aa3624acea 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -247,13 +247,20 @@ int SagaEngine::go() { _interface->addToInventory(_actor->objIndexToId(0)); // Magic hat _scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade); } else if (ConfMan.hasKey("save_slot")) { + // Init the current chapter to 8 (character selection) for IHNM + if (getGameType() == GType_IHNM) + _scene->changeScene(-2, 0, kTransitionFade, 8); + // First scene sets up palette _scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade); _events->handleEvents(0); // Process immediate events - _interface->setMode(kPanelMain); - char *fileName; - fileName = calcSaveFileName(ConfMan.getInt("save_slot")); + if (getGameType() != GType_IHNM) + _interface->setMode(kPanelMain); + else + _interface->setMode(kPanelChapterSelection); + + char *fileName = calcSaveFileName(ConfMan.getInt("save_slot")); load(fileName); syncSoundSettings(); } else { diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index 9a304de8e1..e1e1074e1d 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -276,31 +276,14 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) { if (obj->_sceneNumber != ITE_SCENE_INV) { obj->_sceneNumber = ITE_SCENE_INV; - // WORKAROUND for a problematic object in IHNM - // There are 3 different scenes in front of the zeppelin, in Gorrister's chapter. A scene where the - // zeppelin is in the air (scene 17), a scene where it approaches Gorrister's (scene 16) and another one - // where it has landed (scene 18). - // In two of these scenes (the "on air" and "approaching" ones), when the player uses the knife with the - // rope, the associated script picks up object id 16392. In the "zeppelin landed" scene (scene 18), the - // associated script picks up object id 16390. This seems to be a script bug, as it should be id 16392, - // like in the other two scenes, as it is the same object (the rope). Picking up object 16390 leads to an - // assertion anyway, therefore we change the problematic object (16390) to the correct one (16392) here. - // Fixes bug #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring" - if (_vm->getGameType() == GType_IHNM) { - if (_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 18) { - if (objectId == 16390) - objectId = 16392; - } - } - - // WORKAROUND for two incorrect object sprites in the IHNM demo - // (the mirror and the icon in Ted's part). Set them correctly here - if (_vm->getGameId() == GID_IHNM_DEMO) { - if (objectId == 16408) - obj->_spriteListResourceId = 24; - if (objectId == 16409) - obj->_spriteListResourceId = 25; - } + // Normally, when objects are picked up, they should always have the same + // _spriteListResourceId as their _index value. Some don't in IHNM, so + // we fix their sprite here + // Fixes bugs #2057200 - "IHNM: Invisible inventory objects", + // #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring" + // and some incorrect objects in the IHNM demo + if (_vm->getGameType() == GType_IHNM) + obj->_spriteListResourceId = obj->_index; _vm->_interface->addToInventory(objectId); } diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index 324cc91e78..d281364a77 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -472,12 +472,14 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "fbear", "fbdemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "fbear", "Fatty Bear Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "fbear", "Fatty Bear", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, + { "fbear", "jfbear", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 }, { "puttmoon", "puttmoon", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttmoon", "moondemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttmoon", "Putt-Putt Moon Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttmoon", "Putt-Putt Moon", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, + { "puttputt", "jputtputt", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 }, { "puttputt", "puttputt", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttputt", "puttdemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttputt", "Putt-Putt's Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index b590bba65e..41fe43835f 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -395,8 +395,7 @@ void SaveLoadChooser::updateInfos(bool redraw) { int hours = minutes / 60; minutes %= 60; - snprintf(buffer, 32, "Playtime: %.2d:%.2d", - hours & 0xFF, minutes & 0xFF); + snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours, minutes); _playtime->setLabel(buffer); } else { _date->setLabel("No date saved"); diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index d09accafb0..45b078b6f9 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -46,7 +46,7 @@ namespace Scumm { static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); static void fill(byte *dst, int dstPitch, byte color, int w, int h); -#ifndef ARM_USE_GFX_ASM +#ifndef USE_ARM_GFX_ASM static void copy8Col(byte *dst, int dstPitch, const byte *src, int height); #endif static void clear8Col(byte *dst, int dstPitch, int height); @@ -612,32 +612,37 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i assert(0 == (width & 3)); // Compose the text over the game graphics - - // TODO: Optimize this code. There are several things that come immediately to mind: - // (1) Loop unrolling: We could read 4 or even 8 pixels at once, since everything is - // a multiple of 8 here. - // (2) More ASM versions (in particular, the ARM code for the NDS could be used on - // all ARM systems, couldn't it?) - // (3) Better encoding of the text surface data. This is the one with the biggest - // potential. - // (a) Keep an "isEmpty" marker for each pixel row in the _textSurface. The idea - // is that most rows won't contain any text data, so we can just use memcpy. - // (b) RLE encode the _textSurface row-wise. This is an improved variant of (a), - // but also more complicated to implement, and incurs a bigger overhead when - // writing to the text surface. -#ifdef ARM_USE_GFX_ASM +#ifdef USE_ARM_GFX_ASM asmDrawStripToScreen(height, width, text, src, dst, vs->pitch, width, _textSurface.pitch); #else - for (int h = 0; h < height * m; ++h) { - for (int w = 0; w < width * m; ++w) { - byte tmp = *text++; - if (tmp == CHARSET_MASK_TRANSPARENCY) - tmp = *src; - *dst++ = tmp; - src++; + // We blit four pixels at a time, for improved performance. + const uint32 *src32 = (const uint32 *)src; + const uint32 *text32 = (const uint32 *)text; + uint32 *dst32 = (uint32 *)dst; + + vsPitch >>= 2; + const int textPitch = (_textSurface.pitch - width * m) >> 2; + for (int h = height * m; h > 0; --h) { + for (int w = width*m; w > 0; w-=4) { + uint32 temp = *text32++; + + // Generate a byte mask for those text pixels (bytes) with + // value CHARSET_MASK_TRANSPARENCY. In the end, each byte + // in mask will be either equal to 0x00 or 0xFF. + // Doing it this way avoids branches and bytewise operations, + // at the cost of readability ;). + uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; + mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; + mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; + + // The following line is equivalent to this code: + // *dst32++ = (*src32++ & mask) | (temp & ~mask); + // However, some compilers can generate somewhat better + // machine code for this equivalent statement: + *dst32++ = ((temp ^ *src32++) & mask) ^ temp; } - src += vsPitch; - text += _textSurface.pitch - width * m; + src32 += vsPitch; + text32 += textPitch; } #endif src = _compositeBuf; @@ -1078,7 +1083,7 @@ static void fill(byte *dst, int dstPitch, byte color, int w, int h) { } } -#ifdef ARM_USE_GFX_ASM +#ifdef USE_ARM_GFX_ASM #define copy8Col(A,B,C,D) asmCopy8Col(A,B,C,D) @@ -1098,7 +1103,7 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) { } while (--height); } -#endif /* ARM_USE_GFX_ASM */ +#endif /* USE_ARM_GFX_ASM */ static void clear8Col(byte *dst, int dstPitch, int height) { do { diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index e03fdd1c53..e4c1054450 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -174,7 +174,8 @@ struct ColorCycle { struct StripTable; -#define CHARSET_MASK_TRANSPARENCY 253 +#define CHARSET_MASK_TRANSPARENCY 0xFD +#define CHARSET_MASK_TRANSPARENCY_32 0xFDFDFDFD class Gdi { protected: diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s index 83aaa78927..f3a1f20303 100644 --- a/engines/scumm/gfxARM.s +++ b/engines/scumm/gfxARM.s @@ -24,7 +24,7 @@ .global asmDrawStripToScreen .global asmCopy8Col - + @ ARM implementation of asmDrawStripToScreen. @ @ C prototype would be: @@ -47,7 +47,7 @@ asmDrawStripToScreen: @ r2 = text @ r3 = src MOV r12,r13 - STMFD r13!,{r4-r7,r9-r11,R14} + STMFD r13!,{r4-r11,R14} LDMIA r12,{r4,r5,r6,r7} @ r4 = dst @ r5 = vsPitch @@ -69,57 +69,46 @@ asmDrawStripToScreen: MOV r10,#253 ORR r10,r10,r10,LSL #8 ORR r10,r10,r10,LSL #16 @ r10 = mask -yLoop: - MOV r14,r1 @ r14 = width + MOV r8,#0x7F + ORR r8, r8, r8, LSL #8 + ORR r8, r8, r8, LSL #16 @ r8 = 7f7f7f7f + STR r1,[r13,#-4]! @ Stack width + B xLoop + +notEntirelyTransparent: + AND r14,r9, r8 @ r14 = mask & 7f7f7f7f + ADD r14,r14,r8 @ r14 = (mask & 7f7f7f7f)+7f7f7f7f + ORR r14,r14,r9 @ r14 |= mask + BIC r14,r14,r8 @ r14 &= 80808080 + ADD r14,r8, r14,LSR #7 @ r14 = (rx>>7) + 7f7f7f7f + EOR r14,r14,r8 @ r14 ^= 7f7f7f7f + @ So bytes of r14 are 00 where source was matching value,FF otherwise + BIC r11,r11,r14 + AND r12,r12,r14 + ORR r12,r11,r12 + STR r12,[r4],#4 + SUBS r1,r1,#4 + BLE endXLoop xLoop: - LDR r12,[r2],#4 @ r12 = [text] - LDR r11,[r3],#4 @ r11 = [src] - CMP r12,r10 - BNE singleByteCompare - SUBS r14,r14,#4 + LDR r12,[r2],#4 @ r12 = temp = [text] + LDR r11,[r3],#4 @ r11 = [src] + @ Stall + EORS r9, r12,r10 @ r9 = mask = temp ^ TRANSPARENCY + BNE notEntirelyTransparent + SUBS r1, r1, #4 STR r11,[r4], #4 @ r4 = [dst] BGT xLoop - +endXLoop: ADD r2,r2,r7 @ text += textSurfacePitch ADD r3,r3,r5 @ src += vsPitch ADD r4,r4,r6 @ dst += vmScreenWidth SUBS r0,r0,#1 - BGT yLoop - LDMFD r13!,{r4-r7,r9-r11,PC} - -singleByteCompare: - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - STR r12,[r4],#4 - SUBS r14,r14,#4 + LDRGT r1,[r13] @ r14 = width BGT xLoop - - ADD r2,r2,r7 @ text += textSurfacePitch - ADD r3,r3,r5 @ src += vsPitch - ADD r4,r4,r6 @ dst += vmScreenWidth - SUBS r0,r0,#1 - BGT yLoop + ADD r13,r13,#4 end: - LDMFD r13!,{r4-r7,r9-r11,PC} - + LDMFD r13!,{r4-r11,PC} + @ ARM implementation of asmCopy8Col @ @ C prototype would be: @@ -156,4 +145,4 @@ roll2: STR r14,[r0],r1 BNE yLoop2 - LDMFD r13!,{PC} + LDMFD r13!,{PC} diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 7d52a02116..b86ad8159b 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -53,7 +53,6 @@ MODULE_OBJS := \ scumm.o \ sound.o \ string.o \ - thumbnail.o \ usage_bits.o \ util.o \ vars.o \ diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 9823a9483f..36621440eb 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -809,7 +809,7 @@ byte *ResourceManager::createResource(int type, int idx, uint32 size) { ptr = (byte *)calloc(size + sizeof(MemBlkHeader) + SAFETY_AREA, 1); if (ptr == NULL) { - error("Out of memory while allocating %d", size); + error("createResource(%s,%d): Out of memory while allocating %d", resTypeFromId(type), idx, size); } _allocatedSize += size; diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 426c7ee48b..eb7cf1ba56 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -46,6 +46,8 @@ #include "sound/audiocd.h" #include "sound/mixer.h" +#include "graphics/thumbnail.h" + namespace Scumm { struct SaveGameHeader { @@ -71,6 +73,22 @@ struct SaveInfoSection { #define INFOSECTION_VERSION 2 +Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) { + if (!Graphics::checkThumbnailHeader(*file)) + return 0; + + Graphics::Surface *thumb = new Graphics::Surface(); + assert(thumb); + if (!Graphics::loadThumbnail(*file, *thumb)) { + delete thumb; + return 0; + } + + return thumb; +} + +#pragma mark - + void ScummEngine::requestSave(int slot, const char *name, bool temporary) { _saveLoadSlot = slot; _saveTemporaryState = temporary; @@ -114,7 +132,9 @@ bool ScummEngine::saveState(int slot, bool compat) { memcpy(hdr.name, _saveLoadName, sizeof(hdr.name)); saveSaveGameHeader(out, hdr); - saveThumbnail(out); +#if !defined(__DS__) + Graphics::saveThumbnail(*out); +#endif saveInfos(out); Serializer ser(0, out, CURRENT_VER); @@ -185,16 +205,16 @@ bool ScummEngine::loadState(int slot, bool compat) { // Since version 52 a thumbnail is saved directly after the header. if (hdr.ver >= VER(52)) { - uint32 type = in->readUint32BE(); - // Check for the THMB header. Also, work around a bug which caused - // the chunk type (incorrectly) to be written in LE on LE machines. - if (! (type == MKID_BE('THMB') || (hdr.ver < VER(55) && type == MKID_BE('BMHT')))){ - warning("Can not load thumbnail"); - delete in; - return false; + // Prior to version 75 we always required an thumbnail to be present + if (hdr.ver <= VER(74)) { + if (!Graphics::checkThumbnailHeader(*in)) { + warning("Can not load thumbnail"); + delete in; + return false; + } } - uint32 size = in->readUint32BE(); - in->skip(size - 8); + + Graphics::skipThumbnailHeader(*in); } // Since version 56 we save additional information about the creation of diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 2d7ee64680..4f9899f961 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 74 +#define CURRENT_VER 75 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index 245dca883a..c8534396db 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -2374,7 +2374,7 @@ void ScummEngine_v6::o6_printEgo() { void ScummEngine_v6::o6_talkActor() { int offset = _scriptPointer - _scriptOrgPointer; - // WORKAROUNDfor bug #896489: see below for detailed description + // WORKAROUND for bug #896489: see below for detailed description if (_forcedWaitForMessage) { if (VAR(VAR_HAVE_MSG)) { _scriptPointer--; diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index ce8f0a4d9a..eec9d33903 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 Mon Jul 28 00:13:01 2008 + This file was generated by the md5table tool on Tue Aug 26 11:12:54 2008 DO NOT EDIT MANUALLY! */ @@ -54,6 +54,7 @@ static const MD5Table md5table[] = { { "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", 30919, Common::EN_USA, Common::kPlatformWindows }, { "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", 9080, Common::DE_DEU, Common::kPlatformUnknown }, { "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "100b4c8403ad6a83d4bf7dbf83e44dc4", "spyfox", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, @@ -63,6 +64,7 @@ static const MD5Table md5table[] = { { "11e6e244078ff09b0f3832e35420e0a7", "catalog", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "132bff65e6367c09cc69318ce1b59333", "monkey2", "", "", 11155, Common::EN_ANY, Common::kPlatformAmiga }, { "1387d16aa620dc1c2d1fd87f8a9e7a09", "puttcircus", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, + { "13d2a86a7290813a1c386490447d72db", "fbear", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "145bd3373574feb668cc2eea2ec6cf86", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "14d48c95b43ddeb983254cf6c43851f1", "freddi4", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "151071053a1d0021198216713939521d", "freddi2", "HE 80", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -98,6 +100,7 @@ static const MD5Table md5table[] = { { "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "", -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 }, { "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, @@ -106,6 +109,7 @@ static const MD5Table md5table[] = { { "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "22d07d6c386c9c25aca5dac2a0c0d94b", "maniac", "NES", "", 262144, Common::SE_SWE, Common::kPlatformNES }, + { "22de86b2f7ec6e5db745ed1123310b44", "spyfox2", "", "Demo", 15832, Common::FR_FRA, Common::kPlatformWindows }, { "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 }, @@ -144,6 +148,7 @@ static const MD5Table md5table[] = { { "362c1d281fb9899254cda66ad246c66a", "dig", "Demo", "Demo", 3472, Common::EN_ANY, Common::kPlatformUnknown }, { "3686cf8f89e102ececf4366e1d2c8126", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformPC }, { "36a6750e03fb505fc19fc2bf3e4dbe91", "pajama2", "", "Demo", 58749, Common::EN_ANY, Common::kPlatformUnknown }, + { "3769b56c9a22f5521d74525ee459f88d", "puttrace", "HE 99", "Demo", 13108, Common::DE_DEU, Common::kPlatformWindows }, { "37aed3f91c1ef959e0bd265f9b13781f", "pajama", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "37f56ceb13e401a7ac7d9e6b37fecaf7", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformPC }, { "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows }, @@ -201,6 +206,7 @@ static const MD5Table md5table[] = { { "4edbf9d03550f7ba01e7f34d69b678dd", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "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 }, { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, { "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -272,6 +278,7 @@ static const MD5Table md5table[] = { { "6b27dbcd8d5697d5c918eeca0f68ef6a", "puttrace", "HE CUP", "Preview", 3901484, Common::UNK_LANG, Common::kPlatformUnknown }, { "6b3ec67da214f558dc5ceaa2acd47453", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "6b5a3fef241e90d4b2e77f1e222773ee", "maniac", "NES", "extracted", -1, Common::SE_SWE, Common::kPlatformNES }, + { "6bca7a1a96d16e52b8f3c42b50dbdca3", "fbear", "HE 61", "", -1, Common::JA_JPN, Common::kPlatform3DO }, { "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 }, @@ -296,14 +303,17 @@ static const MD5Table md5table[] = { { "73e5ab7dbb9a8061cc6d25df02dbd1e7", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "7410a8ba9795020cd42f171c4320659e", "pajama3", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "746e88c172a5b7a1ae89ac0ee3ee681a", "freddi", "HE 90", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, + { "74da3494fbe1a7d20213b0afe0954755", "catalog", "HE CUP", "Preview", 10841544, Common::FR_FRA, Common::kPlatformUnknown }, { "754feb59d3bf86b8a00840df74fd7b26", "freddi3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "75bff95816b84672b877d22a911ab811", "freddi3", "HE 99", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, { "76b66b43e593ad4d2f1dfb5cc8f19700", "spyfox", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "771bc18ec6f93837b839c992b211904b", "monkey", "Demo", "EGA Demo", -1, Common::DE_DEU, Common::kPlatformPC }, + { "7766c9487f9d53a8cb0edabda5119c3d", "puttputt", "HE 60", "", 8022, Common::EN_ANY, Common::kPlatformPC }, { "77f5c9cc0986eb729c1a6b4c8823bbae", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "780e4a0ae2ff17dc296f4a79543b44f8", "puttmoon", "", "", -1, Common::UNK_LANG, Common::kPlatformPC }, { "782393c5934ecd0b536eaf5fd541bd26", "pajama", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "784b499c98d07260a30952685758636b", "pajama3", "", "Demo", 13911, Common::DE_DEU, Common::kPlatformWindows }, { "78bd5f036ea35a878b74e4f47941f784", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformPC }, @@ -322,6 +332,7 @@ static const MD5Table md5table[] = { { "81bbfa181184cb494e7a81dcfa94fbd9", "maniac", "NES", "", 262144, Common::FR_FRA, Common::kPlatformNES }, { "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "V2", "Demo", 1916, Common::EN_ANY, Common::kPlatformAtariST }, { "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, + { "839a658f7d22de00787ebc945348cdb6", "dog", "", "", 19681, Common::DE_DEU, Common::kPlatformWindows }, { "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "84e3c23a49ded8a6f9197735c8eb3de7", "PuttTime", "HE 85", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "8539c0ff89868e55a08e652ac44daaae", "water", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -429,7 +440,9 @@ static const MD5Table md5table[] = { { "b886b0a5d909c7158a914e1d7c1c6c65", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformPC }, { "b8955d7d23b4972229060d1592489fef", "freddicove", "HE 100", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "b9ba19ce376efc69be78ef3baef8d2b9", "monkey", "CD", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "b9bb68c5d2c9b6e2d9c513a29a754a57", "puttmoon", "", "", 7828, Common::EN_ANY, Common::kPlatformPC }, { "ba888e6831517597859e91aa173f945c", "spyfox", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "bab0fb81dcb12b8930c5d850b8f2a7de", "balloon", "HE 80", "", 12800, Common::DE_DEU, Common::kPlatformWindows }, { "bbadf7309c4a2c2763e4bbba3c3be634", "freddi3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "bc4700bc0e12879f6d25d14d6be6cfdd", "spyfox2", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "bd126753de619a495f9f22adc951c8d5", "monkey2", "", "", -1, Common::IT_ITA, Common::kPlatformPC }, @@ -546,6 +559,7 @@ static const MD5Table md5table[] = { { "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "", "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 }, { "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 054a1f59b9..3667e5770d 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -632,9 +632,9 @@ public: protected: Graphics::Surface *loadThumbnail(Common::SeekableReadStream *file); - bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff); - void saveThumbnail(Common::WriteStream *file); + void saveInfos(Common::WriteStream* file); + bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff); int32 _engineStartTime; int32 _pauseStartTime; diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp index 850b547021..e4d8393dbe 100644 --- a/engines/scumm/smush/smush_player.cpp +++ b/engines/scumm/smush/smush_player.cpp @@ -55,10 +55,6 @@ #include "sound/vorbis.h" #include "sound/mp3.h" -#ifdef DUMP_SMUSH_FRAMES -#include <png.h> -#endif - #include "common/zlib.h" namespace Scumm { @@ -212,10 +208,6 @@ static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_enc void SmushPlayer::timerCallback() { parseNextFrame(); -#ifdef _WIN32_WCE - _inTimer = true; - _inTimerCount++; -#endif } SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) { @@ -252,11 +244,6 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) { _paused = false; _pauseStartTime = 0; _pauseTime = 0; -#ifdef _WIN32_WCE - _inTimer = false; - _inTimerCount = 0; - _inTimerCountRedraw = ConfMan.getInt("Smush_force_redraw"); -#endif } SmushPlayer::~SmushPlayer() { @@ -926,14 +913,7 @@ void SmushPlayer::handleFrame(Chunk &b) { } if (_width != 0 && _height != 0) { -#ifdef _WIN32_WCE - if (!_inTimer || _inTimerCount == _inTimerCountRedraw) { - updateScreen(); - _inTimerCount = 0; - } -#else updateScreen(); -#endif } _smixer->handleFrame(); @@ -1098,57 +1078,6 @@ void SmushPlayer::warpMouse(int x, int y, int buttons) { } void SmushPlayer::updateScreen() { -#ifdef DUMP_SMUSH_FRAMES - char fileName[100]; - // change path below for dump png files - sprintf(fileName, "/path/to/somethere/%s%04d.png", _vm->getBaseName(), _frame); - FILE *file = fopen(fileName, "wb"); - if (file == NULL) - error("can't open file for writing png"); - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (png_ptr == NULL) { - fclose(file); - error("can't write png header"); - } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - fclose(file); - error("can't create png info struct"); - } - if (setjmp(png_ptr->jmpbuf)) { - fclose(file); - error("png jmpbuf error"); - } - - png_init_io(png_ptr, file); - - png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_colorp palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); - for (int i = 0; i != 256; ++i) { - (palette + i)->red = _pal[i * 3 + 0]; - (palette + i)->green = _pal[i * 3 + 1]; - (palette + i)->blue = _pal[i * 3 + 2]; - } - - png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - - png_write_info(png_ptr, info_ptr); - png_set_flush(png_ptr, 10); - - png_bytep row_pointers[480]; - for (int y = 0 ; y < _height ; y++) - row_pointers[y] = (png_byte *) (_dst + y * _width); - png_write_image(png_ptr, row_pointers); - png_write_end(png_ptr, info_ptr); - png_free(png_ptr, palette); - - fclose(file); - png_destroy_write_struct(&png_ptr, &info_ptr); -#endif - uint32 end_time, start_time = _vm->_system->getMillis(); _updateNeeded = true; end_time = _vm->_system->getMillis(); @@ -1326,10 +1255,6 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st _vm->_system->updateScreen(); _updateNeeded = false; } -#ifdef _WIN32_WCE - _inTimer = false; - _inTimerCount = 0; -#endif } if (_endOfFile) break; diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h index 413a5895d3..64ae167349 100644 --- a/engines/scumm/smush/smush_player.h +++ b/engines/scumm/smush/smush_player.h @@ -84,11 +84,6 @@ private: bool _insanity; bool _middleAudio; bool _skipPalette; -#ifdef _WIN32_WCE - bool _inTimer; - int16 _inTimerCount; - int16 _inTimerCountRedraw; -#endif public: SmushPlayer(ScummEngine_v7 *scumm); diff --git a/engines/scumm/thumbnail.cpp b/engines/scumm/thumbnail.cpp deleted file mode 100644 index 40f1ee48e5..0000000000 --- a/engines/scumm/thumbnail.cpp +++ /dev/null @@ -1,130 +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 file 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/system.h" -#include "common/savefile.h" -#include "graphics/scaler.h" -#include "scumm/scumm.h" - -namespace Scumm { - -#define THMB_VERSION 1 - -struct ThumbnailHeader { - uint32 type; - uint32 size; - byte version; - uint16 width, height; - byte bpp; -}; - -#define ThumbnailHeaderSize (4+4+1+2+2+1) - -inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) { - r = (((color >> 11) & 0x1F) << 3); - g = (((color >> 5) & 0x3F) << 2); - b = ((color&0x1F) << 3); -} - -Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) { - ThumbnailHeader header; - - header.type = file->readUint32BE(); - // We also accept the bad 'BMHT' header here, for the sake of compatibility - // with some older savegames which were written incorrectly due to a bug in - // ScummVM which wrote the thumb header type incorrectly on LE systems. - if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) - return 0; - - header.size = file->readUint32BE(); - header.version = file->readByte(); - - if (header.version > THMB_VERSION) { - file->skip(header.size - 9); - warning("Loading a newer thumbnail version"); - return 0; - } - - header.width = file->readUint16BE(); - header.height = file->readUint16BE(); - header.bpp = file->readByte(); - - // TODO: support other bpp values than 2 - if (header.bpp != 2) { - file->skip(header.size - 14); - return 0; - } - - Graphics::Surface *thumb = new Graphics::Surface(); - thumb->create(header.width, header.height, sizeof(OverlayColor)); - - OverlayColor* pixels = (OverlayColor *)thumb->pixels; - - for (int y = 0; y < thumb->h; ++y) { - for (int x = 0; x < thumb->w; ++x) { - uint8 r, g, b; - colorToRGB(file->readUint16BE(), r, g, b); - - // converting to current OSystem Color - *pixels++ = _system->RGBToColor(r, g, b); - } - } - - return thumb; -} - -void ScummEngine::saveThumbnail(Common::OutSaveFile *file) { - Graphics::Surface thumb; - -#if !defined(__DS__) - if (!createThumbnailFromScreen(&thumb)) -#endif - thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16)); - - ThumbnailHeader header; - header.type = MKID_BE('THMB'); - header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel; - header.version = THMB_VERSION; - header.width = thumb.w; - header.height = thumb.h; - header.bpp = thumb.bytesPerPixel; - - file->writeUint32BE(header.type); - file->writeUint32BE(header.size); - file->writeByte(header.version); - file->writeUint16BE(header.width); - file->writeUint16BE(header.height); - file->writeByte(header.bpp); - - // TODO: for later this shouldn't be casted to uint16... - uint16* pixels = (uint16 *)thumb.pixels; - for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels) - file->writeUint16BE(*pixels); - - thumb.free(); -} - -} // end of namespace Scumm diff --git a/engines/tinsel/config.cpp b/engines/tinsel/config.cpp index 4c143f1b8d..cb2099c130 100644 --- a/engines/tinsel/config.cpp +++ b/engines/tinsel/config.cpp @@ -24,8 +24,6 @@ * This file contains configuration functionality */ -//#define USE_3FLAGS 1 - #include "tinsel/config.h" #include "tinsel/dw.h" #include "tinsel/sound.h" @@ -47,7 +45,7 @@ int volVoice = MAXSAMPVOL; int speedText = DEFTEXTSPEED; int bSubtitles = false; int bSwapButtons = 0; -LANGUAGE language = TXT_ENGLISH; +LANGUAGE g_language = TXT_ENGLISH; int bAmerica = 0; @@ -55,9 +53,8 @@ int bAmerica = 0; bool bNoBlocking; /** - * WriteConfig() + * Write settings to config manager and flush the config file to disk. */ - void WriteConfig(void) { ConfMan.setInt("dclick_speed", dclickSpeed); ConfMan.setInt("music_volume", (volMidi * Audio::Mixer::kMaxChannelVolume) / MAXMIDIVOL); @@ -66,8 +63,33 @@ void WriteConfig(void) { ConfMan.setInt("talkspeed", (speedText * 255) / 100); ConfMan.setBool("subtitles", bSubtitles); //ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0); - //ConfigData.language = language; // not necessary, as language has been set in the launcher //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB + + // Store language for multilingual versions + if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) { + Common::Language lang; + switch (g_language) { + case TXT_FRENCH: + lang = Common::FR_FRA; + break; + case TXT_GERMAN: + lang = Common::DE_DEU; + break; + case TXT_SPANISH: + lang = Common::ES_ESP; + break; + case TXT_ITALIAN: + lang = Common::IT_ITA; + break; + default: + lang = Common::EN_ANY; + } + + ConfMan.set("language", Common::getLanguageCode(lang)); + } + + // Write to disk + ConfMan.flushToDisk(); } /*---------------------------------------------------------------------*\ @@ -94,24 +116,53 @@ void ReadConfig(void) { //ConfigData.language = language; // not necessary, as language has been set in the launcher //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB -// The flags here control how many country flags are displayed in one of the option dialogs. -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) - language = ConfigData.language; - #ifdef USE_3FLAGS - if (language == TXT_ENGLISH || language == TXT_ITALIAN) { - language = TXT_GERMAN; - bSubtitles = true; + // Set language - we'll be clever here and use the ScummVM language setting + g_language = TXT_ENGLISH; + Common::Language lang = _vm->getLanguage(); + if (lang == Common::UNK_LANG && ConfMan.hasKey("language")) + lang = Common::parseLanguage(ConfMan.get("language")); // For multi-lingual versions, fall back to user settings + switch (lang) { + case Common::FR_FRA: + g_language = TXT_FRENCH; + break; + case Common::DE_DEU: + g_language = TXT_GERMAN; + break; + case Common::ES_ESP: + g_language = TXT_SPANISH; + break; + case Common::IT_ITA: + g_language = TXT_ITALIAN; + break; + default: + g_language = TXT_ENGLISH; } - #endif - #ifdef USE_4FLAGS - if (language == TXT_ENGLISH) { - language = TXT_GERMAN; + + if (lang == Common::JA_JPN) { + // TODO: Add support for JAPAN version + } else if (lang == Common::HB_ISR) { + // TODO: Add support for HEBREW version + + // The Hebrew version appears to the software as being English + // but it needs to have subtitles on... + g_language = TXT_ENGLISH; bSubtitles = true; + } else if (_vm->getFeatures() & GF_USE_3FLAGS) { + // 3 FLAGS version supports French, German, Spanish + // Fall back to German if necessary + if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && g_language != TXT_SPANISH) { + g_language = TXT_GERMAN; + bSubtitles = true; + } + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + // 4 FLAGS version supports French, German, Spanish, Italian + // Fall back to German if necessary + if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && + g_language != TXT_SPANISH && g_language != TXT_ITALIAN) { + g_language = TXT_GERMAN; + bSubtitles = true; + } } - #endif -#else - language = TXT_ENGLISH; -#endif } bool isJapanMode() { diff --git a/engines/tinsel/config.h b/engines/tinsel/config.h index 73cc411cb6..fc85f0abe0 100644 --- a/engines/tinsel/config.h +++ b/engines/tinsel/config.h @@ -30,23 +30,11 @@ namespace Tinsel { -// None of these defined -> 1 language, in ENGLISH.TXT -//#define USE_5FLAGS 1 // All 5 flags -//#define USE_4FLAGS 1 // French, German, Italian, Spanish -//#define USE_3FLAGS 1 // French, German, Spanish - -// The Hebrew version appears to the software as being English -// but it needs to have subtitles on... -//#define HEBREW 1 - -//#define JAPAN 1 - - // double click timer initial value -#define DOUBLE_CLICK_TIME 6 // 6 @ 18Hz = .33 sec - -#define DEFTEXTSPEED 0 - +enum { + DOUBLE_CLICK_TIME = 6, // 6 @ 18Hz = .33 sec + DEFTEXTSPEED = 0 +}; extern int dclickSpeed; extern int volMidi; @@ -55,7 +43,7 @@ extern int volVoice; extern int speedText; extern int bSubtitles; extern int bSwapButtons; -extern LANGUAGE language; +extern LANGUAGE g_language; extern int bAmerica; void WriteConfig(void); diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp index b95662cbfe..f933b2dd79 100644 --- a/engines/tinsel/cursor.cpp +++ b/engines/tinsel/cursor.cpp @@ -49,7 +49,7 @@ namespace Tinsel { //----------------- LOCAL DEFINES -------------------- #define ITERATION_BASE FRAC_ONE -#define ITER_ACCELLERATION (10L << (FRAC_BITS - 4)) +#define ITER_ACCELERATION (10L << (FRAC_BITS - 4)) //----------------- LOCAL GLOBAL DATA -------------------- @@ -404,7 +404,8 @@ static void MoveCursor(void) { newY = intToFrac(ptMouse.y); // modify mouse driver position depending on cursor keys - if ((dir = _vm->getKeyDirection()) != 0) { + dir = _vm->getKeyDirection(); + if (dir != 0) { if (dir & MSK_LEFT) newX -= IterationSize; @@ -417,7 +418,7 @@ static void MoveCursor(void) { if (dir & MSK_DOWN) newY += IterationSize; - IterationSize += ITER_ACCELLERATION; + IterationSize += ITER_ACCELERATION; // set new mouse driver position _vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY))); diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 7da4192456..f4fe876290 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -130,6 +130,96 @@ static const TinselGameDescription gameDescriptions[] = { TINSEL_V1, }, + { // Multilingual CD with english speech and *.gra files. + // Note: It contains no english subtitles. + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::ES_ESP, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { // English CD with SCN files { "dw", @@ -189,25 +279,6 @@ static const TinselGameDescription gameDescriptions[] = { { AD_TABLE_END_MARKER, 0, 0, 0, 0 } }; -/** - * The fallback game descriptor used by the Tinsel engine's fallbackDetector. - * Contents of this struct are to be overwritten by the fallbackDetector. - */ -static TinselGameDescription g_fallbackDesc = { - { - "", - "", - AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor - Common::UNK_LANG, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - 0, - 0, - 0, - 0, -}; - } // End of namespace Tinsel static const Common::ADParams detectionParams = { @@ -243,8 +314,6 @@ public: virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; - }; bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { @@ -255,21 +324,6 @@ bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm return gd != 0; } -const Common::ADGameDescription *TinselMetaEngine::fallbackDetect(const FSList *fslist) const { - // Set the default values for the fallback descriptor's ADGameDescription part. - Tinsel::g_fallbackDesc.desc.language = Common::UNK_LANG; - Tinsel::g_fallbackDesc.desc.platform = Common::kPlatformPC; - Tinsel::g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; - - // Set default values for the fallback descriptor's TinselGameDescription part. - Tinsel::g_fallbackDesc.gameID = 0; - Tinsel::g_fallbackDesc.features = 0; - Tinsel::g_fallbackDesc.version = 0; - - //return (const Common::ADGameDescription *)&Tinsel::g_fallbackDesc; - return NULL; -} - #if PLUGIN_ENABLED_DYNAMIC(TINSEL) REGISTER_PLUGIN_DYNAMIC(TINSEL, PLUGIN_TYPE_ENGINE, TinselMetaEngine); #else diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h index d14dd43fa2..9ceef37858 100644 --- a/engines/tinsel/dw.h +++ b/engines/tinsel/dw.h @@ -110,8 +110,11 @@ typedef int HPOLYGON; // Language for the resource strings enum LANGUAGE { - TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, - TXT_ITALIAN, TXT_SPANISH + TXT_ENGLISH, + TXT_FRENCH, + TXT_GERMAN, + TXT_ITALIAN, + TXT_SPANISH }; } // end of namespace Tinsel diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp index e3333bae90..ffecacd1be 100644 --- a/engines/tinsel/inventory.cpp +++ b/engines/tinsel/inventory.cpp @@ -29,8 +29,6 @@ * And there's still a bit of tidying and commenting to do yet. */ -//#define USE_3FLAGS 1 - #include "tinsel/actors.h" #include "tinsel/anim.h" #include "tinsel/background.h" @@ -370,9 +368,7 @@ enum BFUNC { NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN, OPENLOAD, OPENSAVE, OPENREST, OPENSOUND, OPENCONT, -#ifndef JAPAN OPENSUBT, -#endif OPENQUIT, INITGAME, MIDIVOL, CLANG, RLANG @@ -402,9 +398,7 @@ struct CONFBOX { #define SIX_RESTART_OPTION 2 #define SIX_SOUND_OPTION 3 #define SIX_CONTROL_OPTION 4 -#ifndef JAPAN #define SIX_SUBTITLES_OPTION 5 -#endif #define SIX_QUIT_OPTION 6 #define SIX_RESUME_OPTION 7 #define SIX_LOAD_HEADING 8 @@ -568,41 +562,60 @@ CONFBOX controlBox[] = { /*-------------------------------------------------------------*\ -| This is the subtitles 'menu'. | +| This is the subtitles 'menu'. | \*-------------------------------------------------------------*/ -#ifndef JAPAN CONFBOX subtitlesBox[] = { -#ifdef USE_5FLAGS + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + +}; + +CONFBOX subtitlesBox3Flags[] = { + + { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP }, + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + + { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX subtitlesBox4Flags[] = { + + { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP }, + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + + { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX subtitlesBox5Flags[] = { + { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 100, 56, 32, NULL, FIX_UK }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 100, 56, 32, NULL, FIX_FR }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 100, 56, 32, NULL, FIX_GR }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 50, 137, 56, 32, NULL, FIX_IT }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 120, 137, 56, 32, NULL, FIX_SP }, -#endif -#ifdef USE_4FLAGS - { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP }, -#endif -#ifdef USE_3FLAGS - { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP }, -#endif { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } -#endif }; -#endif /*-------------------------------------------------------------*\ @@ -610,7 +623,7 @@ CONFBOX subtitlesBox[] = { \*-------------------------------------------------------------*/ CONFBOX quitBox[] = { -#ifdef JAPAN +#ifdef g { AAGBUT, IQUITGAME, NULL, USE_POINTER,70, 44, 23, 19, NULL, IX_TICK1 }, { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 30, 44, 23, 19, NULL, IX_CROSS1 } #else @@ -652,13 +665,9 @@ CONFINIT ciSound = { 10, 5, 20, 16, false, soundBox, ARRAYSIZE(soundBox), NO_HEA #else CONFINIT ciControl = { 10, 5, 20, 16, false, controlBox, ARRAYSIZE(controlBox), NO_HEADING }; #endif -#ifndef JAPAN -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) -CONFINIT ciSubtitles = { 10, 6, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING }; -#else + CONFINIT ciSubtitles = { 10, 3, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING }; -#endif -#endif + CONFINIT ciQuit = { 4, 2, 98, 53, false, quitBox, ARRAYSIZE(quitBox), SIX_QUIT_HEADING }; CONFINIT ciTopWin = { 6, 5, 72, 23, false, topwinBox, 0, NO_HEADING }; @@ -762,45 +771,39 @@ static void ConfActionSpecial(int i); -#ifndef JAPAN bool LanguageChange(void) { - LANGUAGE nLang; - -#ifdef USE_3FLAGS - // VERY quick dodgy bodge - if (cd.selBox == 0) - nLang = TXT_FRENCH; - else if (cd.selBox == 1) - nLang = TXT_GERMAN; - else - nLang = TXT_SPANISH; - if (nLang != language) { -#elif defined(USE_4FLAGS) - nLang = (LANGUAGE)(cd.selBox + 1); - if (nLang != language) { -#else - if (cd.selBox != language) { + LANGUAGE nLang = TXT_ENGLISH; + + if (_vm->getFeatures() & GF_USE_3FLAGS) { + // VERY quick dodgy bodge + if (cd.selBox == 0) + nLang = TXT_FRENCH; // = 1 + else if (cd.selBox == 1) + nLang = TXT_GERMAN; // = 2 + else + nLang = TXT_SPANISH; // = 4 + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + nLang = (LANGUAGE)(cd.selBox + 1); + } else if (_vm->getFeatures() & GF_USE_5FLAGS) { nLang = (LANGUAGE)cd.selBox; -#endif + } + + if (nLang != g_language) { KillInventory(); ChangeLanguage(nLang); - language = nLang; + g_language = nLang; return true; - } - else + } else return false; } -#endif /**************************************************************************/ /******************** Some miscellaneous functions ************************/ /**************************************************************************/ -/*---------------------------------------------------------------------*\ -| DumpIconArray()/DumpDobjArray()/DumpObjArray() | -|-----------------------------------------------------------------------| -| Delete all the objects in iconArray[]/DobjArray[]/objArray[] | -\*---------------------------------------------------------------------*/ +/** + * Delete all the objects in iconArray[] + */ static void DumpIconArray(void){ for (int i = 0; i < MAX_ICONS; i++) { if (iconArray[i] != NULL) { @@ -813,7 +816,6 @@ static void DumpIconArray(void){ /** * Delete all the objects in DobjArray[] */ - static void DumpDobjArray(void) { for (int i = 0; i < MAX_WCOMP; i++) { if (DobjArray[i] != NULL) { @@ -826,7 +828,6 @@ static void DumpDobjArray(void) { /** * Delete all the objects in objArray[] */ - static void DumpObjArray(void) { for (int i = 0; i < MAX_WCOMP; i++) { if (objArray[i] != NULL) { @@ -886,7 +887,6 @@ bool IsInInventory(int object, int invnum) { /** * Returns which item is held (INV_NOICON (-1) if none) */ - int WhichItemHeld(void) { return HeldItem; } @@ -895,7 +895,6 @@ int WhichItemHeld(void) { * Called from the cursor module when it re-initialises (at the start of * a new scene). For if we are holding something at scene-change time. */ - void InventoryIconCursor(void) { INV_OBJECT *invObj; @@ -908,7 +907,6 @@ void InventoryIconCursor(void) { /** * Returns TRUE if the inventory is active. */ - bool InventoryActive(void) { return (InventoryState == ACTIVE_INV); } @@ -1214,8 +1212,8 @@ void Select(int i, bool force) { break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case FRGROUP: + assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)); iconArray[HL2] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[i].w+6, cd.Box[i].h+6); MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]); MultiSetAniXY(iconArray[HL2], @@ -1224,7 +1222,7 @@ void Select(int i, bool force) { MultiSetZPosition(iconArray[HL2], Z_INV_BRECT+1); break; -#endif + default: break; } @@ -1276,7 +1274,6 @@ void DropItem(int item) { * Stick the item into an inventory list (ItemOrder[]), and hold the * item if requested. */ - void AddToInventory(int invno, int icon, bool hold) { int i; bool bOpen; @@ -1407,12 +1404,12 @@ int InvArea(int x, int y) { int RightX = MultiRightmost(RectObject) + 1; int BottomY = MultiLowest(RectObject) + 1; -// Outside the whole rectangle? + // Outside the whole rectangle? if (x <= LeftX - EXTRA || x > RightX + EXTRA || y <= TopY - EXTRA || y > BottomY + EXTRA) return I_NOTIN; -// The bottom line + // The bottom line if (y > BottomY - 2 - EXTRA) { // Below top of bottom line? if (x <= LeftX + 2 + EXTRA) return I_BLEFT; // Bottom left corner @@ -1422,7 +1419,7 @@ int InvArea(int x, int y) { return I_BOTTOM; // Just plain bottom } -// The top line + // The top line if (y <= TopY + 2 + EXTRA) { // Above bottom of top line? if (x <= LeftX + 2 + EXTRA) return I_TLEFT; // Top left corner @@ -1432,24 +1429,24 @@ int InvArea(int x, int y) { return I_TOP; // Just plain top } -// Sides + // Sides if (x <= LeftX + 2 + EXTRA) // Left of right of left side? return I_LEFT; else if (x > RightX - 2 - EXTRA) // Right of left of right side? return I_RIGHT; -// From here down still needs fixing up properly -/* -* In the move area? -*/ + // From here down still needs fixing up properly + /* + * In the move area? + */ if (ino != INV_CONF && x >= LeftX + M_SW - 2 && x <= RightX - M_SW + 3 && y >= TopY + M_TH - 2 && y < TopY + M_TBB + 2) return I_MOVE; -/* -* Scroll bits -*/ + /* + * Scroll bits + */ if (ino == INV_CONF && cd.bExtraWin) { } else { if (x > RightX - M_IAL + 3 && x <= RightX - M_IAR + 1) { @@ -1476,7 +1473,6 @@ int InvArea(int x, int y) { * Returns the id of the icon displayed under the given position. * Also return co-ordinates of items tag display position, if requested. */ - int InvItem(int *x, int *y, bool update) { int itop, ileft; int row, col; @@ -1510,7 +1506,6 @@ int InvItem(int *x, int *y, bool update) { /** * Returns the id of the icon displayed under the given position. */ - int InvItemId(int x, int y) { int itop, ileft; int row, col; @@ -1539,21 +1534,21 @@ int InvItemId(int x, int y) { return INV_NOICON; } -/*---------------------------------------------------------------------*\ -| WhichInvBox() | -|-----------------------------------------------------------------------| -| Finds which box the cursor is in. | -\*---------------------------------------------------------------------*/ -#define MD_YSLIDTOP 7 -#define MD_YSLIDBOT 18 -#define MD_YBUTTOP 9 -#define MD_YBUTBOT 16 -#define MD_XLBUTL 1 -#define MD_XLBUTR 10 -#define MD_XRBUTL 105 -#define MD_XRBUTR 114 - +/** + * Finds which box the cursor is in. + */ static int WhichInvBox(int curX, int curY, bool bSlides) { + enum { + MD_YSLIDTOP = 7, + MD_YSLIDBOT = 18, + MD_YBUTTOP = 9, + MD_YBUTBOT = 16, + MD_XLBUTL = 1, + MD_XLBUTR = 10, + MD_XRBUTL = 105, + MD_XRBUTR = 114 + }; + if (bSlides) { for (int i = 0; i < numMdSlides; i++) { if (curY > MultiHighest(mdSlides[i].obj) && curY < MultiLowest(mdSlides[i].obj) @@ -1841,7 +1836,6 @@ void InvLabels(bool InBody, int aniX, int aniY) { * It seems to set up slideStuff[], an array of possible first-displayed * icons set against the matching y-positions of the slider. */ - void AdjustTop(void) { int tMissing, bMissing, nMissing; int nslideY; @@ -1904,7 +1898,6 @@ void AdjustTop(void) { /** * Insert an inventory icon object onto the display list. */ - OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) { INV_OBJECT *invObj; // Icon data const MULTI_INIT *pmi; // Its INIT structure - from the reel @@ -1929,7 +1922,6 @@ OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) { /** * Create display objects for the displayed icons in an inventory window. */ - void FillInInventory(void) { int Index; // Index into ItemOrder[] int n = 0; // index into iconArray[] @@ -2010,7 +2002,6 @@ void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int te /** * Insert a part of the inventory window frame onto the display list. */ - static OBJECT *AddObject(const FREEL *pfreel, int num) { const MULTI_INIT *pmi; // Get the MULTI_INIT structure IMAGE *pim; @@ -2043,7 +2034,6 @@ static OBJECT *AddObject(const FREEL *pfreel, int num) { /** * Display the scroll bar slider. */ - void AddSlider(OBJECT **slide, const FILM *pfilm) { SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1); MultiSetAniXY(*slide, MultiRightmost(RectObject)-M_SXOFF+2, InvD[ino].inventoryY + slideY); @@ -2062,7 +2052,6 @@ enum { /** * Display a box with some text in it. */ - void AddBox(int *pi, int i) { int x = InvD[ino].inventoryX + cd.Box[i].xpos; int y = InvD[ino].inventoryY + cd.Box[i].ypos; @@ -2126,8 +2115,8 @@ void AddBox(int *pi, int i) { break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case FRGROUP: + assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)); assert(flagFilm != 0); // Language flags not declared! pfilm = (const FILM *)LockMem(flagFilm); @@ -2141,7 +2130,7 @@ void AddBox(int *pi, int i) { *pi += 1; break; -#endif + case FLIP: pfilm = (const FILM *)LockMem(winPartsf); @@ -2234,7 +2223,6 @@ static void AddBoxes(bool posnSlide) { /** * Display the scroll bar slider. */ - void AddEWSlider(OBJECT **slide, const FILM *pfilm) { SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1); MultiSetAniXY(*slide, InvD[ino].inventoryX + 24 + 127, slideY); @@ -2244,7 +2232,6 @@ void AddEWSlider(OBJECT **slide, const FILM *pfilm) { /** * AddExtraWindow */ - int AddExtraWindow(int x, int y, OBJECT **retObj) { int n = 0; const FILM *pfilm; @@ -2479,7 +2466,7 @@ void ConstructInventory(InventoryType filling) { OBJECT **rect, **title; -// Draw background, slider and icons + // Draw background, slider and icons if (filling == FULL) { rect = &retObj[n++]; title = &retObj[n++]; @@ -2495,8 +2482,7 @@ void ConstructInventory(InventoryType filling) { } FillInInventory(); - } - else if (filling == CONF) { + } else if (filling == CONF) { rect = &retObj[n++]; title = &retObj[n++]; @@ -2800,7 +2786,6 @@ bool convHid(void) { /** * Start up an inventory window. */ - void PopUpInventory(int invno) { assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_CONF)); // Trying to open illegal inventory @@ -2849,7 +2834,6 @@ void SetConfGlobals(CONFINIT *ci) { /** * PopupConf */ - void PopUpConf(CONFTYPE type) { int curX, curY; @@ -2903,11 +2887,27 @@ void PopUpConf(CONFTYPE type) { SetConfGlobals(&ciSound); break; -#ifndef JAPAN case SUBT: + if (_vm->getFeatures() & GF_USE_3FLAGS) { + ciSubtitles.v = 6; + ciSubtitles.Box = subtitlesBox3Flags; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox3Flags); + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + ciSubtitles.v = 6; + ciSubtitles.Box = subtitlesBox4Flags; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags); + } else if (_vm->getFeatures() & GF_USE_5FLAGS) { + ciSubtitles.v = 6; + ciSubtitles.Box = subtitlesBox4Flags; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags); + } else { + ciSubtitles.v = 3; + ciSubtitles.Box = subtitlesBox; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox); + } + SetConfGlobals(&ciSubtitles); break; -#endif case TOPWIN: SetConfGlobals(&ciTopWin); @@ -2927,25 +2927,21 @@ void PopUpConf(CONFTYPE type) { if (type == SAVE || type == LOAD) Select(0, false); -#ifndef JAPAN -#if !defined(USE_3FLAGS) || !defined(USE_4FLAGS) || !defined(USE_5FLAGS) else if (type == SUBT) { -#ifdef USE_3FLAGS - // VERY quick dirty bodges - if (language == TXT_FRENCH) - Select(0, false); - else if (language == TXT_GERMAN) - Select(1, false); - else - Select(2, false); -#elif defined(USE_4FLAGS) - Select(language-1, false); -#else - Select(language, false); -#endif + if (_vm->getFeatures() & GF_USE_3FLAGS) { + // VERY quick dirty bodges + if (g_language == TXT_FRENCH) + Select(0, false); + else if (g_language == TXT_GERMAN) + Select(1, false); + else + Select(2, false); + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + Select(g_language-1, false); + } else if (_vm->getFeatures() & GF_USE_5FLAGS) { + Select(g_language, false); + } } -#endif -#endif // JAPAN GetCursorXY(&curX, &curY, false); InvCursor(IC_AREA, curX, curY); @@ -2954,7 +2950,6 @@ void PopUpConf(CONFTYPE type) { /** * Close down an inventory window. */ - void KillInventory(void) { if (objArray[0] != NULL) { DumpObjArray(); @@ -2976,6 +2971,9 @@ void KillInventory(void) { if (bOpenConf) { bOpenConf = false; PopUpConf(OPTION); + + // Write config changes + WriteConfig(); } else if (ino == INV_CONF) InventoryIconCursor(); } @@ -3098,12 +3096,10 @@ void InventoryProcess(CORO_PARAM, const void *) { KillInventory(); PopUpConf(CONTROLS); break; - #ifndef JAPAN case OPENSUBT: KillInventory(); PopUpConf(SUBT); break; - #endif case OPENQUIT: KillInventory(); PopUpConf(QUIT); @@ -3112,7 +3108,6 @@ void InventoryProcess(CORO_PARAM, const void *) { KillInventory(); bRestart = true; break; - #if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case CLANG: if (!LanguageChange()) KillInventory(); @@ -3120,7 +3115,6 @@ void InventoryProcess(CORO_PARAM, const void *) { case RLANG: KillInventory(); break; - #endif default: break; } @@ -3344,10 +3338,8 @@ static void SlideMSlider(int x, SSFN fn) { case S_END: // End of a drag on the slider AddBoxes(false); // Might change position slightly -#ifndef JAPAN if (ino == INV_CONF && cd.Box == subtitlesBox) - Select(language, false); -#endif + Select(g_language, false); break; } } @@ -3780,8 +3772,8 @@ void ConfAction(int i, bool dbl) { } break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case FRGROUP: + assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)); if (dbl) { Select(i, false); LanguageChange(); @@ -3789,7 +3781,6 @@ void ConfAction(int i, bool dbl) { Select(i, false); } break; -#endif case AAGBUT: case ARSGBUT: diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 7d4efd8079..4d77ee4ace 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -343,8 +343,6 @@ MusicPlayer::~MusicPlayer() { } void MusicPlayer::setVolume(int volume) { - Common::StackLock lock(_mutex); - // FIXME: Could we simply change MAXMIDIVOL to match ScummVM's range? volume = CLIP((255 * volume) / MAXMIDIVOL, 0, 255); _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); @@ -354,6 +352,8 @@ void MusicPlayer::setVolume(int volume) { _masterVolume = volume; + Common::StackLock lock(_mutex); + for (int i = 0; i < 16; ++i) { if (_channel[i]) { _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index bf980f0983..07c1b22b2a 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -1991,7 +1991,6 @@ void topplay(CORO_PARAM, SCNHANDLE film, int x, int y, int complete, int actorid /** * Open or close the 'top window' */ - void topwindow(int bpos) { assert(bpos == TW_START || bpos == TW_END); @@ -2010,7 +2009,6 @@ void topwindow(int bpos) { /** * unhookscene */ - void unhookscene(void) { UnHookScene(); } @@ -2018,7 +2016,6 @@ void unhookscene(void) { /** * Un-define an actor as tagged. */ - void untagactor(int actor) { UnTagActor(actor); } @@ -2026,14 +2023,12 @@ void untagactor(int actor) { /** * vibrate */ - void vibrate(void) { } /** * waitframe(int actor, int frameNumber) */ - void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEvent) { CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -2056,7 +2051,6 @@ void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEven /** * Return when a key pressed or button pushed. */ - void waitkey(CORO_PARAM, bool escOn, int myescEvent) { CORO_BEGIN_CONTEXT; int startEvent; @@ -2104,7 +2098,6 @@ void waitkey(CORO_PARAM, bool escOn, int myescEvent) { /** * Pause for requested time. */ - void waittime(CORO_PARAM, int time, bool frame, bool escOn, int myescEvent) { CORO_BEGIN_CONTEXT; int time; @@ -2261,7 +2254,6 @@ void walkingactor(uint32 id, SCNHANDLE *rp) { * Walk a moving actor towards the polygon's tag, but return when the * actor enters the polygon. */ - void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) { // COROUTINE CORO_BEGIN_CONTEXT; @@ -2309,7 +2301,6 @@ void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, in /** * walktag(actor, reel, hold) */ - void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) { // COROUTINE CORO_BEGIN_CONTEXT; @@ -2385,7 +2376,6 @@ void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int /** * whichinventory */ - int whichinventory(void) { return WhichInventoryOpen(); } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index c91fecf84e..70dd0170b4 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -206,13 +206,16 @@ void KeyboardProcess(CORO_PARAM, const void *) { { int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0; int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset; - if ((language == TXT_GERMAN) && +#if 0 // FIXME: Disabled this code for now, as it doesn't work as it should (see bug #2078922). + if ((g_language == TXT_GERMAN) && ((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) { // Skip to title screen // It seems the German CD version uses scenes 25,26,27,17 for the intro, // instead of 13,14,15,11; also, the title screen is 11 instead of 10 SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); - } else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { + } else +#endif + if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { // Skip to title screen SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); } else { @@ -695,25 +698,8 @@ int TinselEngine::init() { // TODO: More stuff from dos_main.c may have to be added here - // Set language - we'll be clever here and use the ScummVM language setting - language = TXT_ENGLISH; - switch (getLanguage()) { - case Common::FR_FRA: - language = TXT_FRENCH; - break; - case Common::DE_DEU: - language = TXT_GERMAN; - break; - case Common::IT_ITA: - language = TXT_ITALIAN; - break; - case Common::ES_ESP: - language = TXT_SPANISH; - break; - default: - language = TXT_ENGLISH; - } - ChangeLanguage(language); + // load in text strings + ChangeLanguage(g_language); // load in graphics info SetupHandleTable(); diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 347a344519..369fd64a9b 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -55,12 +55,19 @@ enum TinselGameFeatures { GF_DEMO = 1 << 0, GF_CD = 1 << 1, GF_FLOPPY = 1 << 2, - GF_SCNFILES = 1 << 3 + GF_SCNFILES = 1 << 3, + + // The GF_USE_?FLAGS values specify how many country flags are displayed + // in the subtitles options dialog. + // None of these defined -> 1 language, in ENGLISH.TXT + GF_USE_3FLAGS = 1 << 4, // French, German, Spanish + GF_USE_4FLAGS = 1 << 5, // French, German, Spanish, Italian + GF_USE_5FLAGS = 1 << 6 // All 5 flags }; enum TinselEngineVersion { - TINSEL_V0 = 1 << 0, // Used in the DW1 demo only - TINSEL_V1 = 1 << 1 + TINSEL_V0 = 0, // Used in the DW1 demo only + TINSEL_V1 = 1 }; struct TinselGameDescription; @@ -72,7 +79,7 @@ enum TinselKeyDirection { typedef bool (*KEYFPTR)(const Common::KeyState &); -class TinselEngine : public ::Engine { +class TinselEngine : public Engine { int _gameId; Common::KeyState _keyPressed; Common::RandomSource _random; diff --git a/graphics/module.mk b/graphics/module.mk index 93e2db26c5..f658b056df 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -15,8 +15,9 @@ MODULE_OBJS := \ mpeg_player.o \ primitives.o \ scaler.o \ - scaler/thumbnail.o \ - surface.o + scaler/thumbnail_intern.o \ + surface.o \ + thumbnail.o ifndef DISABLE_SCALERS MODULE_OBJS += \ diff --git a/graphics/scaler.h b/graphics/scaler.h index 2cf3f66239..95900de412 100644 --- a/graphics/scaler.h +++ b/graphics/scaler.h @@ -78,10 +78,22 @@ enum { extern void createThumbnail(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height); /** - * creates a thumbnail from the current screen (without overlay) + * Creates a thumbnail from the current screen (without overlay). + * * @param surf a surface (will always have 16 bpp after this for now) * @return false if a error occured */ -extern bool createThumbnailFromScreen(Graphics::Surface* surf); +extern bool createThumbnailFromScreen(Graphics::Surface *surf); + +/** + * Creates a thumbnail from a buffer. + * + * @param surf destination surface (will always have 16 bpp after this for now) + * @param pixels raw pixel data + * @param w width + * @param h height + * @param palette palette in RGB format + */ +extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette); #endif diff --git a/graphics/scaler/thumbnail.cpp b/graphics/scaler/thumbnail_intern.cpp index f1caa5d2e5..bdfa0ff5f6 100644 --- a/graphics/scaler/thumbnail.cpp +++ b/graphics/scaler/thumbnail_intern.cpp @@ -126,70 +126,93 @@ static bool grabScreen565(Graphics::Surface *surf) { return true; } -bool createThumbnailFromScreen(Graphics::Surface* surf) { - assert(surf); - - int screenWidth = g_system->getWidth(); - int screenHeight = g_system->getHeight(); - - Graphics::Surface screen; - - if (!grabScreen565(&screen)) - return false; +static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) { + uint16 width = in.w; + uint16 inHeight = in.h; - uint16 width = screenWidth; - - if (screenWidth < 320) { + if (width < 320) { // Special case to handle MM NES (uses a screen width of 256) width = 320; // center MM NES screen Graphics::Surface newscreen; - newscreen.create(width, screen.h, screen.bytesPerPixel); + newscreen.create(width, in.h, in.bytesPerPixel); - uint8 *dst = (uint8*)newscreen.getBasePtr((320 - screenWidth) / 2, 0); - uint8 *src = (uint8*)screen.getBasePtr(0, 0); - uint16 height = screen.h; + uint8 *dst = (uint8*)newscreen.getBasePtr((320 - in.w) / 2, 0); + const uint8 *src = (uint8*)in.getBasePtr(0, 0); + uint16 height = in.h; while (height--) { - memcpy(dst, src, screen.pitch); + memcpy(dst, src, in.pitch); dst += newscreen.pitch; - src += screen.pitch; + src += in.pitch; } - screen.free(); - screen = newscreen; - } else if (screenWidth == 720) { + in.free(); + in = newscreen; + } else if (width == 720) { // Special case to handle Hercules mode width = 640; - screenHeight = 400; + inHeight = 400; // cut off menu and so on.. Graphics::Surface newscreen; - newscreen.create(width, 400, screen.bytesPerPixel); + newscreen.create(width, 400, in.bytesPerPixel); - uint8 *dst = (uint8*)newscreen.getBasePtr(0, (400 - 240) / 2); - uint8 *src = (uint8*)screen.getBasePtr(41, 28); + uint8 *dst = (uint8*)in.getBasePtr(0, (400 - 240) / 2); + const uint8 *src = (uint8*)in.getBasePtr(41, 28); for (int y = 0; y < 240; ++y) { - memcpy(dst, src, 640 * screen.bytesPerPixel); + memcpy(dst, src, 640 * in.bytesPerPixel); dst += newscreen.pitch; - src += screen.pitch; + src += in.pitch; } - screen.free(); - screen = newscreen; + in.free(); + in = newscreen; } - uint16 newHeight = !(screenHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1; + uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1; int gBitFormatBackUp = gBitFormat; gBitFormat = 565; - surf->create(kThumbnailWidth, newHeight, sizeof(uint16)); - createThumbnail((const uint8*)screen.pixels, width * sizeof(uint16), (uint8*)surf->pixels, surf->pitch, width, screenHeight); + out.create(kThumbnailWidth, newHeight, sizeof(uint16)); + createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight); gBitFormat = gBitFormatBackUp; - screen.free(); + in.free(); return true; } + +bool createThumbnailFromScreen(Graphics::Surface* surf) { + assert(surf); + + Graphics::Surface screen; + + if (!grabScreen565(&screen)) + return false; + + return createThumbnail(*surf, screen); +} + +bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette) { + assert(surf); + + Graphics::Surface screen; + screen.create(w, h, 2); + + for (uint y = 0; y < screen.h; ++y) { + for (uint x = 0; x < screen.w; ++x) { + byte r, g, b; + r = palette[pixels[y * w + x] * 3]; + g = palette[pixels[y * w + x] * 3 + 1]; + b = palette[pixels[y * w + x] * 3 + 2]; + + ((uint16 *)screen.pixels)[y * screen.w + x] = RGBToColor<ColorMasks<565> >(r, g, b); + } + } + + return createThumbnail(*surf, screen); +} + diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp new file mode 100644 index 0000000000..905fea3d93 --- /dev/null +++ b/graphics/thumbnail.cpp @@ -0,0 +1,174 @@ +/* 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/thumbnail.h" +#include "graphics/scaler.h" +#include "common/endian.h" +#include "common/system.h" + +namespace Graphics { + +namespace { +#define THMB_VERSION 1 + +struct ThumbnailHeader { + uint32 type; + uint32 size; + byte version; + uint16 width, height; + byte bpp; +}; + +#define ThumbnailHeaderSize (4+4+1+2+2+1) + +inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) { + r = (((color >> 11) & 0x1F) << 3); + g = (((color >> 5) & 0x3F) << 2); + b = ((color&0x1F) << 3); +} + +bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) { + header.type = in.readUint32BE(); + // We also accept the bad 'BMHT' header here, for the sake of compatibility + // with some older savegames which were written incorrectly due to a bug in + // ScummVM which wrote the thumb header type incorrectly on LE systems. + if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) { + if (outputWarnings) + warning("couldn't find thumbnail header type"); + return false; + } + + header.size = in.readUint32BE(); + header.version = in.readByte(); + + if (header.version > THMB_VERSION) { + if (outputWarnings) + warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION); + return false; + } + + header.width = in.readUint16BE(); + header.height = in.readUint16BE(); + header.bpp = in.readByte(); + + return true; +} +} // end of anonymous namespace + +bool checkThumbnailHeader(Common::SeekableReadStream &in) { + uint32 position = in.pos(); + ThumbnailHeader header; + + bool hasHeader = loadHeader(in, header, false); + + in.seek(position, SEEK_SET); + + return hasHeader; +} + +bool skipThumbnailHeader(Common::SeekableReadStream &in) { + uint32 position = in.pos(); + ThumbnailHeader header; + + if (!loadHeader(in, header, false)) { + in.seek(position, SEEK_SET); + return false; + } + + in.seek(header.size - (in.pos() - position), SEEK_CUR); + return true; +} + +bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to) { + ThumbnailHeader header; + + if (!loadHeader(in, header, true)) + return false; + + if (header.bpp != 2) { + warning("trying to load thumbnail with unsupported bit depth %d", header.bpp); + return false; + } + + to.create(header.width, header.height, sizeof(OverlayColor)); + + OverlayColor *pixels = (OverlayColor *)to.pixels; + for (int y = 0; y < to.h; ++y) { + for (int x = 0; x < to.w; ++x) { + uint8 r, g, b; + colorToRGB(in.readUint16BE(), r, g, b); + + // converting to current OSystem Color + *pixels++ = g_system->RGBToColor(r, g, b); + } + } + + return true; +} + +bool saveThumbnail(Common::WriteStream &out) { + Graphics::Surface thumb; + + if (!createThumbnailFromScreen(&thumb)) { + warning("Couldn't create thumbnail from screen, aborting thumbnail save"); + return false; + } + + bool success = saveThumbnail(out, thumb); + thumb.free(); + + return success; +} + +bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) { + if (thumb.bytesPerPixel != 2) { + warning("trying to save thumbnail with bpp different than 2"); + return false; + } + + ThumbnailHeader header; + header.type = MKID_BE('THMB'); + header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel; + header.version = THMB_VERSION; + header.width = thumb.w; + header.height = thumb.h; + header.bpp = thumb.bytesPerPixel; + + out.writeUint32BE(header.type); + out.writeUint32BE(header.size); + out.writeByte(header.version); + out.writeUint16BE(header.width); + out.writeUint16BE(header.height); + out.writeByte(header.bpp); + + // TODO: for later this shouldn't be casted to uint16... + uint16 *pixels = (uint16 *)thumb.pixels; + for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels) + out.writeUint16BE(*pixels); + + return true; +} + +} // end of namespace Graphics + diff --git a/graphics/thumbnail.h b/graphics/thumbnail.h new file mode 100644 index 0000000000..0553306519 --- /dev/null +++ b/graphics/thumbnail.h @@ -0,0 +1,69 @@ +/* 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 GRAPHICS_THUMBNAIL_H +#define GRAPHICS_THUMBNAIL_H + +#include "common/stream.h" +#include "graphics/surface.h" + +namespace Graphics { + +/** + * Checks for presence of the thumbnail save header. + * Seeks automatically back to start position after check. + * + * @param in stream to check for header + */ +bool checkThumbnailHeader(Common::SeekableReadStream &in); + +/** + * Skips a thumbnail header, if present. + * + * @param in stream to process + */ +bool skipThumbnailHeader(Common::SeekableReadStream &in); + +/** + * Lodas a thumbnail from the given input stream. + * The loaded thumbnail will be automatically converted to the + * current overlay pixelformat. + */ +bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to); + +/** + * Saves a thumbnail to the given write stream. + * Automatically creates a thumbnail from screen contents. + */ +bool saveThumbnail(Common::WriteStream &out); + +/** + * Saves a (given) thumbnail to the given write stream. + */ +bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb); + +} // end of namespace Graphics + +#endif + @@ -10,7 +10,7 @@ # install: all $(INSTALL) -d "$(DESTDIR)$(BINDIR)" - $(INSTALL) -c -s -m 755 "$(srcdir)/scummvm$(EXEEXT)" "$(DESTDIR)$(BINDIR)/scummvm$(EXEEXT)" + $(INSTALL) -c -s -m 755 "./scummvm$(EXEEXT)" "$(DESTDIR)$(BINDIR)/scummvm$(EXEEXT)" $(INSTALL) -d "$(DESTDIR)$(MANDIR)/man6/" $(INSTALL) -c -m 644 "$(srcdir)/dists/scummvm.6" "$(DESTDIR)$(MANDIR)/man6/scummvm.6" $(INSTALL) -d "$(DESTDIR)$(PREFIX)/share/pixmaps/" diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp index 358d42d751..473612f6bc 100644 --- a/sound/mididrv.cpp +++ b/sound/mididrv.cpp @@ -46,7 +46,11 @@ static const MidiDriverDescription s_musicDrivers[] = { {"alsa", "ALSA", MD_ALSA, MDT_MIDI}, #endif -#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__) +#if defined(__MINT__) + {"stmidi", "Atari ST MIDI", MD_STMIDI, MDT_MIDI}, +#endif + +#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__) && !defined(__MINT__) {"seq", "SEQ", MD_SEQ, MDT_MIDI}, #endif @@ -247,7 +251,10 @@ MidiDriver *MidiDriver::createMidi(int midiDriver) { #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) case MD_WINDOWS: return MidiDriver_WIN_create(g_system->getMixer()); #endif -#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__) +#if defined(__MINT__) + case MD_STMIDI: return MidiDriver_STMIDI_create(g_system->getMixer()); +#endif +#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__) && !defined(__MINT__) case MD_SEQ: return MidiDriver_SEQ_create(g_system->getMixer()); #endif #if defined(UNIX) diff --git a/sound/mididrv.h b/sound/mididrv.h index 12513268a8..9d5a7d4407 100644 --- a/sound/mididrv.h +++ b/sound/mididrv.h @@ -51,6 +51,9 @@ enum MidiDriverType { // Windows MD_WINDOWS, + // Atari ST + MD_STMIDI, + // Linux MD_ALSA, MD_SEQ, @@ -271,6 +274,7 @@ public: extern MidiDriver *MidiDriver_NULL_create(Audio::Mixer *mixer); extern MidiDriver *MidiDriver_ADLIB_create(Audio::Mixer *mixer); extern MidiDriver *MidiDriver_WIN_create(Audio::Mixer *mixer); +extern MidiDriver *MidiDriver_STMIDI_create(Audio::Mixer *mixer); extern MidiDriver *MidiDriver_SEQ_create(Audio::Mixer *mixer); extern MidiDriver *MidiDriver_TIMIDITY_create(Audio::Mixer *mixer); extern MidiDriver *MidiDriver_QT_create(Audio::Mixer *mixer); diff --git a/sound/softsynth/mt32/partial.cpp b/sound/softsynth/mt32/partial.cpp index 1aab2a8de7..2866c7757d 100644 --- a/sound/softsynth/mt32/partial.cpp +++ b/sound/softsynth/mt32/partial.cpp @@ -25,7 +25,7 @@ #include "mt32emu.h" -#if defined(MACOSX) || defined(__solaris__) +#if defined(MACOSX) || defined(SOLARIS) // Older versions of Mac OS X didn't supply a powf function, so using it // will cause a binary incompatibility when trying to run a binary built // on a newer OS X release on an olderr one. And Solaris 8 doesn't provide diff --git a/sound/softsynth/mt32/synth.cpp b/sound/softsynth/mt32/synth.cpp index 785e8098c7..366da50d01 100644 --- a/sound/softsynth/mt32/synth.cpp +++ b/sound/softsynth/mt32/synth.cpp @@ -25,7 +25,7 @@ #include "mt32emu.h" -#if defined(MACOSX) || defined(__solaris__) +#if defined(MACOSX) || defined(SOLARIS) // Older versions of Mac OS X didn't supply a powf function, so using it // will cause a binary incompatibility when trying to run a binary built // on a newer OS X release on an olderr one. And Solaris 8 doesn't provide diff --git a/sound/softsynth/mt32/tables.cpp b/sound/softsynth/mt32/tables.cpp index 20b7cf289a..5865ba2950 100644 --- a/sound/softsynth/mt32/tables.cpp +++ b/sound/softsynth/mt32/tables.cpp @@ -25,7 +25,7 @@ #include "mt32emu.h" -#if defined(MACOSX) || defined(__solaris__) +#if defined(MACOSX) || defined(SOLARIS) // Older versions of Mac OS X didn't supply a powf function, so using it // will cause a binary incompatibility when trying to run a binary built // on a newer OS X release on an olderr one. And Solaris 8 doesn't provide diff --git a/test/common/bufferedreadstream.h b/test/common/bufferedreadstream.h index 7733949d9a..2644745af2 100644 --- a/test/common/bufferedreadstream.h +++ b/test/common/bufferedreadstream.h @@ -13,8 +13,7 @@ class BufferedReadStreamTestSuite : public CxxTest::TestSuite { // refilled. Common::BufferedReadStream srs(&ms, 4); - int i; - byte b; + byte i, b; for (i = 0; i < 10; ++i) { TS_ASSERT( !srs.eos() ); diff --git a/test/common/bufferedseekablereadstream.h b/test/common/bufferedseekablereadstream.h index 63941904cd..c3e85c1b66 100644 --- a/test/common/bufferedseekablereadstream.h +++ b/test/common/bufferedseekablereadstream.h @@ -10,8 +10,7 @@ class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite { Common::BufferedSeekableReadStream ssrs(&ms, 4); - int i; - byte b; + byte i, b; for (i = 0; i < 10; ++i) { TS_ASSERT( !ssrs.eos() ); diff --git a/test/common/hashmap.h b/test/common/hashmap.h index 5aa609bc00..acde1da028 100644 --- a/test/common/hashmap.h +++ b/test/common/hashmap.h @@ -1,12 +1,12 @@ #include <cxxtest/TestSuite.h> #include "common/hashmap.h" +#include "common/hash-str.h" class HashMapTestSuite : public CxxTest::TestSuite { public: - void test_empty_clear( void ) - { + void test_empty_clear(void) { Common::HashMap<int, int> container; TS_ASSERT( container.empty() ); container[0] = 17; @@ -14,10 +14,17 @@ class HashMapTestSuite : public CxxTest::TestSuite TS_ASSERT( !container.empty() ); container.clear(); TS_ASSERT( container.empty() ); + + Common::StringMap container2; + TS_ASSERT( container2.empty() ); + container2["foo"] = "bar"; + container2["quux"] = "blub"; + TS_ASSERT( !container2.empty() ); + container2.clear(); + TS_ASSERT( container2.empty() ); } - void test_contains( void ) - { + void test_contains(void) { Common::HashMap<int, int> container; container[0] = 17; container[1] = 33; @@ -25,25 +32,41 @@ class HashMapTestSuite : public CxxTest::TestSuite TS_ASSERT( container.contains(1) ); TS_ASSERT( !container.contains(17) ); TS_ASSERT( !container.contains(-1) ); + + Common::StringMap container2; + container2["foo"] = "bar"; + container2["quux"] = "blub"; + TS_ASSERT( container2.contains("foo") ); + TS_ASSERT( container2.contains("quux") ); + TS_ASSERT( !container2.contains("bar") ); + TS_ASSERT( !container2.contains("asdf") ); } - void test_add_remove( void ) - { + void test_add_remove(void) { Common::HashMap<int, int> container; container[0] = 17; container[1] = 33; + container[2] = 45; + container[3] = 12; + container[4] = 96; TS_ASSERT( container.contains(1) ); container.erase(1); TS_ASSERT( !container.contains(1) ); container[1] = 42; TS_ASSERT( container.contains(1) ); container.erase(0); + TS_ASSERT( !container.empty() ); container.erase(1); + TS_ASSERT( !container.empty() ); + container.erase(2); + TS_ASSERT( !container.empty() ); + container.erase(3); + TS_ASSERT( !container.empty() ); + container.erase(4); TS_ASSERT( container.empty() ); } - void test_lookup( void ) - { + void test_lookup(void) { Common::HashMap<int, int> container; container[0] = 17; container[1] = -1; @@ -58,8 +81,7 @@ class HashMapTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( container[4], 96 ); } - void test_iterator_begin_end( void ) - { + void test_iterator_begin_end(void) { Common::HashMap<int, int> container; // The container is initially empty ... @@ -74,12 +96,11 @@ class HashMapTestSuite : public CxxTest::TestSuite TS_ASSERT( container.begin() == container.end() ); } - void test_hash_map_copy( void ) - { - Common::HashMap<int, int> map1, map2; + void test_hash_map_copy(void) { + Common::HashMap<int, int> map1, container2; map1[323] = 32; - map2 = map1; - TS_ASSERT_EQUALS(map2[323], 32); + container2 = map1; + TS_ASSERT_EQUALS(container2[323], 32); } // TODO: Add test cases for iterators, find, ... diff --git a/test/common/queue.h b/test/common/queue.h new file mode 100644 index 0000000000..7eedec9a5d --- /dev/null +++ b/test/common/queue.h @@ -0,0 +1,80 @@ +#include <cxxtest/TestSuite.h> + +#include "common/queue.h" + +class QueueTestSuite : public CxxTest::TestSuite { +public: + void test_empty_clear() { + Common::Queue<int> queue; + TS_ASSERT(queue.empty()); + + queue.push(1); + queue.push(2); + TS_ASSERT(!queue.empty()); + + queue.clear(); + + TS_ASSERT(queue.empty()); + } + + void test_size() { + Common::Queue<int> queue; + TS_ASSERT_EQUALS(queue.size(), 0); + + queue.push(5); + TS_ASSERT_EQUALS(queue.size(), 1); + + queue.push(9); + queue.push(0); + TS_ASSERT_EQUALS(queue.size(), 3); + + queue.pop(); + TS_ASSERT_EQUALS(queue.size(), 2); + } + + void test_front_back_pop() { + Common::Queue<int> queue; + + queue.push( 42); + queue.push(-23); + + TS_ASSERT_EQUALS(queue.front(), 42); + TS_ASSERT_EQUALS(queue.back(), -23); + + queue.front() = -23; + queue.back() = 42; + TS_ASSERT_EQUALS(queue.front(), -23); + TS_ASSERT_EQUALS(queue.back(), 42); + + queue.pop(); + TS_ASSERT_EQUALS(queue.front(), 42); + } + + void test_assign() { + Common::Queue<int> q1, q2; + + for (int i = 0; i < 5; ++i) { + q1.push(i); + q2.push(4-i); + } + + Common::Queue<int> q3(q1); + + for (int i = 0; i < 5; ++i) { + TS_ASSERT_EQUALS(q3.front(), i); + q3.pop(); + } + + TS_ASSERT(q3.empty()); + + q3 = q2; + + for (int i = 4; i >= 0; --i) { + TS_ASSERT_EQUALS(q3.front(), i); + q3.pop(); + } + + TS_ASSERT(q3.empty()); + } +}; + diff --git a/tools/create_drascula/staticdata.h b/tools/create_drascula/staticdata.h index 4778c530e4..67a1e1abcf 100644 --- a/tools/create_drascula/staticdata.h +++ b/tools/create_drascula/staticdata.h @@ -3056,84 +3056,84 @@ const char *_text[NUM_LANGS][NUM_TEXT] = { { // 0 "", - "\220 la seconda porta pi\243 grande che ho vista nella mia vita", - "Forse.., no", - "\202 chiusa con tabelle. La chiesa deve essere abbandonata da tanti anni fa.", - "Ma se non la ho aperta", + "\324 LA SECONDA PORTA PI\353 GRANDE CHE IO ABBIA MAI VISTO", + "BEH, FORSE NO", + "\324 SIGILLATA CON TAVOLE. LA CHIESA DEV'ESSERE STATA ABBANDONATA PARECCHI ANNI FA.", + "NON L'HO APERTA", // 5 - "Che faccio? La tolgo?", - "Ciao porta. Vado a farti una cornice", - "Troppo per me", - "una finestra chiusa con tabelle", - "Non ce la faccio", + "CHE FACCIO? LA TOLGO?", + "CIAO PORTA. STO PER TRASFORMARTI IN UNO STIPITE.", + "\324 TROPPO PER ME.", + "UNA FINESTRA SIGILLATA CON TAVOLE.", + "NON POSSO.", // 10 - "Eccolo", - "E per che?", - "Ciao finestra. Hai qualcosa da fare stasera?", - "No senza il permesso del Ministero dei Lavori Pubblici", - "-eh! quella finestra ha soltanto una tabella..", + "GI\267 FATTO.", + "E PERCH\220?", + "CIAO FINESTRA. HAI QUALCOSA DA FARE STANOTTE?", + "NON SENZA IL PERMESSO DEL MINISTERO DELLE OPERE PUBBLICHE", + "SE SOLO QUESTA FINESTRA NON FOSSE SIGILLATA...", // 15 - "-Eooooo! -Finestra!", - "Tu, ciao", - "", - "Non ce la faccio", - "Va bene dov'\202 ", + "YOO-HOO! FINESTRA!", + "SALVE.", + "COME QUELLA DELLA MICROCHOF.", + "NON RIESCO AD ARRIVARCI.", + "STA BENE DOV'\324.", // 20 "", - "\220 una tomba in forma di croce", - "Non grazie", - "Ciao morto. Vuoi delle patatine a forma di vermi?", - "Si. Come in Poltergueist.", + "\324 UNA LAPIDE A FORMA DI CROCE", + "NO GRAZIE.", + "CIAO, MORTO. NON TI SCOMODARE AD ALZARTI!", + "S\326, CERTO. COME IN POLTERGEIST.", // 25 "", "", - "Torno in quindici minuti", - "Vietato affigere manifesti", - "", + "TORNO TRA QUINDICI MINUTI.", + "VIETATO AFFIGGERE MANIFESTI.", + "\324 LA TOMBA DELLO ZIO EVARISTO.", // 30 - "\220 chiuso con la chiave", - "Ne ho gi\240 uno.", - "", - "Non risponde.", - "No, \202 ben parcheggiato.", + "\324 CHIUSA A CHIAVE", + "NE HO GI\267 UNO.", + "YOO HOO, ZIO EVARISTO!", + "NON RISPONDE.", + "NO, \324 FISSATO PER BENE.", // 35 - "\220 una porta.", - "Un casseto del tavolino.", - "Un sospettoso armadio.", - "Ciao armadio. Come va?.", + "\324 UNA PORTA.", + "UN CASSETTO DEL TAVOLO.", + "UN ARMADIO SOSPETTO.", + "CIAO ARMADIO. COME VA?", "", // 40 "", - "\220 un candelabro molto vecchio.", - "Deve essere qu\241 da che Mazinguer-Z era una vite.", - "No.\220 una reliquia.", - "\220 una bella pala.", + "\324 UN CANDELABRO MOLTO ANTICO.", + "DEV'ESSERE QUI DA QUANDO MAZINGA Z ERA UNA VITE.", + "NO, \324 UNA RELIQUIA.", + "\324 UNA GRAZIOSA PALA D'ALTARE.", // 45 "", - "Hi, hi, hi", + "HI, HI, HI.", "", - "No.", + "NO.", "", // 50 - "Ha,ha,ha . - che buono!", + "HA, HA, HA. FANTASTICO!", "", "", "", - "Non vedo niente di speciale.", + "NON VEDO NIENTE DI SPECIALE.", // 55 - "Ferdinan, la pianta.", - "\220 una degli spunzoni della cancellata.", - "-Eh! Qu\241 sotto c'\202 una scatola di cerini", - "-Guarda! un pacco di fazzoletti. -E c'\202 ne uno senza utilizzare!.", - "Non c'\202 niente di pi\243 nel secchio.", + "\324 FERNAN, LA PIANTA.", + "\324 UNO DEI PALETTI DELLA STACCIONATA.", + "HEY! C'\324 UN PACCHETTO DI FIAMMIFERI QUI SOTTO.", + "MA GUARDA! UN PACCHETTO DI FAZZOLETTI. CE N'\324 ANCORA UNO NON USATO!", + "NON C'\324 ALTRO NEL CESTINO.", // 60 - "\220 un cieco che non vede", + "\324 UN CIECO CHE NON VEDE.", "", "", "", "", // 65 - "\220 una abbondante quantit\240 di soldi", + "\324 UNA BELLA SOMMA DI DENARO.", "", "", "", @@ -3175,487 +3175,487 @@ const char *_text[NUM_LANGS][NUM_TEXT] = { "", "", // 100 - "NON HA NULLA DI SPECIALE", - "NON \324 MICA SPECIALE", - "TU! CHE C'\324 ?", + "NON HA NULLA DI SPECIALE.", + "NON \324 NIENTE DI INSOLITO.", + "COME TE LA PASSI?", "CIAO", - "NIENTE NUOVO?", + "NIENTE DI NUOVO?", // 105 - "-COME VA LA FAMIGLIA?", - "- MA CHE STAI A DIRE?", - "-MA COME VADO A PRENDERE QUELLA COSA!", - "\324 VIETATO DALLA MIA RELIGIONE", - "MEGLIO DI NO", + "COME VA LA FAMIGLIA?", + "DICI SUL SERIO?", + "MA COME FACCIO A PRENDERLO?", + "LA MIA RELIGIONE ME LO PROIBISCE.", + "MEGLIO DI NO.", // 110 - "-COME NO!", - "NEANCHE PARLARNE", + "SICURO!", + "NEANCHE A PARLARNE.", "IMPOSSIBILE", "QUESTO NON SI APRE", - "IO SOLO NON CE LA FACCIO", + "NON CE LA FACCIO DA SOLO", // 115 - "SE VORREI POTREI, MA MI FA PIGRIZIA", - "NON TROVO UNA BUONA RAGIONE", - "\324 UN CERVELLO ABBASTANZA CARINO", - "ALLORA, CERVELLO, CHE NE PENSI DI FARE STASERA?", - "NO, DEVE CONSERVARSI IN UN POSTO CHIUSO ALLA AZIONE MUTANTE DELLA ATMOSFERA", + "POTREI FARLO, MA MI SENTO UN PO' PIGRO.", + "NON NE VEDO IL MOTIVO.", + "\324 UN CERVELLO PIUTTOSTO CARINO.", + "E ALLORA, CERVELLO, CHE PENSI DI FARE STANOTTE?", + "NO, DEVE ESSERE CONSERVATO IN UN POSTO LONTANO DALL'AZIONE MUTAGENA DELL'ATMOSFERA", // 120 - "\324 COS\336 DURO, COME IL MIO CAPO", - "UNA TALEA MOLTO AFFILATA", - "FEDELE TALEA AFFILATAAA, NOBILE ROVERE TRANSILVANOOO", - "-INSOMMA, DEVO TAGLIARMI LE UNGHIE!", - "-LA, DENTRO, C'\324 B.J,E MAMMA MIA, CHE FIGA!", + "\324 RIGIDO, COME IL MIO CAPO", + "UN PICCHETTO MOLTO AFFILATO.", + "FEDELE PICCHETTO APPUNTITOOO, NOBILE ROVERE TRANSILVANOOO", + "ACCIDENTI, MI DEVO TAGLIARE LE UNGHIE!", + "L\326 DENTRO C'\324 B.J., DOVREI VEDERE COME STA LA RAGAZZA!", // 125 - "\324 CHIUSA SOTTO LUCCHETTO E CATENACCIO", - "\"LUCCHETTO E CATENACCIO S.A\"", - "\324 IL TIPICO SCHELETRO CHE C'\324 IN TUTTE LE CARCERE DI TUTTI I VIDEO-GIOCHI", - "SI UTILIZA PER DARE ELETRICIT\267 AGLI APARATTI COLLEGATI A LUI", - "\324 TOTALMEN11TE ARTIGIANO, PERCHE I GIAPONESSI LI FANNO TASCABILI", + "\324 CHIUSA CON LUCCHETTO E CATENACCIO", + "\"LUCCHETTO E CATENACCIO S.P.A.\"", + "\324 IL TIPICO SCHELETRO CHE C'\324 IN TUTTE LE CARCERI DI TUTTI I VIDEOGIOCHI", + "SI USA PER FORNIRE ELETTRICIT\267 AGLI APPARECCHI COLLEGATI", + "\324 COMPLETAMENTE ARTIGIANALE, VISTO CHE I GIAPPONESI LI FANNO TASCABILI", // 130 - "NELLA MIA VITA, HO VISTO SOLTANTO UNA VOLTA UNA COSA COS\336 BRUTTA", - "SMETILLA. NON DICO NULLA PER SE SI ARRABBIA", + "SOLO UNA VOLTA NELLA MIA VITA HO VISTO UNA COSA COS\326 BRUTTA", + "LASCIA STARE. NON GLI DICO NULLA ALTRIMENTI SI ARRABBIA", "SEMBRA ABBASTANZA RAZIONALE", - "\324 UNA FOTO DI PLATONE SCRIVENDO IL SUO DISCORSO PERSO", - "NON SONO DI QUELLI CHE PARLANO CON POSTERS", + "\324 UNA FOTO DI PLATONE MENTRE SCRIVE IL SUO DIALOGO PERDUTO", + "NON SONO UNO DI QUELLI CHE PARLANO CON I POSTER", // 135 "UNA SCRIVANIA MOLTO CARINA", - "\324 UN DIPLOMA DI CACCIA-CACCIA-VAMPIRI OMOLOGATO DALLA UNIVERSIT\267 DI OXFORD", - "\324 NOTTE BUIA CON LUNA PIENA", - "SEMBRA CHE QUESTE VITI NON SONO MOLTO AVVITATE", - "NON GUARDARE, MA CREDO CHE UNA TELECAMERA NASCOSTA MI ST\267 REGISTRANDO", + "\324 UN DIPLOMA DI CACCIA-CACCIA-VAMPIRI APPROVATO DALL'UNIVERSIT\267 DI OXFORD", + "\324 UNA NOTTE BUIA CON LUNA PIENA", + "SEMBRA CHE QUESTE VITI NON SIANO AVVITATE DEL TUTTO", + "NON GUARDARE, MA CREDO CHE UNA TELECAMERA NASCOSTA MI STIA REGISTRANDO", // 140 - "UN DETETTORE DI TALEE MOLTO MODERNO", - "NO, IL LABORATORIO SI TROVA NEL SECONDO PIANO", - "UN BEL TAVOLINO", - "\324 UN SACCO DI SOLDI CHE NON PUO MANCARE IN UNA AVVENTURA CHE SIA COS\336 IMPORTANTE", - "IF I WERE A RICHMAN, DUBIDUBIDUBIDUBIDUBIDUBIDUBIDU", + "UN RILEVATORE DI PALETTI MOLTO MODERNO", + "NO, IL LABORATORIO SI TROVA AL SECONDO PIANO", + "UN BEL COMODINO", + "\324 UN MUCCHIO DI DENARO CHE NON PU\343 MANCARE IN NESSUNA AVVENTURA CHE SI RISPETTI", + "SE FOSSI RICCO, DUBIDUBIDUBIDUBIDUBIDUBIDUBIDU", // 145 - "SONO DELLE STRANE FOGLIE. DEVONO AVERLE PORTATE DALLA SUDAMERICA", - "NON CREDO CHE SIA RISPOSTO", - "\324 UN BEL CROCIFISSO DI LEGNO. LA ICONA NON RIFLESSA TUTTA LA SUA BELLEZA", - "IO SOLO PREGO PRIMA DI ANDARMENE AL LETTO", - "-EH, SEMBRA CHE QUESTO SPUNZONE \324 UN PO ALLENTATO!", + "SONO DELLE STRANE FOGLIE. DEVONO AVERLE PORTATE DAL SUDAMERICA O GI\353 DI L\326", + "NON CREDO CHE MI RISPONDEREBBERO", + "\324 UN MERAVIGLIOSO CROCIFISSO DI LEGNO. L'ICONA NON RIFLETTE TUTTA LA SUA BELLEZZA", + "IO PREGO SOLAMENTE PRIMA DI CORICARMI", + "EH, PARE CHE QUESTA SBARRA SIA UN PO' ALLENTATA!", // 150 - "E POI TI LAMENTI PERCHE NON TI DO SUGGERIMENTI", - "\324 UNO SPUNZONI ABBASTANZA CONVENZIONALE", - "SONO CARINI, SEBBENE HANNO PARECHIO POLVERE", - "NO, NON MI SENTIRANO; HI,HI,HI -CHE BUONO!", - "\"LA BELLA ADDORMENTATA DEL BOSCO\" DI CIAIKOSKY, O CIOIFRUSKY, O COME SI DICA", + "E POI TI LAMENTI PERCH\220 NON TI DO SUGGERIMENTI", + "\324 UNA SBARRA ABBASTANZA CONVENZIONALE", + "SONO CARINI, SEBBENE SIANO RICOPERTI DA UN PO' DI SCHIFEZZE", + "NO, NON MI SENTIRANNO. HI,HI,HI CHE BUONO!", + "\"LA BELLA ADDORMENTATA NEL BOSCO\" DI CHAIKOSKY, O CHOIFRUSKY, O COME SI DICE", // 155 "MOLTO APPETITOSA", - "NO, IO NON SONO DI QUELLI CHE SI METTONO IN BOCCA GOMME USATE", - "UNA FALCE MOLTO CARINA. MI DOMANDO DOVE CI SAR\265 IL MARTELLO", - "\"I FABBRICANTI DI TABACCO AVVERTONO CHE IL TABACCO NUOCE GRAVEMENTE LA SALUTE\"", - "UNA CANDELA NORMALE, ANZI CON CERA", + "NO, NON SONO UNO DI QUELLI CHE SI METTONO IN BOCCA GOMME USATE", + "UNA FALCE MOLTO CARINA. MI CHIEDO DOVE SIA IL MARTELLO", + "I FABBRICANTI DI TABACCO AVVERTONO CHE LE AUTORIT\267 SANITARIE NUOCCIONO GRAVEMENTE ALLA SALUTE", + "UNA CANDELA ASSOLUTAMENTE NORMALE, CON CERA E TUTTO", // 160 - "MAMMA MIA COME BRILLANO QUESTE DUE BRILLANTI MONETE", - "MAMMA MIA COME BRILLA QUESTA BRILLANTE MONETA", - "CON QUESTO SAR\220 IMMUNE AI MORSI DEI VAMPIRI", - "NO, ANCORA NON \220 IL MOMENTO", - "C'E UN BIGLIETTO DI DIECIMILA E UN PAIO DI MONETE", + "ACCIDENTI COME SONO LUCENTI QUESTE DUE MONETE!", + "ACCIDENTI COM'\324 LUCENTE QUESTA MONETA!", + "CON QUESTO SAR\343 IMMUNE AL MORSO DEI VAMPIRI", + "NO, ANCORA NON \324 IL MOMENTO", + "C'E UN BIGLIETTO DA MILLE E UN PAIO DI MONETE", // 165 - "DICE \"SI PREGA DI NON BUTTARE CIBO AL PIANISTA\"", - "OMELETTA, 3.000 .PESCI FRITI, 2.000,PATATINE, 2.500", - "LE MIGLIORI HAMBURGUER A QUESTA PARTE DEL DANUBIO, SOLTANTO PER 4.000", - "UN BEL TESCHIO, CON UNO SGUARDO MOLTO PENETRANTE. HI,HI,HI, CHE BUONO!", - "CIAO TESCHIO, MI RICORDI AL ZIO DI HAMLET", + "DICE \"SI PREGA DI NON TIRARE CIBO AL PIANISTA\"", + "OMELETTE, 200. PESCE FRITTO, 150, PATATINE CON MAIONESE, 225", + "I MIGLIORI HAMBURGER DI QUESTA RIVA DEL DANUBIO, SOLTANTO PER 325!", + "\324 UN BEL TESCHIO, CON UNO SGUARDO MOLTO PENETRANTE. HI, HI, HI, BUONA QUESTA!", + "CIAO TESCHIO, MI RICORDI LO ZIO DI AMLETO", // 170 - "HO L'ABITUDINE DI NON TOCCARE COSE CHE SIANO STATE VIVE", - "UN CESTINO", - "UN TOTOCALCIO PER LA PARTITA DI STASERA", - "MI DOMANDO CHE CI SAR\265 DIETRO", - "-EH, QUESTA TENDE NON SI MUOVE!", + "HO L'ABITUDINE DI NON TOCCARE COSE CHE SONO STATE VIVE", + "\324 UN CESTINO", + "\324 UNA SCOMMESSA PER LA PARTITA DI STANOTTE", + "MI DOMANDO CHE CI SAR\267 DIETRO", + "EH, QUESTA TENDA NON SI MUOVE!", // 175 - "MADONNA, CHE TETRO \220 QUESTO CASTELLO.", - "NON CE LA FACCIO, \220 TROPPO LONTANO PER SENTIRMI", - "UN TIPICO BOSCO TRANSILVANO, CON GLI ALBERI", - "-MA CHE SCIOCHEZZE DICI, \220 MOLTO BUIO", - "PASTICCERIA ROSSI. DOLCI E GOMME", + "CAVOLI, CHE TETRO QUESTO CASTELLO, EH?", + "NON POSSO, \324 TROPPO LONTANO PER SENTIRMI", + "\324 UN TIPICO BOSCO TRANSILVANO, CON ALBERI", + "CERTO CHE NE SPARI DI SCIOCCHEZZE, CON IL BUIO CHE C'\324!", + "NEGOZIO DI DOLCI GARCIA. TORTE E GOMME DA MASTICARE", // 180 "UNA PORTA MOLTO BELLA", - "\220 CHIUSA", - "UN FUSTO COMPLETAMENTE CHIUSO", + "\324 CHIUSA", + "\324 UN BARILE COMPLETAMENTE SIGILLATO", "", - "CHE ANIMALETTI COS\326 BELLI!", + "CHE BELLE BESTIOLINE!", // 185 - "BSSSSSS,BSSSS, GATINO..", - "NON RISPONDE", - "LA LUNA \220 UN SATELLITE CHE GIRA INTORNO LA TERRA CON UN PERIODO DI RIVOLUZIONE DI 28 GIORNI", + "PSSST, PSSST, GATTINO...", + "NON C'\324 RISPOSTA", + "LA LUNA \324 UN SATELLITE CHE GIRA INTORNO ALLA TERRA CON UN PERIODO DI RIVOLUZIONE DI 28 GIORNI", "CIAO, LUNA LUNETTA", - "\220 TOTALMENTE CHIUSA CON TABELLE", + "\324 COMPLETAMENTE SIGILLATA DA DELLE TAVOLE", // 190 - "IMPOSSIBILE. QUESTO, NON LO APRE N\220 HOUDINI", - ".EH, SEMBRA CHE L'OMBRA DEL CIPRESSE \220 ALUNGATA", - "-EOOO, BARISTA", + "IMPOSSIBILE. QUESTA NON LA APRE NEANCHE BRACCIO DI FERRO", + "EHI, SEMBRA CHE L'OMBRA DEL CIPRESSO SIA ALLUNGATA!", + "EHI, BARISTA!", "VORREI UNA CAMERA", - "SA DOVE POSSO TROVARE A UNO CHE SI FA CHIAMARE CONDE DRASCULA", + "SA DOVE POSSO TROVARE UN CERTO CONTE DRASCULA?", // 195 - "SI, PER CHE?", - "COME MAI?", - "DA.....DAVVERO?", - "BUONA DOMANDA, GLI RACONTER\220 LA MIA STORIA, SENTA..", - "SONO SOLTANTO CINQUE MINUTI", + "S\326, COSA C'\324?", + "AH S\326?", + "DA... DAVVERO?", + "BELLA DOMANDA. LE RACCONTER\343 LA MIA STORIA. ALLORA...", + "SONO SOLO CINQUE MINUTI", // 200 - "MI CHIAMO JOHN HACKER, E SONO RAPPRESENTANTE DI UNA IMMOBILIARIE BRITANICA", - "MI HANNO DETTO CHE IL CONDE DRASCULA VUOLE COMPRARE DEI TERRENI A GIBRALTAR, E SONO QU\326 PER NEGOZIARE LA VENDITA", - "MA CREDO IO CHE DOMANI PRESTO TORNO CON LA MAMMA", - "BELLA NOTTE, VERO?", + "MI CHIAMO JOHN HACKER, E RAPPRESENTO UNA COMPAGNIA IMMOBILIARE BRITANNICA", + "SEMBRA CHE IL CONTE DRASCULA VOGLIA COMPRARE DEI TERRENI A GIBILTERRA E MI HANNO MANDATO QUI PER NEGOZIARE LA VENDITA", + "MA CREDO CHE DOMATTINA PRESTO TORNER\343 DA MIA MADRE", + "BELLA NOTTATA, VERO?", "NO, NIENTE", // 205 - "EOOOO, PIANISTA", - "BELLA NOTTE", - "ANZI, NON FA FREDDO", - "ALLORA... TI LASCIO CONTINUARE A SUONARE", - "VA BENE", + "EHI, PIANISTA", + "BELLA NOTTATA", + "E NON FA NEMMENO FREDDO", + "VA BENE, TI LASCIO CONTINUARE A SUONARE", + "BENE ALLORA", // 210 "CIAO CAPO, COME VA?", "E LA FAMIGLIA?", - "C'\220 GENTE QU\326, EH?", - "MEGLIO NON DICO NULLA", - "SI ST\265 MEGLIO A CASA CHE A NESSUN POSTO... -EH? MA SE LEI NON \220 LA ZIA EMMA. ANZI. SE IO NON HO NESSUNA ZIA EMMA.", + "CARINO COME POSTO, EH?", + "MEGLIO CHE NON DICA NULLA", + "NON C'\324 POSTO PI\353 BELLO DELLA PROPRIA CASA... NON C'\324... EH? MA TU NON SEI LA ZIA EMMA. IN EFFETTI IO NON HO NESSUNA ZIA EMMA!", // 215 - "SI, IL MIO ANCHE. LEI PUO CHIAMARMI COME GLI PARA, MA SE MI CHIAMA JOHNY, VENGO SUBITO COME I CANI", - "SI, CHE SPIRITOSO SONO, VERO? MAA.. DOVE MI TROVO?", - "SI.", - "MANAGIA..", - "OH, SI. COME NO", + "S\326, ANCHE IL MIO. MI PU\343 CHIAMARE COME PI\353 LE PIACE, MA SE MI CHIAMA JOHNNY, CORRER\343 DA LEI COME UN CAGNOLINO", + "S\326, SONO PROPRIO SPIRITOSO, VERO? COMUNQUE, DOVE MI TROVO?", + "S\326.", + "MANNAGGIA...", + "OH, S\326. IMMAGINO DI S\326", // 220 - "ALLORA GRAZIE MILE PER DARMI IL TUO AIUTO. NON TI DISTURBO PI\351 . SE MI DICI DOV'\220 LA PORTA, PER FAVORE...", - "PERCHE LA BOTTA HA DOVUTO DAGNARMI IL CERVELLO E NON VEDO UNA MADONNA", - "NON FA NIENTE. SEMPRE NE PORTO ALTRI IN PI\351 ", - "-UFFA, CHE FIGA!- NON MI ERA ACCORTO, CERTO, SENZA GLI OCCHIALI", - "SENTI..", + "BEH, GRAZIE PER IL TUO AIUTO. NON TI DISTURBER\343 PI\353 . POTRESTI DIRMI DOV'\324 LA PORTA, PER FAVORE...", + "LA BOTTA DEVE AVERMI DANNEGGIATO IL CERVELLO... NON RIESCO A VEDERE UN TUBO...", + "BAH, NON IMPORTA. NE PORTO SEMPRE UN PAIO DI RISERVA", + "WOW, CHE BELLA RAGAZZA! NON ME NE ERO ACCORTO PRIMA! CERTO, SENZA GLI OCCHIALI!", + "SENTI...", // 225 - "COME MAI...?!", - "NON TI PREOCUPARE B.J., AMORE MIO! TI LIBERER\220 DA QUEL TIZIO", - "MI HA FATTO ARRABBIARE", - ".AHHH, IL LUPO- MANNARO! -MUORE MALDITO!", - "BENE, CREDO...", + "E QUESTOOO?!", + "NON TI PREOCCUPARE B.J., AMORE MIO! TI SALVER\343 DALLE SUE GRINFIE", + "MI HAI FATTO DAVVERO ARRABBIARE...", + "AHHH, UN LUPO MANNARO! MUORI, MALEDETTO!", + "S\326, BEH...", // 230 - "BENE, CREDO CHE PROSSIGUER\220 LA MIA STRADA. PERMESSOO..", - "-COME?", - "LA VERIT\267, PENSANDOCI MEGLIO, CREDO DI NO", - "DIMI, OH ERUDITO FILOSOFO, C'\324 QUALCUNA RELAZIONE CAUSA-EFETTO TRA LA VELOCIT\267 E LA PANCETA?", - "VA BENE, SMETTILA. COMUNQUE NON SO PERCHE HO DETTO QUESTO", + "S\326, BEH... CREDO CHE PROSEGUIR\343 PER LA MIA STRADA. CON PERMESSO...", + "COSA?", + "PER LA VERIT\267, PENSANDOCI BENE... CREDO DI NO", + "DIMMI, O ERUDITO FILOSOFO, ESISTE UNA QUALCHE RELAZIONE CAUSA-EFFETTO TRA LA VELOCIT\267 E LA PANCETTA?", + "VA BENE, VA BENE, LASCIA PERDERE. NON SO NEANCHE PERCH\220 L'HO DETTO.", // 235 - "COSA FAI QU\336 FILOSOFANDO, CHE NON STAI MANGIANDO GENTE?", + "PERCH\220 STAI QUI A FILOSOFARE, INVECE DI ANDARE A MANGIARE LE PERSONE?", "COME MAI?", - "SENTI, PUOI RIPETERE QUELLO DI \"INCLINAZIONI PRE-EVOLUTIVE\"?", - "SI SI, QUELLA STORIA CHE MI HAI RACCONTATO PRIMA. PERCHE NON HO CAPITO MOLTO BENE.", - "NO, MEGLIO NON DICO NULLA, NON VOGLIO METTERE IL COLTELLO NELLA PIAGA...", + "SENTI, PUOI RIPETERE QUELLA COSA SULLE RELAZIONI PRE-EVOLUTIVE?", + "S\326, AMICO. QUELLA MENATA CHE MI HAI FATTO SENTIRE PRIMA. \324 CHE NON L'HO CAPITA MOLTO BENE...", + "NO, MEGLIO NON DIRE NULLA, NON VOGLIO METTERE IL COLTELLO NELLA PIAGA...", // 240 - "SI, MI DICA?", - "SI, CHE SUCCEDE?", - "AH, ADESSO CHE CITA IL SOGGETTO GLI DIR\343 CHE...", + "PRONTO?", + "S\326, CHE SUCCEDE?", + "AH, VISTO CHE NE PARLA, LE DIR\343 CHE...", "", - "AH.., COSA SUCCEDEREBBE SE UN VAMPIRO PRENDEREBBE LA RICETA..", + "A PROPOSITO, NON CHE SIA QUESTO IL CASO, CERTO, MA COSA ACCADREBBE SE PER CASO UN VAMPIRO OTTENESSE LA RICETTA?", // 245 - "NIENTE. SENTI, QUESTO SEMBRA UN POSTICCIO MESSO SUL COPIONE PER FINIRE PRESTO IL VIDEO-GIOCO?. BENE, FORSE, NO", + "AD OGNI MODO. SENTI, QUESTA NON TI SEMBRA UNA TROVATA MESSA SUL COPIONE PER FINIRE PRESTO IL GIOCO? BEH, FORSE NO", "\324 VUOTO!", - "PERCHE HAI RUBATO IL MIO AMORE, B.J., SENZA LEI LA MIA VITA NON HA SENSO", - "-IL SUO CERVELLO?!", - "NO NIENTE, MA CREDO CHE ALLA FINE IL TUO PICCOLINO MOSTRO MI HA FATTO ARRABBIARE", + "PERCH\220 MI HAI RUBATO IL MIO UNICO AMORE, B.J.? SENZA DI LEI LA MIA VITA NON HA SENSO", + "IL SUO CERVELLO?!", + "NON PER NIENTE, MA CREDO DI AVERNE ABBASTANZA DEL TUO MOSTRICIATTOLO", // 250 - "SANTA MADONNA AIUTAMI!", - "NON TE LA CAVEREI. SICURO CHE APPARISCE SUPERMAN E MI LIBERA!", - "CHE SCHIFFO DI VIDEO-GIOCO NEL CUI MUORE IL PROTAGONISTA", - "UN ATTIMO, COSA SUCCEDE COL MIO ULTIMO DESIDERIO?", - "-HA,HA! ORA SONO IMMUNIZZATO CONTRO TE, MALEDETTO DEMONIO. QUESTA SIGARETTA \324 UNA POZIONE ANTI-VAMPIRI CHE MI HA DATTO VON BRAUN", + "SANTA VERGINE, SALVAMI DA ALTRE SFORTUNE!", + "NON TE LA CAVERAI. SICURAMENTE APPARIR\267 SUPERMAN E MI SALVER\267!", + "CHE SCHIFO DI GIOCO \324 QUESTO, UNO IN CUI MUORE IL PROTAGONISTA!", + "EHI, UN MOMENTO, COSA NE \324 DEL MIO ULTIMO DESIDERIO?", + "AH, AH! ORA SONO IMMUNIZZATO CONTRO DI TE, MALEDETTO DEMONIO. QUESTA SIGARETTA CONTIENE UNA POZIONE ANTI-VAMPIRO CHE MI HA DATO VON BRAUN", // 255 - "SI CERTO. MA NON RIUSCIRAI MAI A FARMI DIRTI LA RICETA", - "POSSO SOPPORTARE LA TORTURA, ANZI CREARLA", - "-NO, PER FAVORE!- PARLER\220, MA NON FARMI QUESTO!", - "BENE, TI HO GI\267 DETTO QUELLO CHE VOLEVI SAPERE. ORA LIBERA B.J. E ME, E LASCIACI PERDERE", - "-B.J-.! COSA FAI QU\336? DOV'\324 DRASCULA?", + "S\326, CERTO. MA NON RIUSCIRAI MAI A FARMI DIRE LA RICETTA", + "POSSO SOPPORTARE QUALUNQUE TORTURA.", + "NO, TI PREGO! PARLER\343, MA NON FARMI QUESTO!", + "BENE. TI HO DETTO QUELLO CHE VOLEVI SAPERE. ORA LIBERA B.J. E ME, E LASCIACI IN PACE!", + "B.J.! COSA CI FAI QUI? DOV'\324 DRASCULA?", // 260 - "CHE PERVERSO! SOLTANTO PERCH'\324 NOBILE PENSA CHE HA IL DIRITTO SU TUTTI QUANTI", - "ABASSO LA ARISTOCRAZIA!", - "FORZA I POVERI DEL MONDOOO...", - "E QUELLO CHE VEDO \324 CHE TI HA INCATENATO ANZI CON LUCCHETTO", - "O.K., NON AVRAI UNA FONCINA?", + "CHE SPREGEVOLE! SOLTANTO PERCH\220 APPARTIENE ALLA NOBILT\267 PENSA DI AVERE LO \"IUS PRIMAE NOCTIS\" SU QUALUNQUE RAGAZZA LUI VOGLIA", + "ABBASSO IL DISPOTISMO ARISTOCRATICO!", + "FORZA I POVERI DEL MONDOOO...!", + "A QUANTO VEDO TI HA INCATENATO CON LUCCHETTO E TUTTO, EH?", + "VA BENE. NON HAI UNA FORCINA?", // 265 - "BENE BENE, NON PRENDERTELA COS\336, CI PENSER\220 IO", - "EH, BARISTA", + "VA BENE, VA BENE. NON PRENDERTELA COS\326, MI VERR\267 IN MENTE QUALCOSA.", + "EHI, BARISTA!", "COME VA LA PARTITA?", "CHI?", - "MA NON VEDI CHE DRASCULA \324 QU\336?", + "MA NON VEDI CHE DRASCULA \324 QUI?", // 270 - "ANDIAMO A UCCIDERLO", - "SERVIMI UN DRINK..", + "ALLORA LA FINIAMO CON LUI UNA VOLTA PER TUTTE, NO?", + "SERVIMI UN DRINK", "NIENTE. HO DIMENTICATO COSA VOLEVO DIRTI", - "O\247MI\247SERVI\247UN\247DRINK\247O\247MI\247METTO\247A\247SUONARE\247IL\247PIANOFORTE", - "QUANTO MANCA PER LA FINE DELLA PARTITA?", + "O MI SERVI UN DRINK O MI METTO A SUONARE IL PIANOFORTE FINO ALLA FINE DELLA PARTITA", + "QUANTO MANCA ALLA FINE DELLA PARTITA?", // 275 "BUONA SERA", - "COME VA IGOR? VAI CON LA GOBBA? -HI,HI,HI,CHE BUONO!", - "CHE STAI FACENDO?", - "NO", + "E COME TI SENTI, IGOR? UN PO' INGOBBITO? AH, AH, AH, CHE SPASSO!", + "COSA STAI FACENDO?", + "BEH, NO", "ALLORA METTITI GLI OCCHIALI", // 280 - "COSA \324 QUELLA DELLA ORGIA SOPRANNATURALE?", - "VA BENE, NON COTINUARE, MI FACCIO IDEA", - "NON POTREI DIRMI DOV'\324 DRASCULA?", - "DAIII, PER FAVORE", - "PER CHE NO?", + "COS'\324 QUESTA STORIA DELL'ORGIA SOPRANNATURALE?", + "OK, OK, NON CONTINUARE, ME NE SONO FATTO UN'IDEA", + "NON POTRESTI DIRMI DOV'\324 DRASCULA?", + "DAAAI, PER FAVORE...!", + "PERCH\220 NO?", // 285 "AH, MA DORME DI NOTTE?", - "BENE, ALLORA IN BOCCA IL LUPO CON I REDDITI", - "DEVO PROPRIO PARLARE CON LUI", - "EOOOO, SCHELETROOO!", - "OH DIO! UN MORTO CHE PARLA!", + "BENE, ALLORA IN BOCCA AL LUPO CON I REDDITI", + "DEVO PARLARE CON LUI", + "EHI, SCHELETROOO!", + "SANTO CIELO! UN MORTO CHE PARLA!", // 290 - "RACCONTAMI. COME MAI SEI VENUTO QU\336?", - "E PER CHE DRASCULA VUOLE CREARE UN MOSTRO?", + "RACCONTAMI. COME SEI FINITO QUI?", + "E PERCH\220 DRASCULA VUOLE CREARE UN MOSTRO?", "COME TI CHIAMI, AMICO SCHELETRO?", - "SENTI, NON VUOI QUALCOSA DA MANGIARE?", - "DEVI AVERE LO STOMACO VUOTO .- HI,HI,HI!", + "SENTI, NON VUOI CHE TI PORTI QUALCOSA DA MANGIARE?", + "DEVI AVERE LO STOMACO VUOTO. AH, AH, AH!", // 295 - "LA VERIT\267 \324 CHE NON MI VA DI PARLARE ADESSO", - "VANFFAN ( BIP ) FIGLIO DI .......( BIIP ).. VAI A FARE....( BIIIP )", - "IO LA AMAVO DAVVERO. O.K., SONO D'ACCCORDO CHE NON ERA MOLTO INTELLIGENTE, MA NESSUNO \324 PERFETTO, NO?", - "ANZI, AVEVA UN CORPO DA PAURA", - "ORMAI NON SAR\343 PI\353 QUELLO DI PRIMA .MI RICHIUDER\343 IN UN MONASTERO, E LASCIER\343 LA MIA VITA PERDERE", + "ADESSO NON MI VA DI PARLARE", + "CHE FIGLIA DI ...(BIP). VADA A FARSI F...(BIP) QUELLA STR...(BIP)!", + "IO LA AMAVO DAVVERO. VA BENE, NON ERA PROPRIO UN'INTELLETTUALE, MA NESSUNO \324 PERFETTO, NO?", + "E POI, AVEVA UN CORPO MOZZAFIATO", + "NON SAR\343 MAI PI\353 QUELLO DI PRIMA. MI RINCHIUDER\343 IN UN MONASTERO E LASCER\343 SCORRERE VIA LA MIA VITA A POCO A POCO", // 300 - "NIENTE POTR\267 FARMI USCIRE DI QUESTA MISERIA PERCHE...", + "NIENTE POTR\267 TIRARMI FUORI DA QUESTA MISERIA PERCH\220...", "DI CHI? DI CHI?", - "VOGLIO ESSERE PIRATA", - "VOGLIO ESSERE PROGRAMMATORE", + "VOGLIO ESSERE UN PIRATA", + "VOGLIO ESSERE UN PROGRAMMATORE", "RACCONTAMI QUALCOSA SU GARIBALDI", // 305 - "CONTINUER\343 A GIOCARE E DIMENTICHER\343 CHE VI HO VISTI", - "MA CHI AVR\267 PENSATO QUESTA SCIOCHEZZA!", - "\324 UNA BORSA COME QUELLA DI MIA NONNA", - "MA CHE FIGO SONO!", - "PI\353 MI VEDO PI\353 MI PIACCIO", + "CONTINUER\343 A GIOCARE E DIMENTICHER\343 DI AVERVI VISTO", + "A CHI SAR\267 VENUTA IN MENTE QUESTA IDIOZIA?", + "\324 UNA BORSETTA COME QUELLA DI MIA NONNA", + "PER\343, CHE FIGO CHE SONO!", + "PI\353 MI VEDO, PI\353 MI PIACCIO", // 310 "E POI COME MI CHIUDO?", - "PRIMA DEVO APRIRMI, VERO?", - "ST\343 BENE DOVE SONO", - "MI HO GI\267 PRESSO", - "CIAO IO", + "PRIMA DOVR\343 APRIRMI, NO?", + "STO BENE DOVE SONO", + "MI SONO GI\267 PRESO", + "CIAO ME!", // 315 - "ME GLI INDOSSER\343 QUANDO SIA LA OCCASIONE OPORTUNA", - "NON VEDO NIENTE DI SPECIALE", - "\324 BENE DOV'\324", - "E PER CHE?", - "NON CE LA FACCIO", + "LI INDOSSER\343 QUANDO SAR\267 IL MOMENTO GIUSTO", + "NON CI VEDO NIENTE DI SPECIALE", + "STA BENE DOV'\324", + "E PERCH\220?", + "NON POSSO", // 320 - "CIAO TU", - "\324 IL SEPOLCRO DELLO ZIO PEPPINO", - "EOOOO, ZIO PEPPINOOOO!", - "NO.NON VOGLIO TAGLIARMI UN' ALTRA VOLTA", - "-EHEM,EHEM..!", + "CIAO A TE", + "\324 IL SEPOLCRO DELLO ZIO DESIDERIO", + "EHI, ZIO DESIDERIOOOO!", + "NO. NON VOGLIO TAGLIARMI UN'ALTRA VOLTA", + "EHEM, EHM...!", // 325 - "GNAMM, EMMM,!", - "-SI, COF, COF!", - "GUARDA, C'\324 UNA GOMMA QU\336 ATTACATA", + "GNAMM, AH!", + "S\326, COF, COF!", + "GUARDA, C'\324 UNA GOMMA ATTACCATA QUI", "\324 IL TELEFONINO CHE MI HANNO REGALATO A NATALE", - "COM'\324 ALTO", + "COM'\324 ALTO!", // 330 - "ESCI AL BALCONE GIULIETTA!", - "TU SEI LA LUCE CHE ILLUMINA LA MIA VITA!", - "EH, PORTA, CHE C'\324?", - "EOOOO, SPENDITRICE DI TABACCO DI TRANSILVANIAAA", - "\324 UNA SPENDITRICE DI TABACCO", + "ESCI SUL BALCONE, GIULIETTA!", + "TU SEI LA LUCE CHE ILLUMINA LA MIA STRADA!", + "EHI, PORTA, DOVE PORTI?", + "EHI, DISTRIBUTORE DI SIGARETTE DI TRANSILVANIA!", + "\324 UN DISTRIBUTORE DI SIGARETTE", // 335 "HO UN'ALTRA MONETA DENTRO", - "NO. HO DECISSO SMETTERE DI FUMARE E DI BERE", - "DA OGGI SAR\343 SOLTANTO PER LE DONNE", - "QUESTO \324 UNA TRUFFA! NON \324 USCITO NULLA", - "ALLA FINE!", + "NO. HO DECISO DI SMETTERE DI FUMARE E DI BERE", + "A PARTIRE DA ADESSO MI DEDICHER\343 SOLAMENTE ALLE DONNE", + "QUESTA \324 UNA TRUFFA! NON \324 USCITO NULLA!", + "FINALMENTE!", // 340 - "CHE TI HO DETTO?, UN BAULE", - "CIAO BAULE, TI CHIAMI COME MIO CUGINO CHE SI CHIAMA RAUL..E", - "HO TROVATO LA BORSA DI B.J.", - "MIO DIO, NON MI RIFLETTO, SONO UN VAMPIRO!", - "...AH, NO, \324 UN DISEGNO", + "CHE TI HO DETTO? UN BAULE", + "CIAO BAULE, TI CHIAMI QUASI COME MIO CUGINO... RAULE.", + "HO TROVATO LA BORSA DI B.J.!", + "MIO DIO, NON HO UN RIFLESSO, SONO UN VAMPIRO!", + "...AH, NO. \324 UN DISEGNO!", // 345 - "SPECCHIO DELLE MIE BRAME: CHI \220 ILPI\351 BELLO DEL REAME?", + "SPECCHIO, SPECCHIO DELLE MIE BRAME: CHI \324 IL PI\353 BELLO DEL REAME?", "NON VUOLE APRIRMI", - "MOLTO BENE. MI HO MESSO I TAPPI", - "\324 UN DIPLOMA DI CACCIA-VAMPIRI OMOLOGATO DALLA UNVERSIT\267 DI CAMBRIDGE", - "NO. MANCANO ANCORA GLI INGREDIENTI, NON MERITA LA PENA CHE SIA SVEGLIATO", + "MOLTO BENE. HO MESSO I TAPPI", + "\324 UN DIPLOMA DI CACCIA-VAMPIRI APPROVATO DALL'UNIVERSIT\267 DI CAMBRIDGE", + "NO, MANCANO ANCORA ALCUNI INGREDIENTI, NON VALE LA PENA SVEGLIARLO", // 350 - "NON HO SOLDI", - "\324 UNA LAMPADA BRITANICA", + "MA NON HO SOLDI", + "\324 UNA LAMPADA BRITANNICA", "BARISTA! AIUTAMI!", - "HA COMPARITO UN VAMPIRO ED HA PRESSO LA MIA FIDANZATA", - "MA NON MI AIUTER\267", + "\324 COMPARSO UN VAMPIRO ED HA PRESO LA MIA FIDANZATA!!", + "MA NON MI AIUTERAI?!", // 355 - "MORTA? CHE VUOLE DIRE?", - "- EHEM!", - "UN VAMPIRO HA SEQUESTRATO LA RAGAZZA DELLA 506!", - "DEVI AIUTARMI!", - "NON SAI SUONARE NESSUNA DI \"ELIO E LE STORIE TESSE\"", + "MORTA? COSA INTENDI DIRE?", + "EHEM!", + "UN VAMPIRO HA RAPITO LA RAGAZZA DELLA 506!", + "MA MI DEVI AIUTARE!", + "NE SAI SUONARE QUALCUNA DI ELIO E LE STORIE TESE?", // 360 - "COME TI SOPPORTI, SUONANDO SEMPRE LO STESSO?", - "ALLORA COME MI SENTI?", - "PRESTAMI I TAPPI", + "COME FAI A RESISTERE SUONANDO SEMPRE LO STESSO PEZZO TUTTO IL GIORNO?", + "E ALLORA COME FAI A SENTIRMI?", + "PRESTAMI I TAPPI PER LE ORECCHIE", "DAI, TE LI RESTITUISCO SUBITO", "DAIIII...", // 365 - "CIAO. DEVO UCCIDERE UN VAMPIRO", + "BEH, CIAO. HO UN VAMPIRO DA UCCIDERE", "", - "COSA DICI? IN TRANSILVANO?", - "CHI \324 LO ZIO PEPPINO?", - "MA CHE SUCCEDE CON DRASCULA?", + "MA COME PARLI? IN TRANSILVANO?", + "CHI \324 LO ZIO DESIDERIO?", + "MA COSA \324 SUCCESSO CON DRASCULA?", // 370 - "CHI \324 VON BRAUN?", - "E PER CHE NON LO FA?", + "CHI \324 QUESTO VON BRAUN?", + "E PERCH\220 NON LO FA?", "E DOVE POSSO TROVARE VON BRAUN?", - "GRAZIE E CIAO, SOGNI D'ORO", - "SAR\267 MEGLIO BUSSARE PRIMA", + "GRAZIE E CIAO, DORMI BENE", + "SAR\267 MEGLIO SUONARE PRIMA", // 375 - "\324 LEI IL PROFESSORE VON BRAUN?", - "E MI POTREBBE DIRE DOVE POSSO ...?", - "NON CREDO SIA IL NANNO GANIMEDI", - "-PROFESSORE!", - "AIUTAMI! LA VITA DEL MIO AMORE DIPENDE DI LEI!", + "\324 LEI IL PROFESSOR VON BRAUN?", + "E MI POTREBBE DIRE DOVE POSSO...?", + "NON CREDO SIA IL NANO GANIMEDE", + "PROFESSORE!", + "MI AIUTI, LA PREGO! LA VITA DELLA MIA AMATA DIPENDE DA LEI!", // 380 - "VA BENE, NON HO BISOGNO DEL SUO AIUTO", - "O.K. ME NE VADO", - "NON AVERE PAURA. INSIEME VINCEREMO DRASCULA", - "ALLORA PER CHE NON MI AIUTA?", - "IO CE LE HO", + "E VA BENE, NON HO BISOGNO DEL SUO AIUTO", + "D'ACCORDO. ME NE VADO", + "NON ABBIA PAURA. INSIEME SCONFIGGEREMO DRASCULA", + "ALLORA PERCH\220 NON MI AIUTA?", + "IO LE HO", // 385 - "SI CE LE HO", + "ECCOME SE LE HO!", "D'ACCORDO", - "...EHH...SI", - "VENGO A RIENTRARE A QUESTA CABINA", - "SONO PRONTO PER FARE LA PROVA", + "...EHH ...S\326", + "SONO VENUTO PER ENTRARE DI NUOVO IN QUELLA CABINA", + "SONO PRONTO PER AFFRONTARE LA PROVA", // 390 - "VA BENE, VECCHIETO. SONO VENUTO PER IL MIO SOLDI", - "NO, NIENTE. ME NE GI\267 ANDAVO", + "E VA BENE, VECCHIETTO. SONO VENUTO PER I MIEI SOLDI", + "NO, NIENTE. ME NE STAVO ANDANDO", "SCUSA", - "TI \324 INTERESANTE QUESTO LIBRO? HA PARTITURE DI TCIAKOWSKY", + "TI INTERESSA QUESTO LIBRO? HA LE PARTITURE DI TCHAIKOWSKY", "COME POSSO UCCIDERE UN VAMPIRO?", // 395 - "NON TI HANNO DETTO CHE NON \324 BUONO DORMIRE IN CATTIVA POSIZIONE?", - "\324 QUELLO CHE SEMPRE DICE MIA MADRE", - "PER CHE DRASCULA NON FU RIUSCITO A UCCIDERTI?", - "E COSA FU?", - "BENISSIMO! HA LEI LA POZIONE DI IMMUNIT\267...!", + "NON TI HANNO DETTO CHE DORMIRE IN UNA BRUTTA POSIZIONE NON \324 SALUTARE?", + "\324 QUELLO CHE MI DICEVA SEMPRE MIA MADRE", + "PERCH\220 DRASCULA NON RIUSC\326 AD UCCIDERTI?", + "E COSA NE FU?", + "FANTASTICO! LEI HA LA POZIONE DELL'IMMUNIT\267...!", // 400 - "ALLORA", + "E ALLORA?", "MOLTO BENE", - "MI PUO RIPETERE COSA BISOGNO PER QUELLA POZIONE?", - "VADO VIA VELOCE A TROVARLO", - "SENTA, COSA \324 SUCCESO CON IL PIANISTA?", + "MI PU\343 RIPETERE DI COSA HO BISOGNO PER QUELLA POZIONE?", + "OK, CORRO A TROVARLO", + "SENTA, COSA \324 SUCCESSO CON IL PIANISTA?", // 405 "HO GI\267 TUTTI GLI INGREDIENTI DI QUESTA POZIONE", - "UNA DOMANDA: COSA \324 QUELLA DI ALUCSARD ETEREUM?", - "DICA, DICA..", + "SOLO UNA DOMANDA: COS'\324 QUELLA SCRITTA ALUCSARD ETEREUM?", + "DICA, DICA... ", "E DOV'\324 QUELLA GROTTA?", - "CHE C'\324? NON AVETE TRIBUNALE?", + "CHE C'\324? NON AVEVATE UN TRIBUNALE?", // 410 - "...MA ...E SE TROVO PI\353 VAMPIRI?", + "...MA ...E SE TROVO ALTRI VAMPIRI?", "\324 UN VAMPIRO CHE NON MI FA PASSARE", - "SI ASSOMIGLIA A YODA, MA PI\353 ALTO", - "EH, YODA. SE MI FAI PASSARE TI DAR\343 CENTO LIRE", - "BENE, O.K., NON POSSO DIRTI NULLA", + "ASSOMIGLIA A YODA, MA UN PO' PI\353 ALTO", + "EHI, YODA. SE MI FAI PASSARE TI DAR\343 UN PENNY", + "OK, CALMA, CERTO CHE CON TE NON SI PU\343 PROPRIO PARLARE", // 415 + "TI HANNO MAI DETTO CHE ASSOMIGLI A YODA?", "CIAO VAMPIRO, BELLA NOTTE, VERO?", - "TI HANNO DETTO QUALCHE VOLTA CHE TI ASSOMIGLII A YODA?", - "SEI UN VAMPIRO O UN DIPINTO ALL'OLEO?", - "MEGLIO NON DIRTI NIENTE, PERCHE POI TI ARRABBII", - "\324 CHIUSA CON LA CHIAVE", + "SEI UN VAMPIRO O UN DIPINTO A OLIO?", + "MEGLIO NON DIRE NIENTE, ALTRIMENTI POI TI ARRABBI", + "\324 CHIUSA A CHIAVE", // 420 - "SE PROVO, LA GAZZA MI POTREI CAVARE UN OCCHIO", + "SE CI PROVO LA GAZZA POTREBBE CAVARMI UN OCCHIO!", "\324 CHIUSA! DIO MIO, CHE PAURA!", - "LE CERNIERE SONO OSSIDATE", - "LA DENTRO C'\324 SOLTANTO UN BARATOLO DI FARINA", - "QUESTO HA TOLTO L'OSSIDO", + "I CARDINI SONO ARRUGGINITI", + "QUI DENTRO C'\324 SOLTANTO UN CESTO DI FARINA", + "QUESTO HA TOLTO LA RUGGINE", // 425 - "HO TROVATO UNA TALEA DI LEGNO DI PINO", - "PRENDER\343 QUESTO CH'\220 PI\353 GROSSO", - "BENE, CREDO DI POTERE TOGLIERMI QUESTO STUPIDO COSTUME", - "\"CORRIDOIO AI TORRIONI CHIUSO PER LAVORI IN CORSO. PER FAVORE, PER LA PORTA PRINCIPALE. SCUSATE PER IL DISTURBO\"", - "..\324 PALLIDO, HA DENTI CANINI, HA CIUFFO E UTILIZA MANTELLO...- SICURO CH'\324 DRASCULA!", + "HO TROVATO UN PALETTO DI LEGNO DI PINO", + "PRENDER\343 QUESTO QUI PI\353 GROSSO", + "BENE, CREDO DI POTERMI TOGLIERE QUESTO STUPIDO COSTUME", + "\"CORRIDOIO AI TORRIONI CHIUSO PER LAVORI IN CORSO. USATE LA PORTA PRINCIPALE. SCUSATE IL DISTURBO\"", + "...\324 PALLIDO, HA I CANINI IN FUORI, PORTA IL TOUPET E INDOSSA IL MANTELLO... \324 SICURAMENTE DRASCULA!", // 430 - "B.J., B.J., STAI BENE?", - "SI, SO CH'\324 SCEMA MA MI SENTO SOLISSIMO", - "NON AVRAI UNA CHIAVE PER CASO, VERO?", - "- E SICURO CHE NON HAI UN GRIMALDELLO?", - "DAMI UNA FONCINA. VADO A FARE COME MCGYVER", + "\324 B.J.! STAI BENE, B.J.?", + "S\326, LO SO CHE \324 TONTA, MA SONO COS\326 SOLO", + "NON \324 CHE HAI UNA CHIAVE, EH?", + "E SCOMMETTO CHE NON HAI NEANCHE UN GRIMALDELLO...", + "DAMMI UNA FORCINA. GIOCHER\343 A FARE MCGYVER!", // 435 "NON MUOVERTI, TORNO SUBITO", - "- MANAGIA!- SI \324 ROTTA!", - "OLE, ANCHE MI HO FATTO LA BARBA!", - "SI, CARO?", - "NON ARRIVA", + "MANNAGGIA! SI \324 ROTTA!", + "OLEEEE! MI SONO FATTO PERSINO LA BARBA!", + "S\326, TESORO?", + "NON \324 ANCORA ARRIVATO", // 440 - "IL PIANISTA NON C'\324", + "IL PIANISTA NON \324 QUI", "UN DRINK TRANSILVANO", - "ANCORA NON HO CAMERA", - "SEMBRA CHE FU RISUCCHIATO NELLO SCARICO DELLA VASCA E HA DECISO APRIRE UN BAR", - "\324 UBRIACO PERSO", + "NON HO ANCORA UNA CAMERA", + "SEMBRA CHE SIA RIMASTO INCASTRATO NELLA VASCA DA BAGNO E ABBIA DECISO DI APRIRE UN BAR", + "\324 UBRIACO FRADICIO", // 445 - "QUESTI CAPELLI.... CREDO CHE MI FANNO RICORDARE A QUALCUNO", + "QUESTO CAPELLO... MI RICORDA QUALCUNO", "\324 UNO SCHELETRO OSSUTO", - "GUARDA! MIGUEL BOSE!", - "\324 ADDORMENTATO. SAREBBE UN PECCATO SVEGLIARGLI", - "\324 PI\353 BRUTTO CHE BEGNINI", + "GUARDA! C'\324 MIGUEL BOSE!", + "STA DORMENDO. SAREBBE UN PECCATO SVEGLIARLO", + "\324 PI\353 BRUTTO DI EMILIO FEDE", // 450 - "UN FERETRO DI LEGNO DI PINO", - "MI TAGLIER\267 A FETTINI, COME UN SALSICCIOTTO", - "NON MI PIACCIONO I PENDOLI. PREFERISCO LE CARCIOFE", - "LE MIE MANI SONO LEGATE. NON CE LA FAR\343", - "\324 OVVIO CH'\324 UNA PORTA SEGRETA", + "UNA BARA IN LEGNO DI PINO", + "MI TAGLIER\267 A FETTINE, COME UN SALSICCIOTTO", + "NON MI PIACCIONO I PENDULI. PREFERISCO GLI ALCACHOFAS", + "HO LE MANI LEGATE. NON POSSO FARCELA", + "OVVIAMENTE \324 UNA PORTA SEGRETA", // 455 "MI IGNORANO", - "-DAIII!", - "NEL PRIMO COPIONE SI MUOVEVA, MA IL VIDEO-GIOCO \220 USCITO DAL BUDGET E NON HANNO POTUTO PAGARMI UNA PALESTRA E NON SONO GONFFIATO", - "SEMBRA CH'\324 UN P\343 ALLENTATA DAL MURO", - "NON CREDO CHE MI SIA UTILE. \324 TROPPO UMIDA PER ACCENDERLA.", + "DAIII!", + "SECONDO IL COPIONE SI SAREBBE DOVUTO MUOVERE, MA IL BUDGET ERA RISICATO, NON MI HANNO PAGATO LA PALESTRA E COS\326 NON HO POTUTO FARMI I MUSCOLI. FINE DELLA STORIA", + "SEMBRA UN PO' STACCATA DALLA PARETE", + "NON PENSO CHE MI TORNER\267 UTILE. \324 TROPPO UMIDA PER ACCENDERSI", // 460 - "AL LATO OVEST? -N\324 PAZZO, CHI SA CHE CI SAR\267 LI!", - "HA DEI BELLI DISEGNI TRANSILVANI", + "ALL'ALA OVEST? \324 DA PAZZI! CHISS\267 COSA POTRESTI TROVARCI!", + "HA DELLE OTTIME MOTIVAZIONI TRANSILVANE", "", - "CHE PENA CHE NON CI SIA DENTRO UN AGNELLINO ARRROSTANDOSI", - "LA ULTIMA VOLTA CHE APRII UN FORNO, LA CASA SALT\220 PER ARIA", + "PECCATO CHE NON CI SIA UN BELL'AGNELLO ARROSTO, L\326 DENTRO", + "L'ULTIMA VOLTA CHE HO APERTO UN FORNO HO FATTO SALTARE IN ARIA LA CASA", // 465 - "LO SCUDO DELLA SCUADRA DI CALCIO DI TRANSILVANIA", - "E PER CHE? PER INDOSARLA SULLA TESTA?", - "NON CREDO CHE I CASSETI SIANO DI QUELLI CHE SI APPRONO", - "NON VOGLIO SAPERE IL CIBO CHE CI SAR\267 LA DENTRO!", - "HO L'IMPRESSIONE CH'\324 IMPRESSIONISTA", + "LO STEMMA DELLA SQUADRA DI CALCIO TRANSILVANA", + "E PERCH\220? PER METTERMELA SULLA TESTA?", + "NON CREDO CHE QUESTI CASSETTI SIANO DI QUELLI CHE SI APRONO", + "NON VOGLIO SAPERE CHE RAZZA DI CIBO CI SIA L\267 DENTRO", + "MI D\267 L'IMPRESSIONE DI ESSERE IMPRESSIONISTA", // 470 - "LA NOTTE SI IMPADRONA DI TUTTI QUANTI... CHE PAURA?", - "\324 OSTACOLATA", - "\324 IL RE, NON LO AVEVI IMAGINATO?", - "NO, NE UNO A CASA, ANZI GLI DO DA MANGIARE", - "UNA SCAFFALATURA CON LIBRI ED ALTRE COSE", + "LA NOTTE CALA SU OGNUNO DI NOI... NON \324 TERRIFICANTE?", + "\324 INCASTRATA", + "\324 IL RE. LUI NON TE LO SEI IMMAGINATO, VERO?", + "NO, NE HO GI\267 UNO A CASA DA SFAMARE", + "UNO SCAFFALE CON LIBRI ED ALTRE COSE", // 475 - "E A CHI CHIAMO A QUESTE ORE?", - "\"COME FARE LA DECLARAZIONE DI REDDITI\"- CHE INTERESSANTE!", - "NE HO UNO A CASA, CREDO CH'\324 UN BEST-SELLER MONDIALE", - "UNA CHIAVE COMPLETAMENTE NORMALE", - "MI SA QHE QUESTA NON \220 DI QU\336", + "MA CHI POTREBBE MAI CHIAMARE A QUEST'ORA?", + "\"COME COMPILARE LA DICHIARAZIONE DEI REDDITI\". MOLTO INTERESSANTE!", + "NE HO GI\267 UNO A CASA. CREDO SIA UN BEST SELLER MONDIALE", + "UNA CHIAVE ASSOLUTAMENTE NORMALE", + "NON CREDO CHE SIA DI QUESTA ZONA", // 480 - "EH, SONO PATATINE FRITE A FORMA DI DENTI CANINI ! MI AFASCINA", - "NON CREDO CHE SIA IL MOMENTO MIGLIORE PER METTERSI A MANGIARE DOLCI, L'ESSERE PI\353 CATTIVO DEL MONDO ha nelle sue mani la mia fidanzzata", - "COME MI ST\343 DIVERTENDO UCCIDENDO VAMPIRI CON QUESTO!", - "VEDIAMO SE APPARISCE UN ALTRO PRESTO", - "NO, DEVE ESSERE CON UN VAMPIRO SPORCO E SCHIFFOSO COME QUELLO DI PRIMA", + "EHI, SONO PATATINE FRITTE A FORMA DI DENTI CANINI! LE ADORO!", + "NON CREDO SIA IL MOMENTO GIUSTO PER METTERMI A MANGIARE SCHIFEZZE, CONSIDERATO IL FATTO CHE LA MIA FIDANZATA \324 NELLE MANI DELL'UOMO PI\353 CATTIVO DELLA TERRA", + "ME LA STO DAVVERO SPASSANDO AD UCCIDERE VAMPIRI CON QUESTO!", + "VEDIAMO SE NE APPARE UN ALTRO", + "NO, DEV'ESSERE UN VAMPIRO SUDICIO E MALEODORANTE COME QUELLO CHE HO UCCISO PRIMA", // 485 - "\324 L'AUTENTICA PARRUCA CHE UTILIZZ\343 ELVIS QUANDO DIVENT\343 PELATO", - "\220 FARINA MA NON POSSO DIRE MARCHE", - "FORSE IN UN ALTRO MOMENTO. OK?", - "\220 UNA ASCIA BUONISSIMA, CHE PENA CHE NON CI SIA QU\336 VICINO NESSUNA TESTA DI VAMPIRO", - "NO. NEL FONDO SONO UNA BRAVISSIMA PERSONA", + "\324 L'AUTENTICA PARRUCCA CHE UTILIZZ\343 ELVIS QUANDO DIVENT\343 PELATO", + "\324 FARINA, MA NON POSSO DIRE LA MARCA", + "FORSE UN'ALTRA VOLTA, VA BENE?", + "\324 UN'ASCIA MAGNIFICA, PECCATO CHE NON CI SIA NEMMENO UNA TESTA DI VAMPIRO QUI INTORNO", + "NO. IN FONDO SONO UNA BRAVISSIMA PERSONA", // 490 - "\324 IL DEODORANTE DELLA TACHER -HI,HI,HI!", - "\324 UN MANTELLO ABBASTANZA CARINO", + "\324 IL DEODORANTE DELLA TATCHER ... AH, AH, AH...!!", + "\324 UN MANTELLO MOLTO CARINO", "", - "COME TUTTI I RAMI DI TUTTI GLI ALBERI DEL MONDO, CIO\324 MICA SPEZIALE", - "OH, INCREDIBILE!- UNA CORDA IN UNA AVVENTURA GRAFICA!", + "COME I RAMI DI TUTTI GLI ALBERI DEL MONDO. NON CI VEDO NIENTE DI SPECIALE", + "OH, INCREDIBILE! UNA CORDA IN UN'AVVENTURA GRAFICA!", // 495 - "MI DOMANDO A CHE SERVE...", - "UNA CORDA LEGATA A UNA BRANCA, O UNA BRANCA LEGATA A UNA CORDA, DIPENDE COME SI GUARDI", - "SEMBRA CHE QUESTA GAZZA HA CATIVE INTENZIONI", - "DAI.., NON LA DICO NULLA CHE POI SI ARRABBIA", - "SEMBRA ESSERE MORTA, MA NON \220 VERO - EH?", + "MI DOMANDO A COSA POSSA SERVIRE...", + "UNA CORDA LEGATA AD UN RAMO O UN RAMO LEGATO AD UNA CORDA, DIPENDE DA COME SI GUARDA", + "PARE CHE QUESTA GAZZA ABBIA CATTIVE INTENZIONI", + "SCORDATELO, NON DIR\343 NULLA ALTRIMENTI SI ARRABBIA", + "MI SEMBRA MORTA, MA NON LO \324 VERAMENTE, VERO?", // 500 - "NESSUN ANIMALE \220 STATO MALTRATO DURANTE LE RIPRESE DI QUESTO VIDEO-GIOCO", + "NESSUN ANIMALE HA SUBITO MALTRATTAMENTI DURANTE LA PRODUZIONE DI QUESTO VIDEOGIOCO", }, }; @@ -4075,52 +4075,52 @@ const char *_textd[NUM_LANGS][NUM_TEXTD] = { { // 0 "", - "COME VA, IGOR?", - "-SEMPRE CHE C' UNA BUONA PARTITA SUCCEDE LO STESSO! BENE, ANDREMO A GUARDARLA AL BAR, COME SEMPRE", - "ADESSO IGOR, ASCOLTA. ANDIAMO A REALIZZARE LA FASE 1 DEL MIO PROGETTO PER CONQUISTARE IL MONDO", - "ATTRARREMO UN FULMINo DELLA TEMPESTA E LO DISMAGNETIZZAREMO CON L'INDIFIBULATORE. LA ELETTRICIT\265 ANDR\265 AL MIO MOSTRO E, GLI DAR\265 VITA!", + "COME STA ANDANDO, IGOR?", + "\324 SEMPRE LA STESSA STORIA, OGNI VOLTA CHE C'\324 UNA BELLA PARTITA SUL SATELLITE! COMUNQUE ANDREMO A VEDERLA AL BAR, COME AL SOLITO", + "ADESSO ASCOLTA BENE, IGOR, SIAMO ALLA FASE NUMERO UNO DEL MIO PIANO PER LA CONQUISTA DEL MONDO", + "ATTIREREMO UN FULMINE E LO DEMAGNETIZZEREMO CON L'INDIFIBULATORE. L'ELETTRICIT\267 VERR\267 TRASFERITA AL MOSTRO E GLI DAR\267 LA VITA!", // 5 - "SE TUTTO VA BENE QUESTO SAR\265 SOLTANTO IL PRIMO DI UN'IMMENSO ESERCITO CHE CONQUISTAR\265 IL MONDO PER ME, HA,HA,HA", - "I MOSTRI DISTRUGGERANNO TUTTE LE ARME DI TUTTI GLI ESERCITI DEL MONDO, MENTRE NOI CI RIFURGIAREMO nei miei terreni A GIBRALTAR", - "POI, FAREMO UN GOLPE, E I GOVERNI DEL MONDO NON AVRANNO PER DIFENDERSI, E AVR\220 LE LORO NAZIONI SOTTO I MIEI PIEDI", - "SAR\220 IL PRIMO CATTIVO DELLA STORIA CHE RIESCA!", - "A TE NIENTE, SCIOCCO! ST\220 SPORRENDO LA TRAMA. BENE, TUTTO A POSTO?", + "SE TUTTO ANDR\267 PER IL VERSO GIUSTO, QUESTO SAR\267 L'INIZIO DI UN GRANDE ESERCITO CHE CONQUISTER\267 IL MONDO PER ME, AH, AH, AH", + "I MOSTRI DISTRUGGERANNO TUTTI GLI ESERCITI DEL MONDO, MENTRE NOI CI RIFUGEREMO IN UNO DEI TERRENI CHE HO COMPRATO A GIBILTERRA", + "POI FAREMO UN COLPO DI STATO, I GOVERNI DI TUTTO IL MONDO NON AVRANNO MODO DI DIFENDERSI E SI PROSTRERANNO AI MIEI PIEDI", + "SAR\343 IL PRIMO CATTIVO DELLA STORIA A RIUSCIRCI! AH, AH!", + "NON STO PARLANDO CON TE, IDIOTA! STO ESPONENDO LA TRAMA. BENE, \324 TUTTO PRONTO?", // 10 - "-\220 IL MOMENTO! -PREMI L'INTERRUTTORE DELLE BATTERIE ALCALINE!", - "- PORCA MISERIA! -CHE COSA NON \220 ANDATA BENE?", - "SEI SICURO DI AVERLO CONTROLLATO BENE? E NO MANCABA NIENTE? ULTIMAMENTE PER I REDDITI NON VEDI UNA MADONNA", - "IMBECILE!, NON HAI CONETTATO L'INDIFIBULATORE! LE VITI SARANO MAGNETIZZATE E ADESSO AVR\265 IL CERVELLO BRUCIATO", - "SEI MORTO, SEI MORTO, COME TI PRENDA..", + "\324 IL MOMENTO! PREMI L'INTERRUTTORE DELLE BATTERIE ALCALINE!", + "PORCA MISERIA! COS'\324 ANDATO STORTO?", + "SEI SICURO DI AVERLO CONTROLLATO BENE E CHE NON MANCASSE NULLA? ULTIMAMENTE QUESTA STORIA DELLE TASSE TI STA MANDANDO DAVVERO FUORI DI TESTA", + "IDIOTA! HAI DIMENTICATO DI CONNETTERE L'INDIFIBULATORE. PROBABILMENTE LE VITI SI SARANNO MAGNETIZZATE E IL SUO CERVELLO SI SAR\267 ABBRUSTOLITO", + "SEI MORTO, SEI MORTO... ASPETTA CHE TI PRENDA!", // 15 - "STAI ZITTO! DOMANI CERCHER\220 UN ALTRO CERVELLO E RIPETEREMO L'ESPERIMENTO", - "NO. QUESTA VOLTA NE PORTER\220 UNO DI DONNA, COS\326 SAR\265 NUOVISSIMO, MAI UTILIZZATO. HA, HA HA, CHE BARZELLETA FALLITA", - "E? SONO IL CATTIVO DELLA STORIA, E SONO MASCHILISTA SE VOGLIO, CAPITO? E NON LAMENTARTI UNA ALTRA VOLTA PERCHE MANGERAI LA TUA GOBBA", - "HA,HA,HA. UN ALTRO PRESSO. ADESSO PAGHERAI MOLTO CARO QUESTA OFFESA, LA TUA INTENZIONE DI FINIRE CON ME. -IGOR, AL PENDOLO DELLA MORTE!", - "DIMI, STUPIDO UMANO, COME MAI HAI PENSATO A DISTRUGGERMI?", + "STAI ZITTO! DOMANI CERCHER\343 UN ALTRO CERVELLO E RIPETEREMO L'ESPERIMENTO", + "NO. QUESTA VOLTA PRENDER\343 UN CERVELLO DI DONNA. PRATICAMENTE NUOVO, MAI UTILIZZATO. AH, AH,AH, BUONA QUESTA. ", + "E ALLORA? SONO IO IL CATTIVO DELLA STORIA, E POSSO ESSERE MASCHILISTA QUANTO VOGLIO, CAPITO? E SE DICI ANCORA QUALCOSA TI APPICCICO LA GOBBA IN FRONTE!", + "AH, AH, AH, CI SEI CASCATO ANCHE TU!! ADESSO LA PAGHERAI PER AVER OSATO SFIDARMI! IGOR, PORTALO AL PENDOLO DELLA MORTE!", + "DIMMI, STUPIDO UMANO, COME MAI VOLEVI DISTRUGGERMI?", // 20 - "-CHE BELLO!, MI METTEREI A PIANGERE SE NON FOSSE PERCHE MI FA RIDERE", - "HO BISOGNO DELLA TUA RAGAZZA, IL SUO CERVELLO MI AIUTER\265 A CONQUISTARE IL MONDO", - "-SI, HA ! VADO A TOGLIARSILO PER METTEGLIELO AL MIO FRUSKYNSTEIN, E CON LUI DOMINER\220 IL MONDO, HA,HA,HA", - "CHE?! - SEI MORTO, SEI MORTO! TI VADO A...MI HAI FATTO ARRABBIARE. SEI PRONTO PER MORIRE?", - "HA,HA,HA. TU CREDI?", + "CHE BELLO! SE NON MI FACESSE RIDERE, MI METTEREI A PIANGERE", + "HO BISOGNO DELLA TUA RAGAZZA, IL SUO CERVELLO MI AIUTER\267 A CONQUISTARE IL MONDO", + "S\326, SICURO! LO PRENDER\343 DA LEI E LO DAR\343 AL MIO FRUSKYNSTEIN. IL MONDO SAR\267 NELLE MIE MANI, AH, AH, AH", + "COSA!? SEI UN UOMO MORTO! TI FAR\343... MI HAI FATTO VERAMENTE ARRABBIARE... PREPARATI A MORIRE!", + "AH, AH, AH. TI PIACEREBBE!", // 25 - "SI, VERO? HA,HA,HA", - "VA BENE, PUOI FUMARE LA ULTIMA SIGARETTA, MA SBRIGATI", - "SONO STUFFO, BUTTA GI\265 LA SIGARETTA!", - "E DIMI, QUELLA POZIONE HA L'EFFETTO INVERSO?", - "QUELLO SI VEDR\265 ..", + "S\326, VERO? AH, AH AH", + "VA BENE, PUOI FUMARTI L'ULTIMA SIGARETTA. MA FAI PRESTO, OK?", + "MI HAI STUFATO, BUTTA VIA QUELLA SIGARETTA!", + "DIMMI UNA COSA, QUELLA POZIONE HA ANCHE L'EFFETTO OPPOSTO?", + "QUESTO LO VEDREMO...", // 30 - "BENE, SAR\265 VERO?. IGOR, DAMI IL COMPACT DISC DI UNGHIE GRAFFIANDO UNA LAVAGNA", - "NEANCHE SOGNARLO. LA RAGAZZA RIMANE CON ME, E TU RIMANI LI FINO CHE IL PENDOLO TI TAGLII IN FETTE. HA,HA,HA", - "MA COME SONO CATTIVO, ANDIAMO IGOR, ANDIAMO A FARE LA POZIONE, ANDIAMO A CONQUISTARE IL MONDO", + "OK, ADESSO VEDREMO. IGOR DAMMI IL CD \"UNGHIE CHE GRAFFIANO LA LAVAGNA\"", + "NEANCHE PER SOGNO. LA RAGAZZA RIMANE QUI. E TU ASPETTERAI FINCH\220 IL PENDOLO NON TI AVR\267 FATTO A FETTINE. AH, AH, AH", + "CAVOLI, SONO DAVVERO CATTIVO... ANDIAMO, IGOR; PREPARIAMO LA POZIONE E CONQUISTIAMO IL MONDO", "ADESSO CHE SUCCEDE?", - "SI, CHE C'E?....LA PARTITA!", + "S\326, CHE C'\324?... OH DANNAZIONE, LA PARTITA!", // 35 - "L'AVEVO DIMENTICATA. PRENDI LA RAGAZZA E ANDIAMO A GUARDARE IL CALCIO. CONQUISTER\220 IL MONDO DOPO", + "ME L'ERO DIMENTICATA. PRENDI LA RAGAZZA E ANDIAMO A GUARDARCELA. CONQUISTEREMO IL MONDO PI\353 TARDI", "GRAZIE AMICO, AVEVO SETE", - "-ARGH! -QUEL CROCIFISSO! -QUEL CROCIFISSO!...", - "QUE BELLO \220 QUEL CROCIFISSO, NON MI ERO ACCORTO", - "LASCIAMI, ST\220 GUARDANDO LA PARTITA", + "ARGH! QUEL CROCIFISSO! QUEL CROCIFISSO!...", + "CHE BELLO QUEL CROCIFISSO, NON L'AVEVO NOTATO", + "LASCIAMI IN PACE, STO GUARDANDO LA PARTITA", // 40 "", "", @@ -4141,39 +4141,39 @@ const char *_textd[NUM_LANGS][NUM_TEXTD] = { "", // 55 "", - "Ciao cieco. Come va?.", - "Come sai che sono straniero.", - "Sembri un cieco. Hai gli occhiali come il cieco di Sorrento, parli guardando all'infinito come Stevie Wonder..", - "Bene, scusa. Non sapevo che non vedessi", + "CIAO CIECO. COME VA?", + "COME SAI CHE SONO UNO STRANIERO?", + "SEMBRI UN CIECO. HAI GLI OCCHIALI COME IL CIECO DI SORRENTO, PARLI GUARDANDO ALL'INFINITO COME STEVIE WONDER..", + "GUARDA, MI DISPIACE. NON SAPEVO CHE CI VEDESSI", // 60 - "Ma non mi hai appena detto che non sei cieco?.", - "- Ma se non vedi!.", - "Beeeene. Scusa. Allora: Ciao : non vedente", - "Sono John Hacker, st giocando al Drascula. Tu devi proprio essere il tipico personaggio che mi aiuter in cambio di un oggeto. Vero...?", - "Ma... Scusa ciec..- non vedente! .Ma.. . che tipo di mestiere il tuo, di dare falci per soldi, mentre suoni la fisarmonica?.", + "MA NON MI HAI APPENA DETTO CHE NON SEI CIECO?", + "MA SE NON VEDI!", + "BEEEENE. SCUSA. ALLORA: \"CIAO NON VEDENTE\"", + "SONO JOHN HACKER, STO GIOCANDO A DRASCULA. TU DEVI PROPRIO ESSERE IL TIPICO PERSONAGGIO CHE MI AIUTER\267 IN CAMBIO DI UN OGGETTO. VERO? EH? VERO?", + "SCUSA SE TE LO DOMANDO, CIEC... NON VEDENTE! MA... CHE TIPO DI MESTIERE \324 IL TUO, DI DARE FALCI PER SOLDI, MENTRE SUONI LA FISARMONICA?", // 65 - "Ah, si. \324 vero. Ciao non vedente....(cieco)", - "Ecco la abbondante quantit di soldi che mi avevi chiesto.", - "Mi raccomando", - "Ciao straniero.", - "E tu... Come sai che sono cieco?", + "AH, S\326. \324 VERO. CIAO NON VEDENTE...(CIECO)", + "ECCO LA COSPICUA SOMMA DI DENARO CHE MI HAI CHIESTO", + "LO SPERO PROPRIO", + "CIAO STRANIERO.", + "E TU... COME SAI CHE SONO CIECO?", // 70 - "E tu parli come il figlio di Bill Cosby e non ti offendo.", - "No, se non vedo.", - "E non lo sono.", - "-Oh, certo!. Come non vedo mi chiamano cieco, no?.", - "-Ciao Straniero! e cosa fai in Transilvania?", + "E TU PARLI COME IL FIGLIO DI BILL COSBY E NON TI OFFENDO.", + "NO, NON CI VEDO.", + "E NON LO SONO.", + "OH, CERTO! SICCOME NON CI VEDO TU MI ACCUSI DI ESSERE CIECO.", + "CIAO STRANIERO! COSA CI FAI IN TRANSILVANIA?", // 75 - "Corretto straniero. Per una abbondante quantit di soldi, ti dar in cambio una falce, per quando ne avrai bisogno.", - "Shhhhhh. Sono trafficante di falci, devo proprio dissimulare.", - "Perche mi lo hai detto prima, no?", - "Grazie straniero. Ecco la tua falce. Un oggeto che ti sar molto utile pi avanti...... davvero.", + "CORRETTO, STRANIERO. PER UN'ABBONDANTE QUANTIT\267 DI DENARO TI DAR\343 UNA FALCE, PER QUANDO NE AVRAI BISOGNO.", + "SHHHHHH. SONO TRAFFICANTE DI FALCI, PER QUESTO DEVO FINGERE.", + "PERCH\220 ME LO HAI DETTO PRIMA, NO?", + "GRAZIE STRANIERO. ECCO LA TUA FALCE. UN OGGETTO CHE TI SAR\267 MOLTO UTILE PI\353 AVANTI...... DAVVERO.", "", // 80 "", "", - "No, nada", - "bla, bla, bla." + "NO, NIENTE", + "BLA, BLA, BLA.", }, }; @@ -4261,22 +4261,22 @@ const char *_textb[NUM_LANGS][NUM_TEXTB] = { { // 0 "", - "QU\326, BEVENDO", - "MORTI TUTTI. GRAZIE. BURRP", - "SII, CERTO, SICURO..", - "QUESTA PER IL ZIO PEPPINO", + "SONO QUI, STO BEVENDO", + "SONO TUTTI MORTI. GRAZIE. BURRP", + "S\326, CERTO, SICURO...", + "QUESTA \324 PER LO ZIO DESIDERIO", // 5 - "E QUEST'ALTRA, PER IL CADAVERE DEL ZIO PEPPINO", - "MIO ZIO. FU ANDATO AL CASTELLO, E NON MAI TORNATO", - "EEEHH, TORN\220, MA PER POCO TEMPO. SE IL VON BRAUN NON AVESSE SBAGLIATO, MIO ZIO SAREBBE QU\326 BEVENDO", - "NIENTE..", - "EEH,SI! QUEL MALVAGIO CI HA INTIMORATI", + "E QUEST'ALTRA \324 PER IL CADAVERE DELLO ZIO DESIDERIO", + "MIO ZIO. \324 ANDATO AL CASTELLO E NON \324 PI\353 TORNATO", + "EH, TORN\343, MA NON TUTTO INTERO. SE VON BRAUN NON AVESSE SBAGLIATO, ADESSO MIO ZIO SAREBBE QUI A BERE CON NOI", + "NIENTE...", + "EH, S\326! QUEL MALVAGIO CI HA INTIMORITI TUTTI", // 10 - "A VOLTE SCENDE AL PAESE E QUANDO SE NE VA SI PORTA QUALCUNO", - "UN P\220 DOPO SOLTANTO TROVIAMO QUALQUE RESTO. CREDO CHE TRAFFICA ORGANI O QUALCOSA DEL GENERE", - "L'UNICO DEL PAESE CHE SA COME FINIRE CON DRASCULA \220 UNO CHE HA STUDIATO", - "DA CHE FU SCONFFIGIATO DA DRASCULA SI \220 ALLONTANATO A UNA CAPANNA FUORI DEL PAESE", - "L'UNICO CHE POTREBBE AIUTARCI A VINCERE DRASCULA, E NON VUOLE SAPERE NIENTE DI NOI. COSA PENSI?", + "A VOLTE SCENDE IN PAESE E QUANDO SE NE VA SI PORTA VIA QUALCUNO", + "POCO DOPO TROVIAMO SOLTANTO QUALCHE RESTO. CREDO CHE SIA UN TRAFFICANTE DI ORGANI O QUALCOSA DEL GENERE", + "\324 L'UNICA PERSONA DEL VILLAGGIO CHE SAPPIA COME FARLA FINITA CON DRASCULA. \324 UNO CHE HA STUDIATO", + "DA QUANDO FU SCONFITTO DA DRASCULA VIVE IN UNA BARACCA FUORI DAL PAESE", + "LUI \324 L'UNICO CHE POTREBBE AIUTARCI A SCONFIGGERE DRASCULA, MA NON VUOLE SAPERNE. TU CHE NE PENSI?", }, }; @@ -4432,39 +4432,39 @@ const char *_textbj[NUM_LANGS][NUM_TEXTBJ] = { { // 0 "", - "ST\265 BENE? SENTA, PUO SENTIRMI? SI \220 MORTO?", - "NO, IL MIO NOME BILLIE JEAN, MA PUOI CHIAMARMI B.J. PI \351 BREVE", - "HI,HI!- CHE BUONO!", - "NON SO JOHNY, ERO QU\326, STAVO PER ADDORMENTARMI, QUANDO HO SENTITO UN FORTE RUMORE NEL CORRIDOIO", + "TI SENTI BENE? ANDIAMO, SVEGLIATI! RIESCI A SENTIRMI? MA SEI MORTO?", + "NO, MI CHIAMO BILLIE JEAN, MA PUOI CHIAMARMI B.J., \324 PI\353 CORTO.", + "HI, HI! QUESTA ERA BUONA!", + "BEH, JHONNY. VEDI, ME NE STAVO QUA, GI\267 PRONTA PER ANDARE A LETTO, QUANDO HO SENTITO UN FORTE RUMORE IN CORRIDOIO", // 5 - "PRIMA NON GLI HO DATTO IMPORTANZA, MA DUE ORE DOPO HO SCOPERTO CHE NON RIUSCIVO A ADDORMENTARMI E SONO uscita A FARE QUATTRO PASSI", - "E FIGURATI LA SORPRESA QUANDO HO APERTO LA PORTA E TI HO TROVATO PER TERRA. TI GIURO, HO PENSATO CH'ERI MORTO..., MA COME SONO SCIOCCA", - "VOLEVO FARTI IL BOCCA A BOCCA, MA NON C'ERA BISOGNO PERCHE SUBITO HAI COMINCIATO A PARLARE", - "HAI DETTO NON SO CHE DI UN SPAVENTAPASSERI. CHE COLPO.....!, PERCHE QUANDO UN MORTO SI METTE A PARLARE FA UN COLPO GRANDISSIMO!", - "VERO DI SI? NON SO COME SONO RIUSCITA, TI HO TRASPORTATO ALLA MIA CAMERA, TI HO MESSO SUL MIO LETTO E.... NIENTE PI\351 .", + "ALL'INIZIO NON CI HO FATTO CASO, MA DOPO CIRCA DUE ORE NON RIUSCIVO ANCORA A PRENDERE SONNO E ME NE SONO ANDATA A FARE DUE PASSI", + "E IMMAGINA LA MIA SORPRESA QUANDO HO APERTO LA PORTA E TI HO VISTO DISTESO A TERRA. TI GIURO, HO PENSATO CHE FOSSI MORTO... AH, AH, CHE SCIOCCA", + "VOLEVO FARTI LA RESPIRAZIONE BOCCA A BOCCA MA NON \324 SERVITO PERCH\220 HAI INIZIATO A PARLARE", + "HAI DETTO QUALCOSA A PROPOSITO DI UNO SPAVENTAPASSERI. MI HAI FATTO VENIRE UN COLPO. SAI, \324 ABBASTANZA SCIOCCANTE VEDERE UN MORTO CHE PARLA", + "VERO? NON SO COME, MA SONO RIUSCITA A PORTARTI IN CAMERA MIA, TI HO MESSO SUL LETTO E... QUESTO \324 TUTTO... AH, AH, AH.", // 10 - "NO, NON \220 STATA LA BOTTA, HI, HI. \220 PERCHE ... HO PESTATO I TUOI OCCHIALI", - "MAMMA MIA MA COM'\220 BELLO CON GLI OCCHIALI! SO CHE NON \220 FERNANDO LANCHA, MA HA QUALCOSA CHE MI PIACE MOLTISSIMO", - "SI,SI, VOGLIO... ABBRACIAMI FORTE, BACIAMI MOLTO..", - "OH JOHNY, CARO, MENO MALE CHE SEI VENUTO. QUEL MALVAGIO, DRASCULA, MI HA LEGATO AL LETTO E POI SE NE \220 ANDATO A GUARDARE LA PARTITA", - "SI, \220 VERO, LIBERAMI", + "NO, NON \324 STATA LA BOTTA, HI, HI. \324 CHE PER SBAGLIO HO PESTATO I TUOI OCCHIALI", + "MAMMA MIA COM'\324 BELLO CON GLI OCCHIALI! SO CHE NON \324 ANTONIO BANDERAS, MA HA QUALCOSA CHE MI PIACE MOLTISSIMO", + "S\326, S\326, LO VOGLIO... ABBRACCIAMI FORTE, BACIAMI...", + "OH JOHNNY, CARO, MENO MALE CHE SEI QUI. DRASCULA, QUEL MALEDETTO, MI HA LEGATA AL LETTO E POI SE NE \324 ANDATO A GUARDARE LA PARTITA", + "S\326, \324 VERO, LIBERAMI", // 15 - "NO, MI DISPIACE. HO UTILIZZATO TUTTE IN CARCERE PROBANDO LIBERARMI QUANDO TU MI AVEVI LASCIATA", - "JOHNY, SEI TU? - BENISSIMO. LO SAPEVO ", - "NON TI FIGURI QUANTO MI HA FATTO SOFFRIRE DRASCULA", - "PRIMA MI HA PORTATO VOLANDO FINO QUA E POI MI HA RICHIUSA IN QUESTA CAMERACCIA CHE NON HA N\220 UNO SPECCHIO", - "COME HAI SENTITO. E LO PEGLIORE: N\220 UNA VOLTA SI \220 SCUSATO", + "NO, MI DISPIACE. LE HO USATE TUTTE NELLA CELLA CERCANDO DI LIBERARMI QUANDO MI HAI ABBANDONATA", + "JOHNNY, SEI TU? OH, GRAZIE AL CIELO, SAPEVO CHE SARESTI VENUTO!", + "NON IMMAGINI NEMMENO QUANTO QUEL MALVAGIO DI DRASCULA MI ABBIA FATTO SOFFRIRE", + "PRIMA MI HA PORTATO FIN QUA VOLANDO E POI MI HA RINCHIUSA IN QUESTA CAMERACCIA CHE NON HA NEANCHE UNO SPECCHIO", + "\324 QUELLO CHE TI STO DICENDO! E IL PEGGIO \324 CHE NON SI \324 MAI SCUSATO, NEMMENO UNA VOLTA", // 20 - "JOHNY, CARO. DOVE SEI?", - "SONO PRONTA, FAMI USCIRE DA QU\326 ", - "ASPETTA, VADO A GUARDARE... NO CARO, MI DISPIACE", - "PRENDI..", - "\"CARO JOHNY:", + "JOHNNY, CARO. DOVE SEI?", + "SONO PRONTA, FAMMI USCIRE DA QUI", + "ASPETTA CHE CONTROLLO... NO, CARO, MI DISPIACE", + "PRENDI...", + "\"CARO JOHNNY", // 25 - "MAI POTR\220 DIMENTICARTI, MA NON SAREMO MAI FELICI INSIEME. SAR\220 SINCERA CON TE : C'\220 NE UN ALTRO; PI\351 ALTO, PI\351 FORTE..", - "ANZI MI HA LIBERATO DA DRASCULA. MI HA CHIESTO LA MANO E HO DETTO DI SI", - "ADIO JOHNY. NON CERCARE UNA SPIEGAZIONE, PERCHE L'AMORE \220 CIECO.", - "SPERO NON MI ODII, E RICORDA CHE ANCORA TI VOGLIO BENE, SEBBENE SOLO COME UN AMICO\"", + "NON POTR\343 MAI DIMENTICARTI, MA NON SAREMO MAI FELICI INSIEME. SAR\343 SINCERA CON TE: C'\324 UN ALTRO; PI\353 ALTO, PI\353 FORTE...", + "MI HA LIBERATO DA DRASCULA. MI HA CHIESTO LA MANO E HO DETTO DI S\326", + "ADDIO JOHNNY. NON CERCARE UNA SPIEGAZIONE, PERCH\220 L'AMORE \324 CIECO.", + "SPERO CHE NON MI ODIERAI, E RICORDA CHE TI VOGLIO BENE, SEBBENE TU PER ME SIA SOLTANTO UN AMICO\"", }, }; @@ -4597,33 +4597,33 @@ const char *_texte[NUM_LANGS][NUM_TEXTE] = { { // 0 "", - "EO, LEI", - "MA CHE DICI!", - "SONO VIVO, MA HO SEMPRE MOLTA FAME, SA LEI?", - "IO ERO IL BEONE DEL PAESE, DEGNO SUCCESSORE DI UNA FAMIGLIA DI ILLUSTRI BEONI, E UNA NOTTE DRASCULA MI SEQUESTR\220 PER RUBARMI GLI ORGANI", + "EHI, LEI!", + "NON RACCONTARMI CERTE CAVOLATE SU UN CADAVERE, OK?", + "SONO VIVO. STO SOLO MORENDO DI FAME", + "IO ERO L'UBRIACONE DEL PAESE, DEGNO SUCCESSORE DI UNA FAMIGLIA DI ILLUSTRI UBRIACONI, E UNA NOTTE DRASCULA MI RAP\326 PER RUBARMI GLI ORGANI", // 5 - "mi utilizza COME UNO SCASSO, OGNI VOLTA CHE HA BISOGNO DI QUALCOSA PER IL MOSTRO CHE ST\265 CREANDO VIENE QUA E MI LO toglia", - "AL INIZIO MI FACEVA MALE, MA ORA NON FA NIENTE", - "NON SO, SAR\265 LA SUA TESINA DI FINE DI LAUREA", - "IL MIO NOME PEPPINO, PER SERVIRGLI", - "LA VERIT\265 CHE NON HO MOLTA VOGLIA, COMUNQUE GRAZIE MILE, SIGNORE", + "SICCOME L'ALCOL MI MANTIENE IN VITA, MI TIENE QUI COME UNA SCORTA. OGNI VOLTA CHE HA BISOGNO DI QUALCOSA PER IL MOSTRO CHE STA CREANDO, VIENE DA ME E SE LO PRENDE", + "ALL'INIZIO FACEVA MALE, MA ORA NON SENTO PI\353 NULLA", + "NON SO, MAGARI SAR\267 LA SUA TESI DI LAUREA", + "IL MIO NOME \324 DESIDERIO, PER SERVIRVI", + "LA VERIT\267 \324 CHE NON HO MOLTA VOGLIA, COMUNQUE GRAZIE MILLE, SIGNORE", // 10 - "SI, PROPRIO TU", - "PER CHE TUTTI I VIDEO-GIOCHI D' AVVENTURE FINISCONO CON UN'ALBEGGIARE O UN TRAMONTO?", - "E TUTTI QUESTI NOMI SONO DI CHI HANNO FATTO IL GIOCO?", - "E NON SI VERGOGNANO DI USCIRE ED ESSERE VISTI DA TUTTI QUANTI?", - "UFFA, SOLTANTO ESCI \"EMILIO DE PAZ\"", + "PROPRIO TU!", + "PERCH\220 TUTTI I GIOCHI D'AVVENTURA FINISCONO SEMPRE CON UN'ALBA O UN TRAMONTO?", + "E TUTTI QUESTI NOMI SONO DI CHI HA FATTO IL GIOCO?", + "E NON SI VERGOGNANO A FARSI VEDERE DA TUTTI?", + "CAVOLI, QUELL'EMILIO DE PAZ \324 DAPPERTUTTO!!", // 15 "DAVVERO?", - "SI", - "NON \220 PER METTERSI COS\326 ", - "CERTO LUPO-MANNARO..", - "... MA NON SEI CADUTO DA UNA FINESTRA E TI HAI FATTO MALE?", + "S\326", + "BEH, NON NE FARE UNA QUESTIONE", + "CERTO, LUPO MANNARO...", + "... MA NON TI SEI FATTO MALE CADENDO DA UNA FINESTRA?", // 20 - "SE PER UNA VOLTA NON FOSSENO SEMPRE GLI STESSI", - "QUELLO \220 GIA USCITO QUATRO VOLTE", - "MI PIACEREBBE ESSERE TOP MODEL", - "SI, E TU, COSA VAI A FARE?", + "SE PER UNA VOLTA NON FOSSERO SEMPRE GLI STESSI", + "QUELLO \324 GIA USCITO QUATTRO VOLTE", + "MI PIACEREBBE ESSERE UN MODELLO", + "S\326, E TU COSA FARAI?", }, }; @@ -4800,44 +4800,44 @@ const char *_texti[NUM_LANGS][NUM_TEXTI] = { { // 0 "", - "MAESTRO, CREDO CHE QUESTO NON VA", - "SICURISSIMO, MAESTRO", - "SCUSI, MAESTRO", - "VA A PORTARE UN ALTRO SCIENTIFICO PAZZO? GLI AVVERTO CHE IL LABORATORIO PIENO E NE ABBIAMO TUTTI SCADUTI", + "PADRONE, CREDO NON STIA FUNZIONANDO", + "SICURISSIMO, PADRONE", + "MI DISPIACE, PADRONE", + "HAI INTENZIONE DI ATTIRARE ALTRI SCIENZIATI PAZZI? IL LABORATORIO \324 GI\267 PIENO, E TRA L'ALTRO SONO TUTTI SCADUTI.", // 5 - "ZITTO, MAESTRO, FIGURASI SE LE SENTONO LE FEMMINISTE", - "ACCIDENTI!", - "-MAESTRO! NON LE ASPETTAVO COS\326 PRESTO!", - "MALE MAESTRO, DEVONO CI ESSERE PROBLEMI CON IL SATELLITE E NON RIESCO A SINTONIZZARE L'IMMAGINE. ANZI LA TEMPESTA CAUSA INTERFERENZE", - "CHE NE SO, MAESTRO", + "ZITTO, PADRONE, LE FEMMINISTE POTREBBERO SENTIRLA", + "DANNAZIONE!", + "PADRONE! NON LA ASPETTAVO COS\326 PRESTO!", + "MALE, PADRONE; DEV'ESSERCI UN PROBLEMA CON IL SATELLITE E NON RIESCO A SINTONIZZARE L'IMMAGINE. SEMBRA CHE LA TEMPESTA CAUSI INTERFERENZE", + "NON SAPREI, PADRONE", // 10 - "SI, MAESTROl", - "MAESTRO", + "S\326, MIO PADRONE", + "PADRONE", "SA CHE ORE SONO?", - "EH? -AH, CHE COLPO! TU SEI QUELLO DI \"PULIZIA NOTTURNA\" NO?", - "IO SONO IGOR, IL MAGGIORDOMO. PUOI COMINCIARE NEL SALOTTO DI BALLO, IERI C'ERA ORGIA SOPRANATURALE ED \220 PIENO DI MERDA", + "COSA? AH, MI HAI SPAVENTATO! TU SEI IL \"RAGAZZO DELLE PULIZIE NOTTURNE\" GIUSTO?", + "SONO IGOR, IL MAGGIORDOMO. PUOI COMINCIARE DALLA SALA DA BALLO. IERI \324 STATA TEATRO DI UN'ORGIA SOPRANNATURALE ED OGGI \324 RIDOTTA AD UNA MERDA.", // 15 "SE HAI BISOGNO DI QUALCOSA, COMPRALA", - "LA DECLARAZIONE DI REDDITI, NON VEDI?", - "NEANCH'IO, I NUMERI SONO PICCOLISSIMI E ANZI, IO NON VEDO BENE DA LONTANO", - "NEANCHE PARLARNE, MI FANNO SEMBRARE BRUTTO", - "\220 UNA FESTA CHE FA IL MAESTRO PER I SUOI AMICI OGNI VOLTA CHE ARRIVA QUALCHE IMBECILE CHE VUOLE FINIRE CON LUI", + "\324 LA DICHIARAZIONE DEI REDDITI, NON VEDI?", + "NEANCH'IO. I NUMERI SONO PICCOLISSIMI E NON CI VEDO MOLTO BENE DA LONTANO", + "NEANCHE PER SOGNO! MI FANNO SEMBRARE BRUTTO", + "\324 UNA FESTA CHE ORGANIZZA IL PADRONE CON I SUOI AMICI OGNI VOLTA CHE ARRIVA QUALCHE IMBECILLE CHE VUOL CERCARE DI UCCIDERLO", // 20 - "PRIMA, GLI TOGLIANO GLI OCCHI; POI GLI VERSANO SUCCO DI LIMONE, DOPO IL BRUCIORE.......", + "PER PRIMA COSA GLI CAVANO GLI OCCHI. POI GLI VERSANO DEL SUCCO DI LIMONE IN MODO CHE BRUCI, POI...", "NO", - "COME CHE PER CHE NO? MA TU HAI VISTO CHE ORE SONO?", - "IN INVERNO, SI", + "COME PERCH\220 NO? HAI VISTO CHE ORE SONO?", + "IN INVERNO, S\326", "ARRIVEDERCI", // 25 - "N\324 PENSARCI", - "BENE, BASTA PER OGGI. VADO A CENARE", - "E CHE SEMPRE DIMENTICO CHIUDERE CON LA CHIAVE", + "NON PENSARCI NEMMENO!", + "BENE, BASTA PER OGGI. VADO A CENA", + "DIMENTICO SEMPRE DI CHIUDERE A CHIAVE", "ACCIDENTI!", - "EH? -AH! CHE COLPO, MAESTRO, PENSAVO STAVA DURMENDO", + "COSA? PADRONE! MI HA SPAVENTATO! PENSAVO STESSE DORMENDO", // 30 - "ORA MI RICORDO, PRENDA LE CHIAVI DEL SOGGIORNO, COS\326 DOMANI MATTINA NON MI DISTURBA SE VUOLE GUARDARE I CARTONI ANIMATI", - "HA PRESSO FREDDO UN'ALTRA VOLTA, MAESTRO? SEMPRE GLI DICO CHE METTA IL RISCALDAMENTO", - "PRENDA UNA ASPIRINA ED A SUDARE. BUONA NOTTE", + "OH, A PROPOSITO, HO PRESO LE CHIAVI DEL SOGGIORNO, COS\326 POTR\267 VEDERE I CARTONI ANIMATI DEL MATTINO SENZA SVEGLIARMI", + "HA DI NUOVO PRESO IL RAFFREDDORE, PADRONE? DANNAZIONE. \324 ANNI CHE LE DICO DI METTERE IL RISCALDAMENTO", + "BENE, PRENDA UN'ASPIRINA E VADA A LETTO A SUDARE. BUONA NOTTE", }, }; @@ -5010,43 +5010,43 @@ const char *_textl[NUM_LANGS][NUM_TEXTL] = { { // 0 "", - "UN ATTIMO. PERCHE SIAMO DI DIVERSE RAZZE E LA SOCIET\265 DICA CHE SIAMO NEMICI, ANDIAMO A LASCIARCI DOMINARE PER I PI\351 PRIMITIVI ISTINTI?", - "MA NON SIAMO UNITI DALLA RAGIONE, DALLA ARMA PI\351 PODEROSA E ANCHE PER IL DONO PI\351 PREZIOSO CHE ABBIAMO?", - "SE IL GIUDIZIO GUIDASSE I NOSTRI PASSI NELLA VITA SENZA LASCIARE POSTO AI SENTIMENTI, CHE MOSTRANO LE NOSTRE INCLINAZIONI PRE-EVOLUTIVI!", - "NON CREDI CHE SAREMMO PI\351 BEATI SENZA QUESTO LEGAME EMOZIONALE? RISPONDE EFFIMERA CREATURA", + "UN ATTIMO. SOLO PERCH\220 APPARTENIAMO A RAZZE DIVERSE E LA SOCIET\267 DICE CHE SIAMO NEMICI, VOGLIAMO LASCIARE CHE SIANO I NOSTRI ISTINTI PI\353 PRIMITIVI A GUIDARCI?", + "NON SIAMO FORSE UNITI DALLA RAGIONE? CHE \324 SIA L'ARMA PI\353 PODEROSA SIA IL DONO PI\353 PREZIOSO CHE ABBIAMO?", + "AH, SE IL GIUDIZIO GUIDASSE I NOSTRI PASSI NELLA VITA SENZA LASCIARE IL POSTO AI SENTIMENTI CHE MOSTRANO LE NOSTRE INCLINAZIONI PRE-EVOLUTIVE!", + "RISPONDI, EFFIMERA CREATURA. NON CREDI CHE SAREMMO PI\353 FELICI SENZA QUESTO LEGAME EMOZIONALE?", // 5 - "NON PASSI", - "VEDI? QUESTO UN CHIARO ESEMPIO: TU VUOI PASSARE E PROSEGUIRE LA TUA AVVENTURA ED IO NON POSSO PERMETTERLO", - "MA DEVE ESSERE CAUSA DI CONFRONTO QUANDO ANCORA NON CI CONOSCIAMO?", - "CHE TI HO DETTO?", - "BOH, DIPENDE DI CHE CAPIAMO COME RELAZIONE. CI SONO AUTORI CHE DIFENDONO...", + "NON PASSERAI", + "VEDI? QUESTO \324 UN CHIARO ESEMPIO: TU VUOI PASSARE E PROSEGUIRE LA TUA AVVENTURA ED IO NON POSSO PERMETTERLO", + "DEVE ESSERE DUNQUE MOTIVO DI CONFRONTO TRA NOI, CHE NON CI CONOSCIAMO PER NULLA?", + "BENE QUINDI", + "BEH, DIPENDE DA COSA INTENDIAMO PER RELAZIONE. ALCUNI AUTORI DIFENDONO...", // 10 - "LA CACCIA COME FORMA DI SUSSISTENZA \220 UNA ATTIVIT\265 ARCAICA, INCOMPATIBILE CON UNA NATURA SUPERIORE COM'\220 LA MIA: ADESSO SONO VEGETARIANO", - "TEMPO FA, STAVO MANGIANDO UN TIZIO QUANDO MI SONO MESSO A RIFLETTERE. FU QUANDO LA CONCLUSIONE DI PRIMA ARRIV\220 ", - "FU DIFFICILE LASCIARE LE MIE VECCHIE ABITUDINI, MA LA MIA ANIMA IRASCIBILE HA VINTO LA CONCUPISCIBILE E NON MANGIO PI\351 DELLA CARNE", - "NEPPURE IL PIACERE CHE FA UN OSSO, COL SUCCO DELLA PELLE E QUEL SAPORE CHE TI PORTA A POSTI LONTANI E PARADISIACI...", - "NEMMENO MI TOCCA DA VICINO, DAVVERO", + "LA CACCIA COME FORMA DI SUSSISTENZA \324 UNA ATTIVIT\267 ARCAICA, INCOMPATIBILE CON LA MIA ATTUALE NATURA SUPERIORE: SONO DIVENTATO VEGETARIANO", + "SONO ARRIVATO A QUESTA CONCLUSIONE TEMPO FA. STAVO MANGIANDO UN TIZIO QUANDO MI SONO MESSO A RIFLETTERE.", + "FU DIFFICILE LASCIARE LE MIE VECCHIE ABITUDINI, MA LA MIA ANIMA IRASCIBILE HA AVUTO LA MEGLIO SU QUELLA CONCUPISCENTE E DA ALLORA NON MANGIO PI\353 CARNE", + "NEPPURE IL PIACERE DI SUCCHIARE UN OSSO, SENTIRE IL GUSTO DELLA PELLE E IL SAPORE DOLCE DEL MIDOLLO CHE TI PORTA IN POSTI LONTANI E PARADISIACI...", + "NEPPURE QUESTO MI TOCCA, DAVVERO", // 15 "CHE COSA?", - "NON SO SU CHE MI PARLI, EFFIMERA CREATURA", - "NON MI INTERESA", - "GLI ALTRI VIDEO-GIOCHI, NON SO, MA QUESTO \220 PER APPROFITTARE QUESTO BELLO SCHERMO", + "NON CAPISCO DI CHE PARLI, EFFIMERA CREATURA", + "NON MI INTERESSA", + "GLI ALTRI VIDEOGIOCHI, NON SAPREI, MA QUESTO \324 PER SFRUTTARE AL MEGLIO QUESTO BELLO SCHERMO", "", // 20 - "IO SI ME VERGOGNAREI", - "NO, SONO IL NONNO, IL PADRE, IL FIGLIO, E UN AMICO CHE SI CHIAMA COS\326 ", - "NO, MA SE NON \220 COS\326, SEMBRAR\265 CHE HANNO FATTO IL VIDEO-GIOCO IN CINQUE", - "BRAVI RAGAZZI", - "-QUELLO \220 BUONO, QUELLO \220 BUONO!", + "IO ME LA PRENDEREI", + "NO, SONO IL NONNO, IL PADRE, IL FIGLIO, E UN AMICO CHE SI CHIAMA COS\326", + "NO, MA SE NON \324 COS\326, SEMBRER\267 CHE IL VIDEOGIOCO L'ABBIANO FATTO IN CINQUE", + "SONO RAGAZZI PROMETTENTI", + "\324 BRAVO, \324 BRAVO!", // 25 "CHIAMAMI COSTANTINO", - "NON ERO IO, DAI,. ERA IL MIO CONTROFIGURA, IL COYOTE", - "INSOMMA, MOLTI TITOLI DI CODA", - "IO NON SO GI\265 QUANTI", - "ALLORA PEPPINO, CHE VAI FARE ADESSO?", + "NON ERO IO, DAI. ERA IL MIO GEMELLO, IL COYOTE", + "ALLA FACCIA, CHE TITOLI DI CODA LUNGHI", + "HO PERSO IL CONTO", + "ALLORA DESIDERIO, CHE FARAI ORA?", // 30 "MA DOVRESTI DIMAGRIRE", - "MI APPARTER\220 AL TIBET A RIFLETTERE SUL SENSO DELLA VITA", + "MI RITIRER\343 IN TIBET A RIFLETTERE SUL SENSO DELLA VITA", }, }; @@ -5159,27 +5159,27 @@ const char *_textp[NUM_LANGS][NUM_TEXTP] = { // 0 "", "CIAO", - "BELLA, MOLTO BELLA", - "NO, CHE NON LO FA", + "SISSIGNORE, MOLTO BELLA", + "NO CHE NON LO FA", "VA BENE", // 5 - "-SI?", + "S\326?", "E?", - "MI DISPIACE. IL SINDACATODI PIANISTI NON MI DA PERMESSO PER LIBERARE RAGAZZE DALLE MANI DI VAMPIRI", - "SE LA AVESSE SEQUESTRATA IL LUPO-MANNARO...", - "SOLTANTO POSSO SUONARE QUESTA CANZONE", + "MI DISPIACE. IL SINDACATO DEI PIANISTI NON MI PERMETTE DI SALVARE RAGAZZE DALLE GRINFIE DEI VAMPIRI", + "SE FOSSE STATA RAPITA DAL LUPO MANNARO...", + "NON POSSO SUONARE ALTRO CHE QUESTA CANZONE", // 10 - "\324 PERCHE SONO PIANISTA DI CONSERVATORIO E IL TABERNERO NON COMPRA PI\353 PARTITURE", - "PECCATO.....MI PIACE MOLTISSIMO LA MUSICA CLASSICA!", - "PERCHE MI HO MESSO TAPPI NEGLI ORECCHII", - "PERCHE SO LEGGERE LE LABRA", + "\324 PERCH\220 SONO PIANISTA DI CONSERVATORIO E IL BARISTA NON COMPRA PI\353 SPARTITI", + "E DIRE CHE MI PIACE MOLTISSIMO LA MUSICA CLASSICA!", + "PERCH\220 HO I TAPPI NELLE ORECCHIE", + "PERCH\220 SO LEGGERE LE LABBRA", "NOOO", // 15 - "NO!, NON MI SOPPOROTO!", + "NO! NON POSSO ANDARE AVANTI COS\326!", "HO DETTO DI NOOO!", - "COSA? SI, SI MI INTERESA, COME NO", - "ADESSSO POTR\343 SUONARE UN'ALTRA CANZONE, GRAZIE!!", - "CREDO CHE I MIEI TAPPI ADESSO SONO TUOI", + "COSA? CERTO CHE MI INTERESSA", + "DEO GRATIAS! ADESSO POTR\343 SUONARE UN'ALTRA CANZONE!", + "SUPPONGO CHE ORA POSSA DARTI I MIEI TAPPI", }, }; @@ -5316,34 +5316,34 @@ const char *_textt[NUM_LANGS][NUM_TEXTT] = { { // 0 "", - "CHE SUCCEDE, CHE SUCCEDE?", + "CHE C'\324, CHE C'\324?", "D'ACCORDO. CAMERA 512. DEVE SALIRE LE SCALE. LA CHIAVE \324 NELLA PORTA", - "IL CONDE DRASCULA?", - "NO, NIENTE. QUEL TIZIO HA MALA REPUTAZIONE QU\336", + "IL CONTE DRASCULA?!", + "NO, NIENTE. \324 SOLO CHE QUEL TIPO HA UNA CATTIVA REPUTAZIONE QUI", // 5 - "SE DICONO MOLTE COSE SU LUI. COME CH'\324 UN VAMPIRO E SEQUESTRA GENTE PER BERE LA SUA SANGUE", - "ALTRI DICONO CHE SOLO \324 UN TRAFFICANTE DI ORGANI, PER QUELLO TROVIAMO GENTE SQUARTATA FUORI LE MURA", - "SONO SOLTANTO CHIACCHIERE. FORSE SIA LE DUE COSE. MA, PERCHE VUOLE TROVARE QUEL TIZIO?", - "NO, HO MOLTO DA FARE..", - "VA BENE, MA PERCHE VOGLIO IO, NON PERCHE L'ABBIA DETTO TU", + "BEH, CORRONO MOLTE VOCI SUL SUO CONTO. ALCUNI DICONO CHE \324 UN VAMPIRO E RAPISCE LE PERSONE PER SUCCHIAR LORO IL SANGUE", + "COMUNQUE, ALTRI DICONO CHE \324 SOLO UN TRAFFICANTE DI ORGANI, ED \324 PER QUESTO CHE SI TROVANO CORPI SQUARTATI NELLE VICINANZE", + "CHIARAMENTE SONO SOLTANTO VOCI. \324 PI\353 PROBABILE CHE SIA ENTRAMBE LE COSE. A PROPOSITO, PERCH\220 VUOLE INCONTRARE QUEL TIPO?", + "NO, LASCIA PERDERE. HO MOLTO DA FARE...", + "VA BENE, OK. MA PERCH\220 LO VOGLIO IO, NON PERCH\220 L'HAI DETTO TU", // 10 - "ADESSO VINCONO", - "LASCIAMI IN PACE, O.K.?", + "STANNO VINCENDO", + "LASCIAMI IN PACE, OK?", "CERTO, NON SONO CIECO", - "C'\324 LA TRADIZIONE NEL PAESE DI DIMENTICARE I RANCORI QUANDO C'\324 PARTITA DI CALCIO; PER ANIMARE LA SELEZIONE", - "TI HO DETTO DI STARE ZITTO, NON RIESCO A SENTIRE", + "IN PAESE C'\324 L'USANZA DI DIMENTICARE I RANCORI QUANDO C'\324 UNA PARTITA, PER SOSTENERE LA SQUADRA LOCALE", + "E STAI ZITTO UNA BUONA VOLTA. NON RIESCO A SENTIRE", // 15 - "LASCIAMI IN PACE E NON MI DISTURBARE", - "\324 APPENA COMINCIATO, ZITTO!", - "AH, BENE. HO PENSATO CHE SUCCEDEVA QUALCOSA", - "NO, NON FA NIENTE. ADESSO SICURO CH'\324 GI\267 MORTA", - "SI \324 MESSO A SUONARE MUSICA CLASSICA ED IO LA ODIO", + "INSOMMA, LASCIAMI IN PACE E NON MI DISTURBARE PI\353", + "\324 APPENA INIZIATA! STAI ZITTO!", + "AH, OK. CREDEVO CHE FOSSE SUCCESSO QUALCOSA", + "NO, \324 INUTILE. PROBABILMENTE A QUEST'ORA SAR\267 GI\267 MORTA", + "\324 CHE SI \324 MESSO A SUONARE MUSICA CLASSICA. E IO NON LA SOPPORTO", // 20 - "\324 COME FACCIO PER SENTIRE QUELLO CHE VOGLIO SE L'HO LICENZIATO", - "E ORA SI METTE BULLO...-E SEMBRAVA PROPRIO SCEMO!", - "...SENTA! FACCIA ATTENZIONE. IL PAVIMENTO \324 APPENA INCERATO", - "ZITTO! - STIAMO GUARDANDO LA PARTITA!", - "DAI! PRENDI", + "E SICCOME LO PAGO PERCH\220 SUONI QUELLO CHE VOGLIO IO, L'HO LICENZIATO", + "E POI SI \324 MESSO A FARE IL BULLO... SEMBRAVA COS\326 INNOCUO PRIMA, CHE IPOCRITA!", + "...A PROPOSITO, FACCIA ATTENZIONE. HO APPENA PASSATO LA CERA", + "SILENZIO! STIAMO GUARDANDO LA PARTITA!", + "DAI, FORZA! PRENDI.", }, }; @@ -5664,80 +5664,80 @@ const char *_textvb[NUM_LANGS][NUM_TEXTVB] = { { // 0 "", - "MA CHI BUSSA A QUESTE ORE?", - "EH...NO,NO. IO SONO IL NANNO GANIMEDI....IL PROFESSORE VON BRAUN NON ABITA QU\336 PI\353", + "CHI DIAVOLO \324 A QUEST'ORA?", + "OH... NO, NO. IO SONO IL NANO GANIMEDE... IL PROFESSOR VON BRAUN NON VIVE PI\353 QUI", "NO, NON SO DOV'\324!", - "HO DETTO VIA!", + "VATTENE!", // 5 - "IMBECILE. ORMAI TROPPO TARDE, SEMRE TARDE", - "SONO COMPLETAMENTE D'ACCORDO", + "IMBECILLE! ORMAI \324 TROPPO TARDI, LO \324 SEMPRE", + "SONO TOTALMENTE D'ACCORDO", "IO, PAURA?", - "ASCOLTA BENE RAGAZZO: STAI PARLANDO CON L'UNICA PERSONA CHE CONOSCE IL SEGRETO PER VINCERE AI VAMPIRI", - "NON TUTTI QUANTI POSSONO LOTTARE CON UN VAMPIRO. SI DEVONO AVERE DELLE CARATTERISTICHE SPEZIALI", + "ASCOLTA BENE, RAGAZZO: STAI PARLANDO CON L'UNICA PERSONA CHE CONOSCE IL SEGRETO PER AFFRONTARE I VAMPIRI", + "NON TUTTI POSSONO COMBATTERE CONTRO UN VAMPIRO. BISOGNA AVERE DELLE QUALIT\267 SPECIALI", // 10 - "NO CE LE HAI", - "SICURO CHE NON SCOMMETI TUTTO IL TUO SOLDI!", - "VA BENE . AVANTI", - "SE DAVVERO SEI PRONTO PER LOTTARE CONTRO DRASCULA, DEVI POTERE SOPPORTARE TUTTI I RUMORI STRIDENTI E VAMPIRICI", - "TUTTO CHIARO?", + "E TU NON LE POSSIEDI", + "SCOMMETTERESTI TUTTI I TUOI SOLDI?", + "VA BENE. ENTRA", + "SE DAVVERO INTENDI AFFRONTARE DRASCULA, DEVI ESSERE IN GRADO DI SOPPORTARE TUTTI I RUMORI PI\353 STRIDENTI E VAMPIRICI", + "\324 CHIARO?", // 15 - "D'ACCORDO. ASPETTA UN ATTIMO", - "PER FAVORE, METTETI NEL CENTRO DELLA CAMERA", - "DOV'\324 HO MESSO IL COMPACT DISC DI \"UNGHIE GRAFFIANDO UNA LAVAGNA\"", - "MOLTO BENE, ANDIAMO", - "VEDI? SEI UN INUTILE, COME TUTTI GLI ALTRI", + "D'ACCORDO. ASPETTA UN MOMENTO", + "PER FAVORE, METTITI AL CENTRO DELLA STANZA", + "DOV'\324 CHE HO MESSO IL CD DI \"UNGHIE CHE GRAFFIANO LA LAVAGNA\"?", + "MOLTO BENE. SI COMINCIA", + "VEDI? SEI UN INCAPACE, COME TUTTI GLI ALTRI", // 20 - "ORA DAMI IL SOLDI CHE HAI PERSO, E VIA", - "E NON TORNARE FINO CHE NON SIA COMPLETAMENTE PRONTO", - "E COSA VUOI TU ADESSO?", - "DEVO AMMETTERLO... HAI LA STOFFA DI LOTTATORE PER VINCERE DRASCULA", - "EH..! PRENDI IL TUO SOLDI. SO QUANDO HO SBAGLIATO", + "ORA DAMMI I SOLDI CHE HAI PERSO E VATTENE", + "E NON TORNARE FINCH\220 NON SARAI COMPLETAMENTE PRONTO", + "CHE COSA VUOI ADESSO?", + "DEVO RICONOSCERLO... HAI LA STOFFA PER COMBATTERE I VAMPIRI", + "A PROPOSITO, PRENDI I TUOI SOLDI. SO RICONOSCERE I MIEI ERRORI", // 25 - "ADESSO VATENE, VOGLIO DORMIRE UN P\343", - "QUANDO SIA DISPOSTO A UCCIDERE QUALCHE VAMPIRO, TORNA E TI AIUTER\343 ", - "QUELLO \324 FACILE. LA LUCE DEL SOLE O UN CROCIFISSO, E L'HAI SCHISCCIATO", - "CON CHI DEVI FARE MOLTA ATTENZIONE \324 CON DRASCULA. I SUOI POTERI FRISISHNOSTICI GLI FANNO IL PI\353 FORTE DEI VAMPIRI", - "NON POTREI FARE NULLA SE NON FOSSE PER LA .....", + "ADESSO VATTENE, VOGLIO DORMIRE UN PO'", + "QUANDO SARAI PRONTO AD AFFRONTARE UN VAMPIRO, TORNA E TI AIUTER\343 COME POSSO", + "OH, \324 FACILE. BASTA LA LUCE DEL SOLE O UN CROCIFISSO PER INCENERIRLO", + "DEVI INVECE STARE MOLTO ATTENTO A DRASCULA. I SUOI POTERI FRISISNOTICI LO RENDONO IL PI\353 POTENTE DEI VAMPIRI", + "SARESTI SPACCIATO, SE NON FOSSE PER LA...", // 30 "...POZIONE!", - "CERTO. HAI RAGIONE, SE CONTINUO DORMENDO COS\336 FORSE AVR\343 PROBLEMI DI SCHIENA QUANDO SIA VECCHIO", - "BENE, \324 VERO CHE FU MEGLIO LOTTATORE DI ME, MA IL MIO STUDIO SU TECNICHE ANTI-VAMPIRI GLI AIUT\343 MOLTISSIMO", - "HO SCOPERTO UNA POZIONE DI IMMUNUT\267 . TI FA INVULNERABILE AI MORSI DI VAMPIRI, O AI SUOI POTERI FRISISHNOTICI", - "NO, SCUSA, CE L'EBBI MOLTO TEMPO FA, MA UNA POZIONE COM'ERA LA MIA \324 PERICOLOSA. FIGURATI SE LA AVESSE UN VAMPIRO", + "OH, CERTO, HAI RAGIONE! SE CONTINUO A DORMIRE COS\326, FORSE AVR\343 PROBLEMI ALLA SCHIENA QUANDO SAR\343 VECCHIO", + "BEH, AMMETTO CHE SI \324 RIVELATO PI\353 FORTE DI ME, MA LA MIA PRINCIPALE SCOPERTA SULLE TECNICHE ANTI-VAMPIRO MI HA COPERTO LE SPALLE", + "HO SCOPERTO UNA POZIONE DI IMMUNIT\267 CHE TI RENDE INVULNERABILE A QUALUNQUE MORSO DI VAMPIRO, O AI SUOI POTERI FRISISNOTICI", + "NO, MI DISPIACE. CE L'AVEVO UNA VOLTA, MA UNA POZIONE CON QUELLE CARATTERISTICHE \324 PERICOLOSA. IMMAGINA SE CADESSE NELLE MANI DI UN VAMPIRO", // 35 - "GLI FAREBBE IMMUNE AGLI AGLII, ALLA LUCE DEL SOLE.... PER QUELLO L'HO SCARICATA NEL CESO", - "TRANQUILLO, MI RICORDO BENISSIMO DI COME RIFARLA", - "BISOGNO AGLII, CHE NE HO QU\326, DOVRAI PORTARMI UN P\220 DI CERA, NICOTINA, UNA GOMMA, E UNA CARTINA O UN TOVAGLIOLO, O QUALCOSA DEL GENERE", - "-AH! E COME NO, L'INGREDIENTE PRINCIPALE: DELLE FOGLIE DI UNA STRANA PIANTA CHIAMATA FERDINAN", - "\324 UNA PIANTA CONVOLVOLO, LE SUE FOGLIE PROPORZIONANO POTERI MAGICI SE SONO TAGLIATE DA UNA FALCE D'ORO", + "LO RENDEREBBE IMMUNE ALL'AGLIO E ALLA LUCE DEL SOLE... COS\326 MI SONO LIBERATO DI QUELLA CHE NON HO USATO CON UN METODO ALTAMENTE SCIENTIFICO: GETTANDOLA NELLA TAZZA DEL WATER", + "TRANQUILLO, MI RICORDO PERFETTAMENTE COME PREPARARE QUELLA POZIONE", + "HO BISOGNO DI AGLIO, CHE HO GI\267 QUI. PER\343 DOVRAI PORTARMI UN PO' DI CERA, DELLA NICOTINA, UNA GOMMA E UNA CARTINA DI SIGARETTA, O UN TOVAGLIOLO O QUALCOSA DEL GENERE", + "AH! E, OVVIAMENTE, L'INGREDIENTE PRINCIPALE: LE FOGLIE DI UNA STRANA PIANTA CHIAMATA FERNAN", + "SI TRATTA DI UNA PIANTA RAMPICANTE LE CUI FOGLIE ACQUISTANO POTERI MAGICI SE VENGONO TAGLIATE CON UNA FALCE D'ORO", // 40 - "ALLORA, PORTAMI QUESTE CINQUE COSE E FAR\343 PER TE LA POZIONE", - "DOPO SAREI PRONTO PER UCCIDERE DRASCULA", - "RICORDA: CERA, NICOTINA, UNA GOMMA, UNA CARTINA E FOGLIE DI FERDINAN, LA PIANTA, TAGLIATE DA UNA FALCE D'ORO", - "TI L'HO GI\267 DETTO! FU TUTTO GRAZIE ALLA POZIONE", - "AH, MOLTO BENE. DUNQUE VADO A FARE LA CAN......LA POZIONE. SAR\267 UN ATTIMINO", + "ALLORA, QUANDO AVRAI QUESTE CINQUE COSE, PORTAMELE E TI PREPARER\343 LA POZIONE", + "DOPO SARAI PRONTO PER AFFRONTARE DRASCULA", + "RICORDA: CERA, NICOTINA, UNA GOMMA, UNA CARTINA E DELLE FOGLIE DI FERNAN, LA PIANTA, TAGLIATE CON UNA FALCE D'ORO", + "TE L'HO GI\267 DETTO! FU MERITO DELLA POZIONE", + "AH, MOLTO BENE. ALLORA VADO A FARMI LA CAN... LA POZIONE. DAMMI UN MINUTO, OK?", // 45 - "\324 SOLTANTO UN SORTILEGIO DI PROTEZIONE CONTRO VAMPIRI", - "L'HO MESSO PER DISSIMULARE CHE IL DISEGNATORE HA DIMENTICATO METTERE LA FINESTRA CHE SI VEDE DA FUORI", - "BENE, PRIMA DEVI SAPERE COME ARRIVARE AL CASTELLO DRASCULA", - "C'\324 UNAGROTTA CHE VA AL CASTELLO E CHE UTILIZZA QUEL MATTO FAN DI ELVIS, IGOR, PER SCENDERE AL PAESE TUTTE LA MATTINE", - "MA FA ATTENZIONE, SEMPRE \220 PROTETTA DA UN VAMPIRO. DOVRAI LIBERARTI DI LUI", + "\324 UN INCANTESIMO DI PROTEZIONE CONTRO I VAMPIRI", + "L'HO MESSA L\326 PER NASCONDERE IL FATTO CHE IL DISEGNATORE HA DIMENTICATO DI METTERE LA FINESTRA CHE SI VEDE DA FUORI", + "BENE, LA PRIMA COSA CHE DEVI SAPERE \324 COME ARRIVARE AL CASTELLO DI DRASCULA", + "C'\324 UNA GROTTA CHE PORTA DIRETTAMENTE AL CASTELLO. QUEL MATTO FAN DI ELVIS, IGOR, LA USA PER SCENDERE AL PAESE TUTTE LA MATTINE", + "MA FA' ATTENZIONE, \324 SEMPRE PROTETTA DA UN VAMPIRO. DOVRAI LIBERARTI DI LUI", // 50 - "C'\220 UN VECCHIO POZZO ACCANTO ALLA CAPELLA DEL CIMITERO", - "SI UTILIZZAVA MOLTO TEMPO FA PER GIUDICARE CASI DI STREGONERIA", - "SI BUTTAVANO DENTRO ALLE STREGE. SE SI AFFONDAVANO ERANO STREGHE. SE NO, NO", - "UNA VOLTA BUTTAMMO UNA E GALLEGGI\220, DUNQUE NON SAREBBE UNA STREGA", - "ORA BEVE LA POZIONE. PECCATO CI SIA SOLTANTO PER UNO", + "C'\324 UN VECCHIO POZZO ACCANTO ALLA CAPPELLA DEL CIMITERO", + "SI USAVA ANTICAMENTE PER GIUDICARE I CASI DI STREGONERIA", + "SI BUTTAVANO LE STREGHE NEL POZZO. SE AFFONDAVANO ERANO STREGHE. SE NO, NO", + "UNA VOLTA NE BUTTAMMO GI\353 UNA E NON AFFOND\343. SUPPONGO NON FOSSE UNA STREGA.", + "AD OGNI MODO. PRENDI LA POZIONE. BASTA PER UNA VOLTA SOLA", // 55 - "SAR\265 MEGLIO FUMARLO PROPRIO PRIMA DELLA LOTTA CONTRO DRASCULA", - "CORRI1", - "SCUSE!", - "JOHN HACKER? SONO IL DOTTORE VON BRAUN", - "SENTA, \220 MOLTO IMPORTANTE, \220 SULLA POZIONE", + "\324 MEGLIO CHE LA FUMI APPENA PRIMA DI AFFRONTARE DRASCULA", + "CORRI!", + "SCUSI!", + "JOHN HACKER? SONO IL DOTTOR VON BRAUN", + "ASCOLTA, \324 MOLTO IMPORTANTE. RIGUARDA LA POZIONE", // 60 - "HO TROVATO UN LIBRO SU POZIONI E DICE CHE NON SI DEVE BERE ALCOL DOPO AVERE FUMATO LA POZIONE", - "L'ALCOL BEVUTO FA REAZIONE CON LE SOSTANZE DELLA POZIONE E ANNULLA I SUOI EFFETTI IN DECIME DI SECONDO", - "DEVO RIATTACARE. LA POLIZIA MI CERCA. DICONO CHE TRAFFICO DROGHE -IGNORANTI! BENE, ALLORA ADIO E IN BOCA IL LUPO", + "STAI ZITTO E LASCIAMI PARLARE. HO TROVATO UN LIBRO SULLE POZIONI E DICE CHE NON SI DEVE BERE ALCOL DOPO AVERE FUMATO LA POZIONE", + "L'ALCOL INGERITO REAGISCE CON LE SOSTANZE DELLA POZIONE E ANNULLA I SUOI EFFETTI IN POCHI SECONDI", + "MI DISPIACE, MA DEVO RIATTACCARE. LA POLIZIA MI CERCA. DICONO CHE SONO UNO SPACCIATORE. IGNORANTI! BEH, ADDIO E BUONA FORTUNA NEL SALVARE IL MONDO", }, }; @@ -5768,10 +5768,10 @@ const char *_textsys[NUM_LANGS][NUM_TEXTSYS] = { "VOIX ET TEXT", }, { - "PREMI DI NUOVO SUPR PER COMINZIARE", - "PRMI DI NUOVO ESC PER USCIRE", - "SOLO SUONI", - "SUONI E TESTO", + "PREMI DI NUOVO CANC PER RICOMINCIARE", + "PREMI DI NUOVO ESC PER USCIRE", + "SOLO VOCI", + "VOCI E TESTO", }, }; @@ -5807,10 +5807,10 @@ const char *_texthis[NUM_LANGS][NUM_TEXTHIS] = { }, { "", - "", - "", - "", - "" + "RACCONTANO CHE, MOLTI ANNI FA, DRASCULA UCCISE LA MOGLIE DI VON BRAUN. DA ALLORA, CON L'INTENZIONE DI AFFRONTARE IL CONTE, VON BRAUN COMINCI\343 A STUDIARE TUTTO QUELLO CHE TROVAVA SUI VAMPIRI.", + "QUANDO PENS\343 DI ESSERE PRONTO, AND\343 AL CASTELLO ED EBBE UN VIOLENTO SCONTRO CON DRASCULA.", + "NESSUNO SA COSA ACCADDE LASS\353. MA SEBBENE VON BRAUN FU SCONFITTO, DRASCULA NON RIUSC\326 A UCCIDERLO.", + "UMILIATO DALLA SCONFITTA, VON BRAUN SCAPP\343 DAL CASTELLO E DA ALLORA NON HA MAI PI\353 OSATO AFFRONTARE DRASCULA.", }, }; @@ -5934,7 +5934,7 @@ const char *_textverbs[NUM_LANGS][NUM_TEXTVERBS] = { "poussez", }, { - "esamina", + "guarda", "prendi", "apri", "chiudi", @@ -5966,9 +5966,9 @@ const char *_textmisc[NUM_LANGS][NUM_TEXTMISC] = { "GOOOOOOOAAAAAAAL!", }, { - "HUNCHBACKED", - "Transilvania, 1993 d.c.", - "GOOOOOOOAAAAAAAL!", + "GOBBO", + "Transilvania, 1993 d.c. (dopo cena)", + "GOOOOOOOOOOOOOOOL!", }, }; diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp index 78de2b6bce..c69c38199a 100644 --- a/tools/create_kyradat/create_kyradat.cpp +++ b/tools/create_kyradat/create_kyradat.cpp @@ -31,7 +31,7 @@ #include "md5.h" enum { - kKyraDatVersion = 31, + kKyraDatVersion = 32, kIndexSize = 12 }; diff --git a/tools/create_kyradat/hof_floppy.h b/tools/create_kyradat/hof_floppy.h index e2709eb3fd..e61f43fb2c 100644 --- a/tools/create_kyradat/hof_floppy.h +++ b/tools/create_kyradat/hof_floppy.h @@ -28,6 +28,16 @@ const ExtractEntry kyra2File1G[] = { { -1, 0, 0 } }; +const ExtractEntry kyra2File1I[] = { + { k2SeqplayPakFiles, 0x00021189, 0x000211B7 }, + { k2SeqplayStrings, 0x00022C62, 0x0002352A }, + { k2SeqplaySfxFiles, 0x0002352A, 0x0002369D }, + { k2SeqplayIntroTracks, 0x000236AA, 0x000236AA }, + { k2SeqplayFinaleTracks, 0x000236C7, 0x000236D9 }, + { k2SeqplaySeqData, 0x00022250, 0x00022944 }, + { -1, 0, 0 } +}; + const ExtractEntry kyra2File2E[] = { { k2IngamePakFiles, 0x0035E4E, 0x00362ED }, { k2IngameSfxFiles, 0x00034700, 0x00034DF1 }, @@ -58,12 +68,24 @@ const ExtractEntry kyra2File2G[] = { { -1, 0, 0 } }; +const ExtractEntry kyra2File2I[] = { + { k2IngamePakFiles, 0x00036816, 0x00036CB5 }, + { k2IngameSfxFiles, 0x000350C6, 0x000357B7 }, + { k2IngameSfxIndex, 0x0002AB80, 0x0002AED8 }, + { k2IngameTracks, 0x0003BE78, 0x0003BEF6 }, + { k2IngameTalkObjIndex, 0x00034872, 0x000348EA }, + { k2IngameItemAnimData, 0x0003C4E2, 0x0003C82A }, + { -1, 0, 0 } +}; + const Game kyra2FloppyGames[] = { { kKyra2, EN_ANY, k2FloppyFile1, "9b0f5e57b5a2ed88b5b989cbb402b6c7", kyra2File1E}, { kKyra2, FR_FRA, k2FloppyFile1, "df31cc9e37e1cf68df2fdc75ddf2d87b", kyra2File1F}, { kKyra2, DE_DEU, k2FloppyFile1, "0ca4f9a1438264a4c63c3218e064ed3b", kyra2File1G}, + { kKyra2, IT_ITA, k2FloppyFile1, "178d3ab913f61bfba21d2fb196405e8c", kyra2File1I}, { kKyra2, EN_ANY, k2FloppyFile2, "7c3eadbe5122722cf2e5e1611e19dfb9", kyra2File2E}, { kKyra2, FR_FRA, k2FloppyFile2, "fc2c6782778e6c6d5a553d1cb73c98ad", kyra2File2F}, { kKyra2, DE_DEU, k2FloppyFile2, "0d9b0eb7b0ad889ec942d74d80dde1bf", kyra2File2G}, + { kKyra2, IT_ITA, k2FloppyFile2, "3a61ed6b7c00ddae383a0361799e2ba6", kyra2File2I}, GAME_DUMMY_ENTRY }; diff --git a/tools/create_kyradat/pak.h b/tools/create_kyradat/pak.h index a90b930fcc..1e0fd2c72f 100644 --- a/tools/create_kyradat/pak.h +++ b/tools/create_kyradat/pak.h @@ -35,7 +35,7 @@ public: bool saveFile(const char *file); void clearFile() { delete _fileList; _fileList = 0; } - const uint32 getFileSize() const { return _fileList->getTableSize()+5+4+_fileList->getFileSize(); } + uint32 getFileSize() const { return _fileList->getTableSize()+5+4+_fileList->getFileSize(); } void drawFileList(); diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt index 4da978914d..225af32573 100644 --- a/tools/scumm-md5.txt +++ b/tools/scumm-md5.txt @@ -436,8 +436,11 @@ readtime Blue's Reading Time Activities 95818b178d473c989ac753574e8892aa -1 en All - Demo - Kirben fbear Fatty Bear's Birthday Surprise + 13d2a86a7290813a1c386490447d72db -1 en 3DO HE 61 - - George Kormendi 5b08000a9c47b2887df6506ac767ca68 -1 en 3DO HE 61 - - sev + 6bca7a1a96d16e52b8f3c42b50dbdca3 -1 jp 3DO HE 61 - - George Kormendi 3824e60cdf639d22f6df92a03dc4b131 7732 en DOS HE 61 - - khalek + 4f1d6f8b38343dba405472538b5037ed 7717 en DOS HE 61 - - George Kormendi ef74d9071d4e564b037cb44bd6774de7 -1 hb DOS HE 61 - - sev 3df6ead57930488bc61e6e41901d0e97 -1 en Mac HE 61 - - khalek 179879b6e35c1ead0d93aab26db0951b 13381 en Windows HE 70 - - khalek @@ -553,6 +556,7 @@ FreddisFunShop Freddi Fish's One-Stop Fun Shop catalog Humongous Interactive Catalog 11e6e244078ff09b0f3832e35420e0a7 -1 en Windows - Demo - khalek, sev 037385a953789190298494d92b89b3d0 -1 en Windows HE 72 Demo - khalek, sev + 74da3494fbe1a7d20213b0afe0954755 10841544 fr All HE CUP Preview - George Kormendi 4c4820518e16e1a0e3616a3b021a04f3 10927456 de All HE CUP Preview - Kirben airport Let's Explore the Airport with Buzzy @@ -621,6 +625,7 @@ pajama3 Pajama Sam 3: You Are What You Eat From Your Head to Your Feet 4fe6a2e8df3c4536b278fdd2fbcb181e -1 en Windows - Mini Game - Trekky 679855cf61932f9bf995c8f3677380ed -1 fr Windows - Demo - Mevi c8c5baadcbfc8d0372ed4335abace8a7 -1 fr Windows - Demo - Mevi + 784b499c98d07260a30952685758636b 13911 de Windows - Demo - George Kormendi 3e48298920fab9b7aec5a971e1bd1fab -1 gb Windows - Demo - eriktorbjorn cf90b4db5486ef798db78fe6fbf897e5 -1 us Windows - Demo - khalek @@ -658,12 +663,14 @@ puttrace Putt-Putt Enters the Race aaa587701cde7e74692c68c1024b85eb -1 nl All HE 99 Demo - joostp 0bf1a3eb198ca1bd2ebe104825cec770 -1 fr Windows HE 99 Demo - Mevi c8575e0b973ff1723aba6cd92c642db2 -1 fr Windows HE 99 Demo - Mevi + 3769b56c9a22f5521d74525ee459f88d 13108 de Windows HE 99 Demo - George Kormendi 7c8100e360e8ef05f88069d4cfa0afd1 13108 gb Windows HE 99 Demo - eriktorbjorn 6b27dbcd8d5697d5c918eeca0f68ef6a 3901484 All All HE CUP Preview - sev puttmoon Putt-Putt Goes to the Moon a9543ef0d79bcb47cd76ec197ad0a967 -1 en 3DO - - - sev 780e4a0ae2ff17dc296f4a79543b44f8 -1 All DOS - - - khalek + b9bb68c5d2c9b6e2d9c513a29a754a57 7828 en DOS - - - George Kormendi 697c9b7c55a05d8199c48b48e379d2c8 -1 hb DOS - - - sev 9dc02577bf50d4cfaf3de3fbac06fbe2 -1 en Mac - - - khalek 9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek @@ -685,9 +692,11 @@ puttcircus Putt-Putt Joins the Circus 3af61c5edf8e15b43dbafd285b2e9777 -1 hb Windows - Demo - Ori Avtalion puttputt Putt-Putt Joins the Parade + 7766c9487f9d53a8cb0edabda5119c3d 8022 en DOS HE 60 - - George Kormendi 0b3222aaa7efcf283eb621e0cefd26cc -1 ru DOS HE 60 - - sev 7e151c17adf624f1966c8fc5827c95e9 -1 en 3DO HE 61 - - khalek be2abe172f58db170de3a037daa1dd27 -1 jp 3DO HE 61 - - clone2727 + ee41f6afbc5b26fa475754b56fe92048 8032 jp 3DO HE 61 - - George Kormendi 9708cf716ed8bcc9ff3fcfc69413b746 -1 en DOS HE 61 - - khalek e361a7058ed8e8ebb462663c0a3ae8d6 -1 hb DOS HE 61 - - sev 684732efb5799c0f78804c99d8de9aba -1 en Mac HE 61 - - khalek @@ -703,6 +712,7 @@ puttzoo Putt-Putt Saves the Zoo 1005456bfe351c1b679e1ff2dc2849e9 -1 All Windows - - - khalek c3b22fa4654bb580b20325ebf4174841 -1 nl Windows - - - joostp 9781422e4288dbc090720e4563168ba7 -1 fr Windows - - - gist974 + 0f9d3317910ac7a9f449243118884ada 42070 de Windows - - - George Kormendi 92e7727e67f5cd979d8a1070e4eb8cb3 -1 en All HE 98.5 Updated - cyx 3a3e592b074f595489f7f11e150c398d -1 us Windows HE 99 Updated - Adrian @@ -734,6 +744,7 @@ PuttTime Putt-Putt Travels Through Time balloon Putt-Putt and Pep's Balloon-O-Rama 08cc5c3eedaf72ebe12734eee94f7fa2 -1 en All HE 80 - - Kirben + bab0fb81dcb12b8930c5d850b8f2a7de 12800 de Windows HE 80 - - George Kormendi 145bd3373574feb668cc2eea2ec6cf86 -1 ru Windows HE 80 - - sev 2232b0b9411575b1f9961713ebc9de61 -1 es Windows HE 80 - - exiltd d7b247c26bf1f01f8f7daf142be84de3 -1 en Windows HE 99 Updated - iziku @@ -741,6 +752,7 @@ balloon Putt-Putt and Pep's Balloon-O-Rama dog Putt-Putt and Pep's Dog on a Stick eae95b2b3546d8ba86ae1d397c383253 -1 en All - - - Kirben + 839a658f7d22de00787ebc945348cdb6 19681 de Windows - - - George Kormendi d4b8ee426b1afd3e53bc0cf020418cf6 -1 en Windows HE 99 - - sev activity Putt-Putt & Fatty Bear's Activity Pack @@ -789,6 +801,8 @@ spyfox2 SPY Fox 2: Some Assembly Required 7222f260253f325c21fcfa68b5bfab67 -1 us All - Demo - Kirben 732845548b1d6c2da572cb6a1bf81b07 -1 de All - Demo - Joachim Eberhard e62056ba675ad65d8854ab3c5ad4b3c0 -1 en Windows - Mini Game - Trekky + 22de86b2f7ec6e5db745ed1123310b44 15832 fr Windows - Demo - George Kormendi + 204453e33456c4faa26e276229fe5b76 14689 de Windows - Demo - George Kormendi 19bf6938a94698296bcb0c99c31c91a7 -1 gb Windows - Demo - eriktorbjorn 49a1739981a89066b1121fac04b710f4 5756234 All All HE CUP Preview - sev |