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  | 
