diff options
Diffstat (limited to 'engines')
314 files changed, 26826 insertions, 12307 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 1c1c53dee7..bc3cd86e7c 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -46,8 +46,6 @@ #include "agi/menu.h" #include "agi/sound.h" - - namespace Agi { static uint32 g_tickTimer; @@ -370,7 +368,7 @@ int AgiEngine::agiInit() { memset(&_game.views[i], 0, sizeof(struct AgiView)); memset(&_game.pictures[i], 0, sizeof(struct AgiPicture)); memset(&_game.logics[i], 0, sizeof(struct AgiLogic)); - memset(&_game.sounds[i], 0, sizeof(struct AgiSound)); + memset(&_game.sounds[i], 0, sizeof(class AgiSound *)); // _game.sounds contains pointers now memset(&_game.dirView[i], 0, sizeof(struct AgiDir)); memset(&_game.dirPic[i], 0, sizeof(struct AgiDir)); memset(&_game.dirLogic[i], 0, sizeof(struct AgiDir)); @@ -495,7 +493,7 @@ int AgiEngine::agiDetectGame() { assert(_gameDescription != NULL); - if(getVersion() <= 0x2999) { + if (getVersion() <= 0x2999) { _loader = new AgiLoader_v2(this); } else { _loader = new AgiLoader_v3(this); @@ -521,6 +519,7 @@ int AgiEngine::agiLoadResource(int r, int n) { int i; i = _loader->loadResource(r, n); + return i; } @@ -602,7 +601,11 @@ AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) { setAmigaStyle(renderMode == Common::kRenderAmiga); } -AgiEngine::AgiEngine(OSystem *syst) : Engine(syst) { +AgiBase::AgiBase(OSystem *syst) : Engine(syst) { + +} + +AgiEngine::AgiEngine(OSystem *syst) : AgiBase(syst) { // Setup mixer if (!_mixer->isReady()) { @@ -677,13 +680,20 @@ void AgiEngine::initialize() { // drivers, and I'm not sure what they are. For now, they might // as well be called "PC Speaker" and "Not PC Speaker". - switch (MidiDriver::detectMusicDriver(MDT_PCSPK)) { - case MD_PCSPK: - _soundemu = SOUND_EMU_PC; - break; - default: - _soundemu = SOUND_EMU_NONE; - break; + // If used platform is Apple IIGS then we must use Apple IIGS sound emulation + // because Apple IIGS AGI games use only Apple IIGS specific sound resources. + if (ConfMan.hasKey("platform") && + Common::parsePlatform(ConfMan.get("platform")) == Common::kPlatformApple2GS) { + _soundemu = SOUND_EMU_APPLE2GS; + } else { + switch (MidiDriver::detectMusicDriver(MDT_PCSPK)) { + case MD_PCSPK: + _soundemu = SOUND_EMU_PC; + break; + default: + _soundemu = SOUND_EMU_NONE; + break; + } } if (ConfMan.hasKey("render_mode")) { diff --git a/engines/agi/agi.h b/engines/agi/agi.h index f37b61478e..dfe149de4f 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -45,8 +45,6 @@ typedef signed int Err; * Version and other definitions */ -#define USE_IIGS_SOUND - #define TITLE "AGI engine" #define DIR_ "dir" @@ -88,6 +86,29 @@ typedef signed int Err; #define ADD_PIC 1 #define ADD_VIEW 2 +enum AgiGameID { + GID_AGIDEMO, + GID_BC, + GID_DDP, + GID_GOLDRUSH, + GID_KQ1, + GID_KQ2, + GID_KQ3, + GID_KQ4, + GID_LSL1, + GID_MH1, + GID_MH2, + GID_MIXEDUP, + GID_PQ1, + GID_SQ1, + GID_SQ2, + GID_XMASCARD, + GID_FANMADE, + GID_MICKEY, // PreAGI + GID_WINNIE, // PreAGI + GID_TROLL // PreAGI +}; + } // End of namespace Agi /* AGI resources */ @@ -100,8 +121,9 @@ typedef signed int Err; namespace Agi { enum AgiGameType { + GType_PreAGI = 0, GType_V2 = 1, - GType_V3 + GType_V3 = 2 }; enum AgiGameFeatures { @@ -116,26 +138,6 @@ enum AgiGameFeatures { GF_ESCPAUSE = (1 << 8) }; -enum AgiGameID { - GID_AGIDEMO, - GID_BC, - GID_DDP, - GID_GOLDRUSH, - GID_KQ1, - GID_KQ2, - GID_KQ3, - GID_KQ4, - GID_LSL1, - GID_MH1, - GID_MH2, - GID_MIXEDUP, - GID_PQ1, - GID_SQ1, - GID_SQ2, - GID_XMASCARD, - GID_FANMADE // TODO: Should this be extended to include all fanmade games? -}; - struct AGIGameDescription; enum { @@ -527,7 +529,7 @@ struct AgiGame { AgiPicture pictures[MAX_DIRS]; /**< AGI picture resources */ AgiLogic logics[MAX_DIRS]; /**< AGI logic resources */ AgiView views[MAX_DIRS]; /**< AGI view resources */ - AgiSound sounds[MAX_DIRS]; /**< AGI sound resources */ + AgiSound *sounds[MAX_DIRS]; /**< Pointers to AGI sound resources */ /* view table */ VtEntry viewTable[MAX_VIEWTABLE]; @@ -538,10 +540,6 @@ struct AgiGame { }; class AgiLoader { -private: - int intVersion; - AgiEngine *_vm; - public: AgiLoader() {} @@ -644,7 +642,50 @@ struct StringData { #define KEY_QUEUE_SIZE 16 -class AgiEngine : public ::Engine { +class AgiBase : public ::Engine { +public: + AgiButtonStyle _defaultButtonStyle; + AgiButtonStyle _buttonStyle; + Common::RenderMode _renderMode; + volatile uint32 _clockCount; + AgiDebug _debug; + AgiGame _game; + Common::RandomSource *_rnd; + + virtual void agiTimerLow() = 0; + virtual int agiGetKeypressLow() = 0; + virtual int agiIsKeypressLow() = 0; + + AgiBase(OSystem *syst); + + #define INITIAL_IMAGE_STACK_SIZE 32 + + int _stackSize; + ImageStackElement *_imageStack; + int _imageStackPointer; + + virtual void clearImageStack() = 0; + virtual void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) = 0; + virtual void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) = 0; + virtual void releaseImageStack() = 0; + + int _soundemu; + + int getflag(int); + void setflag(int, int); + void flipflag(int); + + const AGIGameDescription *_gameDescription; + uint32 getGameID() const; + uint32 getFeatures() const; + uint16 getVersion() const; + uint16 getGameType() const; + Common::Platform getPlatform() const; +}; + +class AgiEngine : public AgiBase { int _gameId; protected: @@ -662,12 +703,6 @@ public: return _gameId; } - const AGIGameDescription *_gameDescription; - uint32 getGameID() const; - uint32 getFeatures() const; - uint16 getVersion() const; - Common::Platform getPlatform() const; - private: int _keyQueue[KEY_QUEUE_SIZE]; @@ -685,15 +720,10 @@ private: int _firstSlot; public: - AgiGame _game; AgiObject *_objects; /* objects in the game */ StringData _stringdata; - AgiLoader *_loader; /* loader */ - - Common::RandomSource *_rnd; - const char *getSavegameFilename(int num); void getSavegameDescription(int num, char *buf, bool showEmpty = true); int selectSlot(); @@ -704,14 +734,10 @@ public: int loadGameDialog(); int loadGameSimple(); - volatile uint32 _clockCount; - uint8 *_intobj; int _oldMode; Menu* _menu; - AgiButtonStyle _buttonStyle; - AgiButtonStyle _defaultButtonStyle; char _lastSentence[40]; @@ -719,12 +745,7 @@ public: GfxMgr *_gfx; SoundMgr *_sound; PictureMgr *_picture; - - #define INITIAL_IMAGE_STACK_SIZE 32 - - int _stackSize; - ImageStackElement *_imageStack; - int _imageStackPointer; + AgiLoader *_loader; /* loader */ void clearImageStack(); void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, @@ -733,10 +754,6 @@ public: int16 p4, int16 p5, int16 p6, int16 p7); void releaseImageStack(); - AgiDebug _debug; - Common::RenderMode _renderMode; - int _soundemu; - int _keyControl; int _keyAlt; @@ -752,18 +769,15 @@ public: int agiUnloadResource(int, int); void agiUnloadResources(); - void agiTimerLow(); - int agiGetKeypressLow(); - int agiIsKeypressLow(); + virtual void agiTimerLow(); + virtual int agiGetKeypressLow(); + virtual int agiIsKeypressLow(); static void agiTimerFunctionLow(void *refCon); void initPriTable(); void newInputMode(int); void oldInputMode(); - int getflag(int); - void setflag(int, int); - void flipflag(int); int getvar(int); void setvar(int, int); void decrypt(uint8 * mem, int len); @@ -811,7 +825,6 @@ public: int decodeLogic(int); void unloadLogic(int); int runLogic(int); - void debugConsole(int, int, const char *); int testIfCode(int); void executeAgiCommand(uint8, uint8 *); diff --git a/engines/agi/console.h b/engines/agi/console.h index ad955d51ae..a6994ce922 100644 --- a/engines/agi/console.h +++ b/engines/agi/console.h @@ -31,6 +31,7 @@ namespace Agi { class AgiEngine; +class PreAgiEngine; struct AgiDebug { int enabled; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 79e3be3238..afd61ae765 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -28,9 +28,11 @@ #include "base/plugins.h" #include "common/advancedDetector.h" +#include "common/config-manager.h" #include "common/file.h" #include "agi/agi.h" +#include "agi/preagi.h" #include "agi/wagparser.h" @@ -45,22 +47,26 @@ struct AGIGameDescription { uint16 version; }; -uint32 AgiEngine::getGameID() const { +uint32 AgiBase::getGameID() const { return _gameDescription->gameID; } -uint32 AgiEngine::getFeatures() const { +uint32 AgiBase::getFeatures() const { return _gameDescription->features; } -Common::Platform AgiEngine::getPlatform() const { +Common::Platform AgiBase::getPlatform() const { return _gameDescription->desc.platform; } -uint16 AgiEngine::getVersion() const { +uint16 AgiBase::getVersion() const { return _gameDescription->version; } +uint16 AgiBase::getGameType() const { + return _gameDescription->gameType; +} + } static const PlainGameDescriptor agiGames[] = { @@ -76,6 +82,7 @@ static const PlainGameDescriptor agiGames[] = { {"kq3", "King's Quest III: To Heir Is Human"}, {"kq4", "King's Quest IV: The Perils of Rosella"}, {"lsl1", "Leisure Suit Larry in the Land of the Lounge Lizards"}, + {"mickey", "Mickey\'s Space Adventure"}, {"mixedup", "Mixed-Up Mother Goose"}, {"mh1", "Manhunter 1: New York"}, {"mh2", "Manhunter 2: San Francisco"}, @@ -87,6 +94,8 @@ static const PlainGameDescriptor agiGames[] = { {"sq2", "Space Quest II: Vohaul's Revenge"}, {"sqx", "Space Quest X: The Lost Chapter"}, {"tetris", "AGI Tetris"}, + {"troll", "Troll\'s Tale"}, + {"winnie", "Winnie the Pooh in the Hundred Acre Wood"}, {"xmascard", "Xmas Card"}, {0, 0} @@ -1114,6 +1123,23 @@ static const AGIGameDescription gameDescriptions[] = { 0x3149, }, + { + // Mickey's Space Adventure + // Preagi game + { + "mickey", + "", + AD_ENTRY1("1.pic", "b6ec04c91a05df374792872c4d4ce66d"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_MICKEY, + GType_PreAGI, + 0, + 0x0000, + }, + #if 0 { // Mixed-Up Mother Goose (Amiga) 1.1 @@ -1590,6 +1616,39 @@ static const AGIGameDescription gameDescriptions[] = { 0x2936, }, + { + // Troll's Tale + // preagi game + { + "troll", + "", + AD_ENTRY1s("troll.exe", "c594b4d6791e9580d8d5dc9d71760027", 59120), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_TROLL, + GType_PreAGI, + 0, + 0x0000, + }, + + { + // Winnie the Pooh in the Hundred Acre Wood + // preagi game + { + "winnie", + "", + AD_ENTRY1("title.pic", "2e7900c1ccaa7671d65405f6d1efed30"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_WINNIE, + GType_PreAGI, + 0, + 0x0000, + }, { // Xmas Card 1986 (PC) [AGI 2.272] @@ -1865,8 +1924,13 @@ Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { // Use the current directory for searching if fslist == NULL if (fslist == NULL) { - FilesystemNode fsCurrentDir("."); - fslistCurrentDir.push_back(fsCurrentDir); + Common::String path = ConfMan.get("path").c_str(); + + if (path.empty()) + path = "."; + + FilesystemNode fsCurrentDir(path); + fsCurrentDir.getChildren(fslistCurrentDir, FilesystemNode::kListFilesOnly); fslist = &fslistCurrentDir; } @@ -2027,9 +2091,31 @@ static const Common::ADParams detectionParams = { Common::kADFlagAugmentPreferredTarget }; -ADVANCED_DETECTOR_DEFINE_PLUGIN(AGI, Agi::AgiEngine, detectionParams); +bool engineCreateAgi(OSystem *syst, Engine **engine, Common::EncapsulatedADGameDesc encapsulatedDesc) { + const Agi::AGIGameDescription *gd = (const Agi::AGIGameDescription *)(encapsulatedDesc.realDesc); + bool res = true; + + switch (gd->gameType) { + case Agi::GType_PreAGI: + *engine = new Agi::PreAgiEngine(syst); + break; + case Agi::GType_V2: + *engine = new Agi::AgiEngine(syst); + break; + case Agi::GType_V3: + *engine = new Agi::AgiEngine(syst); + break; + default: + res = false; + error("AGI engine: unknown gameType"); + } + + return res; +} -REGISTER_PLUGIN(AGI, "AGI v2 + v3 Engine", "Sierra AGI Engine (C) Sierra On-Line Software"); +ADVANCED_DETECTOR_DEFINE_PLUGIN_WITH_COMPLEX_CREATION(AGI, engineCreateAgi, detectionParams); + +REGISTER_PLUGIN(AGI, "AGI preAGI + v2 + v3 Engine", "Sierra AGI Engine (C) Sierra On-Line Software"); namespace Agi { @@ -2040,5 +2126,12 @@ bool AgiEngine::initGame() { return (_gameDescription != 0); } +bool PreAgiEngine::initGame() { + Common::EncapsulatedADGameDesc encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); + _gameDescription = (const AGIGameDescription *)(encapsulatedDesc.realDesc); + + return (_gameDescription != 0); +} + } // End of namespace Agi diff --git a/engines/agi/font.h b/engines/agi/font.h index 12b36f2520..1bf61878ec 100644 --- a/engines/agi/font.h +++ b/engines/agi/font.h @@ -294,6 +294,524 @@ static const uint8 curFont[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00 }; +static const uint8 mickey_fontdata[] = { + 0x00, 0x36, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, + 0x00, 0x00, 0x3F, 0x20, 0x2F, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x2F, 0x20, 0x2F, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x2F, 0x20, 0x3F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xEF, 0x28, 0x28, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x28, 0xEF, 0x00, 0xEF, 0x28, 0x28, 0x28, + 0x28, 0x28, 0xEF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0x08, 0xE8, 0x28, 0x28, 0x28, + 0x28, 0x28, 0xE8, 0x08, 0xE8, 0x28, 0x28, 0x28, + 0x28, 0x28, 0xE8, 0x08, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10, + 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10, + 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, + 0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x00, + 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, + 0x00, 0x66, 0x6C, 0x18, 0x30, 0x66, 0x46, 0x00, + 0x1C, 0x36, 0x1C, 0x38, 0x6F, 0x66, 0x3B, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x1C, 0x18, 0x18, 0x18, 0x1C, 0x0E, 0x00, + 0x70, 0x38, 0x18, 0x18, 0x18, 0x38, 0x70, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, + 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00, + 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00, + 0x7E, 0x0C, 0x18, 0x0C, 0x06, 0x66, 0x3C, 0x00, + 0x0C, 0x1C, 0x3C, 0x6C, 0x6C, 0x7E, 0x0C, 0x00, + 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, + 0x3C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, + 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, + 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x3C, 0x66, 0x04, 0x0C, 0x18, 0x00, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, + 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, + 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, + 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, + 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, + 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, + 0x3E, 0x60, 0x60, 0x6E, 0x66, 0x66, 0x3E, 0x00, + 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00, + 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0x00, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, + 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00, + 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, + 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, + 0x3C, 0x66, 0x66, 0x66, 0x66, 0x6C, 0x36, 0x00, + 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00, + 0x3C, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x3C, 0x00, + 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, + 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, + 0x66, 0x66, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x00, + 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, + 0x7E, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x7E, 0x00, + 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00, + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x00, 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, + 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00, + 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0x0E, 0x18, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C, + 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3C, + 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x66, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00, + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, + 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00, + 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, + 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, + 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78, + 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x18, 0x3C, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x7E, 0x78, 0x7C, 0x6E, 0x66, 0x06, 0x00, + 0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00, + 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00, + 0xFF, 0xC9, 0x80, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, + 0xFF, 0xFF, 0xC0, 0xDF, 0xD0, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD0, 0xDF, 0xD0, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD0, 0xDF, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xFF, 0x10, 0xD7, 0xD7, 0xD7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD7, 0xD7, 0x10, 0xFF, 0x10, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0x10, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x07, 0xF7, 0x17, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0x17, 0xF7, 0x17, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0x17, 0xF7, 0x07, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0x00, 0xFF, 0x00, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEF, 0xEF, 0xEF, 0x00, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, + 0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xE7, 0xE7, 0xFF, + 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x99, 0x00, 0x99, 0x99, 0x00, 0x99, 0xFF, + 0xE7, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xE7, 0xFF, + 0xFF, 0x99, 0x93, 0xE7, 0xCF, 0x99, 0xB9, 0xFF, + 0xE3, 0xC9, 0xE3, 0xC7, 0x90, 0x99, 0xC4, 0xFF, + 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF1, 0xE3, 0xE7, 0xE7, 0xE7, 0xE3, 0xF1, 0xFF, + 0x8F, 0xC7, 0xE7, 0xE7, 0xE7, 0xC7, 0x8F, 0xFF, + 0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF, + 0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, + 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, + 0xFD, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xBF, 0xFF, + 0xC3, 0x99, 0x91, 0x81, 0x89, 0x99, 0xC3, 0xFF, + 0xE7, 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF, + 0xC3, 0x99, 0xF9, 0xF3, 0xE7, 0xCF, 0x81, 0xFF, + 0x81, 0xF3, 0xE7, 0xF3, 0xF9, 0x99, 0xC3, 0xFF, + 0xF3, 0xE3, 0xC3, 0x93, 0x93, 0x81, 0xF3, 0xFF, + 0x81, 0x9F, 0x83, 0xF9, 0xF9, 0x99, 0xC3, 0xFF, + 0xC3, 0x9F, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF, + 0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xFF, + 0xC3, 0x99, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF, + 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xF3, 0xC7, 0xFF, + 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, + 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, + 0xF9, 0xF3, 0xE7, 0xCF, 0xE7, 0xF3, 0xF9, 0xFF, + 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, + 0x9F, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, + 0xC3, 0x99, 0xFB, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF, + 0xC3, 0x99, 0x99, 0x91, 0x91, 0x9F, 0xC1, 0xFF, + 0xE7, 0xC3, 0x99, 0x99, 0x81, 0x99, 0x99, 0xFF, + 0x83, 0x99, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF, + 0xC3, 0x99, 0x9F, 0x9F, 0x9F, 0x99, 0xC3, 0xFF, + 0x87, 0x93, 0x99, 0x99, 0x99, 0x93, 0x87, 0xFF, + 0x81, 0x9F, 0x9F, 0x83, 0x9F, 0x9F, 0x81, 0xFF, + 0x81, 0x9F, 0x9F, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, + 0xC1, 0x9F, 0x9F, 0x91, 0x99, 0x99, 0xC1, 0xFF, + 0x99, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, + 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0x99, 0xC3, 0xFF, + 0x99, 0x93, 0x87, 0x87, 0x93, 0x99, 0x99, 0xFF, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF, + 0x9C, 0x88, 0x80, 0x94, 0x9C, 0x9C, 0x9C, 0xFF, + 0x99, 0x89, 0x81, 0x81, 0x91, 0x99, 0x99, 0xFF, + 0xC3, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, + 0x83, 0x99, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0xFF, + 0xC3, 0x99, 0x99, 0x99, 0x99, 0x93, 0xC9, 0xFF, + 0x83, 0x99, 0x99, 0x83, 0x93, 0x99, 0x99, 0xFF, + 0xC3, 0x9F, 0x9F, 0xC3, 0xF9, 0xF9, 0xC3, 0xFF, + 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x81, 0xFF, + 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, + 0x9C, 0x9C, 0x9C, 0x94, 0x80, 0x88, 0x9C, 0xFF, + 0x99, 0x99, 0xC3, 0xC3, 0x99, 0x99, 0x99, 0xFF, + 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xFF, + 0x81, 0xF3, 0xE7, 0xCF, 0x9F, 0x9F, 0x81, 0xFF, + 0xE1, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE1, 0xFF, + 0xFF, 0xBF, 0x9F, 0xCF, 0xE7, 0xF3, 0xF9, 0xFF, + 0x87, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x87, 0xFF, + 0xFF, 0xF7, 0xE3, 0xC9, 0x9C, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, + 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00, + 0xFF, 0xFF, 0xC3, 0xF9, 0xC1, 0x99, 0xC1, 0xFF, + 0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x83, 0xFF, + 0xFF, 0xFF, 0xC3, 0x9F, 0x9F, 0x9F, 0xC3, 0xFF, + 0xF9, 0xF9, 0xC1, 0x99, 0x99, 0x99, 0xC1, 0xFF, + 0xFF, 0xFF, 0xC3, 0x99, 0x81, 0x9F, 0xC3, 0xFF, + 0xF1, 0xE7, 0xE7, 0xC1, 0xE7, 0xE7, 0xE7, 0xFF, + 0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0x83, + 0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF, + 0xE7, 0xFF, 0xC7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, + 0xF9, 0xFF, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xC3, + 0x9F, 0x9F, 0x93, 0x87, 0x93, 0x99, 0x99, 0xFF, + 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, + 0xFF, 0xFF, 0x99, 0x80, 0x80, 0x94, 0x9C, 0xFF, + 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF, + 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF, + 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F, + 0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0xF9, + 0xFF, 0xFF, 0x83, 0x99, 0x9F, 0x9F, 0x9F, 0xFF, + 0xFF, 0xFF, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xFF, + 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xE7, 0xF1, 0xFF, + 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC1, 0xFF, + 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, + 0xFF, 0xFF, 0x9C, 0x94, 0x80, 0xC1, 0xC9, 0xFF, + 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0xFF, + 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC1, 0xF3, 0x87, + 0xFF, 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x81, 0xFF, + 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x18, 0x3C, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x7E, 0x78, 0x7C, 0x6E, 0x66, 0x06, 0x00, + 0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00, + 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00, +}; + +static const uint8 ibm_fontdata[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, + 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, + 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C, + 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, + 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, + 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, + 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00, + 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, + 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, + 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, + 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, + 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, + 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, + 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, + 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00, + 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, + 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, + 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, + 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00, + 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00, + 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, + 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, + 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00, + 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, + 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, + 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00, + 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38, + 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, + 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00, + 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00, + 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00, + 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00, + 0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00, + 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00, + 0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30, + 0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7, + 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70, + 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00, + 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, + 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00, + 0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F, + 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03, + 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, + 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00, + 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0, + 0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, + 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, + 0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00, + 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0, + 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC, + 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00, + 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00, + 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0, + 0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00, + 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, + 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00, + 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, + 0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C, + 0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, + 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + } // End of namespace Agi #endif /* AGI_FONT_H */ diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp index 0baf8c259c..36cc547a8d 100644 --- a/engines/agi/global.cpp +++ b/engines/agi/global.cpp @@ -29,14 +29,14 @@ namespace Agi { -int AgiEngine::getflag(int n) { +int AgiBase::getflag(int n) { uint8 *set = (uint8 *)&_game.flags; set += n >> 3; return (*set & (1 << (n & 0x07))) != 0; } -void AgiEngine::setflag(int n, int v) { +void AgiBase::setflag(int n, int v) { uint8 *set = (uint8 *)&_game.flags; set += n >> 3; @@ -46,7 +46,7 @@ void AgiEngine::setflag(int n, int v) { *set &= ~(1 << (n & 0x07)); /* clear bit */ } -void AgiEngine::flipflag(int n) { +void AgiBase::flipflag(int n) { uint8 *set = (uint8 *)&_game.flags; set += n >> 3; diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp index b6430e0f81..5af68e9b5e 100644 --- a/engines/agi/graphics.cpp +++ b/engines/agi/graphics.cpp @@ -532,7 +532,7 @@ static struct UpdateBlock update = { MAX_INT, MAX_INT, 0, 0 }; -GfxMgr::GfxMgr(AgiEngine *vm) : _vm(vm) { +GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) { _shakeH = NULL; _shakeV = NULL; _agipalFileNum = 0; @@ -612,11 +612,11 @@ void GfxMgr::shakeEnd() { free(_shakeH); } -void GfxMgr::putTextCharacter(int l, int x, int y, unsigned int c, int fg, int bg, bool checkerboard) { +void GfxMgr::putTextCharacter(int l, int x, int y, unsigned int c, int fg, int bg, bool checkerboard, const uint8 *font) { int x1, y1, xx, yy, cc; const uint8 *p; - p = Agi::curFont + ((unsigned int)c * CHAR_LINES); + p = font + ((unsigned int)c * CHAR_LINES); for (y1 = 0; y1 < CHAR_LINES; y1++) { for (x1 = 0; x1 < CHAR_COLS; x1++) { xx = x + x1; @@ -1005,6 +1005,14 @@ void GfxMgr::setCursor(bool amigaStyleCursor) { } } +void GfxMgr::setCursorPalette(bool amigaStyleCursor) { + if (!amigaStyleCursor) { + CursorMan.replaceCursorPalette(sciMouseCursorPalette, 1, ARRAYSIZE(sciMouseCursorPalette) / 4); + } else { // amigaStyleCursor + CursorMan.replaceCursorPalette(amigaMouseCursorPalette, 1, ARRAYSIZE(amigaMouseCursorPalette) / 4); + } +} + /** * Initialize graphics device. * @@ -1078,7 +1086,7 @@ void GfxMgr::putPixelsA(int x, int y, int n, uint8 *p) { } else { const uint16 mask = _vm->getFeatures() & (GF_AGI256 | GF_AGI256_2) && !_vm->_debug.priority ? 0xffff : 0x0f0f; for (x *= 2; n--; p++, x += 2) { - register uint16 q = ((uint16) * p << 8) | *p; + register uint16 q = ((uint16)*p << 8) | *p; *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & mask; } } diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h index e06af90f5d..96b6247aeb 100644 --- a/engines/agi/graphics.h +++ b/engines/agi/graphics.h @@ -27,6 +27,7 @@ #define AGI_GRAPHICS_H #include "common/stdafx.h" +#include "agi/font.h" namespace Agi { @@ -39,7 +40,7 @@ class AgiEngine; class GfxMgr { private: - AgiEngine *_vm; + AgiBase *_vm; uint8 _palette[256 * 4]; uint8 *_agiScreen; @@ -54,11 +55,11 @@ private: void rawDrawButton(int x, int y, const char *s, int fgcolor, int bgcolor, bool border, int textOffset); public: - GfxMgr(AgiEngine *vm); + GfxMgr(AgiBase *vm); void gfxPutBlock(int x1, int y1, int x2, int y2); - void putTextCharacter(int, int, int, unsigned int, int, int, bool checkerboard = false); + void putTextCharacter(int, int, int, unsigned int, int, int, bool checkerboard = false, const uint8 *font = curFont); void shakeScreen(int); void shakeStart(); void shakeEnd(); @@ -88,10 +89,10 @@ public: int getAGIPalFileNum(); void drawFrame(int x1, int y1, int x2, int y2, int c1, int c2); - void putPixel(int, int, int); void putBlock(int x1, int y1, int x2, int y2); void gfxSetPalette(); void setCursor(bool amigaStyleCursor = false); + void setCursorPalette(bool amigaStylePalette = false); int keypress(); int getKey(); diff --git a/engines/agi/agi_v2.cpp b/engines/agi/loader_v2.cpp index 375bbec411..c0c6df2fcb 100644 --- a/engines/agi/agi_v2.cpp +++ b/engines/agi/loader_v2.cpp @@ -173,12 +173,6 @@ uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) { abort(); } } else { -#if 0 - /* FIXME: call some panic handler instead of - * deiniting directly - */ - deinitVideoMode(); -#endif report("Error: bad signature %04x\n", sig); // fprintf (stderr, "ACK! BAD RESOURCE!!!\n"); return 0; @@ -254,9 +248,9 @@ int AgiLoader_v2::loadResource(int t, int n) { data = loadVolRes(&_vm->_game.dirSound[n]); if (data != NULL) { - _vm->_game.sounds[n].rdata = data; + // Freeing of the raw resource from memory is delegated to the createFromRawResource-function + _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, *_vm->_sound); _vm->_game.dirSound[n].flags |= RES_LOADED; - _vm->_sound->decodeSound(n); } else { ec = errBadResource; } diff --git a/engines/agi/agi_v3.cpp b/engines/agi/loader_v3.cpp index 69a8698ecb..362d778c66 100644 --- a/engines/agi/agi_v3.cpp +++ b/engines/agi/loader_v3.cpp @@ -228,10 +228,6 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) { fp.read(&x, 7); if (READ_BE_UINT16((uint8 *) x) != 0x1234) { -#if 0 - /* FIXME */ - deinitVideoMode(); -#endif debugC(3, kDebugLevelResources, "path = %s", path.c_str()); debugC(3, kDebugLevelResources, "offset = %d", agid->offset); debugC(3, kDebugLevelResources, "x = %x %x", x[0], x[1]); @@ -345,9 +341,9 @@ int AgiLoader_v3::loadResource(int t, int n) { data = loadVolRes(&_vm->_game.dirSound[n]); if (data != NULL) { - _vm->_game.sounds[n].rdata = data; + // Freeing of the raw resource from memory is delegated to the createFromRawResource-function + _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, *_vm->_sound); _vm->_game.dirSound[n].flags |= RES_LOADED; - _vm->_sound->decodeSound(n); } else { ec = errBadResource; } diff --git a/engines/agi/module.mk b/engines/agi/module.mk index d74eba034a..e5e8555ba2 100644 --- a/engines/agi/module.mk +++ b/engines/agi/module.mk @@ -2,8 +2,6 @@ MODULE := engines/agi MODULE_OBJS = \ agi.o \ - agi_v2.o \ - agi_v3.o \ checks.o \ console.o \ cycle.o \ @@ -13,6 +11,8 @@ MODULE_OBJS = \ id.o \ inv.o \ keyboard.o \ + loader_v2.o \ + loader_v3.o \ logic.o \ lzw.o \ menu.o \ @@ -22,6 +22,11 @@ MODULE_OBJS = \ op_dbg.o \ op_test.o \ picture.o \ + preagi.o \ + preagi_common.o \ + preagi_mickey.o \ + preagi_troll.o \ + preagi_winnie.o \ predictive.o \ saveload.o \ sound.o \ diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp index 144e965465..006348f433 100644 --- a/engines/agi/picture.cpp +++ b/engines/agi/picture.cpp @@ -28,75 +28,45 @@ #include "agi/agi.h" #include "agi/graphics.h" + namespace Agi { -#define nextByte data[foffs++] - -static uint8 *data; -static uint32 flen; -static uint32 foffs; - -static uint8 patCode; -static uint8 patNum; -static uint8 priOn; -static uint8 scrOn; -static uint8 scrColour; -static uint8 priColour; - -static uint8 circles[][15] = { /* agi circle bitmaps */ - {0x80}, - /* {0xfc}, */ - { 3 << 4 }, /* pattern data different from specs. fixes gold rush. does not seem to break any other v3 games */ - {0x5f, 0xf4}, - {0x66, 0xff, 0xf6, 0x60}, - {0x23, 0xbf, 0xff, 0xff, 0xee, 0x20}, - {0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00}, - {0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80}, - {0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18} -}; - -static uint8 splatterMap[32] = { /* splatter brush bitmaps */ - 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, - 0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14, - 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, - 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 -}; - -static uint8 splatterStart[128] = { /* starting bit position */ - 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, - 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, - 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, - 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, - 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, - 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, - 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, - 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, - 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, - 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, - 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, - 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, - 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, - 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, - 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 -}; +PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) { + _vm = agi; + _gfx = gfx; + + _data = NULL; + _flen = _foffs = 0; + + _patCode = _patNum = _priOn = _scrOn = _scrColor = _priColor = 0; + _xOffset = _yOffset = 0; + + _pictureVersion = AGIPIC_V2; + _minCommand = 0xf0; + _flags = 0; +} void PictureMgr::putVirtPixel(int x, int y) { uint8 *p; - if (x < 0 || y < 0 || x >= _WIDTH || y >= _HEIGHT) + x += _xOffset; + y += _yOffset; + + if (x < 0 || y < 0 || x >= _width || y >= _height) return; - p = &_vm->_game.sbuf16c[y * _WIDTH + x]; + p = &_vm->_game.sbuf16c[y * _width + x]; - if (priOn) - *p = (priColour << 4) | (*p & 0x0f); - if (scrOn) - *p = scrColour | (*p & 0xf0); + if (_priOn) + *p = (_priColor << 4) | (*p & 0x0f); + if (_scrOn) + *p = _scrColor | (*p & 0xf0); } /* For the flood fill routines */ /* MH2 needs stack size > 300 */ +// FIXME: Consider using FixedStack<> or Stack<> from common/stack.h here #define STACK_SIZE 512 static unsigned int stackPtr; static uint16 stack[STACK_SIZE]; @@ -130,10 +100,10 @@ void PictureMgr::drawLine(int x1, int y1, int x2, int y2) { /* CM: Do clipping */ #define clip(x, y) if((x)>=(y)) (x)=(y) - clip(x1, _WIDTH - 1); - clip(x2, _WIDTH - 1); - clip(y1, _HEIGHT - 1); - clip(y2, _HEIGHT - 1); + clip(x1, _width - 1); + clip(x2, _width - 1); + clip(y1, _height - 1); + clip(y2, _height - 1); /* Vertical line */ @@ -219,13 +189,13 @@ void PictureMgr::drawLine(int x1, int y1, int x2, int y2) { void PictureMgr::dynamicDrawLine() { int x1, y1, disp, dx, dy; - x1 = nextByte; - y1 = nextByte; + x1 = nextByte(); + y1 = nextByte(); putVirtPixel(x1, y1); for (;;) { - if ((disp = nextByte) >= 0xf0) + if ((disp = nextByte()) >= _minCommand) break; dx = ((disp & 0xf0) >> 4) & 0x0f; @@ -240,7 +210,7 @@ void PictureMgr::dynamicDrawLine() { x1 += dx; y1 += dy; } - foffs--; + _foffs--; } /************************************************************************** @@ -251,22 +221,22 @@ void PictureMgr::dynamicDrawLine() { void PictureMgr::absoluteDrawLine() { int x1, y1, x2, y2; - x1 = nextByte; - y1 = nextByte; + x1 = nextByte(); + y1 = nextByte(); putVirtPixel(x1, y1); for (;;) { - if ((x2 = nextByte) >= 0xf0) + if ((x2 = nextByte()) >= _minCommand) break; - if ((y2 = nextByte) >= 0xf0) + if ((y2 = nextByte()) >= _minCommand) break; drawLine(x1, y1, x2, y2); x1 = x2; y1 = y2; } - foffs--; + _foffs--; } /************************************************************************** @@ -275,21 +245,26 @@ void PictureMgr::absoluteDrawLine() { INLINE int PictureMgr::isOkFillHere(int x, int y) { uint8 p; - if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT) + if (x < 0 || x >= _width || y < 0 || y >= _height) return false; - if (!scrOn && !priOn) + if (!_scrOn && !_priOn) return false; - p = _vm->_game.sbuf16c[y * _WIDTH + x]; + p = _vm->_game.sbuf16c[y * _width + x]; + + // FIXME: This overflows stack, but otherwise is a wild guess + // original has some checks against color 11 (0xB) + if (_pictureVersion == AGIPIC_V15 && 0) + return (p & 0x0f) == 0; - if (!priOn && scrOn && scrColour != 15) + if (!_priOn && _scrOn && _scrColor != 15) return (p & 0x0f) == 15; - if (priOn && !scrOn && priColour != 4) + if (_priOn && !_scrOn && _priColor != 4) return (p >> 4) == 4; - return (scrOn && (p & 0x0f) == 15 && scrColour != 15); + return (_scrOn && (p & 0x0f) == 15 && _scrColor != 15); } /************************************************************************** @@ -352,30 +327,39 @@ void PictureMgr::agiFill(unsigned int x, unsigned int y) { ** ** Draws an xCorner (drawing action 0xF5) **************************************************************************/ -void PictureMgr::xCorner() { +void PictureMgr::xCorner(bool skipOtherCoords) { int x1, x2, y1, y2; - x1 = nextByte; - y1 = nextByte; + x1 = nextByte(); + y1 = nextByte(); putVirtPixel(x1, y1); for (;;) { - x2 = nextByte; + x2 = nextByte(); - if (x2 >= 0xf0) + if (skipOtherCoords) + if (nextByte() >= _minCommand) + break; + + if (x2 >= _minCommand) break; drawLine(x1, y1, x2, y1); x1 = x2; - y2 = nextByte; - if (y2 >= 0xf0) + if (skipOtherCoords) + if (nextByte() >= _minCommand) + break; + + y2 = nextByte(); + + if (y2 >= _minCommand) break; drawLine(x1, y1, x1, y2); y1 = y2; } - foffs--; + _foffs--; } /************************************************************************** @@ -383,31 +367,39 @@ void PictureMgr::xCorner() { ** ** Draws an yCorner (drawing action 0xF4) **************************************************************************/ -void PictureMgr::yCorner() { +void PictureMgr::yCorner(bool skipOtherCoords) { int x1, x2, y1, y2; - x1 = nextByte; - y1 = nextByte; + x1 = nextByte(); + y1 = nextByte(); putVirtPixel(x1, y1); for (;;) { - y2 = nextByte; + if (skipOtherCoords) + if (nextByte() >= _minCommand) + break; + + y2 = nextByte(); - if (y2 >= 0xF0) + if (y2 >= _minCommand) break; drawLine(x1, y1, x1, y2); y1 = y2; - x2 = nextByte; + x2 = nextByte(); - if (x2 >= 0xf0) + if (x2 >= _minCommand) break; + if (skipOtherCoords) + if (nextByte() >= _minCommand) + break; + drawLine(x1, y1, x2, y1); x1 = x2; } - foffs--; + _foffs--; } /************************************************************************** @@ -418,10 +410,14 @@ void PictureMgr::yCorner() { void PictureMgr::fill() { int x1, y1; - while ((x1 = nextByte) < 0xF0 && (y1 = nextByte) < 0xf0) + if (_pictureVersion == AGIPIC_V15 && 0) + if (_scrColor == 0xf && !(_flags & kPicFTrollMode)) + return; + + while ((x1 = nextByte()) < _minCommand && (y1 = nextByte()) < _minCommand) agiFill(x1, y1); - foffs--; + _foffs--; } /************************************************************************** @@ -431,43 +427,111 @@ void PictureMgr::fill() { ** on the pattern code. **************************************************************************/ -int PictureMgr::plotPatternPoint(int x, int y, int bitpos) { - if (patCode & 0x20) { - if ((splatterMap[bitpos >> 3] >> (7 - (bitpos & 7))) & 1) { - putVirtPixel(x, y); - } - bitpos++; - if (bitpos == 0xff) - bitpos = 0; - } else - putVirtPixel(x, y); - - return bitpos; -} - void PictureMgr::plotPattern(int x, int y) { - int32 circlePos = 0; - uint32 x1, y1, pensize, bitpos = splatterStart[patNum]; - - pensize = (patCode & 7); - - if (x < (int)pensize) - x = pensize - 1; - if (y < (int)pensize) - y = pensize; - - for (y1 = y - pensize; y1 <= y + pensize; y1++) { - for (x1 = x - (pensize + 1) / 2; x1 <= x + pensize / 2; x1++) { - if (patCode & 0x10) { /* Square */ - bitpos = plotPatternPoint (x1, y1, bitpos); - } else { /* Circle */ - if ((circles[patCode & 7][circlePos >> 3] >> (7 - (circlePos & 7))) & 1) { - bitpos = plotPatternPoint(x1, y1, bitpos); - } - circlePos++; + static const uint16 binary_list[] = {0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, + 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1}; + + static const uint8 circle_list[] = {0, 1, 4, 9, 16, 25, 37, 50}; + + static const uint16 circle_data[] = + {0x8000, + 0xE000, 0xE000, 0xE000, + 0x7000, 0xF800, 0x0F800, 0x0F800, 0x7000, + 0x3800, 0x7C00, 0x0FE00, 0x0FE00, 0x0FE00, 0x7C00, 0x3800, + 0x1C00, 0x7F00, 0x0FF80, 0x0FF80, 0x0FF80, 0x0FF80, 0x0FF80, 0x7F00, 0x1C00, + 0x0E00, 0x3F80, 0x7FC0, 0x7FC0, 0x0FFE0, 0x0FFE0, 0x0FFE0, 0x7FC0, 0x7FC0, 0x3F80, 0x1F00, 0x0E00, + 0x0F80, 0x3FE0, 0x7FF0, 0x7FF0, 0x0FFF8, 0x0FFF8, 0x0FFF8, 0x0FFF8, 0x0FFF8, 0x7FF0, 0x7FF0, 0x3FE0, 0x0F80, + 0x07C0, 0x1FF0, 0x3FF8, 0x7FFC, 0x7FFC, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x0FFFE, 0x7FFC, 0x7FFC, 0x3FF8, 0x1FF0, 0x07C0}; + + uint16 circle_word; + const uint16 *circle_ptr; + uint16 counter; + uint16 pen_width = 0; + int pen_final_x = 0; + int pen_final_y = 0; + + uint8 t = 0; + uint8 temp8; + uint16 temp16; + + int pen_x = x; + int pen_y = y; + uint16 texture_num = 0; + uint16 pen_size = (_patCode & 0x07); + + circle_ptr = &circle_data[circle_list[pen_size]]; + + // setup the X position + // = pen_x - pen.size/2 + + pen_x = (pen_x * 2) - pen_size; + if (pen_x < 0) pen_x = 0; + + temp16 = 320 - (2 * pen_size); + if (pen_x >= temp16) + pen_x = temp16; + + pen_x /= 2; + pen_final_x = pen_x; // original starting point?? -> used in plotrelated + + // Setup the Y Position + // = pen_y - pen.size + pen_y = pen_y - pen_size; + if (pen_y < 0) pen_y = 0; + + temp16 = 167 - (2 * pen_size); + if (pen_y >= temp16) + pen_y = temp16; + + pen_final_y = pen_y; // used in plotrelated + + t = (uint8)(texture_num | 0x01); // even + + // new purpose for temp16 + + temp16 =( pen_size<<1) +1; // pen size + pen_final_y += temp16; // the last row of this shape + temp16 = temp16 << 1; + pen_width = temp16; // width of shape? + + bool circleCond; + int counterStep; + int ditherCond; + + if (_flags & kPicFCircle) + _patCode |= 0x10; + + if (_vm->getGameType() == GType_PreAGI) { + circleCond = ((_patCode & 0x10) == 0); + counterStep = 3; + ditherCond = 0x03; + } else { + circleCond = ((_patCode & 0x10) != 0); + counterStep = 4; + ditherCond = 0x02; + } + + for (; pen_y < pen_final_y; pen_y++) { + circle_word = *circle_ptr++; + + for (counter = 0; counter <= pen_width; counter += counterStep) { + if (circleCond || ((binary_list[counter>>1] & circle_word) != 0)) { + temp8 = t % 2; + t = t >> 1; + if (temp8 != 0) + t = t ^ 0xB8; + + // == box plot, != circle plot + if ((_patCode & 0x20) == 0 || (t & 0x03) == ditherCond) + putVirtPixel(pen_x, pen_y); } + pen_x++; } + + pen_x = pen_final_x; } + + return; } /************************************************************************** @@ -479,97 +543,223 @@ void PictureMgr::plotBrush() { int x1, y1; for (;;) { - if (patCode & 0x20) { - if ((patNum = nextByte) >= 0xF0) + if (_patCode & 0x20) { + if ((_patNum = nextByte()) >= _minCommand) break; - patNum = (patNum >> 1) & 0x7f; + _patNum = (_patNum >> 1) & 0x7f; } - if ((x1 = nextByte) >= 0xf0) + if ((x1 = nextByte()) >= _minCommand) break; - if ((y1 = nextByte) >= 0xf0) + if ((y1 = nextByte()) >= _minCommand) break; plotPattern(x1, y1); } - foffs--; + _foffs--; } /************************************************************************** -** fill -** -** AGI flood fill. (drawing action 0xF8) +** Draw AGI picture **************************************************************************/ void PictureMgr::drawPicture() { uint8 act; int drawing; - patCode = 0; - patNum = 0; - priOn = scrOn = false; - scrColour = 0xf; - priColour = 0x4; + _patCode = 0; + _patNum = 0; + _priOn = _scrOn = false; + _scrColor = 0xf; + _priColor = 0x4; drawing = 1; - debugC(8, kDebugLevelMain, "Drawing picture"); - for (drawing = 1; drawing && foffs < flen;) { - act = nextByte; + debugC(8, kDebugLevelMain, "Drawing v2 picture"); + for (drawing = 1; drawing && _foffs < _flen;) { + act = nextByte(); + + if (_pictureVersion == AGIPIC_C64 && act >= 0xf0 && act <= 0xfe) { + _scrColor = act - 0xf0; + continue; + } + switch (act) { - case 0xf0: /* set colour on screen */ - scrColour = nextByte; - scrColour &= 0xF; /* for v3 drawing diff */ - scrOn = true; + case 0xe0: // x-corner (C64) + xCorner(); + break; + case 0xe1: // y-corner (C64) + yCorner(); + break; + case 0xe2: // dynamic draw lines (C64) + dynamicDrawLine(); + break; + case 0xe3: // absolute draw lines (C64) + absoluteDrawLine(); break; - case 0xf1: /* disable screen drawing */ - scrOn = false; + case 0xe4: // fill (C64) + _scrColor = nextByte(); + _scrColor &= 0xF; /* for v3 drawing diff */ + fill(); + break; + case 0xe5: // enable screen drawing (C64) + _scrOn = true; break; - case 0xf2: /* set colour on priority */ - priColour = nextByte; - priColour &= 0xf; /* for v3 drawing diff */ - priOn = true; + case 0xe6: // plot brush (C64) + _patCode = nextByte(); + plotBrush(); break; - case 0xf3: /* disable priority screen */ - priOn = false; + case 0xf0: // set colour on screen (AGI pic v2) + if (_pictureVersion == AGIPIC_V15) + break; + + _scrColor = nextByte(); + _scrColor &= 0xF; // for v3 drawing diff + _scrOn = true; + break; + case 0xf1: + if (_pictureVersion == AGIPIC_V1) { + _scrColor = nextByte(); + _scrColor &= 0xF; // for v3 drawing diff + _scrOn = true; + _priOn = false; + } else if (_pictureVersion == AGIPIC_V15) { // set colour on screen + _scrColor = nextByte(); + _scrColor &= 0xF; + _scrOn = true; + } else if (_pictureVersion == AGIPIC_V2) { // disable screen drawing + _scrOn = false; + } + break; + case 0xf2: // set colour on priority (AGI pic v2) + if (_pictureVersion == AGIPIC_V15) + break; + + _priColor = nextByte(); + _priColor &= 0xf; // for v3 drawing diff + _priOn = true; + break; + case 0xf3: + if (_pictureVersion == AGIPIC_V1) { + _scrColor = nextByte(); + _scrColor &= 0xF; // for v3 drawing diff + _scrOn = true; + _priColor = nextByte(); + _priColor &= 0xf; // for v3 drawing diff + _priOn = true; + } + + if (_pictureVersion == AGIPIC_V15 && (_flags & kPicFf3Stop)) + drawing = 0; + + if (_pictureVersion == AGIPIC_V2) // disable priority screen + _priOn = false; break; - case 0xf4: /* y-corner */ + case 0xf4: // y-corner + if (_pictureVersion == AGIPIC_V15) + break; + yCorner(); break; - case 0xf5: /* x-corner */ + case 0xf5: // x-corner + if (_pictureVersion == AGIPIC_V15) + break; + xCorner(); break; - case 0xf6: /* absolute draw lines */ + case 0xf6: // absolute draw lines + if (_pictureVersion == AGIPIC_V15) + break; + absoluteDrawLine(); break; - case 0xf7: /* dynamic draw lines */ + case 0xf7: // dynamic draw lines + if (_pictureVersion == AGIPIC_V15) + break; + dynamicDrawLine(); break; - case 0xf8: /* fill */ - fill(); + case 0xf8: // fill + if (_pictureVersion == AGIPIC_V15) { + yCorner(true); + } else if (_pictureVersion == AGIPIC_V2) { + fill(); + } break; - case 0xf9: /* set pattern */ - patCode = nextByte; + case 0xf9: // set pattern + if (_pictureVersion == AGIPIC_V15) { + xCorner(true); + } else if (_pictureVersion == AGIPIC_V2) { + _patCode = nextByte(); + + if (_vm->getGameType() == GType_PreAGI) + plotBrush(); + } break; - case 0xfA: /* plot brush */ - plotBrush(); + case 0xfa: // plot brush + if (_pictureVersion == AGIPIC_V1) { + _scrOn = false; + _priOn = true; + absoluteDrawLine(); + _scrOn = true; + _priOn = false; + } else if (_pictureVersion == AGIPIC_V15) { + absoluteDrawLine(); + } else if (_pictureVersion == AGIPIC_V2) { + plotBrush(); + } break; - case 0xFF: /* end of pic data */ - default: + case 0xfb: + if (_pictureVersion == AGIPIC_V1) { + dynamicDrawLine(); + } else if (_pictureVersion == AGIPIC_V15) { + absoluteDrawLine(); + } + break; + case 0xfc: // fill (AGI pic v1) + if (_pictureVersion == AGIPIC_V15) + break; + + _scrColor = nextByte(); + _scrColor &= 0xF; + _priColor = nextByte(); + _priColor &= 0xf; + fill(); + break; + case 0xfe: // fill (AGI pic v1.5) + _scrColor = nextByte(); + _scrColor &= 0xF; + _scrOn = true; + fill(); + break; + case 0xff: // end of pic data drawing = 0; break; + default: + warning("Unknown picture opcode (%x) at (%x)", act, _foffs - 1); + } + if ((_flags & kPicFStep) && _vm->getGameType() == GType_PreAGI) { + // FIXME: This is used by Mickey for the crystal animation, but + // currently it's very very very slow + /* + int storedXOffset = _xOffset; + int storedYOffset = _yOffset; + // FIXME: picture coordinates are correct for Mickey only + showPic(10, 0, _width, _height); + _gfx->doUpdate(); + g_system->updateScreen(); + _xOffset = storedXOffset; + _yOffset = storedYOffset; + g_system->delayMillis(25); + */ } } } -/* - * Public functions - */ - /** - * + * convert AGI v3 format picture to AGI v2 format */ uint8 *PictureMgr::convertV3Pic(uint8 *src, uint32 len) { uint8 d, old = 0, x, *in, *xdata, *out, mode = 0; @@ -621,33 +811,36 @@ uint8 *PictureMgr::convertV3Pic(uint8 *src, uint32 len) { * @param clear clear AGI screen before drawing * @param agi256 load an AGI256 picture resource */ -int PictureMgr::decodePicture(int n, int clear, bool agi256) { +int PictureMgr::decodePicture(int n, int clear, bool agi256, int pic_width, int pic_height) { debugC(8, kDebugLevelResources, "(%d)", n); - patCode = 0; - patNum = 0; - priOn = scrOn = false; - scrColour = 0xF; - priColour = 0x4; + _patCode = 0; + _patNum = 0; + _priOn = _scrOn = false; + _scrColor = 0xF; + _priColor = 0x4; - data = _vm->_game.pictures[n].rdata; - flen = _vm->_game.dirPic[n].len; - foffs = 0; + _data = _vm->_game.pictures[n].rdata; + _flen = _vm->_game.dirPic[n].len; + _foffs = 0; + + _width = pic_width; + _height = pic_height; if (clear && !agi256) // 256 color pictures should always fill the whole screen, so no clearing for them. - memset(_vm->_game.sbuf16c, 0x4f, _WIDTH * _HEIGHT); // Clear 16 color AGI screen (Priority 4, color white). + memset(_vm->_game.sbuf16c, 0x4f, _width * _height); // Clear 16 color AGI screen (Priority 4, color white). if (!agi256) { drawPicture(); // Draw 16 color picture. } else { - const uint32 maxFlen = _WIDTH * _HEIGHT; - memcpy(_vm->_game.sbuf256c, data, MIN(flen, maxFlen)); // Draw 256 color picture. + const uint32 maxFlen = _width * _height; + memcpy(_vm->_game.sbuf256c, _data, MIN(_flen, maxFlen)); // Draw 256 color picture. - if (flen < maxFlen) { + if (_flen < maxFlen) { warning("Undersized AGI256 picture resource %d, using it anyway. Filling rest with white.", n); - memset(_vm->_game.sbuf256c + flen, 0x0f, maxFlen - flen); // Fill missing area with white. - } else if (flen > maxFlen) - warning("Oversized AGI256 picture resource %d, decoding only %ux%u part of it", n, _WIDTH, _HEIGHT); + memset(_vm->_game.sbuf256c + _flen, 0x0f, maxFlen - _flen); // Fill missing area with white. + } else if (_flen > maxFlen) + warning("Oversized AGI256 picture resource %d, decoding only %ux%u part of it", n, _width, _height); } if (clear) @@ -658,6 +851,40 @@ int PictureMgr::decodePicture(int n, int clear, bool agi256) { } /** + * Decode an AGI picture resource. + * This function decodes an AGI picture resource into the correct slot + * and draws it on the AGI screen, optionally clearing the screen before + * drawing. + * @param data the AGI Picture data + * @param length the size of the picture data buffer + * @param clear clear AGI screen before drawing + */ +int PictureMgr::decodePicture(byte* data, uint32 length, int clear, int pic_width, int pic_height) { + _patCode = 0; + _patNum = 0; + _priOn = _scrOn = false; + _scrColor = 0xF; + _priColor = 0x4; + + _data = data; + _flen = length; + _foffs = 0; + + _width = pic_width; + _height = pic_height; + + if (clear) // 256 color pictures should always fill the whole screen, so no clearing for them. + memset(_vm->_game.sbuf16c, 0x4f, _width * _height); // Clear 16 color AGI screen (Priority 4, color white). + + drawPicture(); // Draw 16 color picture. + + free(_data); + _data = 0; + + return errOK; +} + +/** * Unload an AGI picture resource. * This function unloads an AGI picture resource and deallocates * resource data. @@ -677,20 +904,44 @@ int PictureMgr::unloadPicture(int n) { * Show AGI picture. * This function copies a ``hidden'' AGI picture to the output device. */ -void PictureMgr::showPic() { - int i, y; +void PictureMgr::showPic(int x, int y, int pic_width, int pic_height) { + int i, y1; int offset; + _width = pic_width; + _height = pic_height; debugC(8, kDebugLevelMain, "Show picture!"); i = 0; offset = _vm->_game.lineMinPrint * CHAR_LINES; - for (y = 0; y < _HEIGHT; y++) { - _gfx->putPixelsA(0, y + offset, _WIDTH, &_vm->_game.sbuf16c[i]); - i += _WIDTH; + for (y1 = y; y1 < y + _height; y1++) { + _gfx->putPixelsA(x, y1 + offset, _width, &_vm->_game.sbuf16c[i]); + i += _width; } _gfx->flushScreen(); } +// preagi needed functions (for plotPattern) +void PictureMgr::setPattern(uint8 code, uint8 num) { + _patCode = code; + _patNum = num; +} + +void PictureMgr::setPictureVersion(AgiPictureVersion version) { + _pictureVersion = version; + + if (version == AGIPIC_C64) + _minCommand = 0xe0; + else + _minCommand = 0xf0; +} + +void PictureMgr::setPictureData(uint8 *data, int len) { + _data = data; + _flen = len; + _foffs = 0; + _flags = 0; +} + } // End of namespace Agi diff --git a/engines/agi/picture.h b/engines/agi/picture.h index 0f8584f3b2..50689b5b3a 100644 --- a/engines/agi/picture.h +++ b/engines/agi/picture.h @@ -30,6 +30,9 @@ namespace Agi { +#define _DEFAULT_WIDTH 160 +#define _DEFAULT_HEIGHT 168 + /** * AGI picture resource. */ @@ -38,11 +41,28 @@ struct AgiPicture { uint8 *rdata; /**< raw vector image data */ }; -class AgiEngine; +// AGI picture version +enum AgiPictureVersion { + AGIPIC_C64, + AGIPIC_V1, + AGIPIC_V15, + AGIPIC_V2 +}; + +enum AgiPictureFlags { + kPicFNone = (1 >> 0), + kPicFCircle = (1 >> 1), + kPicFStep = (1 >> 2), + kPicFf3Stop = (1 >> 3), + kPicFf3Cont = (1 >> 4), + kPicFTrollMode = (1 >> 5) +}; + +class AgiBase; class GfxMgr; class PictureMgr { - AgiEngine *_vm; + AgiBase *_vm; GfxMgr *_gfx; private: @@ -54,24 +74,69 @@ private: INLINE int isOkFillHere(int x, int y); void fillScanline(int x, int y); void agiFill(unsigned int x, unsigned int y); - void xCorner(); - void yCorner(); + void xCorner(bool skipOtherCoords = false); + void yCorner(bool skipOtherCoords = false); void fill(); int plotPatternPoint(int x, int y, int bitpos); - void plotPattern(int x, int y); void plotBrush(); - void drawPicture(); + + uint8 nextByte() { return _data[_foffs++]; } public: - PictureMgr(AgiEngine *agi, GfxMgr *gfx) { - _vm = agi; - _gfx = gfx; - } + PictureMgr(AgiBase *agi, GfxMgr *gfx); - int decodePicture(int n, int clear, bool agi256 = false); + int decodePicture(int n, int clear, bool agi256 = false, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT); + int decodePicture(byte* data, uint32 length, int clear, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT); int unloadPicture(int); - void showPic(); + void drawPicture(); + void showPic(int x = 0, int y = 0, int pic_width = _DEFAULT_WIDTH, int pic_height = _DEFAULT_HEIGHT); uint8 *convertV3Pic(uint8 *src, uint32 len); + + void plotPattern(int x, int y); // public because it's used directly by preagi + + void setPattern(uint8 code, uint8 num); + + void setPictureVersion(AgiPictureVersion version); + void setPictureData(uint8 *data, int len); + + void setPictureFlags(int flags) { _flags = flags; } + + void setOffset(int offX, int offY) { + _xOffset = offX; + _yOffset = offY; + } + + void setDimensions(int w, int h) { + _width = w; + _height = h; + } + + void putPixel(int x, int y, uint8 color) { + _scrColor = color; + _priOn = false; + _scrOn = true; + putVirtPixel(x, y); + } + +private: + uint8 *_data; + uint32 _flen; + uint32 _foffs; + + uint8 _patCode; + uint8 _patNum; + uint8 _priOn; + uint8 _scrOn; + uint8 _scrColor; + uint8 _priColor; + + uint8 _minCommand; + + AgiPictureVersion _pictureVersion; + int _width, _height; + int _xOffset, _yOffset; + + int _flags; }; } // End of namespace Agi diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp new file mode 100644 index 0000000000..b42948ccdb --- /dev/null +++ b/engines/agi/preagi.cpp @@ -0,0 +1,253 @@ +/* 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/stdafx.h" + +#include "common/events.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "graphics/cursorman.h" + +#include "sound/mididrv.h" +#include "sound/mixer.h" + +#include "agi/preagi.h" +#include "agi/graphics.h" +#include "agi/sprite.h" +#include "agi/opcodes.h" +#include "agi/keyboard.h" +#include "agi/menu.h" +#include "agi/sound.h" + +// preagi engines +#include "agi/preagi_mickey.h" +#include "agi/preagi_troll.h" +#include "agi/preagi_winnie.h" + +namespace Agi { + +PreAgiEngine::PreAgiEngine(OSystem *syst) : AgiBase(syst) { + + // Setup mixer + if (!_mixer->isReady()) { + warning("Sound initialization failed."); + } + + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + + /* + const GameSettings *g; + + const char *gameid = ConfMan.get("gameid").c_str(); + for (g = agiSettings; g->gameid; ++g) + if (!scumm_stricmp(g->gameid, gameid)) + _gameId = g->id; + */ + + _rnd = new Common::RandomSource(); + + Common::addSpecialDebugLevel(kDebugLevelMain, "Main", "Generic debug level"); + Common::addSpecialDebugLevel(kDebugLevelResources, "Resources", "Resources debugging"); + Common::addSpecialDebugLevel(kDebugLevelSprites, "Sprites", "Sprites debugging"); + Common::addSpecialDebugLevel(kDebugLevelInventory, "Inventory", "Inventory debugging"); + Common::addSpecialDebugLevel(kDebugLevelInput, "Input", "Input events debugging"); + Common::addSpecialDebugLevel(kDebugLevelMenu, "Menu", "Menu debugging"); + Common::addSpecialDebugLevel(kDebugLevelScripts, "Scripts", "Scripts debugging"); + Common::addSpecialDebugLevel(kDebugLevelSound, "Sound", "Sound debugging"); + Common::addSpecialDebugLevel(kDebugLevelText, "Text", "Text output debugging"); + Common::addSpecialDebugLevel(kDebugLevelSavegame, "Savegame", "Saving & restoring game debugging"); + + memset(&_game, 0, sizeof(struct AgiGame)); + memset(&_debug, 0, sizeof(struct AgiDebug)); + memset(&g_mouse, 0, sizeof(struct Mouse)); + +/* + _game.clockEnabled = false; + _game.state = STATE_INIT; + + _keyQueueStart = 0; + _keyQueueEnd = 0; + + _keyControl = 0; + _keyAlt = 0; + + _allowSynthetic = false; + + g_tickTimer = 0; + + _intobj = NULL; + + _stackSize = 0; + _imageStack = NULL; + _imageStackPointer = 0; + + _lastSentence[0] = 0; + memset(&_stringdata, 0, sizeof(struct StringData)); + + _objects = NULL; + + _oldMode = -1; + + _firstSlot = 0; +*/ +} + +void PreAgiEngine::initialize() { + // TODO: Some sound emulation modes do not fit our current music + // drivers, and I'm not sure what they are. For now, they might + // as well be called "PC Speaker" and "Not PC Speaker". + + switch (MidiDriver::detectMusicDriver(MDT_PCSPK)) { + case MD_PCSPK: + _soundemu = SOUND_EMU_PC; + break; + default: + _soundemu = SOUND_EMU_NONE; + break; + } + + if (ConfMan.hasKey("render_mode")) { + _renderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str()); + } else if (ConfMan.hasKey("platform")) { + switch (Common::parsePlatform(ConfMan.get("platform"))) { + case Common::kPlatformAmiga: + _renderMode = Common::kRenderAmiga; + break; + case Common::kPlatformPC: + _renderMode = Common::kRenderEGA; + break; + default: + _renderMode = Common::kRenderEGA; + break; + } + } + + _gfx = new GfxMgr(this); + _sound = new SoundMgr(this, _mixer); + _picture = new PictureMgr(this, _gfx); + //_sprites = new SpritesMgr(this, _gfx); + + _gfx->initMachine(); + + _game.gameFlags = 0; + + _game.colorFg = 15; + _game.colorBg = 0; + + _defaultColor = 0xF; + + _game.name[0] = '\0'; + + _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically + _game.sbuf16c = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen + _game.sbuf = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default + + _game.lineMinPrint = 0; // hardcoded + + _gfx->initVideo(); + _sound->initSound(); + + //_timer->installTimerProc(agiTimerFunctionLow, 10 * 1000, NULL); + + _game.ver = -1; // Don't display the conf file warning + + debugC(2, kDebugLevelMain, "Detect game"); + + /* clear all resources and events */ + for (int i = 0; i < MAX_DIRS; i++) { + memset(&_game.pictures[i], 0, sizeof(struct AgiPicture)); + memset(&_game.sounds[i], 0, sizeof(class AgiSound *)); // _game.sounds contains pointers now + memset(&_game.dirPic[i], 0, sizeof(struct AgiDir)); + memset(&_game.dirSound[i], 0, sizeof(struct AgiDir)); + } + + debugC(2, kDebugLevelMain, "Init sound"); +} + +PreAgiEngine::~PreAgiEngine() { + +} + +int PreAgiEngine::init() { + + // Detect game + if (!initGame()) { + GUIErrorMessage("No valid games were found in the specified directory."); + return -1; + } + + // Initialize backend + _system->beginGFXTransaction(); + initCommonGFX(false); + _system->initSize(320, 200); + _system->endGFXTransaction(); + + initialize(); + + _gfx->gfxSetPalette(); + + return 0; +} + +int PreAgiEngine::go() { + setflag(fSoundOn, true); // enable sound + + // run preagi engine main loop + switch (getGameID()) { + case GID_MICKEY: + { + Mickey *mickey = new Mickey(this); + mickey->init(); + mickey->run(); + } + break; + case GID_WINNIE: + { + Winnie *winnie = new Winnie(this); + winnie->init(); + winnie->run(); + } + break; + case GID_TROLL: + { + Troll *troll = new Troll(this); + troll->init(); + troll->run(); + } + break; + default: + error("Unknown preagi engine"); + break; + } + return 0; +} + +} // End of namespace Agi diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h new file mode 100644 index 0000000000..50c68991c9 --- /dev/null +++ b/engines/agi/preagi.h @@ -0,0 +1,99 @@ +/* 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 AGI_PREAGI_H +#define AGI_PREAGI_H + +#include "agi/agi.h" +#include "agi/preagi_common.h" + +namespace Agi { + +class PreAgiEngine : public AgiBase { + int _gameId; + +protected: + int init(); + int go(); + void shutdown(); + void initialize(); + + bool initGame(); + +public: + void agiTimerLow() {} + int agiGetKeypressLow() { return 0; } + int agiIsKeypressLow() { return 0; } + + PreAgiEngine(OSystem *syst); + virtual ~PreAgiEngine(); + int getGameId() { + return _gameId; + } + + GfxMgr *_gfx; + SoundMgr *_sound; + PictureMgr *_picture; + + void clearImageStack() {} + void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) {} + void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, + int16 p4, int16 p5, int16 p6, int16 p7) {} + void releaseImageStack() {} + + // Game + Common::String getTargetName() { return _targetName; } + + // Screen + void clearScreen(int attr, bool overrideDefault = true); + void clearGfxScreen(int attr); + void setDefaultTextColor(int attr) { _defaultColor = attr; } + + // Keyboard + int getSelection(SelectionTypes type); + bool waitAnyKeyChoice(); + int rnd(int hi) { return (_rnd->getRandomNumber(hi) + 1); } + + // Text + void drawStr(int row, int col, int attr, const char *buffer); + void drawStrMiddle(int row, int attr, const char *buffer); + void clearTextArea(); + void clearRow(int row); + void XOR80(char *buffer); + void printStr(const char *szMsg); + void printStrXOR(char *szMsg); + + // Saved Games + Common::SaveFileManager* getSaveFileMan() { return _saveFileMan; } + +private: + int _defaultColor; +}; + +} // End of namespace Agi + + +#endif diff --git a/engines/agi/preagi_common.cpp b/engines/agi/preagi_common.cpp new file mode 100644 index 0000000000..9ad494e410 --- /dev/null +++ b/engines/agi/preagi_common.cpp @@ -0,0 +1,211 @@ +/* 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/stdafx.h" +#include "common/events.h" + +#include "agi/preagi.h" +#include "agi/font.h" +#include "agi/graphics.h" +#include "agi/keyboard.h" + +#include "agi/preagi_common.h" + +namespace Agi { + +// Screen functions +void PreAgiEngine::clearScreen(int attr, bool overrideDefault) { + if (overrideDefault) + _defaultColor = attr; + + _gfx->clearScreen((attr & 0xF0) / 0x10); +} + +void PreAgiEngine::clearGfxScreen(int attr) { + _gfx->drawRectangle(0, 0, GFX_WIDTH - 1, IDI_MAX_ROW_PIC * 8 -1, (attr & 0xF0) / 0x10); +} + +// String functions + +void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) { + int code; + + if (attr == kColorDefault) + attr = _defaultColor; + + for (int iChar = 0; iChar < (int)strlen(buffer); iChar++) { + code = buffer[iChar]; + + switch (code) { + case '\n': + case 0x8D: + if (++row == 200 / 8) return; + col = 0; + break; + + case '|': + // swap attribute nibbles + break; + + default: + _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, getGameID() == GID_MICKEY ? mickey_fontdata : ibm_fontdata); + + if (++col == 320 / 8) { + col = 0; + if (++row == 200 / 8) return; + } + } + } +} + +void PreAgiEngine::drawStrMiddle(int row, int attr, const char *buffer) { + int col = (25 / 2) - (strlen(buffer) / 2); // 25 = 320 / 8 (maximum column) + drawStr(row, col, attr, buffer); +} + +void PreAgiEngine::clearTextArea() { + int start = IDI_MAX_ROW_PIC; + + if (getGameID() == GID_TROLL) + start = 21; + + for (int row = start; row < 200 / 8; row++) { + clearRow(row); + } +} + +void PreAgiEngine::clearRow(int row) { + drawStr(row, 0, IDA_DEFAULT, " "); // 40 spaces +} + +void PreAgiEngine::printStr(const char* szMsg) { + clearTextArea(); + drawStr(21, 0, IDA_DEFAULT, szMsg); + _gfx->doUpdate(); + _system->updateScreen(); +} + +void PreAgiEngine::XOR80(char *buffer) { + for (size_t i = 0; i < strlen(buffer); i++) + if (buffer[i] & 0x80) + buffer[i] ^= 0x80; +} + +void PreAgiEngine::printStrXOR(char *szMsg) { + XOR80(szMsg); + printStr(szMsg); +} + +// Input functions + +int PreAgiEngine::getSelection(SelectionTypes type) { + Common::Event event; + + // Selection types: + // 0: Y/N + // 1: 1-9 + for (;;) { + while (_eventMan->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _system->quit(); + case Common::EVENT_LBUTTONUP: + if (type == kSelYesNo) + return 1; + case Common::EVENT_RBUTTONUP: + return 0; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_y: + if (type == kSelYesNo) + return 1; + case Common::KEYCODE_n: + if (type == kSelYesNo) + return 0; + case Common::KEYCODE_ESCAPE: + if (type == kSelNumber) + return 0; + case Common::KEYCODE_1: + case Common::KEYCODE_2: + case Common::KEYCODE_3: + case Common::KEYCODE_4: + case Common::KEYCODE_5: + case Common::KEYCODE_6: + case Common::KEYCODE_7: + case Common::KEYCODE_8: + case Common::KEYCODE_9: + if (type == kSelNumber) + return event.kbd.keycode - Common::KEYCODE_1 + 1; + case Common::KEYCODE_SPACE: + if (type == kSelSpace) + return 1; + default: + if (type == kSelYesNo) { + return 2; + } else if (type == kSelNumber) { + return 10; + } + } + break; + default: + break; + } + } + _system->updateScreen(); + _system->delayMillis(10); + } + return 0; +} + +bool PreAgiEngine::waitAnyKeyChoice() { + Common::Event event; + + for (;;) { + while (_eventMan->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _system->quit(); + case Common::EVENT_LBUTTONUP: + return true; + case Common::EVENT_RBUTTONUP: + return false; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: //Escape + return false; + default: + return true; + } + break; + default: + break; + } + } + _system->updateScreen(); + _system->delayMillis(10); + } +} + +} diff --git a/engines/parallaction/commands.h b/engines/agi/preagi_common.h index 64510afc13..434bb685a6 100644 --- a/engines/parallaction/commands.h +++ b/engines/agi/preagi_common.h @@ -23,61 +23,27 @@ * */ -#ifndef PARALLACTION_COMMANDS_H -#define PARALLACTION_COMMANDS_H -#include "common/stdafx.h" -#include "common/scummsys.h" +#ifndef AGI_PREAGI_COMMON_H +#define AGI_PREAGI_COMMON_H -#include "parallaction/defs.h" +namespace Agi { -namespace Parallaction { +// default attributes +#define IDA_DEFAULT 0x0F +#define IDA_DEFAULT_REV 0xF0 -enum CommandFlags { - kFlagsVisited = 1, - kFlagsExit = 0x10000000, - kFlagsEnter = 0x20000000, - kFlagsGlobal = 0x40000000 -}; - -struct Zone; -struct Animation; - - -// TODO: turn this into a struct -union CommandData { - uint32 _flags; - Animation * _animation; - Zone* _zone; - char* _string; - uint16 _callable; - uint16 _object; - struct { - int16 _x; - int16 _y; - } _move; +#define kColorDefault 0x1337 - CommandData() { - _flags = 0; - } +#define IDI_MAX_ROW_PIC 20 - ~CommandData() { - } +enum SelectionTypes { + kSelYesNo, + kSelNumber, + kSelSpace }; -struct Command { - uint16 _id; - CommandData u; - uint32 _flagsOn; - uint32 _flagsOff; - - Command(); - ~Command(); -}; - -typedef ManagedList<Command*> CommandList; - -} // namespace Parallaction +} // End of namespace Agi #endif diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp new file mode 100644 index 0000000000..5215d90c21 --- /dev/null +++ b/engines/agi/preagi_mickey.cpp @@ -0,0 +1,2215 @@ +/* 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/stdafx.h" +#include "common/events.h" +#include "common/savefile.h" + +#include "graphics/cursorman.h" + +#include "agi/preagi.h" +#include "agi/preagi_common.h" +#include "agi/preagi_mickey.h" +#include "agi/graphics.h" + +#define IDI_SND_OSCILLATOR_FREQUENCY 1193180 + +namespace Agi { + +int Mickey::getDat(int iRoom) { + if (((iRoom > 0) && (iRoom < 24)) || iRoom == 154 || iRoom == 155) return IDI_MSA_PLANET_EARTH; + if ((iRoom >= 30) && (iRoom <= 39)) return IDI_MSA_PLANET_VENUS; + if ((iRoom >= 40) && (iRoom <= 69)) return IDI_MSA_PLANET_NEPTUNE; + if ((iRoom >= 70) && (iRoom <= 82)) return IDI_MSA_PLANET_MERCURY; + if ((iRoom >= 83) && (iRoom <= 92)) return IDI_MSA_PLANET_SATURN; + if ((iRoom >= 93) && (iRoom <= 103)) return IDI_MSA_PLANET_PLUTO; + if ((iRoom >= 106) && (iRoom <= 120)) return IDI_MSA_PLANET_JUPITER; + if ((iRoom >= 121) && (iRoom <= 132)) return IDI_MSA_PLANET_MARS; + if ((iRoom >= 133) && (iRoom <= 145)) return IDI_MSA_PLANET_URANUS; + return IDI_MSA_PLANET_SPACESHIP; +} + +void Mickey::readExe(int ofs, uint8 *buffer, long buflen) { + Common::File infile; + if (!infile.open(IDS_MSA_PATH_EXE)) + return; + infile.seek(ofs, SEEK_SET); + infile.read(buffer, buflen); + infile.close(); +} + +void Mickey::getDatFileName(int iRoom, char *szFile) { + sprintf(szFile, IDS_MSA_PATH_DAT, IDS_MSA_NAME_DAT[getDat(iRoom)]); +} + +void Mickey::readDatHdr(char *szFile, MSA_DAT_HEADER *hdr) { + Common::File infile; + + if (!infile.open(szFile)) + return; + + hdr->filelen = infile.readByte(); + hdr->filelen += infile.readByte() * 0x100; + for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) { + hdr->ofsRoom[i] = infile.readByte(); + hdr->ofsRoom[i] += infile.readByte() * 0x100; + } + for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) { + hdr->ofsDesc[i] = infile.readByte(); + hdr->ofsDesc[i] += infile.readByte() * 0x100; + } + for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) { + hdr->ofsStr[i] = infile.readByte(); + hdr->ofsStr[i] += infile.readByte() * 0x100; + } + + infile.close(); +} + +void Mickey::readDesc(int iRoom, char *buffer, long buflen) { + MSA_DAT_HEADER hdr; + char szFile[256] = {0}; + + getDatFileName(iRoom, szFile); + readDatHdr(szFile, &hdr); + + Common::File infile; + + if (!infile.open(szFile)) + return; + + memset(buffer, 0, buflen); + + infile.seek(hdr.ofsDesc[iRoom - 1] + IDI_MSA_OFS_DAT, SEEK_SET); + infile.read(buffer, buflen); + infile.close(); +} + +void Mickey::readMenu(int iRoom, char *buffer) { + MSA_DAT_HEADER hdr; + char szFile[256] = {0}; + + getDatFileName(iRoom, szFile); + readDatHdr(szFile, &hdr); + + Common::File infile; + + if (!infile.open(szFile)) + return; + + infile.seek(hdr.ofsRoom[iRoom - 1] + IDI_MSA_OFS_DAT, SEEK_SET); + infile.read((uint8 *)buffer, sizeof(MSA_MENU)); + infile.close(); +} + +void Mickey::readDatStr(int iDat, int iStr, char *buffer, long buflen) { + MSA_DAT_HEADER hdr; + char szFile[256] = {0}; + + sprintf(szFile, IDS_MSA_PATH_DAT, IDS_MSA_NAME_DAT[iDat]); + readDatHdr(szFile, &hdr); + + Common::File infile; + + if (!infile.open(szFile)) + return; + + infile.seek(hdr.ofsStr[iStr] + IDI_MSA_OFS_DAT, SEEK_SET); + infile.read((uint8 *)buffer, buflen); + infile.close(); +} + +void Mickey::readOfsData(int offset, int iItem, uint8 *buffer, long buflen) { + uint16 ofs[256]; + + readExe(offset, buffer, buflen); + memcpy(ofs, buffer, sizeof(ofs)); + for (int i = 0; i < 256; i++) + ofs[i] = buffer[i*2] + 256 * buffer[i*2+1]; + readExe(ofs[iItem] + IDI_MSA_OFS_EXE, buffer, buflen); +} + +// User Interface + +bool Mickey::chooseY_N(int ofsPrompt, bool fErrorMsg) { + printExeStr(ofsPrompt); + + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + int a = _vm->getSelection(kSelYesNo); + for (;;) { + switch (a) { + case 0: return false; + case 1: return true; + default: if (fErrorMsg) { + printExeStr(IDO_MSA_PRESS_YES_OR_NO); + waitAnyKey(); + printExeStr(ofsPrompt); + } + break; + } + a = _vm->getSelection(kSelYesNo); + } +} + +int Mickey::choose1to9(int ofsPrompt) { + printExeStr(ofsPrompt); + + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + int a = _vm->getSelection(kSelNumber); + for (;;) { + if (a == 10) { + printExeStr(IDO_MSA_PRESS_1_TO_9); + if (!_vm->waitAnyKeyChoice()) + return 0; + printExeStr(ofsPrompt); + } else return a; + a = _vm->getSelection(kSelNumber); + } + +} + +void Mickey::printStr(char *buffer) { + int pc = 1; + int nRows, iCol, iRow; + + nRows = *buffer + IDI_MSA_ROW_MENU_0; + + _vm->clearTextArea(); + + for (iRow = IDI_MSA_ROW_MENU_0; iRow < nRows; iRow++) { + iCol = *(buffer + pc++); + _vm->drawStr(iRow, iCol, IDA_DEFAULT, buffer + pc); + pc += strlen(buffer + pc) + 1; + } +} + +void Mickey::printExeStr(int ofs) { + uint8 buffer[256] = {0}; + + if (!ofs) + return; + + readExe(ofs, buffer, sizeof(buffer)); + printStr((char *)buffer); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop +} + +void Mickey::printExeMsg(int ofs) { + if (!ofs) + return; + printExeStr(ofs); + waitAnyKeyAnim(); +} + +void Mickey::printDatStr(int iDat, int iStr) { + char *buffer = (char *)malloc(256); + readDatStr(iDat, iStr, buffer, 256); + printStr(buffer); + free(buffer); +} + +void Mickey::printDesc(int iRoom) { + char *buffer = (char *)malloc(256); + readDesc(iRoom, buffer, 256); + printStr(buffer); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + free(buffer); +} + +void Mickey::drawMenu(MSA_MENU menu, int sel0, int sel1) { + int iWord; + int iRow; + int sel; + uint8 attr; + + // draw menu + + _vm->clearTextArea(); + + for (iRow = 0; iRow < 2; iRow++) { + for (iWord = 0; iWord < menu.row[iRow].count; iWord++) { + if (iRow) + sel = sel1; + else + sel = sel0; + + if (iWord == sel) + attr = IDA_DEFAULT_REV; + else + attr = IDA_DEFAULT; + + _vm->drawStr(IDI_MSA_ROW_MENU_0 + iRow, menu.row[iRow].entry[iWord].x0, + attr, (char *)menu.row[iRow].entry[iWord].szText); + } + } + + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop +} + +void Mickey::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow, int x, int y) { + int iWord; + int *sel = 0; + + switch(iRow) { + case 0: + if (y != IDI_MSA_ROW_MENU_0) return; + sel = sel0; + break; + case 1: + if (y != IDI_MSA_ROW_MENU_1) return; + sel = sel1; + break; + } + + for (iWord = 0; iWord < menu.row[iRow].count; iWord++) { + if ((x >= menu.row[iRow].entry[iWord].x0) && + (x < (int)(menu.row[iRow].entry[iWord].x0 + + strlen((char *)menu.row[iRow].entry[iWord].szText)))) { + *sel = iWord; + break; + } + } +} + +bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { + Common::Event event; + int *sel = 0; + int nWords; + int x, y; + int goIndex = -1, northIndex = -1, southIndex = -1, eastIndex = -1, westIndex = -1; + + switch(iRow) { + case 0: + sel = sel0; + break; + case 1: + sel = sel1; + break; + } + nWords = menu.row[iRow].count; + clickToMove = false; + + for (int i = 0; i <= menu.row[0].count; i++) + if (menu.row[0].entry[i].szText[0] == 71 && menu.row[0].entry[i].szText[1] == 79) // GO + goIndex = i; + + if (goIndex >= 0) { + for (int j = 0; j <= menu.row[1].count; j++) { + if (menu.row[1].entry[j].szText[0] == 78 && menu.row[1].entry[j].szText[1] == 79 && + menu.row[1].entry[j].szText[2] == 82 && menu.row[1].entry[j].szText[3] == 84 && + menu.row[1].entry[j].szText[4] == 72) + northIndex = j; + if (menu.row[1].entry[j].szText[0] == 83 && menu.row[1].entry[j].szText[1] == 79 && + menu.row[1].entry[j].szText[2] == 85 && menu.row[1].entry[j].szText[3] == 84 && + menu.row[1].entry[j].szText[4] == 72) + southIndex = j; + if (menu.row[1].entry[j].szText[0] == 69 && menu.row[1].entry[j].szText[1] == 65 && + menu.row[1].entry[j].szText[2] == 83 && menu.row[1].entry[j].szText[3] == 84) + eastIndex = j; + if (menu.row[1].entry[j].szText[0] == 87 && menu.row[1].entry[j].szText[1] == 69 && + menu.row[1].entry[j].szText[2] == 83 && menu.row[1].entry[j].szText[3] == 84) + westIndex = j; + } + } + + drawMenu(menu, *sel0, *sel1); + + for (;;) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + exit(0); + case Common::EVENT_MOUSEMOVE: + if (iRow < 2) { + x = event.mouse.x / 8; + y = event.mouse.y / 8; + // If the mouse hovers over the menu, refresh the menu + if ((iRow == 0 && y == IDI_MSA_ROW_MENU_0) || (iRow == 1 && y == IDI_MSA_ROW_MENU_1)) { + getMouseMenuSelRow(menu, sel0, sel1, iRow, x, y); + drawMenu(menu, *sel0, *sel1); + } + + // Change cursor + if (northIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= 0 && event.mouse.y <= 10)) { + _vm->_gfx->setCursorPalette(true); + } else if (southIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) { + _vm->_gfx->setCursorPalette(true); + } else if (westIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && + (event.mouse.x >= 20 && event.mouse.x <= 30)) { + _vm->_gfx->setCursorPalette(true); + } else if (eastIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && + (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) { + _vm->_gfx->setCursorPalette(true); + } else { + _vm->_gfx->setCursorPalette(false); + } + } + break; + case Common::EVENT_LBUTTONUP: + // Click to move + if (northIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= 0 && event.mouse.y <= 10)) { + *sel0 = goIndex; *sel1 = northIndex; + drawMenu(menu, *sel0, *sel1); + _vm->_gfx->setCursorPalette(false); + clickToMove = true; + } else if (southIndex >= 0 && (event.mouse.x >= 20 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= IDI_MSA_PIC_HEIGHT - 10 && event.mouse.y <= IDI_MSA_PIC_HEIGHT)) { + *sel0 = goIndex; *sel1 = southIndex; + drawMenu(menu, *sel0, *sel1); + _vm->_gfx->setCursorPalette(false); + clickToMove = true; + } else if (westIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && + (event.mouse.x >= 20 && event.mouse.x <= 30)) { + *sel0 = goIndex; *sel1 = westIndex; + drawMenu(menu, *sel0, *sel1); + _vm->_gfx->setCursorPalette(false); + clickToMove = true; + } else if (eastIndex >= 0 && (event.mouse.y >= 0 && event.mouse.y <= IDI_MSA_PIC_HEIGHT) && + (event.mouse.x >= IDI_MSA_PIC_WIDTH * 2 && event.mouse.x <= (IDI_MSA_PIC_WIDTH + 10) * 2)) { + *sel0 = goIndex; *sel1 = eastIndex; + drawMenu(menu, *sel0, *sel1); + _vm->_gfx->setCursorPalette(false); + clickToMove = true; + } else { + _vm->_gfx->setCursorPalette(false); + } + return true; + case Common::EVENT_RBUTTONUP: + *sel0 = 0; *sel1 = -1; + return false; + case Common::EVENT_WHEELUP: + if (iRow < 2) { + *sel -= 1; + if (*sel < 0) *sel = nWords - 1; + drawMenu(menu, *sel0, *sel1); + } + break; + case Common::EVENT_WHEELDOWN: + if (iRow < 2) { + *sel += 1; + if (*sel == nWords) *sel = 0; + drawMenu(menu, *sel0, *sel1); + } + break; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_2: + hidden(); + break; + case Common::KEYCODE_8: + if (event.kbd.flags & Common::KBD_CTRL) { + *sel0 = 0; *sel1 = -1; return false; + } + break; + case Common::KEYCODE_ESCAPE: + *sel0 = 0; *sel1 = -1; return false; + case Common::KEYCODE_s: + _vm->flipflag(fSoundOn); + break; + case Common::KEYCODE_c: + inventory(); + drawRoom(); + *sel0 = 0; *sel1 = -1; return false; + case Common::KEYCODE_b: + printRoomDesc(); + drawMenu(menu, *sel0, *sel1); + *sel0 = 0; *sel1 = -1; return false; + case Common::KEYCODE_LEFT: + case Common::KEYCODE_KP4: + case Common::KEYCODE_4: + if (iRow < 2) { + *sel -= 1; + if (*sel < 0) *sel = nWords - 1; + drawMenu(menu, *sel0, *sel1); + } + break; + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_SPACE: + case Common::KEYCODE_KP6: + case Common::KEYCODE_6: + if (iRow < 2) { + *sel += 1; + if (*sel == nWords) *sel = 0; + drawMenu(menu, *sel0, *sel1); + } + break; + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + return true; + default: + break; + } + break; + default: + break; + } + animate(); + drawMenu(menu, *sel0, *sel1); + } + animate(); + drawMenu(menu, *sel0, *sel1); + } +} + +void Mickey::getMenuSel(char *buffer, int *sel0, int *sel1) { + MSA_MENU menu; + + memcpy(&menu, buffer, sizeof(MSA_MENU)); + + *sel0 = 0; + *sel1 = -1; + + // Show the mouse cursor for the menu + CursorMan.showMouse(true); + + for (;;) { + for (;;) { + if (getMenuSelRow(menu, sel0, sel1, 0)) { + if (clickToMove) + break; + *sel1 = 0; + if (getMenuSelRow(menu, sel0, sel1, 1)) { + break; + } + } + } + if (clickToMove || getMenuSelRow(menu, sel0, sel1, 2)) { + break; + } + } + + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); +} + +void Mickey::centerMenu(MSA_MENU *menu) { + int iWord; + int iRow; + int w, x; + + for (iRow = 0; iRow < 2; iRow++) { + w = 0; + for (iWord = 0; iWord < menu->row[iRow].count; iWord++) { + w += strlen((char *)menu->row[iRow].entry[iWord].szText); + } + w += menu->row[iRow].count - 1; + x = (40 - w) / 2; // FIX + for (iWord = 0; iWord < menu->row[iRow].count; iWord++) { + menu->row[iRow].entry[iWord].x0 = x; + x += strlen((char *)menu->row[iRow].entry[iWord].szText) + 1; + } + } +} + +void Mickey::patchMenu(MSA_MENU *menu) { + uint8 buffer[512]; + uint8 menubuf[sizeof(MSA_MENU)]; + int nPatches; + int pBuf = 0; + + // change planet name in ship airlock menu + if (game.iRoom == IDI_MSA_PIC_SHIP_AIRLOCK) { + strcpy((char *)menu->row[1].entry[2].szText, IDS_MSA_NAME_PLANET[game.iPlanet]); + } + + // exit if fix unnecessary + if (!game.iRmMenu[game.iRoom]) { + centerMenu(menu); + return; + } + + // copy menu to menubuf + memcpy(menubuf, menu, sizeof(menubuf)); + + // read patches + readOfsData( + IDOFS_MSA_MENU_PATCHES, + game.nRmMenu[game.iRoom] + game.iRmMenu[game.iRoom] - 1, + buffer, sizeof(buffer) + ); + + // get number of patches + nPatches = buffer[pBuf++]; + + // patch menubuf + for (int iPatch = 0; iPatch < nPatches; iPatch++) { + if (buffer[pBuf] > sizeof(menubuf)) { + // patch address out of bounds + } + menubuf[buffer[pBuf]] = buffer[pBuf + 1]; + pBuf += 2; + } + + // copy menubuf back to menu + memcpy(menu, menubuf, sizeof(MSA_MENU)); + + // center menu + centerMenu(menu); +} + +void Mickey::printDatString(int iStr) { + printDatStr(getDat(game.iRoom), iStr); +} + +void Mickey::printDatMessage(int iStr) { + printDatString(iStr); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKeyAnim(); +} + +// Sound + +void Mickey::playNote(MSA_SND_NOTE note) { + // TODO + if (!note.counter) { + //_vm->_sound->playNote(1, 0, 160); // ScummVM + //playNote(1, 0, note.length / IDI_SND_TIMER_RESOLUTION); // TrollVM + } else { + //_vm->_sound->playNote(1, IDI_SND_OSCILLATOR_FREQUENCY / note.counter, 160); // ScummVM + //playNote(1, IDI_SND_OSCILLATOR_FREQUENCY / note.counter, + // note.length / IDI_SND_TIMER_RESOLUTION / IDI_SND_PITCH); // TrollVM + } +} + +void Mickey::playSound(ENUM_MSA_SOUND iSound) { + if (!_vm->getflag(fSoundOn)) + return; + + Common::Event event; + MSA_SND_NOTE note; + uint8 *buffer = new uint8[1024]; + int pBuf = 1; + + switch(iSound) { + case IDI_MSA_SND_XL30: + for (int iNote = 0; iNote < 6; iNote++) { + note.counter = _vm->rnd(59600) + 59; + note.length = 4; + playNote(note); + } + break; + default: + readOfsData(IDOFS_MSA_SOUND_DATA, iSound, buffer, 1024); + + for (;;) { + memcpy(¬e, buffer + pBuf, sizeof(note)); + if (!note.counter && !note.length) + break; + + playNote(note); + + pBuf += 3; + + if (iSound == IDI_MSA_SND_THEME) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _vm->_system->quit(); + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_KEYDOWN: + delete [] buffer; + return; + default: + break; + } + } + } + } + + break; + } + + delete [] buffer; +} + +void Mickey::debug() { + char szLine[41] = {0}; + + _vm->clearScreen(IDA_DEFAULT); + + sprintf(szLine, IDS_MSA_DEBUG_ROOM, game.iRoom); + _vm->drawStr(5, 10, IDA_DEFAULT, szLine); + + if (game.iRoom < IDI_MSA_MAX_PIC_ROOM) { + if (game.iRmObj[game.iRoom] != IDI_MSA_OBJECT_NONE) { + sprintf(szLine, IDS_MSA_DEBUG_OBJ, game.iRmObj[game.iRoom]); + _vm->drawStr(7, 10, IDA_DEFAULT, szLine); + } + } else { + sprintf(szLine, IDS_MSA_DEBUG_OBJ, 32); + _vm->drawStr(7, 10, IDA_DEFAULT, szLine); + } + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop +} + +// Graphics + +void Mickey::drawObj(ENUM_MSA_OBJECT iObj, int x0, int y0) { + uint8* buffer = new uint8[4096]; + char szFile[255] = {0}; + sprintf(szFile, IDS_MSA_PATH_OBJ, IDS_MSA_NAME_OBJ[iObj]); + + Common::File file; + if (!file.open(szFile)) + return; + uint32 size = file.size(); + file.read(buffer, size); + file.close(); + + if (iObj == IDI_MSA_OBJECT_CRYSTAL) + _vm->_picture->setPictureFlags(kPicFStep); + + _vm->_picture->setOffset(x0, y0); + _vm->_picture->decodePicture(buffer, size, false, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _vm->_picture->setOffset(0, 0); + _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); +} + +void Mickey::drawPic(int iPic) { + uint8* buffer = new uint8[4096]; + char szFile[255] = {0}; + sprintf(szFile, IDS_MSA_PATH_PIC, iPic); + + Common::File file; + if (!file.open(szFile)) + return; + uint32 size = file.size(); + file.read(buffer, size); + file.close(); + + // Note that decodePicture clears the screen + _vm->_picture->decodePicture(buffer, size, true, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop +} + +void Mickey::drawRoomPicture() { + if (false) { // (getDebug()) { // TODO + drawPic(0); + debug(); + } else { + if (game.iRoom == IDI_MSA_PIC_TITLE) { + drawPic(IDI_MSA_PIC_TITLE); + } else { + drawPic(game.iRmPic[game.iRoom]); + } + } +} + +void Mickey::drawRoomObjects() { + if (game.iRoom >= IDI_MSA_MAX_PIC_ROOM) + return; + + uint8 buffer[256]; + int pBuf = 0; + int nObjs; + + // draw ship control room window + + if (game.iRoom == IDI_MSA_PIC_SHIP_CONTROLS) { + if (game.fFlying) { + drawObj(IDI_MSA_OBJECT_W_SPACE, 0, 0); + } else { + drawObj((ENUM_MSA_OBJECT)(IDI_MSA_OBJECT_W_EARTH + game.iPlanet), 0, 1); + } + } + + // draw objects + + if (game.iRmObj[game.iRoom] != IDI_MSA_OBJECT_NONE) { + readOfsData(IDO_MSA_ROOM_OBJECT_XY_OFFSETS, + game.iRmObj[game.iRoom], buffer, sizeof(buffer)); + + nObjs = buffer[pBuf++]; + + for (int iObj = 0; iObj < nObjs; iObj++) { + drawObj((ENUM_MSA_OBJECT)buffer[pBuf], buffer[pBuf + 1], buffer[pBuf + 2]); + pBuf += 3; + } + } +} + +void Mickey::drawRoomAnimation() { + uint8 objLight[] = { + 0xF0, 1, 0xF9, 2, 43, 45, 0xFF + }; + + switch(game.iRoom) { + case IDI_MSA_PIC_EARTH_SHIP: + case IDI_MSA_PIC_VENUS_SHIP: + case IDI_MSA_PIC_NEPTUNE_SHIP: + case IDI_MSA_PIC_MERCURY_SHIP: + case IDI_MSA_PIC_SATURN_SHIP: + case IDI_MSA_PIC_PLUTO_SHIP: + case IDI_MSA_PIC_JUPITER_SHIP: + case IDI_MSA_PIC_MARS_SHIP: + case IDI_MSA_PIC_URANUS_SHIP: + case IDI_MSA_PIC_SHIP_VENUS: + case IDI_MSA_PIC_SHIP_NEPTUNE: + case IDI_MSA_PIC_SHIP_MERCURY: + case IDI_MSA_PIC_SHIP_SATURN: + case IDI_MSA_PIC_SHIP_PLUTO: + case IDI_MSA_PIC_SHIP_JUPITER: + case IDI_MSA_PIC_SHIP_MARS: + case IDI_MSA_PIC_SHIP_URANUS: + { + // draw blinking ship lights + + uint8 iColor = 0; + + _vm->_picture->setPattern(2, 0); + + for (int i = 0; i < 12; i++) { + iColor = game.nFrame + i; + if (iColor > 15) iColor -= 15; + + objLight[1] = iColor; + objLight[4] += 7; + + _vm->_picture->setPictureData(objLight, ARRAYSIZE(objLight)); + _vm->_picture->setPictureFlags(kPicFCircle); + _vm->_picture->drawPicture(); + } + _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + + + game.nFrame--; + if (game.nFrame < 0) game.nFrame = 15; + + playSound(IDI_MSA_SND_PRESS_BLUE); + } + break; + + case IDI_MSA_PIC_SHIP_CONTROLS: + + // draw XL30 screen + + if (game.fAnimXL30) { + if (game.nFrame > 5) game.nFrame = 0; + drawObj((ENUM_MSA_OBJECT)(IDI_MSA_OBJECT_XL31 + game.nFrame), 0, 4); + game.nFrame++; + }; + + break; + + default: + + // draw crystal + + if (game.iRoom == IDI_MSA_XTAL_ROOM_XY[game.iPlanet][0]) { + if (!game.fHasXtal) { + switch(game.iPlanet) { + case IDI_MSA_PLANET_VENUS: + if (game.iRmMenu[game.iRoom] != 2) break; + default: + drawObj( + IDI_MSA_OBJECT_CRYSTAL, + IDI_MSA_XTAL_ROOM_XY[game.iPlanet][1], + IDI_MSA_XTAL_ROOM_XY[game.iPlanet][2] + ); + break; + } + } + } + + break; + } +} + +void Mickey::drawRoom() { + drawRoomPicture(); + drawRoomObjects(); + drawRoomAnimation(); +} + +const uint8 colorBCG[16][2] = { + { 0x00, 0x00 }, // 0 (black, black) + { 0, 0 }, + { 0x00, 0x0D }, // 2 (black, purple) + { 0x00, 0xFF }, // 3 (black, white) + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x0D, 0x00 }, // 8 (purple, black) + { 0, 0 }, + { 0x0D, 0x0D }, // A (purple, purple) + { 0, 0 }, + { 0xFF, 0x00 }, // C (white, black) + { 0, 0 }, + { 0, 0 }, + { 0xFF, 0xFF } // F (white, white) +}; + +void Mickey::drawLogo() { + char szFile[256] = {0}; + uint8 *buffer = new uint8[16384]; + const int w = 80; + const int h = 170; + uint8 bitmap[h][w]; + + // read in logos.bcg + sprintf(szFile, IDS_MSA_PATH_LOGO); + Common::File infile; + if (!infile.open(szFile)) + return; + infile.read(buffer, infile.size()); + infile.close(); + + // draw logo bitmap + memcpy(bitmap, buffer, sizeof(bitmap)); + + /* + // TODO: Show BCG picture + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + uint8 color = colorBCG[(bitmap[y][x] & 0xf0) / 0x10][0]; // background + uint8 color2 = colorBCG[(bitmap[y][x] & 0xf0) / 0x10][1]; // background + uint8 color3 = colorBCG[ bitmap[y][x] & 0x0f][0]; // foreground + uint8 color4 = colorBCG[ bitmap[y][x] & 0x0f][1]; // foreground + + _vm->_picture->putPixel(x * 4, y, color); + _vm->_picture->putPixel(x * 4 + 1, y, color2); + _vm->_picture->putPixel(x * 4 + 2, y, color3); + _vm->_picture->putPixel(x * 4 + 3, y, color4); + _vm->_picture->putPixel(x * 4, y + 1, color); + _vm->_picture->putPixel(x * 4 + 1, y + 1, color2); + _vm->_picture->putPixel(x * 4 + 2, y + 1, color3); + _vm->_picture->putPixel(x * 4 + 3, y + 1, color4); + } + } + + _vm->_picture->showPic(10, 0, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT); + */ + + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + delete [] buffer; +} + +void Mickey::animate() { + _vm->_system->delayMillis(IDI_MSA_ANIM_DELAY); + drawRoomAnimation(); +} + +void Mickey::printRoomDesc() { + // print room description + + printDesc(game.iRoom); + waitAnyKeyAnim(); + + // print extended room description + + if (game.fRmTxt[game.iRoom]) { + printExeMsg(game.oRmTxt[game.iRoom] + IDI_MSA_OFS_EXE); + } +} + +bool Mickey::loadGame() { + Common::InSaveFile *infile; + char szFile[256] = {0}; + bool diskerror = true; + int sel; + + while (diskerror) { + sel = choose1to9(IDO_MSA_LOAD_GAME[1]); + if (!sel) + return false; + + // load game + sprintf(szFile, "%s.s%2d", _vm->getTargetName().c_str(), sel); + if (!(infile = _vm->getSaveFileMan()->openForLoading(szFile))) { + printExeStr(IDO_MSA_CHECK_DISK_DRIVE); + if (!_vm->waitAnyKeyChoice()) + return false; + } else { + infile->read(&game, sizeof(MSA_GAME)); + diskerror = false; + delete infile; + } + } + + printExeMsg(IDO_MSA_LOAD_GAME[2]); + return true; +} + +void Mickey::saveGame() { + Common::OutSaveFile* outfile; + char szFile[256] = {0}; + bool diskerror = true; + int sel; + + bool fOldDisk = chooseY_N(IDO_MSA_SAVE_GAME[0], false); + + if (fOldDisk) + printExeStr(IDO_MSA_SAVE_GAME[1]); + else + printExeStr(IDO_MSA_SAVE_GAME[2]); + + if (!_vm->waitAnyKeyChoice()) + return; + + while (diskerror) { + sel = choose1to9(IDO_MSA_SAVE_GAME[3]); + if (!sel) + return; + + if (fOldDisk) + printExeStr(IDO_MSA_SAVE_GAME[5]); + else + printExeStr(IDO_MSA_SAVE_GAME[4]); + + if (!_vm->waitAnyKeyChoice()) + return; + + // save game + sprintf(szFile, "%s.s%2d", _vm->getTargetName().c_str(), sel); + if (!(outfile = _vm->getSaveFileMan()->openForSaving(szFile))) { + printExeStr(IDO_MSA_CHECK_DISK_DRIVE); + if (!_vm->waitAnyKeyChoice()) + return; + } else { + outfile->write(&game, sizeof(MSA_GAME)); + diskerror = false; + delete outfile; + } + } + + printExeMsg(IDO_MSA_SAVE_GAME[6]); +} + +void Mickey::showPlanetInfo() { + for (int i = 0; i < IDI_MSA_MAX_PLANET_INFO; i++) { + printExeStr(IDO_MSA_PLANET_INFO[game.iPlanet][i]); + waitAnyKey(); + } +} + +void Mickey::printStory() { + char buffer[IDI_MSA_LEN_STORY] = {0}; + char szLine[41] = {0}; + int iRow; + int pBuf = 0; + + readExe(IDO_MSA_GAME_STORY, (uint8 *)buffer, sizeof(buffer)); + + _vm->clearScreen(IDA_DEFAULT); + for (iRow = 0; iRow < 25; iRow++) { + strcpy(szLine, buffer + pBuf); + _vm->drawStr(iRow, 0, IDA_DEFAULT, szLine); + pBuf += strlen(szLine) + 1; + } + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + + _vm->clearScreen(IDA_DEFAULT); + for (iRow = 0; iRow < 21; iRow++) { + strcpy(szLine, buffer + pBuf); + _vm->drawStr(iRow, 0, IDA_DEFAULT, szLine); + pBuf += strlen(szLine) + 1; + } + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + + //Set back to black + _vm->_gfx->clearScreen(0); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + drawRoom(); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + game.fStoryShown = true; +} + +void Mickey::hidden() { + if (game.iRoom == IDI_MSA_PIC_MERCURY_CAVE_0) { + for (int i = 0; i < 5; i++) { + printExeMsg(IDO_MSA_HIDDEN_MSG[i]); + } + _vm->clearTextArea(); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + } +} + +int Mickey::getPlanet() { + if (!game.nButtons) + return -1; + + for (int iPlanet = 0; iPlanet < IDI_MSA_MAX_DAT; iPlanet++) { + if (!strcmp(IDS_MSA_ADDR_PLANET[iPlanet], game.szAddr)) { + return iPlanet; + } + } + + return -1; +} + +void Mickey::pressOB(int iButton) { + char szButtons[12] = {0}; + + // check if too many buttons pressed + if (game.nButtons == IDI_MSA_MAX_BUTTON) { + game.nButtons = 0; + memset(game.szAddr, 0, sizeof(game.szAddr)); + printExeMsg(IDO_MSA_TOO_MANY_BUTTONS_PRESSED); + return; + } + + // add button press to address + game.nButtons++; + game.szAddr[game.nButtons - 1] = (char)iButton; + + // format buttons string + for (int i = 0; i < IDI_MSA_MAX_BUTTON; i++) { + szButtons[i * 2] = game.szAddr[i]; + if (game.szAddr[i + 1]) szButtons[(i * 2) + 1] = ','; + } + + // print pressed buttons + printExeStr(IDO_MSA_MICKEY_HAS_PRESSED); + _vm->drawStr(IDI_MSA_ROW_BUTTONS, IDI_MSA_COL_BUTTONS, IDA_DEFAULT, szButtons); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); +} + +void Mickey::checkAirSupply(bool fSuit, int *iSupply) { + if (fSuit) { + *iSupply -= 1; + for (int i = 0; i < 4; i++) { + if (*iSupply == IDI_MSA_AIR_SUPPLY[i]) { + playSound(IDI_MSA_SND_XL30); + printExeMsg(IDO_MSA_XL30_SPEAKING); + printExeMsg(IDO_MSA_AIR_SUPPLY[i]); + if (i == 3) { + exit(0); + } + } + } + } else { + *iSupply = IDI_MSA_MAX_AIR_SUPPLY; + } +} + +void Mickey::insertDisk(int iDisk) { + _vm->clearTextArea(); + _vm->drawStr(IDI_MSA_ROW_INSERT_DISK, IDI_MSA_COL_INSERT_DISK, IDA_DEFAULT, (const char *)IDS_MSA_INSERT_DISK[iDisk]); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); +} + +void Mickey::gameOver() { + drawPic(IDI_MSA_PIC_EARTH_SHIP_LEAVING); + printExeMsg(IDO_MSA_GAME_OVER[3]); + playSound(IDI_MSA_SND_GAME_OVER); + + if (game.fItemUsed[IDI_MSA_ITEM_LETTER]) { + drawPic(IDI_MSA_PIC_EARTH_MINNIE); + printExeMsg(IDO_MSA_GAME_OVER[4]); + printExeMsg(IDO_MSA_GAME_OVER[5]); + } else { + printExeMsg(IDO_MSA_GAME_OVER[6]); + printExeMsg(IDO_MSA_GAME_OVER[7]); + } + + waitAnyKey(); + exit(0); +} + +void Mickey::flipSwitch() { + if (game.fHasXtal || game.nXtals) { + if (!game.fStoryShown) { + printStory(); + randomize(); + } + + // activate screen animation + game.fAnimXL30 = true; + + _vm->clearTextArea(); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + playSound(IDI_MSA_SND_XL30); + printExeMsg(IDO_MSA_XL30_SPEAKING); + + if (game.fHasXtal) { + game.fHasXtal = false; + printExeMsg(IDO_MSA_CRYSTAL_PIECE_FOUND); + } + + if (game.nXtals == IDI_MSA_MAX_PLANET) { + printExeMsg(IDO_MSA_GAME_OVER[0]); + printExeMsg(IDO_MSA_GAME_OVER[1]); + printExeMsg(IDO_MSA_GAME_OVER[2]); + +#if 0 + // DEBUG + strcpy(game.szAddr, (char *)IDS_MSA_ADDR_PLANET[IDI_MSA_PLANET_EARTH]); + game.nButtons = strlen(game.szAddr); +#endif + + } else { + printExeStr(game.iClue[game.nXtals]); + +#if 0 + // DEBUG + _vm->drawStr(24, 12, IDA_DEFAULT, (char *)IDS_MSA_NAME_PLANET_2[game.iPlanetXtal[game.nXtals]]); + _vm->drawStr(24, 22, IDA_DEFAULT, (char *)IDS_MSA_ADDR_PLANET[game.iPlanetXtal[game.nXtals]]); + strcpy(game.szAddr, (char *)IDS_MSA_ADDR_PLANET[game.iPlanetXtal[game.nXtals]]); + game.nButtons = strlen(game.szAddr); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop +#endif + + waitAnyKeyAnim(); + } + } else { + printStory(); + } +} + +void Mickey::inventory() { + int iRow = IDI_MSA_ROW_INV_ITEMS; + char szCrystals[12] = {0}; + + sprintf(szCrystals, IDS_MSA_CRYSTALS, IDS_MSA_CRYSTAL_NO[game.nXtals]); + + CursorMan.showMouse(false); + + _vm->clearScreen(IDA_DEFAULT); + _vm->drawStr(IDI_MSA_ROW_INV_TITLE, IDI_MSA_COL_INV_TITLE, IDA_DEFAULT, IDS_MSA_INVENTORY); + _vm->drawStr(IDI_MSA_ROW_INV_CRYSTALS, IDI_MSA_COL_INV_ITEMS, IDA_DEFAULT, szCrystals); + + for (int iItem = 0; iItem < IDI_MSA_MAX_ITEM; iItem++) { + if (game.fItem[game.iItem[iItem]] && (game.iItem[iItem] != IDI_MSA_OBJECT_NONE)) { + _vm->drawStr(iRow++, IDI_MSA_COL_INV_ITEMS, IDA_DEFAULT, (const char *)IDS_MSA_NAME_ITEM[game.iItem[iItem]]); + } + } + + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + + _vm->clearScreen(IDA_DEFAULT); + + CursorMan.showMouse(true); +} + +void Mickey::randomize() { + int iPlanet = 0; + int iHint = 0; + bool done; + + memset(game.iPlanetXtal, 0, sizeof(game.iPlanetXtal)); + memset(game.iClue, 0, sizeof(game.iClue)); + + game.iPlanetXtal[0] = IDI_MSA_PLANET_EARTH; + game.iPlanetXtal[8] = IDI_MSA_PLANET_URANUS; + + for (int i = 1; i < 9; i++) { + if (i == 8) { + iPlanet = IDI_MSA_PLANET_URANUS; + } else { + done = false; + while (!done) { + iPlanet = _vm->rnd(IDI_MSA_MAX_PLANET); + done = true; + for (int j = 0; j < IDI_MSA_MAX_PLANET; j++) { + if (game.iPlanetXtal[j] == iPlanet) { + done = false; + break; + } + } + } + } + + game.iPlanetXtal[i] = iPlanet; + + done = false; + while (!done) { + iHint = _vm->rnd(5); + done = true; + } + + game.iClue[i] = IDO_MSA_NEXT_PIECE[iPlanet][iHint]; + } +} + +void Mickey::flashScreen() { + playSound(IDI_MSA_SND_PRESS_BLUE); + + //Set screen to white + _vm->_gfx->clearScreen(15); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + _vm->_system->delayMillis(IDI_MSA_ANIM_DELAY); + + //Set back to black + _vm->_gfx->clearScreen(0); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + drawRoom(); + printDesc(game.iRoom); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop +} + +void Mickey::intro() { + // draw sierra logo + drawLogo(); + //waitAnyKey(); // Not in the original, but needed so that the logo is visible + + // draw title picture + game.iRoom = IDI_MSA_PIC_TITLE; + drawRoom(); + + // show copyright and play theme + printExeMsg(IDO_MSA_COPYRIGHT); + playSound(IDI_MSA_SND_THEME); + + // load game + game.fIntro = true; + if (chooseY_N(IDO_MSA_LOAD_GAME[0], true)) { + if (loadGame()) { + game.iPlanet = IDI_MSA_PLANET_EARTH; + game.fIntro = false; + game.iRoom = IDI_MSA_PIC_SHIP_CORRIDOR; + return; + } + } + + // play spaceship landing scene + game.iPlanet = IDI_MSA_PLANET_EARTH; + game.iRoom = IDI_MSA_PIC_EARTH_ROAD_4; + + drawRoom(); + printRoomDesc(); + + playSound(IDI_MSA_SND_SHIP_LAND); + + flashScreen(); + flashScreen(); + flashScreen(); + + printExeMsg(IDO_MSA_INTRO); +} + +void Mickey::getItem(ENUM_MSA_ITEM iItem) { + game.fItem[iItem] = true; + game.iItem[game.nItems++] = iItem; + game.fRmTxt[game.iRoom] = 0; + playSound(IDI_MSA_SND_TAKE); + drawRoom(); +} + +void Mickey::getXtal(int iStr) { + game.fRmTxt[game.iRoom] = 0; + game.fHasXtal = true; + game.nXtals++; + playSound(IDI_MSA_SND_CRYSTAL); + drawRoom(); + printDatMessage(iStr); +} + +bool Mickey::parse(int cmd, int arg) { + switch(cmd) { + + // BASIC + + case IDI_MSA_ACTION_GOTO_ROOM: + game.iRoom = arg; + return true; + case IDI_MSA_ACTION_SHOW_INT_STR: + printExeMsg(IDO_MSA_ERROR[arg]); + break; + case IDI_MSA_ACTION_SHOW_DAT_STR: + printDatMessage(arg); + break; + + // GENERAL + + case IDI_MSA_ACTION_PLANET_INFO: + showPlanetInfo(); + break; + case IDI_MSA_ACTION_SAVE_GAME: + saveGame(); + break; + case IDI_MSA_ACTION_LOOK_MICKEY: + printExeMsg(IDO_MSA_YOU_CAN_SEE_MICKEY_ALREADY); + break; + + // EARTH + + case IDI_MSA_ACTION_GET_ROPE: + if (game.iRmMenu[game.iRoom] == 2) { + game.iRmObj[game.iRoom] = IDI_MSA_OBJECT_NONE; + game.iRmMenu[game.iRoom] = 3; + getItem(IDI_MSA_ITEM_ROPE); + printExeMsg(IDO_MSA_ERROR[7]); + } else { + game.iRmMenu[game.iRoom] = 1; + printDatMessage(11); + } + break; + case IDI_MSA_ACTION_UNTIE_ROPE: + game.iRmPic[game.iRoom] = IDI_MSA_PIC_EARTH_TIRE_SWING_1; + game.iRmObj[game.iRoom] = 0; + game.iRmMenu[game.iRoom] = 2; + drawRoom(); + printDatMessage(12); + break; + case IDI_MSA_ACTION_GET_BONE: + game.iRmObj[game.iRoom] = IDI_MSA_OBJECT_NONE; + game.iRmMenu[game.iRoom] = 1; + getItem(IDI_MSA_ITEM_BONE); + printDatMessage(arg); + break; + case IDI_MSA_ACTION_GET_XTAL_EARTH: + game.iRmMenu[game.iRoom] = 1; + getXtal(arg); + break; + case IDI_MSA_ACTION_LOOK_DESK: + game.iRmMenu[game.iRoom] = 1; + game.iRmObj[game.iRoom] = 2; + drawRoom(); + printDatMessage(arg); + break; + case IDI_MSA_ACTION_WRITE_LETTER: + game.iRmMenu[game.iRoom] = 3; + game.iRmMenu[IDI_MSA_PIC_EARTH_MAILBOX] = 1; + game.iRmObj[game.iRoom] = IDI_MSA_OBJECT_NONE; + getItem(IDI_MSA_ITEM_LETTER); + printDatMessage(arg); + break; + case IDI_MSA_ACTION_MAIL_LETTER: + game.fItemUsed[IDI_MSA_ITEM_LETTER] = true; + game.fItem[IDI_MSA_ITEM_LETTER] = false; + game.iRmMenu[game.iRoom] = 0; + printDatMessage(arg); + break; + case IDI_MSA_ACTION_OPEN_MAILBOX: + if (game.fItemUsed[IDI_MSA_ITEM_LETTER]) { + printDatMessage(110); + } else { + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_OPEN_CUPBOARD: + if (game.iRmMenu[game.iRoom]) { + if (game.iRmObj[game.iRoom] == IDI_MSA_OBJECT_NONE) { + printDatMessage(78); + } else { + printDatMessage(arg); + } + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_EARTH_KITCHEN_1; + game.iRmObj[game.iRoom] = 3; + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_FLASHLIGHT: + if (game.fItem[IDI_MSA_ITEM_FLASHLIGHT]) { + printDatMessage(90); + } else { + game.iRmObj[game.iRoom] = IDI_MSA_OBJECT_NONE; + getItem(IDI_MSA_ITEM_FLASHLIGHT); + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_OPEN_CABINET: + if (game.iRmMenu[game.iRoom]) { + printDatMessage(109); + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_EARTH_GARAGE_1; + game.iRmObj[game.iRoom] = 15; + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_CROWBAR: + if (game.fItem[IDI_MSA_ITEM_CROWBAR]) { + printDatMessage(90); + } else { + game.iRmObj[game.iRoom]--; + getItem(IDI_MSA_ITEM_CROWBAR); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_WRENCH: + if (game.fItem[IDI_MSA_ITEM_WRENCH]) { + printDatMessage(90); + } else { + game.iRmObj[game.iRoom] -= 2; + getItem(IDI_MSA_ITEM_WRENCH); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_OPEN_CLOSET: + if (game.iRmMenu[game.iRoom]) { + printDatMessage(99); + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_EARTH_BEDROOM_1; + game.iRmObj[game.iRoom] = 7; + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_MATTRESS: + if (game.fItem[IDI_MSA_ITEM_MATTRESS]) { + printDatMessage(90); + } else { + game.iRmObj[game.iRoom]--; + getItem(IDI_MSA_ITEM_MATTRESS); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_SCARF: + if (game.fItem[IDI_MSA_ITEM_SCARF]) { + printDatMessage(90); + } else { + game.iRmObj[game.iRoom] -= 2; + getItem(IDI_MSA_ITEM_SCARF); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_SUNGLASSES: + if (game.fItem[IDI_MSA_ITEM_SUNGLASSES]) { + printDatMessage(90); + } else { + game.iRmObj[game.iRoom]--; + getItem(IDI_MSA_ITEM_SUNGLASSES); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_SCALE: + if (game.fItem[IDI_MSA_ITEM_SCALE]) { + printDatMessage(90); + } else { + game.iRmMenu[IDI_MSA_PIC_VENUS_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_NEPTUNE_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_MERCURY_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_SATURN_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_PLUTO_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_JUPITER_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_MARS_WEIGH] = 1; + game.iRmMenu[IDI_MSA_PIC_URANUS_WEIGH] = 1; + game.iRmObj[game.iRoom] -= 2; + getItem(IDI_MSA_ITEM_SCALE); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GOTO_SPACESHIP: + game.iRoom = IDI_MSA_PIC_SHIP_AIRLOCK; + if (game.iPlanet != IDI_MSA_PLANET_EARTH) + insertDisk(0); + return true; + + // VENUS + + case IDI_MSA_ACTION_DOWN_CHASM: + if (game.fItem[IDI_MSA_ITEM_ROPE]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + break; + case IDI_MSA_ACTION_DOWN_ROPE: + if (game.fItemUsed[IDI_MSA_ITEM_ROPE]) { + game.iRoom = IDI_MSA_PIC_VENUS_PROBE; + return true; + } else { + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_USE_ROPE: + if (game.fItemUsed[IDI_MSA_ITEM_ROPE]) { + printDatMessage(22); + } else { + game.fItemUsed[IDI_MSA_ITEM_ROPE] = true; + game.fItem[IDI_MSA_ITEM_ROPE] = false; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_VENUS_CHASM_1; + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_OPEN_HATCH: + if (game.fItemUsed[IDI_MSA_ITEM_WRENCH]) { + if ((game.iRmMenu[game.iRoom] == 3) || (game.iRmPic[game.iRoom] == IDI_MSA_PIC_VENUS_PROBE_1)) + printDatMessage(39); + else { + game.iRmMenu[game.iRoom] = 2; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_VENUS_PROBE_1; + drawRoom(); + printDatMessage(24); + } + } else { + if (game.fItem[IDI_MSA_ITEM_WRENCH]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_USE_WRENCH: + game.fItemUsed[IDI_MSA_ITEM_WRENCH] = true; + printDatString(arg); + if (game.iRmPic[game.iRoom] == IDI_MSA_PIC_VENUS_PROBE_1) { + _vm->clearRow(22); + } + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + break; + case IDI_MSA_ACTION_GET_XTAL_VENUS: + game.iRmMenu[game.iRoom] = 3; + getXtal(arg); + break; + + // TRITON (NEPTUNE) + + case IDI_MSA_ACTION_LOOK_CASTLE: + if (!game.iRmMenu[game.iRoom]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + break; + case IDI_MSA_ACTION_ENTER_OPENING: + if (game.fItemUsed[IDI_MSA_ITEM_CROWBAR]) { + game.iRoom = IDI_MSA_PIC_NEPTUNE_CASTLE_4; + return true; + } else { + if (game.fItem[IDI_MSA_ITEM_CROWBAR]) { + game.iRmMenu[game.iRoom] = 2; + } + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_USE_CROWBAR: + game.fItemUsed[IDI_MSA_ITEM_CROWBAR] = true; + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_NEPTUNE_ENTRANCE_1; + drawRoom(); + printDatMessage(arg); + break; + case IDI_MSA_ACTION_GET_XTAL_NEPTUNE: + if (game.fHasXtal) { + printDatMessage(71); + } else { + if (game.fItem[IDI_MSA_ITEM_SCARF]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_TALK_LEADER: + game.iRoom = IDI_MSA_PIC_NEPTUNE_ENTRYWAY; + printDatMessage(arg); + return true; + case IDI_MSA_ACTION_GIVE_SCARF: + game.iRmObj[game.iRoom] = 18; + getXtal(arg); + game.fItem[IDI_MSA_ITEM_SCARF] = false; + game.iRmMenu[game.iRoom] = 0; + game.iRmMenu[IDI_MSA_PIC_EARTH_BEDROOM] = 2; + game.iRoom = IDI_MSA_PIC_NEPTUNE_ENTRYWAY; + return true; + + // MERCURY + + case IDI_MSA_ACTION_GET_XTAL_MERCURY: + if (game.fHasXtal) { + game.iRmMenu[game.iRoom] = 2; + printDatMessage(32); + } else { + if (game.fItem[IDI_MSA_ITEM_SUNGLASSES]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GIVE_SUNGLASSES: + game.iRmObj[game.iRoom] = 17; + game.iRmMenu[game.iRoom] = 2; + game.fItem[IDI_MSA_ITEM_SUNGLASSES] = false; + getXtal(arg); + break; + + // TITAN (SATURN) + + case IDI_MSA_ACTION_CROSS_LAKE: + if (game.fItem[IDI_MSA_ITEM_MATTRESS]) { + game.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_0] = 1; + game.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_1] = 1; + game.iRmMenu[IDI_MSA_PIC_SATURN_LAKE_2] = 1; + } + printDatMessage(arg); + break; + case IDI_MSA_ACTION_USE_MATTRESS: + game.iRoom = IDI_MSA_PIC_SATURN_ISLAND; + printDatMessage(arg); + return true; + case IDI_MSA_ACTION_GET_XTAL_SATURN: + if (game.fHasXtal) { + printDatMessage(29); + } else { + getXtal(arg); + } + break; + case IDI_MSA_ACTION_LEAVE_ISLAND: + game.iRoom = IDI_MSA_PIC_SATURN_LAKE_1; + printDatMessage(arg); + return true; + + // PLUTO + + case IDI_MSA_ACTION_GET_XTAL_PLUTO: + if (game.fHasXtal) { + printDatMessage(19); + } else { + if (game.fItem[IDI_MSA_ITEM_BONE]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GIVE_BONE: + game.fItem[IDI_MSA_ITEM_BONE] = false; + game.iRmMenu[game.iRoom] = 0; + game.iRmObj[game.iRoom] = 16; + getXtal(arg); + break; + + // IO (JUPITER) + + case IDI_MSA_ACTION_GET_ROCK_0: + if (game.fItem[IDI_MSA_ITEM_ROCK]) { + printDatMessage(38); + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmObj[game.iRoom] = IDI_MSA_OBJECT_NONE; + getItem(IDI_MSA_ITEM_ROCK); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_ROCK_1: + if (game.fItem[IDI_MSA_ITEM_ROCK]) { + printDatMessage(38); + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmObj[game.iRoom] = IDI_MSA_OBJECT_NONE; + getItem(IDI_MSA_ITEM_ROCK); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_XTAL_JUPITER: + if (game.fHasXtal) { + printDatMessage(15); + } else { + switch (game.nRocks) { + case 0: + if (game.fItem[IDI_MSA_ITEM_ROCK]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + break; + case 1: + if (game.fItem[IDI_MSA_ITEM_ROCK]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(34); + break; + case 2: + getXtal(35); + break; + } + } + break; + case IDI_MSA_ACTION_THROW_ROCK: + game.fItem[IDI_MSA_ITEM_ROCK] = false; + game.nItems--; + game.iRmObj[game.iRoom]++; + game.iRmMenu[game.iRoom] = 0; + drawRoom(); + if (game.nRocks) { + printDatMessage(37); + } else { + printDatMessage(arg); + } + game.nRocks++; + break; + + // MARS + + case IDI_MSA_ACTION_GO_TUBE: + if (game.fItem[IDI_MSA_ITEM_FLASHLIGHT]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + break; + case IDI_MSA_ACTION_USE_FLASHLIGHT: + game.iRoom = IDI_MSA_PIC_MARS_TUBE_1; + printDatMessage(15); + return true; + case IDI_MSA_ACTION_PLUTO_DIG: + if (game.fHasXtal) { + printDatMessage(21); + } else { + getXtal(arg); + } + break; + case IDI_MSA_ACTION_GET_XTAL_MARS: + if (game.fHasXtal) { + printDatMessage(23); + } else { + printDatMessage(arg); + } + break; + + // OBERON (URANUS) + + case IDI_MSA_ACTION_ENTER_TEMPLE: + game.iRoom = IDI_MSA_PIC_URANUS_TEMPLE; + return true; + case IDI_MSA_ACTION_USE_CRYSTAL: + if (game.iRmMenu[game.iRoom]) { + printDatMessage(25); + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE_1; + drawRoom(); + game.iRmPic[game.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE; + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_OPEN_DOOR: + if (game.fTempleDoorOpen) { + printDatMessage(36); + } else { + game.fTempleDoorOpen = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_URANUS_TEMPLE_2; + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_ENTER_DOOR: + if (game.fTempleDoorOpen) { + game.iRoom = IDI_MSA_PIC_URANUS_STEPS; + return true; + } else { + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GET_XTAL_URANUS: + if (game.fHasXtal) { + printDatMessage(34); + } else { + if (game.fItem[IDI_MSA_ITEM_CROWBAR]) { + game.iRmMenu[game.iRoom] = 1; + } + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_USE_CROWBAR_1: + game.iRmMenu[game.iRoom] = 0; + getXtal(arg); + break; + + // SPACESHIP + + case IDI_MSA_ACTION_GO_NORTH: + if (game.fShipDoorOpen) { + if (game.fSuit) { + printDatMessage(45); + } else { + game.iRoom = IDI_MSA_PIC_SHIP_CORRIDOR; + return true; + } + } else { + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_GO_PLANET: + if (!game.fShipDoorOpen) { + if ((game.nXtals == IDI_MSA_MAX_PLANET) && (game.iPlanet == IDI_MSA_PLANET_EARTH)) + gameOver(); + if ((game.iPlanet == game.iPlanetXtal[game.nXtals]) || (game.iPlanet == IDI_MSA_PLANET_EARTH)) { + game.fHasXtal = false; + game.iRoom = IDI_MSA_HOME_PLANET[game.iPlanet]; + if (game.iPlanet != IDI_MSA_PLANET_EARTH) + insertDisk(1); + return true; + } else { + game.iRoom = IDI_MSA_SHIP_PLANET[game.iPlanet]; + return true; + } + } else { + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_PRESS_BUTTON: + if (game.fShipDoorOpen) { // inner door open + if (game.iPlanet && !game.fSuit) { + printDatMessage(arg); + } else { + game.fShipDoorOpen = false; + game.iRmPic[game.iRoom]--; + drawRoom(); + printDatMessage(2); + } + } else { + game.fShipDoorOpen = true; + game.iRmPic[game.iRoom]++; + drawRoom(); + printDatMessage(14); + } + break; + case IDI_MSA_ACTION_WEAR_SPACESUIT: + if (game.fSuit) { + if (game.fShipDoorOpen) { + game.fSuit = false; + game.iRmMenu[game.iRoom] = 0; + game.iRmPic[game.iRoom] -= 2; + drawRoom(); + printDatMessage(13); + } else { + printDatMessage(3); + } + } else { + if (game.iPlanet) { + game.fSuit = true; + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] += 2; + drawRoom(); + printDatMessage(arg); + } else { + printDatMessage(12); + } + } + break; + case IDI_MSA_ACTION_READ_GAUGE: + printDatString(arg); + _vm->drawStr(IDI_MSA_ROW_TEMPERATURE, IDI_MSA_COL_TEMPERATURE_C, IDA_DEFAULT, + (const char *)IDS_MSA_TEMP_C[game.iPlanet]); + _vm->drawStr(IDI_MSA_ROW_TEMPERATURE, IDI_MSA_COL_TEMPERATURE_F, IDA_DEFAULT, + (const char *)IDS_MSA_TEMP_F[game.iPlanet]); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + break; + case IDI_MSA_ACTION_PRESS_ORANGE: + if (game.fFlying) { + printDatMessage(4); + } else { + playSound(IDI_MSA_SND_PRESS_ORANGE); + printDatMessage(arg); + pressOB(IDI_MSA_BUTTON_ORANGE); + } + break; + case IDI_MSA_ACTION_PRESS_BLUE: + if (game.fFlying) { + printDatMessage(4); + } else { + playSound(IDI_MSA_SND_PRESS_BLUE); + printDatMessage(arg); + pressOB(IDI_MSA_BUTTON_BLUE); + } + break; + case IDI_MSA_ACTION_FLIP_SWITCH: + flipSwitch(); + break; + case IDI_MSA_ACTION_PUSH_THROTTLE: + if (game.fFlying) { + game.fFlying = false; + game.nButtons = 0; + memset(game.szAddr, 0, sizeof(game.szAddr)); + drawRoom(); + printDatString(22); + _vm->drawStr(IDI_MSA_ROW_PLANET, IDI_MSA_COL_PLANET, IDA_DEFAULT, + (const char *)IDS_MSA_PLANETS[game.iPlanet]); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKeyAnim(); + showPlanetInfo(); + } else { + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_PULL_THROTTLE: + if (game.fFlying) { + printDatMessage(18); + } else { + if (getPlanet() != -1) { + game.fFlying = true; + game.iPlanet = getPlanet(); + drawRoom(); + printDatMessage(16); + } else { + game.nButtons = 0; + memset(game.szAddr, 0, sizeof(game.szAddr)); + printDatMessage(17); + } + } + break; + case IDI_MSA_ACTION_LEAVE_ROOM: + if (game.fFlying) { + printDatMessage(24); + } else { + game.iRoom = arg; + return true; + } + break; + case IDI_MSA_ACTION_OPEN_CABINET_1: + if (game.iRmMenu[game.iRoom]) { + printExeMsg(IDO_MSA_THE_CABINET_IS_ALREADY_OPEN); + } else { + game.iRmMenu[game.iRoom] = 1; + game.iRmPic[game.iRoom] = IDI_MSA_PIC_SHIP_KITCHEN_1; + drawRoom(); + printDatMessage(arg); + } + break; + case IDI_MSA_ACTION_READ_MAP: + game.iRmPic[game.iRoom] = IDI_MSA_PIC_STAR_MAP; + drawRoom(); + printDatMessage(46); + printDatMessage(47); + printDatMessage(48); + game.iRmPic[game.iRoom] = IDI_MSA_PIC_SHIP_BEDROOM; + drawRoom(); + break; + case IDI_MSA_ACTION_GO_WEST: + game.nButtons = 0; + memset(game.szAddr, 0, sizeof(game.szAddr)); + game.iRoom = arg; + return true; + } + + return false; +} + +void Mickey::gameLoop() { + char *buffer = new char[sizeof(MSA_MENU)]; + MSA_MENU menu; + int iSel0, iSel1; + bool done; + + for (;;) { + drawRoom(); + + if (game.fIntro) { + game.fIntro = false; + } else { + printRoomDesc(); + } + + if (game.iRoom == IDI_MSA_PIC_NEPTUNE_GUARD) { + game.iRoom = IDI_MSA_PIC_NEPTUNE_LEADER; + done = true; + } else { + done = false; + } + + while (!done) { + checkAirSupply(game.fSuit, &game.nAir); + readMenu(game.iRoom, buffer); + memcpy(&menu, buffer, sizeof(MSA_MENU)); + patchMenu(&menu); + memcpy(buffer, &menu, sizeof(MSA_MENU)); + getMenuSel(buffer, &iSel0, &iSel1); + done = parse(menu.cmd[iSel0].data[iSel1], menu.arg[iSel0].data[iSel1]); + } + + game.nFrame = 0; + } + + delete [] buffer; +} + +// Keyboard + +void Mickey::waitAnyKeyAnim() { + waitAnyKey(true); +} + +void Mickey::waitAnyKey(bool anim) { + Common::Event event; + + if (!anim) { + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + } + + for (;;) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _vm->_system->quit(); + case Common::EVENT_KEYDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: + return; + default: + break; + } + } + if (anim) { + animate(); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + } + } +} + +// Debug + +void Mickey::debug_DrawObjs() { + char szTitle[14] = {0}; + + for (int iObj = 0; iObj < IDI_MSA_MAX_OBJ; iObj++) { + drawPic(0); + drawObj((ENUM_MSA_OBJECT)iObj, 0, 0); + + _vm->clearTextArea(); + sprintf(szTitle, "Object %d", iObj); + _vm->drawStrMiddle(22, IDA_DEFAULT, szTitle); + _vm->drawStrMiddle(23, IDA_DEFAULT, (const char *)IDS_MSA_NAME_OBJ[iObj]); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + } +} + +void Mickey::debug_DrawPics(){ + char szTitle[14] = {0}; + + for (int iPic = 1; iPic <= IDI_MSA_MAX_PIC; iPic++) { + drawPic(iPic); + + _vm->clearTextArea(); + sprintf(szTitle, "Picture %d", iPic); + _vm->drawStrMiddle(22, IDA_DEFAULT, szTitle); + //_vm->_gfx->doUpdate(); + //_vm->_system->updateScreen(); // TODO: this should go in the game's main loop + waitAnyKey(); + } +} + +// Init + +void Mickey::initVars() { + uint8 buffer[512]; + + // clear game struct + memset(&game, 0, sizeof(game)); + memset(&game.iItem, IDI_MSA_OBJECT_NONE, sizeof(game.iItem)); + // read room extended desc flags + readExe(IDO_MSA_ROOM_TEXT, buffer, sizeof(buffer)); + memcpy(game.fRmTxt, buffer, sizeof(game.fRmTxt)); + + // read room extended desc offsets + readExe(IDO_MSA_ROOM_TEXT_OFFSETS, buffer, sizeof(buffer)); + memcpy(game.oRmTxt, buffer, sizeof(game.oRmTxt)); + for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) + game.oRmTxt[i] = buffer[i*2] + 256 * buffer[i*2+1]; + + // read room object indices + readExe(IDO_MSA_ROOM_OBJECT, buffer, sizeof(buffer)); + memcpy(game.iRmObj, buffer, sizeof(game.iRmObj)); + + // read room picture indices + //readExe(IDO_MSA_ROOM_PICTURE, buffer, sizeof(buffer)); + //memcpy(game.iRmPic, buffer, sizeof(game.iRmPic)); + + // read room menu patch indices + readExe(IDO_MSA_ROOM_MENU_FIX, buffer, sizeof(buffer)); + memcpy(game.nRmMenu, buffer, sizeof(game.nRmMenu)); + + // set room picture indices + for (int i = 0; i < IDI_MSA_MAX_ROOM; i++) { + game.iRmPic[i] = i; + } + game.iRmPic[IDI_MSA_PIC_SHIP_AIRLOCK] = IDI_MSA_PIC_SHIP_AIRLOCK_0; + +#if 0 + // DEBUG + game.iPlanet = IDI_MSA_PLANET_EARTH; + game.iRoom = IDI_MSA_PIC_SHIP_CONTROLS; + game.fHasXtal = true; + game.nXtals = 9; + game.fItemUsed[IDI_MSA_ITEM_LETTER] = true; + +#endif + +} + +void Mickey::initEngine() { + // PreAGI sets the screen params here, but we've already done that in the preagi class +} + +Mickey::Mickey(PreAgiEngine *vm) : _vm(vm) { +} + +Mickey::~Mickey() { +} + +void Mickey::init() { + initEngine(); + initVars(); +} + +void Mickey::run() { + intro(); + gameLoop(); + gameOver(); +} + +} diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h new file mode 100644 index 0000000000..3b45fb8630 --- /dev/null +++ b/engines/agi/preagi_mickey.h @@ -0,0 +1,809 @@ +/* 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 AGI_PREAGI_MICKEY_H +#define AGI_PREAGI_MICKEY_H + +#include "agi/agi.h" + +namespace Agi { + +// strings + +#define IDS_MSA_PATH_DAT "dat/%s" +#define IDS_MSA_PATH_OBJ "obj/%s.ooo" +#define IDS_MSA_PATH_PIC "%d.pic" +#define IDS_MSA_PATH_LOGO "logos.bcg" +#define IDS_MSA_PATH_EXE "mickey.exe" + +#define IDS_MSA_INVENTORY "MICKEY IS CARRYING THE FOLLOWING:" +#define IDS_MSA_CRYSTALS "%s CRYSTALS" + +const char IDS_MSA_CRYSTAL_NO[][3] = { + "NO", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9" +}; +const char IDS_MSA_TEMP_C[][5] = { + " 20 ", " 480", "-200", " 430", "-185", "-230", "-130", "-150", "-215" +}; +const char IDS_MSA_TEMP_F[][5] = { + " 68 ", " 897", "-328", " 807", "-301", "-382", "-202", "-238", "-355" +}; +const char IDS_MSA_PLANETS[][10] = { + "EARTH. ", "VENUS. ", "TRITON. ", "MERCURY.", "TITAN. ", + "PLUTO. ", "IO. ", "MARS. ", "OBERON. " +}; + +#define IDS_MSA_DEBUG_ROOM "Now in room #%d " +#define IDS_MSA_DEBUG_OBJ "There is object #%d " + +// patch Mickey.exe offset 0x21E to value 0x01 to enable debug mode + +const char IDS_MSA_INSERT_DISK[][40] = { + "Please insert disk 1 and press any key", "Please insert disk 2 and press any key" +}; + +#define IDS_MSA_ERROR_EXE_NOT_FOUND "File 'mickey.exe' not found in folder 'mickey\'." + +// max values + +#define IDI_MSA_MAX_PLANET 9 +#define IDI_MSA_MAX_DAT 10 +#define IDI_MSA_MAX_OBJ 32 +#define IDI_MSA_MAX_PIC 240 +#define IDI_MSA_MAX_PIC_ROOM 224 +#define IDI_MSA_MAX_SOUND 8 +#define IDI_MSA_MAX_ROOM 160 +#define IDI_MSA_MAX_STR 160 + +#define IDI_MSA_MAX_BUTTON 6 +#define IDI_MSA_MAX_ITEM 11 +#define IDI_MSA_MAX_HINT 20 +#define IDI_MSA_MAX_PLANET_INFO 4 +#define IDI_MSA_MAX_AIR_SUPPLY 50 + +#define IDI_MSA_ANIM_DELAY 25 + +#define IDI_MSA_LEN_STORY 1372 + +// rows + +#define IDI_MSA_ROW_MENU_0 20 +#define IDI_MSA_ROW_MENU_1 21 +#define IDI_MSA_ROW_INV_TITLE 2 +#define IDI_MSA_ROW_INV_CRYSTALS 4 +#define IDI_MSA_ROW_INV_ITEMS 5 +#define IDI_MSA_ROW_TEMPERATURE 21 +#define IDI_MSA_ROW_PLANET 22 +#define IDI_MSA_ROW_BUTTONS 20 +#define IDI_MSA_ROW_INSERT_DISK 23 + +#define IDI_MSA_COL_INV_TITLE 4 +#define IDI_MSA_COL_INV_ITEMS 15 +#define IDI_MSA_COL_TEMPERATURE_C 15 +#define IDI_MSA_COL_TEMPERATURE_F 23 +#define IDI_MSA_COL_PLANET 28 +#define IDI_MSA_COL_BUTTONS 22 +#define IDI_MSA_COL_INSERT_DISK 1 + +// messages + +#define IDI_MSA_MSG_STAR_MAP_0 46 +#define IDI_MSA_MSG_STAR_MAP_1 47 +#define IDI_MSA_MSG_STAR_MAP_2 48 +#define IDI_MSA_MSG_SPACESUIT_WEAR 11 +#define IDI_MSA_MSG_SPACESUIT_REMOVE 13 +#define IDI_MSA_MSG_SPACESUIT_0 3 +#define IDI_MSA_MSG_SPACESUIT_CANT_WEAR_ON_EARTH 12 +#define IDI_MSA_MSG_SHIP_LAUNCH 16 +#define IDI_MSA_MSG_SHIP_LAND 22 + +// screen + +#define IDI_MSA_PIC_WIDTH 140 +#define IDI_MSA_PIC_HEIGHT 159 +#define IDI_MSA_PIC_X0 10 +#define IDI_MSA_PIC_Y0 0 +#define IDI_MSA_PIC_FLAGS IDF_AGI_PIC_V2 + +// pictures + +#define IDI_MSA_PIC_EARTH_TIRE_SWING 1 +#define IDI_MSA_PIC_EARTH_TIRE_SWING_1 200 // rope taken, swing on ground +#define IDI_MSA_PIC_EARTH_DOGHOUSE 2 +#define IDI_MSA_PIC_EARTH_IN_DOGHOUSE 154 +#define IDI_MSA_PIC_EARTH_TREE 3 +#define IDI_MSA_PIC_EARTH_GARDEN 4 +#define IDI_MSA_PIC_EARTH_FRONT_HOUSE 5 +#define IDI_MSA_PIC_EARTH_HAMMOCK 6 +#define IDI_MSA_PIC_EARTH_BUTTERFLY 7 +#define IDI_MSA_PIC_EARTH_MAILBOX 8 +#define IDI_MSA_PIC_EARTH_ROAD_0 9 +#define IDI_MSA_PIC_EARTH_ROAD_1 10 +#define IDI_MSA_PIC_EARTH_ROAD_2 11 +#define IDI_MSA_PIC_EARTH_ROAD_3 12 +#define IDI_MSA_PIC_EARTH_ROAD_4 13 // starting room +#define IDI_MSA_PIC_EARTH_ROAD_5 14 +#define IDI_MSA_PIC_EARTH_ROAD_6 15 +#define IDI_MSA_PIC_EARTH_ROAD_7 18 +#define IDI_MSA_PIC_EARTH_UNDER_TREE 16 +#define IDI_MSA_PIC_EARTH_UP_IN_TREE 155 // CRYSTAL +#define IDI_MSA_PIC_EARTH_SHIP 17 +#define IDI_MSA_PIC_EARTH_LIVING_ROOM 19 +#define IDI_MSA_PIC_EARTH_KITCHEN 20 +#define IDI_MSA_PIC_EARTH_KITCHEN_1 159 // cupboard open +#define IDI_MSA_PIC_EARTH_GARAGE 21 +#define IDI_MSA_PIC_EARTH_GARAGE_1 160 // cabinet open +#define IDI_MSA_PIC_EARTH_BEDROOM 22 +#define IDI_MSA_PIC_EARTH_BEDROOM_1 161 // closet open +#define IDI_MSA_PIC_EARTH_BATHROOM 23 // WEIGH MICKEY +#define IDI_MSA_PIC_EARTH_SHIP_LEAVING 24 +#define IDI_MSA_PIC_EARTH_MINNIE 25 + +#define IDI_MSA_PIC_SHIP_AIRLOCK 25 +#define IDI_MSA_PIC_SHIP_AIRLOCK_0 201 // door closed +#define IDI_MSA_PIC_SHIP_AIRLOCK_1 202 // door open +#define IDI_MSA_PIC_SHIP_AIRLOCK_2 203 // door closed, spacesuits on +#define IDI_MSA_PIC_SHIP_AIRLOCK_3 204 // door open, spacesuits on +#define IDI_MSA_PIC_SHIP_BEDROOM 29 +#define IDI_MSA_PIC_SHIP_CONTROLS 26 +#define IDI_MSA_PIC_SHIP_CORRIDOR 27 +#define IDI_MSA_PIC_SHIP_KITCHEN 28 +#define IDI_MSA_PIC_SHIP_KITCHEN_1 172 // cabinet open + +#define IDI_MSA_PIC_SHIP_VENUS 146 +#define IDI_MSA_PIC_SHIP_NEPTUNE 147 +#define IDI_MSA_PIC_SHIP_MERCURY 148 +#define IDI_MSA_PIC_SHIP_SATURN 149 +#define IDI_MSA_PIC_SHIP_PLUTO 150 +#define IDI_MSA_PIC_SHIP_JUPITER 151 +#define IDI_MSA_PIC_SHIP_MARS 152 +#define IDI_MSA_PIC_SHIP_URANUS 153 + +#define IDI_MSA_PIC_VENUS_0 30 +#define IDI_MSA_PIC_VENUS_1 31 +#define IDI_MSA_PIC_VENUS_2 32 +#define IDI_MSA_PIC_VENUS_3 34 +#define IDI_MSA_PIC_VENUS_4 36 +#define IDI_MSA_PIC_VENUS_5 38 +#define IDI_MSA_PIC_VENUS_CHASM 35 +#define IDI_MSA_PIC_VENUS_CHASM_1 183 // rope lowered +#define IDI_MSA_PIC_VENUS_PROBE 39 // CRYSTAL, USE WRENCH +#define IDI_MSA_PIC_VENUS_PROBE_1 184 // hatch open +#define IDI_MSA_PIC_VENUS_SHIP 33 +#define IDI_MSA_PIC_VENUS_WEIGH 37 // WEIGH MICKEY + +#define IDI_MSA_PIC_NEPTUNE_0 40 +#define IDI_MSA_PIC_NEPTUNE_1 42 +#define IDI_MSA_PIC_NEPTUNE_2 43 +#define IDI_MSA_PIC_NEPTUNE_3 44 +#define IDI_MSA_PIC_NEPTUNE_4 45 +#define IDI_MSA_PIC_NEPTUNE_5 48 +#define IDI_MSA_PIC_NEPTUNE_6 50 +#define IDI_MSA_PIC_NEPTUNE_7 52 +#define IDI_MSA_PIC_NEPTUNE_8 53 +#define IDI_MSA_PIC_NEPTUNE_9 54 +#define IDI_MSA_PIC_NEPTUNE_10 55 +#define IDI_MSA_PIC_NEPTUNE_11 56 +#define IDI_MSA_PIC_NEPTUNE_BABIES 61 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_0 46 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_1 51 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_2 57 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_3 58 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_4 59 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_5 60 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_6 66 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_7 67 +#define IDI_MSA_PIC_NEPTUNE_CASTLE_8 68 +#define IDI_MSA_PIC_NEPTUNE_EATING_AREA 62 +#define IDI_MSA_PIC_NEPTUNE_ENTRANCE 47 +#define IDI_MSA_PIC_NEPTUNE_ENTRANCE_1 185 // entrance open +#define IDI_MSA_PIC_NEPTUNE_ENTRYWAY 63 +#define IDI_MSA_PIC_NEPTUNE_GUARD 69 +#define IDI_MSA_PIC_NEPTUNE_LEADER 64 // CRYSTAL, GIVE SCARF +#define IDI_MSA_PIC_NEPTUNE_SHIP 49 +#define IDI_MSA_PIC_NEPTUNE_SLEEP_AREA 65 +#define IDI_MSA_PIC_NEPTUNE_WEIGH 41 + +#define IDI_MSA_PIC_MERCURY_0 71 +#define IDI_MSA_PIC_MERCURY_1 73 +#define IDI_MSA_PIC_MERCURY_2 75 +#define IDI_MSA_PIC_MERCURY_3 77 +#define IDI_MSA_PIC_MERCURY_4 80 +#define IDI_MSA_PIC_MERCURY_ALIEN_0 72 // CRYSTAL, GIVE SUNGLASSES +#define IDI_MSA_PIC_MERCURY_ALIEN_1 74 +#define IDI_MSA_PIC_MERCURY_ALIEN_2 81 +#define IDI_MSA_PIC_MERCURY_CAVE_0 70 // hidden feature, press '2' here +#define IDI_MSA_PIC_MERCURY_CAVE_1 78 +#define IDI_MSA_PIC_MERCURY_CAVE_2 79 +#define IDI_MSA_PIC_MERCURY_SHIP 76 +#define IDI_MSA_PIC_MERCURY_WEIGH 82 + +#define IDI_MSA_PIC_SATURN_0 84 +#define IDI_MSA_PIC_SATURN_1 86 +#define IDI_MSA_PIC_SATURN_2 90 +#define IDI_MSA_PIC_SATURN_3 91 +#define IDI_MSA_PIC_SATURN_ISLAND 89 // CRYSTAL +#define IDI_MSA_PIC_SATURN_LAKE_0 85 // USE MATTRESS +#define IDI_MSA_PIC_SATURN_LAKE_1 88 // USE MATTRESS +#define IDI_MSA_PIC_SATURN_LAKE_2 92 // USE MATTRESS +#define IDI_MSA_PIC_SATURN_SHIP 87 +#define IDI_MSA_PIC_SATURN_WEIGH 83 // WEIGH MICKEY + +#define IDI_MSA_PIC_PLUTO_0 93 +#define IDI_MSA_PIC_PLUTO_1 96 +#define IDI_MSA_PIC_PLUTO_2 97 +#define IDI_MSA_PIC_PLUTO_3 98 +#define IDI_MSA_PIC_PLUTO_4 101 +#define IDI_MSA_PIC_PLUTO_ALIENS 100 // CRYSTAL, GIVE BONE +#define IDI_MSA_PIC_PLUTO_CAVE_0 99 +#define IDI_MSA_PIC_PLUTO_CAVE_1 103 +#define IDI_MSA_PIC_PLUTO_CRATER 102 +#define IDI_MSA_PIC_PLUTO_SHIP 95 +#define IDI_MSA_PIC_PLUTO_WEIGH 94 // WEIGH MICKEY + +#define IDI_MSA_PIC_JUPITER_0 106 +#define IDI_MSA_PIC_JUPITER_1 107 +#define IDI_MSA_PIC_JUPITER_2 108 +#define IDI_MSA_PIC_JUPITER_3 109 +#define IDI_MSA_PIC_JUPITER_4 113 +#define IDI_MSA_PIC_JUPITER_5 116 +#define IDI_MSA_PIC_JUPITER_6 117 +#define IDI_MSA_PIC_JUPITER_7 120 +#define IDI_MSA_PIC_JUPITER_CRACK 114 +#define IDI_MSA_PIC_JUPITER_LAVA 110 // CRYSTAL, THROW ROCK +#define IDI_MSA_PIC_JUPITER_ROCK_0 112 // GET ROCK +#define IDI_MSA_PIC_JUPITER_ROCK_1 119 // GET ROCK +#define IDI_MSA_PIC_JUPITER_SHIP 115 +#define IDI_MSA_PIC_JUPITER_WEIGH 118 // WEIGH MICKEY + +#define IDI_MSA_PIC_MARS_0 121 +#define IDI_MSA_PIC_MARS_1 124 +#define IDI_MSA_PIC_MARS_2 125 +#define IDI_MSA_PIC_MARS_3 126 +#define IDI_MSA_PIC_MARS_4 127 +#define IDI_MSA_PIC_MARS_5 128 +#define IDI_MSA_PIC_MARS_6 130 +#define IDI_MSA_PIC_MARS_SHIP 123 +#define IDI_MSA_PIC_MARS_TUBE_0 129 +#define IDI_MSA_PIC_MARS_TUBE_1 131 +#define IDI_MSA_PIC_MARS_VOLCANO 132 // CRYSTAL, DIG PLUTO +#define IDI_MSA_PIC_MARS_WEIGH 122 // WEIGH MICKEY + +#define IDI_MSA_PIC_URANUS_0 133 +#define IDI_MSA_PIC_URANUS_1 134 +#define IDI_MSA_PIC_URANUS_2 135 +#define IDI_MSA_PIC_URANUS_3 138 +#define IDI_MSA_PIC_URANUS_4 139 +#define IDI_MSA_PIC_URANUS_5 140 +#define IDI_MSA_PIC_URANUS_6 142 +#define IDI_MSA_PIC_URANUS_CHAMBER 145 // CRYSTAL, USE CROWBAR +#define IDI_MSA_PIC_URANUS_SHIP 137 +#define IDI_MSA_PIC_URANUS_STEPS 144 +#define IDI_MSA_PIC_URANUS_ENTRANCE 141 // ENTER TEMPLE +#define IDI_MSA_PIC_URANUS_TEMPLE 143 // USE CRYSTAL, ENTER DOOR +#define IDI_MSA_PIC_URANUS_TEMPLE_1 206 // crystal used +#define IDI_MSA_PIC_URANUS_TEMPLE_2 207 // door open +#define IDI_MSA_PIC_URANUS_WEIGH 136 // WEIGH MICKEY + +#define IDI_MSA_PIC_STAR_MAP 165 +#define IDI_MSA_PIC_TITLE 240 + +// objects + +enum ENUM_MSA_OBJECT { + IDI_MSA_OBJECT_NONE = -1, + IDI_MSA_OBJECT_ROCK_0, + IDI_MSA_OBJECT_WRENCH, + IDI_MSA_OBJECT_SCALE, + IDI_MSA_OBJECT_CROWBAR, + IDI_MSA_OBJECT_BONE, + IDI_MSA_OBJECT_SUNGLASSES, + IDI_MSA_OBJECT_DESK_STUFF, + IDI_MSA_OBJECT_MATTRESS, + IDI_MSA_OBJECT_SCARF, + IDI_MSA_OBJECT_FLASHLIGHT, + IDI_MSA_OBJECT_ROPE, + IDI_MSA_OBJECT_ROCK_1, + IDI_MSA_OBJECT_SCARF_C64, + IDI_MSA_OBJECT_ROCK_2, + IDI_MSA_OBJECT_ROCK_3, + IDI_MSA_OBJECT_W_EARTH, + IDI_MSA_OBJECT_W_VENUS, + IDI_MSA_OBJECT_W_TRITON, + IDI_MSA_OBJECT_W_MERCURY, + IDI_MSA_OBJECT_W_TITAN, + IDI_MSA_OBJECT_W_PLUTO, + IDI_MSA_OBJECT_W_IO, + IDI_MSA_OBJECT_W_MARS, + IDI_MSA_OBJECT_W_OBERON, + IDI_MSA_OBJECT_W_SPACE, + IDI_MSA_OBJECT_XL31, + IDI_MSA_OBJECT_XL31E, + IDI_MSA_OBJECT_XL32, + IDI_MSA_OBJECT_XL32E, + IDI_MSA_OBJECT_XL33, + IDI_MSA_OBJECT_XL33E, + IDI_MSA_OBJECT_CRYSTAL +}; + +const char IDS_MSA_NAME_OBJ[][9] = { + "rok1", "wrench", "scale", "cbar", "bone", "glasses", "deskstuf", "raft", + "scarf", "flashlit", "rope", "rok1", "scarfc64", "rok2", "rock35", "earthw", + "venw", "trw", "merw", "titw", "plw", "iow", "mrw", "obw", "spw", "xl31", + "xl31e", "xl32", "xl32e", "xl33", "xl33e", "crys1" +}; + +const int IDI_MSA_XTAL_ROOM_XY[IDI_MSA_MAX_PLANET][3] = { + // room x y + {IDI_MSA_PIC_EARTH_UP_IN_TREE, 14, 76}, + {IDI_MSA_PIC_VENUS_PROBE, 74, 80}, + {IDI_MSA_PIC_NEPTUNE_LEADER, 70, 27}, + {IDI_MSA_PIC_MERCURY_ALIEN_0, 123, 64}, + {IDI_MSA_PIC_SATURN_ISLAND, 110, 115}, + {IDI_MSA_PIC_PLUTO_ALIENS, 60, 104}, + {IDI_MSA_PIC_JUPITER_LAVA, 56, 54}, + {IDI_MSA_PIC_MARS_VOLCANO, 107, 100}, + {IDI_MSA_PIC_URANUS_CHAMBER, 90, 4} +}; + +// planets + +enum ENUM_MSA_PLANET { + IDI_MSA_PLANET_EARTH = 0, + IDI_MSA_PLANET_VENUS, + IDI_MSA_PLANET_NEPTUNE, + IDI_MSA_PLANET_MERCURY, + IDI_MSA_PLANET_SATURN, + IDI_MSA_PLANET_PLUTO, + IDI_MSA_PLANET_JUPITER, + IDI_MSA_PLANET_MARS, + IDI_MSA_PLANET_URANUS, + IDI_MSA_PLANET_SPACESHIP +}; + +const char IDS_MSA_NAME_DAT[][13] = { + "earth.dat", "venus.dat", "neptune.dat", "mercury.dat", "saturn.dat", + "pluto.dat", "jupiter.dat", "mars.dat", "uranus.dat", "spacship.dat" +}; + +const char IDS_MSA_NAME_PLANET[][10] = { + "EARTH", "VENUS", "TRITON", "MERCURY", "TITAN", + "PLUTO", "IO", "MARS", "OBERON" +}; + +const char IDS_MSA_NAME_PLANET_2[][10] = { + "EARTH", "VENUS", "NEPTUNE", "MERCURY", "SATURN", + "PLUTO", "JUPITER", "MARS", "URANUS" +}; + +const char IDS_MSA_ADDR_PLANET[][7] = { + "OB", "B", "OOBBB", "O", "OOBB", + "OOOBBB", "OBB", "OOB", "OOOBB" +}; + +const int IDI_MSA_HOME_PLANET[] = { + IDI_MSA_PIC_EARTH_SHIP, IDI_MSA_PIC_VENUS_SHIP, IDI_MSA_PIC_NEPTUNE_SHIP, IDI_MSA_PIC_MERCURY_SHIP, + IDI_MSA_PIC_SATURN_SHIP, IDI_MSA_PIC_PLUTO_SHIP, IDI_MSA_PIC_JUPITER_SHIP, IDI_MSA_PIC_MARS_SHIP, + IDI_MSA_PIC_URANUS_SHIP +}; + +const int IDI_MSA_SHIP_PLANET[] = { + 0, IDI_MSA_PIC_SHIP_VENUS, IDI_MSA_PIC_SHIP_NEPTUNE, IDI_MSA_PIC_SHIP_MERCURY, IDI_MSA_PIC_SHIP_SATURN, + IDI_MSA_PIC_SHIP_PLUTO, IDI_MSA_PIC_SHIP_JUPITER, IDI_MSA_PIC_SHIP_MARS, IDI_MSA_PIC_SHIP_URANUS +}; + +// items + +enum ENUM_MSA_ITEM { + IDI_MSA_ITEM_FLASHLIGHT = 0, + IDI_MSA_ITEM_ROPE, + IDI_MSA_ITEM_BONE, + IDI_MSA_ITEM_LETTER, + IDI_MSA_ITEM_CROWBAR, + IDI_MSA_ITEM_WRENCH, + IDI_MSA_ITEM_MATTRESS, + IDI_MSA_ITEM_SCARF, + IDI_MSA_ITEM_SUNGLASSES, + IDI_MSA_ITEM_SCALE, + IDI_MSA_ITEM_ROCK +}; + +const char IDS_MSA_NAME_ITEM[][15] = { + "A FLASHLIGHT", "A ROPE ", "A BONE ", "A LETTER", "A CROWBAR", "A WRENCH", + "A MATTRESS", "A SCARF", "SUNGLASSES", "A SCALE ", "A ROCK " +}; + +// buttons + +#define IDI_MSA_BUTTON_ORANGE 0x4F // 'O' +#define IDI_MSA_BUTTON_BLUE 0x42 // 'B' + +// file structures + +struct MSA_TEXT_ENTRY { + uint8 x0; + uint8 szText[11]; +}; + +struct MSA_TEXT_BLOCK { + uint8 count; + MSA_TEXT_ENTRY entry[5]; +}; + +struct MSA_MSG_BLOCK { + uint8 data[5]; +}; + +struct MSA_MENU { + MSA_TEXT_BLOCK row[2]; + MSA_MSG_BLOCK cmd[5]; + MSA_MSG_BLOCK arg[5]; +}; + +struct MSA_DAT_HEADER { + uint16 filelen; + uint16 ofsRoom[IDI_MSA_MAX_ROOM]; + uint16 ofsDesc[IDI_MSA_MAX_ROOM]; + uint16 ofsStr[IDI_MSA_MAX_STR]; +}; + +struct MSA_SND_NOTE { + uint16 counter; // freq = 1193180 / counter + uint8 length; // msec = length / 0.0182 +}; + +// file offset modifiers + +#define IDI_MSA_OFS_INVALID 0xFE9A +#define IDI_MSA_OFS_DAT 0x0002 +#define IDI_MSA_OFS_EXE 0x35C0 +#define IDI_MSA_OFS_OBJECT_DATA 0x58E8 + +// actions + +#define IDI_MSA_ACTION_GOTO_ROOM 0x00 +#define IDI_MSA_ACTION_SHOW_INT_STR 0x01 +#define IDI_MSA_ACTION_UNUSED 0x02 +#define IDI_MSA_ACTION_SHOW_DAT_STR 0x03 + +#define IDI_MSA_ACTION_GET_ROPE 0x7F +#define IDI_MSA_ACTION_UNTIE_ROPE 0x80 +#define IDI_MSA_ACTION_GET_BONE 0x81 +#define IDI_MSA_ACTION_GET_XTAL_EARTH 0x82 +#define IDI_MSA_ACTION_LOOK_DESK 0x83 +#define IDI_MSA_ACTION_WRITE_LETTER 0x84 +#define IDI_MSA_ACTION_MAIL_LETTER 0x85 +#define IDI_MSA_ACTION_OPEN_CUPBOARD 0x86 +#define IDI_MSA_ACTION_GET_FLASHLIGHT 0x87 +#define IDI_MSA_ACTION_OPEN_CABINET 0x88 +#define IDI_MSA_ACTION_GET_CROWBAR 0x89 +#define IDI_MSA_ACTION_GET_WRENCH 0x8A +#define IDI_MSA_ACTION_OPEN_CLOSET 0x8B +#define IDI_MSA_ACTION_GET_MATTRESS 0x8C +#define IDI_MSA_ACTION_GET_SCARF 0x8D +#define IDI_MSA_ACTION_GET_SUNGLASSES 0x8E +#define IDI_MSA_ACTION_GET_SCALE 0x8F +#define IDI_MSA_ACTION_GOTO_SPACESHIP 0x90 + +#define IDI_MSA_ACTION_DOWN_CHASM 0x91 +#define IDI_MSA_ACTION_DOWN_ROPE 0x92 +#define IDI_MSA_ACTION_USE_ROPE 0x93 +#define IDI_MSA_ACTION_OPEN_HATCH 0x94 +#define IDI_MSA_ACTION_USE_WRENCH 0x95 +#define IDI_MSA_ACTION_GET_XTAL_VENUS 0x96 + +#define IDI_MSA_ACTION_LOOK_CASTLE 0x97 +#define IDI_MSA_ACTION_ENTER_OPENING 0x98 +#define IDI_MSA_ACTION_USE_CROWBAR 0x99 +#define IDI_MSA_ACTION_GET_XTAL_NEPTUNE 0x9A +#define IDI_MSA_ACTION_TALK_LEADER 0x9B +#define IDI_MSA_ACTION_GIVE_SCARF 0x9C + +#define IDI_MSA_ACTION_GET_XTAL_MERCURY 0x9D +#define IDI_MSA_ACTION_GIVE_SUNGLASSES 0x9E +#define IDI_MSA_ACTION_CROSS_LAKE 0x9F +#define IDI_MSA_ACTION_USE_MATTRESS 0xA0 +#define IDI_MSA_ACTION_GET_XTAL_SATURN 0xA1 +#define IDI_MSA_ACTION_LEAVE_ISLAND 0xA2 + +#define IDI_MSA_ACTION_GET_XTAL_PLUTO 0xA3 +#define IDI_MSA_ACTION_GIVE_BONE 0xA4 + +#define IDI_MSA_ACTION_GET_ROCK_0 0xA5 +#define IDI_MSA_ACTION_GET_ROCK_1 0xA6 +#define IDI_MSA_ACTION_GET_XTAL_JUPITER 0xA7 +#define IDI_MSA_ACTION_THROW_ROCK 0xA8 + +#define IDI_MSA_ACTION_GO_TUBE 0xA9 +#define IDI_MSA_ACTION_USE_FLASHLIGHT 0xAA +#define IDI_MSA_ACTION_PLUTO_DIG 0xAB +#define IDI_MSA_ACTION_GET_XTAL_MARS 0xAC + +#define IDI_MSA_ACTION_USE_CRYSTAL 0xAD +#define IDI_MSA_ACTION_OPEN_DOOR 0xAE +#define IDI_MSA_ACTION_ENTER_DOOR 0xAF +#define IDI_MSA_ACTION_GET_XTAL_URANUS 0xB0 +#define IDI_MSA_ACTION_USE_CROWBAR_1 0xB1 + +#define IDI_MSA_ACTION_GO_NORTH 0xB2 +#define IDI_MSA_ACTION_GO_PLANET 0xB3 +#define IDI_MSA_ACTION_PRESS_BUTTON 0xB4 +#define IDI_MSA_ACTION_WEAR_SPACESUIT 0xB5 +#define IDI_MSA_ACTION_READ_GAUGE 0xB6 +#define IDI_MSA_ACTION_PRESS_ORANGE 0xB7 +#define IDI_MSA_ACTION_PRESS_BLUE 0xB8 +#define IDI_MSA_ACTION_FLIP_SWITCH 0xB9 +#define IDI_MSA_ACTION_PUSH_THROTTLE 0xBA +#define IDI_MSA_ACTION_PULL_THROTTLE 0xBB +#define IDI_MSA_ACTION_LEAVE_ROOM 0xBC +#define IDI_MSA_ACTION_OPEN_CABINET_1 0xBD +#define IDI_MSA_ACTION_READ_MAP 0xBE +#define IDI_MSA_ACTION_GO_WEST 0xBF + +#define IDI_MSA_ACTION_PLANET_INFO 0xC0 +#define IDI_MSA_ACTION_ENTER_TEMPLE 0xC1 +#define IDI_MSA_ACTION_OPEN_MAILBOX 0xC2 +#define IDI_MSA_ACTION_SAVE_GAME 0xC3 +#define IDI_MSA_ACTION_LOOK_MICKEY 0xC4 + +// sounds + +enum ENUM_MSA_SOUND { + IDI_MSA_SND_THEME, + IDI_MSA_SND_CRYSTAL, + IDI_MSA_SND_TAKE, + IDI_MSA_SND_GAME_OVER, + IDI_MSA_SND_PRESS_BLUE, + IDI_MSA_SND_PRESS_ORANGE, + IDI_MSA_SND_SHIP_LAND, + IDI_MSA_SND_XL30 +}; + +// message offsets within mickey.exe + +const int IDO_MSA_ERROR[] = { + 0x4C9C, 0x4CB9, 0x4CD4, 0x4CEA, 0x4D0D, 0x4D20, 0x4D3B, 0x4D5E +}; + +const int IDO_MSA_HIDDEN_MSG[] = { + 0x8C44, 0x8C83, 0x8D23, 0x8D97, 0x8E2A +}; + +const int IDO_MSA_GAME_OVER[] = { + 0x7914, 0x7978, 0x7A17, 0x7A94, 0x7B04, 0x7B8F, 0x7BEB, 0x7C79 +}; + +const int IDO_MSA_SAVE_GAME[] = { + 0x73FA, 0x7436, 0x746C, 0x74E9, 0x75F6, 0x766A, 0x758B + // do you have a formatted disk, insert disk, insert disk 2, save by number + // everything will be lost, previous game will be lost, game saved +}; + +const int IDO_MSA_LOAD_GAME[] = { + 0x76CE, 0x770B, 0x7777 + // do you want to load game, insert game save disk, game restored +}; + +const int IDO_MSA_AIR_SUPPLY[] = { + 0x7D10, 0x7D31, 0x7D51, 0x7D9B + // be aware, low, dangerously low, out of air + // 30, 20, 10, 0 +}; + +const int IDI_MSA_AIR_SUPPLY[] = { 30, 20, 10, 0 }; + +// planet information + +const int IDO_MSA_PLANET_INFO[IDI_MSA_MAX_PLANET][4] = { + {0x6313, 0x63B2, 0x6449, 0}, // EARTH + {0x61EB, 0x6288, 0, 0}, // VENUS + {0x6B64, 0x6C06, 0x6CA3, 0}, // NEPTUNE + {0x609B, 0x612C, 0x61CA, 0}, // MERCURY + {0x6879, 0x6916, 0x6984, 0}, // SATURN + {0x6CCF, 0x6D72, 0x6E10, 0}, // PLUTO + {0x667C, 0x6714, 0x67B1, 0x684E}, // JUPITER + {0x6471, 0x650F, 0x65AD, 0x6651}, // MARS + {0x69C3, 0x6A62, 0x6B00, 0} // URANUS +}; + +// next crystal piece hints + +const int IDO_MSA_NEXT_PIECE[IDI_MSA_MAX_PLANET][5] = { + {0, 0, 0, 0, 0}, // earth + {0x4DCC, 0x4E20, 0x4E64, 0x4E9E, 0x4F0B}, // venus + {0x5900, 0x599B, 0x5A07, 0x5A8E, 0x5B07}, // neptune + {0x4F57, 0x4FA3, 0x4FF1, 0x5056, 0x50BD}, // mercury + {0x5471, 0x54DF, 0x5548, 0x55C2, 0x562A}, // saturn + {0x5B78, 0x5BB6, 0x5C29, 0x5C76, 0x5CE1}, // pluto + {0x526B, 0x52DA, 0x5340, 0x53A1, 0x540C}, // jupiter + {0x50F6, 0x512C, 0x5170, 0x51D5, 0x5228}, // mars + {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus +}; + +// message offsets + +#define IDO_MSA_COPYRIGHT 0x7801 +#define IDO_MSA_INTRO 0x4679 +#define IDO_MSA_GAME_STORY 0x6E9C + +#define IDO_MSA_CHECK_DISK_DRIVE 0x7885 +#define IDO_MSA_YOU_CAN_SEE_MICKEY_ALREADY 0x46D1 +#define IDO_MSA_THE_CABINET_IS_ALREADY_OPEN 0x46EF + +#define IDO_MSA_PRESS_1_TO_9 0x7530 +#define IDO_MSA_PRESS_YES_OR_NO 0x480D +#define IDO_MSA_TOO_MANY_BUTTONS_PRESSED 0x5DF7 + +#define IDO_MSA_MICKEY_HAS_PRESSED 0x5D90 + +#define IDO_MSA_XL30_SPEAKING 0x4725 +#define IDO_MSA_CRYSTAL_PIECE_FOUND 0x600C + +#define IDO_MSA_FONT 0x7EDC // 256 chars, 2048 bytes (00110010 * 8 = character) + +#define IDO_MSA_ROOM_TEXT 0x4B80 +#define IDO_MSA_ROOM_TEXT_OFFSETS 0x8B01 +#define IDO_MSA_ROOM_OBJECT 0x475C +#define IDO_MSA_ROOM_PICTURE 0x4AE4 +#define IDO_MSA_ROOM_OBJECT_XY_OFFSETS 0x8EA8 +#define IDO_MSA_PIC_SHIP_LIGHT 0x8F38 +#define IDO_MSA_XTAL_ROOM_XY 0x97F8 +//#define IDO_MSA_PLANET_INFO 0x6048 +#define IDO_MSA_ROOM_MENU_FIX 0x4a27 +#define IDO_MSA_ROOM_MENU_FIX_OFFSETS 0x5E7A + +// offsets to offset arrays + +#define IDOFS_MSA_INTERPRETER_ERRORS 0x4c8e +#define IDOFS_MSA_HIDDEN_FEATURE 0x8c3a +#define IDOFS_MSA_MENU_PATCHES 0x5e7a +#define IDOFS_MSA_SOUND_DATA 0x9deb +#define IDOFS_MSA_NEXT_PLANET_CLUES 0x4d7c +#define IDOFS_MSA_PLANET_INFORMATION 0x6048 +#define IDOFS_MSA_PLANET_ADDRESSES 0x5e40 +#define IDOFS_MSA_OBJECT_DATA 0x8ea8 +#define IDOFS_MSA_EXTENDED_ROOM_DESCRIPTIONS 0x8b01 + +// game structure + +struct MSA_GAME { + int iRoom; + int iPlanet; + int iDisk; + + int nAir; + int nButtons; + int nRocks; + + bool fHasXtal; + int nXtals; + int iPlanetXtal[IDI_MSA_MAX_DAT]; + int iClue[IDI_MSA_MAX_PLANET]; + char szAddr[IDI_MSA_MAX_BUTTON + 1]; + + bool fIntro; + bool fSuit; + bool fShipDoorOpen; + bool fFlying; + bool fStoryShown; + bool fTempleDoorOpen; + + bool fItem[IDI_MSA_MAX_ITEM]; + bool fItemUsed[IDI_MSA_MAX_ITEM]; + int iItem[IDI_MSA_MAX_ITEM]; + int nItems; + + int8 fRmTxt[IDI_MSA_MAX_ROOM]; + int8 iRmObj[IDI_MSA_MAX_ROOM]; + uint8 iRmPic[IDI_MSA_MAX_ROOM]; + uint16 oRmTxt[IDI_MSA_MAX_ROOM]; + + uint8 iRmMenu[IDI_MSA_MAX_ROOM]; + uint8 nRmMenu[IDI_MSA_MAX_ROOM]; + + int nFrame; // 0.1.4 + bool fAnimXL30; // 0.1.4 + int nTicks; // 0.1.4 +}; + +class Mickey { + friend class PreAgiEngine; +public: + + Mickey(PreAgiEngine *vm); + ~Mickey(); + + void init(); + void run(); +protected: + PreAgiEngine *_vm; + MSA_GAME game; + bool clickToMove; + + int getDat(int); + void readExe(int, uint8*, long); + void getDatFileName(int, char*); + void readDatHdr(char*, MSA_DAT_HEADER*); + void readDesc(int, char*, long); + void readMenu(int, char*); + void readDatStr(int, int, char*, long); + void readOfsData(int, int, uint8*, long); + bool chooseY_N(int, bool); + int choose1to9(int); + void printStr(char*); + void printExeStr(int); + void printExeMsg(int); + void printDatStr(int, int); + void printDesc(int); + void drawMenu(MSA_MENU, int, int); + void getMouseMenuSelRow(MSA_MENU, int*, int*, int, int, int); + bool getMenuSelRow(MSA_MENU, int*, int*, int); + void getMenuSel(char*, int*, int*); + void centerMenu(MSA_MENU*); + void patchMenu(MSA_MENU*); + void printDatString(int); + void printDatMessage(int); + void playNote(MSA_SND_NOTE); + void playSound(ENUM_MSA_SOUND); + void debug(); + void drawObj(ENUM_MSA_OBJECT, int, int); + void drawPic(int); + void drawRoomPicture(); + void drawRoomObjects(); + void drawRoomAnimation(); + void drawRoom(); + void drawLogo(); + void animate(); + void printRoomDesc(); + bool loadGame(); + void saveGame(); + void showPlanetInfo(); + void printStory(); + void hidden(); + int getPlanet(); + void pressOB(int); + void checkAirSupply(bool, int*); + void insertDisk(int); + void gameOver(); + void inventory(); + void randomize(); + void flashScreen(); + void intro(); + void getItem(ENUM_MSA_ITEM); + void getXtal(int); + bool parse(int, int); + void gameLoop(); + void debug_DrawObjs(); + void debug_DrawPics(); + void initVars(); + void initEngine(); + void flipSwitch(); + void waitAnyKeyAnim(); + void waitAnyKey(bool anim = false); +}; + +} // End of namespace Agi + +#endif diff --git a/engines/agi/preagi_troll.cpp b/engines/agi/preagi_troll.cpp new file mode 100644 index 0000000000..5136286768 --- /dev/null +++ b/engines/agi/preagi_troll.cpp @@ -0,0 +1,502 @@ +/* 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 "agi/preagi.h" +#include "agi/preagi_common.h" +#include "agi/preagi_troll.h" +#include "agi/graphics.h" + +#include "graphics/cursorman.h" + +#include "common/events.h" + +namespace Agi { + +Troll::Troll(PreAgiEngine* vm) : _vm(vm) { +} + +// User Interface + +void Troll::pressAnyKey() { + _vm->drawStr(24, 4, kColorDefault, IDS_TRO_PRESSANYKEY); + _vm->_gfx->doUpdate(); + _vm->waitAnyKeyChoice(); +} + +void Troll::drawMenu(const char *szMenu, int iSel) { + _vm->clearTextArea(); + _vm->drawStr(21, 0, kColorDefault, szMenu); + _vm->drawStr(22 + iSel, 0, kColorDefault, " *"); + _vm->_gfx->doUpdate(); +} + +void Troll::getMenuSel(const char *szMenu, int *iSel, int nSel) { + Common::Event event; + int y; + + drawMenu(szMenu, *iSel); + + for (;;) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _vm->_system->quit(); + case Common::EVENT_MOUSEMOVE: + y = event.mouse.y / 8; + + if (y >= 22) + if (nSel > y - 22) + *iSel = y - 22; + + drawMenu(szMenu, *iSel); + break; + case Common::EVENT_LBUTTONUP: + return; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_t: + case Common::KEYCODE_f: + inventory(); + *iSel = 0; + drawMenu(szMenu, *iSel); + break; + case Common::KEYCODE_SPACE: + *iSel += 1; + + if (*iSel == nSel) + *iSel = IDI_TRO_SEL_OPTION_1; + + drawMenu(szMenu, *iSel); + break; + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + return; + default: + break; + } + break; + default: + break; + } + } + _vm->_system->updateScreen(); + _vm->_system->delayMillis(10); + } +} + +// Graphics + +void Troll::drawPic(int iPic, bool f3IsCont, bool clear) { + uint8 frame[] = { + 0xf1, 0x3, 0xf9, 0x0, 0x0, 0x9f, 0x0, 0x9f, 0xa7, 0x0, 0xa7, 0x0, 0x0, 0xff + }; + + if (clear) + _vm->clearScreen(0x0f); + + _vm->_picture->setDimensions(IDI_TRO_PIC_WIDTH, IDI_TRO_PIC_HEIGHT); + + _vm->_picture->setPictureData(frame, ARRAYSIZE(frame)); + _vm->_picture->drawPicture(); + + _vm->_picture->setPictureData(_gameData + _pictureOffsets[iPic], 4096); + + if (f3IsCont) + _vm->_picture->setPictureFlags(kPicFf3Cont); + else + _vm->_picture->setPictureFlags(kPicFf3Stop); + + _vm->_picture->drawPicture(); + + _vm->_picture->showPic(); + _vm->_gfx->doUpdate(); +} + +// Game Logic + +void Troll::inventory() { + char szMissing[40]; + + _vm->clearScreen(0x07); + _vm->drawStr(1, 12, kColorDefault, IDS_TRO_TREASURE_0); + _vm->drawStr(2, 12, kColorDefault, IDS_TRO_TREASURE_1); + + switch (_treasuresLeft) { + case 1: + sprintf(szMissing, IDS_TRO_TREASURE_5, _treasuresLeft); + _vm->drawStr(20, 10,kColorDefault, szMissing); + break; + case 0: + _vm->drawStr(20, 1, kColorDefault, IDS_TRO_TREASURE_6); + break; + case IDI_TRO_MAX_TREASURE: + _vm->drawStr(3, 17, kColorDefault, IDS_TRO_TREASURE_2); + default: + sprintf(szMissing, IDS_TRO_TREASURE_4, _treasuresLeft); + _vm->drawStr(20, 10,kColorDefault, szMissing); + break; + } + + _vm->drawStr(24, 6, kColorDefault, IDS_TRO_PRESSANYKEY); + _vm->_gfx->doUpdate(); + _vm->waitAnyKeyChoice(); +} + +void Troll::waitAnyKeyIntro() { + Common::Event event; + int iMsg = 0; + + for (;;) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _vm->_system->quit(); + case Common::EVENT_LBUTTONUP: + case Common::EVENT_KEYDOWN: + return; + default: + break; + } + } + + switch (iMsg) { + case 200: + iMsg = 0; + case 0: + _vm->drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_2); + _vm->_gfx->doUpdate(); + break; + case 100: + _vm->drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_3); + _vm->_gfx->doUpdate(); + break; + } + + iMsg++; + + _vm->_system->updateScreen(); + _vm->_system->delayMillis(10); + } +} + +void Troll::credits() { + _vm->clearScreen(0x07); + + _vm->drawStr(1, 2, kColorDefault, IDS_TRO_CREDITS_0); + + int color = 10; + char str[2]; + + str[1] = 0; + + for (uint i = 0; i < strlen(IDS_TRO_CREDITS_1); i++) { + str[0] = IDS_TRO_CREDITS_1[i]; + _vm->drawStr(7, 19 + i, color++, str); + if (color > 15) + color = 9; + } + + _vm->drawStr(8, 19, kColorDefault, IDS_TRO_CREDITS_2); + + _vm->drawStr(13, 11, 9, IDS_TRO_CREDITS_3); + _vm->drawStr(15, 8, 10, IDS_TRO_CREDITS_4); + _vm->drawStr(17, 7, 12, IDS_TRO_CREDITS_5); + _vm->drawStr(19, 2, 14, IDS_TRO_CREDITS_6); + + _vm->_gfx->doUpdate(); + + pressAnyKey(); +} + +void Troll::tutorial() { + bool done = false; + int iSel = 0; + //char szTreasure[16] = {0}; + + for (;;) { + _vm->clearScreen(0xFF); + + _vm->printStr(IDS_TRO_TUTORIAL_0); + _vm->getSelection(kSelSpace); + + _vm->clearScreen(0x55); + _vm->setDefaultTextColor(0x0F); + + done = false; + while (!done) { + getMenuSel(IDS_TRO_TUTORIAL_1, &iSel, IDI_TRO_MAX_OPTION); + switch(iSel) { + case IDI_TRO_SEL_OPTION_1: + _vm->clearScreen(0x22, false); + _vm->_gfx->doUpdate(); + break; + case IDI_TRO_SEL_OPTION_2: + _vm->clearScreen(0x00, false); + _vm->_gfx->doUpdate(); + break; + case IDI_TRO_SEL_OPTION_3: + done = true; + break; + } + } + + // do you need more practice ? + _vm->clearScreen(0x4F); + _vm->drawStr(7, 4, kColorDefault, IDS_TRO_TUTORIAL_5); + _vm->drawStr(9, 4, kColorDefault, IDS_TRO_TUTORIAL_6); + _vm->_gfx->doUpdate(); + + if (!_vm->getSelection(kSelYesNo)) + break; + } + + // show info texts + _vm->clearScreen(0x5F); + _vm->drawStr(4, 1, kColorDefault, IDS_TRO_TUTORIAL_7); + _vm->drawStr(5, 1, kColorDefault, IDS_TRO_TUTORIAL_8); + _vm->_gfx->doUpdate(); + pressAnyKey(); + + _vm->clearScreen(0x2F); + _vm->drawStr(6, 1, kColorDefault, IDS_TRO_TUTORIAL_9); + _vm->_gfx->doUpdate(); + pressAnyKey(); + + _vm->clearScreen(0x19); + _vm->drawStr(7, 1, kColorDefault, IDS_TRO_TUTORIAL_10); + _vm->drawStr(8, 1, kColorDefault, IDS_TRO_TUTORIAL_11); + _vm->_gfx->doUpdate(); + pressAnyKey(); + + _vm->clearScreen(0x6E); + _vm->drawStr(9, 1, kColorDefault, IDS_TRO_TUTORIAL_12); + _vm->drawStr(10, 1, kColorDefault, IDS_TRO_TUTORIAL_13); + _vm->_gfx->doUpdate(); + pressAnyKey(); + + _vm->clearScreen(0x4C); + _vm->drawStr(11, 1, kColorDefault, IDS_TRO_TUTORIAL_14); + _vm->drawStr(12, 1, kColorDefault, IDS_TRO_TUTORIAL_15); + _vm->_gfx->doUpdate(); + pressAnyKey(); + + _vm->clearScreen(0x5D); + _vm->drawStr(13, 1, kColorDefault, IDS_TRO_TUTORIAL_16); + _vm->drawStr(14, 1, kColorDefault, IDS_TRO_TUTORIAL_17); + _vm->drawStr(15, 1, kColorDefault, IDS_TRO_TUTORIAL_18); + _vm->_gfx->doUpdate(); + pressAnyKey(); + + // show treasures + _vm->clearScreen(0x2A); + _vm->drawStr(2, 1, kColorDefault, IDS_TRO_TUTORIAL_19); + for (int i = 0; i < IDI_TRO_MAX_TREASURE; i++) + _vm->drawStr(19 - i, 11, kColorDefault, (const char *)IDS_TRO_NAME_TREASURE[i]); + + _vm->_gfx->doUpdate(); + + pressAnyKey(); +} + +void Troll::intro() { + // sierra on-line presents + _vm->clearScreen(0x2F); + _vm->drawStr(9, 10, kColorDefault, IDS_TRO_INTRO_0); + _vm->drawStr(14, 15, kColorDefault, IDS_TRO_INTRO_1); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(3200); + + // Draw logo + drawPic(45, false, true); + _vm->_gfx->doUpdate(); + + // wait for keypress and alternate message + waitAnyKeyIntro(); + + // have you played this game before? + _vm->drawStr(22, 3, kColorDefault, IDS_TRO_INTRO_4); + _vm->drawStr(23, 6, kColorDefault, IDS_TRO_INTRO_5); + _vm->_gfx->doUpdate(); + + if (!_vm->getSelection(kSelYesNo)) + tutorial(); + + credits(); +} + +void Troll::gameOver() { + char szMoves[40]; + + _vm->clearScreen(0x0f); // hack + + _vm->clearTextArea(); + //DrawPic(0); + + _vm->clearTextArea(); + //DrawPic(0); + + sprintf(szMoves, IDS_TRO_GAMEOVER_0, _moves); + _vm->drawStr(21, 1, kColorDefault, szMoves); + _vm->drawStr(22, 1, kColorDefault, IDS_TRO_GAMEOVER_1); + _vm->_gfx->doUpdate(); + pressAnyKey(); +} + +int Troll::drawRoom(char *menu) { + int n; + + drawPic(_currentRoom - 1, false, true); + _vm->_gfx->doUpdate(); + + // TODO: Troll + + char tmp[10]; + strncat(menu, (char*)_gameData + IDO_TRO_LOCMESSAGES + _locationDescIndex * 39, 39); + + for (int i = 0; i < 3; i++) { + if (_roomDescs[_currentRoom - 1].options[i]) { + sprintf(tmp, "\n %d.", i); + strcat(menu, tmp); + + strncat(menu, (char *)_gameData + _options[_roomDescs[_currentRoom - 1].options[i]], 35); + + n = i + 1; + } + } + + return n; +} + +void Troll::gameLoop() { + bool done = false; + char menu[160+5]; + int currentOption, numberOfOptions; + + _moves = 0; + _currentRoom = 1; + _treasuresLeft = IDI_TRO_MAX_TREASURE; + _haveFlashlight = false; + _locationDescIndex = 0; + + while (!done) { + *menu = 0; + + currentOption = 0; + + numberOfOptions = drawRoom(menu); + + getMenuSel(menu, ¤tOption, numberOfOptions); + _moves++; + + switch(_roomDescs[_currentRoom - 1].optionTypes[currentOption]) { + case IDI_TRO_SEL_OPTION_1: + break; + case IDI_TRO_SEL_OPTION_2: + break; + case IDI_TRO_SEL_OPTION_3: + break; + case OT_UNKN: + break; + } + } + +} + +void Troll::fillOffsets() { + int i; + + for (i = 0; i < IDI_TRO_PICNUM; i++) + _pictureOffsets[i] = READ_LE_UINT16(_gameData + IDO_TRO_PIC_START + i * 2); + + for (i = 0; i < IDI_TRO_NUM_OPTIONS; i++) + _options[i] = READ_LE_UINT16(_gameData + IDO_TRO_OPTIONS + i * 2); +} + +void Troll::fillRoomDescs() { + int start = READ_LE_UINT16(_gameData + IDO_TRO_ROOMDESCS); + int ptr; + int j; + + for (int i = 0; i < IDI_TRO_NUM_ROOMDESCS; i++) { + ptr = READ_LE_UINT16(_gameData + start); + + for (j = 0; j < 3; j++) + _roomDescs[i].options[j] = _gameData[ptr++]; + + for (j = 0; j < 3; j++) { + switch (_gameData[ptr++]) { + case 0: + _roomDescs[i].optionTypes[j] = OT_GO; + break; + case 1: + _roomDescs[i].optionTypes[j] = OT_GET; + break; + case 2: + _roomDescs[i].optionTypes[j] = OT_WIN; + break; + case 3: + _roomDescs[i].optionTypes[j] = OT_UNKN; + break; + default: + error("Bad data @ (%x) %d", ptr - 1, i); + } + } + + for (j = 0; j < 3; j++) + _roomDescs[i].roomDescIndex[j] = _gameData[ptr++]; + + start += 2; + } +} + +// Init + +void Troll::init() { + _vm->_picture->setPictureVersion(AGIPIC_V15); + //SetScreenPar(320, 200, (char*)ibm_fontdata); + + Common::File infile; + if (!infile.open(IDA_TRO_BINNAME)) + return; + + _gameData = (byte *)malloc(infile.size()); + infile.seek(IDO_TRO_DATA_START); + infile.read(_gameData, infile.size() - IDO_TRO_DATA_START); + infile.close(); + + fillOffsets(); + fillRoomDescs(); +} + +void Troll::run() { + intro(); + + gameLoop(); + + gameOver(); +} + +} // end of namespace Agi diff --git a/engines/agi/preagi_troll.h b/engines/agi/preagi_troll.h new file mode 100644 index 0000000000..ef458afb41 --- /dev/null +++ b/engines/agi/preagi_troll.h @@ -0,0 +1,197 @@ +/* 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 AGI_PREAGI_TROLL_H +#define AGI_PREAGI_TROLL_H + +#include "agi/agi.h" + +namespace Agi { + +// strings + +#define IDS_TRO_DISK "ERROR ERROR !" +#define IDS_TRO_PATH_PIC "%s" + +#define IDS_TRO_PRESSANYKEY "PRESS ANY KEY TO CONTINUE:" + +#define IDS_TRO_INTRO_0 "SIERRA ON-LINE INC." +#define IDS_TRO_INTRO_1 "Presents :" +#define IDS_TRO_INTRO_2 "Copyright 1984 Sierra On-Line Inc." +#define IDS_TRO_INTRO_3 " Press any key to continue. " +#define IDS_TRO_INTRO_4 "HAVE YOU PLAYED THIS GAME BEFORE ?" +#define IDS_TRO_INTRO_5 "PRESS <Y> OR <N>" + +#define IDS_TRO_TUTORIAL_0 " First press the <space bar>.\n 1. Turn the screen GREEN.\n 2. Turn the screen BLACK.\n *3. SEE a SURPRISE, and then more." +#define IDS_TRO_TUTORIAL_1 " Press <return> to make your choice.\n 1. Turn the screen GREEN.\n 2. Turn the screen BLACK.\n 3. SEE a SURPRISE, and then more." +//#define IDS_TRO_TUTORIAL_0 "First press the <space bar>." +//#define IDS_TRO_TUTORIAL_1 "1. Turn the screen GREEN." +//#define IDS_TRO_TUTORIAL_2 "2. Turn the screen BLACK." +//#define IDS_TRO_TUTORIAL_3 "3. SEE a SURPRISE, and then more." +//#define IDS_TRO_TUTORIAL_4 "Press <return> to make your choice." +#define IDS_TRO_TUTORIAL_5 "Would you like more practice ?" +#define IDS_TRO_TUTORIAL_6 "Press <Y> for yes, <N> for no." +#define IDS_TRO_TUTORIAL_7 "The evil TROLL has hidden all the" +#define IDS_TRO_TUTORIAL_8 "Treasures of MARK, the Dwarf King." +#define IDS_TRO_TUTORIAL_9 "Help KING MARK find his Treasures." +#define IDS_TRO_TUTORIAL_10 "You can't take a Treasure if the TROLL" +#define IDS_TRO_TUTORIAL_11 "is in the same picture as the Treasure." +#define IDS_TRO_TUTORIAL_12 "To make the TROLL go away you have to" +#define IDS_TRO_TUTORIAL_13 "make the picture change." +#define IDS_TRO_TUTORIAL_14 "During the game see the Treasures you" +#define IDS_TRO_TUTORIAL_15 "have already found by pressing <F>." +#define IDS_TRO_TUTORIAL_16 "During the game you can turn the sound" +#define IDS_TRO_TUTORIAL_17 "on or off by pressing the <S> key " +#define IDS_TRO_TUTORIAL_18 "while holding down the <Ctrl> key." +#define IDS_TRO_TUTORIAL_19 "The TROLL has hidden these Treasures:" + +#define IDS_TRO_CREDITS_0 "Prepare to enter the world of . . ." +#define IDS_TRO_CREDITS_1 "TROLL'S TALE (tm)" +#define IDS_TRO_CREDITS_2 "------------" +#define IDS_TRO_CREDITS_3 "Written by MIKE MACCHESNEY" +#define IDS_TRO_CREDITS_4 "Conversion by PETER OLIPHANT" +#define IDS_TRO_CREDITS_5 "Graphic Art by DOUG MACNEILL" +#define IDS_TRO_CREDITS_6 "Original Version by AL LOWE" + +#define IDS_TRO_TREASURE_0 "TREASURES FOUND" +#define IDS_TRO_TREASURE_1 "---------------" +#define IDS_TRO_TREASURE_2 "NONE" +#define IDS_TRO_TREASURE_3 "THERE ARE STILL" +#define IDS_TRO_TREASURE_4 "%d TREASURES TO FIND" +#define IDS_TRO_TREASURE_5 "%d TREASURE TO FIND" +#define IDS_TRO_TREASURE_6 "YOU HAVE FOUND ALL OF THE TREASURES!!" +#define IDS_TRO_TREASURE_7 "THERE'S ONLY ONE MORE TREASURE TO FIND." +#define IDS_TRO_TREASURE_8 "GREAT!! YOU HAVE FOUND EVERY TREASURE." +#define IDS_TRO_TREASURE_9 "TAKE THE TREASURES TO THE GUARD." + +#define IDS_TRO_GAMEOVER_0 "You took %d moves to complete TROLL'S" +#define IDS_TRO_GAMEOVER_1 "TALE. Do you think you can do better?" + +const char IDS_TRO_NAME_TREASURE[][16] = { + " FLASHLIGHT ", " BAG OF GOLD ", " BOX OF JEWELS ", " DIAMOND RING ", + " CANDY SUCKER ", "DOLLAR AND CENT", " FIDDLE ", "BAG OF PENNIES ", + " TREASURE CHEST", " PENNY ", " SILVER CUP ", " NECKLACE ", + " SHELL ", " GOLD BRICK ", " GIFT ", " POT OF MONEY " +}; + +// picture + +#define IDI_TRO_PICNUM 47 + +#define IDI_TRO_PIC_WIDTH 160 +#define IDI_TRO_PIC_HEIGHT 168 +#define IDI_TRO_PIC_X0 0 +#define IDI_TRO_PIC_Y0 0 +#define IDI_TRO_PIC_FLAGS IDF_AGI_PIC_V15 + +// max values + +#define IDI_TRO_MAX_TREASURE 16 +#define IDI_TRO_MAX_OPTION 3 + +#define IDI_TRO_SEL_OPTION_1 0 +#define IDI_TRO_SEL_OPTION_2 1 +#define IDI_TRO_SEL_OPTION_3 2 + +#define IDI_TRO_MAX_ROW_PIC 21 + +#define IDI_TRO_NUM_ROOMDESCS 65 +#define IDI_TRO_NUM_OPTIONS 129 + +// offsets + +#define IDA_TRO_BINNAME "troll.exe" + +#define IDO_TRO_DATA_START 0x1960 +#define IDO_TRO_PIC_START 0x3EF5 +#define IDO_TRO_LOCMESSAGES 0x1F7C +#define IDO_TRO_ROOMDESCS 0x0082 +#define IDO_TRO_OPTIONS 0x0364 + +enum OptionType { + OT_GO, + OT_GET, + OT_WIN, + OT_UNKN +}; + +struct RoomDesc { + int options[3]; + OptionType optionTypes[3]; + int roomDescIndex[3]; +}; + +class Troll { + friend class PreAgiEngine; +public: + Troll(PreAgiEngine *vm); + + void init(); + void run(); + +private: + int _currentRoom; + int _moves; + int _treasuresLeft; + int _locationDescIndex; + int _numberOfOptions; + + bool _haveFlashlight; + + RoomDesc _roomDescs[IDI_TRO_NUM_ROOMDESCS]; + int _options[IDI_TRO_NUM_OPTIONS]; + + byte *_gameData; + + PreAgiEngine *_vm; + + void intro(); + void drawPic(int iPic, bool f3IsCont, bool clear); + void gameLoop(); + void gameOver(); + void tutorial(); + void credits(); + + void inventory(); + + int drawRoom(char *menu); + + void pressAnyKey(); + void waitAnyKeyIntro(); + + void getMenuSel(const char*, int*, int); + + void drawMenu(const char *szMenu, int iSel); + + void fillOffsets(); + void fillRoomDescs(); + +private: + int _pictureOffsets[IDI_TRO_PICNUM]; +}; + +} // End of namespace Agi + +#endif diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp new file mode 100644 index 0000000000..8d60f0861e --- /dev/null +++ b/engines/agi/preagi_winnie.cpp @@ -0,0 +1,1127 @@ +/* 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 "agi/preagi.h" +#include "agi/preagi_winnie.h" +#include "agi/graphics.h" + +#include "graphics/cursorman.h" + +#include "common/events.h" +#include "common/savefile.h" + +namespace Agi { + +// default attributes +#define IDA_DEFAULT 0x0F +#define IDA_DEFAULT_REV 0xF0 + +void Winnie::initEngine() { + //SetScreenPar(320, 200, (char*)ibm_fontdata); + //SetMenuPars(21, 21, IDS_WTP_SELECTION); +} + +void Winnie::initVars() { + memset(&game, 0, sizeof(game)); + game.fSound = 1; + game.nObjMiss = IDI_WTP_MAX_OBJ_MISSING; + game.nObjRet = 0; + game.fGame[0] = 1; + game.fGame[1] = 1; + room = IDI_WTP_ROOM_HOME; + + mist = -1; + doWind = false; + winnie_event = false; +} + +void Winnie::readRoom(int iRoom, uint8 *buffer, int buflen) { + char szFile[256] = {0}; + sprintf(szFile, IDS_WTP_PATH_ROOM, iRoom); + Common::File file; + if (!file.open(szFile)) + return; + uint32 filelen = file.size(); + memset(buffer, 0, sizeof(buffer)); + file.read(buffer, filelen); + file.close(); +} + +void Winnie::readObj(int iObj, uint8 *buffer, int buflen) { + char szFile[256] = {0}; + sprintf(szFile, IDS_WTP_PATH_OBJ, iObj); + Common::File file; + if (!file.open(szFile)) + return; + uint32 filelen = file.size(); + memset(buffer, 0, sizeof(buffer)); + file.read(buffer, filelen); + file.close(); +} + +void Winnie::randomize() { + int iObj = 0; + int iRoom = 0; + bool done; + + for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) { + done = false; + while (!done) { + iObj = _vm->rnd(IDI_WTP_MAX_OBJ - 1) + 2; + done = true; + for (int j = 0; j < IDI_WTP_MAX_OBJ_MISSING; j++) { + if (game.iUsedObj[j] == iObj) { + done = false; + break; + } + } + } + + game.iUsedObj[i] = iObj; + + done = false; + while (!done) { + iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL) + 1; + done = true; + for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) { + if (game.iObjRoom[j] == iRoom) { + done = false; + break; + } + } + } + + game.iObjRoom[iObj] = iRoom; + } +} + +void Winnie::intro() { + drawPic(IDS_WTP_FILE_LOGO); + _vm->printStr(IDS_WTP_INTRO_0); + _vm->_system->delayMillis(0x640); + drawPic(IDS_WTP_FILE_TITLE); + _vm->printStr(IDS_WTP_INTRO_1); + _vm->_system->delayMillis(0x640); + //if (!Winnie_PlaySound(IDI_WTP_SND_POOH_0)) return; + //if (!Winnie_PlaySound(IDI_WTP_SND_POOH_1)) return; + //if (!Winnie_PlaySound(IDI_WTP_SND_POOH_2)) return; +} + +int Winnie::getObjInRoom(int iRoom) { + for (int iObj = 1; iObj < IDI_WTP_MAX_ROOM_OBJ; iObj++) + if (game.iObjRoom[iObj] == iRoom) + return iObj; + return 0; +} + +#define setTakeDrop() {\ + if (getObjInRoom(room))\ + fCanSel[IDI_WTP_SEL_TAKE] = true;\ + else\ + fCanSel[IDI_WTP_SEL_TAKE] = false;\ + if (game.iObjHave)\ + fCanSel[IDI_WTP_SEL_DROP] = true;\ + else\ + fCanSel[IDI_WTP_SEL_DROP] = false;\ +} + +void Winnie::setFlag(int iFlag) { + game.fGame[iFlag] = 1; +} + +void Winnie::clearFlag(int iFlag) { + game.fGame[iFlag] = 0; +} + +int Winnie::parser(int pc, int index, uint8 *buffer) { + WTP_ROOM_HDR hdr; + int startpc = pc; + int8 opcode; + int iNewRoom = 0; + + int iSel, iDir, iBlock; + int fCanSel[IDI_WTP_SEL_LAST + 1]; + char szMenu[121] = {0}; + bool done; + int fBlock; + + // extract header from buffer + memcpy(&hdr, buffer, sizeof(WTP_ROOM_HDR)); + + for (;;) { + pc = startpc; + + // check if block is to be run + + iBlock = *(buffer + pc++); + if (iBlock == 0) + return IDI_WTP_PAR_OK; + + fBlock = *(buffer + pc++); + if (game.fGame[iBlock] != fBlock) + return IDI_WTP_PAR_OK; + + // extract text from block + + opcode = *(buffer + pc); + switch(opcode) { + case 0: + case IDO_WTP_OPTION_0: + case IDO_WTP_OPTION_1: + case IDO_WTP_OPTION_2: + // clear fCanSel block + memset(fCanSel, 0, sizeof(fCanSel)); + + // check if NSEW directions should be displayed + if (hdr.roomNew[0]) + fCanSel[IDI_WTP_SEL_NORTH] = fCanSel[IDI_WTP_SEL_SOUTH] = + fCanSel[IDI_WTP_SEL_EAST] = fCanSel[IDI_WTP_SEL_WEST] = true; + + // check if object in room or player carrying one + setTakeDrop(); + + // check which rows have a menu option + for (iSel = 0; iSel < IDI_WTP_MAX_OPTION; iSel++) { + opcode = *(buffer + pc++); + if (opcode) { + fCanSel[opcode - IDO_WTP_OPTION_0] = true; + fCanSel[iSel + IDI_WTP_SEL_REAL_OPT_1] = opcode - 0x14; + } + } + + // extract menu string + strcpy(szMenu, (char *)(buffer + pc)); + _vm->XOR80(szMenu); + break; + default: + // print description + _vm->printStrXOR((char *)(buffer + pc)); + if (getSelOkBack()) + return IDI_WTP_PAR_OK; + else + return IDI_WTP_PAR_BACK; + } + + // input handler + + done = false; + while (!done) { + // run wind if it's time + if (doWind) + wind(); + + // get menu selection + getMenuSel(szMenu, &iSel, fCanSel); + + if (++game.nMoves == IDI_WTP_MAX_MOVES_UNTIL_WIND) + doWind = true; + + if (winnie_event && (room <= IDI_WTP_MAX_ROOM_TELEPORT)) { + if (!tigger_mist) { + tigger_mist = 1; + //Winnie_Tigger(); + } else { + tigger_mist = 0; + //Winnie_Mist(); + } + winnie_event = false; + return IDI_WTP_PAR_GOTO; + } + + // process selection + switch(iSel) { + case IDI_WTP_SEL_HOME: + switch(room) { + case IDI_WTP_ROOM_HOME: + case IDI_WTP_ROOM_MIST: + case IDI_WTP_ROOM_TIGGER: + break; + default: + room = IDI_WTP_ROOM_HOME; + return IDI_WTP_PAR_GOTO; + } + break; + case IDI_WTP_SEL_BACK: + return IDI_WTP_PAR_BACK; + case IDI_WTP_SEL_OPT_1: + case IDI_WTP_SEL_OPT_2: + case IDI_WTP_SEL_OPT_3: + done = true; + break; + case IDI_WTP_SEL_NORTH: + case IDI_WTP_SEL_SOUTH: + case IDI_WTP_SEL_EAST: + case IDI_WTP_SEL_WEST: + iDir = iSel - IDI_WTP_SEL_NORTH; + if (hdr.roomNew[iDir] == IDI_WTP_ROOM_NONE) { + _vm->printStr(IDS_WTP_CANT_GO); + _vm->waitAnyKeyChoice(); + } else { + room = hdr.roomNew[iDir]; + return IDI_WTP_PAR_GOTO; + } + break; + case IDI_WTP_SEL_TAKE: + takeObj(room); + setTakeDrop(); + break; + case IDI_WTP_SEL_DROP: + dropObj(room); + setTakeDrop(); + break; + } + } + + // jump to the script block of the selected option + pc = hdr.opt[index].ofsOpt[iSel] - IDI_WTP_OFS_ROOM; + opcode = *(buffer + pc); + if (!opcode) pc++; + + // process script + do { + opcode = *(buffer + pc++); + switch(opcode) { + case IDO_WTP_GOTO_ROOM: + opcode = *(buffer + pc++); + iNewRoom = opcode; + break; + case IDO_WTP_PRINT_MSG: + opcode = *(buffer + pc++); + printRoomStr(room, opcode); + _vm->waitAnyKeyChoice(); + break; + case IDO_WTP_PRINT_STR: + opcode = *(buffer + pc++); + printRoomStr(room, opcode); + break; + case IDO_WTP_DROP_OBJ: + opcode = *(buffer + pc++); + opcode = -1; + dropObjRnd(); + break; + case IDO_WTP_FLAG_CLEAR: + opcode = *(buffer + pc++); + clearFlag(opcode); + break; + case IDO_WTP_FLAG_SET: + opcode = *(buffer + pc++); + setFlag(opcode); + break; + case IDO_WTP_GAME_OVER: + gameOver(); + break; + case IDO_WTP_WALK_MIST: + mist--; + if (!mist) { + room = _vm->rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1; + return IDI_WTP_PAR_GOTO; + } + break; + case IDO_WTP_PLAY_SOUND: + opcode = *(buffer + pc++); + //Winnie_PlaySound((ENUM_WTP_SOUND)opcode); + break; + case IDO_WTP_SAVE_GAME: + saveGame(); + room = IDI_WTP_ROOM_HOME; + return IDI_WTP_PAR_GOTO; + case IDO_WTP_LOAD_GAME: + loadGame(); + room = IDI_WTP_ROOM_HOME; + return IDI_WTP_PAR_GOTO; + case IDO_WTP_OWL_HELP: + opcode = *(buffer + pc++); + showOwlHelp(); + break; + case IDO_WTP_GOTO_RND: + room = _vm->rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1; + return IDI_WTP_PAR_GOTO; + default: + opcode = 0; + break; + } + } while (opcode); + + if (iNewRoom) { + room = iNewRoom; + return IDI_WTP_PAR_GOTO; + } + + if (iBlock == 1) + return IDI_WTP_PAR_OK; + } +} + +void Winnie::keyHelp() { + //Winnie_PlaySound(IDI_WTP_SND_KEYHELP); + _vm->printStr(IDS_WTP_HELP_0); + _vm->waitAnyKeyChoice(); + _vm->printStr(IDS_WTP_HELP_1); + _vm->waitAnyKeyChoice(); +} + +void Winnie::inventory() { + char szMissing[41] = {0}; + + if (game.iObjHave) + printObjStr(game.iObjHave, IDI_WTP_OBJ_TAKE); + else { + _vm->clearTextArea(); + _vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, IDS_WTP_INVENTORY_0); + } + + sprintf(szMissing, IDS_WTP_INVENTORY_1, game.nObjMiss); + _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, szMissing); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); + _vm->waitAnyKeyChoice(); +} + +void Winnie::printObjStr(int iObj, int iStr) { + WTP_OBJ_HDR hdr; + uint8 *buffer = (uint8 *)malloc(2048); + + readObj(iObj, buffer, 2048); + memcpy(&hdr, buffer, sizeof(hdr)); + _vm->printStrXOR((char *)(buffer + hdr.ofsStr[iStr] - IDI_WTP_OFS_OBJ)); + + free(buffer); +} + +bool Winnie::isRightObj(int iRoom, int iObj, int *iCode) { + WTP_ROOM_HDR roomhdr; + WTP_OBJ_HDR objhdr; + uint8 *roomdata = new uint8[4096]; + uint8 *objdata = new uint8[2048]; + + readRoom(iRoom, roomdata, 4096); + memcpy(&roomhdr, roomdata, sizeof(WTP_ROOM_HDR)); + readObj(iObj, objdata, 2048); + memcpy(&objhdr, objdata, sizeof(WTP_OBJ_HDR)); + + delete [] roomdata; + delete [] objdata; + + *iCode = objhdr.objId; + + if (objhdr.objId == 11) objhdr.objId = 34; + + if (roomhdr.objId == objhdr.objId) + return true; + else + return false; +} + +void Winnie::takeObj(int iRoom) { + if (game.iObjHave) { + // player is already carrying an object, can't take + _vm->printStr(IDS_WTP_CANT_TAKE); + _vm->waitAnyKeyChoice(); + } else { + // take object + int iObj = getObjInRoom(iRoom); + game.iObjHave = iObj; + game.iObjRoom[iObj] = 0; + + _vm->printStr(IDS_WTP_OK); + //Winnie_PlaySound(IDI_WTP_SND_TAKE); + + drawRoomPic(); + + // print object "take" string + printObjStr(game.iObjHave, IDI_WTP_OBJ_TAKE); + _vm->waitAnyKeyChoice(); + + // HACK WARNING + if (iObj == 18) { + game.fGame[0x0d] = 1; + } + } +} + +void Winnie::dropObj(int iRoom) { + int iCode; + + if (getObjInRoom(iRoom)) { + // there already is an object in the room, can't drop + _vm->printStr(IDS_WTP_CANT_DROP); + _vm->waitAnyKeyChoice(); + } else { + // HACK WARNING + if (game.iObjHave == 18) { + game.fGame[0x0d] = 0; + } + + if (isRightObj(iRoom, game.iObjHave, &iCode)) { + // object has been dropped in the right place + _vm->printStr(IDS_WTP_OK); + _vm->waitAnyKeyChoice(); + //Winnie_PlaySound(IDI_WTP_SND_DROP_OK); + printObjStr(game.iObjHave, IDI_WTP_OBJ_DROP); + _vm->waitAnyKeyChoice(); + + // increase amount of objects returned, decrease amount of objects missing + game.nObjMiss--; + game.nObjRet++; + + // xor the dropped object with 0x80 to signify it has been dropped in the right place + for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) { + if (game.iUsedObj[i] == game.iObjHave) { + game.iUsedObj[i] ^= 0x80; + break; + } + } + + // set flag according to dropped object's id + game.fGame[iCode] = 1; + + // player is carrying nothing + game.iObjHave = 0; + + if (!game.nObjMiss) { + // all objects returned, tell player to find party + //Winnie_PlaySound(IDI_WTP_SND_FANFARE); + _vm->printStr(IDS_WTP_GAME_OVER_0); + _vm->waitAnyKeyChoice(); + _vm->printStr(IDS_WTP_GAME_OVER_1); + _vm->waitAnyKeyChoice(); + } + } else { + // drop object in the given room + game.iObjRoom[game.iObjHave] = iRoom; + + // object has been dropped in the wrong place + _vm->printStr(IDS_WTP_WRONG_PLACE); + _vm->waitAnyKeyChoice(); + //Winnie_PlaySound(IDI_WTP_SND_DROP); + drawRoomPic(); + _vm->printStr(IDS_WTP_WRONG_PLACE); + _vm->waitAnyKeyChoice(); + + // print object description + printObjStr(game.iObjHave, IDI_WTP_OBJ_DESC); + _vm->waitAnyKeyChoice(); + + game.iObjHave = 0; + } + } +} + +void Winnie::dropObjRnd() { + if (!game.iObjHave) + return; + + int iRoom = 0; + bool done = false; + + while (!done) { + iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL); + done = true; + if (iRoom == room) + done = false; + for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) { + if (game.iObjRoom[j] == iRoom) { + done = false; + } + } + } + + game.iObjRoom[game.iObjHave] = iRoom; + game.iObjHave = 0; +} + +void Winnie::wind() { + int iRoom = 0; + bool done; + + doWind = 0; + game.nMoves = 0; + if (!game.nObjMiss) + return; + + _vm->printStr(IDS_WTP_WIND_0); + //Winnie_PlaySound(IDI_WTP_SND_WIND_0); + _vm->waitAnyKeyChoice(); + _vm->printStr(IDS_WTP_WIND_1); + //Winnie_PlaySound(IDI_WTP_SND_WIND_0); + _vm->waitAnyKeyChoice(); + + dropObjRnd(); + + // randomize positions of objects at large + for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) { + if (!(game.iUsedObj[i] & IDI_XOR_KEY)) { + done = false; + while (!done) { + iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL); + done = true; + for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) { + if (game.iObjRoom[j] == iRoom) { + done = false; + } + } + } + game.iObjRoom[game.iUsedObj[i]] = iRoom; + } + } +} + +void Winnie::showOwlHelp() { + if (game.iObjHave) { + _vm->printStr(IDS_WTP_OWL_0); + _vm->waitAnyKeyChoice(); + printObjStr(game.iObjHave, IDI_WTP_OBJ_HELP); + _vm->waitAnyKeyChoice(); + } + if (getObjInRoom(room)) { + _vm->printStr(IDS_WTP_OWL_0); + _vm->waitAnyKeyChoice(); + printObjStr(getObjInRoom(room), IDI_WTP_OBJ_HELP); + _vm->waitAnyKeyChoice(); + } +} + + +void Winnie::drawMenu(char *szMenu, int iSel, int fCanSel[]) { + int iRow = 0, iCol = 0; + + _vm->clearTextArea(); + _vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, szMenu); + + if (fCanSel[IDI_WTP_SEL_NORTH]) + _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_NSEW, IDA_DEFAULT, IDS_WTP_NSEW); + if (fCanSel[IDI_WTP_SEL_TAKE]) + _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_TAKE, IDA_DEFAULT, IDS_WTP_TAKE); + if (fCanSel[IDI_WTP_SEL_DROP]) + _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_DROP, IDA_DEFAULT, IDS_WTP_DROP); + + switch(iSel) { + case IDI_WTP_SEL_OPT_1: + iRow = IDI_WTP_ROW_OPTION_1; + iCol = IDI_WTP_COL_OPTION; + break; + case IDI_WTP_SEL_OPT_2: + iRow = IDI_WTP_ROW_OPTION_2; + iCol = IDI_WTP_COL_OPTION; + break; + case IDI_WTP_SEL_OPT_3: + iRow = IDI_WTP_ROW_OPTION_3; + iCol = IDI_WTP_COL_OPTION; + break; + case IDI_WTP_SEL_NORTH: + iRow = IDI_WTP_ROW_OPTION_4; + iCol = IDI_WTP_COL_NORTH; + break; + case IDI_WTP_SEL_SOUTH: + iRow = IDI_WTP_ROW_OPTION_4; + iCol = IDI_WTP_COL_SOUTH; + break; + case IDI_WTP_SEL_EAST: + iRow = IDI_WTP_ROW_OPTION_4; + iCol = IDI_WTP_COL_EAST; + break; + case IDI_WTP_SEL_WEST: + iRow = IDI_WTP_ROW_OPTION_4; + iCol = IDI_WTP_COL_WEST; + break; + case IDI_WTP_SEL_TAKE: + iRow = IDI_WTP_ROW_OPTION_4; + iCol = IDI_WTP_COL_TAKE; + break; + case IDI_WTP_SEL_DROP: + iRow = IDI_WTP_ROW_OPTION_4; + iCol = IDI_WTP_COL_DROP; + break; + } + _vm->drawStr(iRow, iCol - 1, IDA_DEFAULT, IDS_WTP_SELECTION); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop +} + +void Winnie::incMenuSel(int *iSel, int fCanSel[]) { + do { + *iSel += 1; + if (*iSel > IDI_WTP_SEL_DROP) *iSel = IDI_WTP_SEL_OPT_1; + } while(!fCanSel[*iSel]); +} + +void Winnie::decMenuSel(int *iSel, int fCanSel[]) { + do { + *iSel -= 1; + if (*iSel < IDI_WTP_SEL_OPT_1) *iSel = IDI_WTP_SEL_DROP; + } while(!fCanSel[*iSel]); +} + +void Winnie::getMenuMouseSel(int *iSel, int fCanSel[], int x, int y) { + switch(y) { + case IDI_WTP_ROW_OPTION_1: + if (fCanSel[IDI_WTP_SEL_OPT_1]) *iSel = IDI_WTP_SEL_OPT_1; + break; + case IDI_WTP_ROW_OPTION_2: + if (fCanSel[IDI_WTP_SEL_OPT_2]) *iSel = IDI_WTP_SEL_OPT_2; + break; + case IDI_WTP_ROW_OPTION_3: + if (fCanSel[IDI_WTP_SEL_OPT_3]) *iSel = IDI_WTP_SEL_OPT_3; + break; + case IDI_WTP_ROW_OPTION_4: + if (fCanSel[IDI_WTP_SEL_NORTH] && (x > IDI_WTP_COL_NORTH - 1) && (x < 6)) *iSel = IDI_WTP_SEL_NORTH; + if (fCanSel[IDI_WTP_SEL_SOUTH] && (x > IDI_WTP_COL_SOUTH - 1) && (x < 13)) *iSel = IDI_WTP_SEL_SOUTH; + if (fCanSel[IDI_WTP_SEL_EAST] && (x > IDI_WTP_COL_EAST - 1) && (x < 19)) *iSel = IDI_WTP_SEL_EAST; + if (fCanSel[IDI_WTP_SEL_WEST] && (x > IDI_WTP_COL_WEST - 1) && (x < 25)) *iSel = IDI_WTP_SEL_WEST; + if (fCanSel[IDI_WTP_SEL_TAKE] && (x > IDI_WTP_COL_TAKE - 1) && (x < 33)) *iSel = IDI_WTP_SEL_TAKE; + if (fCanSel[IDI_WTP_SEL_DROP] && (x > IDI_WTP_COL_DROP - 1) && (x < 39)) *iSel = IDI_WTP_SEL_DROP; + break; + } +} + +#define makeSel() {\ + if (fCanSel[*iSel]) {\ + return;\ + } else {\ + keyHelp();\ + clrMenuSel(iSel, fCanSel);\ + }\ +} + +void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { + Common::Event event; + int x, y; + + clrMenuSel(iSel, fCanSel); + drawMenu(szMenu, *iSel, fCanSel); + + // Show the mouse cursor for the menu + CursorMan.showMouse(true); + + for (;;) { + // check if tigger/mist is to be triggered +// if (something) +// event = true; + + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch(event.type) { + case Common::EVENT_QUIT: + _vm->_system->quit(); + break; + case Common::EVENT_MOUSEMOVE: + x = event.mouse.x / 8; + y = event.mouse.y / 8; + getMenuMouseSel(iSel, fCanSel, x, y); + + // Change cursor + if (fCanSel[IDI_WTP_SEL_NORTH] && (event.mouse.x >= 20 && event.mouse.x <= (IDI_WTP_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= 0 && event.mouse.y <= 10)) { + _vm->_gfx->setCursorPalette(true); + } else if (fCanSel[IDI_WTP_SEL_SOUTH] && (event.mouse.x >= 20 && event.mouse.x <= (IDI_WTP_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= IDI_WTP_PIC_HEIGHT - 10 && event.mouse.y <= IDI_WTP_PIC_HEIGHT)) { + _vm->_gfx->setCursorPalette(true); + } else if (fCanSel[IDI_WTP_SEL_WEST] && (event.mouse.y >= 0 && event.mouse.y <= IDI_WTP_PIC_HEIGHT) && + (event.mouse.x >= 20 && event.mouse.x <= 30)) { + _vm->_gfx->setCursorPalette(true); + } else if (fCanSel[IDI_WTP_SEL_EAST] && (event.mouse.y >= 0 && event.mouse.y <= IDI_WTP_PIC_HEIGHT) && + (event.mouse.x >= IDI_WTP_PIC_WIDTH * 2 && event.mouse.x <= (IDI_WTP_PIC_WIDTH + 10) * 2)) { + _vm->_gfx->setCursorPalette(true); + } else { + _vm->_gfx->setCursorPalette(false); + } + + break; + case Common::EVENT_LBUTTONUP: + // Click to move + if (fCanSel[IDI_WTP_SEL_NORTH] && (event.mouse.x >= 20 && event.mouse.x <= (IDI_WTP_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= 0 && event.mouse.y <= 10)) { + *iSel = IDI_WTP_SEL_NORTH; + makeSel(); + _vm->_gfx->setCursorPalette(false); + return; + } else if (fCanSel[IDI_WTP_SEL_SOUTH] && (event.mouse.x >= 20 && event.mouse.x <= (IDI_WTP_PIC_WIDTH + 10) * 2) && + (event.mouse.y >= IDI_WTP_PIC_HEIGHT - 10 && event.mouse.y <= IDI_WTP_PIC_HEIGHT)) { + *iSel = IDI_WTP_SEL_SOUTH; + makeSel(); + _vm->_gfx->setCursorPalette(false); + return; + } else if (fCanSel[IDI_WTP_SEL_WEST] && (event.mouse.y >= 0 && event.mouse.y <= IDI_WTP_PIC_HEIGHT) && + (event.mouse.x >= 20 && event.mouse.x <= 30)) { + *iSel = IDI_WTP_SEL_WEST; + makeSel(); + _vm->_gfx->setCursorPalette(false); + return; + } else if (fCanSel[IDI_WTP_SEL_EAST] && (event.mouse.y >= 0 && event.mouse.y <= IDI_WTP_PIC_HEIGHT) && + (event.mouse.x >= IDI_WTP_PIC_WIDTH * 2 && event.mouse.x <= (IDI_WTP_PIC_WIDTH + 10) * 2)) { + *iSel = IDI_WTP_SEL_EAST; + makeSel(); + _vm->_gfx->setCursorPalette(false); + return; + } else { + _vm->_gfx->setCursorPalette(false); + } + + switch(*iSel) { + case IDI_WTP_SEL_OPT_1: + case IDI_WTP_SEL_OPT_2: + case IDI_WTP_SEL_OPT_3: + for (int iSel2 = 0; iSel2 < IDI_WTP_MAX_OPTION; iSel2++) { + if (*iSel == (fCanSel[iSel2 + IDI_WTP_SEL_REAL_OPT_1] - 1)) { + *iSel = iSel2; + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + } + } + break; + default: + if (fCanSel[*iSel]) { + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + } + break; + } + break; + case Common::EVENT_RBUTTONUP: + *iSel = IDI_WTP_SEL_BACK; + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + case Common::EVENT_WHEELUP: + decMenuSel(iSel, fCanSel); + break; + case Common::EVENT_WHEELDOWN: + incMenuSel(iSel, fCanSel); + break; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: + *iSel = IDI_WTP_SEL_HOME; + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + case Common::KEYCODE_BACKSPACE: + *iSel = IDI_WTP_SEL_BACK; + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + case Common::KEYCODE_c: + inventory(); + break; + case Common::KEYCODE_SPACE: + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_DOWN: + incMenuSel(iSel, fCanSel); + break; + case Common::KEYCODE_LEFT: + case Common::KEYCODE_UP: + decMenuSel(iSel, fCanSel); + break; + case Common::KEYCODE_1: + case Common::KEYCODE_2: + case Common::KEYCODE_3: + *iSel = event.kbd.keycode - Common::KEYCODE_1; + if (fCanSel[*iSel + IDI_WTP_SEL_REAL_OPT_1]) { + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + } else { + keyHelp(); + clrMenuSel(iSel, fCanSel); + } + break; + case Common::KEYCODE_n: + *iSel = IDI_WTP_SEL_NORTH; + makeSel(); + break; + case Common::KEYCODE_s: + if (event.kbd.flags & Common::KBD_CTRL) { + //FlipSound(); + } else { + *iSel = IDI_WTP_SEL_SOUTH; + makeSel(); + } + break; + case Common::KEYCODE_e: + *iSel = IDI_WTP_SEL_EAST; + makeSel(); + break; + case Common::KEYCODE_w: + *iSel = IDI_WTP_SEL_WEST; + makeSel(); + break; + case Common::KEYCODE_t: + *iSel = IDI_WTP_SEL_TAKE; + makeSel(); + break; + case Common::KEYCODE_d: + *iSel = IDI_WTP_SEL_DROP; + makeSel(); + break; + case Common::KEYCODE_RETURN: + switch(*iSel) { + case IDI_WTP_SEL_OPT_1: + case IDI_WTP_SEL_OPT_2: + case IDI_WTP_SEL_OPT_3: + for (int iSel2 = 0; iSel2 < IDI_WTP_MAX_OPTION; iSel2++) { + if (*iSel == (fCanSel[iSel2 + IDI_WTP_SEL_REAL_OPT_1] - 1)) { + *iSel = iSel2; + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + } + } + break; + default: + if (fCanSel[*iSel]) { + // Menu selection made, hide the mouse cursor + CursorMan.showMouse(false); + return; + } + break; + } + default: + keyHelp(); + clrMenuSel(iSel, fCanSel); + break; + } + break; + default: + break; + } + + drawMenu(szMenu, *iSel, fCanSel); + } + } +} + +void Winnie::gameLoop() { + WTP_ROOM_HDR hdr; + uint8 *roomdata = new uint8[4096]; + int iBlock; + +phase0: + if (!game.nObjMiss && (room == IDI_WTP_ROOM_PICNIC)) + room = IDI_WTP_ROOM_PARTY; + readRoom(room, roomdata, 4096); + memcpy(&hdr, roomdata, sizeof(WTP_ROOM_HDR)); + drawRoomPic(); +phase1: + if (getObjInRoom(room)) { + printObjStr(getObjInRoom(room), IDI_WTP_OBJ_DESC); + _vm->waitAnyKeyChoice(); + } +phase2: + for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) { + if (parser(hdr.ofsDesc[iBlock] - IDI_WTP_OFS_ROOM, iBlock, roomdata) == IDI_WTP_PAR_BACK) { + goto phase1; + } + } + for (;;) { + for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) { + switch(parser(hdr.ofsBlock[iBlock] - IDI_WTP_OFS_ROOM, iBlock, roomdata)) { + case IDI_WTP_PAR_GOTO: + goto phase0; + break; + case IDI_WTP_PAR_BACK: + goto phase2; + break; + } + } + } + + delete [] roomdata; +} + +void Winnie::drawPic(const char *szName) { + char szFile[256] = {0}; + uint8 *buffer = new uint8[4096]; + + // construct filename + sprintf(szFile, IDS_WTP_PATH, szName); + Common::File file; + if (!file.open(szName)) + return; + uint32 size = file.size(); + file.read(buffer, size); + file.close(); + + _vm->_picture->decodePicture(buffer, size, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _vm->_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + delete [] buffer; +} + +void Winnie::drawObjPic(int iObj, int x0, int y0) { + WTP_OBJ_HDR objhdr; + uint8 *buffer = new uint8[2048]; + + if (!iObj) + return; + + readObj(iObj, buffer, 2048); + memcpy(&objhdr, buffer, sizeof(WTP_OBJ_HDR)); + + _vm->_picture->setOffset(x0, y0); + _vm->_picture->decodePicture(buffer + objhdr.ofsPic - IDI_WTP_OFS_OBJ, 4096, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _vm->_picture->setOffset(0, 0); + _vm->_picture->showPic(10, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); + + delete [] buffer; +} + +void Winnie::drawRoomPic() { + WTP_ROOM_HDR roomhdr; + uint8 *buffer = new uint8[4096]; + int iObj = getObjInRoom(room); + + // clear gfx screen + _vm->_gfx->clearScreen(0); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + // read room picture + readRoom(room, buffer, 4096); + memcpy(&roomhdr, buffer, sizeof(WTP_ROOM_HDR)); + + // draw room picture + _vm->_picture->decodePicture(buffer + roomhdr.ofsPic - IDI_WTP_OFS_ROOM, 4096, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _vm->_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT); + _vm->_gfx->doUpdate(); + _vm->_system->updateScreen(); // TODO: this should go in the game's main loop + + // draw object picture + drawObjPic(iObj, IDI_WTP_PIC_X0 + roomhdr.objX, IDI_WTP_PIC_Y0 + roomhdr.objY); + + delete [] buffer; +} + +bool Winnie::getSelOkBack() { + Common::Event event; + + for (;;) { + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + _vm->_system->quit(); + break; + case Common::EVENT_LBUTTONUP: + return true; + case Common::EVENT_RBUTTONUP: + return false; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + return false; + default: + return true; + } + default: + break; + } + } + } +} +void Winnie::clrMenuSel(int *iSel, int fCanSel[]) { + *iSel = IDI_WTP_SEL_OPT_1; + while(!fCanSel[*iSel]) { + *iSel += 1; + } +} + +void Winnie::printRoomStr(int iRoom, int iStr) { + WTP_ROOM_HDR hdr; + uint8 *buffer = (uint8 *)malloc(4096); + + readRoom(iRoom, buffer, 4096); + memcpy(&hdr, buffer, sizeof(hdr)); + _vm->printStrXOR((char *)(buffer + hdr.ofsStr[iStr - 1] - IDI_WTP_OFS_ROOM)); + + free(buffer); +} + +void Winnie::gameOver() { + // sing the Pooh song forever + for (;;) { + _vm->printStr(IDS_WTP_SONG_0); + //Winnie_PlaySound(IDI_WTP_SND_POOH_0); + _vm->printStr(IDS_WTP_SONG_1); + //Winnie_PlaySound(IDI_WTP_SND_POOH_1); + _vm->printStr(IDS_WTP_SONG_2); + //Winnie_PlaySound(IDI_WTP_SND_POOH_2); + _vm->waitAnyKeyChoice(); + } +} + +void Winnie::saveGame() { + uint8 *buffer = new uint8[sizeof(WTP_SAVE_GAME)]; + memcpy(buffer, &game, sizeof(WTP_SAVE_GAME)); + writeSaveGame(buffer); + delete [] buffer; +} + +void Winnie::loadGame() { + uint8 *buffer = new uint8[sizeof(WTP_SAVE_GAME)]; + readSaveGame(buffer); + memcpy(&game, buffer, sizeof(WTP_SAVE_GAME)); + delete [] buffer; +} + +void Winnie::readSaveGame(uint8 *buffer) { + Common::InSaveFile* infile; + char szFile[256] = {0}; + sprintf(szFile, IDS_WTP_FILE_SAVEGAME); + if (!(infile = _vm->getSaveFileMan()->openForLoading(szFile))) + return; + infile->read(buffer, sizeof(WTP_SAVE_GAME)); + delete infile; +} + +void Winnie::writeSaveGame(uint8 *buffer) { + Common::OutSaveFile* outfile; + char szFile[256] = {0}; + sprintf(szFile, IDS_WTP_FILE_SAVEGAME); + if (!(outfile = _vm->getSaveFileMan()->openForSaving(szFile))) + return; + outfile->write(buffer, sizeof(WTP_SAVE_GAME)); + delete outfile; +} + +Winnie::Winnie(PreAgiEngine* vm) : _vm(vm) { + +} + +void Winnie::init() { + initEngine(); + initVars(); +} + +void Winnie::run() { + randomize(); + intro(); + gameLoop(); +} + +} diff --git a/engines/agi/preagi_winnie.h b/engines/agi/preagi_winnie.h new file mode 100644 index 0000000000..625795d7e1 --- /dev/null +++ b/engines/agi/preagi_winnie.h @@ -0,0 +1,352 @@ +/* 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 AGI_PREAGI_WINNIE_H +#define AGI_PREAGI_WINNIE_H + +#include "agi/agi.h" + +namespace Agi { + +// strings + +#define IDS_WTP_SELECTION ">" + +#define IDS_WTP_PATH_ROOM "rooms\\rm.%02d" +#define IDS_WTP_PATH_OBJ "obj.%02d" +#define IDS_WTP_PATH_SND "snd.%02d" +#define IDS_WTP_PATH "%s" + +#define IDS_WTP_FILE_LOGO "logo.pic" +#define IDS_WTP_FILE_TITLE "title.pic" +#define IDS_WTP_FILE_SAVEGAME "savegame" +#define IDS_WTP_FILE_RND "rnd" + +#define IDS_WTP_DISK_ERROR "There is a problem with your disk drive.Please make sure your Winnie-the-Pooh disk is in the drive correctly." + +#define IDS_WTP_INTRO_0 " PRESENT" +#define IDS_WTP_INTRO_1 " TM designates trademark of\n Sierra On-Line, Inc.\n (c) 1985 Walt Disney Productions" + +#define IDS_WTP_HELP_0 "The <SPACE BAR> moves the pointer. Press <RETURN> when it is by the choice you want. Press the <Backspace> key to see what you just finished reading." +#define IDS_WTP_HELP_1 "Press <C> to see what you are carrying. <Ctrl-S> turns the sound off and on. <ESC> takes you to the playroom (in caseyou get lost or want to save the game)." + +#define IDS_WTP_GAME_OVER_0 "Congratulations!! You did it! You returned everything that was lost. Now,Christopher Robin invites you to a Hero party." +#define IDS_WTP_GAME_OVER_1 "The good news is: YOU are the Hero!! The bad news is: you have to find the party by yourself. Good luck!" + +#define IDS_WTP_OWL_0 "\"For example, that object you are carrying now is interesting. I know I've seen it before. Hmmm. Let me think about this . . .\"" +#define IDS_WTP_OWL_1 "\"You know, this object here beside me isfamiliar. I'm sure I could give you some sort of clue about it. Let me see. . .\"" + +#define IDS_WTP_WIND_0 "Oh, no! The Blustery Wind begins to howl. It has returned, and mixed up all the objects in the Wood." +#define IDS_WTP_WIND_1 "But don't worry. Everyone still has theobjects you returned to them.\n\n (Today must be Winds-day!)" +#define IDS_WTP_TIGGER "\"Hallooooo, there!!!! It's ME, Tigger! Let's BOUNCE!\"" +#define IDS_WTP_MIST "Oh, look out! The mysterious mist is coming in. It gets so thick that you can't see through it. Just keep walkingand it will soon clear up." + +#define IDS_WTP_SONG_0 "Winnie-the-Pooh, Winnie-the-Pooh, Tubby little cubby all stuffed with fluff, He's Winnie-the-Pooh, Winnie-the-Pooh, Willy, nilly, silly, old bear." +#define IDS_WTP_SONG_1 "Deep in the Hundred Acre Wood, Where Christopher Robin plays, You will find the enchanted neighborhoodof Christopher's childhood days." +#define IDS_WTP_SONG_2 "A donkey named Eeyore is his friend, and Kanga and little Roo. There's Rabbit and Piglet and there's Owl But most of all Winnie-the-Pooh!" + +#define IDS_WTP_NSEW "North South East West" +#define IDS_WTP_TAKE "Take" +#define IDS_WTP_DROP "Drop" +#define IDS_WTP_CANT_GO "\nSorry, but you can't go that way." +#define IDS_WTP_CANT_TAKE "You can't take it. You can only carry one object at a time." +#define IDS_WTP_CANT_DROP "You can't drop it. Another object is already here." +#define IDS_WTP_WRONG_PLACE "\nOk, but it doesn't belong here." +#define IDS_WTP_OK "\nOk." + +#define IDS_WTP_INVENTORY_0 "You are carrying nothing." +#define IDS_WTP_INVENTORY_1 "Number of objects still missing: %d" + +// COMMODORE 64 version strings + +#define IDS_WTP_PATH_ROOM_C64 "%sroom%02d" +#define IDS_WTP_PATH_OBJ_C64 "%sobject%02d" +#define IDS_WTP_PATH_SND_C64 "%ssound.obj" +#define IDS_WTP_FILE_SAVEGAME_C64 "saved game" +#define IDS_WTP_DISK_ERROR_C64 "There is a problem with your disk drive.Please make sure your disk is in the drive correctly." +#define IDS_WTP_HELP_0_C64 "The <SPACE BAR> moves the pointer. Press <RETURN> when it is by the choice you want. <F1> brings back what you have already read." +#define IDS_WTP_HELP_1_C64 "<F3> takes you back to the playroom (if you get lost, or want to save the game).<F5> turns the sound off and on. <F7> shows what you're carrying." +#define IDS_WTP_WRONG_PLACE_C64 "\nOk, but this is not the right place." + +// maximum values + +#define IDI_WTP_MAX_OBJ_MISSING 10 + +#define IDI_WTP_MAX_ROOM 62 +#define IDI_WTP_MAX_OBJ 40 +#define IDI_WTP_MAX_SND 14 +#define IDI_WTP_MAX_PIC 2 + +#define IDI_WTP_MAX_ROOM_NORMAL 57 +#define IDI_WTP_MAX_ROOM_TELEPORT 30 +#define IDI_WTP_MAX_ROOM_OBJ 42 +#define IDI_WTP_MAX_BLOCK 4 +#define IDI_WTP_MAX_STR 6 +#define IDI_WTP_MAX_OBJ_STR 4 +#define IDI_WTP_MAX_OBJ_STR_END 2 +#define IDI_WTP_MAX_FLAG 40 +#define IDI_WTP_MAX_OPTION 3 +#define IDI_WTP_MAX_DIR 4 +#define IDI_WTP_MAX_MOVES_UNTIL_WIND 150 + +// positions + +#define IDI_WTP_ROW_MENU 21 +#define IDI_WTP_ROW_OPTION_1 21 +#define IDI_WTP_ROW_OPTION_2 22 +#define IDI_WTP_ROW_OPTION_3 23 +#define IDI_WTP_ROW_OPTION_4 24 + +#define IDI_WTP_COL_MENU 0 +#define IDI_WTP_COL_OPTION 1 +#define IDI_WTP_COL_NSEW 1 +#define IDI_WTP_COL_NORTH 1 +#define IDI_WTP_COL_SOUTH 8 +#define IDI_WTP_COL_EAST 15 +#define IDI_WTP_COL_WEST 21 +#define IDI_WTP_COL_TAKE 29 +#define IDI_WTP_COL_DROP 35 +#define IDI_WTP_COL_PRESENT 17 + +// data file offset modifiers + +#define IDI_WTP_OFS_ROOM 0x5400 +#define IDI_WTP_OFS_OBJ 0x0800 + +// picture + +#define IDI_WTP_PIC_WIDTH 140 +#define IDI_WTP_PIC_HEIGHT 159 +#define IDI_WTP_PIC_X0 10 +#define IDI_WTP_PIC_Y0 0 +#define IDI_WTP_PIC_FLAGS IDF_AGI_PIC_V2 + +// selections + +enum { + IDI_WTP_SEL_HOME = -2, + IDI_WTP_SEL_BACK, + IDI_WTP_SEL_OPT_1, + IDI_WTP_SEL_OPT_2, + IDI_WTP_SEL_OPT_3, + IDI_WTP_SEL_NORTH, + IDI_WTP_SEL_SOUTH, + IDI_WTP_SEL_EAST, + IDI_WTP_SEL_WEST, + IDI_WTP_SEL_TAKE, + IDI_WTP_SEL_DROP, + IDI_WTP_SEL_REAL_OPT_1, + IDI_WTP_SEL_REAL_OPT_2, + IDI_WTP_SEL_REAL_OPT_3 +}; + +#define IDI_WTP_SEL_LAST IDI_WTP_SEL_REAL_OPT_3 + +// rooms + +enum { + IDI_WTP_ROOM_NONE = -1, + IDI_WTP_ROOM_NORTH, + IDI_WTP_ROOM_SOUTH, + IDI_WTP_ROOM_EAST, + IDI_WTP_ROOM_WEST +}; + +#define IDI_WTP_ROOM_HIDE 0 + +#define IDI_WTP_ROOM_PICNIC 2 +#define IDI_WTP_ROOM_HOME 28 +#define IDI_WTP_ROOM_PARTY 58 +#define IDI_WTP_ROOM_MIST 59 +#define IDI_WTP_ROOM_TIGGER 61 + +// sound + +enum ENUM_WTP_SOUND { + IDI_WTP_SND_POOH_0 = 1, + IDI_WTP_SND_TIGGER, + IDI_WTP_SND_TAKE, + IDI_WTP_SND_DROP, + IDI_WTP_SND_DROP_OK, + IDI_WTP_SND_FANFARE, + IDI_WTP_SND_POOH_1, + IDI_WTP_SND_KEYHELP, + IDI_WTP_SND_POOH_2, + IDI_WTP_SND_WIND_0, + IDI_WTP_SND_WIND_1 +}; + +// script opcodes + +#define IDO_WTP_GOTO_ROOM 0x06 +#define IDO_WTP_PRINT_MSG 0x08 +#define IDO_WTP_PRINT_STR 0x0A +#define IDO_WTP_DROP_OBJ 0x0C +#define IDO_WTP_FLAG_CLEAR 0x0E +#define IDO_WTP_FLAG_SET 0x10 +#define IDO_WTP_GAME_OVER 0x12 +#define IDO_WTP_WALK_MIST 0x14 +#define IDO_WTP_PLAY_SOUND 0x16 +#define IDO_WTP_SAVE_GAME 0x18 +#define IDO_WTP_LOAD_GAME 0x1A +#define IDO_WTP_OWL_HELP 0x1C +#define IDO_WTP_GOTO_RND 0x1E + +#define IDO_WTP_OPTION_0 0x15 +#define IDO_WTP_OPTION_1 0x16 +#define IDO_WTP_OPTION_2 0x17 + +enum { + IDI_WTP_OBJ_DESC = 0, + IDI_WTP_OBJ_TAKE, + IDI_WTP_OBJ_DROP, + IDI_WTP_OBJ_HELP +}; + +enum { + IDI_WTP_PAR_OK = 0, + IDI_WTP_PAR_GOTO, + IDI_WTP_PAR_BACK +}; + +// room file option block + +struct WTP_ROOM_BLOCK { + uint16 ofsOpt[IDI_WTP_MAX_BLOCK]; +}; + +// room file header + +struct WTP_ROOM_HDR { + uint8 roomNumber; + uint8 objId; + uint16 ofsPic; + uint16 fileLen; + uint16 reserved0; + int8 roomNew[IDI_WTP_MAX_DIR]; + uint8 objX; + uint8 objY; + uint16 reserved1; + uint16 ofsDesc[IDI_WTP_MAX_BLOCK]; + uint16 ofsBlock[IDI_WTP_MAX_BLOCK]; + uint16 ofsStr[IDI_WTP_MAX_STR]; + uint32 reserved2; + WTP_ROOM_BLOCK opt[IDI_WTP_MAX_BLOCK]; +}; + +// object file header + +struct WTP_OBJ_HDR { + uint16 fileLen; + uint16 objId; + uint16 ofsEndStr[IDI_WTP_MAX_OBJ_STR_END]; + uint16 ofsStr[IDI_WTP_MAX_OBJ_STR]; + uint16 ofsPic; +}; + +// savegame + +struct WTP_SAVE_GAME { + uint16 reserved0; // 10c2 unused + uint16 fSound; // 10c4 + uint16 nMoves; // 10c6 + uint16 nObjMiss; // 10c8 + uint16 nObjRet; // 10ca + uint16 reserved1; // 10ce unused + uint16 reserved2; // 10cf unused + uint16 reserved3; // 10d0 unused + uint16 iObjHave; // 10d2 + uint16 o10d4; // 10d4 can be ignored + uint16 o10d6; // 10d6 can be ignored + uint16 o10d8; // 10d8 can be ignored + uint8 fGame[IDI_WTP_MAX_FLAG]; // 10da + uint8 iUsedObj[IDI_WTP_MAX_OBJ_MISSING]; // 1102 + uint8 iObjRoom[IDI_WTP_MAX_ROOM_OBJ]; // 110c + uint16 o1136; // 1136 can be ignored + uint16 o1138; // 1138 can be ignored +}; + +#define IDI_XOR_KEY 0x80 + +class Winnie { + friend class PreAgiEngine; +public: + Winnie(PreAgiEngine *vm); + //~Winnie(); + + void init(); + void run(); + +private: + PreAgiEngine *_vm; + WTP_SAVE_GAME game; + int room; + int mist; + bool doWind; + bool winnie_event; + int tigger_mist; + + void initEngine(); + void initVars(); + void randomize(); + void intro(); + void drawPic(const char*); + void gameLoop(); + void readRoom(int, uint8*, int); + void drawRoomPic(); + int parser(int, int, uint8*); + int getObjInRoom(int); + bool getSelOkBack(); + void getMenuSel(char*, int*, int[]); + void keyHelp(); + void clrMenuSel(int*, int[]); + void incMenuSel(int*, int[]); + void decMenuSel(int*, int[]); + void drawMenu(char*, int, int[]); + void printRoomStr(int, int); + void inventory(); + void printObjStr(int, int); + void readObj(int, uint8*, int); + void takeObj(int); + void dropObj(int); + bool isRightObj(int, int, int*); + void drawObjPic(int, int, int); + void getMenuMouseSel(int*, int[], int, int); + void setFlag(int); + void clearFlag(int); + void gameOver(); + void saveGame(); + void loadGame(); + void writeSaveGame(uint8*); + void readSaveGame(uint8*); + void dropObjRnd(); + void wind(); + void showOwlHelp(); +}; + +} // End of namespace Agi + +#endif + diff --git a/engines/agi/predictive.cpp b/engines/agi/predictive.cpp index eef4360cbf..5ffa3d159f 100644 --- a/engines/agi/predictive.cpp +++ b/engines/agi/predictive.cpp @@ -199,7 +199,8 @@ bool AgiEngine::predictiveDialog(void) { color2 = 7; } - bool _addIsActive = false; // FIXME + // needs fixing, or remove it! + bool _addIsActive = false; // FIXME: word adding is not implemented if (i == 10 && !_addIsActive) { // Add color2 = 7; } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index 05ce80b1a3..c8cae3b479 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -525,7 +525,7 @@ int AgiEngine::selectSlot() { int oldActive = active + 1; for (;;) { - int sbPos; + int sbPos = 0; if (oldFirstSlot != _firstSlot || oldActive != active) { char dstr[64]; diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp index b083b77440..b76ab309a5 100644 --- a/engines/agi/sound.cpp +++ b/engines/agi/sound.cpp @@ -25,6 +25,10 @@ #include "common/stdafx.h" +#include "common/md5.h" +#include "common/config-manager.h" +#include "common/fs.h" +#include "common/algorithm.h" #include "sound/mixer.h" #include "agi/agi.h" @@ -33,204 +37,241 @@ namespace Agi { #define USE_INTERPOLATION -#define USE_CHORUS +static bool g_useChorus = true; /* TODO: add support for variable sampling rate in the output device */ -#ifdef USE_IIGS_SOUND +AgiSound *AgiSound::createFromRawResource(uint8 *data, uint32 len, int resnum, SoundMgr &manager) { + if (data == NULL || len < 2) return NULL; // Check for too small resource or no resource at all + uint16 type = READ_LE_UINT16(data); + + switch (type) { // Create a sound object based on the type + case AGI_SOUND_SAMPLE : return new IIgsSample(data, len, resnum, manager); + case AGI_SOUND_MIDI : return new IIgsMidi (data, len, resnum, manager); + case AGI_SOUND_4CHN : return new PCjrSound (data, len, resnum, manager); + } + + warning("Sound resource (%d) has unknown type (0x%04x). Not using the sound", resnum, type); + return NULL; +} -struct IIgsEnvelopeSegment { - uint8 bp; - uint16 inc; ///< 8b.8b fixed point, big endian? -}; +IIgsMidi::IIgsMidi(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : AgiSound(manager) { + _data = data; // Save the resource pointer + _ptr = _data + 2; // Set current position to just after the header + _len = len; // Save the resource's length + _type = READ_LE_UINT16(data); // Read sound resource's type + _isValid = (_type == AGI_SOUND_MIDI) && (_data != NULL) && (_len >= 2); -#define ENVELOPE_SEGMENT_COUNT 8 -struct IIgsEnvelope { - IIgsEnvelopeSegment seg[ENVELOPE_SEGMENT_COUNT]; -}; + if (!_isValid) // Check for errors + warning("Error creating Apple IIGS midi sound from resource %d (Type %d, length %d)", resnum, _type, len); +} -// 2**(1/12) i.e. the 12th root of 2 -#define SEMITONE 1.059463094359295 - -struct IIgsWaveInfo { - uint8 top; - uint8 addr; - uint8 size; -// Oscillator channel (Bits 4-7 of mode-byte). Simplified to use only stereo here. -#define MASK_OSC_CHANNEL (1 << 4) -#define OSC_CHANNEL_LEFT (1 << 4) -#define OSC_CHANNEL_RIGHT (0 << 4) -// Oscillator halt bit (Bit 0 of mode-byte) -#define MASK_OSC_HALT (1 << 0) -#define OSC_HALT (1 << 0) -// Oscillator mode (Bits 1 and 2 of mode-byte) -#define MASK_OSC_MODE (3 << 1) -#define OSC_MODE_LOOP (0 << 1) -#define OSC_MODE_ONESHOT (1 << 1) -#define OSC_MODE_SYNC_AM (2 << 1) -#define OSC_MODE_SWAP (3 << 1) - uint8 mode; - uint16 relPitch; ///< 8b.8b fixed point, big endian? -}; +PCjrSound::PCjrSound(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : AgiSound(manager) { + _data = data; // Save the resource pointer + _len = len; // Save the resource's length + _type = READ_LE_UINT16(data); // Read sound resource's type + _isValid = (_type == AGI_SOUND_4CHN) && (_data != NULL) && (_len >= 2); -#define MAX_WAVE_COUNT 8 -struct IIgsInstrumentHeader { - IIgsEnvelope env; - uint8 relseg; - uint8 priority; - uint8 bendrange; - uint8 vibdepth; - uint8 vibspeed; - uint8 spare; - uint8 wac; - uint8 wbc; - IIgsWaveInfo wal[MAX_WAVE_COUNT]; - IIgsWaveInfo wbl[MAX_WAVE_COUNT]; -}; + if (!_isValid) // Check for errors + warning("Error creating PCjr 4-channel sound from resource %d (Type %d, length %d)", resnum, _type, len); +} -struct IIgsSampleHeader { - uint16 type; - uint8 pitch; ///< Logarithmic, base is 2**(1/12), unknown multiplier (Possibly in range 1040-1080) - uint8 unknownByte_Ofs3; // 0x7F in Gold Rush's sound resource 60, 0 in all others. - uint8 volume; ///< Current guess: Logarithmic in 6 dB steps - uint8 unknownByte_Ofs5; ///< 0 in all tested samples. - uint16 instrumentSize; ///< Little endian. 44 in all tested samples. A guess. - uint16 sampleSize; ///< Little endian. Accurate in all tested samples excluding Manhunter I's sound resource 16. - IIgsInstrumentHeader instrument; -}; +const uint8 *PCjrSound::getVoicePointer(uint voiceNum) { + assert(voiceNum < 4); + uint16 voiceStartOffset = READ_LE_UINT16(_data + voiceNum * 2); + return _data + voiceStartOffset; +} -#if 0 -static SoundInstrument *instruments; -static int numInstruments; -static uint8 *wave; -#endif +IIgsSample::IIgsSample(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : AgiSound(manager) { + Common::MemoryReadStream stream(data, len, true); -bool readIIgsEnvelope(IIgsEnvelope &envelope, Common::SeekableReadStream &stream) { + // Check that the header was read ok and that it's of the correct type + if (_header.read(stream) && _header.type == AGI_SOUND_SAMPLE) { // An Apple IIGS AGI sample resource + uint32 sampleStartPos = stream.pos(); + uint32 tailLen = stream.size() - sampleStartPos; + + if (tailLen < _header.sampleSize) { // Check if there's no room for the sample data in the stream + // Apple IIGS Manhunter I: Sound resource 16 has only 16074 bytes + // of sample data although header says it should have 16384 bytes. + warning("Apple IIGS sample (%d) too short (%d bytes. Should be %d bytes). Using the part that's left", + resnum, tailLen, _header.sampleSize); + _header.sampleSize = (uint16) tailLen; // Use the part that's left + } + + if (_header.pitch > 0x7F) { // Check if the pitch is invalid + warning("Apple IIGS sample (%d) has too high pitch (0x%02x)", resnum, _header.pitch); + _header.pitch &= 0x7F; // Apple IIGS AGI probably did it this way too + } + + // Finalize the header info using the 8-bit unsigned sample data + _header.finalize(stream); + + // Convert sample data from 8-bit unsigned to 16-bit signed format + stream.seek(sampleStartPos); + _sample = new int16[_header.sampleSize]; + if (_sample != NULL) + _isValid = _manager.convertWave(stream, _sample, _header.sampleSize); + } + + if (!_isValid) // Check for errors + warning("Error creating Apple IIGS sample from resource %d (Type %d, length %d)", resnum, _header.type, len); +} + +/** Reads an Apple IIGS envelope from then given stream. */ +bool IIgsEnvelope::read(Common::SeekableReadStream &stream) { for (int segNum = 0; segNum < ENVELOPE_SEGMENT_COUNT; segNum++) { - envelope.seg[segNum].bp = stream.readByte(); - envelope.seg[segNum].inc = stream.readUint16BE(); + seg[segNum].bp = stream.readByte(); + seg[segNum].inc = stream.readUint16LE(); } return !stream.ioFailed(); } -bool readIIgsWaveInfo(IIgsWaveInfo &waveInfo, Common::SeekableReadStream &stream) { - waveInfo.top = stream.readByte(); - waveInfo.addr = stream.readByte(); - waveInfo.size = stream.readByte(); - waveInfo.mode = stream.readByte(); - waveInfo.relPitch = stream.readUint16BE(); +/** Reads an Apple IIGS wave information structure from the given stream. */ +bool IIgsWaveInfo::read(Common::SeekableReadStream &stream, bool ignoreAddr) { + top = stream.readByte(); + addr = stream.readByte() * 256; + size = (1 << (stream.readByte() & 7)) * 256; + + // Read packed mode byte and parse it into parts + byte packedModeByte = stream.readByte(); + channel = (packedModeByte >> 4) & 1; // Bit 4 + mode = (packedModeByte >> 1) & 3; // Bits 1-2 + halt = (packedModeByte & 1) != 0; // Bit 0 (Converted to boolean) + + relPitch = stream.readSint16LE(); + + // Zero the wave address if we want to ignore the wave address info + if (ignoreAddr) + addr = 0; + return !stream.ioFailed(); } -/** - * Read an Apple IIGS instrument header from the given stream. - * @param header The header to which to write the data. - * @param stream The source stream from which to read the data. - * @return True if successful, false otherwise. - */ -bool readIIgsInstrumentHeader(IIgsInstrumentHeader &header, Common::SeekableReadStream &stream) { - readIIgsEnvelope(header.env, stream); - header.relseg = stream.readByte(); - header.priority = stream.readByte(); - header.bendrange = stream.readByte(); - header.vibdepth = stream.readByte(); - header.vibspeed = stream.readByte(); - header.spare = stream.readByte(); - header.wac = stream.readByte(); - header.wbc = stream.readByte(); - for (int waveA = 0; waveA < header.wac; waveA++) // Read A wave lists - readIIgsWaveInfo(header.wal[waveA], stream); - for (int waveB = 0; waveB < header.wbc; waveB++) // Read B wave lists - readIIgsWaveInfo(header.wbl[waveB], stream); - return !stream.ioFailed(); +bool IIgsWaveInfo::finalize(Common::SeekableReadStream &uint8Wave) { + uint32 startPos = uint8Wave.pos(); // Save stream's starting position + uint8Wave.seek(addr, SEEK_CUR); // Seek to wave's address + + // Calculate the true sample size (A zero ends the sample prematurely) + uint trueSize = size; // Set a default value for the result + for (uint i = 0; i < size; i++) { + if (uint8Wave.readByte() == 0) { + trueSize = i; + // A zero in the sample stream turns off looping + // (At least that's what MESS 0.117 and KEGS32 0.91 seem to do) + if (mode == OSC_MODE_LOOP) + mode = OSC_MODE_ONESHOT; + break; + } + } + size = trueSize; // Set the true sample size + + uint8Wave.seek(startPos); // Seek back to the stream's starting position + return true; } -/** - * Read an Apple IIGS AGI sample header from the given stream. - * @param header The header to which to write the data. - * @param stream The source stream from which to read the data. - * @return True if successful, false otherwise. - */ -bool readIIgsSampleHeader(IIgsSampleHeader &header, Common::SeekableReadStream &stream) { - header.type = stream.readUint16LE(); - header.pitch = stream.readByte(); - header.unknownByte_Ofs3 = stream.readByte(); - header.volume = stream.readByte(); - header.unknownByte_Ofs5 = stream.readByte(); - header.instrumentSize = stream.readUint16LE(); - header.sampleSize = stream.readUint16LE(); - return readIIgsInstrumentHeader(header.instrument, stream); +bool IIgsOscillator::finalize(Common::SeekableReadStream &uint8Wave) { + for (uint i = 0; i < WAVES_PER_OSCILLATOR; i++) + if (!waves[i].finalize(uint8Wave)) + return false; + return true; } -/** - * Load an Apple IIGS AGI sample resource from the given stream and - * create an AudioStream out of it. - * - * @param stream The source stream. - * @param resnum Sound resource number. Optional. Used for error messages. - * @return A non-null AudioStream pointer if successful, NULL otherwise. - * @note In case of failure (i.e. NULL is returned), stream is reset back - * to its original position and its I/O failed -status is cleared. - * TODO: Add better handling of invalid resource number when printing error messages. - * TODO: Add support for looping sounds. - * FIXME: Fix sample rate calculation, it's probably not accurate at the moment. - */ -Audio::AudioStream *makeIIgsSampleStream(Common::SeekableReadStream &stream, int resnum = -1) { - const uint32 startPos = stream.pos(); - IIgsSampleHeader header; - Audio::AudioStream *result = NULL; - bool readHeaderOk = readIIgsSampleHeader(header, stream); +bool IIgsOscillatorList::read(Common::SeekableReadStream &stream, uint oscillatorCount, bool ignoreAddr) { + // First read the A waves and then the B waves for the oscillators + for (uint waveNum = 0; waveNum < WAVES_PER_OSCILLATOR; waveNum++) + for (uint oscNum = 0; oscNum < oscillatorCount; oscNum++) + if (!osc[oscNum].waves[waveNum].read(stream, ignoreAddr)) + return false; - // Check that the header was read ok and that it's of the correct type - // and that there's room for the sample data in the stream. - if (readHeaderOk && header.type == AGI_SOUND_SAMPLE) { // An Apple IIGS AGI sample resource - uint32 tailLen = stream.size() - stream.pos(); - if (tailLen < header.sampleSize) { // Check if there's no room for the sample data in the stream - // Apple IIGS Manhunter I: Sound resource 16 has only 16074 bytes - // of sample data although header says it should have 16384 bytes. - warning("Apple IIGS sample (%d) too short (%d bytes. Should be %d bytes). Using the part that's left", resnum, tailLen, header.sampleSize); - header.sampleSize = (uint16) tailLen; // Use the part that's left - } - if (header.pitch > 0x7F) { // Check if the pitch is invalid - warning("Apple IIGS sample (%d) has too high pitch (0x%02x)", resnum, header.pitch); - header.pitch &= 0x7F; // Apple IIGS AGI probably did it this way too - } - // Allocate memory for the sample data and read it in - byte *sampleData = (byte *) malloc(header.sampleSize); - uint32 readBytes = stream.read(sampleData, header.sampleSize); - if (readBytes == header.sampleSize) { // Check that we got all the data we requested - // Make an audio stream from the mono, 8 bit, unsigned input data - byte flags = Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED; - int rate = (int) (1076 * pow(SEMITONE, header.pitch)); - result = Audio::makeLinearInputStream(sampleData, header.sampleSize, rate, flags, 0, 0); - } - } + count = oscillatorCount; // Set the oscillator count + return true; +} - // If couldn't make a sample out of the input stream for any reason then - // rewind back to stream's starting position and clear I/O failed -status. - if (result == NULL) { - stream.seek(startPos); - stream.clearIOFailed(); - } +bool IIgsOscillatorList::finalize(Common::SeekableReadStream &uint8Wave) { + for (uint i = 0; i < count; i++) + if (!osc[i].finalize(uint8Wave)) + return false; + return true; +} - return result; +bool IIgsInstrumentHeader::read(Common::SeekableReadStream &stream, bool ignoreAddr) { + env.read(stream); + relseg = stream.readByte(); + /*byte priority =*/ stream.readByte(); // Not needed? 32 in all tested data. + bendrange = stream.readByte(); + vibdepth = stream.readByte(); + vibspeed = stream.readByte(); + /*byte spare =*/ stream.readByte(); // Not needed? 0 in all tested data. + byte wac = stream.readByte(); // Read A wave count + byte wbc = stream.readByte(); // Read B wave count + oscList.read(stream, wac, ignoreAddr); // Read the oscillators + return (wac == wbc) && !stream.ioFailed(); // A and B wave counts must match } -#endif +bool IIgsInstrumentHeader::finalize(Common::SeekableReadStream &uint8Wave) { + return oscList.finalize(uint8Wave); +} + +bool IIgsSampleHeader::read(Common::SeekableReadStream &stream) { + type = stream.readUint16LE(); + pitch = stream.readByte(); + unknownByte_Ofs3 = stream.readByte(); + volume = stream.readByte(); + unknownByte_Ofs5 = stream.readByte(); + instrumentSize = stream.readUint16LE(); + sampleSize = stream.readUint16LE(); + // Read the instrument header *ignoring* its wave address info + return instrument.read(stream, true); +} + +bool IIgsSampleHeader::finalize(Common::SeekableReadStream &uint8Wave) { + return instrument.finalize(uint8Wave); +} + +/** Older Apple IIGS AGI instrument set. Used only by Space Quest I (AGI v1.002). */ +static const instrumentSetInfo instSetV1 = { + 1192, 26, "7ee16bbc135171ffd6b9120cc7ff1af2", "edd3bf8905d9c238e02832b732fb2e18" +}; -static int playing; -static ChannelInfo chn[NUM_CHANNELS]; -static int endflag = -1; -static int playingSound = -1; -static uint8 *song; -static uint8 env; +/** Newer Apple IIGS AGI instrument set (AGI v1.003+). Used by all others than Space Quest I. */ +static const instrumentSetInfo instSetV2 = { + 1292, 28, "b7d428955bb90721996de1cbca25e768", "c05fb0b0e11deefab58bc68fbd2a3d07" +}; +/** Information about different Apple IIGS AGI executables. */ +static const IIgsExeInfo IIgsExeInfos[] = { + {GID_SQ1, "SQ", 0x1002, 138496, 0x80AD, instSetV1}, + {GID_LSL1, "LL", 0x1003, 141003, 0x844E, instSetV2}, + {GID_AGIDEMO, "DEMO", 0x1005, 141884, 0x8469, instSetV2}, + {GID_KQ1, "KQ", 0x1006, 141894, 0x8469, instSetV2}, + {GID_PQ1, "PQ", 0x1007, 141882, 0x8469, instSetV2}, + {GID_MIXEDUP, "MG", 0x1013, 142552, 0x84B7, instSetV2}, + {GID_KQ2, "KQ2", 0x1013, 143775, 0x84B7, instSetV2}, + {GID_KQ3, "KQ3", 0x1014, 144312, 0x84B7, instSetV2}, + {GID_SQ2, "SQ2", 0x1014, 107882, 0x6563, instSetV2}, + {GID_MH1, "MH", 0x2004, 147678, 0x8979, instSetV2}, + {GID_KQ4, "KQ4", 0x2006, 147652, 0x8979, instSetV2}, + {GID_BC, "BC", 0x3001, 148192, 0x8979, instSetV2}, + {GID_GOLDRUSH, "GR", 0x3003, 148268, 0x8979, instSetV2} +}; -static int16 *sndBuffer; -static int16 *waveform; +static IIgsInstrumentHeader g_instruments[MAX_INSTRUMENTS]; +static uint g_numInstruments = 0; +static int16 g_wave[SIERRASTANDARD_SIZE]; // FIXME? Should this be allocated from the heap? (Size is 128KiB) +// Time (In milliseconds) in Apple IIGS mixing buffer time granularity +// (i.e. in IIGS_BUFFER_SIZE / getRate() seconds granularity) +static uint32 g_IIgsBufGranMillis = 0; +static uint32 g_midiMillis = 0; // Time position (In milliseconds) in currently playing MIDI sound + +bool SoundMgr::finalizeInstruments(Common::SeekableReadStream &uint8Wave) { + for (uint i = 0; i < g_numInstruments; i++) + if (!g_instruments[i].finalize(uint8Wave)) + return false; + return true; +} -static int16 waveformRamp[WAVEFORM_SIZE] = { +static const int16 waveformRamp[WAVEFORM_SIZE] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, @@ -241,7 +282,7 @@ static int16 waveformRamp[WAVEFORM_SIZE] = { -64, -56, -48, -40, -32, -24, -16, -8 /* Ramp up */ }; -static int16 waveformSquare[WAVEFORM_SIZE] = { +static const int16 waveformSquare[WAVEFORM_SIZE] = { 255, 230, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, @@ -252,7 +293,7 @@ static int16 waveformSquare[WAVEFORM_SIZE] = { -220, -220, -220, -110, 0, 0, 0, 0 /* Square */ }; -static int16 waveformMac[WAVEFORM_SIZE] = { +static const int16 waveformMac[WAVEFORM_SIZE] = { 45, 110, 135, 161, 167, 173, 175, 176, 156, 137, 123, 110, 91, 72, 35, -2, -60, -118, -142, -165, -170, -176, -177, -179, @@ -263,157 +304,137 @@ static int16 waveformMac[WAVEFORM_SIZE] = { -175, -172, -165, -159, -137, -114, -67, -19 }; -#ifdef USE_IIGS_SOUND - -static uint16 period[] = { +static const uint16 period[] = { 1024, 1085, 1149, 1218, 1290, 1367, 1448, 1534, 1625, 1722, 1825, 1933 }; -static struct AgiNote playSample[] = { - {0xff, 0x7f, 0x18, 0x00, 0x7f}, - {0xff, 0xff, 0x00, 0x00, 0x00}, - {0xff, 0xff, 0x00, 0x00, 0x00}, - {0xff, 0xff, 0x00, 0x00, 0x00} -}; - +#if 0 static int noteToPeriod(int note) { return 10 * (period[note % 12] >> (note / 12 - 3)); } - -#endif /* USE_IIGS_SOUND */ +#endif void SoundMgr::unloadSound(int resnum) { if (_vm->_game.dirSound[resnum].flags & RES_LOADED) { - if (_vm->_game.sounds[resnum].flags & SOUND_PLAYING) - /* FIXME: Stop playing */ - ; + if (_vm->_game.sounds[resnum]->isPlaying()) { + _vm->_game.sounds[resnum]->stop(); + } - /* Release RAW data for sound */ - free(_vm->_game.sounds[resnum].rdata); - _vm->_game.sounds[resnum].rdata = NULL; + // Release the sound resource's data + delete _vm->_game.sounds[resnum]; + _vm->_game.sounds[resnum] = NULL; _vm->_game.dirSound[resnum].flags &= ~RES_LOADED; } } -void SoundMgr::decodeSound(int resnum) { -#if 0 - int type, size; - int16 *buf; - uint8 *src; - struct SoundIIgsSample *smp; - - debugC(3, kDebugLevelSound, "(%d)", resnum); - type = READ_LE_UINT16(_vm->_game.sounds[resnum].rdata); - - if (type == AGI_SOUND_SAMPLE) { - /* Convert sample data to 16 bit signed format - */ - smp = (struct SoundIIgsSample *)_vm->_game.sounds[resnum].rdata; - size = ((int)smp->sizeHi << 8) + smp->sizeLo; - src = (uint8 *)_vm->_game.sounds[resnum].rdata; - buf = (int16 *)calloc(1, 54 + (size << 1) + 100); /* FIXME */ - memcpy(buf, src, 54); - for (; size--; buf[size + 54] = ((int16)src[size + 54] - 0x80) << 4); /* FIXME */ - _vm->_game.sounds[resnum].rdata = (uint8 *) buf; - free(src); - } -#endif -} - void SoundMgr::startSound(int resnum, int flag) { - int i, type; -#if 0 - struct SoundIIgsSample *smp; -#endif + int i; + AgiSoundType type; - if (_vm->_game.sounds[resnum].flags & SOUND_PLAYING) + if (_vm->_game.sounds[resnum] != NULL && _vm->_game.sounds[resnum]->isPlaying()) return; stopSound(); - if (_vm->_game.sounds[resnum].rdata == NULL) + if (_vm->_game.sounds[resnum] == NULL) // Is this needed at all? return; - type = READ_LE_UINT16(_vm->_game.sounds[resnum].rdata); + type = (AgiSoundType)_vm->_game.sounds[resnum]->type(); if (type != AGI_SOUND_SAMPLE && type != AGI_SOUND_MIDI && type != AGI_SOUND_4CHN) return; - _vm->_game.sounds[resnum].flags |= SOUND_PLAYING; - _vm->_game.sounds[resnum].type = type; - playingSound = resnum; - song = (uint8 *)_vm->_game.sounds[resnum].rdata; + _vm->_game.sounds[resnum]->play(); + _playingSound = resnum; + + debugC(3, kDebugLevelSound, "startSound(resnum = %d, flag = %d)", resnum, flag); switch (type) { -#if 0 - case AGI_SOUND_SAMPLE: - debugC(3, kDebugLevelSound, "IIGS sample"); - smp = (struct SoundIIgsSample *)_vm->_game.sounds[resnum].rdata; - for (i = 0; i < NUM_CHANNELS; i++) { - chn[i].type = type; - chn[i].flags = 0; - chn[i].ins = (int16 *)&_vm->_game.sounds[resnum].rdata[54]; - chn[i].size = ((int)smp->sizeHi << 8) + smp->sizeLo; - chn[i].ptr = &playSample[i]; - chn[i].timer = 0; - chn[i].vol = 0; - chn[i].end = 0; - } + case AGI_SOUND_SAMPLE: { + IIgsSample *sampleRes = (IIgsSample *) _vm->_game.sounds[_playingSound]; + const IIgsWaveInfo &waveInfo = _IIgsChannel.ins.oscList(0).waves[0]; + const IIgsSampleHeader &header = sampleRes->getHeader(); + + _IIgsChannel.ins = header.instrument; + _IIgsChannel.sample = sampleRes->getSample() + waveInfo.addr; + _IIgsChannel.pos = intToFrac(0); + _IIgsChannel.posAdd = intToFrac(0); + _IIgsChannel.note = intToFrac(header.pitch) + doubleToFrac(waveInfo.relPitch/256.0); + _IIgsChannel.startEnvVol = intToFrac(0); + _IIgsChannel.chanVol = intToFrac(header.volume); + _IIgsChannel.envVol = _IIgsChannel.startEnvVol; + _IIgsChannel.vol = doubleToFrac(fracToDouble(_IIgsChannel.envVol) * fracToDouble(_IIgsChannel.chanVol) / 127.0); + _IIgsChannel.envSeg = intToFrac(0); + _IIgsChannel.loop = (waveInfo.mode == OSC_MODE_LOOP); + _IIgsChannel.size = waveInfo.size - waveInfo.addr; + _IIgsChannel.end = false; break; + } case AGI_SOUND_MIDI: + g_IIgsBufGranMillis = g_midiMillis = 0; +#if 0 debugC(3, kDebugLevelSound, "IIGS MIDI sequence"); for (i = 0; i < NUM_CHANNELS; i++) { - chn[i].type = type; - chn[i].flags = AGI_SOUND_LOOP | AGI_SOUND_ENVELOPE; - chn[i].ins = waveform; - chn[i].size = WAVEFORM_SIZE; - chn[i].vol = 0; - chn[i].end = 0; + _chn[i].type = type; + _chn[i].flags = AGI_SOUND_LOOP | AGI_SOUND_ENVELOPE; + _chn[i].ins = _waveform; + _chn[i].size = WAVEFORM_SIZE; + _chn[i].vol = 0; + _chn[i].end = 0; } - chn[0].timer = *(song + 2); - chn[0].ptr = (struct AgiNote *)(song + 3); - break; + _chn[0].timer = *(song + 2); + _chn[0].ptr = (struct AgiNote *)(song + 3); #endif + break; case AGI_SOUND_4CHN: + PCjrSound *pcjrSound = (PCjrSound *) _vm->_game.sounds[resnum]; /* Initialize channel info */ for (i = 0; i < NUM_CHANNELS; i++) { - chn[i].type = type; - chn[i].flags = AGI_SOUND_LOOP; - if (env) { - chn[i].flags |= AGI_SOUND_ENVELOPE; - chn[i].adsr = AGI_SOUND_ENV_ATTACK; + _chn[i].type = type; + _chn[i].flags = AGI_SOUND_LOOP; + if (_env) { + _chn[i].flags |= AGI_SOUND_ENVELOPE; + _chn[i].adsr = AGI_SOUND_ENV_ATTACK; } - chn[i].ins = waveform; - chn[i].size = WAVEFORM_SIZE; - chn[i].ptr = (struct AgiNote *)(song + (song[i << 1] | (song[(i << 1) + 1] << 8))); - chn[i].timer = 0; - chn[i].vol = 0; - chn[i].end = 0; + _chn[i].ins = _waveform; + _chn[i].size = WAVEFORM_SIZE; + _chn[i].ptr = pcjrSound->getVoicePointer(i % 4); + _chn[i].timer = 0; + _chn[i].vol = 0; + _chn[i].end = 0; } break; } - memset(sndBuffer, 0, BUFFER_SIZE << 1); - endflag = flag; + memset(_sndBuffer, 0, BUFFER_SIZE << 1); + _endflag = flag; /* Nat Budin reports that the flag should be reset when sound starts */ - _vm->setflag(endflag, false); + _vm->setflag(_endflag, false); } void SoundMgr::stopSound() { int i; - endflag = -1; - for (i = 0; i < NUM_CHANNELS; i++) - stopNote(i); + _endflag = -1; + if (_vm->_soundemu != SOUND_EMU_APPLE2GS) { + for (i = 0; i < NUM_CHANNELS; i++) + stopNote(i); + } - if (playingSound != -1) { - _vm->_game.sounds[playingSound].flags &= ~SOUND_PLAYING; - playingSound = -1; + if (_playingSound != -1) { + _vm->_game.sounds[_playingSound]->stop(); + + if (_vm->_soundemu == SOUND_EMU_APPLE2GS) { + _IIgsChannel.end = true; + _IIgsChannel.chanVol = intToFrac(0); + } + + _playingSound = -1; } } @@ -422,37 +443,36 @@ static int16 *buffer; int SoundMgr::initSound() { int r = -1; - buffer = sndBuffer = (int16 *)calloc(2, BUFFER_SIZE); + buffer = _sndBuffer = (int16 *)calloc(2, BUFFER_SIZE); - env = false; + _env = false; switch (_vm->_soundemu) { case SOUND_EMU_NONE: - waveform = waveformRamp; - env = true; + _waveform = waveformRamp; + _env = true; break; case SOUND_EMU_AMIGA: case SOUND_EMU_PC: - waveform = waveformSquare; + _waveform = waveformSquare; break; case SOUND_EMU_MAC: - waveform = waveformMac; + _waveform = waveformMac; + break; + case SOUND_EMU_APPLE2GS: + loadInstruments(); break; } report("Initializing sound:\n"); report("sound: envelopes "); - if (env) { + if (_env) { report("enabled (decay=%d, sustain=%d)\n", ENV_DECAY, ENV_SUSTAIN); } else { report("disabled\n"); } -#ifdef USE_IIGS_SOUND - /*loadInstruments("demo.sys"); */ -#endif - _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); return r; @@ -461,19 +481,19 @@ int SoundMgr::initSound() { void SoundMgr::deinitSound() { debugC(3, kDebugLevelSound, "()"); _mixer->stopHandle(_soundHandle); - free(sndBuffer); + free(_sndBuffer); } void SoundMgr::stopNote(int i) { - chn[i].adsr = AGI_SOUND_ENV_RELEASE; + _chn[i].adsr = AGI_SOUND_ENV_RELEASE; -#ifdef USE_CHORUS - /* Stop chorus ;) */ - if (chn[i].type == AGI_SOUND_4CHN && - _vm->_soundemu == SOUND_EMU_NONE && i < 3) { - stopNote(i + 4); + if (g_useChorus) { + /* Stop chorus ;) */ + if (_chn[i].type == AGI_SOUND_4CHN && + _vm->_soundemu == SOUND_EMU_NONE && i < 3) { + stopNote(i + 4); + } } -#endif } void SoundMgr::playNote(int i, int freq, int vol) { @@ -482,127 +502,186 @@ void SoundMgr::playNote(int i, int freq, int vol) { else if (vol && _vm->_soundemu == SOUND_EMU_PC) vol = 160; - chn[i].phase = 0; - chn[i].freq = freq; - chn[i].vol = vol; - chn[i].env = 0x10000; - chn[i].adsr = AGI_SOUND_ENV_ATTACK; - -#ifdef USE_CHORUS - /* Add chorus ;) */ - if (chn[i].type == AGI_SOUND_4CHN && - _vm->_soundemu == SOUND_EMU_NONE && i < 3) { - int newfreq = freq * 1007 / 1000; - if (freq == newfreq) - newfreq++; - playNote(i + 4, newfreq, vol * 2 / 3); + _chn[i].phase = 0; + _chn[i].freq = freq; + _chn[i].vol = vol; + _chn[i].env = 0x10000; + _chn[i].adsr = AGI_SOUND_ENV_ATTACK; + + if (g_useChorus) { + /* Add chorus ;) */ + if (_chn[i].type == AGI_SOUND_4CHN && + _vm->_soundemu == SOUND_EMU_NONE && i < 3) { + int newfreq = freq * 1007 / 1000; + if (freq == newfreq) + newfreq++; + playNote(i + 4, newfreq, vol * 2 / 3); + } } -#endif } -#ifdef USE_IIGS_SOUND - void SoundMgr::playMidiSound() { - uint8 *p; + const uint8 *p; uint8 parm1, parm2; static uint8 cmd, ch; - playing = 1; - - if (chn[0].timer > 0) { - chn[0].timer -= 2; + if (_playingSound == -1 || _vm->_game.sounds[_playingSound] == NULL) { + warning("Error playing Apple IIGS MIDI sound resource"); + _playing = false; return; } - p = (uint8 *)chn[0].ptr; + IIgsMidi *midiObj = (IIgsMidi *) _vm->_game.sounds[_playingSound]; - if (*p & 0x80) { - cmd = *p++; - ch = cmd & 0x0f; - cmd >>= 4; - } + _playing = true; + p = midiObj->getPtr(); - switch (cmd) { - case 0x08: - parm1 = *p++; - parm2 = *p++; - if (ch < NUM_CHANNELS) - stopNote(ch); - break; - case 0x09: - parm1 = *p++; - parm2 = *p++; - if (ch < NUM_CHANNELS) - playNote(ch, noteToPeriod(parm1), 127); - break; - case 0x0b: - parm1 = *p++; - parm2 = *p++; - debugC(3, kDebugLevelSound, "controller %02x, ch %02x, val %02x", parm1, ch, parm2); - break; - case 0x0c: - parm1 = *p++; -#if 0 - if (ch < NUM_CHANNELS) { - chn[ch].ins = (uint16 *)&wave[waveaddr[parm1]]; - chn[ch].size = wavesize[parm1]; + g_IIgsBufGranMillis += (IIGS_BUFFER_SIZE * 1000) / getRate(); + + while (g_midiMillis < g_IIgsBufGranMillis) { + uint8 readByte = *p++; + + // Check for end of MIDI sequence marker (Can also be here before delta-time) + if (readByte == MIDI_BYTE_STOP_SEQUENCE) { + debugC(3, kDebugLevelSound, "End of MIDI sequence (Before reading delta-time)"); + g_IIgsBufGranMillis = g_midiMillis = 0; + _playing = false; + midiObj->rewind(); + return; + } else if (readByte == MIDI_BYTE_TIMER_SYNC) { + debugC(3, kDebugLevelSound, "Timer sync"); + continue; + } + + uint8 deltaTime = readByte; + uint32 bpm = 120; // Don't know if this is correct + g_midiMillis += (deltaTime * 1000) / bpm; + + // Check for end of MIDI sequence marker (This time it after reading delta-time) + if (*p == MIDI_BYTE_STOP_SEQUENCE) { + debugC(3, kDebugLevelSound, "End of MIDI sequence (After reading delta-time)"); + g_IIgsBufGranMillis = g_midiMillis = 0; + _playing = false; + midiObj->rewind(); + return; + } + + // Separate byte into command and channel if it's a command byte. + // Otherwise use running status (i.e. previously set command and channel). + if (*p & 0x80) { + cmd = *p++; + ch = cmd & 0x0f; + cmd >>= 4; } - debugC(3, kDebugLevelSound, "set patch %02x (%d,%d), ch %02x", - parm1, waveaddr[parm1], wavesize[parm1], ch); + + switch (cmd) { + case MIDI_CMD_NOTE_OFF: + parm1 = *p++; + parm2 = *p++; +#if 0 + if (ch < NUM_CHANNELS) + stopNote(ch); #endif - break; + debugC(3, kDebugLevelSound, "note off, channel %02x, note %02x, velocity %02x", ch, parm1, parm2); + break; + case MIDI_CMD_NOTE_ON: + parm1 = *p++; + parm2 = *p++; +#if 0 + if (ch < NUM_CHANNELS) + playNote(ch, noteToPeriod(parm1), 127); +#endif + debugC(3, kDebugLevelSound, "note on, channel %02x, note %02x, velocity %02x", ch, parm1, parm2); + break; + case MIDI_CMD_CONTROLLER: + // The tested Apple IIGS AGI MIDI resources only used + // controllers 0 (Bank select?), 7 (Volume) and 64 (Sustain On/Off). + // Controller 0's parameter was in range 94-127, + // controller 7's parameter was in range 0-127 and + // controller 64's parameter was always 0 (i.e. sustain off). + // TODO: Find out what controller 0 does and implement volume changes. + parm1 = *p++; + parm2 = *p++; + debugC(3, kDebugLevelSound, "controller %02x, ch %02x, val %02x", parm1, ch, parm2); + break; + case MIDI_CMD_PROGRAM_CHANGE: + // In all the tested Apple IIGS AGI MIDI resources + // program change's parameter was in range 0-43. + // This doesn't map directly to instrument numbers as all of + // the tested Apple IIGS AGI games only use 26 or 28 instruments. + // TODO: Find out the mapping to instruments and implement it. + parm1 = *p++; + debugC(3, kDebugLevelSound, "program change %02x, channel %02x", parm1, ch); +#if 0 + if (ch < NUM_CHANNELS) { + chn[ch].ins = (uint16 *)&wave[waveaddr[parm1]]; + chn[ch].size = wavesize[parm1]; + } + debugC(3, kDebugLevelSound, "set patch %02x (%d,%d), ch %02x", + parm1, waveaddr[parm1], wavesize[parm1], ch); +#endif + break; + case MIDI_CMD_PITCH_WHEEL: + parm1 = *p++; + parm2 = *p++; + // In all the tested Apple IIGS AGI MIDI resources + // pitch wheel commands always had 0x2000 (Center position) + // as the combined 14-bit value for the position. + uint16 wheelPos = ((parm2 & 0x7F) << 7) | (parm1 & 0x7F); // 14-bit value + debugC(3, kDebugLevelSound, "Pitch wheel position %04x (Not implemented yet)", wheelPos); + break; + } } - chn[0].timer = *p++; - chn[0].ptr = (struct AgiNote *)p; + midiObj->setPtr(p); +} - if (*p >= 0xfc) { - debugC(3, kDebugLevelSound, "end of sequence"); - playing = 0; +void SoundMgr::playSampleSound() { + if (_vm->_soundemu != SOUND_EMU_APPLE2GS) { + warning("Trying to play a sample but not using Apple IIGS sound emulation mode"); return; } -} -void SoundMgr::playSampleSound() { - playNote(0, 11025 * 10, 200); - playing = 1; + if (_playingSound != -1) + _playing = !_IIgsChannel.end; } -#endif /* USE_IIGS_SOUND */ - void SoundMgr::playAgiSound() { - int i, freq; + int i; + AgiNote note; - for (playing = i = 0; i < (_vm->_soundemu == SOUND_EMU_PC ? 1 : 4); i++) { - playing |= !chn[i].end; + _playing = false; + for (i = 0; i < (_vm->_soundemu == SOUND_EMU_PC ? 1 : 4); i++) { + _playing |= !_chn[i].end; + note.read(_chn[i].ptr); // Read a single note (Doesn't advance the pointer) - if (chn[i].end) + if (_chn[i].end) continue; - if ((--chn[i].timer) <= 0) { + if ((--_chn[i].timer) <= 0) { stopNote(i); - freq = ((chn[i].ptr->frq0 & 0x3f) << 4) | (int)(chn[i].ptr->frq1 & 0x0f); - if (freq) { - uint8 v = chn[i].ptr->vol & 0x0f; - playNote(i, freq * 10, v == 0xf ? 0 : 0xff - (v << 1)); + if (note.freqDiv != 0) { + int volume = (note.attenuation == 0x0F) ? 0 : (0xFF - note.attenuation * 2); + playNote(i, note.freqDiv * 10, volume); } - chn[i].timer = ((int)chn[i].ptr->durHi << 8) | chn[i].ptr->durLo; - - if (chn[i].timer == 0xffff) { - chn[i].end = 1; - chn[i].vol = 0; - chn[i].env = 0; -#ifdef USE_CHORUS - /* chorus */ - if (chn[i].type == AGI_SOUND_4CHN && _vm->_soundemu == SOUND_EMU_NONE && i < 3) { - chn[i + 4].vol = 0; - chn[i + 4].env = 0; + _chn[i].timer = note.duration; + + if (_chn[i].timer == 0xffff) { + _chn[i].end = 1; + _chn[i].vol = 0; + _chn[i].env = 0; + + if (g_useChorus) { + /* chorus */ + if (_chn[i].type == AGI_SOUND_4CHN && _vm->_soundemu == SOUND_EMU_NONE && i < 3) { + _chn[i + 4].vol = 0; + _chn[i + 4].env = 0; + } } -#endif } - chn[i].ptr++; + _chn[i].ptr += 5; // Advance the pointer to the next note data (5 bytes per note) } } } @@ -610,100 +689,183 @@ void SoundMgr::playAgiSound() { void SoundMgr::playSound() { int i; - if (endflag == -1) + if (_endflag == -1) return; -#ifdef USE_IIGS_SOUND - if (chn[0].type == AGI_SOUND_MIDI) { - /* play_midi_sound (); */ - playing = 0; - } else if (chn[0].type == AGI_SOUND_SAMPLE) { - playSampleSound(); - } else -#endif + if (_vm->_soundemu == SOUND_EMU_APPLE2GS) { + if (_playingSound != -1) { + if (_vm->_game.sounds[_playingSound]->type() == AGI_SOUND_MIDI) { + playMidiSound(); + //warning("playSound: Trying to play an Apple IIGS MIDI sound. Not yet implemented!"); + } else if (_vm->_game.sounds[_playingSound]->type() == AGI_SOUND_SAMPLE) { + //debugC(3, kDebugLevelSound, "playSound: Trying to play an Apple IIGS sample"); + playSampleSound(); + } + } + } else { + //debugC(3, kDebugLevelSound, "playSound: Trying to play a PCjr 4-channel sound"); playAgiSound(); + } - if (!playing) { - for (i = 0; i < NUM_CHANNELS; chn[i++].vol = 0); + if (!_playing) { + if (_vm->_soundemu != SOUND_EMU_APPLE2GS) { + for (i = 0; i < NUM_CHANNELS; _chn[i++].vol = 0); + } - if (endflag != -1) - _vm->setflag(endflag, true); + if (_endflag != -1) + _vm->setflag(_endflag, true); - if (playingSound != -1) - _vm->_game.sounds[playingSound].flags &= ~SOUND_PLAYING; - playingSound = -1; - endflag = -1; + if (_playingSound != -1) + _vm->_game.sounds[_playingSound]->stop(); + _playingSound = -1; + _endflag = -1; } } uint32 SoundMgr::mixSound(void) { register int i, p; - int16 *src; + const int16 *src; int c, b, m; - memset(sndBuffer, 0, BUFFER_SIZE << 1); + memset(_sndBuffer, 0, BUFFER_SIZE << 1); + + if (!_playing || _playingSound == -1) + return BUFFER_SIZE; + + // Handle Apple IIGS sound mixing here + if (_vm->_soundemu == SOUND_EMU_APPLE2GS) { + AgiSoundType type = (AgiSoundType) _vm->_game.sounds[_playingSound]->type(); + // Currently we only support mixing a single sample in Apple IIGS mixing code. + if (type != AGI_SOUND_SAMPLE) + return IIGS_BUFFER_SIZE; + //IIgsWaveInfo &waveInfo = _IIgsChannel.ins.oscList(0).waves[0]; + + //uint period = noteToPeriod(fracToInt(_IIgsChannel.note + FRAC_HALF)); + //_IIgsChannel.posAdd = ((frac_t) (118600 * 4 / period)) << (FRAC_BITS - 8); + + // Hertz (number of vibrations a second) = 6.875 x 2 ^ ( ( 3 + MIDI_Pitch ) / 12 ) + // From http://www.musicmasterworks.com/WhereMathMeetsMusic.html + //double hertz = 6.875 * pow(SEMITONE, 3 + fracToDouble(_IIgsChannel.note)); + //double hertz = 8.175798915644 * pow(SEMITONE, fracToDouble(_IIgsChannel.note)); + // double step = getRate() / hertz; + // _IIgsChannel.posAdd = doubleToFrac(step); + + // Frequency multiplier was 1076.0 based on tests made with MESS 0.117. + // Tests made with KEGS32 averaged the multiplier to around 1045. + // So this is a guess but maybe it's 1046.5... i.e. C6's frequency? + double hertz = C6_FREQ * pow(SEMITONE, fracToDouble(_IIgsChannel.note)); + _IIgsChannel.posAdd = doubleToFrac(hertz / getRate()); + _IIgsChannel.vol = doubleToFrac(fracToDouble(_IIgsChannel.envVol) * fracToDouble(_IIgsChannel.chanVol) / 127.0); + double tempVol = fracToDouble(_IIgsChannel.vol)/127.0; + + for (i = 0; i < IIGS_BUFFER_SIZE; i++) { + b = _IIgsChannel.sample[fracToInt(_IIgsChannel.pos)]; + // DOESN'T DO MIXING YET! ONLY ONE SAMPLE PER PLAYING! + _sndBuffer[i] = (int16) (b * tempVol); + _IIgsChannel.pos += _IIgsChannel.posAdd; + + if (_IIgsChannel.pos >= intToFrac(_IIgsChannel.size)) { + if (_IIgsChannel.loop) { + _IIgsChannel.pos %= intToFrac(_IIgsChannel.size); + // Probably we should loop the envelope too + _IIgsChannel.envSeg = 0; + _IIgsChannel.envVol = _IIgsChannel.startEnvVol; + } else { + _IIgsChannel.pos = _IIgsChannel.chanVol = 0; + _IIgsChannel.end = true; + break; + } + } + } + + if (_IIgsChannel.envSeg <= _IIgsChannel.ins.relseg) { + IIgsEnvelopeSegment &seg = _IIgsChannel.ins.env.seg[_IIgsChannel.envSeg]; + double bufSecLen = IIGS_BUFFER_SIZE / (double) getRate(); + double ticksPerSec = 100; // 1000 is way too much + double bufTickLen = bufSecLen / (1.0/ticksPerSec); + frac_t envVolDelta = doubleToFrac((seg.inc/256.0)*bufTickLen); + if (intToFrac(seg.bp) >= _IIgsChannel.envVol) { + _IIgsChannel.envVol += envVolDelta; + if (_IIgsChannel.envVol >= intToFrac(seg.bp)) { + _IIgsChannel.envVol = intToFrac(seg.bp); + _IIgsChannel.envSeg += 1; + } + } else { + _IIgsChannel.envVol -= envVolDelta; + if (_IIgsChannel.envVol <= intToFrac(seg.bp)) { + _IIgsChannel.envVol = intToFrac(seg.bp); + _IIgsChannel.envSeg += 1; + } + } + } + //_IIgsChannel.envSeg += doubleToFrac(1/100.0); + return IIGS_BUFFER_SIZE; + } /* else ... */ + // Handle PCjr 4-channel sound mixing here for (c = 0; c < NUM_CHANNELS; c++) { - if (!chn[c].vol) + if (!_chn[c].vol) continue; - m = chn[c].flags & AGI_SOUND_ENVELOPE ? - chn[c].vol * chn[c].env >> 16 : chn[c].vol; + m = _chn[c].flags & AGI_SOUND_ENVELOPE ? + _chn[c].vol * _chn[c].env >> 16 : _chn[c].vol; - if (chn[c].type != AGI_SOUND_4CHN || c != 3) { - src = chn[c].ins; + if (_chn[c].type != AGI_SOUND_4CHN || c != 3) { + src = _chn[c].ins; - p = chn[c].phase; + p = _chn[c].phase; for (i = 0; i < BUFFER_SIZE; i++) { b = src[p >> 8]; #ifdef USE_INTERPOLATION - b += ((src[((p >> 8) + 1) % chn[c].size] - src[p >> 8]) * (p & 0xff)) >> 8; + b += ((src[((p >> 8) + 1) % _chn[c].size] - src[p >> 8]) * (p & 0xff)) >> 8; #endif - sndBuffer[i] += (b * m) >> 4; + _sndBuffer[i] += (b * m) >> 4; - p += (uint32) 118600 *4 / chn[c].freq; + p += (uint32) 118600 *4 / _chn[c].freq; + // FIXME: Fingolfin asks: why is there a FIXME here? Please either clarify what + // needs fixing, or remove it! /* FIXME */ - if (chn[c].flags & AGI_SOUND_LOOP) { - p %= chn[c].size << 8; + if (_chn[c].flags & AGI_SOUND_LOOP) { + p %= _chn[c].size << 8; } else { - if (p >= chn[c].size << 8) { - p = chn[c].vol = 0; - chn[c].end = 1; + if (p >= _chn[c].size << 8) { + p = _chn[c].vol = 0; + _chn[c].end = 1; break; } } } - chn[c].phase = p; + _chn[c].phase = p; } else { /* Add white noise */ for (i = 0; i < BUFFER_SIZE; i++) { b = _vm->_rnd->getRandomNumber(255) - 128; - sndBuffer[i] += (b * m) >> 4; + _sndBuffer[i] += (b * m) >> 4; } } - switch (chn[c].adsr) { + switch (_chn[c].adsr) { case AGI_SOUND_ENV_ATTACK: /* not implemented */ - chn[c].adsr = AGI_SOUND_ENV_DECAY; + _chn[c].adsr = AGI_SOUND_ENV_DECAY; break; case AGI_SOUND_ENV_DECAY: - if (chn[c].env > chn[c].vol * ENV_SUSTAIN + ENV_DECAY) { - chn[c].env -= ENV_DECAY; + if (_chn[c].env > _chn[c].vol * ENV_SUSTAIN + ENV_DECAY) { + _chn[c].env -= ENV_DECAY; } else { - chn[c].env = chn[c].vol * ENV_SUSTAIN; - chn[c].adsr = AGI_SOUND_ENV_SUSTAIN; + _chn[c].env = _chn[c].vol * ENV_SUSTAIN; + _chn[c].adsr = AGI_SOUND_ENV_SUSTAIN; } break; case AGI_SOUND_ENV_SUSTAIN: break; case AGI_SOUND_ENV_RELEASE: - if (chn[c].env >= ENV_RELEASE) { - chn[c].env -= ENV_RELEASE; + if (_chn[c].env >= ENV_RELEASE) { + _chn[c].env -= ENV_RELEASE; } else { - chn[c].env = 0; + _chn[c].env = 0; } } } @@ -711,101 +873,194 @@ uint32 SoundMgr::mixSound(void) { return BUFFER_SIZE; } -#ifdef USE_IIGS_SOUND +/** + * Finds information about an Apple IIGS AGI executable based on the game ID. + * @return A non-null IIgsExeInfo pointer if successful, otherwise NULL. + */ +const IIgsExeInfo *SoundMgr::getIIgsExeInfo(enum AgiGameID gameid) const { + for (int i = 0; i < ARRAYSIZE(IIgsExeInfos); i++) + if (IIgsExeInfos[i].gameid == gameid) + return &IIgsExeInfos[i]; + return NULL; +} -#if 0 -int SoundMgr::loadInstruments(char *fname) { - Common::File fp; - int i, j, k; - struct SoundInstrument ai; - int numWav; - char *path; - - path = "sierrast"; - - if (!fp.open(path)) - return errBadFileOpen; - report("Loading samples: %s\n", path); - - if ((wave = malloc(0x10000 * 2)) == NULL) - return errNotEnoughMemory; - - fp.read(wave, 0x10000); - fp.close(); - for (i = 0x10000; i--;) { - ((int16 *)wave)[i] = 2 * ((int16)wave[i] - 128); - } +bool SoundMgr::loadInstrumentHeaders(const Common::String &exePath, const IIgsExeInfo &exeInfo) { + bool loadedOk = false; // Was loading successful? + Common::File file; - fp = fopen("bla", "w"); - fwrite(wave, 2, 0x10000, fp); - fclose(fp); + // Open the executable file and check that it has correct size + file.open(exePath); + if (file.size() != exeInfo.exeSize) { + debugC(3, kDebugLevelSound, "Apple IIGS executable (%s) has wrong size (Is %d, should be %d)", + exePath.c_str(), file.size(), exeInfo.exeSize); + } - report("Loading instruments: %s\n", path); + // Read the whole executable file into memory + Common::MemoryReadStream *data = file.readStream(file.size()); + file.close(); + + // Check that we got enough data to be able to parse the instruments + if (data != NULL && data->size() >= (exeInfo.instSetStart + exeInfo.instSet.byteCount)) { + // Check instrument set's length (The info's saved in the executable) + data->seek(exeInfo.instSetStart - 4); + uint16 instSetByteCount = data->readUint16LE(); + if (instSetByteCount != exeInfo.instSet.byteCount) { + debugC(3, kDebugLevelSound, "Wrong instrument set size (Is %d, should be %d) in Apple IIGS executable (%s)", + instSetByteCount, exeInfo.instSet.byteCount, exePath.c_str()); + } - if ((fp = fopen(path, "rb")) == NULL) - return errBadFileOpen; + // Check instrument set's md5sum + data->seek(exeInfo.instSetStart); + char md5str[32+1]; + Common::md5_file_string(*data, md5str, exeInfo.instSet.byteCount); + if (scumm_stricmp(md5str, exeInfo.instSet.md5)) { + warning("Unknown Apple IIGS instrument set (md5: %s) in %s, trying to use it nonetheless", + md5str, exePath.c_str()); + } - fseek(fp, 0x8469, SEEK_SET); + // Read in the instrument set one instrument at a time + data->seek(exeInfo.instSetStart); + g_numInstruments = 0; // Zero number of successfully loaded instruments + for (uint i = 0; i < exeInfo.instSet.instCount; i++) { + if (!g_instruments[i].read(*data)) { + warning("Error loading Apple IIGS instrument (%d. of %d) from %s, not loading more instruments", + i + 1, exeInfo.instSet.instCount, exePath.c_str()); + break; + } + g_numInstruments++; // Increase number of successfully loaded instruments + } - for (numWav = j = 0; j < 40; j++) { - fread(&ai, 1, 32, fp); + // Loading was successful only if all instruments were loaded successfully + loadedOk = (g_numInstruments == exeInfo.instSet.instCount); + } else // Couldn't read enough data from the executable file + warning("Error loading instruments from Apple IIGS executable (%s)", exePath.c_str()); - if (ai.env[0].bp > 0x7f) - break; + delete data; // Free the memory buffer allocated for reading the executable file + return loadedOk; +} -#if 0 - printf("Instrument %d loaded ----------------\n", j); - printf("Envelope:\n"); - for (i = 0; i < 8; i++) - printf("[seg %d]: BP %02x Inc %04x\n", i, ai.env[i].bp, - ((int)ai.env[i].inc_hi << 8) | ai.env[i].inc_lo); - printf("rel seg: %d, pri inc: %d, bend range: %d, vib dep: %d, " - "vib spd: %d\n", ai.relseg, ai.priority, - ai.bendrange, ai.vibdepth, ai.vibspeed); - printf("A wave count: %d, B wave count: %d\n", ai.wac, ai.wbc); -#endif +/** + * Convert sample from 8-bit unsigned to 16-bit signed format. + * @param source Source stream containing the 8-bit unsigned sample data. + * @param dest Destination buffer for the 16-bit signed sample data. + * @param length Length of the sample data to be converted. + */ +bool SoundMgr::convertWave(Common::SeekableReadStream &source, int16 *dest, uint length) { + // Convert the wave from 8-bit unsigned to 16-bit signed format + for (uint i = 0; i < length; i++) + dest[i] = (int16) ((source.readByte() - 128) * 256); + return !source.ioFailed(); +} - for (k = 0; k < ai.wac; k++, num_wav++) { - fread(&ai.wal[k], 1, 6, fp); -#if 0 - printf("[A %d of %d] top: %02x, wave address: %02x, " - "size: %02x, mode: %02x, relPitch: %04x\n", k + 1, - ai.wac, ai.wal[k].top, ai.wal[k].addr, ai.wal[k].size, - ai.wal[k].mode, ((int)ai.wal[k].rel_hi << 8) | ai.wal[k].rel_lo); -#endif +Common::MemoryReadStream *SoundMgr::loadWaveFile(const Common::String &wavePath, const IIgsExeInfo &exeInfo) { + Common::File file; + + // Open the wave file and read it into memory + file.open(wavePath); + Common::MemoryReadStream *uint8Wave = file.readStream(file.size()); + file.close(); + + // Check that we got the whole wave file + if (uint8Wave != NULL && uint8Wave->size() == SIERRASTANDARD_SIZE) { + // Check wave file's md5sum + char md5str[32+1]; + Common::md5_file_string(*uint8Wave, md5str, SIERRASTANDARD_SIZE); + if (scumm_stricmp(md5str, exeInfo.instSet.waveFileMd5)) { + warning("Unknown Apple IIGS wave file (md5: %s, game: %s).\n" \ + "Please report the information on the previous line to the ScummVM team.\n" \ + "Using the wave file as it is - music may sound weird", md5str, exeInfo.exePrefix); } + uint8Wave->seek(0); // Seek wave to its start + return uint8Wave; + } else { // Couldn't read the wave file or it had incorrect size + warning("Error loading Apple IIGS wave file (%s), not loading instruments", wavePath.c_str()); + delete uint8Wave; // Free the memory buffer allocated for reading the wave file + return NULL; + } +} - for (k = 0; k < ai.wbc; k++, num_wav++) { - fread(&ai.wbl[k], 1, 6, fp); -#if 0 - printf("[B %d of %d] top: %02x, wave address: %02x, " - "size: %02x, mode: %02x, relPitch: %04x\n", k + 1, ai.wbc, - ai.wbl[k].top, ai.wbl[k].addr, ai.wbl[k].size, - ai.wbl[k].mode, ((int)ai.wbl[k].rel_hi << 8) | ai.wbl[k].rel_lo); -#endif - } - waveaddr[j] = 256 * ai.wal[0].addr; - wavesize[j] = 256 * (1 << ((ai.wal[0].size) & 0x07)); -#if 1 - printf("%d addr = %d\n", j, waveaddr[j]); - printf(" size = %d\n", wavesize[j]); -#endif +/** + * A function object (i.e. a functor) for testing if a FilesystemNode + * object's name is equal (Ignoring case) to a string or to at least + * one of the strings in a list of strings. Can be used e.g. with find_if(). + */ +struct fsnodeNameEqualsIgnoreCase : public Common::UnaryFunction<const FilesystemNode&, bool> { + fsnodeNameEqualsIgnoreCase(const Common::StringList &str) : _str(str) {} + fsnodeNameEqualsIgnoreCase(const Common::String str) { _str.push_back(str); } + bool operator()(const FilesystemNode ¶m) const { + for (Common::StringList::const_iterator iter = _str.begin(); iter != _str.end(); iter++) + if (param.getName().equalsIgnoreCase(*iter)) + return true; + return false; } +private: + Common::StringList _str; +}; - numInstruments = j; - printf("%d Ensoniq 5503 instruments loaded. (%d waveforms)\n", num_instruments, num_wav); +bool SoundMgr::loadInstruments() { + // Check that the platform is Apple IIGS, as only it uses custom instruments + if (_vm->getPlatform() != Common::kPlatformApple2GS) { + debugC(3, kDebugLevelSound, "Platform isn't Apple IIGS so not loading any instruments"); + return true; + } + + // Get info on the particular Apple IIGS AGI game's executable + const IIgsExeInfo *exeInfo = getIIgsExeInfo((enum AgiGameID) _vm->getGameID()); + if (exeInfo == NULL) { + warning("Unsupported Apple IIGS game, not loading instruments"); + return false; + } + + // List files in the game path + FSList fslist; + FilesystemNode dir(ConfMan.get("path")); + if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) { + warning("Invalid game path (\"%s\"), not loading Apple IIGS instruments", dir.getPath().c_str()); + return false; + } - fclose(fp); + // Populate executable filenames list (Long filename and short filename) for searching + Common::StringList exeNames; + exeNames.push_back(Common::String(exeInfo->exePrefix) + ".SYS16"); + exeNames.push_back(Common::String(exeInfo->exePrefix) + ".SYS"); + + // Populate wave filenames list (Long filename and short filename) for searching + Common::StringList waveNames; + waveNames.push_back("SIERRASTANDARD"); + waveNames.push_back("SIERRAST"); + + // Search for the executable file and the wave file (i.e. check if any of the filenames match) + FSList::const_iterator exeFsnode, waveFsnode; + exeFsnode = Common::find_if(fslist.begin(), fslist.end(), fsnodeNameEqualsIgnoreCase(exeNames)); + waveFsnode = Common::find_if(fslist.begin(), fslist.end(), fsnodeNameEqualsIgnoreCase(waveNames)); + + // Make sure that we found the executable file + if (exeFsnode == fslist.end()) { + warning("Couldn't find Apple IIGS game executable (%s), not loading instruments", exeNames.begin()->c_str()); + return false; + } - return errOK; -} + // Make sure that we found the wave file + if (waveFsnode == fslist.end()) { + warning("Couldn't find Apple IIGS wave file (%s), not loading instruments", waveNames.begin()->c_str()); + return false; + } -void Sound::unloadInstruments() { - free(instruments); -} -#endif + // First load the wave file and then load the instrument headers. + // Finally fix the instruments' lengths using the wave file data + // (A zero in the wave file data can end the sample prematurely) + // and convert the wave file from 8-bit unsigned to 16-bit signed format. + Common::MemoryReadStream *uint8Wave = loadWaveFile(waveFsnode->getPath(), *exeInfo); + // Seek the wave to its + if (uint8Wave != NULL) + uint8Wave->seek(0); + + bool result = uint8Wave != NULL && loadInstrumentHeaders(exeFsnode->getPath(), *exeInfo) && + finalizeInstruments(*uint8Wave) && convertWave(*uint8Wave, g_wave, uint8Wave->size()); -#endif /* USE_IIGS_SOUND */ + delete uint8Wave; // Free the 8-bit unsigned wave file buffer + return result; +} static void fillAudio(void *udata, int16 *stream, uint len) { SoundMgr *soundMgr = (SoundMgr *)udata; @@ -834,10 +1089,14 @@ static void fillAudio(void *udata, int16 *stream, uint len) { n -= s; } -SoundMgr::SoundMgr(AgiEngine *agi, Audio::Mixer *pMixer) { +SoundMgr::SoundMgr(AgiBase *agi, Audio::Mixer *pMixer) { _vm = agi; _mixer = pMixer; _sampleRate = pMixer->getOutputRate(); + _endflag = -1; + _playingSound = -1; + _sndBuffer = 0; + _waveform = 0; } void SoundMgr::premixerCall(int16 *data, uint len) { diff --git a/engines/agi/sound.h b/engines/agi/sound.h index 5b3a16668b..5d9bfda445 100644 --- a/engines/agi/sound.h +++ b/engines/agi/sound.h @@ -26,20 +26,23 @@ #ifndef AGI_SOUND_H #define AGI_SOUND_H +#include "agi/agi.h" #include "sound/audiostream.h" #include "sound/mixer.h" +#include "common/frac.h" namespace Agi { #define BUFFER_SIZE 410 +#define IIGS_BUFFER_SIZE 200 #define SOUND_EMU_NONE 0 #define SOUND_EMU_PC 1 #define SOUND_EMU_TANDY 2 #define SOUND_EMU_MAC 3 #define SOUND_EMU_AMIGA 4 +#define SOUND_EMU_APPLE2GS 5 -#define SOUND_PLAYING 0x01 #define WAVEFORM_SIZE 64 #define ENV_ATTACK 10000 /**< envelope attack rate */ #define ENV_DECAY 1000 /**< envelope decay rate */ @@ -47,51 +50,197 @@ namespace Agi { #define ENV_RELEASE 7500 /**< envelope release rate */ #define NUM_CHANNELS 7 /**< number of sound channels */ -/** - * AGI sound resource structure. - */ -struct AgiSound { - uint32 flen; /**< size of raw data */ - uint8 *rdata; /**< raw sound data */ - uint8 flags; /**< sound flags */ - uint16 type; /**< sound resource type */ +// MIDI command values (Shifted right by 4 so they're in the lower nibble) +#define MIDI_CMD_NOTE_OFF 0x08 +#define MIDI_CMD_NOTE_ON 0x09 +#define MIDI_CMD_CONTROLLER 0x0B +#define MIDI_CMD_PROGRAM_CHANGE 0x0C +#define MIDI_CMD_PITCH_WHEEL 0x0E +// Whole MIDI byte values (Command and channel info together) +#define MIDI_BYTE_STOP_SEQUENCE 0xFC +#define MIDI_BYTE_TIMER_SYNC 0xF8 + +struct IIgsEnvelopeSegment { + uint8 bp; + uint16 inc; ///< 8b.8b fixed point, very probably little endian +}; + +#define ENVELOPE_SEGMENT_COUNT 8 +struct IIgsEnvelope { + IIgsEnvelopeSegment seg[ENVELOPE_SEGMENT_COUNT]; + + /** Reads an Apple IIGS envelope from then given stream. */ + bool read(Common::SeekableReadStream &stream); +}; + +// 2**(1/12) i.e. the 12th root of 2 +#define SEMITONE 1.059463094359295 + +// C6's frequency is A4's (440 Hz) frequency but one full octave and three semitones higher +// i.e. C6_FREQ = 440 * pow(2.0, 15/12.0) +#define C6_FREQ 1046.502261202395 + +// Size of the SIERRASTANDARD file (i.e. the wave file i.e. the sample data used by the instruments). +#define SIERRASTANDARD_SIZE 65536 + +// Maximum number of instruments in an Apple IIGS instrument set. +// Chosen empirically based on Apple IIGS AGI game data, increase if needed. +#define MAX_INSTRUMENTS 28 + +struct IIgsWaveInfo { + uint8 top; + uint addr; + uint size; +// Oscillator channel +#define OSC_CHANNEL_RIGHT 0 +#define OSC_CHANNEL_LEFT 1 + uint channel; +// Oscillator mode +#define OSC_MODE_LOOP 0 +#define OSC_MODE_ONESHOT 1 +#define OSC_MODE_SYNC_AM 2 +#define OSC_MODE_SWAP 3 + uint mode; + bool halt; + int16 relPitch; ///< Relative pitch in semitones (Signed 8b.8b fixed point) + + /** Reads an Apple IIGS wave information structure from the given stream. */ + bool read(Common::SeekableReadStream &stream, bool ignoreAddr = false); + bool finalize(Common::SeekableReadStream &uint8Wave); }; -#include "common/pack-start.h" +// Number of waves per Apple IIGS sound oscillator +#define WAVES_PER_OSCILLATOR 2 + +/** An Apple IIGS sound oscillator. Consists always of two waves. */ +struct IIgsOscillator { + IIgsWaveInfo waves[WAVES_PER_OSCILLATOR]; + + bool finalize(Common::SeekableReadStream &uint8Wave); +}; + +// Maximum number of oscillators in an Apple IIGS instrument. +// Chosen empirically based on Apple IIGS AGI game data, increase if needed. +#define MAX_OSCILLATORS 4 + +/** An Apple IIGS sound oscillator list. */ +struct IIgsOscillatorList { + uint count; ///< Oscillator count + IIgsOscillator osc[MAX_OSCILLATORS]; ///< The oscillators + + /** Indexing operators for easier access to the oscillators. */ + const IIgsOscillator &operator()(uint index) const { return osc[index]; } + IIgsOscillator &operator()(uint index) { return osc[index]; } + + /** Reads an Apple IIGS oscillator list from the given stream. */ + bool read(Common::SeekableReadStream &stream, uint oscillatorCount, bool ignoreAddr = false); + bool finalize(Common::SeekableReadStream &uint8Wave); +}; + +struct IIgsInstrumentHeader { + IIgsEnvelope env; + uint8 relseg; + uint8 bendrange; + uint8 vibdepth; + uint8 vibspeed; + IIgsOscillatorList oscList; + + /** + * Read an Apple IIGS instrument header from the given stream. + * @param stream The source stream from which to read the data. + * @param ignoreAddr Should we ignore wave infos' wave address variable's value? + * @return True if successful, false otherwise. + */ + bool read(Common::SeekableReadStream &stream, bool ignoreAddr = false); + bool finalize(Common::SeekableReadStream &uint8Wave); +}; + +struct IIgsSampleHeader { + uint16 type; + uint8 pitch; ///< Logarithmic, base is 2**(1/12), unknown multiplier (Possibly in range 1040-1080) + uint8 unknownByte_Ofs3; // 0x7F in Gold Rush's sound resource 60, 0 in all others. + uint8 volume; ///< Current guess: Logarithmic in 6 dB steps + uint8 unknownByte_Ofs5; ///< 0 in all tested samples. + uint16 instrumentSize; ///< Little endian. 44 in all tested samples. A guess. + uint16 sampleSize; ///< Little endian. Accurate in all tested samples excluding Manhunter I's sound resource 16. + IIgsInstrumentHeader instrument; + + /** + * Read an Apple IIGS AGI sample header from the given stream. + * @param stream The source stream from which to read the data. + * @return True if successful, false otherwise. + */ + bool read(Common::SeekableReadStream &stream); + bool finalize(Common::SeekableReadStream &uint8Wave); +}; /** * AGI sound note structure. */ struct AgiNote { - uint8 durLo; /**< LSB of note duration */ - uint8 durHi; /**< MSB of note duration */ - uint8 frq0; /**< LSB of note frequency */ - uint8 frq1; /**< MSB of note frequency */ - uint8 vol; /**< note volume */ + uint16 duration; ///< Note duration + uint16 freqDiv; ///< Note frequency divisor (10-bit) + uint8 attenuation; ///< Note volume attenuation (4-bit) + + /** Reads an AgiNote through the given pointer. */ + void read(const uint8 *ptr) { + duration = READ_LE_UINT16(ptr); + uint16 freqByte0 = *(ptr + 2); // Bits 4-9 of the frequency divisor + uint16 freqByte1 = *(ptr + 3); // Bits 0-3 of the frequency divisor + // Merge the frequency divisor's bits together into a single variable + freqDiv = ((freqByte0 & 0x3F) << 4) | (freqByte1 & 0x0F); + attenuation = *(ptr + 4) & 0x0F; + } }; -#include "common/pack-end.h" +struct IIgsChannelInfo { + IIgsInstrumentHeader ins; ///< Instrument info + const int16 *sample; ///< Source sample data (16-bit signed format) + frac_t pos; ///< Current sample position + frac_t posAdd; ///< Current sample position adder (Calculated using note, vibrato etc) + frac_t note; ///< Note + frac_t vol; ///< Current volume (Takes both channel volume and enveloping into account) + frac_t chanVol; ///< Channel volume + frac_t startEnvVol; ///< Starting envelope volume + frac_t envVol; ///< Current envelope volume + uint envSeg; ///< Current envelope segment + uint size; ///< Sample size + bool loop; ///< Should we loop the sample? + bool end; ///< Has the playing ended? +}; + /** + * AGI sound resource types. + * It's probably coincidence that all the values here are powers of two + * as they're simply the different used values in AGI sound resources' + * starts (The first 16-bit little endian word, to be precise). + */ + enum AgiSoundType { + AGI_SOUND_SAMPLE = 0x0001, + AGI_SOUND_MIDI = 0x0002, + AGI_SOUND_4CHN = 0x0008 + }; + enum AgiSoundFlags { + AGI_SOUND_LOOP = 0x0001, + AGI_SOUND_ENVELOPE = 0x0002 + }; + enum AgiSoundEnv { + AGI_SOUND_ENV_ATTACK = 3, + AGI_SOUND_ENV_DECAY = 2, + AGI_SOUND_ENV_SUSTAIN = 1, + AGI_SOUND_ENV_RELEASE = 0 + }; /** * AGI engine sound channel structure. */ struct ChannelInfo { -#define AGI_SOUND_SAMPLE 0x0001 -#define AGI_SOUND_MIDI 0x0002 -#define AGI_SOUND_4CHN 0x0008 - uint32 type; - struct AgiNote *ptr; - int16 *ins; + AgiSoundType type; + const uint8 *ptr; // Pointer to the AgiNote data + const int16 *ins; int32 size; uint32 phase; -#define AGI_SOUND_LOOP 0x0001 -#define AGI_SOUND_ENVELOPE 0x0002 - uint32 flags; -#define AGI_SOUND_ENV_ATTACK 3 -#define AGI_SOUND_ENV_DECAY 2 -#define AGI_SOUND_ENV_SUSTAIN 1 -#define AGI_SOUND_ENV_RELEASE 0 - uint32 adsr; + uint32 flags; // ORs values from AgiSoundFlags + AgiSoundEnv adsr; int32 timer; uint32 end; uint32 freq; @@ -99,13 +248,101 @@ struct ChannelInfo { uint32 env; }; +class SoundMgr; + +/** + * AGI sound resource structure. + */ +class AgiSound { +public: + AgiSound(SoundMgr &manager) : _manager(manager), _isPlaying(false), _isValid(false) {} + virtual ~AgiSound() {} + virtual void play() { _isPlaying = true; } + virtual void stop() { _isPlaying = false; } + virtual bool isPlaying() { return _isPlaying; } + virtual uint16 type() = 0; + + /** + * A named constructor for creating different types of AgiSound objects + * from a raw sound resource. + * + * NOTE: This function should take responsibility for freeing the raw resource + * from memory using free() or delegate the responsibility onwards to some other + * function! + */ + static AgiSound *createFromRawResource(uint8 *data, uint32 len, int resnum, SoundMgr &manager); + +protected: + SoundMgr &_manager; ///< AGI sound manager object + bool _isPlaying; ///< Is the sound playing? + bool _isValid; ///< Is this a valid sound object? +}; + +class PCjrSound : public AgiSound { +public: + PCjrSound(uint8 *data, uint32 len, int resnum, SoundMgr &manager); + ~PCjrSound() { if (_data != NULL) free(_data); } + virtual uint16 type() { return _type; } + const uint8 *getVoicePointer(uint voiceNum); +protected: + uint8 *_data; ///< Raw sound resource data + uint32 _len; ///< Length of the raw sound resource + uint16 _type; ///< Sound resource type +}; + +class IIgsMidi : public AgiSound { +public: + IIgsMidi(uint8 *data, uint32 len, int resnum, SoundMgr &manager); + ~IIgsMidi() { if (_data != NULL) free(_data); } + virtual uint16 type() { return _type; } + virtual const uint8 *getPtr() { return _ptr; } + virtual void setPtr(const uint8 *ptr) { _ptr = ptr; } + virtual void rewind() { _ptr = _data + 2; } +protected: + uint8 *_data; ///< Raw sound resource data + const uint8 *_ptr; ///< Pointer to the current position in the MIDI data + uint32 _len; ///< Length of the raw sound resource + uint16 _type; ///< Sound resource type +}; + +class IIgsSample : public AgiSound { +public: + IIgsSample(uint8 *data, uint32 len, int resnum, SoundMgr &manager); + ~IIgsSample() { delete[] _sample; } + virtual uint16 type() { return _header.type; } + const IIgsSampleHeader &getHeader() const { return _header; } + const int16 *getSample() const { return _sample; } +protected: + IIgsSampleHeader _header; ///< Apple IIGS AGI sample header + int16 *_sample; ///< Sample data (16-bit signed format) +}; + +/** Apple IIGS AGI instrument set information. */ +struct instrumentSetInfo { + uint byteCount; ///< Length of the whole instrument set in bytes + uint instCount; ///< Amount of instrument in the set + const char *md5; ///< MD5 hex digest of the whole instrument set + const char *waveFileMd5; ///< MD5 hex digest of the wave file (i.e. the sample data used by the instruments) +}; + +/** Apple IIGS AGI executable file information. */ +struct IIgsExeInfo { + enum AgiGameID gameid; ///< Game ID + const char *exePrefix; ///< Prefix of the Apple IIGS AGI executable (e.g. "SQ", "PQ", "KQ4" etc) + uint agiVer; ///< Apple IIGS AGI version number, not strictly needed + uint exeSize; ///< Size of the Apple IIGS AGI executable file in bytes + uint instSetStart; ///< Starting offset of the instrument set inside the executable file + const instrumentSetInfo &instSet; ///< Information about the used instrument set +}; + class AgiEngine; +class AgiBase; class SoundMgr : public Audio::AudioStream { - AgiEngine *_vm; + AgiBase *_vm; public: - SoundMgr(AgiEngine *agi, Audio::Mixer *pMixer); + SoundMgr(AgiBase *agi, Audio::Mixer *pMixer); ~SoundMgr(); virtual void setVolume(uint8 volume); @@ -133,11 +370,19 @@ private: Audio::SoundHandle _soundHandle; uint32 _sampleRate; + bool _playing; + ChannelInfo _chn[NUM_CHANNELS]; + IIgsChannelInfo _IIgsChannel; + int _endflag; + int _playingSound; + uint8 _env; + + int16 *_sndBuffer; + const int16 *_waveform; + void premixerCall(int16 *buf, uint len); public: - - void decodeSound(int); void unloadSound(int); void playSound(); int initSound(); @@ -148,11 +393,15 @@ public: void playNote(int i, int freq, int vol); void playAgiSound(); uint32 mixSound(); - int loadInstruments(char *fname); -#ifdef USE_IIGS_SOUND + bool loadInstruments(); void playMidiSound(); void playSampleSound(); -#endif + bool finalizeInstruments(Common::SeekableReadStream &uint8Wave); + Audio::AudioStream *makeIIgsSampleStream(Common::SeekableReadStream &stream, int resnum = -1); + const IIgsExeInfo *getIIgsExeInfo(enum AgiGameID gameid) const; + bool loadInstrumentHeaders(const Common::String &exePath, const IIgsExeInfo &exeInfo); + bool convertWave(Common::SeekableReadStream &source, int16 *dest, uint length); + Common::MemoryReadStream *loadWaveFile(const Common::String &wavePath, const IIgsExeInfo &exeInfo); }; } // End of namespace Agi diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp index 1d653a9415..bb334d0401 100644 --- a/engines/agi/text.cpp +++ b/engines/agi/text.cpp @@ -67,6 +67,8 @@ void AgiEngine::printText2(int l, const char *msg, int foff, int xoff, int yoff, for (m = (const unsigned char *)msg, x1 = y1 = 0; *m; m++) { if (*m >= 0x20 || *m == 1 || *m == 2 || *m == 3) { + // FIXME: Fingolfin asks: why is there a FIXME here? Please either clarify what + // needs fixing, or remove it! /* FIXME */ int ypos; diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index 76e4378982..aa927b1dcd 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -37,21 +37,10 @@ #include "sound/mididrv.h" #include "sound/mods/protracker.h" -#ifdef PALMOS_68K -#include "globals.h" -#endif - using Common::File; namespace AGOS { -#ifdef PALMOS_68K -#define PTR(a) a -static const GameSpecificSettings *simon1_settings; -static const GameSpecificSettings *simon2_settings; -static const GameSpecificSettings *feeblefiles_settings; -#else -#define PTR(a) &a static const GameSpecificSettings simon1_settings = { "EFFECTS", // effects_filename "SIMON", // speech_filename @@ -71,8 +60,6 @@ static const GameSpecificSettings puzzlepack_settings = { "", // effects_filename "MUSIC", // speech_filename }; -#endif - AGOSEngine_PuzzlePack::AGOSEngine_PuzzlePack(OSystem *system) : AGOSEngine_Feeble(system) { @@ -692,13 +679,9 @@ static const uint16 initialVideoWindows_Common[20] = { }; void AGOSEngine_PuzzlePack::setupGame() { - gss = PTR(puzzlepack_settings); + gss = &puzzlepack_settings; _numVideoOpcodes = 85; -#ifndef PALMOS_68K _vgaMemSize = 7500000; -#else - _vgaMemSize = gVars->memory[kMemSimon2Games]; -#endif _itemMemSize = 20000; _tableMemSize = 200000; _frameCount = 1; @@ -713,13 +696,9 @@ void AGOSEngine_PuzzlePack::setupGame() { } void AGOSEngine_Feeble::setupGame() { - gss = PTR(feeblefiles_settings); + gss = &feeblefiles_settings; _numVideoOpcodes = 85; -#ifndef PALMOS_68K _vgaMemSize = 7500000; -#else - _vgaMemSize = gVars->memory[kMemSimon2Games]; -#endif _itemMemSize = 20000; _tableMemSize = 200000; _frameCount = 1; @@ -736,14 +715,12 @@ void AGOSEngine_Feeble::setupGame() { } void AGOSEngine_Simon2::setupGame() { - gss = PTR(simon2_settings); + gss = &simon2_settings; _tableIndexBase = 1580 / 4; _textIndexBase = 1500 / 4; _numVideoOpcodes = 75; #if defined(__DS__) _vgaMemSize = 1300000; -#elif defined(PALMOS_68K) - _vgaMemSize = gVars->memory[kMemSimon2Games]; #else _vgaMemSize = 2000000; #endif @@ -772,15 +749,11 @@ void AGOSEngine_Simon2::setupGame() { } void AGOSEngine_Simon1::setupGame() { - gss = PTR(simon1_settings); + gss = &simon1_settings; _tableIndexBase = 1576 / 4; _textIndexBase = 1460 / 4; _numVideoOpcodes = 64; -#ifndef PALMOS_68K _vgaMemSize = 1000000; -#else - _vgaMemSize = gVars->memory[kMemSimon1Games]; -#endif _itemMemSize = 20000; _tableMemSize = 50000; _musicIndexBase = 1316 / 4; @@ -802,13 +775,9 @@ void AGOSEngine_Simon1::setupGame() { } void AGOSEngine_Waxworks::setupGame() { - gss = PTR(simon1_settings); + gss = &simon1_settings; _numVideoOpcodes = 64; -#ifndef PALMOS_68K _vgaMemSize = 1000000; -#else - _vgaMemSize = gVars->memory[kMemSimon1Games]; -#endif _itemMemSize = 80000; _tableMemSize = 50000; _frameCount = 4; @@ -826,13 +795,9 @@ void AGOSEngine_Waxworks::setupGame() { } void AGOSEngine_Elvira2::setupGame() { - gss = PTR(simon1_settings); + gss = &simon1_settings; _numVideoOpcodes = 60; -#ifndef PALMOS_68K _vgaMemSize = 1000000; -#else - _vgaMemSize = gVars->memory[kMemSimon1Games]; -#endif _itemMemSize = 64000; _tableMemSize = 100000; _frameCount = 4; @@ -849,13 +814,9 @@ void AGOSEngine_Elvira2::setupGame() { } void AGOSEngine_Elvira1::setupGame() { - gss = PTR(simon1_settings); + gss = &simon1_settings; _numVideoOpcodes = 57; -#ifndef PALMOS_68K _vgaMemSize = 1000000; -#else - _vgaMemSize = gVars->memory[kMemSimon1Games]; -#endif _itemMemSize = 64000; _tableMemSize = 256000; _frameCount = 4; @@ -1094,20 +1055,3 @@ void AGOSEngine::shutdown() { } } // End of namespace AGOS - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(AGOS_AGOS) -_GSETPTR(AGOS::simon1_settings, GBVARS_SIMON1SETTINGS_INDEX, AGOS::GameSpecificSettings, GBVARS_AGOS) -_GSETPTR(AGOS::simon2_settings, GBVARS_SIMON2SETTINGS_INDEX, AGOS::GameSpecificSettings, GBVARS_AGOS) -_GSETPTR(AGOS::feeblefiles_settings, GBVARS_FEEBLEFILESSETTINGS_INDEX, AGOS::GameSpecificSettings, GBVARS_AGOS) -_GEND - -_GRELEASE(AGOS_AGOS) -_GRELEASEPTR(GBVARS_SIMON1SETTINGS_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_SIMON2SETTINGS_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_FEEBLEFILESSETTINGS_INDEX, GBVARS_AGOS) -_GEND - -#endif diff --git a/engines/agos/charset.cpp b/engines/agos/charset.cpp index 9a37d90c33..68eb2d7ac8 100644 --- a/engines/agos/charset.cpp +++ b/engines/agos/charset.cpp @@ -543,7 +543,15 @@ void AGOSEngine::justifyOutPut(byte chr) { doOutput(&chr, 1); clsCheck(_textWindow); } else if (chr == 0 || chr == ' ' || chr == 10) { - if (_printCharMaxPos - _printCharCurPos >= _printCharPixelCount) { + bool fit; + + if (getGameType() == GType_FF || getGameType() == GType_PP) { + fit = _printCharMaxPos - _printCharCurPos > _printCharPixelCount; + } else { + fit = _printCharMaxPos - _printCharCurPos >= _printCharPixelCount; + } + + if (fit) { _printCharCurPos += _printCharPixelCount; doOutput(_lettersToPrintBuf, _numLettersToPrint); @@ -741,22 +749,6 @@ void AGOSEngine::windowScroll(WindowBlock *window) { _lockWord &= ~0x8000; } -#ifdef PALMOS_68K -static const byte *feeble_windowFont; -static const byte *czech_simonFont; -static const byte *russian_simonFont; -static const byte *polish_simonFont; -static const byte *french_simonFont; -static const byte *german_simonFont; -static const byte *hebrew_simonFont; -static const byte *italian_simonFont; -static const byte *spanish_simonFont; -static const byte *english_simonFont; -static const byte *spanish_commonFont; -static const byte *italian_commonFont; -static const byte *french_commonFont; -static const byte *english_commonFont; -#else static const byte feeble_windowFont[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,128,128,128,128,0,0,128,0,0,0, @@ -2267,7 +2259,6 @@ static const byte english_commonFont[] = { 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, }; -#endif void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { const byte *src; @@ -2379,29 +2370,3 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { } // End of namespace AGOS -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(AGOS_Charset) -_GSETPTR(AGOS::russian_windowFont, GBVARS_RUSSIANVIDEOFONT_INDEX, byte, GBVARS_AGOS) -//_GSETPTR(AGOS::polish_windowFont, GBVARS_POLISHVIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GSETPTR(AGOS::french_windowFont, GBVARS_FRENCHVIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GSETPTR(AGOS::german_windowFont, GBVARS_GERMANVIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GSETPTR(AGOS::hebrew_windowFont, GBVARS_HEBREWVIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GSETPTR(AGOS::italian_windowFont, GBVARS_ITALIANVIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GSETPTR(AGOS::spanish_windowFont, GBVARS_SPANISHVIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GSETPTR(AGOS::english_windowFont, GBVARS_VIDEOFONT_INDEX, byte, GBVARS_AGOS) -_GEND - -_GRELEASE(AGOS_Charset) -_GRELEASEPTR(GBVARS_RUSSIANVIDEOFONT_INDEX, GBVARS_AGOS) -//_GRELEASEPTR(GBVARS_POLISHVIDEOFONT_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_FRENCHVIDEOFONT_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_GERMANVIDEOFONT_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_HEBREWVIDEOFONT_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_ITALIANVIDEOFONT_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_SPANISHVIDEOFONT_INDEX, GBVARS_AGOS) -_GRELEASEPTR(GBVARS_VIDEOFONT_INDEX, GBVARS_AGOS) -_GEND - -#endif diff --git a/engines/agos/cursor.cpp b/engines/agos/cursor.cpp index 35bb8ea216..9c2cb42988 100644 --- a/engines/agos/cursor.cpp +++ b/engines/agos/cursor.cpp @@ -790,16 +790,3 @@ void AGOSEngine::drawMousePointer() { } } // End of namespace AGOS - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(AGOS_Cursor) -_GSETPTR(AGOS::_simon1_cursor, GBVARS_SIMON1CURSOR_INDEX, byte, GBVARS_AGOS) -_GEND - -_GRELEASE(AGOS_Cursor) -_GRELEASEPTR(GBVARS_SIMON1CURSOR_INDEX, GBVARS_AGOS) -_GEND - -#endif diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp index 0f5aa2768a..31ff220412 100644 --- a/engines/agos/detection.cpp +++ b/engines/agos/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/agos/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -101,55 +101,42 @@ static const Common::ADParams detectionParams = { Common::kADFlagAugmentPreferredTarget }; -GameList Engine_AGOS_gameIDList() { - return GameList(simonGames); -} - -GameDescriptor Engine_AGOS_findGameID(const char *gameid) { - return Common::AdvancedDetector::findGameID(gameid, simonGames, obsoleteGameIDsTable); -} +bool engineCreateAgos(OSystem *syst, Engine **engine, Common::EncapsulatedADGameDesc encapsulatedDesc) { + const AGOS::AGOSGameDescription *gd = (const AGOS::AGOSGameDescription *)(encapsulatedDesc.realDesc); + bool res = true; -GameList Engine_AGOS_detectGames(const FSList &fslist) { - return Common::AdvancedDetector::detectAllGames(fslist, detectionParams); -} - -PluginError Engine_AGOS_create(OSystem *syst, Engine **engine) { - assert(engine); - const char *gameid = ConfMan.get("gameid").c_str(); - - //Common::EncapsulatedADGameDesc encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); - //const AGOSGameDescription *gd = (const AGOSGameDescription *)(encapsulatedDesc.realDesc); - //if (gd == 0) { - // return kNoGameDataFoundError; - //} - - if (!scumm_stricmp("elvira1", gameid)) { + switch (gd->gameType) { + case AGOS::GType_ELVIRA1: *engine = new AGOS::AGOSEngine_Elvira1(syst); - } else if (!scumm_stricmp("elvira2", gameid)) { + break; + case AGOS::GType_ELVIRA2: *engine = new AGOS::AGOSEngine_Elvira2(syst); - } else if (!scumm_stricmp("waxworks", gameid)) { + break; + case AGOS::GType_WW: *engine = new AGOS::AGOSEngine_Waxworks(syst); - } else if (!scumm_stricmp("simon1", gameid)) { + break; + case AGOS::GType_SIMON1: *engine = new AGOS::AGOSEngine_Simon1(syst); - } else if (!scumm_stricmp("simon2", gameid)) { + break; + case AGOS::GType_SIMON2: *engine = new AGOS::AGOSEngine_Simon2(syst); - } else if (!scumm_stricmp("feeble", gameid)) { + break; + case AGOS::GType_FF: *engine = new AGOS::AGOSEngine_Feeble(syst); - } else if (!scumm_stricmp("dimp", gameid)) { - *engine = new AGOS::AGOSEngine_PuzzlePack(syst); - } else if (!scumm_stricmp("jumble", gameid)) { + break; + case AGOS::GType_PP: *engine = new AGOS::AGOSEngine_PuzzlePack(syst); - } else if (!scumm_stricmp("puzzle", gameid)) { - *engine = new AGOS::AGOSEngine_PuzzlePack(syst); - } else if (!scumm_stricmp("swampy", gameid)) { - *engine = new AGOS::AGOSEngine_PuzzlePack(syst); - } else { - error("AGOS engine created with invalid gameid"); + break; + default: + res = false; + error("AGOS engine: unknown gameType"); } - return kNoError; + return res; } - + +ADVANCED_DETECTOR_DEFINE_PLUGIN_WITH_COMPLEX_CREATION(AGOS, engineCreateAgos, detectionParams); + REGISTER_PLUGIN(AGOS, "AGOS", "AGOS (C) Adventure Soft"); namespace AGOS { diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h index 988de6729b..f600b3febf 100644 --- a/engines/agos/detection_tables.h +++ b/engines/agos/detection_tables.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/agos/detection_tables.h $ - * $Id:detection_tables.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -290,6 +290,31 @@ static const AGOSGameDescription gameDescriptions[] = { GF_OLD_BUNDLE | GF_CRUNCHED | GF_PLANAR }, + // Elvira 2 - German Amiga Floppy + { + { + "elvira2", + "Floppy", + + { + { "menus.dat", GAME_MENUFILE, "a2fdc88a77c8bdffec6b36cbeda4d955", -1}, + { "stripped.txt", GAME_STRFILE, "41c975a9c1106cb5298a0bc3df0a266e", -1}, + { "gameamiga", GAME_BASEFILE, "7af80eb9759bcafcd8df21e61c5af200", -1}, + { "icon.dat", GAME_ICONFILE, "a88b1c02e13ab04dd790ec30502c323d", -1}, + { "tbllist", GAME_TBLFILE, "177f5f2640e80ef92d1421d32de06a5e", -1}, + { "start", GAME_RESTFILE, "a9f876c6c66dfd011b971da3dc7b4ada", -1}, + { NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformAmiga, + Common::ADGF_NO_FLAGS + }, + + GType_ELVIRA2, + GID_ELVIRA2, + GF_OLD_BUNDLE | GF_CRUNCHED | GF_PLANAR + }, + // Elvira 2 - Italian Amiga Floppy { { diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp index bb28da73b5..68bb152844 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -503,8 +503,8 @@ void AGOSEngine::saveBackGround(VgaSprite *vsp) { if (_window3Flag == 1) { animTable->srcPtr = (const byte *)_window4BackScn; } else { - uint xoffs = (_videoWindows[vsp->windowNum * 4 + 0] * 2 + x) * 8; - uint yoffs = (_videoWindows[vsp->windowNum * 4 + 1] + y); + int xoffs = (_videoWindows[vsp->windowNum * 4 + 0] * 2 + x) * 8; + int yoffs = (_videoWindows[vsp->windowNum * 4 + 1] + y); animTable->srcPtr = getBackGround() + xoffs + yoffs * _screenWidth; } diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 15937db0da..20ab84d15d 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -668,7 +668,7 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { if (_windowNum == 4 || (_windowNum >= 10 && _windowNum <= 27)) { state->surf2_addr = getBackGround(); state->surf2_pitch = _screenWidth; - + state->surf_addr = _window4BackScn; state->surf_pitch = _videoWindows[18] * 16; diff --git a/engines/agos/intern.h b/engines/agos/intern.h index 44d38fbeed..a6d843d183 100644 --- a/engines/agos/intern.h +++ b/engines/agos/intern.h @@ -187,13 +187,8 @@ struct TimeEvent { }; struct GameSpecificSettings { -#ifndef PALMOS_68K const char *effects_filename; const char *speech_filename; - #else - const char effects_filename[12]; - const char speech_filename[12]; - #endif }; enum BoxFlags { diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index 4746e87a66..4ba083a653 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cine/sound.cpp $ - * $Id:sound.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cine/sound.h b/engines/cine/sound.h index 4ebda2c236..719f37f151 100644 --- a/engines/cine/sound.h +++ b/engines/cine/sound.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cine/sound.h $ - * $Id:sound.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/actor.cpp b/engines/cruise/actor.cpp index dd38e15838..c4af217117 100644 --- a/engines/cruise/actor.cpp +++ b/engines/cruise/actor.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/actor.cpp $ - * $Id:actor.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -471,8 +471,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2 (*nclick)++; ctpVar19 = ctpVar11; - if (*nclick == 2) // second point - { + if (*nclick == 2) { // second point x1 = table_ptselect[0][0]; y1 = table_ptselect[0][1]; x2 = table_ptselect[1][0]; @@ -858,26 +857,18 @@ void processAnimation(void) { currentActor->phase = ANIM_PHASE_MOVE; } - if ((currentActor->counter >= - 0) - && ((currentActor->phase == - ANIM_PHASE_STATIC_END) - || (currentActor-> - phase == - ANIM_PHASE_STATIC))) + if ((currentActor->counter >= 0) + && ((currentActor->phase == ANIM_PHASE_STATIC_END) + || (currentActor->phase == ANIM_PHASE_STATIC))) { int newA; int inc = 1; - int t_inc = - currentActor-> - startDirection - 1; + int t_inc = currentActor->startDirection - 1; if (t_inc < 0) t_inc = 3; - if (currentActor-> - nextDirection == - t_inc) + if (currentActor->nextDirection == t_inc) inc = -1; if (inc > 0) diff --git a/engines/cruise/actor.h b/engines/cruise/actor.h index 072eef9581..43b9b03e87 100644 --- a/engines/cruise/actor.h +++ b/engines/cruise/actor.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/actor.h $ - * $Id:actor.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/background.cpp b/engines/cruise/background.cpp index ebf0b78934..f23c331eb8 100644 --- a/engines/cruise/background.cpp +++ b/engines/cruise/background.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/background.cpp $ - * $Id:background.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -98,8 +98,7 @@ int loadBackground(char *name, int idx) { backgroundPtrtable[idx] = (uint8 *) mallocAndZero(320 * 200 /*64000 */ ); } -/* else - { +/* else { backgroundPtrtable[idx] = hwMemAddr[idx]; } */ } diff --git a/engines/cruise/background.h b/engines/cruise/background.h index b8b9e623c6..d506d1663e 100644 --- a/engines/cruise/background.h +++ b/engines/cruise/background.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/background.h $ - * $Id:background.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/backgroundIncrust.cpp b/engines/cruise/backgroundIncrust.cpp index edaa68b490..7e79c048b1 100644 --- a/engines/cruise/backgroundIncrust.cpp +++ b/engines/cruise/backgroundIncrust.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/backgroundIncrust.cpp $ - * $Id:backgroundIncrust.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -113,8 +113,7 @@ backgroundIncrustStruct *addBackgroundIncrust(int16 overlayIdx, newElement->ptr = NULL; strcpy(newElement->name, filesDatabase[params.fileIdx].subData.name); - if (filesDatabase[params.fileIdx].subData.resourceType == 4) // sprite - { + if (filesDatabase[params.fileIdx].subData.resourceType == 4) { // sprite int width = filesDatabase[params.fileIdx].width; int height = filesDatabase[params.fileIdx].height; @@ -125,8 +124,7 @@ backgroundIncrustStruct *addBackgroundIncrust(int16 overlayIdx, newElement->Y, newElement->X, (char *)backgroundPtr, (char *)filesDatabase[params.fileIdx].subData.ptr); // ASSERT(0); - } else // poly - { + } else { // poly /* if(param4 == 1) * { * int var_A; diff --git a/engines/cruise/backgroundIncrust.h b/engines/cruise/backgroundIncrust.h index 3f61faadae..6de30978fd 100644 --- a/engines/cruise/backgroundIncrust.h +++ b/engines/cruise/backgroundIncrust.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/backgroundIncrust.h $ - * $Id:backgroundIncrust.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/cell.cpp b/engines/cruise/cell.cpp index 8a7b524a7b..d4b5aaed66 100644 --- a/engines/cruise/cell.cpp +++ b/engines/cruise/cell.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/cell.cpp $ - * $Id:cell.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/cell.h b/engines/cruise/cell.h index ea2fb7e777..c10ab93541 100644 --- a/engines/cruise/cell.h +++ b/engines/cruise/cell.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/cell.h $ - * $Id:cell.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index b427498c6f..9693fb7d03 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/cruise.cpp $ - * $Id:cruise.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h index cf768d8d57..73de46c599 100644 --- a/engines/cruise/cruise.h +++ b/engines/cruise/cruise.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/cruise.h $ - * $Id:cruise.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index 79a699433f..b3b0077ee7 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/cruise_main.cpp $ - * $Id:cruise_main.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -627,192 +627,98 @@ int getCursorFromObject(int mouseX, int mouseY, int *outX, int *outY) { cellStruct *currentObject = cellHead.prev; while (currentObject) { - if (currentObject->overlay >= 0) { - if (overlayTable[currentObject->overlay].alreadyLoaded) { - if (currentObject->type == 4 - || currentObject->type == 1 - || currentObject->type == 9 - || currentObject->type == 3) { - strcpy(objectName, - getObjectName(currentObject->idx, - overlayTable[currentObject-> - overlay].ovlData-> - specialString2)); - - if (strlen(objectName)) { - if (currentObject->freeze == 0) { - var_2 = - currentObject->idx; - var_4 = - currentObject-> - overlay; - var_14 = - currentObject-> - followObjectIdx; - var_16 = - currentObject-> - followObjectOverlayIdx; - - getMultipleObjectParam - (currentObject-> - overlay, - currentObject->idx, - ¶ms); - - var_10 = 0; - var_E = 0; - var_C = 0; - - if ((var_4 != var_16) - && (var_2 != - var_14)) { - getMultipleObjectParam - (var_16, - var_14, - ¶ms); - - var_C = - params.X; - var_E = - params.Y; - var_10 = - params. - fileIdx; + if (currentObject->overlay >= 0 && overlayTable[currentObject->overlay].alreadyLoaded + && (currentObject->type == 4 || currentObject->type == 1 + || currentObject->type == 9 || currentObject->type == 3)) { + strcpy(objectName, + getObjectName(currentObject->idx, + overlayTable[currentObject->overlay].ovlData->specialString2)); + + if (strlen(objectName)) { + if (currentObject->freeze == 0) { + var_2 = currentObject->idx; + var_4 = currentObject->overlay; + var_14 = currentObject->followObjectIdx; + var_16 = currentObject->followObjectOverlayIdx; + + getMultipleObjectParam(currentObject->overlay, currentObject->idx, ¶ms); + + var_10 = 0; + var_E = 0; + var_C = 0; + + if ((var_4 != var_16) + && (var_2 != var_14)) { + getMultipleObjectParam + (var_16, var_14, ¶ms); + + var_C = params.X; + var_E = params.Y; + var_10 = params.fileIdx; + } + + if (params.var5 >= 0 && params.fileIdx >= 0) { + if (currentObject->type == 3) { + assert(0); + + var_2 = params.scale; + var_A = params.X + var_C; + + // TODO: this var3 is stupid, investigate... + if ((var_A <= mouseX) && (var_A + params.fileIdx >= mouseX) && (mouseY >= params.Y + var_E) && (params.Y + var_E + var2 >= mouseY)) { + *outX = var_16; + *outY = var_14; + + return (currentObject->type); } + } else if (currentObject->type == 4 || + currentObject->type == 1 || + currentObject->type == 9) { + int si; + int var_8; + int di; - if (params.var5 >= 0 - && params. - fileIdx >= 0) { - if (currentObject->type == 3) { - assert - (0); - - var_2 = - params. - scale; - var_A = - params. - X + - var_C; - - // TODO: this var3 is stupid, investigate... - if ((var_A <= mouseX) && (var_A + params.fileIdx >= mouseX) && (mouseY >= params.Y + var_E) && (params.Y + var_E + var2 >= mouseY)) { - *outX - = - var_16; - *outY - = - var_14; - - return - (currentObject-> - type); - } - } else - if - (currentObject-> - type == 4 - || - currentObject-> - type == 1 - || - currentObject-> - type == - 9) { - int si; - int var_8; - int di; - - var_A = - params. - X + - var_C; - var_6 = - params. - Y + - var_E; - - di = params.fileIdx; - - if (di - < - 0) - { - di += var_10; - } + var_A = params.X + var_C; + var_6 = params.Y + var_E; -/* if((filesDatabase[di].subData.resourceType == 8) && (filesDatabase[di].subData.ptr)) - { - assert(0); - } - else */ - { - var_4 - = - filesDatabase - [di]. - resType; + di = params.fileIdx; + if (di < 0) { + di += var_10; + } + +/* if((filesDatabase[di].subData.resourceType == 8) && (filesDatabase[di].subData.ptr)) { + assert(0); + } +*/ + { + var_4 = filesDatabase[di].resType; + + if (var_4 == 1) { + var_C = filesDatabase[di].widthInColumn / 2; + } else { + var_C = filesDatabase[di].width; + } + + var_8 = filesDatabase[di].height; + + var_2 = mouseX - var_A; + si = mouseY - var_6; + + if (var_2 > 0 && var_C > var_2 && si > 0 && var_8 >= si) { + if (filesDatabase[di].subData.ptr) { if (var_4 == 1) { - var_C - = - filesDatabase - [di]. - widthInColumn - / - 2; } else { - var_C - = - filesDatabase - [di]. - width; } - var_8 - = - filesDatabase - [di]. - height; - - var_2 - = - mouseX - - - var_A; - si = mouseY - var_6; - - if (var_2 > 0) { - if (var_C > var_2) { - if (si > 0) { - if (var_8 >= si) { - if (filesDatabase[di].subData.ptr) { - if (var_4 == 1) { - } else { - } - - printf - ("should compare to mask in getCursorFromObject...\n"); + printf("should compare to mask in getCursorFromObject...\n"); - *outX - = - var_16; - *outY - = - var_14; + *outX = var_16; + *outY = var_14; - printf - ("Selected: %s\n", - objectName); + printf("Selected: %s\n", objectName); - return - currentObject-> - type; - } - } - } - } - } + return currentObject->type; } } } @@ -878,52 +784,22 @@ void buildInventory(int X, int Y) { menuStruct *pMenu; pMenu = createMenu(X, Y, "Inventaire"); - menuTable[1] = pMenu; - if (pMenu) { - numObjectInInventory = 0; + if (pMenu && numOfLoadedOverlay > 1) { + for (int i = 1; i < numOfLoadedOverlay; i++) { + ovlDataStruct *pOvlData = overlayTable[i].ovlData; - if (numOfLoadedOverlay > 1) { - int i; + if (pOvlData && pOvlData->objDataTable && pOvlData->numObjData) { + for (int j = 0; j < pOvlData->numObjData; j++) { + if (buildInventorySub1(i, j) != 3) { + int16 returnVar; - for (i = 1; i < numOfLoadedOverlay; i++) { - ovlDataStruct *pOvlData = - overlayTable[i].ovlData; + getSingleObjectParam(i, j, 5, &returnVar); - if (pOvlData && pOvlData->objDataTable) { - int var_2; - - var_2 = 0; - - if (pOvlData->numObjData) { - int j; - - for (j = 0; - j < pOvlData->numObjData; - j++) { - if (buildInventorySub1 - (i, j) != 3) { - int16 - returnVar; - - getSingleObjectParam - (i, j, 5, - &returnVar); - - if (returnVar < - -1) { - addSelectableMenuEntry - (i, - j, - pMenu, - 1, - -1, - getObjectName - (j, pOvlData->specialString2)); - numObjectInInventory++; - } - } + if (returnVar < -1) { + addSelectableMenuEntry(i, j, pMenu, 1, -1, getObjectName(j, pOvlData->specialString2)); + numObjectInInventory++; } } } @@ -1014,12 +890,9 @@ int callInventoryObject(int param0, int param1, int x, int y) { var_34->stringNameOffset); if (var_2 == param0) { - if (param1 == - var_34->stringNameOffset) { + if (param1 == var_34->stringNameOffset) { if (pObject) { - if (pObject-> - type != - 3) { + if (pObject->type != 3) { char var_214[80]; char var_1C4[80]; char var_174[80]; @@ -1027,110 +900,52 @@ int callInventoryObject(int param0, int param1, int x, int y) { char var_D4[80]; char var_84[80]; - ovlDataStruct - *var_12; - ovlDataStruct - *var_22; + ovlDataStruct *var_12; + ovlDataStruct *var_22; int var_E = var_34->varIdx; - int cx - = - var_34-> - stringIdx; + int cx = var_34->stringIdx; int var_C = var_34->procIdx; - int di - = - var_E; + int di = var_E; if (var_E == 0) di = var_1E; - var_2 = - cx; - if (cx - == - 0) - var_2 - = - var_1E; + var_2 = cx; + if (cx == 0) + var_2 = var_1E; if (var_C == 0) - var_C - = - var_1E; - - var_12 - = - NULL; - var_22 - = - NULL; - - var_214 - [0] - = - 0; - var_1C4 - [0] - = - 0; - var_174 - [0] - = - 0; - var_124 - [0] - = - 0; - var_D4 - [0] - = - 0; - var_84 - [0] - = - 0; - - if (di - > - 0) - { - var_22 - = - overlayTable - [di]. - ovlData; + var_C = var_1E; + + var_12 = NULL; + var_22 = NULL; + + var_214[0] = 0; + var_1C4[0] = 0; + var_174[0] = 0; + var_124[0] = 0; + var_D4[0] = 0; + var_84[0] = 0; + + if (di > 0) { + var_22 = overlayTable[di].ovlData; } if (var_2 > 0) { - var_12 - = - overlayTable - [var_2]. - ovlData; + var_12 = overlayTable[var_2].ovlData; } if (var_12) { if (var_34->stringNameOffset) { - var_30 - = - var_34-> - field_1A; + var_30 = var_34->field_1A; if (var_28) { if (var_12->specialString2) { if (var_30 == -1 || var_30 == returnVar) { char *ptrName = getObjectName(var_34->stringNameOffset, var_12->specialString2); - menuTable - [0] - = - createMenu - (x, - y, - ptrName); - var_28 - = - 0; + menuTable[0] = createMenu(x, y, ptrName); + var_28 = 0; } } } @@ -1138,8 +953,7 @@ int callInventoryObject(int param0, int param1, int x, int y) { } if (var_22) { - if (true /*var_34->varNameOffset>=0 */ ) // FIXME: This check is always true since varNameOffset is unsigned - { + if (true /*var_34->varNameOffset>=0 */ ) { // FIXME: This check is always true since varNameOffset is unsigned if (var_22->specialString1) { char *ptr = getObjectName(var_34->varNameOffset, var_22->specialString1); @@ -1289,8 +1103,7 @@ int processInput(void) { ASSERT(0); } - if (var38 == 0) // are we in inventory mode ? - { + if (var38 == 0) { // are we in inventory mode ? if (menuTable[0] == 0) { int X; int Y; diff --git a/engines/cruise/cruise_main.h b/engines/cruise/cruise_main.h index 324d99f024..c42650a007 100644 --- a/engines/cruise/cruise_main.h +++ b/engines/cruise/cruise_main.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/cruise_main.h $ - * $Id:cruise_main.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/ctp.cpp b/engines/cruise/ctp.cpp index 07df6029b2..5af2cda46c 100644 --- a/engines/cruise/ctp.cpp +++ b/engines/cruise/ctp.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/ctp.cpp $ - * $Id:ctp.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -66,16 +66,14 @@ void loadCtpSub2(short int coordCount, short int *ptr) { short int *cur_ctp_routeCoords = (short int *)ctp_routeCoords; // coordinates table int8 *cur_ctp_routes = (int8 *) ctp_routes; - for (i = 0; i < coordCount; i++) // for i < ctp_routeCoordCount - { + for (i = 0; i < coordCount; i++) { // for i < ctp_routeCoordCount int varX = cur_ctp_routeCoords[0]; // x int varY = cur_ctp_routeCoords[1]; // y int di = 0; int var4Offset = 2; - while (*(int16 *) cur_ctp_routes > di) // while (coordCount > counter++) - { + while (*(int16 *) cur_ctp_routes > di) { // while (coordCount > counter++) int idx = *(int16 *) (cur_ctp_routes + var4Offset); ptr[offset + idx] = ctpProc2(varX, varY, ctp_routeCoords[idx][0], @@ -189,8 +187,7 @@ void loadCtpSub1(int boxIdx, int scale, uint16 *_walkboxTable, ASSERT(boxIdx <= 15); - if (_walkboxTable[boxIdx * 40] > 0) // is walkbox used ? - { + if (_walkboxTable[boxIdx * 40] > 0) { // is walkbox used ? getWalkBoxCenter(boxIdx, _walkboxTable); currentWalkBoxCenterYBis = currentWalkBoxCenterY; diff --git a/engines/cruise/ctp.h b/engines/cruise/ctp.h index b35523a3a7..2ea47ce62e 100644 --- a/engines/cruise/ctp.h +++ b/engines/cruise/ctp.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/ctp.h $ - * $Id:ctp.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp index 2212a3bde2..54a0e97732 100644 --- a/engines/cruise/dataLoader.cpp +++ b/engines/cruise/dataLoader.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/dataLoader.cpp $ - * $Id:dataLoader.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/dataLoader.h b/engines/cruise/dataLoader.h index 6b6bf52cf6..46e4ef447f 100644 --- a/engines/cruise/dataLoader.h +++ b/engines/cruise/dataLoader.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/dataLoader.h $ - * $Id:dataLoader.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/decompiler.cpp b/engines/cruise/decompiler.cpp index 68beab0846..b027f948aa 100644 --- a/engines/cruise/decompiler.cpp +++ b/engines/cruise/decompiler.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/decompiler.cpp $ - * $Id:decompiler.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -136,52 +136,47 @@ void pushDecomp(char *string, ...) { void resolveDecompShort(char *buffer) { ovlData3Struct *data3Ptr = currentScript; + int i; - { - int i; + importScriptStruct *importEntry = + (importScriptStruct *) (data3Ptr->dataPtr + + data3Ptr->offsetToImportData); - importScriptStruct *importEntry = - (importScriptStruct *) (data3Ptr->dataPtr + - data3Ptr->offsetToImportData); - - for (i = 0; i < data3Ptr->numImport; i++) { - switch (importEntry->type) { - case 20: // script - case 30: - case 40: - case 50: - { - if (importEntry->offset == currentDecompScriptPtr->var4 - 3) // param1 - { - sprintf(buffer, - data3Ptr->dataPtr + - data3Ptr-> - offsetToImportName + - importEntry->offsetToName); - return; - } - if (importEntry->offset == currentDecompScriptPtr->var4 - 6) // param2 - { - sprintf(buffer, "linkedIdx"); - return; - } - break; + for (i = 0; i < data3Ptr->numImport; i++) { + switch (importEntry->type) { + case 20: // script + case 30: + case 40: + case 50: + { + if (importEntry->offset == currentDecompScriptPtr->var4 - 3) { // param1 + sprintf(buffer, + data3Ptr->dataPtr + + data3Ptr-> + offsetToImportName + + importEntry->offsetToName); + return; } - default: - { - if (importEntry->offset == - currentDecompScriptPtr->var4 - 4) { - sprintf(buffer, - data3Ptr->dataPtr + - data3Ptr-> - offsetToImportName + - importEntry->offsetToName); - return; - } + if (importEntry->offset == currentDecompScriptPtr->var4 - 6) { // param2 + sprintf(buffer, "linkedIdx"); + return; + } + break; + } + default: + { + if (importEntry->offset == + currentDecompScriptPtr->var4 - 4) { + sprintf(buffer, + data3Ptr->dataPtr + + data3Ptr-> + offsetToImportName + + importEntry->offsetToName); + return; } } - importEntry++; } + importEntry++; } buffer[0] = 0; @@ -190,31 +185,28 @@ void resolveDecompShort(char *buffer) { void resolveDecompChar(char *buffer) { ovlData3Struct *data3Ptr = currentScript; + int i; - { - int i; + importScriptStruct *importEntry = + (importScriptStruct *) (data3Ptr->dataPtr + + data3Ptr->offsetToImportData); - importScriptStruct *importEntry = - (importScriptStruct *) (data3Ptr->dataPtr + - data3Ptr->offsetToImportData); - - for (i = 0; i < data3Ptr->numImport; i++) { - switch (importEntry->type) { - default: - { - if (importEntry->offset == - currentDecompScriptPtr->var4 - 2) { - sprintf(buffer, - data3Ptr->dataPtr + - data3Ptr-> - offsetToImportName + - importEntry->offsetToName); - return; - } + for (i = 0; i < data3Ptr->numImport; i++) { + switch (importEntry->type) { + default: + { + if (importEntry->offset == + currentDecompScriptPtr->var4 - 2) { + sprintf(buffer, + data3Ptr->dataPtr + + data3Ptr-> + offsetToImportName + + importEntry->offsetToName); + return; } } - importEntry++; } + importEntry++; } buffer[0] = 0; @@ -342,16 +334,14 @@ void resolveVarName(char *ovlIdxString, int varType, char *varIdxString, for (i = 0; i < currentDecompOvl->numExport; i++) { if (varIdx == currentDecompOvl->exportDataPtr[i].idx) { - if (((currentDecompOvl->exportDataPtr[i].var4 & 0xF0) == 0) && varType != 0x20) // var - { + if (((currentDecompOvl->exportDataPtr[i].var4 & 0xF0) == 0) && varType != 0x20) { // var strcpy(outputName, currentDecompOvl->exportNamesPtr + currentDecompOvl->exportDataPtr[i]. offsetToName); return; } - if ((currentDecompOvl->exportDataPtr[i].var4) == 20 && varType == 0x20) // script - { + if ((currentDecompOvl->exportDataPtr[i].var4) == 20 && varType == 0x20) { // script strcpy(outputName, currentDecompOvl->exportNamesPtr + currentDecompOvl->exportDataPtr[i]. @@ -722,13 +712,11 @@ int decompCompare(void) { if(!pop) si = 1; - if(pop<0) - { + if(pop<0) { si |= 4; } - if(pop>0) - { + if(pop>0) { si |= 2; } @@ -1435,7 +1423,7 @@ int decompBreak(void) { } void generateIndentation(void) { - int i; + int i, j; for (i = 0; i < positionInDecompileLineTable; i++) { if (decompileLineTable[i].type != 0) { @@ -1449,37 +1437,25 @@ void generateIndentation(void) { gotoStatement = strchr(gotoStatement, ' ') + 1; destLine = atoi(gotoStatement); + destLineIdx = -1; - { - int j; - - destLineIdx = -1; - - for (j = 0; j < positionInDecompileLineTable; - j++) { - if (decompileLineTable[j].lineOffset == - destLine) { - destLineIdx = j; - break; - } + for (j = 0; j < positionInDecompileLineTable; j++) { + if (decompileLineTable[j].lineOffset == destLine) { + destLineIdx = j; + break; } + } - assert(destLineIdx != -1); - - if (destLineIdx > i) { - int j; + assert(destLineIdx != -1); - for (j = i + 1; j < destLineIdx; j++) { - decompileLineTable[j].indent++; - } + if (destLineIdx > i) { + for (j = i + 1; j < destLineIdx; j++) { + decompileLineTable[j].indent++; + } - if (strstr(decompileLineTable - [destLineIdx - 1].line, - "goto") == - decompileLineTable[destLineIdx - - 1].line) { - //decompileLineTable[destLineIdx-1].pendingElse = 1; - } + if (strstr(decompileLineTable[destLineIdx - 1].line, "goto") == + decompileLineTable[destLineIdx - 1].line) { + //decompileLineTable[destLineIdx-1].pendingElse = 1; } } } diff --git a/engines/cruise/delphine-unpack.cpp b/engines/cruise/delphine-unpack.cpp index db4188fbfe..b1cdc13148 100644 --- a/engines/cruise/delphine-unpack.cpp +++ b/engines/cruise/delphine-unpack.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/delphine-unpack.cpp $ - * $Id:delphine-unpack.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index fc1d864a56..2ca83f4046 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/font.cpp b/engines/cruise/font.cpp index 92064acc53..ee99567525 100644 --- a/engines/cruise/font.cpp +++ b/engines/cruise/font.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/font.cpp $ - * $Id:font.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -253,8 +253,7 @@ void renderWord(uint8 * fontPtr_Data, uint8 * outBufferPtr, outBufferPtr += heightOff * width * 2; // param2 = height , param6 = width outBufferPtr += drawPosPixel_X; // param1 = drawPosPixel_X - for (i = 0; i < height; i++) // y++ - { + for (i = 0; i < height; i++) { // y++ uint16 currentColor1 = (*(fontPtr_Data) << 8) | *(fontPtr_Data + 1); uint16 currentColor2 = diff --git a/engines/cruise/font.h b/engines/cruise/font.h index 2a75cf28dd..b74482962d 100644 --- a/engines/cruise/font.h +++ b/engines/cruise/font.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/font.h $ - * $Id:font.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/fontCharacterTable.cpp b/engines/cruise/fontCharacterTable.cpp index ce0bec0f0f..2c2dddc479 100644 --- a/engines/cruise/fontCharacterTable.cpp +++ b/engines/cruise/fontCharacterTable.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/fontCharacterTable.cpp $ - * $Id:fontCharacterTable.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/fontCharacterTable.h b/engines/cruise/fontCharacterTable.h index f7956968ec..0bfe78641a 100644 --- a/engines/cruise/fontCharacterTable.h +++ b/engines/cruise/fontCharacterTable.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/fontCharacterTable.h $ - * $Id:fontCharacterTable.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp index 092425bfc7..cfb579e331 100644 --- a/engines/cruise/function.cpp +++ b/engines/cruise/function.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/function.cpp $ - * $Id:function.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -1006,8 +1006,7 @@ actorStruct *addAnimation(actorStruct * pHead, int overlay, int objIdx, int para return pNewElement; } -int removeAnimation(actorStruct * pHead, int overlay, int objIdx, int objType) -{ +int removeAnimation(actorStruct * pHead, int overlay, int objIdx, int objType) { actorStruct* pl; actorStruct* pl2; actorStruct* pl3; @@ -1019,14 +1018,12 @@ int removeAnimation(actorStruct * pHead, int overlay, int objIdx, int objType) pl2 = pl; pl = pl2->next; - while(pl) - { + while (pl) { pl2 = pl; - if(((pl->overlayNumber == overlay) || (overlay == -1)) && + if (((pl->overlayNumber == overlay) || (overlay == -1)) && ((pl->idx == objIdx) || (objIdx == -1)) && - ((pl->type == objType) || (objType == -1))) - { + ((pl->type == objType) || (objType == -1))) { pl->type = -1; } @@ -1037,29 +1034,25 @@ int removeAnimation(actorStruct * pHead, int overlay, int objIdx, int objType) pl2 = pl; pl = pl2->next; - while(pl) - { - if(pl->type == -1) - { + while (pl) { + if (pl->type == -1) { pl4 = pl->next; pl2->next = pl4; pl3 = pl4; - if(pl3 == NULL) + if (pl3 == NULL) pl3 = pHead; pl3->prev = pl->prev; dir = pl->startDirection; - if(pl->idx >= 0) + if (pl->idx >= 0) freePerso(pl->idx); free(pl); pl = pl4; - } - else - { + } else { pl2 = pl; pl = pl2->next; } diff --git a/engines/cruise/function.h b/engines/cruise/function.h index 76100e41ba..13eb21ea1f 100644 --- a/engines/cruise/function.h +++ b/engines/cruise/function.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/function.h $ - * $Id:function.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/gfxModule.cpp b/engines/cruise/gfxModule.cpp index 119f99739e..9228193560 100644 --- a/engines/cruise/gfxModule.cpp +++ b/engines/cruise/gfxModule.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/gfxModule.cpp $ - * $Id:gfxModule.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -526,10 +526,8 @@ void gfxModuleData_field_60(char *sourcePtr, int width, int height, int i; int j; - for(i=x;i<height+x;i++) - { - for(j=y;j<width*16+y;j++) - { + for(i=x;i<height+x;i++) { + for(j=y;j<width*16+y;j++) { if(i>=0&&i<200&&j>=0&&j<320) destPtr[i*320+j] = *(sourcePtr++); } diff --git a/engines/cruise/gfxModule.h b/engines/cruise/gfxModule.h index 7339113f4c..e63b26e29f 100644 --- a/engines/cruise/gfxModule.h +++ b/engines/cruise/gfxModule.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/gfxModule.h $ - * $Id:gfxModule.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/linker.cpp b/engines/cruise/linker.cpp index 0057625e81..e72218037b 100644 --- a/engines/cruise/linker.cpp +++ b/engines/cruise/linker.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/linker.cpp $ - * $Id:linker.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -186,70 +186,36 @@ int updateScriptImport(int ovlIdx) { int temp = ptrImportData-> offset; - if (out1) //is sub function... (ie 'invent.livre:s') - { + if (out1) { //is sub function... (ie 'invent.livre:s') uint8 *ptr = ptrData + temp; - *(ptr + - 1) - = - out2; - *(int16 - *) - (ptr - + - 2) - = - ptrDest2-> - idx; - - flipShort - ( - (int16 - *) - (ptr + 2)); + *(ptr + 1) = out2; + *(int16 *)(ptr + 2) = ptrDest2->idx; + + flipShort((int16 *)(ptr + 2)); } else { - if (param2 == 20 || param2 == 30 || param2 == 40 || param2 == 50) // this patch a double push - { - uint8 - * - ptr - = - ptrData - + - temp; + if (param2 == 20 || param2 == 30 || param2 == 40 || param2 == 50) { // this patch a double push + uint8 *ptr = ptrData + temp; *(ptr + 1) = 0; *(ptr + 2) = out2; // update the overlay number - *(int16 *) (ptr + 4) = ptrDest2->idx; + *(int16 *)(ptr + 4) = ptrDest2->idx; - flipShort - ( - (int16 - *) - (ptr + 4)); + flipShort((int16 *)(ptr + 4)); } else { int var_4 = ptrDest2->var4; if (var_4 & 1) { - param2 - = - 8; + param2 = 8; } else { - param2 - = - 16; + param2 = 16; } if (var_4 >= 0 && var_4 <= 3) { - param2 - |= - 5; + param2 |= 5; } else { - param2 - |= - 6; + param2 |= 6; } *(ptrData + temp) = param2; diff --git a/engines/cruise/linker.h b/engines/cruise/linker.h index 975ed0f322..808ace75e0 100644 --- a/engines/cruise/linker.h +++ b/engines/cruise/linker.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/linker.h $ - * $Id:linker.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp index 3d409d0ba5..b30dc29380 100644 --- a/engines/cruise/mainDraw.cpp +++ b/engines/cruise/mainDraw.cpp @@ -18,13 +18,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/mainDraw.cpp $ - * $Id:mainDraw.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ #include "cruise/cruise_main.h" -#include "polys.h" +#include "cruise/polys.h" +#include "common/util.h" namespace Cruise { @@ -131,8 +132,7 @@ void getPolyData(int fileIndex, int X, int Y, int *outScale, int *outY, newFileIndex += fileIndex; - if (true /*newFileIndex >= 0 */ ) // FIXME: comparison is always true due to limited range of data type - { + if (true /*newFileIndex >= 0 */ ) { // FIXME: comparison is always true due to limited range of data type if (filesDatabase[newFileIndex].resType == 0 && filesDatabase[newFileIndex].subData.ptr) { dataPtr = @@ -180,8 +180,7 @@ void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], int lowerBorder; m_flipLeftRight = 0; - if (scale < 0) // flip left right - { + if (scale < 0) { // flip left right m_flipLeftRight = 1; scale = -scale; } @@ -208,11 +207,8 @@ void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16; - if (upperBorder < lowerBorder) // exchange borders if lower > upper - { - int temp = upperBorder; - upperBorder = lowerBorder; - lowerBorder = temp; + if (upperBorder < lowerBorder) { // exchange borders if lower > upper + SWAP(upperBorder, lowerBorder); } sizeTable[0] = lowerBorder; // left @@ -231,11 +227,8 @@ void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], upperBorder -= *(dataPtr + 4); upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16; - if (upperBorder < lowerBorder) // exchange borders if lower > upper - { - int temp = upperBorder; - upperBorder = lowerBorder; - lowerBorder = temp; + if (upperBorder < lowerBorder) { // exchange borders if lower > upper + SWAP(upperBorder, lowerBorder); } sizeTable[2] = lowerBorder; // bottom @@ -397,8 +390,7 @@ void buildPolyModel(int positionX, int positionY, int scale, char *ptr2, m_flipLeftRight = 1; } - if (scale < 0x180) // If scale is smaller than 384 - { + if (scale < 0x180) { // If scale is smaller than 384 m_useSmallScale = 1; m_scaleValue = scale << 1; // double scale } else { @@ -448,8 +440,7 @@ void buildPolyModel(int positionX, int positionY, int scale, char *ptr2, x = *(dataPointer++) - m_first_X; y = *(dataPointer++) - m_first_Y; - if (m_useSmallScale) // shrink all coordinates by factor 2 if a scale smaller than 384 is used - { + if (m_useSmallScale) { // shrink all coordinates by factor 2 if a scale smaller than 384 is used x >>= 1; y >>= 1; } @@ -502,8 +493,7 @@ void buildPolyModel(int positionX, int positionY, int scale, char *ptr2, do { int linesToDraw = *dataPointer++; - if (linesToDraw > 1) // if value not zero - { + if (linesToDraw > 1) { // if value not zero uint16 minimumScale; m_color = *dataPointer; // color @@ -514,8 +504,7 @@ void buildPolyModel(int positionX, int positionY, int scale, char *ptr2, flipShort(&minimumScale); - if (minimumScale > scale) // if the scale is too small, for the model to be drawn ... - { + if (minimumScale > scale) { // if the scale is too small, for the model to be drawn ... dataPointer += linesToDraw; // ... skip ahead } else { if (m_flipLeftRight) { @@ -913,13 +902,10 @@ void mainDraw(int16 param) { } if ((params.var5 >= 0) && (objZ2 >= 0) && filesDatabase[objZ2].subData.ptr) { - if (filesDatabase[objZ2].subData.resourceType == 8) // Poly - { + if (filesDatabase[objZ2].subData.resourceType == 8) { // Poly mainDrawPolygons(objZ2, currentObjPtr, objX2, params.scale, objY2, (char *)gfxModuleData.pPage10, (char *)filesDatabase[objZ2].subData.ptr); // poly - } else if (filesDatabase[objZ2].subData.resourceType == 6) // sound - { - } else if (filesDatabase[objZ2].resType == 1) //(num plan == 1) - { + } else if (filesDatabase[objZ2].subData.resourceType == 6) { // sound + } else if (filesDatabase[objZ2].resType == 1) { //(num plan == 1) } else if (filesDatabase[objZ2].subData.resourceType == 4) { objX1 = filesDatabase[objZ2].width; // width spriteHeight = filesDatabase[objZ2].height; // height @@ -953,12 +939,10 @@ void mainDraw(int16 param) { change = false; currentObjPtr->animStep = 0; - if (currentObjPtr->animType) // should we resume the script ? - { + if (currentObjPtr->animType) { // should we resume the script ? if (currentObjPtr->parentType == 20) { changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, 0, -1); - } - else if(currentObjPtr->parentType == 30) { + } else if (currentObjPtr->parentType == 30) { changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, 0, -1); } } diff --git a/engines/cruise/mainDraw.h b/engines/cruise/mainDraw.h index 7ff6ffdc8f..ad10bcddc6 100644 --- a/engines/cruise/mainDraw.h +++ b/engines/cruise/mainDraw.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/mainDraw.h $ - * $Id:mainDraw.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp index e30542cc1b..4f828d1fd3 100644 --- a/engines/cruise/menu.cpp +++ b/engines/cruise/menu.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/menu.cpp $ - * $Id:menu.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -221,8 +221,7 @@ int playerMenu(int menuX, int menuY) { freeStuff2(); } /* - if(currentMenu) - { + if(currentMenu) { freeMenu(currentMenu); currentMenu = 0; var37 = 0; @@ -230,8 +229,7 @@ int playerMenu(int menuX, int menuY) { main9 = -1; } - if(inventoryMenu) - { + if(inventoryMenu) { freeMenu(inventoryMenu); inventoryMenu = 0; var37 = 0; @@ -239,8 +237,7 @@ int playerMenu(int menuX, int menuY) { main9 = -1; }*/ -/* if(mouseVar2) - { +/* if(mouseVar2) { free3(mouseVar2); } */ diff --git a/engines/cruise/menu.h b/engines/cruise/menu.h index 9a33545224..4e15d15cf1 100644 --- a/engines/cruise/menu.h +++ b/engines/cruise/menu.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/menu.h $ - * $Id:menu.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/mouse.cpp b/engines/cruise/mouse.cpp index c9cec8f72a..a918e0536f 100644 --- a/engines/cruise/mouse.cpp +++ b/engines/cruise/mouse.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/mouse.cpp $ - * $Id:mouse.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/mouse.h b/engines/cruise/mouse.h index c7ef2a69c5..a6911ce27e 100644 --- a/engines/cruise/mouse.h +++ b/engines/cruise/mouse.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/mouse.h $ - * $Id:mouse.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/object.cpp b/engines/cruise/object.cpp index ce4de2a12b..22e81dea90 100644 --- a/engines/cruise/object.cpp +++ b/engines/cruise/object.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/object.cpp $ - * $Id:object.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/object.h b/engines/cruise/object.h index feec666687..546d2bc440 100644 --- a/engines/cruise/object.h +++ b/engines/cruise/object.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/object.h $ - * $Id:object.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/overlay.cpp b/engines/cruise/overlay.cpp index c1b35f61f6..179c53357d 100644 --- a/engines/cruise/overlay.cpp +++ b/engines/cruise/overlay.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/overlay.cpp $ - * $Id:overlay.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -375,8 +375,7 @@ int loadOverlay(const uint8 *scriptName) { if (!ovlData->ptr8) { /* releaseScript(scriptIdx,scriptName); - if(freeIsNeeded) - { + if(freeIsNeeded) { freePtr(unpackedBuffer); } */ @@ -396,8 +395,7 @@ int loadOverlay(const uint8 *scriptName) { if (!ovlData->objDataTable) { /* releaseScript(scriptIdx,scriptName); - if(freeIsNeeded) - { + if(freeIsNeeded) { freePtr(unpackedBuffer); } */ @@ -457,8 +455,7 @@ int loadOverlay(const uint8 *scriptName) { if (!ovlData->objData2WorkTable) { /* releaseScript(scriptIdx,scriptName); - if(freeIsNeeded) - { + if(freeIsNeeded) { freePtr(unpackedBuffer); } */ @@ -474,8 +471,7 @@ int loadOverlay(const uint8 *scriptName) { if (!ovlData->objData2SourceTable) { /* releaseScript(scriptIdx,scriptName); - if(freeIsNeeded) - { + if(freeIsNeeded) { freePtr(unpackedBuffer); } */ @@ -501,8 +497,7 @@ int loadOverlay(const uint8 *scriptName) { } } -/* if(freeIsNeeded) - { +/* if(freeIsNeeded) { freePtr(unpackedBuffer); } */ @@ -701,14 +696,12 @@ int releaseOverlay(const char *name) { if (!ovlDataPtr) return -4; /* - if(overlayTable[overlayIdx].var1E) - { + if(overlayTable[overlayIdx].var1E) { free(overlayTable[overlayIdx].var1E); overlayTable[overlayIdx].var1E = NULL; } - if(overlayTable[overlayIdx].var16) - { + if(overlayTable[overlayIdx].var16) { free(overlayTable[overlayIdx].var16); overlayTable[overlayIdx].var16 = NULL; } */ diff --git a/engines/cruise/overlay.h b/engines/cruise/overlay.h index 03db06fada..5d2e4e890e 100644 --- a/engines/cruise/overlay.h +++ b/engines/cruise/overlay.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/overlay.h $ - * $Id:overlay.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/perso.cpp b/engines/cruise/perso.cpp index a95607a2f1..e0cd85f2fe 100644 --- a/engines/cruise/perso.cpp +++ b/engines/cruise/perso.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/perso.cpp $ - * $Id:perso.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/perso.h b/engines/cruise/perso.h index 0d5676a4c8..aa9f59a1a3 100644 --- a/engines/cruise/perso.h +++ b/engines/cruise/perso.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/perso.h $ - * $Id:perso.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/polys.cpp b/engines/cruise/polys.cpp index 83192b0dda..a2eea8a9a7 100644 --- a/engines/cruise/polys.cpp +++ b/engines/cruise/polys.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/polys.cpp $ - * $Id:polys.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/polys.h b/engines/cruise/polys.h index b5da8dd241..53ce4672cd 100644 --- a/engines/cruise/polys.h +++ b/engines/cruise/polys.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/polys.h $ - * $Id:polys.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index ffda142e66..189bde1ea1 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/saveload.cpp $ - * $Id:saveload.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/saveload.h b/engines/cruise/saveload.h index de97f24b64..5a719066c5 100644 --- a/engines/cruise/saveload.h +++ b/engines/cruise/saveload.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/saveload.h $ - * $Id:saveload.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp index dc1b12f736..c9ba819d75 100644 --- a/engines/cruise/script.cpp +++ b/engines/cruise/script.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/script.cpp $ - * $Id:script.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -73,8 +73,7 @@ int32 opcodeType0(void) { if (!byte2) { ptr = scriptDataPtrTable[var_E] + short1; - } else // TODO: - { + } else { // TODO: if (!overlayTable[byte2].alreadyLoaded) { return (-7); } @@ -145,8 +144,7 @@ int32 opcodeType0(void) { if (!byte2) { ptr = scriptDataPtrTable[var_E] + var_12; - } else // TODO: - { + } else { // TODO: if (!overlayTable[byte2].alreadyLoaded) { return (-7); } @@ -635,8 +633,7 @@ uint8 *attacheNewScriptToTail(int16 overlayNumber, oldTail = scriptHandlePtr; - while (oldTail->nextScriptPtr) // go to the end of the list - { + while (oldTail->nextScriptPtr) { // go to the end of the list oldTail = oldTail->nextScriptPtr; } @@ -660,8 +657,7 @@ uint8 *attacheNewScriptToTail(int16 overlayNumber, tempPtr->scriptNumber = param; tempPtr->overlayNumber = overlayNumber; - if (scriptType == 20) // Obj or not ? - { + if (scriptType == 20) { // Obj or not ? tempPtr->sysKey = useArg3Neg; } else { tempPtr->sysKey = 1; diff --git a/engines/cruise/script.h b/engines/cruise/script.h index ca7d812836..e5d21b1ba0 100644 --- a/engines/cruise/script.h +++ b/engines/cruise/script.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/script.h $ - * $Id:script.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/stack.cpp b/engines/cruise/stack.cpp index 7622564503..1639ba3942 100644 --- a/engines/cruise/stack.cpp +++ b/engines/cruise/stack.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/stack.cpp $ - * $Id:stack.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/stack.h b/engines/cruise/stack.h index 1adb3540cb..831c07e217 100644 --- a/engines/cruise/stack.h +++ b/engines/cruise/stack.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/stack.h $ - * $Id:stack.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/stringSupport.cpp b/engines/cruise/stringSupport.cpp index 54747104ff..791f203d9b 100644 --- a/engines/cruise/stringSupport.cpp +++ b/engines/cruise/stringSupport.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/stringSupport.cpp $ - * $Id:stringSupport.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/stringSupport.h b/engines/cruise/stringSupport.h index 531fe56aca..841e2dd496 100644 --- a/engines/cruise/stringSupport.h +++ b/engines/cruise/stringSupport.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/stringSupport.h $ - * $Id:stringSupport.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/various.cpp b/engines/cruise/various.cpp index e4c908af5f..5c6134c374 100644 --- a/engines/cruise/various.cpp +++ b/engines/cruise/various.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/various.cpp $ - * $Id:various.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/various.h b/engines/cruise/various.h index f6e07e00e7..fe18e5abd6 100644 --- a/engines/cruise/various.h +++ b/engines/cruise/various.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/various.h $ - * $Id:various.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/vars.cpp b/engines/cruise/vars.cpp index 1a3d5f0a27..094680f0bb 100644 --- a/engines/cruise/vars.cpp +++ b/engines/cruise/vars.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/vars.cpp $ - * $Id:vars.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h index 63a15f24e4..dbace8bdf3 100644 --- a/engines/cruise/vars.h +++ b/engines/cruise/vars.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/vars.h $ - * $Id:vars.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/volume.cpp b/engines/cruise/volume.cpp index 901ac4a7a5..b32ffb0ccd 100644 --- a/engines/cruise/volume.cpp +++ b/engines/cruise/volume.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/volume.cpp $ - * $Id:volume.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/cruise/volume.h b/engines/cruise/volume.h index 7881f6c872..0f9e489236 100644 --- a/engines/cruise/volume.h +++ b/engines/cruise/volume.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/cruise/volume.h $ - * $Id:volume.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index df433e12f0..eb676a7be4 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -118,7 +118,7 @@ static char mirar_t[3][88] = {TEXT100, TEXT101, TEXT54}; static char mirar_v[3][14] = {"100.als", "101.als", "54.als"}; static char poder_t[6][88] = {TEXT11, TEXT109, TEXT111, TEXT110, TEXT115, TEXT116}; static char poder_v[6][14] = {"11.als", "109.als", "111.als", "110.als", "115.als", "116.als"}; - + int DrasculaEngine::init() { // Detect game if (!initGame()) { @@ -128,14 +128,13 @@ int DrasculaEngine::init() { // Initialize backend _system->beginGFXTransaction(); - initCommonGFX(false); + initCommonGFX(false); _system->initSize(320, 200); _system->endGFXTransaction(); return 0; } - int DrasculaEngine::go() { num_ejec = 1; @@ -163,7 +162,8 @@ int DrasculaEngine::go() { frame_velas = 0; cont_sv = 0; term_int = 0; - cual_ejec = 0; hay_que_load = 0; + con_voces = 1; + hay_que_load = 0; corta_musica = 0; hay_seleccion = 0; Leng = 0; @@ -178,20 +178,73 @@ int DrasculaEngine::go() { asigna_memoria(); carga_info(); - lee_dibujos("95.alg"); - descomprime_dibujo(dir_mesa, 1); + if (num_ejec != 6) { + lee_dibujos("95.alg"); + descomprime_dibujo(dir_mesa, 1); + } + + if (num_ejec == 6) + dir_pendulo = dir_dibujo3; - lee_dibujos("96.alg"); - descomprime_dibujo(dir_hare_frente, COMPLETA); if (num_ejec == 1) { + con_voces = 0; + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); lee_dibujos("99.alg"); descomprime_dibujo(dir_hare_fondo, 1); lee_dibujos("97.alg"); descomprime_dibujo(dir_hare_dch, 1); } else if (num_ejec == 2) { + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); lee_dibujos("pts.alg"); descomprime_dibujo(dir_dibujo2, 1); - } + } else if (num_ejec == 3) { + lee_dibujos("aux13.alg"); + descomprime_dibujo(dir_dibujo1, COMPLETA); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + } else if (num_ejec == 4) { + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); + if (hay_que_load == 0) + animacion_rayo(); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + borra_pantalla(); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + } else if (num_ejec == 5) { + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + } else if (num_ejec == 6) { + x_igor = 105, y_igor = 85, sentido_igor = 1; + x_dr = 62, y_dr = 99, sentido_dr = 1; + frame_pen = 0; + flag_tv = 0; + + dir_pendulo = dir_dibujo3; + + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + + lee_dibujos("95.alg"); + descomprime_dibujo(dir_mesa, 1); + } strcpy(nombre_icono[1], "look"); strcpy(nombre_icono[2], "take"); strcpy(nombre_icono[3], "open"); @@ -206,6 +259,7 @@ int DrasculaEngine::go() { } salir_al_dos(0); } + return 0; } @@ -363,7 +417,7 @@ void DrasculaEngine::setvgapalette256(byte *PalBuf) { } void DrasculaEngine::DIBUJA_FONDO(int xorg, int yorg, int xdes, int ydes, int Ancho, - int Alto, byte *Origen, byte *Destino) { + int Alto, byte *Origen, byte *Destino) { int x; Destino += xdes + ydes * 320; Origen += xorg + yorg * 320; @@ -375,7 +429,7 @@ void DrasculaEngine::DIBUJA_FONDO(int xorg, int yorg, int xdes, int ydes, int An } void DrasculaEngine::DIBUJA_BLOQUE(int xorg, int yorg, int xdes, int ydes, int Ancho, - int Alto, byte *Origen, byte *Destino) { + int Alto, byte *Origen, byte *Destino) { int y, x; Destino += xdes + ydes * 320; @@ -437,19 +491,21 @@ void DrasculaEngine::VUELCA_PANTALLA(int xorg, int yorg, int xdes, int ydes, int } bool DrasculaEngine::escoba() { - int soc, l, n; + int n; dir_texto = dir_mesa; musica_antes = -1; - soc = 0; - for (l = 0; l < 6; l++) { - soc = soc + ANCHO_PERSONAJE; - frame_x[l] = soc; + if (num_ejec != 2) { + int soc = 0; + for (n = 0; n < 6; n++) { + soc = soc + ANCHO_PERSONAJE; + frame_x[n] = soc; + } } - for (n = 1; n < 43; n++) + for (n = 1; n < 50; n++) objetos_que_tengo[n] = 0; for (n = 0; n < NUM_BANDERAS; n++) @@ -479,7 +535,7 @@ bool DrasculaEngine::escoba() { if (hay_que_load != 0) para_cargar(nom_partida); else { - carga_escoba_1("62.ald"); + carga_escoba("62.ald"); hare_x = -20; hare_y = 56; lleva_al_hare(65, 145); @@ -490,9 +546,73 @@ bool DrasculaEngine::escoba() { sentido_hare = 3; obj_saliendo = 162; if (hay_que_load == 0) - carga_escoba_2("14.ald"); + carga_escoba("14.ald"); + else + para_cargar(nom_partida); + } else if (num_ejec == 3) { + suma_objeto(28); + suma_objeto(11); + suma_objeto(14); + suma_objeto(22); + suma_objeto(9); + suma_objeto(20); + suma_objeto(19); + flags[1] = 1; + buffer_teclado(); + sentido_hare = 1; + obj_saliendo = 99; + if (hay_que_load == 0) + carga_escoba("20.ald"); else para_cargar(nom_partida); + } else if (num_ejec == 3) { + suma_objeto(28); + suma_objeto(9); + suma_objeto(20); + suma_objeto(22); + buffer_teclado(); + obj_saliendo = 100; + if (hay_que_load == 0) { + carga_escoba("21.ald"); + sentido_hare = 0; + hare_x = 235; + hare_y = 164; + } else + para_cargar(nom_partida); + } else if (num_ejec == 5) { + suma_objeto(28); + suma_objeto(7); + suma_objeto(9); + suma_objeto(11); + suma_objeto(13); + suma_objeto(14); + suma_objeto(15); + suma_objeto(17); + suma_objeto(20); + buffer_teclado(); + sentido_hare = 1; + obj_saliendo = 100; + if (hay_que_load == 0) { + carga_escoba("45.ald"); + } else + para_cargar(nom_partida); + } else if (num_ejec == 6) { + suma_objeto(28); + suma_objeto(9); + + buffer_teclado(); + sentido_hare = 1; + obj_saliendo = 104; + if (hay_que_load == 0) + carga_escoba("58.ald"); + else + para_cargar(nom_partida); + if (hay_que_load == 0) + animacion_1_6(); + else { + lee_dibujos("auxdr.alg"); + descomprime_dibujo(dir_dibujo2, 1); + } } bucles: @@ -525,38 +645,50 @@ bucles: comprueba_objetos(); if (boton_dch == 1 && menu_scr == 1) { - if (num_ejec == 1) - lee_dibujos("99.alg"); - else if (num_ejec == 2) + if (num_ejec == 2) lee_dibujos(fondo_y_menu); + else + lee_dibujos("99.alg"); descomprime_dibujo(dir_hare_fondo, 1); setvgapalette256((byte *)&palJuego); menu_scr = 0; espera_soltar(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } if (boton_dch == 1 && menu_scr == 0) { hare_se_mueve = 0; if (sentido_hare == 2) sentido_hare = 1; - lee_dibujos("icons.alg"); + if (num_ejec == 4) + lee_dibujos("icons2.alg"); + else if (num_ejec == 5) + lee_dibujos("icons3.alg"); + else if (num_ejec == 6) + lee_dibujos("iconsp.alg"); + else + lee_dibujos("icons.alg"); descomprime_dibujo(dir_hare_fondo, 1); menu_scr = 1; espera_soltar(); sin_verbo(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } if (boton_izq == 1 && menu_bar == 1) { elige_en_barra(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (boton_izq == 1 && lleva_objeto == 0) { if (comprueba1()) return true; - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (boton_izq == 1 && lleva_objeto == 1) { comprueba2(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } if (y_raton < 24 && menu_scr == 0) @@ -567,59 +699,85 @@ bucles: Common::KeyCode key = getscan(); if (key == Common::KEYCODE_F1 && menu_scr == 0) { elige_verbo(1); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F2 && menu_scr == 0) { elige_verbo(2); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F3 && menu_scr == 0) { elige_verbo(3); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F4 && menu_scr == 0) { elige_verbo(4); cont_sv = 0; } else if (key == Common::KEYCODE_F5 && menu_scr == 0) { elige_verbo(5); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F6 && menu_scr == 0) { elige_verbo(6); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F9) { mesa(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F10) { saves(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_F8) { sin_verbo(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_v) { con_voces = 1; print_abc(SYS2, 96, 86); VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); delay(1410); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_t) { con_voces = 0; print_abc(SYS3, 94, 86); VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); delay(1460); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_DELETE) { - confirma_go(); - cont_sv = 0; + if (num_ejec == 4) + carga_partida("gsave00"); + else + confirma_go(); + if (num_ejec != 3) + cont_sv = 0; } else if (key == Common::KEYCODE_ESCAPE) { confirma_salir(); - cont_sv = 0; + if (num_ejec != 3) + cont_sv = 0; + } else if (num_ejec == 6 && key == Common::KEYCODE_0 && !strcmp(num_room, "61.alg")) { + lee_dibujos("alcbar.alg"); + descomprime_dibujo(dir_dibujo1, 255); } else if (cont_sv == 1500) { salva_pantallas(); - cont_sv = 0; - } else - cont_sv++; + if (num_ejec != 3) + cont_sv = 0; + } else { + if (num_ejec != 3) + cont_sv++; + } goto bucles; } void DrasculaEngine::agarra_objeto(int objeto) { - lee_dibujos("icons.alg"); + if (num_ejec == 6) + lee_dibujos("iconsp.alg"); + else if (num_ejec == 4 || num_ejec == 5) + lee_dibujos("icons2.alg"); + else + lee_dibujos("icons.alg"); descomprime_dibujo(dir_hare_fondo, 1); elige_objeto(objeto); lee_dibujos("99.alg"); @@ -627,8 +785,13 @@ void DrasculaEngine::agarra_objeto(int objeto) { } void DrasculaEngine::elige_objeto(int objeto) { - if (lleva_objeto == 1 && menu_scr == 0) - suma_objeto(objeto_que_lleva); + if (num_ejec == 5) { + if (lleva_objeto == 1 && menu_scr == 0 && objeto_que_lleva != 16) + suma_objeto(objeto_que_lleva); + } else { + if (lleva_objeto == 1 && menu_scr == 0) + suma_objeto(objeto_que_lleva); + } DIBUJA_FONDO(x1d_menu[objeto], y1d_menu[objeto], 0, 0, ANCHOBJ,ALTOBJ, dir_hare_fondo, dir_dibujo3); lleva_objeto = 1; objeto_que_lleva = objeto; @@ -1082,7 +1245,7 @@ bool DrasculaEngine::animacion_2_1() { if ((term_int == 1) || (getscan() == Common::KEYCODE_ESCAPE)) break; - strcpy(num_room,"16.alg"); + strcpy(num_room, "16.alg"); if ((term_int == 1) || (getscan() == Common::KEYCODE_ESCAPE)) break; @@ -1221,9 +1384,14 @@ void DrasculaEngine::sin_verbo() { int c = 171; if (menu_scr == 1) c = 0; - if (lleva_objeto == 1) - suma_objeto(objeto_que_lleva); - DIBUJA_FONDO(0, c, 0, 0, ANCHOBJ,ALTOBJ, dir_hare_fondo, dir_dibujo3); + if (num_ejec == 5) { + if (lleva_objeto == 1 && objeto_que_lleva != 16) + suma_objeto(objeto_que_lleva); + } else { + if (lleva_objeto == 1) + suma_objeto(objeto_que_lleva); + } + DIBUJA_FONDO(0, c, 0, 0, ANCHOBJ,ALTOBJ, dir_hare_fondo, dir_dibujo3); lleva_objeto = 0; hay_nombre = 0; @@ -1232,14 +1400,14 @@ void DrasculaEngine::sin_verbo() { void DrasculaEngine::para_cargar(char nom_game[]) { musica_antes = musica_room; menu_scr = 0; - if (num_ejec == 2) + if (num_ejec == 2 || num_ejec == 3 || num_ejec == 4) borra_pantalla(); carga_partida(nom_game); - if (num_ejec == 1) { - carga_escoba_1(datos_actuales); - } else if (num_ejec == 2) { - ald->close(); - carga_escoba_2(datos_actuales); + if (num_ejec == 1 || num_ejec == 4) { + carga_escoba(datos_actuales); + } else if (num_ejec == 2 || num_ejec == 3) { + delete ald; + carga_escoba(datos_actuales); } sin_verbo(); } @@ -1269,10 +1437,11 @@ static char *getLine(Common::File *fp, char *buf, int len) { return buf; } -void DrasculaEngine::carga_escoba_1(const char *nom_fich) { - int l, obj_salir; +void DrasculaEngine::carga_escoba(const char *nom_fich) { + int soc, l, martin, obj_salir; float chiquez, pequegnez = 0; - char para_codificar[13]; + char pant1[20], pant2[20], pant3[20], pant4[20]; + char para_codificar[20]; char buffer[256]; hay_nombre = 0; @@ -1301,183 +1470,39 @@ void DrasculaEngine::carga_escoba_1(const char *nom_fich) { getLine(ald, buffer, size); sscanf(buffer, "%d", &nivel_osc); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &objs_room); - - for (l = 0; l < objs_room; l++) { + if (num_ejec == 2) { getLine(ald, buffer, size); - sscanf(buffer, "%d", &num_obj[l]); + sscanf(buffer, "%d", &martin); + if (martin == 0) + goto martini; + ancho_hare = martin; getLine(ald, buffer, size); - sscanf(buffer, "%s", nombre_obj[l]); + sscanf(buffer, "%d",&alto_hare); getLine(ald, buffer, size); - sscanf(buffer, "%d", &x1[l]); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &y1[l]); + sscanf(buffer, "%d",&alto_pies); getLine(ald, buffer, size); - sscanf(buffer, "%d", &x2[l]); + sscanf(buffer, "%d",&paso_x); getLine(ald, buffer, size); - sscanf(buffer, "%d", &y2[l]); + sscanf(buffer, "%d",&paso_y); + getLine(ald, buffer, size); - sscanf(buffer, "%d", &sitiobj_x[l]); + sscanf(buffer, "%s",pant1); getLine(ald, buffer, size); - sscanf(buffer, "%d", &sitiobj_y[l]); + sscanf(buffer, "%s",pant2); getLine(ald, buffer, size); - sscanf(buffer, "%d", &sentidobj[l]); + sscanf(buffer, "%s",pant3); getLine(ald, buffer, size); - sscanf(buffer, "%d", &visible[l]); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &espuerta[l]); - if (espuerta[l] != 0) { - getLine(ald, buffer, size); - sscanf(buffer, "%s", alapantallakeva[l]); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &x_alakeva[l]); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &y_alakeva[l]); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &sentido_alkeva[l]); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &alapuertakeva[l]); - puertas_cerradas(l); - } - } - - getLine(ald, buffer, size); - sscanf(buffer, "%d", &suelo_x1); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &suelo_y1); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &suelo_x2); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &suelo_y2); - - getLine(ald, buffer, size); - sscanf(buffer, "%d", &lejos); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &cerca); - delete ald; - - canal_p(para_codificar); - - for (l = 0; l < objs_room; l++) { - if (num_obj[l] == obj_saliendo) - obj_salir = l; - } - - lee_dibujos(pantalla_disco); - descomprime_dibujo(dir_dibujo3, 1); - - lee_dibujos(num_room); - descomprime_dibujo(dir_dibujo1, MEDIA); - - DIBUJA_FONDO(0, 171, 0, 0, ANCHOBJ, ALTOBJ, dir_hare_fondo, dir_dibujo3); - - color_hare(); - if (nivel_osc != 0) - funde_hare(nivel_osc); - paleta_hare_claro(); - color_hare(); - funde_hare(nivel_osc + 2); - paleta_hare_oscuro(); - - hare_claro(); - cambio_de_color = -1; - - for (l = 0; l <= suelo_y1; l++) - factor_red[l] = lejos; - for (l = suelo_y1; l <= 201; l++) - factor_red[l] = cerca; + sscanf(buffer, "%s",pant4); - chiquez = (float)(cerca-lejos) / (float)(suelo_y2 - suelo_y1); - for (l = suelo_y1; l <= suelo_y2; l++) { - factor_red[l] = (int)(lejos + pequegnez); - pequegnez = pequegnez + chiquez; - } - - if (hare_x == -1) { - hare_x = x_alakeva[obj_salir]; - hare_y = y_alakeva[obj_salir]; - alto_hare = (ALTO_PERSONAJE * factor_red[hare_y]) / 100; - ancho_hare = (ANCHO_PERSONAJE * factor_red[hare_y]) / 100; - hare_y = hare_y - alto_hare; - } else { - alto_hare = (ALTO_PERSONAJE * factor_red[hare_y]) / 100; - ancho_hare = (ANCHO_PERSONAJE * factor_red[hare_y]) / 100; - } - hare_se_mueve = 0; - - actualiza_datos(); - - espuerta[7] = 0; - - if (musica_antes != musica_room) - playmusic(musica_room); - refresca_pantalla(); -} - -void DrasculaEngine::carga_escoba_2(const char *nom_fich) { - int soc, l, martin, obj_salir; - char pant1[20], pant2[20], pant3[20], pant4[20]; - char para_codificar[20]; - char buffer[256]; - - hay_nombre = 0; - - strcpy(para_codificar, nom_fich); - canal_p(para_codificar); - strcpy(datos_actuales, nom_fich); - - buffer_teclado(); + lee_dibujos(pant2); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos(pant1); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos(pant4); + descomprime_dibujo(dir_hare_fondo, 1); - ald = new Common::File; - ald->open(nom_fich); - if (!ald->isOpen()) { - error("missing data file"); + strcpy(fondo_y_menu, pant4); } - int size = ald->size(); - - getLine(ald, buffer, size); - sscanf(buffer, "%s", num_room); - strcat(num_room, ".alg"); - - getLine(ald, buffer, size); - sscanf(buffer, "%d", &musica_room); - getLine(ald, buffer, size); - sscanf(buffer, "%s", pantalla_disco); - getLine(ald, buffer, size); - sscanf(buffer, "%d", &nivel_osc); - - getLine(ald, buffer, size); - sscanf(buffer, "%d", &martin); - if (martin == 0) - goto martini; - ancho_hare = martin; - getLine(ald, buffer, size); - sscanf(buffer, "%d",&alto_hare); - getLine(ald, buffer, size); - sscanf(buffer, "%d",&alto_pies); - getLine(ald, buffer, size); - sscanf(buffer, "%d",&paso_x); - getLine(ald, buffer, size); - sscanf(buffer, "%d",&paso_y); - - getLine(ald, buffer, size); - sscanf(buffer, "%s",pant1); - getLine(ald, buffer, size); - sscanf(buffer, "%s",pant2); - getLine(ald, buffer, size); - sscanf(buffer, "%s",pant3); - getLine(ald, buffer, size); - sscanf(buffer, "%s",pant4); - - lee_dibujos(pant2); - descomprime_dibujo(dir_hare_dch, 1); - lee_dibujos(pant1); - descomprime_dibujo(dir_hare_frente, 1); - lee_dibujos(pant4); - descomprime_dibujo(dir_hare_fondo, 1); - - strcpy(fondo_y_menu, pant4); martini: @@ -1531,37 +1556,47 @@ martini: getLine(ald, buffer, size); sscanf(buffer, "%d", &suelo_y2); + if (num_ejec != 2) { + getLine(ald, buffer, size); + sscanf(buffer, "%d", &lejos); + getLine(ald, buffer, size); + sscanf(buffer, "%d", &cerca); + } delete ald; - canal_p(para_codificar); - if (martin == 0) { - paso_x = PASO_HARE_X; - paso_y = PASO_HARE_Y; - alto_hare = ALTO_PERSONAJE; - ancho_hare = ANCHO_PERSONAJE; - alto_pies = PIES_HARE; - lee_dibujos("97.alg"); - descomprime_dibujo(dir_hare_dch, 1); - lee_dibujos("96.alg"); - descomprime_dibujo(dir_hare_frente, 1); - lee_dibujos("99.alg"); - descomprime_dibujo(dir_hare_fondo, 1); + if (num_ejec == 2) { + if (martin == 0) { + paso_x = PASO_HARE_X; + paso_y = PASO_HARE_Y; + alto_hare = ALTO_PERSONAJE; + ancho_hare = ANCHO_PERSONAJE; + alto_pies = PIES_HARE; + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); - strcpy(fondo_y_menu,"99.alg"); + strcpy(fondo_y_menu, "99.alg"); + } } - + + obj_salir = -1; for (l = 0; l < objs_room; l++) { if (num_obj[l] == obj_saliendo) obj_salir = l; } - if (hare_x == -1) { - hare_x = x_alakeva[obj_salir]; - hare_y = y_alakeva[obj_salir] - alto_hare; + if (num_ejec == 2) { + if (hare_x == -1) { + assert(obj_salir != -1); + hare_x = x_alakeva[obj_salir]; + hare_y = y_alakeva[obj_salir] - alto_hare; + } + hare_se_mueve = 0; } - hare_se_mueve = 0; - lee_dibujos(pantalla_disco); descomprime_dibujo(dir_dibujo3, 1); @@ -1581,21 +1616,72 @@ martini: hare_claro(); cambio_de_color = -1; - color_abc(VERDE_CLARO); + if (num_ejec == 2) + color_abc(VERDE_CLARO); + + if (num_ejec != 2) { + for (l = 0; l <= suelo_y1; l++) + factor_red[l] = lejos; + for (l = suelo_y1; l <= 201; l++) + factor_red[l] = cerca; + + chiquez = (float)(cerca - lejos) / (float)(suelo_y2 - suelo_y1); + for (l = suelo_y1; l <= suelo_y2; l++) { + factor_red[l] = (int)(lejos + pequegnez); + pequegnez = pequegnez + chiquez; + } + } + + if (!strcmp(num_room, "24.alg")) { + for (l = suelo_y1 - 1; l > 74; l--) { + factor_red[l] = (int)(lejos - pequegnez); + pequegnez = pequegnez + chiquez; + } + } + + if (!strcmp(num_room, "54.alg")) { + for (l = suelo_y1 - 1; l > 84; l--) { + factor_red[l] = (int)(lejos - pequegnez); + pequegnez = pequegnez + chiquez; + } + } - soc = 0; - for (l = 0; l < 6; l++) { - soc = soc + ancho_hare; - frame_x[l] = soc; + if (num_ejec != 2) { + if (hare_x == -1) { + assert(obj_salir != -1); + hare_x = x_alakeva[obj_salir]; + hare_y = y_alakeva[obj_salir]; + alto_hare = (ALTO_PERSONAJE * factor_red[hare_y]) / 100; + ancho_hare = (ANCHO_PERSONAJE * factor_red[hare_y]) / 100; + hare_y = hare_y - alto_hare; + } else { + alto_hare = (ALTO_PERSONAJE * factor_red[hare_y]) / 100; + ancho_hare = (ANCHO_PERSONAJE * factor_red[hare_y]) / 100; + } + hare_se_mueve = 0; + } + + if (num_ejec == 2) { + soc = 0; + for (l = 0; l < 6; l++) { + soc = soc + ancho_hare; + frame_x[l] = soc; + } } + if (num_ejec == 5) + hare_se_ve = 1; + actualiza_datos(); + if (num_ejec == 1) + espuerta[7] = 0; + if (!strcmp(num_room, "14.alg") && flags[39] == 1) musica_room = 16; else if (!strcmp(num_room, "15.alg") && flags[39] == 1) musica_room = 16; - if (!strcmp(num_room, "14.alg") && flags[5]==1) + if (!strcmp(num_room, "14.alg") && flags[5] == 1) musica_room = 0; else if (!strcmp(num_room, "15.alg") && flags[5] == 1) musica_room = 0; @@ -1606,9 +1692,17 @@ martini: stopmusic(); if ((!strcmp(num_room, "9.alg")) || (strcmp(num_room, "2.alg")) - || (!strcmp(num_room, "14.alg")) || (!strcmp(num_room, "18.alg"))) - conta_ciego_vez = vez(); + || (!strcmp(num_room, "14.alg")) || (!strcmp(num_room, "18.alg")) + || (!strcmp(num_room, "26.alg"))) + conta_ciego_vez = (int)vez(); + if (!strcmp(num_room, "24.alg") && flags[29] == 1) + animacion_7_4(); + if (!strcmp(num_room, "45.alg")) + hare_se_ve = 0; + if (!strcmp(num_room, "49.alg") && flags[7] == 0) + animacion_4_5(); + refresca_pantalla(); } @@ -1619,11 +1713,18 @@ void DrasculaEngine::borra_pantalla() { } void DrasculaEngine::lleva_al_hare(int punto_x, int punto_y) { + if (num_ejec == 5 || num_ejec == 6) { + if (hare_se_ve == 0) { + hare_x = sitio_x; + hare_y = sitio_y; + goto fin; + } + } sitio_x = punto_x; sitio_y = punto_y; empieza_andar(); - for(;;) { + for (;;) { refresca_pantalla(); VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); if (hare_se_mueve == 0) @@ -1634,6 +1735,7 @@ void DrasculaEngine::lleva_al_hare(int punto_x, int punto_y) { anda_a_objeto = 0; sentido_hare = sentido_final; } +fin: refresca_pantalla(); VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); } @@ -1681,20 +1783,21 @@ void DrasculaEngine::comprueba_objetos() { } } - if (num_ejec == 1) + if (num_ejec == 2) { if (x_raton > hare_x + 2 && y_raton > hare_y + 2 - && x_raton < hare_x + ancho_hare - 2 && y_raton < hare_y + alto_hare - 2 && veo == 0) { + && x_raton < hare_x + ancho_hare - 2 && y_raton < hare_y + alto_hare - 2) { strcpy(texto_nombre, "hacker"); hay_nombre = 1; veo = 1; } - else if (num_ejec == 2) + } else { if (x_raton > hare_x + 2 && y_raton > hare_y + 2 - && x_raton < hare_x + ancho_hare - 2 && y_raton < hare_y + alto_hare - 2) { + && x_raton < hare_x + ancho_hare - 2 && y_raton < hare_y + alto_hare - 2 && veo == 0) { strcpy(texto_nombre, "hacker"); hay_nombre = 1; veo = 1; } + } if (veo == 0) hay_nombre = 0; @@ -1790,6 +1893,8 @@ void DrasculaEngine::comprueba2() { anda_a_objeto = 1; lleva_al_hare(sitiobj_x[l], sitiobj_y[l]); banderas(num_obj[l]); + if (num_ejec == 4) + break; } } } @@ -1847,8 +1952,13 @@ void DrasculaEngine::elige_verbo(int verbo) { if (menu_scr == 1) c = 0; - if (lleva_objeto == 1) - suma_objeto(objeto_que_lleva); + if (num_ejec == 5) { + if (lleva_objeto == 1 && objeto_que_lleva != 16) + suma_objeto(objeto_que_lleva); + } else { + if (lleva_objeto == 1) + suma_objeto(objeto_que_lleva); + } DIBUJA_FONDO(ANCHOBJ * verbo, c, 0, 0, ANCHOBJ, ALTOBJ, dir_hare_fondo, dir_dibujo3); @@ -1920,7 +2030,7 @@ void DrasculaEngine::mesa() { void DrasculaEngine::saves() { char nombres[10][23]; char fichero[13]; - int n, n2, num_sav, y = 27; + int n, n2, num_sav = 0, y = 27; Common::InSaveFile *sav; borra_pantalla(); @@ -1955,6 +2065,9 @@ void DrasculaEngine::saves() { for (n = 0; n < NUM_SAVES; n++) { if (x_raton > 115 && y_raton > y + (9 * n) && x_raton < 115 + 175 && y_raton < y + 10 + (9 * n)) { strcpy(select, nombres[n]); + + // FIXME: The indention is wrong and misleading here!!! Or maybe there's simply a + // closing brace missing here??? See below for a second FIXME of a similar kind... if (strcmp(select, "*")) hay_seleccion = 1; @@ -1962,6 +2075,8 @@ void DrasculaEngine::saves() { introduce_nombre(); strcpy(nombres[n], select); if (hay_seleccion == 1) { + // FIXME: Just use: + //sprintf(fichero, "gsave%02d", n+1); if (n == 0) strcpy(fichero, "gsave01"); if (n == 1) @@ -2001,6 +2116,8 @@ void DrasculaEngine::saves() { y = y + 9; } if (hay_seleccion == 1) { + // FIXME: Just use: + //sprintf(fichero, "gsave%02d", n+1); if (n == 0) strcpy(fichero, "gsave01"); if (n == 1) @@ -2020,7 +2137,12 @@ void DrasculaEngine::saves() { if (n == 8) strcpy(fichero, "gsave09"); if (n == 9) - strcpy(fichero, "gsave10");} + strcpy(fichero, "gsave10");} // FIXME: EVIL wrong place for closing brace! + // In particular: is the assignment below maybe supposed to be inside the "if" + // statement that was just closed? + // Also note that the indention is wrong here, which is not immediately visible + // due to the other indention mistake above. But is the indention wrong, or is + // the brace placement wrong??? num_sav = n; } } @@ -2052,7 +2174,7 @@ void DrasculaEngine::saves() { } else if (x_raton > 168 && y_raton > 154 && x_raton < 242 && y_raton < 180) break; else if (hay_seleccion == 0) { - print_abc("elige una partida",117,15); + print_abc("elige una partida", 117, 15); } VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); delay(400); @@ -2436,8 +2558,8 @@ char DrasculaEngine::LimitaVGA(char valor) { } void DrasculaEngine::centra_texto(const char *mensaje, int x_texto, int y_texto) { - char bb[190], m2[190], m1[190], mb[10][40]; - char m3[190]; + char bb[200], m2[200], m1[200], mb[10][50]; + char m3[200]; int h, fil, x_texto3, x_texto2, x_texto1, conta_f = 0, ya = 0; strcpy(m1, " "); @@ -2669,10 +2791,14 @@ void DrasculaEngine::pon_igor() { int pos_igor[6]; pos_igor[0] = 1; - if (sentido_igor == 3) + if (num_ejec == 4) { pos_igor[1] = 138; - else if (sentido_igor == 1) - pos_igor[1] = 76; + } else { + if (sentido_igor == 3) + pos_igor[1] = 138; + else if (sentido_igor == 1) + pos_igor[1] = 76; + } pos_igor[2] = x_igor; pos_igor[3] = y_igor; pos_igor[4] = 54; @@ -2719,13 +2845,13 @@ void DrasculaEngine::habla_igor_dch(const char *dicho, const char *filename) { int tiempou; long tiempol; - int x_habla[8] = { 56, 82, 108, 134, 160, 186, 212, 238}; + int x_habla[8] = { 56, 82, 108, 134, 160, 186, 212, 238 }; int cara; int longitud; longitud = strlen(dicho); - tiempol = time (NULL); + tiempol = _system->getMillis(); tiempou = (unsigned int)tiempol / 2; _rnd->setSeed(tiempou); @@ -2754,11 +2880,9 @@ bucless: pon_igor(); pon_dr(); - DIBUJA_FONDO(x_igor + 17, y_igor, x_igor + 17, y_igor, 37, 24, - dir_dibujo1, dir_zona_pantalla); + DIBUJA_FONDO(x_igor + 17, y_igor, x_igor + 17, y_igor, 37, 24, dir_dibujo1, dir_zona_pantalla); - DIBUJA_BLOQUE(x_habla[cara], 148, x_igor + 17, y_igor, 25, 24, - dir_hare_frente, dir_zona_pantalla); + DIBUJA_BLOQUE(x_habla[cara], 148, x_igor + 17, y_igor, 25, 24, dir_hare_frente, dir_zona_pantalla); actualiza_refresco(); @@ -2832,8 +2956,7 @@ bucless: pon_dr(); DIBUJA_FONDO(x_dr, y_dr, x_dr, y_dr, 38, 31, dir_dibujo1, dir_zona_pantalla); - DIBUJA_BLOQUE(x_habla[cara], 90, x_dr, y_dr, 38, 31, - dir_hare_fondo, dir_zona_pantalla); + DIBUJA_BLOQUE(x_habla[cara], 90, x_dr, y_dr, 38, 31, dir_hare_fondo, dir_zona_pantalla); actualiza_refresco(); @@ -2907,8 +3030,7 @@ bucless: pon_dr(); DIBUJA_FONDO(x_dr, y_dr, x_dr, y_dr, 45, 31, dir_dibujo1, dir_zona_pantalla); - DIBUJA_BLOQUE(x_habla[cara], 58, x_dr + 7, y_dr, 38, 31, - dir_hare_fondo, dir_zona_pantalla); + DIBUJA_BLOQUE(x_habla[cara], 58, x_dr + 7, y_dr, 38, 31, dir_hare_fondo, dir_zona_pantalla); actualiza_refresco(); @@ -2994,7 +3116,7 @@ void DrasculaEngine::habla_igor_frente(const char *dicho, const char *filename) int tiempou; long tiempol; - int x_habla[8] = { 56, 86, 116, 146, 176, 206, 236, 266}; + int x_habla[8] = { 56, 86, 116, 146, 176, 206, 236, 266 }; int cara; int longitud; @@ -3029,17 +3151,15 @@ bucless: pon_igor(); pon_dr(); - DIBUJA_FONDO(x_igor, y_igor, x_igor, y_igor, 29, 25, - dir_dibujo1, dir_zona_pantalla); - DIBUJA_BLOQUE(x_habla[cara], 173, x_igor, y_igor, 29, 25, - dir_hare_frente, dir_zona_pantalla); + DIBUJA_FONDO(x_igor, y_igor, x_igor, y_igor, 29, 25, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x_habla[cara], 173, x_igor, y_igor, 29, 25, dir_hare_frente, dir_zona_pantalla); actualiza_refresco(); if (con_voces == 0) centra_texto(dicho, x_igor + 26, y_igor); - VUELCA_PANTALLA(0,0, 0,0, 320,200, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); pausa(3); @@ -3070,7 +3190,7 @@ void DrasculaEngine::habla_tabernero(const char *dicho, const char *filename) { int tiempou; long tiempol; - int x_habla[9] = { 1, 23, 45, 67, 89, 111, 133, 155, 177}; + int x_habla[9] = { 1, 23, 45, 67, 89, 111, 133, 155, 177 }; int cara; int longitud; @@ -3138,23 +3258,33 @@ bucless: void DrasculaEngine::hipo(int contador) { int y = 0, sentido = 0; - - contador = contador; + if (num_ejec == 3) + y = -1; comienza: contador--; refresca_pantalla(); - VUELCA_PANTALLA(0, 1, 0, y, 320, 198, dir_zona_pantalla); + if (num_ejec <= 2) + VUELCA_PANTALLA(0, 1, 0, y, 320, 198, dir_zona_pantalla); + else if (num_ejec == 3) + VUELCA_PANTALLA(0, 0, 0, y, 320, 200, dir_zona_pantalla); if (sentido == 0) y++; else y--; - if (y == 2) - sentido = 1; - if (y == 0) - sentido = 0; + if (num_ejec <= 2) { + if (y == 2) + sentido = 1; + if (y == 0) + sentido = 0; + } else if (num_ejec == 3) { + if (y == 1) + sentido = 1; + if (y == -1) + sentido = 0; + } if (contador > 0) goto comienza; @@ -3175,7 +3305,7 @@ void DrasculaEngine::habla_bj(const char *dicho, const char *filename) { int tiempou; long tiempol; - int x_habla[5] = { 64, 92, 120, 148, 176}; + int x_habla[5] = { 64, 92, 120, 148, 176 }; int cara; int longitud; @@ -3258,6 +3388,17 @@ void DrasculaEngine::hablar(const char *dicho, const char *filename) { int longitud; longitud = strlen(dicho); + if (num_ejec == 6) { + if (flags[0] == 0 && (!strcmp(num_room, "102.alg"))) { + habla_pen(dicho, filename); + return; + } + if (flags[0] == 0 && (!strcmp(num_room, "58.alg"))) { + habla_pen2(dicho, filename); + return; + } + } + tiempol = _system->getMillis(); tiempou = (unsigned int)tiempol / 2; _rnd->setSeed(tiempou); @@ -3268,8 +3409,12 @@ void DrasculaEngine::hablar(const char *dicho, const char *filename) { if (num_ejec == 2) buffer_teclado(); - color_abc(AMARILLO); - + if (num_ejec == 4) { + if (strcmp(num_room, "24.alg") || flags[29] == 0) + color_abc(AMARILLO); + } else { + color_abc(AMARILLO); + } if (hay_sb == 1) { sku = new Common::File; sku->open(filename); @@ -3289,20 +3434,15 @@ bucless: actualiza_refresco_antes(); if (num_ejec == 1) - DIBUJA_FONDO(hare_x, hare_y, ANCHOBJ + 1, 0, - ancho_hare * factor_red[hare_y + alto_hare] / 100, - (alto_habla - 1) * factor_red[hare_y + alto_hare] / 100, - dir_zona_pantalla, dir_dibujo3); + DIBUJA_FONDO(hare_x, hare_y, ANCHOBJ + 1, 0, ancho_hare * factor_red[hare_y + alto_hare] / 100, + (alto_habla - 1) * factor_red[hare_y + alto_hare] / 100, dir_zona_pantalla, dir_dibujo3); else if (num_ejec == 2) - DIBUJA_FONDO(hare_x, hare_y, ANCHOBJ + 1, 0, ancho_hare, alto_habla - 1, - dir_zona_pantalla, dir_dibujo3); + DIBUJA_FONDO(hare_x, hare_y, ANCHOBJ + 1, 0, ancho_hare, alto_habla - 1, dir_zona_pantalla, dir_dibujo3); pon_hare(); if (num_ejec == 1) - DIBUJA_FONDO(ANCHOBJ + 1, 0, hare_x, hare_y, - ancho_hare * factor_red[hare_y + alto_hare] / 100, - (alto_habla - 1) * factor_red[hare_y + alto_hare] / 100, - dir_dibujo3, dir_zona_pantalla); + DIBUJA_FONDO(ANCHOBJ + 1, 0, hare_x, hare_y, ancho_hare * factor_red[hare_y + alto_hare] / 100, + (alto_habla - 1) * factor_red[hare_y + alto_hare] / 100, dir_dibujo3, dir_zona_pantalla); else if (num_ejec == 2) DIBUJA_FONDO(ANCHOBJ + 1, 0, hare_x, hare_y, ancho_hare, alto_habla - 1, @@ -3310,24 +3450,20 @@ bucless: if (sentido_hare == 0) { if (num_ejec == 1) - reduce_hare_chico(x_habla_izq[cara], y_mask_habla, - hare_x + 8 * factor_red[hare_y + alto_hare] / 100, + reduce_hare_chico(x_habla_izq[cara], y_mask_habla, hare_x + 8 * factor_red[hare_y + alto_hare] / 100, hare_y, ancho_habla, alto_habla, factor_red[hare_y + alto_hare], dir_hare_dch, dir_zona_pantalla); else if (num_ejec == 2) - DIBUJA_BLOQUE(x_habla_dch[cara], y_mask_habla, - hare_x + 12, hare_y, ancho_habla, alto_habla, + DIBUJA_BLOQUE(x_habla_dch[cara], y_mask_habla, hare_x + 12, hare_y, ancho_habla, alto_habla, dir_hare_dch, dir_zona_pantalla); actualiza_refresco(); } else if (sentido_hare == 1) { if (num_ejec == 1) - reduce_hare_chico(x_habla_dch[cara], y_mask_habla, - hare_x + 12 * factor_red[hare_y + alto_hare] / 100, - hare_y, ancho_habla,alto_habla, factor_red[hare_y + alto_hare], + reduce_hare_chico(x_habla_dch[cara], y_mask_habla, hare_x + 12 * factor_red[hare_y + alto_hare] / 100, + hare_y, ancho_habla,alto_habla, factor_red[hare_y + alto_hare], dir_hare_dch, dir_zona_pantalla); else if (num_ejec == 2) - DIBUJA_BLOQUE(x_habla_dch[cara], y_mask_habla, - hare_x + 8, hare_y, ancho_habla, alto_habla, + DIBUJA_BLOQUE(x_habla_dch[cara], y_mask_habla, hare_x + 8, hare_y, ancho_habla, alto_habla, dir_hare_dch, dir_zona_pantalla); actualiza_refresco(); } else if (sentido_hare == 2) { @@ -3393,7 +3529,13 @@ int DrasculaEngine::music_status() { void DrasculaEngine::refresca_pantalla() { DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); actualiza_refresco_antes(); - pon_hare(); + if (num_ejec == 3) { + if (flags[0] == 0) + pon_hare(); + else + DIBUJA_BLOQUE(113, 54, hare_x - 20, hare_y - 1, 77, 89, dir_dibujo3, dir_zona_pantalla); + } else + pon_hare(); actualiza_refresco(); } @@ -3465,38 +3607,92 @@ void DrasculaEngine::canal_p(const char *fich){ rename(fich2, fich); } -void DrasculaEngine::puertas_cerradas (int l) { - if (num_ejec == 1) +void DrasculaEngine::puertas_cerradas(int l) { + if (num_ejec == 1 || num_ejec == 3 || num_ejec == 5 || num_ejec == 6) return; - - if (num_obj[l] == 138 && flags[0] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 138 && flags[0] == 1) - espuerta[l] = 1; - else if (num_obj[l] == 136 && flags[8] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 136 && flags[8] == 1) - espuerta[l] = 1; - else if (num_obj[l] == 156 && flags[16] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 156 && flags[16] == 1) - espuerta[l] = 1; - else if (num_obj[l] == 163 && flags[17] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 163 && flags[17] == 1) - espuerta[l] = 1; - else if (num_obj[l] == 177 && flags[15] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 177 && flags[15] == 1) - espuerta[l] = 1; - else if (num_obj[l] == 175 && flags[40] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 175 && flags[40] == 1) - espuerta[l] = 1; - else if (num_obj[l] == 173 && flags[36] == 0) - espuerta[l] = 0; - else if (num_obj[l] == 173 && flags[36] == 1) - espuerta[l] = 1; + else if (num_ejec == 2) { + if (num_obj[l] == 138 && flags[0] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 138 && flags[0] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 136 && flags[8] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 136 && flags[8] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 156 && flags[16] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 156 && flags[16] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 163 && flags[17] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 163 && flags[17] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 177 && flags[15] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 177 && flags[15] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 175 && flags[40] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 175 && flags[40] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 173 && flags[36] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 173 && flags[36] == 1) + espuerta[l] = 1; + } else if (num_ejec == 4) { + if (num_obj[l] == 101 && flags[0] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 101 && flags[0] == 1 && flags[28] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 103 && flags[0] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 103 && flags[0] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 104 && flags[1] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 104 && flags[1] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 105 && flags[1] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 105 && flags[1] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 106 && flags[2] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 106 && flags[2] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 107 && flags[2] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 107 && flags[2] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 110 && flags[6] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 110 && flags[6] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 114 && flags[4] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 114 && flags[4] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 115 && flags[4] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 115 && flags[4] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 116 && flags[5] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 116 && flags[5] == 1 && flags[23] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 117 && flags[5] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 117 && flags[5] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 120 && flags[8] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 120 && flags[8] == 1) + espuerta[l] = 1; + else if (num_obj[l] == 122 && flags[7] == 0) + espuerta[l] = 0; + else if (num_obj[l] == 122 && flags[7] == 1) + espuerta[l] = 1; + } } void DrasculaEngine::color_hare() { @@ -3559,18 +3755,7 @@ void DrasculaEngine::empieza_andar() { paso_x = PASO_HARE_X; paso_y = PASO_HARE_Y; - if (num_ejec == 1) { - if ((sitio_x < hare_x + ancho_hare / 2 ) && (sitio_y <= (hare_y + alto_hare))) - cuadrante_1(); - else if ((sitio_x < hare_x + ancho_hare / 2) && (sitio_y > (hare_y + alto_hare))) - cuadrante_3(); - else if ((sitio_x > hare_x + ancho_hare / 2) && (sitio_y <= (hare_y + alto_hare))) - cuadrante_2(); - else if ((sitio_x > hare_x + ancho_hare / 2) && (sitio_y > (hare_y + alto_hare))) - cuadrante_4(); - else - hare_se_mueve = 0; - } else if (num_ejec == 2) { + if (num_ejec == 2) { if ((sitio_x < hare_x) && (sitio_y <= (hare_y + alto_hare))) cuadrante_1(); else if ((sitio_x < hare_x) && (sitio_y > (hare_y + alto_hare))) @@ -3583,6 +3768,17 @@ void DrasculaEngine::empieza_andar() { anda_parriba(); else if (sitio_y > hare_y + alto_hare) anda_pabajo(); + } else { + if ((sitio_x < hare_x + ancho_hare / 2 ) && (sitio_y <= (hare_y + alto_hare))) + cuadrante_1(); + else if ((sitio_x < hare_x + ancho_hare / 2) && (sitio_y > (hare_y + alto_hare))) + cuadrante_3(); + else if ((sitio_x > hare_x + ancho_hare / 2) && (sitio_y <= (hare_y + alto_hare))) + cuadrante_2(); + else if ((sitio_x > hare_x + ancho_hare / 2) && (sitio_y > (hare_y + alto_hare))) + cuadrante_4(); + else + hare_se_mueve = 0; } conta_vez = vez(); } @@ -3592,7 +3788,13 @@ void DrasculaEngine::actualiza_refresco() { refresca_63(); else if (!strcmp(num_room, "62.alg")) refresca_62(); - else if (!strcmp(num_room, "3.alg")) + else if (!strcmp(num_room, "60.alg")) + refresca_60(); + else if (!strcmp(num_room, "61.alg")) + refresca_61(); + else if (!strcmp(num_room, "58.alg")) + refresca_58(); + else if (!strcmp(num_room, "3.alg")) refresca_3(); else if (!strcmp(num_room, "2.alg")) refresca_2(); @@ -3608,11 +3810,29 @@ void DrasculaEngine::actualiza_refresco() { refresca_18(); else if (!strcmp(num_room, "10.alg")) mapa(); -} + else if (!strcmp(num_room, "20.alg")) + refresca_20(); + else if (!strcmp(num_room, "13.alg")) + refresca_13(); + else if (!strcmp(num_room, "45.alg")) + mapa(); + else if (!strcmp(num_room, "50.alg")) + refresca_50(); + else if (!strcmp(num_room, "57.alg")) + refresca_57(); + } void DrasculaEngine::actualiza_refresco_antes() { if (!strcmp(num_room, "62.alg")) refresca_62_antes(); + else if (!strcmp(num_room, "102.alg")) + refresca_pendulo(); + else if (!strcmp(num_room, "58.alg")) + refresca_58_antes(); + else if (!strcmp(num_room, "59.alg")) + refresca_59_antes(); + else if (!strcmp(num_room, "60.alg")) + refresca_60_antes(); else if (!strcmp(num_room, "1.alg")) refresca_1_antes(); else if (!strcmp(num_room, "3.alg")) @@ -3639,6 +3859,14 @@ void DrasculaEngine::actualiza_refresco_antes() { refresca_17_antes(); else if (!strcmp(num_room,"18.alg")) refresca_18_antes(); + else if (!strcmp(num_room,"49.alg")) + refresca_49_antes(); + else if (!strcmp(num_room,"53.alg")) + refresca_53_antes(); + else if (!strcmp(num_room,"54.alg")) + refresca_54_antes(); + else if (!strcmp(num_room,"56.alg")) + refresca_56_antes(); } void DrasculaEngine::pon_hare() { @@ -3691,7 +3919,7 @@ void DrasculaEngine::pon_hare() { } } - if (num_ejec == 1) + if (num_ejec == 1 || num_ejec == 4 || num_ejec == 5 || num_ejec == 6) if (hare_se_ve == 0) goto no_vuelco; @@ -3700,100 +3928,76 @@ void DrasculaEngine::pon_hare() { pos_hare[1] = DIF_MASK_HARE; pos_hare[2] = hare_x; pos_hare[3] = hare_y; - if (num_ejec == 1) { - pos_hare[4] = ANCHO_PERSONAJE; - pos_hare[5] = ALTO_PERSONAJE; - } else if (num_ejec == 2) { + if (num_ejec == 2) { pos_hare[4] = ancho_hare; pos_hare[5] = alto_hare; + } else { + pos_hare[4] = ANCHO_PERSONAJE; + pos_hare[5] = ALTO_PERSONAJE; } if (sentido_hare == 0) { pos_hare[1] = 0; - if (num_ejec == 1) - reduce_hare_chico(pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_dch, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_dch, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_dch, dir_zona_pantalla); } else if (sentido_hare == 1) - if (num_ejec == 1) - reduce_hare_chico(pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_dch, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_dch, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_dch, dir_zona_pantalla); else if (sentido_hare == 2) - if (num_ejec == 1) - reduce_hare_chico( pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_fondo, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_fondo, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_fondo, dir_zona_pantalla); else - if (num_ejec == 1) - reduce_hare_chico( pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_frente, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_frente, dir_zona_pantalla); + else + reduce_hare_chico( pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_frente, dir_zona_pantalla); } else if (hare_se_mueve == 1) { pos_hare[0] = frame_x[num_frame]; pos_hare[1] = frame_y + DIF_MASK_HARE; pos_hare[2] = hare_x; pos_hare[3] = hare_y; - if (num_ejec == 1) { - pos_hare[4] = ANCHO_PERSONAJE; - pos_hare[5] = ALTO_PERSONAJE; - } else if (num_ejec == 2) { + if (num_ejec == 2) { pos_hare[4] = ancho_hare; pos_hare[5] = alto_hare; + } else { + pos_hare[4] = ANCHO_PERSONAJE; + pos_hare[5] = ALTO_PERSONAJE; } if (sentido_hare == 0) { pos_hare[1] = 0; - if (num_ejec == 1) - reduce_hare_chico(pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_dch, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_dch, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_dch, dir_zona_pantalla); } else if (sentido_hare == 1) if (num_ejec == 1) - reduce_hare_chico(pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_dch, dir_zona_pantalla); - else if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_dch, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_dch, dir_zona_pantalla); else if (sentido_hare == 2) - if (num_ejec == 1) - reduce_hare_chico(pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_fondo, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_fondo, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_fondo, dir_zona_pantalla); else - if (num_ejec == 1) - reduce_hare_chico(pos_hare[0], pos_hare[1], - pos_hare[2], pos_hare[3], - pos_hare[4], pos_hare[5], - factor_red[hare_y + alto_hare], - dir_hare_frente, dir_zona_pantalla); - else if (num_ejec == 2) + if (num_ejec == 2) DIBUJA_BLOQUE_CUT(pos_hare, dir_hare_frente, dir_zona_pantalla); + else + reduce_hare_chico(pos_hare[0], pos_hare[1], pos_hare[2], pos_hare[3], pos_hare[4], pos_hare[5], + factor_red[hare_y + alto_hare], dir_hare_frente, dir_zona_pantalla); no_vuelco: aumenta_num_frame(); @@ -3811,8 +4015,12 @@ void DrasculaEngine::menu_sin_volcar() { h = objetos_que_tengo[n]; if (h != 0) - DIBUJA_FONDO(x_pol[n], y_pol[n], x_obj[n], y_obj[n], - ANCHOBJ, ALTOBJ, dir_hare_frente, dir_zona_pantalla); + if (num_ejec == 6) + DIBUJA_FONDO(x_pol[n], y_pol[n], x_obj[n], y_obj[n], + ANCHOBJ, ALTOBJ, dir_mesa, dir_zona_pantalla); + else + DIBUJA_FONDO(x_pol[n], y_pol[n], x_obj[n], y_obj[n], + ANCHOBJ, ALTOBJ, dir_hare_frente, dir_zona_pantalla); DIBUJA_BLOQUE(x1d_menu[h], y1d_menu[h], x_obj[n], y_obj[n], ANCHOBJ, ALTOBJ, dir_hare_fondo, dir_zona_pantalla); @@ -3828,9 +4036,8 @@ void DrasculaEngine::barra_menu() { for (n = 0; n < 7; n++) { if (x_raton > x_barra[n] && x_raton < x_barra[n + 1]) sobre_verbo = 0; - DIBUJA_BLOQUE(ANCHOBJ * n, ALTOBJ * sobre_verbo, - x_barra[n], 2, ANCHOBJ, ALTOBJ, - dir_hare_fondo, dir_zona_pantalla); + DIBUJA_BLOQUE(ANCHOBJ * n, ALTOBJ * sobre_verbo, x_barra[n], 2, + ANCHOBJ, ALTOBJ, dir_hare_fondo, dir_zona_pantalla); sobre_verbo = 1; } } @@ -3882,7 +4089,7 @@ bool DrasculaEngine::sal_de_la_habitacion(int l) { strcpy(salgo, alapantallakeva[l]); strcat(salgo, ".ald"); hare_x = -1; - carga_escoba_1(salgo); + carga_escoba(salgo); } } } else if (num_ejec == 2) { @@ -3893,13 +4100,13 @@ bool DrasculaEngine::sal_de_la_habitacion(int l) { sentido_hare = sentido_alkeva[l]; obj_saliendo = alapuertakeva[l]; rompo = 1; - musica_antes = musica_room; + musica_antes = musica_room; if (num_obj[l] == 136) animacion_2_2(); if (num_obj[l] == 124) animacion_3_2(); if (num_obj[l] == 173) - animacion_35(); + animacion_35_2(); if (num_obj[l] == 146 && flags[39] == 1) { flags[5] = 1; flags[11] = 1; @@ -3910,11 +4117,91 @@ bool DrasculaEngine::sal_de_la_habitacion(int l) { suma_objeto(11); } borra_pantalla(); - ald->close(); + delete ald; + strcpy(salgo, alapantallakeva[l]); + strcat(salgo, ".ald"); + hare_x =- 1; + carga_escoba(salgo); + } + } else if (num_ejec == 3) { + puertas_cerradas(l); + if (espuerta[l] != 0 && visible[l] == 1) { + lleva_al_hare(sitiobj_x[l], sitiobj_y[l]); + sentido_hare = sentidobj[l]; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hare_se_mueve = 0; + sentido_hare = sentido_alkeva[l]; + obj_saliendo = alapuertakeva[l]; + rompo = 1; + musica_antes = musica_room; + borra_pantalla(); strcpy(salgo, alapantallakeva[l]); strcat(salgo, ".ald"); hare_x =- 1; - carga_escoba_2(salgo); + carga_escoba(salgo); + } + } else if (num_ejec == 4) { + puertas_cerradas(l); + if (espuerta[l] != 0) { + lleva_al_hare(sitiobj_x[l], sitiobj_y[l]); + sentido_hare = sentidobj[l]; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hare_se_mueve = 0; + sentido_hare = sentido_alkeva[l]; + obj_saliendo = alapuertakeva[l]; + rompo = 1; + musica_antes = musica_room; + + if (num_obj[l] == 108) + lleva_al_hare(171, 78); + borra_pantalla(); + strcpy(salgo, alapantallakeva[l]); + strcat(salgo, ".ald"); + hare_x = -1; + carga_escoba(salgo); + } + } else if (num_ejec == 5) { + puertas_cerradas(l); + if (espuerta[l] != 0 && visible[l] == 1) { + lleva_al_hare(sitiobj_x[l], sitiobj_y[l]); + sentido_hare = sentidobj[l]; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hare_se_mueve = 0; + sentido_hare = sentido_alkeva[l]; + obj_saliendo = alapuertakeva[l]; + rompo = 1; + musica_antes = musica_room; + hare_se_ve = 1; + borra_pantalla(); + strcpy(salgo, alapantallakeva[l]); + strcat(salgo, ".ald"); + hare_x = -1; + carga_escoba(salgo); + } + } else if (num_ejec == 6) { + puertas_cerradas(l); + + if (espuerta[l] != 0) { + lleva_al_hare(sitiobj_x[l], sitiobj_y[l]); + sentido_hare = sentidobj[l]; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hare_se_mueve = 0; + sentido_hare = sentido_alkeva[l]; + obj_saliendo = alapuertakeva[l]; + rompo = 1; + musica_antes = musica_room; + borra_pantalla(); + strcpy(salgo, alapantallakeva[l]); + strcat(salgo, ".ald"); + hare_x = -1; + carga_escoba(salgo); + + if (obj_saliendo == 105) + animacion_19_6(); } } @@ -3959,60 +4246,236 @@ void DrasculaEngine::banderas(int fl) { hay_respuesta = 1; if (menu_scr == 1) { - if (objeto_que_lleva == MIRAR && fl == 28) - hablar(TEXT328, "328.als"); - if ((objeto_que_lleva == MIRAR && fl == 22 && flags[23] == 0) - || (objeto_que_lleva == ABRIR && fl == 22 && flags[23] == 0)) { - hablar(TEXT164, "164.als"); - flags[23] = 1; - sin_verbo(); - suma_objeto(7); - suma_objeto(18); - } else if (objeto_que_lleva == MIRAR && fl == 22 && flags[23] == 1) - hablar(TEXT307, "307.als"); - else if (objeto_que_lleva == MIRAR && fl == 7) - hablar(TEXT143, "143.als"); - else if (objeto_que_lleva == HABLAR && fl == 7) - hablar(TEXT144, "144.als"); - else if (objeto_que_lleva == MIRAR && fl == 8) - hablar(TEXT145, "145.als"); - else if (objeto_que_lleva == HABLAR && fl == 8) - hablar(TEXT146, "146.als"); - else if (objeto_que_lleva == MIRAR && fl == 9) - hablar(TEXT147, "147.als"); - else if (objeto_que_lleva == HABLAR && fl == 9) - hablar(TEXT148, "148.als"); - else if (objeto_que_lleva == MIRAR && fl == 10) - hablar(TEXT151, "151.als"); - else if (objeto_que_lleva == MIRAR && fl == 11) - hablar(TEXT152, "152.als"); - else if (objeto_que_lleva == HABLAR && fl == 11) - hablar(TEXT153, "153.als"); - else if (objeto_que_lleva == MIRAR && fl == 12) - hablar(TEXT154, "154.als"); - else if (objeto_que_lleva == MIRAR && fl == 13) - hablar(TEXT155, "155.als"); - else if (objeto_que_lleva == MIRAR && fl == 14) - hablar(TEXT157, "157.als"); - else if (objeto_que_lleva == MIRAR && fl == 15) - hablar(TEXT58, "58.als"); - else if (objeto_que_lleva == MIRAR && fl == 16) - hablar(TEXT158, "158.als"); - else if (objeto_que_lleva == MIRAR && fl == 17) - hablar(TEXT159, "159.als"); - else if (objeto_que_lleva == MIRAR && fl == 18) - hablar(TEXT160, "160.als"); - else if (objeto_que_lleva == MIRAR && fl == 19) - hablar(TEXT161, "161.als"); - else if (objeto_que_lleva == MIRAR && fl == 20) - hablar(TEXT162, "162.als"); - else if (objeto_que_lleva == MIRAR && fl == 23) - hablar(TEXT152, "152.als"); - else - hay_respuesta = 0; + if (num_ejec == 4) { + if (objeto_que_lleva == MIRAR && fl == 28) + hablar(TEXT328, "328.als"); + else if (objeto_que_lleva == MIRAR && fl == 7) + hablar(TEXT478, "478.als"); + else if (objeto_que_lleva == MIRAR && fl == 8) + hablar(TEXT120, "120.als"); + else if (objeto_que_lleva == MIRAR && fl == 9) { + hablar(TEXT482, "482.als"); + hablar(TEXT483, "483.als"); + } else if (objeto_que_lleva == MIRAR && fl == 11) + hablar(TEXT488, "488.als"); + else if (objeto_que_lleva == MIRAR && fl == 13) + hablar(TEXT490, "490.als"); + else if (objeto_que_lleva == MIRAR && fl == 14) + hablar(TEXT121, "121.als"); + else if (objeto_que_lleva == MIRAR && fl == 15) + hablar(TEXT117, "117.als" ); + else if (objeto_que_lleva == HABLAR && fl == 15) + hablar(TEXT118, "118.als" ); + else if (objeto_que_lleva == ABRIR && fl == 15) + hablar(TEXT119, "119.als" ); + else if (objeto_que_lleva == MIRAR && fl == 17) + hablar(TEXT478, "478.als"); + else if (objeto_que_lleva == MIRAR && fl == 20) + hablar(TEXT162, "162.als"); + else + hay_respuesta = 0; + return; + } + if (num_ejec == 3) { + if (objeto_que_lleva == MIRAR && fl == 22) + hablar(TEXT307, "307.als"); + else if (objeto_que_lleva == MIRAR && fl == 28) + hablar(TEXT328, "328.als"); + else if (objeto_que_lleva == MIRAR && fl == 7) + hablar(TEXT143, "143.als"); + else if (objeto_que_lleva == HABLAR && fl == 7) + hablar(TEXT144, "144.als"); + else if (objeto_que_lleva == MIRAR && fl == 8) + hablar(TEXT145, "145.als"); + else if (objeto_que_lleva == HABLAR && fl == 8) + hablar(TEXT146, "146.als"); + else if (objeto_que_lleva == MIRAR && fl == 9) + hablar(TEXT147, "147.als"); + else if (objeto_que_lleva == HABLAR && fl == 9) + hablar(TEXT148, "148.als"); + else if (objeto_que_lleva == MIRAR && fl == 10) + hablar(TEXT151, "151.als"); + else if (objeto_que_lleva == MIRAR && fl == 11) + hablar(TEXT152, "152.als"); + else if (objeto_que_lleva == HABLAR && fl == 11) + hablar(TEXT153, "153.als"); + else if (objeto_que_lleva == MIRAR && fl == 12) + hablar(TEXT154, "154.als"); + else if (objeto_que_lleva == MIRAR && fl == 13) + hablar(TEXT155, "155.als"); + else if (objeto_que_lleva == MIRAR && fl == 14) + hablar(TEXT157, "157.als"); + else if (objeto_que_lleva == MIRAR && fl == 15) + hablar(TEXT58, "58.als"); + else if (objeto_que_lleva == MIRAR && fl == 16) + hablar(TEXT158, "158.als"); + else if (objeto_que_lleva == MIRAR && fl == 17) + hablar(TEXT159, "159.als"); + else if (objeto_que_lleva == MIRAR && fl == 18) + hablar(TEXT160, "160.als"); + else if (objeto_que_lleva == MIRAR && fl == 19) + hablar(TEXT161, "161.als"); + else if (objeto_que_lleva == MIRAR && fl == 20) + hablar(TEXT162, "162.als"); + else if (objeto_que_lleva == MIRAR && fl == 23) + hablar(TEXT152, "152.als"); + else + hay_respuesta = 0; + } else if (num_ejec == 1) { + if (objeto_que_lleva == MIRAR && fl == 28) + hablar(TEXT328, "328.als"); + if ((objeto_que_lleva == MIRAR && fl == 22 && flags[23] == 0) + || (objeto_que_lleva == ABRIR && fl == 22 && flags[23] == 0)) { + hablar(TEXT164, "164.als"); + flags[23] = 1; + sin_verbo(); + suma_objeto(7); + suma_objeto(18); + } else if (objeto_que_lleva == MIRAR && fl == 22 && flags[23] == 1) + hablar(TEXT307, "307.als"); + else if (objeto_que_lleva == MIRAR && fl == 7) + hablar(TEXT143, "143.als"); + else if (objeto_que_lleva == HABLAR && fl == 7) + hablar(TEXT144, "144.als"); + else if (objeto_que_lleva == MIRAR && fl == 8) + hablar(TEXT145, "145.als"); + else if (objeto_que_lleva == HABLAR && fl == 8) + hablar(TEXT146, "146.als"); + else if (objeto_que_lleva == MIRAR && fl == 9) + hablar(TEXT147, "147.als"); + else if (objeto_que_lleva == HABLAR && fl == 9) + hablar(TEXT148, "148.als"); + else if (objeto_que_lleva == MIRAR && fl == 10) + hablar(TEXT151, "151.als"); + else if (objeto_que_lleva == MIRAR && fl == 11) + hablar(TEXT152, "152.als"); + else if (objeto_que_lleva == HABLAR && fl == 11) + hablar(TEXT153, "153.als"); + else if (objeto_que_lleva == MIRAR && fl == 12) + hablar(TEXT154, "154.als"); + else if (objeto_que_lleva == MIRAR && fl == 13) + hablar(TEXT155, "155.als"); + else if (objeto_que_lleva == MIRAR && fl == 14) + hablar(TEXT157, "157.als"); + else if (objeto_que_lleva == MIRAR && fl == 15) + hablar(TEXT58, "58.als"); + else if (objeto_que_lleva == MIRAR && fl == 16) + hablar(TEXT158, "158.als"); + else if (objeto_que_lleva == MIRAR && fl == 17) + hablar(TEXT159, "159.als"); + else if (objeto_que_lleva == MIRAR && fl == 18) + hablar(TEXT160, "160.als"); + else if (objeto_que_lleva == MIRAR && fl == 19) + hablar(TEXT161, "161.als"); + else if (objeto_que_lleva == MIRAR && fl == 20) + hablar(TEXT162, "162.als"); + else if (objeto_que_lleva == MIRAR && fl == 23) + hablar(TEXT152, "152.als"); + else + hay_respuesta = 0; + } else if (num_ejec == 4) { + if ((objeto_que_lleva == 18 && fl == 19) || (objeto_que_lleva == 19 && fl == 18)) { + sin_verbo(); + elige_objeto(21); + resta_objeto(18); + resta_objeto(19); + } else if ((objeto_que_lleva == 14 && fl == 19) || + (objeto_que_lleva == 19 && fl == 14)) + hablar(TEXT484, "484.als"); + else if (objeto_que_lleva == MIRAR && fl == 28) + hablar(TEXT328, "328.als"); + else if (objeto_que_lleva == MIRAR && fl == 7) + hablar(TEXT478, "478.als"); + else if (objeto_que_lleva == MIRAR && fl == 8) + hablar(TEXT480, "480.als"); + else if (objeto_que_lleva == MIRAR && fl == 9) { + hablar(TEXT482, "482.als"); + hablar(TEXT483, "483.als"); + } else if (objeto_que_lleva == MIRAR && fl == 10) + hablar(TEXT485, "485.als"); + else if (objeto_que_lleva == MIRAR && fl == 11) + hablar(TEXT488, "488.als"); + else if (objeto_que_lleva == MIRAR && fl == 12) + hablar(TEXT486, "486.als"); + else if (objeto_que_lleva == MIRAR && fl == 13) + hablar(TEXT490, "490.als"); + else if (objeto_que_lleva == MIRAR && fl == 14) + hablar(TEXT122, "122.als"); + else if (objeto_que_lleva == MIRAR && fl == 15) + hablar(TEXT117, "117.als"); + else if (objeto_que_lleva == HABLAR && fl == 15) + hablar(TEXT118, "118.als"); + else if (objeto_que_lleva == ABRIR && fl == 15) + hablar(TEXT119, "119.als"); + else if (objeto_que_lleva == MIRAR && fl == 16) + hablar(TEXT491, "491.als"); + else if (objeto_que_lleva == MIRAR && fl == 17) + hablar(TEXT478, "478.als"); + else if (objeto_que_lleva == MIRAR && fl == 18) + hablar(TEXT493, "493.als"); + else if (objeto_que_lleva == MIRAR && fl == 19) { + hablar(TEXT494, "494.als"); + hablar(TEXT495, "495.als"); + } else if (objeto_que_lleva == MIRAR && fl == 20) + hablar(TEXT162, "162.als"); + else if (objeto_que_lleva == MIRAR && fl == 21) + hablar(TEXT496, "496.als"); + else if (objeto_que_lleva == MIRAR && fl == 22) + hablar(TEXT161, "161.als"); + else + hay_respuesta = 0; + } else if (num_ejec == 5) { + if (objeto_que_lleva == MIRAR && fl == 50) + hablar("Cuanto mas me miro, mas me gusto.", "54.als"); + else if (objeto_que_lleva == ABRIR && fl == 50) + hablar(".y luego como me cierro?.", "19.als"); + else if (objeto_que_lleva == CERRAR && fl == 50) + hablar("Tendre que abrirme primero .no?.", "19.als"); + else if (objeto_que_lleva == MOVER && fl == 50) + hablar("Estoy bien donde estoy.", "19.als"); + else if (objeto_que_lleva == COGER && fl == 50) + hablar("Ya me tengo.", "11.als"); + else if (objeto_que_lleva == HABLAR && fl == 50) + hablar("hola yo.", "16.als" ); + else if (objeto_que_lleva == 20 && fl == 50) + hablar(TEXT487, "487.als" ); + else if (!strcmp(num_room, "49.alg")) + pantalla_49(fl); + else if (!strcmp(num_room, "53.alg")) + pantalla_53(fl); + else if (!strcmp(num_room, "54.alg")) + pantalla_54(fl); + else if (!strcmp(num_room, "55.alg")) + pantalla_55(fl); + else if (!strcmp(num_room, "56.alg")) + pantalla_56(fl); + else + hay_respuesta = 0; + return; + } else if (num_ejec == 6) { + if (objeto_que_lleva == MIRAR && fl == 28) + hablar(TEXT328, "328.als"); + else if (objeto_que_lleva == MIRAR && fl == 9) { + hablar(TEXT482, "482.als"); + hablar(TEXT483, "483.als"); + } else if (objeto_que_lleva == MIRAR && fl == 20) + hablar(TEXT123, "123.als"); + else if (objeto_que_lleva == MIRAR && fl == 21) + hablar(TEXT441, "441.als"); + else + hay_respuesta = 0; + } } else { if (objeto_que_lleva == MIRAR && fl == 50) - hablar(TEXT308, "308.als"); + if (num_ejec == 3) + hablar(TEXT308, "308.als"); + else if (num_ejec == 6) + if (flags[0] == 1) + hablar(TEXT308, "308.als"); + else if (flags[0] == 0) + hablar(TEXT250, "250.als"); + else + hablar(TEXT309, "309.als"); else if (objeto_que_lleva == ABRIR && fl == 50) hablar(TEXT310, "310.als" ); else if (objeto_que_lleva == CERRAR && fl == 50) @@ -4022,11 +4485,23 @@ void DrasculaEngine::banderas(int fl) { else if (objeto_que_lleva == COGER && fl == 50) hablar(TEXT313, "313.als" ); else if (objeto_que_lleva == HABLAR && fl == 50) - hablar(TEXT314,"314.als" ); - else if (!strcmp(num_room, "62.alg")) + hablar(TEXT314, "314.als" ); + else if (!strcmp(num_room, "102.alg")) + pantalla_pendulo(fl); + else if (!strcmp(num_room, "58.alg")) + pantalla_58(fl); + else if (!strcmp(num_room, "59.alg")) + pantalla_59(fl); + else if (!strcmp(num_room, "60.alg")) + pantalla_60(fl); + else if (!strcmp(num_room, "61.alg")) + pantalla_61(fl); + else if (!strcmp(num_room, "62.alg")) pantalla_62(fl); else if (!strcmp(num_room, "63.alg")) pantalla_63(fl); + else if (!strcmp(num_room, "13.alg")) + pantalla_13(fl); else hay_respuesta = 0; } @@ -4196,29 +4671,52 @@ int DrasculaEngine::PlayFrameSSN() { mSesion += 1; } switch (CHUNK) { - case SET_PALET: - if (!UsingMem) - _Sesion->read(dacSSN, 768); - else { - memcpy(dacSSN, mSesion, 768); - mSesion += 768; - } - set_dacSSN(dacSSN); - break; - case EMPTY_FRAME: - WaitFrameSSN(); - break; - case INIT_FRAME: + case SET_PALET: + if (!UsingMem) + _Sesion->read(dacSSN, 768); + else { + memcpy(dacSSN, mSesion, 768); + mSesion += 768; + } + set_dacSSN(dacSSN); + break; + case EMPTY_FRAME: + WaitFrameSSN(); + break; + case INIT_FRAME: + if (!UsingMem) { + _Sesion->read(&CMP, 1); + _Sesion->read(&Lengt, 4); + } else { + memcpy(&CMP, mSesion, 1); + mSesion += 1; + memcpy(&Lengt, mSesion, 4); + mSesion += 4; + } + if (CMP == CMP_RLE) { if (!UsingMem) { - _Sesion->read(&CMP, 1); - _Sesion->read(&Lengt, 4); + BufferSSN = (byte *)malloc(Lengt); + _Sesion->read(BufferSSN, Lengt); } else { - memcpy(&CMP, mSesion, 1); - mSesion += 1; - memcpy(&Lengt, mSesion, 4); - mSesion += 4; + BufferSSN = (byte *)malloc(Lengt); + memcpy(BufferSSN, mSesion, Lengt); + mSesion += Lengt; } - if (CMP == CMP_RLE) { + Des_RLE(BufferSSN, MiVideoSSN); + free(BufferSSN); + if (FrameSSN) { + WaitFrameSSN(); + MixVideo(VGA, MiVideoSSN); + _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + } else { + WaitFrameSSN(); + memcpy(VGA, MiVideoSSN, 64000); + _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + } + _system->updateScreen(); + FrameSSN++; + } else { + if (CMP == CMP_OFF) { if (!UsingMem) { BufferSSN = (byte *)malloc(Lengt); _Sesion->read(BufferSSN, Lengt); @@ -4227,7 +4725,7 @@ int DrasculaEngine::PlayFrameSSN() { memcpy(BufferSSN, mSesion, Lengt); mSesion += Lengt; } - Des_RLE(BufferSSN, MiVideoSSN); + Des_OFF(BufferSSN, MiVideoSSN, Lengt); free(BufferSSN); if (FrameSSN) { WaitFrameSSN(); @@ -4240,39 +4738,17 @@ int DrasculaEngine::PlayFrameSSN() { } _system->updateScreen(); FrameSSN++; - } else { - if (CMP == CMP_OFF) { - if (!UsingMem) { - BufferSSN = (byte *)malloc(Lengt); - _Sesion->read(BufferSSN, Lengt); - } else { - BufferSSN = (byte *)malloc(Lengt); - memcpy(BufferSSN, mSesion, Lengt); - mSesion += Lengt; - } - Des_OFF(BufferSSN, MiVideoSSN, Lengt); - free(BufferSSN); - if (FrameSSN) { - WaitFrameSSN(); - MixVideo(VGA, MiVideoSSN); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); - } else { - WaitFrameSSN(); - memcpy(VGA, MiVideoSSN, 64000); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); - } - _system->updateScreen(); - FrameSSN++; - } } - break; - case END_ANIM: - Exit = 1; - break; - default: - Exit = 1; - break; } + break; + case END_ANIM: + Exit = 1; + break; + default: + Exit = 1; + break; + } + return (!Exit); } @@ -4348,7 +4824,8 @@ void DrasculaEngine::MixVideo(byte *OldScreen, byte *NewScreen) { } void DrasculaEngine::WaitFrameSSN() { - while (clock() < LastFrame + GlobalSpeed) {}; + while ((int)clock() < LastFrame + GlobalSpeed) + ; LastFrame = LastFrame + GlobalSpeed; } @@ -4387,6 +4864,11 @@ void DrasculaEngine::WaitForNext(int FPS) { } float DrasculaEngine::vez() { + // FIXME: This function is really silly. It first divides an int by an int (resulting + // in an *int*, loosing precision), *then* converts the result to a float and returns + // that -- only so that many calling functions have to convert it back to an int :-). + // So: Either divide by 20.0 / cast to float *first*, if you absolutly need the precision. + // Or: Just change this to return int! return _system->getMillis() / 20; // originaly was 1 } @@ -4405,8 +4887,8 @@ void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int a pixel_x = xx1; pixel_y = yy1; - for (n = 0;n < nuevo_alto; n++){ - for (m = 0; m < nuevo_ancho; m++){ + for (n = 0; n < nuevo_alto; n++) { + for (m = 0; m < nuevo_ancho; m++) { pos_pixel[0] = (int)pixel_x; pos_pixel[1] = (int)pixel_y; pos_pixel[2] = xx2 + m; @@ -4430,10 +4912,10 @@ char DrasculaEngine::codifica(char car) { void DrasculaEngine::cuadrante_1() { float distancia_x = 0, distancia_y; - if (num_ejec == 1) - distancia_x = hare_x + ancho_hare / 2 - sitio_x; - else if (num_ejec == 2) + if (num_ejec == 2) distancia_x = hare_x + ancho_hare - sitio_x; + else + distancia_x = hare_x + ancho_hare / 2 - sitio_x; distancia_y = (hare_y + alto_hare) - sitio_y; @@ -4451,10 +4933,10 @@ void DrasculaEngine::cuadrante_1() { void DrasculaEngine::cuadrante_2() { float distancia_x = 0, distancia_y; - if (num_ejec == 1) - distancia_x = abs(hare_x + ancho_hare / 2 - sitio_x); - else if (num_ejec == 2) + if (num_ejec == 2) distancia_x = abs(hare_x + ancho_hare - sitio_x); + else + distancia_x = abs(hare_x + ancho_hare / 2 - sitio_x); distancia_y = (hare_y + alto_hare) - sitio_y; @@ -4472,10 +4954,10 @@ void DrasculaEngine::cuadrante_2() { void DrasculaEngine::cuadrante_3() { float distancia_x = 0, distancia_y; - if (num_ejec == 1) - distancia_x = hare_x + ancho_hare / 2 - sitio_x; - else if (num_ejec == 2) + if (num_ejec == 2) distancia_x = hare_x + ancho_hare - sitio_x; + else + distancia_x = hare_x + ancho_hare / 2 - sitio_x; distancia_y = sitio_y - (hare_y + alto_hare); @@ -4493,10 +4975,10 @@ void DrasculaEngine::cuadrante_3() { void DrasculaEngine::cuadrante_4() { float distancia_x = 0, distancia_y; - if (num_ejec == 1) - distancia_x = abs(hare_x + ancho_hare / 2 - sitio_x); - else if (num_ejec == 2) + if (num_ejec == 2) distancia_x = abs(hare_x + ancho_hare - sitio_x); + else + distancia_x = abs(hare_x + ancho_hare / 2 - sitio_x); distancia_y = sitio_y - (hare_y + alto_hare); @@ -4527,7 +5009,7 @@ void DrasculaEngine::refresca_63() { } void DrasculaEngine::refresca_62_antes() { - int velas_y[] = { 158, 172, 186}; + int velas_y[] = { 158, 172, 186 }; int cirio_x[] = { 14, 19, 24 }; int pianista_x[] = {1, 91, 61, 31, 91, 31, 1, 61, 31 }; int borracho_x[] = {1, 42, 83, 124, 165, 206, 247, 1 }; @@ -4642,7 +5124,7 @@ void DrasculaEngine::aumenta_num_frame() { } } - if (num_ejec == 1) { + if (num_ejec != 2) { diferencia_y = alto_hare - (int)nuevo_alto; diferencia_x = ancho_hare - (int)nuevo_ancho; hare_y = hare_y + diferencia_y; @@ -4667,7 +5149,7 @@ int DrasculaEngine::sobre_que_objeto() { void DrasculaEngine::comprueba_banderas_menu() { int h, n; - for (n = 0; n < 43; n++){ + for (n = 0; n < 43; n++) { if (sobre_que_objeto() == n) { h = objetos_que_tengo[n]; if (h != 0) @@ -4677,6 +5159,77 @@ void DrasculaEngine::comprueba_banderas_menu() { } void DrasculaEngine::pantalla_0() { + if (num_ejec == 6) { + if (objeto_que_lleva == MIRAR) { + hablar(mirar_t[c_mirar], mirar_v[c_mirar]); + c_mirar++; + if (c_mirar == 3) + c_mirar = 0; + } else if (objeto_que_lleva == MOVER) + hablar(TEXT19, "19.als"); + else if (objeto_que_lleva == COGER) { + hablar(poder_t[c_poder], poder_v[c_poder]); + c_poder++; + if (c_poder == 6) + c_poder = 0; + } else if (objeto_que_lleva == ABRIR) + hablar(TEXT9, "9.als"); + else if (objeto_que_lleva == CERRAR) + hablar(TEXT9, "9.als"); + else if (objeto_que_lleva == HABLAR) + hablar(TEXT16, "16.als"); + else { + hablar(poder_t[c_poder], poder_v[c_poder]); + c_poder++; + if (c_poder == 6) + c_poder = 0; + } + } + if (num_ejec == 5) { + if (objeto_que_lleva == MIRAR) { + hablar(mirar_t[c_mirar], mirar_v[c_mirar]); + c_mirar++; + if (c_mirar == 3) + c_mirar = 0; + } else if (objeto_que_lleva == MOVER) + hablar(TEXT19, "19.als"); + else if (objeto_que_lleva == COGER) { + hablar(poder_t[c_poder], poder_v[c_poder]); + c_poder++; + if (c_poder == 6) + c_poder = 0; + } else if (objeto_que_lleva == ABRIR) + hablar(TEXT9, "9.als"); + else if (objeto_que_lleva == CERRAR) + hablar(TEXT9, "9.als"); + else if (objeto_que_lleva == HABLAR) + hablar(TEXT16, "16.als"); + else { + hablar(poder_t[c_poder], poder_v[c_poder]); + c_poder++; + if (c_poder == 6) + c_poder = 0; + } + return; + } + if (num_ejec == 3) { + if (objeto_que_lleva == MIRAR) + hablar(TEXT316, "316.als"); + else if (objeto_que_lleva == MOVER) + hablar(TEXT317, "317.als"); + else if (objeto_que_lleva == COGER) + hablar(TEXT318, "318.als"); + else if (objeto_que_lleva == ABRIR) + hablar(TEXT319, "319.als"); + else if (objeto_que_lleva == CERRAR) + hablar(TEXT319, "319.als"); + else if (objeto_que_lleva == HABLAR) + hablar(TEXT320, "320.als"); + else + hablar(TEXT318, "318.als"); + return; + } + if (objeto_que_lleva == MIRAR) { if (num_ejec == 1) hablar(TEXT54, "54.als"); @@ -4780,6 +5333,9 @@ void DrasculaEngine::conversa(const char *nom_fich) { strcpy(para_codificar, nom_fich); canal_p(para_codificar); + if (num_ejec == 5) + sin_verbo(); + ald = new Common::File; ald->open(nom_fich); if (!ald->isOpen()) { @@ -4818,6 +5374,18 @@ void DrasculaEngine::conversa(const char *nom_fich) { respuesta3 = 31; } + if (num_ejec == 6 && !strcmp(nom_fich, "op_5.cal") && flags[7] == 1) { + strcpy(frase3, TEXT273); + strcpy(suena3, "273.als"); + respuesta3 = 14; + } + + if (num_ejec == 6 && !strcmp(nom_fich, "op_5.cal") && flags[10] == 1) { + strcpy(frase3, ".cuanto.queda.para.que.acabe.el.partido?"); + strcpy(suena3, "274.als"); + respuesta3 = 15; + } + longitud = strlen(frase1); for (h = 0; h < longitud; h++) if (frase1[h] == (char)0xa7) @@ -4840,7 +5408,7 @@ void DrasculaEngine::conversa(const char *nom_fich) { lee_dibujos("car.alg"); descomprime_dibujo(dir_hare_fondo,1); -/* TODO +/* TODO this is limit for mouse, but we can't implement this ent.w.ax = 8; ent.w.cx = 1; ent.w.dx = 31; @@ -4858,10 +5426,19 @@ bucle_opc: else if (num_ejec == 2) if (music_status() == 0 && flags[11] == 0 && musica_room != 0) playmusic(musica_room); + else if (num_ejec == 3) + if (music_status() == 0) + playmusic(musica_room); + else if (num_ejec == 4) + if (music_status() == 0) + playmusic(musica_room); + else if (num_ejec == 5) + if (music_status() == 0) + playmusic(musica_room); MirarRaton(); - if ( y_raton > 0 && y_raton < 9) { + if (y_raton > 0 && y_raton < 9) { if (usado1 == 1 && _color != BLANCO) color_abc(BLANCO); else if (usado1 == 0 && _color != VERDE_CLARO) @@ -4898,15 +5475,24 @@ bucle_opc: if ((boton_izq == 1) && (juego1 == 2)) { usado1 = 1; hablar(frase1, suena1); - responde(respuesta1); + if (num_ejec == 3) + grr(); + else + responde(respuesta1); } else if ((boton_izq == 1) && (juego2 == 2)) { usado2 = 1; hablar(frase2, suena2); - responde(respuesta2); + if (num_ejec == 3) + grr(); + else + responde(respuesta2); } else if ((boton_izq == 1) && (juego3 == 2)) { usado3 = 1; hablar(frase3, suena3); - responde(respuesta3); + if (num_ejec == 3) + grr(); + else + responde(respuesta3); } else if ((boton_izq == 1) && (juego4 == 2)) { hablar(frase4, suena4); rompo_y_salgo = 1; @@ -4938,7 +5524,8 @@ bucle_opc: else if (num_ejec == 2) lee_dibujos(fondo_y_menu); descomprime_dibujo(dir_hare_fondo, 1); - sin_verbo(); + if (num_ejec < 5) + sin_verbo(); } void DrasculaEngine::animacion_3_1() { @@ -5196,7 +5783,51 @@ void DrasculaEngine::print_abc_opc(const char *dicho, int x_pantalla, int y_pant } void DrasculaEngine::responde(int funcion) { - if (funcion == 10) + if (num_ejec == 5) { + if (funcion == 2) + animacion_2_5(); + else if (funcion == 3) + animacion_3_5(); + else if (funcion == 6) + animacion_6_5(); + else if (funcion == 7) + animacion_7_5(); + else if (funcion == 8) + animacion_8_5(); + else if (funcion == 15) + animacion_15_5(); + else if (funcion == 16) + animacion_16_5(); + else if (funcion == 17) + animacion_17_5(); + return; + } + if (num_ejec == 6) { + if (funcion == 2) + animacion_2_6(); + else if (funcion == 3) + animacion_3_6(); + else if (funcion == 4) + animacion_4_6(); + else if (funcion == 11) + animacion_11_6(); + else if (funcion == 12) + animacion_12_6(); + else if (funcion == 13) + animacion_13_6(); + else if (funcion == 14) + animacion_14_6(); + else if (funcion == 15) + animacion_15_6(); + return; + } + if (funcion == 2) + animacion_2_4(); + else if (funcion == 3) + animacion_3_4(); + else if (funcion == 4) + animacion_4_4(); + else if (funcion == 10) habla_borracho(TEXTB1, "B1.als"); else if (funcion == 11) habla_borracho(TEXTB2, "B2.als"); @@ -5235,7 +5866,7 @@ void DrasculaEngine::responde(int funcion) { void DrasculaEngine::habla_pianista(const char *dicho, const char *filename) { int tiempou; long tiempol; - int x_habla[4] = { 97, 145, 193, 241}; + int x_habla[4] = { 97, 145, 193, 241 }; int cara; int longitud; longitud = strlen(dicho); @@ -5380,8 +6011,9 @@ bucless: lee_dibujos("96.alg"); descomprime_dibujo(dir_hare_frente, 1); - if (music_status() == 0 && flags[11] == 0) - playmusic(musica_room); + if (num_ejec <= 3) + if (music_status() == 0 && flags[11] == 0) + playmusic(musica_room); } void DrasculaEngine::suma_objeto(int osj) { @@ -5395,7 +6027,7 @@ void DrasculaEngine::suma_objeto(int osj) { if (puesto == 0) { for (h = 1; h < 43; h++) { if (objetos_que_tengo[h] == 0) { - objetos_que_tengo[h]=osj; + objetos_que_tengo[h] = osj; puesto = 1; break; } @@ -5473,6 +6105,29 @@ void DrasculaEngine::actualiza_datos() { visible[4] = 0; else if (!strcmp(num_room, "18.alg") && flags[28] == 1) visible[2] = 0; + if (!strcmp(num_room,"49.alg") && flags[6] == 1) + visible[2] = 0; + if (!strcmp(num_room,"49.alg") && flags[6] == 0) + visible[1] = 0; + if (!strcmp(num_room,"49.alg") && flags[6] == 1) + visible[1] = 1; + if (!strcmp(num_room,"45.alg") && flags[6] == 1) + visible[3] = 1; + if (!strcmp(num_room,"53.alg") && flags[2] == 1) + visible[3] = 0; + if (!strcmp(num_room,"54.alg") && flags[13] == 1) + visible[3] = 0; + if (!strcmp(num_room,"55.alg") && flags[8] == 1) + visible[1] = 0; + if ((!strcmp(num_room, "58.alg")) && flags[8] == 0) + espuerta[1] = 0; + if ((!strcmp(num_room, "58.alg")) && flags[8] == 1) + espuerta[1] = 1; + if (!strcmp(num_room, "59.alg")) + espuerta[1] = 0; + if (!strcmp(num_room, "60.alg")) { + sentido_dr = 0; x_dr = 155; y_dr = 69; + } } void DrasculaEngine::animacion_1_2() { @@ -5577,7 +6232,7 @@ void DrasculaEngine::animacion_4_2() { flags[9] = 1; pausa(12); - hablar(TEXTD56, "d56.als" ); + hablar(TEXTD56, "d56.als"); pausa(8); borra_pantalla(); @@ -5680,12 +6335,12 @@ void DrasculaEngine::animacion_14() { descomprime_dibujo(dir_hare_fondo, 1); lee_dibujos("an14_1.alg"); - pos_cabina[0]=150; - pos_cabina[1]=6; - pos_cabina[2]=69; - pos_cabina[3]=-160; - pos_cabina[4]=158; - pos_cabina[5]=161; + pos_cabina[0] = 150; + pos_cabina[1] = 6; + pos_cabina[2] = 69; + pos_cabina[3] = -160; + pos_cabina[4] = 158; + pos_cabina[5] = 161; for (n = -160; n <= 0; n = n + 5 + l) { DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); @@ -5759,7 +6414,7 @@ void DrasculaEngine::animacion_16() { descomprime_dibujo(dir_dibujo1, MEDIA); DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); centra_texto(HIS2, 180, 180); - VUELCA_PANTALLA(0,0,0,0, 320,200, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); key = getscan(); if (key != 0) goto asco; @@ -5809,10 +6464,10 @@ void DrasculaEngine::animacion_16() { if (key != 0) goto asco; - for (l = 1; l < 200; l++){ + for (l = 1; l < 200; l++) { DIBUJA_FONDO(0, 0, 0, l, 320, 200 - l, dir_dibujo3, dir_zona_pantalla); DIBUJA_FONDO(0, 200 - l, 0, 0, 320, l, dir_dibujo1, dir_zona_pantalla); - VUELCA_PANTALLA(0,0,0,0, 320,200, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); key = getscan(); if (key != 0) goto asco; @@ -5939,8 +6594,10 @@ void DrasculaEngine::animacion_23() { void DrasculaEngine::animacion_23_anexo() { int n, p_x = hare_x + 2, p_y = hare_y - 3; - int x[] = {1,38,75,112,75,112,75,112,149,112,149,112,149,186,223,260,1,38,75,112,149,112,149,112,149,112,149,186,223,260,260,260,260,223}; - int y[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1}; + int x[] = {1, 38, 75, 112, 75, 112, 75, 112, 149, 112, 149, 112, 149, 186, 223, 260, + 1, 38, 75, 112, 149, 112, 149, 112, 149, 112, 149, 186, 223, 260, 260, 260, 260, 223}; + int y[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 1, 1, 1, 1}; lee_dibujos("an23.alg"); descomprime_dibujo(dir_hare_fondo, 1); @@ -5959,8 +6616,8 @@ void DrasculaEngine::animacion_23_anexo() { void DrasculaEngine::animacion_23_anexo2() { int n, p_x = hare_x + 4, p_y = hare_y; - int x[] = {1,35,69,103,137,171,205,239,273,1,35,69,103,137}; - int y[] = {1,1,1,1,1,1,1,1,1,73,73,73,73,73}; + int x[] = {1, 35, 69, 103, 137, 171, 205, 239, 273, 1, 35, 69, 103, 137}; + int y[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 73, 73, 73, 73, 73}; pausa(50); @@ -6010,7 +6667,7 @@ void DrasculaEngine::animacion_25() { DIBUJA_BLOQUE_CUT(pos_cabina, dir_hare_fondo, dir_zona_pantalla); actualiza_refresco(); - VUELCA_PANTALLA(0,0, 0,0, 320,200, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); } fin_sound(); @@ -6129,7 +6786,7 @@ void DrasculaEngine::animacion_31(){ suma_objeto(20); } -void DrasculaEngine::animacion_35() { +void DrasculaEngine::animacion_35_2() { int n, x = 0; lleva_al_hare(96, 165); @@ -6150,8 +6807,8 @@ void DrasculaEngine::animacion_35() { x = x + 46; pausa(3); } - x = 0; + x = 0; for (n = 0; n < 6; n++) { x++; DIBUJA_FONDO(x, 82, 70, 90, 46, 80, dir_hare_fondo, dir_zona_pantalla); @@ -6161,7 +6818,6 @@ void DrasculaEngine::animacion_35() { } x = 0; - for (n = 0; n < 6; n++) { x++; DIBUJA_FONDO(x, 1, 70, 90, 46, 80, dir_hare_frente, dir_zona_pantalla); @@ -6171,8 +6827,8 @@ void DrasculaEngine::animacion_35() { pausa(3); } - x = 0; + x = 0; for (n = 0; n < 2; n++) { x++; DIBUJA_FONDO(x, 82, 70, 90, 46, 80, dir_hare_frente, dir_zona_pantalla); @@ -6196,14 +6852,14 @@ void DrasculaEngine::animacion_35() { FundeAlNegro(2); // TODO - salir_al_dos(3); + error("hit part 3"); } void DrasculaEngine::habla_vb(const char *dicho, const char *filename) { int tiempou; long tiempol; - int x_habla[6] = {1,27,53,79,105,131}; + int x_habla[6] = {1, 27, 53, 79, 105, 131}; int cara; int longitud; @@ -6328,7 +6984,7 @@ bucless: void DrasculaEngine::habla_ciego(const char *dicho, const char *filename, const char *sincronia) { byte *num_cara; - int p; + int p = 0; int pos_ciego[6]; int cara = 0; @@ -6339,13 +6995,6 @@ void DrasculaEngine::habla_ciego(const char *dicho, const char *filename, const color_abc(VON_BRAUN); - // FIXME: We can't do this to a read-only string! -#if 0 - for (p = 0; sincronia[p]; p++) - sincronia[p] = toupper(sincronia[p]); -#endif - - p = 0; DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); @@ -6369,21 +7018,22 @@ void DrasculaEngine::habla_ciego(const char *dicho, const char *filename, const bucless: DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); pos_ciego[5] = 149; - if (sincronia[p] == '0') + char c = toupper(sincronia[p]); + if (c == '0') cara = 0; - if (sincronia[p] == '1') + if (c == '1') cara = 1; - if (sincronia[p] == '2') + if (c == '2') cara = 2; - if (sincronia[p] == '3') + if (c == '3') cara = 3; - if (sincronia[p] == '4') + if (c == '4') cara = 4; - if (sincronia[p] == '5') + if (c == '5') cara = 5; - if (sincronia[p] == '6') + if (c == '6') cara = 6; - if (sincronia[p] == '7') + if (c == '7') cara = 7; if (cara == 0 || cara == 2 || cara == 4 || cara == 6) @@ -6468,7 +7118,7 @@ bucless: VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); int key = getscan(); - if (key!=0) + if (key != 0) ctvd_stop(); if (hay_sb == 1) { if (LookForFree() != 0) @@ -6560,22 +7210,33 @@ void DrasculaEngine::lleva_vb(int punto_x) { void DrasculaEngine::hipo_sin_nadie(int contador){ int y = 0, sentido = 0; - contador = contador; + if (num_ejec == 3) + y = -1; comienza: contador--; DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); - VUELCA_PANTALLA(0, 1, 0, y, 320, 198, dir_zona_pantalla); + if (num_ejec <= 2) + VUELCA_PANTALLA(0, 1, 0, y, 320, 198, dir_zona_pantalla); + else + VUELCA_PANTALLA(0, 0, 0, y, 320, 200, dir_zona_pantalla); if (sentido == 0) y++; else y--; - if (y == 2) - sentido = 1; - if (y == 0) - sentido = 0; + if (num_ejec <= 2) { + if (y == 2) + sentido = 1; + if (y == 0) + sentido = 0; + } else if (num_ejec == 3) { + if (y == 1) + sentido = 1; + if (y == -1) + sentido = 0; + } if (contador > 0) goto comienza; @@ -6585,6 +7246,12 @@ comienza: void DrasculaEngine::abre_puerta(int nflag, int n_puerta) { if (flags[nflag] == 0) { + if (num_ejec == 5 || num_ejec == 6) { + comienza_sound("s3.als"); + flags[nflag] = 1; + } + if (num_ejec == 1 && nflag == 7) + return; comienza_sound("s3.als"); flags[nflag] = 1; if (n_puerta != NO_PUERTA) @@ -6592,7 +7259,8 @@ void DrasculaEngine::abre_puerta(int nflag, int n_puerta) { refresca_pantalla(); VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); fin_sound(); - sin_verbo(); + if (num_ejec != 5) + sin_verbo(); } } @@ -6601,11 +7269,11 @@ void DrasculaEngine::mapa() { for (l = 0; l < objs_room; l++) { if (x_raton > x1[l] && y_raton > y1[l] - && x_raton < x2[l] && y_raton < y2[l] - && visible[l] == 1) { - strcpy(texto_nombre, nombre_obj[l]); - hay_nombre = 1; - veo = 1; + && x_raton < x2[l] && y_raton < y2[l] + && visible[l] == 1) { + strcpy(texto_nombre, nombre_obj[l]); + hay_nombre = 1; + veo = 1; } } @@ -6633,21 +7301,21 @@ void DrasculaEngine::refresca_1_antes() { void DrasculaEngine::refresca_2(){ int pos_murci[6]; int diferencia; - int murci_x[] = {0,38,76,114,152,190,228,266, - 0,38,76,114,152,190,228,266, - 0,38,76,114,152,190, - 0,48,96,144,192,240, - 30,88,146,204,262, - 88,146,204,262, - 88,146,204,262}; - - int murci_y[] = {179,179,179,179,179,179,179,179, - 158,158,158,158,158,158,158,158, - 137,137,137,137,137,137, - 115,115,115,115,115,115, - 78,78,78,78,78, - 41,41,41,41, - 4,4,4,4}; + int murci_x[] = {0, 38, 76, 114, 152, 190, 228, 266, + 0, 38, 76, 114, 152, 190, 228, 266, + 0, 38, 76, 114, 152, 190, + 0, 48, 96, 144, 192, 240, + 30, 88, 146, 204, 262, + 88, 146, 204, 262, + 88, 146, 204, 262}; + + int murci_y[] = {179, 179, 179, 179, 179, 179, 179, 179, + 158, 158, 158, 158, 158, 158, 158, 158, + 137, 137, 137, 137, 137, 137, + 115, 115, 115, 115, 115, 115, + 78, 78, 78, 78, 78, + 41, 41, 41, 41, + 4, 4, 4, 4}; if (frame_murcielago == 41) frame_murcielago = 0; @@ -6670,10 +7338,10 @@ void DrasculaEngine::refresca_2(){ pos_murci[3] = 19; DIBUJA_BLOQUE_CUT(pos_murci, dir_dibujo3, dir_zona_pantalla); - diferencia = vez() - conta_ciego_vez; + diferencia = (int)vez() - conta_ciego_vez; if (diferencia >= 6) { frame_murcielago++; - conta_ciego_vez = vez(); + conta_ciego_vez = (int)vez(); } DIBUJA_BLOQUE(29, 37, 58, 114, 57, 39, dir_dibujo3, dir_zona_pantalla); @@ -6696,7 +7364,7 @@ void DrasculaEngine::refresca_4() { if (hare_x > 190) cambio_de_color = 1; else - cambio_de_color=0; + cambio_de_color = 0; if (cambio_col_antes != cambio_de_color && cambio_de_color == 1) hare_oscuro(); @@ -6728,13 +7396,13 @@ void DrasculaEngine::refresca_5_antes(){ } void DrasculaEngine::refresca_6_antes() { - int cambio_col_antes=cambio_de_color; + int cambio_col_antes = cambio_de_color; if ((hare_x > 149 && hare_y + alto_hare > 160 && hare_x < 220 && hare_y + alto_hare < 188) || (hare_x > 75 && hare_y + alto_hare > 183 && hare_x < 145)) cambio_de_color = 0; else - cambio_de_color=1; + cambio_de_color = 1; if (cambio_col_antes != cambio_de_color && cambio_de_color == 1) hare_oscuro(); @@ -6755,21 +7423,21 @@ void DrasculaEngine::refresca_7_antes() { } void DrasculaEngine::refresca_9_antes() { - int ciego_x[] = {26,68,110,152,194,236,278,26,68}; - int ciego_y[] = {51,51,51,51,51,51,51,127,127}; + int ciego_x[] = {26, 68, 110, 152, 194, 236, 278, 26, 68}; + int ciego_y[] = {51, 51, 51, 51, 51, 51, 51, 127, 127}; int diferencia; DIBUJA_BLOQUE(ciego_x[frame_ciego], ciego_y[frame_ciego], 122, 57, 41, 72, dir_dibujo3, dir_zona_pantalla); if (flags[9] == 0) { - diferencia = vez() - conta_ciego_vez; + diferencia = (int)vez() - conta_ciego_vez; if (diferencia >= 11) { frame_ciego++; - conta_ciego_vez = vez(); + conta_ciego_vez = (int)vez(); } if (frame_ciego == 9) frame_ciego = 0; } else - frame_ciego=3; + frame_ciego = 3; } void DrasculaEngine::refresca_12_antes() { @@ -6778,10 +7446,10 @@ void DrasculaEngine::refresca_12_antes() { } void DrasculaEngine::refresca_14_antes() { - int velas_y[] = {158,172,186}; - int cirio_x[] = {14,19,24}; - int pianista_x[] = {1,91,61,31,91,31,1,61,31}; - int borracho_x[] = {1,42,83,124,165,206,247,1}; + int velas_y[] = {158, 172, 186}; + int cirio_x[] = {14, 19, 24}; + int pianista_x[] = {1, 91, 61, 31, 91, 31, 1, 61, 31}; + int borracho_x[] = {1, 42, 83, 124, 165, 206, 247, 1}; int diferencia; DIBUJA_FONDO(123, velas_y[frame_velas], 142, 14, 39, 13, dir_dibujo3, dir_zona_pantalla); @@ -6800,7 +7468,7 @@ void DrasculaEngine::refresca_14_antes() { if (flags[12] == 1) DIBUJA_FONDO(borracho_x[frame_borracho], 82, 170, 50, 40, 53, dir_dibujo3, dir_zona_pantalla); - diferencia = vez() - conta_ciego_vez; + diferencia = (int)vez() - conta_ciego_vez; if (diferencia > 6) { if (flags[12] == 1) { frame_borracho++; @@ -6818,7 +7486,7 @@ void DrasculaEngine::refresca_14_antes() { if (frame_piano == 9) frame_piano = 0; parpadeo = _rnd->getRandomNumber(10); - conta_ciego_vez=vez(); + conta_ciego_vez = (int)vez(); } } @@ -6836,8 +7504,8 @@ void DrasculaEngine::refresca_17_antes() { void DrasculaEngine::refresca_18_antes() { int diferencia; - int ronquido_x[] = {95,136,95,136,95,95,95,95,136,95,95,95,95,95,95,95}; - int ronquido_y[] = {18,18,56,56,94,94,94,94,94,18,18,18,18,18,18,18}; + int ronquido_x[] = {95, 136, 95, 136, 95, 95, 95, 95, 136, 95, 95, 95, 95, 95, 95, 95}; + int ronquido_y[] = {18, 18, 56, 56, 94, 94, 94, 94, 94, 18, 18, 18, 18, 18, 18, 18}; if (flags[21] == 0) { DIBUJA_FONDO(1, 69, 120, 58, 56, 61, dir_dibujo3, dir_zona_pantalla); @@ -6845,15 +7513,2134 @@ void DrasculaEngine::refresca_18_antes() { } else pon_vb(); - diferencia = vez() - conta_ciego_vez; + diferencia = (int)vez() - conta_ciego_vez; if (diferencia > 9) { frame_ronquido++; if (frame_ronquido == 16) frame_ronquido = 0; - conta_ciego_vez = vez(); + conta_ciego_vez = (int)vez(); + } +} + +void DrasculaEngine::grr() { + int longitud; + longitud = 30; + + buffer_teclado(); + + color_abc(VERDE_OSCURO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open("s10.als"); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(4); + ctvd_speaker(1); + ctvd_output(sku); + } + + refresca_pantalla(); + DIBUJA_FONDO(253, 110, 150, 65, 20, 30, dir_dibujo3, dir_zona_pantalla); + + if (con_voces == 0) + centra_texto(".groaaarrrrgghhh!", 153, 65); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + +bucless: + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; } + + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::pantalla_13(int fl) { + if (objeto_que_lleva == MIRAR && fl == 51) { + hablar(TEXT411, "411.als"); + sentido_hare = 3; + hablar(TEXT412, "412.als"); + strcpy(nombre_obj[1], "yoda"); + } else if (objeto_que_lleva == HABLAR && fl == 51) + conversa("op_7.cal"); + else if (objeto_que_lleva == 19 && fl == 51) + animacion_1_3(); + else if (objeto_que_lleva == 9 && fl == 51) + animacion_2_3(); + else + hay_respuesta = 0; +} + +void DrasculaEngine::refresca_13() { + if (hare_x > 55 && flags[3] == 0) + animacion_6(); + if (flags[1] == 0) + DIBUJA_BLOQUE(185, 110, 121, 65, 67, 88, dir_dibujo3, dir_zona_pantalla); + if (flags[2] == 0) + DIBUJA_BLOQUE(185, 21, 121, 63, 67, 88, dir_dibujo3, dir_zona_pantalla); + DIBUJA_BLOQUE(3, 127, 99, 102, 181, 71, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_20() { + DIBUJA_BLOQUE(1, 137, 106, 121, 213, 61, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::animacion_1_3() { + hablar(TEXT413, "413.als"); + grr(); + pausa(50); + hablar(TEXT414, "414.als"); +} + +void DrasculaEngine::animacion_2_3() { + flags[0] = 1; + playmusic(13); + animacion_3_3(); + playmusic(13); + animacion_4_3(); + flags[1] = 1; + refresca_pantalla(); + VUELCA_PANTALLA(120, 0, 120, 0, 200, 200, dir_zona_pantalla); + animacion_5(); + flags[0] = 0; + flags[1] = 1; + + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + lleva_al_hare(332, 127); + libera_memoria(); + // TODO + error("4 segment hit"); } +void DrasculaEngine::animacion_3_3() { + int n, x = 0; + int px = hare_x - 20, py = hare_y - 1; + + lee_dibujos("an2y_1.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("an2y_2.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("an2y_3.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 2, px, py, 71, 72, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 75, px, py, 71, 72, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 2, px, py, 71, 72, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 75, px, py, 71, 72, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 2, px, py, 71, 72, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 75, px, py, 71, 72, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } +} + +void DrasculaEngine::animacion_4_3() { + int n, x = 0; + int px = 120, py = 63; + + lee_dibujos("any_1.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("any_2.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("any_3.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + for (n = 0; n < 4; n++){ + x++; + DIBUJA_FONDO(px, py, px, py, 77, 89, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 1, px, py, 77, 89, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 77, 89, dir_zona_pantalla); + x = x + 77; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 77, 89, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 91, px, py, 77, 89, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 77, 89, dir_zona_pantalla); + x = x + 77; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 77, 89, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 1, px, py, 77, 89, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 77, 89, dir_zona_pantalla); + x = x + 77; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 77, 89, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 91, px, py, 77, 89, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 77, 89, dir_zona_pantalla); + x = x + 77; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 77, 89, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 1, px, py, 77, 89, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 77, 89, dir_zona_pantalla); + x = x + 77; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 77, 89, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 91, px, py, 77, 89, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 77, 89, dir_zona_pantalla); + x = x + 77; + pausa(3); + } +} + +void DrasculaEngine::animacion_5() { + int n, x = 0; + int px = hare_x - 20, py = hare_y - 1; + + lee_dibujos("an3y_1.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("an3y_2.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("an3y_3.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 2, px, py, 71, 72, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 75, px, py, 71, 72, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 2, px, py, 71, 72, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 75, px, py, 71, 72, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(px,py, px,py, 71,72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 2, px, py, 71, 72, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } + + x = 0; + + for (n = 0; n < 4; n++) { + x++; + DIBUJA_FONDO(px, py, px, py, 71, 72, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x, 75, px, py, 71, 72, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 71, 72, dir_zona_pantalla); + x = x + 71; + pausa(3); + } +} + +void DrasculaEngine::animacion_6() { + int frame = 0, px = 112, py = 62; + int yoda_x[] = { 3 ,82, 161, 240, 3, 82 }; + int yoda_y[] = { 3, 3, 3, 3, 94, 94 }; + + hare_se_mueve = 0; + flags[3] = 1; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + flags[1] = 0; + + lee_dibujos("an4y.alg"); + descomprime_dibujo(dir_hare_frente, 1); + + for (frame = 0; frame < 6; frame++) { + pausa(3); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(yoda_x[frame], yoda_y[frame], px, py, 78, 90, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(px, py, px, py, 78, 90, dir_zona_pantalla); + } + + flags[2] = 1; + + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::animacion_rayo() { + lee_dibujos("anr_1.alg"); + descomprime_dibujo(dir_hare_frente, MEDIA); + lee_dibujos("anr_2.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("anr_3.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("anr_4.alg"); + descomprime_dibujo(dir_dibujo1, 1); + lee_dibujos("anr_5.alg"); + descomprime_dibujo(dir_dibujo3, 1); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_hare_frente); + + pausa(50); + + comienza_sound("s5.als"); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_hare_dch); + pausa(3); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_hare_fondo); + pausa(3); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_dibujo1); + pausa(3); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_hare_fondo); + pausa(3); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_dibujo3); + pausa(3); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_hare_frente); + fin_sound(); +} + +void DrasculaEngine::animacion_2_4() { + habla_igor_sentado(TEXTI16, "I16.als"); + hablar(TEXT278, "278.als"); + habla_igor_sentado(TEXTI17, "I17.als"); + hablar(TEXT279, "279.als"); + habla_igor_sentado(TEXTI18, "I18.als"); +} + +void DrasculaEngine::animacion_3_4() { + habla_igor_sentado(TEXTI19, "I19.als"); + habla_igor_sentado(TEXTI20, "I20.als"); + hablar(TEXT281, "281.als"); +} + +void DrasculaEngine::animacion_4_4() { + hablar(TEXT287, "287.als"); + habla_igor_sentado(TEXTI21, "I21.als"); + hablar(TEXT284, "284.als"); + habla_igor_sentado(TEXTI22, "I22.als"); + hablar(TEXT285, "285.als"); + habla_igor_sentado(TEXTI23, "I23.als"); +} + +void DrasculaEngine::habla_igor_sentado(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[4] = { 80, 102, 124, 146 }; + int cara; + + int longitud; + longitud = strlen(dicho); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(BLANCO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(3); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_FONDO(x_habla[cara], 109, 207, 92, 21, 23, dir_dibujo3, dir_zona_pantalla); + pon_hare(); + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 221, 102); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::animacion_7_4() { + Negro(); + hablar(TEXT427, "427.als"); + FundeDelNegro(1); + resta_objeto(8); + resta_objeto(10); + resta_objeto(12); + resta_objeto(16); + suma_objeto(17); + flags[30] = 0; + flags[29] = 0; +} + +void DrasculaEngine::animacion_1_5() { + if (flags[0] == 0) { + hablar(TEXT430, "430.als"); + habla_bj(TEXTBJ16, "BJ16.als"); + habla_bj(TEXTBJ17, "BJ17.als"); + habla_bj(TEXTBJ18, "BJ18.als"); + hablar(TEXT217, "217.als"); + habla_bj(TEXTBJ19, "BJ19.als"); + hablar(TEXT229, "229.als"); + pausa(5); + lleva_al_hare(114, 170); + sentido_hare = 3; + hablar(TEXT431, "431.als"); + habla_bj(TEXTBJ20, "BJ20.als"); + sentido_hare = 2; + pausa(4); + hablar(TEXT438, "438.als"); + sitio_x = 120; + sitio_y = 157; + anda_a_objeto = 1; + sentido_final = 1; + empieza_andar(); + habla_bj(TEXTBJ21, "BJ21.als"); + + for (;;) { + if (hare_se_mueve == 0) + break; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + } + + sentido_hare = 1; + hablar(TEXT229, "229.als"); + flags[0] = 1; + } + + sentido_hare = 1; + conversa("op_8.cal"); +} + +void DrasculaEngine::animacion_2_5() { + habla_bj(TEXTBJ22, "BJ22.als"); +} + +void DrasculaEngine::animacion_3_5() { + habla_bj(TEXTBJ23, "BJ23.als"); + agarra_objeto(10); + rompo_y_salgo = 1; +} + +void DrasculaEngine::animacion_4_5() { + flags[7] = 1; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hablar(TEXT228, "228.als"); + habla_lobo(TEXTL1, "L1.als"); + habla_lobo(TEXTL2, "L2.als"); + pausa(23); + hablar(TEXT229, "229.als"); + habla_lobo(TEXTL3, "L3.als"); + habla_lobo(TEXTL4, "L4.als"); + hablar(TEXT230, "230.als"); + habla_lobo(TEXTL5, "L5.als"); + hablar(TEXT231, "231.als"); + habla_lobo(TEXTL6, "L6.als"); + habla_lobo(TEXTL7, "L7.als"); + pausa(33); + hablar(TEXT232, "232.als"); + habla_lobo(TEXTL8, "L8.als"); +} + +void DrasculaEngine::animacion_5_5(){ + int h; + int frame = 0; + int hueso_x[] = {1, 99, 197, 1, 99, 197, 1, 99, 197}; + int hueso_y[] = {1, 1, 1, 66, 66, 66, 131, 131, 131}; + int vuela_x[] = {1, 63, 125, 187, 249}; + int pixel_x = hare_x - 53, pixel_y = hare_y - 9; + + sin_verbo(); + resta_objeto(8); + + lleva_al_hare(hare_x - 19, hare_y + alto_hare); + sentido_hare = 1; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + lee_dibujos("3an5_1.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("3an5_2.alg"); + descomprime_dibujo(dir_hare_frente, 1); + + for (frame = 0; frame < 9; frame++) { + pausa(3); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(hueso_x[frame], hueso_y[frame], pixel_x, pixel_y, 97, 64, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(pixel_x, pixel_y, pixel_x,pixel_y, 97,64, dir_zona_pantalla); + } + + DIBUJA_FONDO(52, 161, 198, 81, 26, 24, dir_dibujo3, dir_zona_pantalla); + VUELCA_PANTALLA(198, 81, 198, 81, 26, 24, dir_zona_pantalla); + + for (frame = 0; frame < 9; frame++) { + pausa(3); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(hueso_x[frame], hueso_y[frame], pixel_x, pixel_y, 97, 64, dir_hare_frente, dir_zona_pantalla); + VUELCA_PANTALLA(pixel_x, pixel_y, pixel_x,pixel_y, 97, 64, dir_zona_pantalla); + } + + flags[6] = 1; + actualiza_datos(); + pausa(12); + + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + for (h = 0; h < (200 - 18); h++) + DIBUJA_FONDO(0, 53, 0, h, 320, 19, dir_hare_frente, dir_zona_pantalla); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + lee_dibujos("101.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); + lee_dibujos("3an5_3.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("3an5_4.alg"); + descomprime_dibujo(dir_hare_dch, 1); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_dibujo1); + pausa(9); + for (frame = 0; frame < 5; frame++) { + pausa(3); + DIBUJA_FONDO(vuela_x[frame], 1, 174, 79, 61, 109, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(174, 79, 174, 79, 61, 109, dir_zona_pantalla); + } + for (frame = 0; frame < 5; frame++) { + pausa(3); + DIBUJA_FONDO(vuela_x[frame], 1, 174, 79, 61, 109, dir_hare_dch, dir_zona_pantalla); + VUELCA_PANTALLA(174, 79, 174, 79, 61, 109, dir_zona_pantalla); + } + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_dibujo1); + + comienza_sound("s1.als"); + fin_sound(); + + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + + borra_pantalla(); + + lee_dibujos("49.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); +} + +void DrasculaEngine::animacion_6_5() { + habla_lobo(TEXTL9, "L9.als"); + hablar(TEXT234, "234.als"); +} + +void DrasculaEngine::animacion_7_5() { + habla_lobo(TEXTL10, "L10.als"); + hablar(TEXT236, "236.als"); + habla_lobo(TEXTL11, "L11.als"); + habla_lobo(TEXTL12, "L12.als"); + habla_lobo(TEXTL13, "L13.als"); + pausa(34); + habla_lobo(TEXTL14, "L14.als"); +} + +void DrasculaEngine::animacion_8_5() { + habla_lobo(TEXTL15, "L15.als"); + hablar(TEXT238, "238.als"); + habla_lobo(TEXTL16, "L16.als"); +} + +void DrasculaEngine::animacion_9_5() { + flags[4] = 1; + hablar(TEXT401, "401.als"); + sin_verbo(); + resta_objeto(15); +} + +void DrasculaEngine::animacion_10_5() { + flags[3] = 1; + hablar(TEXT401, "401.als"); + sin_verbo(); + resta_objeto(12); +} + +void DrasculaEngine::animacion_11_5() { + flags[9] = 1; + if (flags[2] == 1 && flags[3] == 1 && flags[4] == 1) + animacion_12_5(); + else { + flags[9] = 0; + hablar(TEXT33, "33.als"); + } +} + +void DrasculaEngine::animacion_12_5() { + DacPalette256 palFondo1; + DacPalette256 palFondo2; + DacPalette256 palFondo3; + + int frame; + const int rayo_x[] = {1, 46, 91, 136, 181, 226, 271, 181}; + const int frusky_x[] = {100, 139, 178, 217, 100, 178, 217, 139, 100, 139}; + const int elfrusky_x[] = {1, 68, 135, 1, 68, 135, 1, 68, 135, 68, 1, 135, 68, 135, 68}; + //const int humo_x[] = {1, 29, 57, 85, 113, 141, 169, 197, 225}; + int color, componente; + char fundido; + + playmusic(26); + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + pausa(27); + anima("rayo1.bin", 23); + comienza_sound("s5.als"); + anima("rayo2.bin", 17); + sentido_hare = 1; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + hare_oscuro(); + + for (color = 0; color < 255; color++) + for (componente = 0; componente < 3; componente++) { + palFondo1[color][componente] = palJuego[color][componente]; + palFondo2[color][componente] = palJuego[color][componente]; + palFondo3[color][componente] = palJuego[color][componente]; + } + + for (fundido = 1; fundido >= 0; fundido--) { + for (color = 0; color < 128; color++) + for (componente = 0; componente < 3; componente++) + palFondo1[color][componente] = LimitaVGA(palFondo1[color][componente] - 8 + fundido); + } + + for (fundido = 2; fundido >= 0; fundido--) { + for (color = 0; color < 128; color++) + for (componente = 0; componente < 3; componente++) + palFondo2[color][componente] = LimitaVGA(palFondo2[color][componente] - 8 + fundido); + } + + for (fundido = 3; fundido >= 0; fundido--) { + for (color = 0; color < 128; color++) + for (componente = 0; componente < 3; componente++) + palFondo3[color][componente] = LimitaVGA(palFondo3[color][componente] - 8 + fundido); + } + + lee_dibujos("3an11_1.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + for (frame = 0; frame < 8; frame++) { + if (frame == 2 || frame == 4 || frame == 8 || frame==10) + setvgapalette256((byte *)&palFondo1); + else if (frame == 1 || frame == 5 || frame == 7 || frame == 9) + setvgapalette256((byte *)&palFondo2); + else + setvgapalette256((byte *)&palFondo3); + + pausa(4); + refresca_pantalla(); + DIBUJA_BLOQUE(rayo_x[frame], 1, 41, 0, 44, 44, dir_hare_fondo, dir_zona_pantalla); + DIBUJA_BLOQUE(frusky_x[frame], 113, 205, 50, 38, 86, dir_dibujo3, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + } + + fin_sound_corte(); + + for (frame = 0; frame < 15; frame++) { + if (frame == 2 || frame == 4 || frame == 7 || frame == 9) + setvgapalette256((byte *)&palFondo1); + else if (frame == 1 || frame == 5) + setvgapalette256((byte *)&palJuego); + else + setvgapalette256((byte *)&palFondo2); + + pausa(4); + refresca_pantalla(); + DIBUJA_BLOQUE(elfrusky_x[frame], 47, 192, 39, 66, 106, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + } + + anima("frel.bin", 16); + borra_pantalla(); + hare_claro(); + ActualizaPaleta(); + + flags[1] = 1; + + animacion_13_5(); + comienza_sound("s1.als"); + hipo(12); + fin_sound(); + + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + lleva_al_hare(40, 169); + lleva_al_hare(-14, 175); + + rompo = 1; + musica_antes = musica_room; + hare_se_ve = 1; + borra_pantalla(); + sentido_hare = 1; + hare_se_mueve = 0; + hare_x = -1; + obj_saliendo = 104; + sin_verbo(); + carga_escoba("57.ald"); +} + +void DrasculaEngine::animacion_13_5() { + int frank_x = 199; + int frame = 0; + int frus_x[] = {1, 46, 91, 136, 181, 226, 271}; + int frus_y[] = {1, 1, 1, 1, 1, 1, 1, 89}; + int pos_frusky[6]; + + lee_dibujos("auxfr.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + + pos_frusky[3] = 81; + pos_frusky[4] = 44; + pos_frusky[5] = 87; + pos_frusky[0] = 1; + pos_frusky[1] = 1; + pos_frusky[2] = frank_x; + refresca_pantalla(); + DIBUJA_BLOQUE_CUT(pos_frusky, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + pausa(15); + + playmusic(18); + + for (;;) { + refresca_pantalla(); + pos_frusky[0] = frus_x[frame]; + pos_frusky[1] = frus_y[frame]; + pos_frusky[2] = frank_x; + DIBUJA_BLOQUE_CUT( pos_frusky, dir_hare_fondo, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + frank_x = frank_x - 5; + frame++; + if (frank_x <= -45) + break; + if (frame == 7) { + frame = 0; + sentido_hare = 3; + } + pausa(6); + } +} + +void DrasculaEngine::animacion_14_5() { + flags[11] = 1; + comienza_sound("s3.als"); + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0,0 , 320, 200, dir_zona_pantalla); + fin_sound(); + pausa(17); + sentido_hare = 3; + hablar(TEXT246,"246.als"); + lleva_al_hare(89, 160); + flags[10] = 1; + comienza_sound("s7.als"); + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + fin_sound(); + pausa(14); + sentido_hare = 3; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + habla_solo(TEXTD18, "d18.als"); + FundeAlNegro(1); + error("part 6 hit"); +} + +void DrasculaEngine::animacion_15_5() { + habla_mus(TEXTE4, "E4.als"); + habla_mus(TEXTE5, "E5.als"); + habla_mus(TEXTE6, "E6.als"); + hablar(TEXT291, "291.als"); + habla_mus(TEXTE7, "E7.als"); +} + +void DrasculaEngine::animacion_16_5() { + habla_mus(TEXTE8, "E8.als"); +} + +void DrasculaEngine::animacion_17_5() { + habla_mus(TEXTE9, "E9.als"); +} + +void DrasculaEngine::refresca_49_antes() { + if (flags[6] == 0) + DIBUJA_FONDO(2, 136, 176, 81, 49, 62, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_53_antes() { + if (flags[1] == 0) + DIBUJA_BLOQUE(2, 113, 205, 50, 38, 86, dir_dibujo3, dir_zona_pantalla); + if (flags[2] == 0) + DIBUJA_FONDO(41, 159, 27, 117, 25, 40, dir_dibujo3, dir_zona_pantalla); + if (flags[9] == 1) + DIBUJA_FONDO(67, 184, 56, 93, 32, 15, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_54_antes() { + if (flags[5] == 1) + DIBUJA_FONDO(168, 156, 187, 111, 7, 11, dir_dibujo3, dir_zona_pantalla); + if (flags[12] == 1) + DIBUJA_FONDO(16, 156, 190, 64, 18, 24, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_56_antes() { + if (flags[10] == 0) + DIBUJA_FONDO(2, 126, 42, 67, 57, 67, dir_dibujo3, dir_zona_pantalla); + if (flags[11] == 1) + DIBUJA_FONDO(60, 160, 128, 97, 103, 38, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_50() { + DIBUJA_BLOQUE(4, 153, 118, 95, 67, 44, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_57() { + DIBUJA_BLOQUE(7, 113, 166, 61, 62, 82, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::pantalla_49(int fl){ + if (objeto_que_lleva == HABLAR && fl ==51) + conversa("op_9.cal"); + else if (objeto_que_lleva == MIRAR && fl == 51) + hablar(TEXT132, "132.als"); + else if ((objeto_que_lleva == 8 && fl == 51) || (objeto_que_lleva == 8 && fl == 203)) + animacion_5_5(); + else if (objeto_que_lleva == MIRAR && fl == 200) + hablar(TEXT133, "133.als"); + else if (objeto_que_lleva == HABLAR && fl == 200) + hablar(TEXT134, "134.als"); + else if (objeto_que_lleva == MIRAR && fl == 201) + hablar(TEXT135, "135.als"); + else if (objeto_que_lleva == MIRAR && fl == 203) + hablar(TEXT137, "137.als"); + else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_53(int fl) { + if (objeto_que_lleva == COGER && fl == 120) { + agarra_objeto(16); + visible[3] = 0; + } else if (objeto_que_lleva == MIRAR && fl == 121) + hablar(TEXT128, "128.als"); + else if (objeto_que_lleva == MIRAR && fl == 209) + hablar(TEXT129, "129.als"); + else if (objeto_que_lleva == MOVER && fl == 123) + animacion_11_5(); + else if (objeto_que_lleva == MIRAR && fl == 52) + hablar(TEXT447, "447.als"); + else if (objeto_que_lleva == HABLAR && fl == 52) + hablar(TEXT131, "131.als"); + else if (objeto_que_lleva == 12 && fl == 52) + animacion_10_5(); + else if (objeto_que_lleva == 15 && fl == 52) + animacion_9_5(); + else if (objeto_que_lleva == 16 && fl == 121) { + flags[2] = 1; + sin_verbo(); + actualiza_datos(); + } else if (objeto_que_lleva == 16) { + hablar(TEXT439, "439.als"); + sin_verbo(); + visible[3] = 1; + } else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_54(int fl) { + if ((objeto_que_lleva == HABLAR && fl == 118) || (objeto_que_lleva == MIRAR && fl == 118 && flags[0] == 0)) + animacion_1_5(); + else if (objeto_que_lleva == MIRAR && fl == 118 && flags[0]==1) + hablar(TEXT124, "124.als"); + else if (objeto_que_lleva == MIRAR && fl == 53) + hablar(TEXT127, "127.als"); + else if (objeto_que_lleva == HABLAR && fl == 53 && flags[14] == 0) { + hablar(TEXT288, "288.als"); + flags[12] = 1; + pausa(10); + habla_mus(TEXTE1, "E1.als"); + hablar(TEXT289, "289.als"); + habla_mus(TEXTE2, "E2.als"); + habla_mus(TEXTE3, "E3.als"); + conversa("op_10.cal"); + flags[12] = 0; + flags[14] = 1; + } else if (objeto_que_lleva == HABLAR && fl == 53 && flags[14] == 1) + hablar(TEXT109, "109.als"); + else if (objeto_que_lleva == COGER && fl == 9999 && flags[13] == 0) { + agarra_objeto(8); + flags[13] = 1; + habla_mus(TEXTE10, "e10.als"); + actualiza_datos(); + } else if (objeto_que_lleva == ABRIR && fl == 119) + hablar(TEXT125, "125.als"); + else if (objeto_que_lleva == MIRAR && fl == 119) + hablar(TEXT126, "126.als"); + else if (objeto_que_lleva == 10 && fl == 119) { + pausa(4); + hablar(TEXT436, "436.als"); + sin_verbo(); + resta_objeto(10); + } else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_55(int fl) { + if (objeto_que_lleva == COGER && fl == 122) { + agarra_objeto(12); + flags[8] = 1; + actualiza_datos(); + } else if (objeto_que_lleva == MIRAR && fl == 122) + hablar(TEXT138, "138.als"); + else if (objeto_que_lleva == MIRAR && fl == 204) + hablar(TEXT139, "139.als"); + else if (objeto_que_lleva == MIRAR && fl == 205) + hablar(TEXT140, "140.als"); + else if (fl == 206) { + comienza_sound("s11.als"); + anima("det.bin", 17); + fin_sound(); + lleva_al_hare(hare_x - 3, hare_y + alto_hare + 6); + } else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_56(int fl) { + if (objeto_que_lleva == ABRIR && fl == 124) + animacion_14_5(); + else if (objeto_que_lleva == MIRAR && fl == 124) + hablar(TEXT450, "450.als"); + else if (objeto_que_lleva == ABRIR && fl == 207) + hablar(TEXT141, "141.als"); + else if (objeto_que_lleva == MIRAR && fl == 208) + hablar(TEXT142, "142.als"); + else + hay_respuesta = 0; +} + +void DrasculaEngine::habla_lobo(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[9] = {52, 79, 106, 133, 160, 187, 214, 241, 268}; + int cara; + + int longitud; + longitud = strlen(dicho); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + color_abc(ROJO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(8); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_FONDO(x_habla[cara], 136, 198, 81, 26, 24, dir_dibujo3, dir_zona_pantalla); + pon_hare(); + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 203, 78); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::habla_mus(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[8] = { 16, 35, 54, 73, 92, 111, 130, 149}; + int cara; + + int longitud; + longitud = strlen(dicho); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(BLANCO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(7); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_FONDO(x_habla[cara], 156, 190, 64, 18, 24, dir_dibujo3, dir_zona_pantalla); + pon_hare(); + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 197, 64); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::animacion_1_6() { + int l; + + sentido_hare = 0; + hare_x = 103; + hare_y = 108; + flags[0] = 1; + for (l = 0; l < 200; l++) + factor_red[l] = 98; + + lee_dibujos("auxig2.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("auxdr.alg"); + descomprime_dibujo(dir_dibujo2, 1); + lee_dibujos("car.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + habla_dr_dch(TEXTD19, "D19.als"); + hablar(TEXT247, "247.als"); + habla_dr_dch(TEXTD20, "d20.als"); + habla_dr_dch(TEXTD21, "d21.als"); + hablar(TEXT248, "248.als"); + habla_dr_dch(TEXTD22, "d22.als"); + hablar(TEXT249, "249.als"); + habla_dr_dch(TEXTD23, "d23.als"); + conversa("op_11.cal"); + habla_dr_dch(TEXTD26, "d26.als"); + + anima("fum.bin", 15); + + habla_dr_dch(TEXTD27, "d27.als"); + hablar(TEXT254, "254.als"); + habla_dr_dch(TEXTD28, "d28.als"); + hablar(TEXT255, "255.als"); + habla_dr_dch(TEXTD29, "d29.als"); + FundeAlNegro(1); + borra_pantalla(); + lee_dibujos("time1.alg"); + descomprime_dibujo(dir_zona_pantalla, 1); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + delay(930); + borra_pantalla(); + Negro(); + hare_se_ve = 0; + flags[0] = 0; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + FundeDelNegro(1); + hablar(TEXT256, "256.als"); + habla_dr_dch(TEXTD30, "d30.als"); + hablar(TEXT257, "257.als"); + FundeAlNegro(0); + borra_pantalla(); + lee_dibujos("time1.alg"); + descomprime_dibujo(dir_zona_pantalla,1); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + delay(900); + borra_pantalla(); + Negro(); + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + FundeDelNegro(1); + hablar(TEXT258, "258.als"); + habla_dr_dch(TEXTD31, "d31.als"); + animacion_5_6(); + habla_dr_dch(TEXTD32, "d32.als"); + habla_igor_dch(TEXTI11, "I11.als"); + sentido_igor = 3; + habla_dr_dch(TEXTD33, "d33.als"); + habla_igor_frente(TEXTI12, "I12.als"); + habla_dr_dch(TEXTD34, "d34.als"); + sentido_dr = 0; + habla_dr_izq(TEXTD35,"d35.als"); + borra_pantalla(); + carga_escoba("102.ald"); + activa_pendulo(); +} + +void DrasculaEngine::animacion_2_6() { + habla_dr_dch(TEXTD24, "d24.als"); +} + +void DrasculaEngine::animacion_3_6() { + habla_dr_dch(TEXTD24, "d24.als"); +} + +void DrasculaEngine::animacion_4_6() { + habla_dr_dch(TEXTD25, "d25.als"); +} + +void DrasculaEngine::animacion_5_6() { + int n, pos_pen[6]; + + pos_pen[0] = 1; + pos_pen[1] = 29; + pos_pen[2] = 204; + pos_pen[3] = -125; + pos_pen[4] = 18; + pos_pen[5] = 125; + + anima("man.bin", 14); + + for (n = -125; n <= 0; n = n + 2) { + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + actualiza_refresco_antes(); + pos_pen[3] = n; + DIBUJA_BLOQUE_CUT(pos_pen, dir_dibujo3, dir_zona_pantalla); + + actualiza_refresco(); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + pausa(2); + } + + flags[3] = 1; +} + +void DrasculaEngine::animacion_6_6() { + anima("rct.bin", 11); + borra_pantalla(); + sin_verbo(); + resta_objeto(20); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("97.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + rompo = 1; + obj_saliendo = 104; + hare_x = -1; + sin_verbo(); + carga_escoba("58.ald"); + hare_se_ve = 1; + sentido_hare = 1; + anima("hbp.bin", 14); + + sentido_hare = 3; + flags[0] = 1; + flags[1] = 0; + flags[2] = 1; +} + +void DrasculaEngine::animacion_7_6() { + flags[8] = 1; + actualiza_datos(); +} + +void DrasculaEngine::animacion_9_6() { + int v_cd; + + anima("fin.bin", 14); + playmusic(13); + flags[5] = 1; + anima("drf.bin", 16); + FundeAlNegro(0); + borra_pantalla(); + hare_x = -1; + obj_saliendo = 108; + carga_escoba("59.ald"); + strcpy(num_room, "nada.alg"); + lee_dibujos("nota2.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); + Negro(); + sentido_hare = 1; + hare_x -= 21; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + FundeDelNegro(0); + pausa(96); + lleva_al_hare(116, 178); + sentido_hare = 2; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + playmusic(9); + borra_pantalla(); + lee_dibujos("nota.alg"); + descomprime_dibujo(dir_dibujo1, COMPLETA); + color_abc(BLANCO); + habla_solo(TEXTBJ24, "bj24.als"); + habla_solo(TEXTBJ25, "bj25.als"); + habla_solo(TEXTBJ26, "bj26.als"); + habla_solo(TEXTBJ27, "bj27.als"); + habla_solo(TEXTBJ28, "bj28.als"); + sentido_hare = 3; + borra_pantalla(); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); + lee_dibujos("nota2.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); + hablar(TEXT296, "296.als"); + hablar(TEXT297, "297.als"); + hablar(TEXT298, "298.als"); + sentido_hare = 1; + hablar(TEXT299, "299.als"); + hablar(TEXT300, "300.als"); + refresca_pantalla(); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_zona_pantalla, dir_dibujo1); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + color_abc(VERDE_CLARO); + habla_solo("GOOOOOOOOOOOOOOOL", "s15.als"); + lee_dibujos("nota2.alg"); + descomprime_dibujo(dir_dibujo1, 1); + sentido_hare = 0; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hablar(TEXT301, "301.als"); + v_cd = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 16; + v_cd = v_cd + 4; + playmusic(17); + FundeAlNegro(1); + borra_pantalla(); + fliplay("qpc.bin", 1); + MusicFadeout(); + stopmusic(); + borra_pantalla(); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, v_cd * 16); + playmusic(3); + fliplay("crd.bin", 1); + stopmusic(); + error("end of game ?"); +} + +void DrasculaEngine::animacion_10_6() { + comienza_sound ("s14.als"); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + actualiza_refresco_antes(); + DIBUJA_FONDO(164, 85, 155, 48, 113, 114, dir_dibujo3, dir_zona_pantalla); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + fin_sound(); + habla_taber2(TEXTT23, "t23.als"); + flags[7] = 1; + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + FundeDelNegro(0); + pausa(96); + lleva_al_hare(116, 178); + sentido_hare = 2; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + playmusic(9); + borra_pantalla(); + lee_dibujos("nota.alg"); + descomprime_dibujo(dir_dibujo1, COMPLETA); + color_abc(BLANCO); + habla_solo(TEXTBJ24, "bj24.als"); + habla_solo(TEXTBJ25, "bj25.als"); + habla_solo(TEXTBJ26, "bj26.als"); + habla_solo(TEXTBJ27, "bj27.als"); + habla_solo(TEXTBJ28, "bj28.als"); + sentido_hare = 3; + borra_pantalla(); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); + lee_dibujos("nota2.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); + hablar(TEXT296, "296.als"); + hablar(TEXT297, "297.als"); + hablar(TEXT298, "298.als"); + sentido_hare = 1; + hablar(TEXT299, "299.als"); + hablar(TEXT300, "300.als"); + refresca_pantalla(); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_zona_pantalla, dir_dibujo1); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + color_abc(VERDE_CLARO); + habla_solo("GOOOOOOOOOOOOOOOL", "s15.als"); + lee_dibujos("nota2.alg"); + descomprime_dibujo(dir_dibujo1, 1); +} + +void DrasculaEngine::animacion_11_6() { + habla_taber2(TEXTT10, "t10.als"); + hablar(TEXT268, "268.als"); + habla_taber2(TEXTT11, "t11.als"); +} + +void DrasculaEngine::animacion_12_6() { + habla_taber2(TEXTT12, "t12.als"); + hablar(TEXT270, "270.als"); + habla_taber2(TEXTT13, "t13.als"); + habla_taber2(TEXTT14, "t14.als"); +} + +void DrasculaEngine::animacion_13_6() { + habla_taber2(TEXTT15, "t15.als"); +} + +void DrasculaEngine::animacion_14_6() { + habla_taber2(TEXTT24, "t24.als"); + suma_objeto(21); + flags[10] = 1; + rompo_y_salgo = 1; +} + +void DrasculaEngine::animacion_15_6() { + habla_taber2(TEXTT16, "t16.als"); +} + +void DrasculaEngine::animacion_18_6() { + sin_verbo(); + resta_objeto(21); + anima("beb.bin", 10); +} + +void DrasculaEngine::animacion_19_6() { + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + DIBUJA_FONDO(140, 23, 161, 69, 35, 80, dir_dibujo3, dir_zona_pantalla); + + actualiza_refresco_antes(); + pon_hare(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + pausa(6); + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + comienza_sound("s4.als"); + pausa(6); + fin_sound(); +} + +void DrasculaEngine::activa_pendulo() { + flags[1] = 2; + hare_se_ve = 0; + strcpy(num_room, "102.alg"); + lee_dibujos("102.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); + lee_dibujos("an_p1.alg"); + descomprime_dibujo(dir_dibujo3, 1); + lee_dibujos("an_p2.alg"); + descomprime_dibujo(dir_hare_dch, 1); + lee_dibujos("an_p3.alg"); + descomprime_dibujo(dir_hare_frente, 1); + + DIBUJA_FONDO(0, 171, 0, 0, ANCHOBJ, ALTOBJ, dir_hare_fondo, dir_dibujo3); + + conta_ciego_vez = (int)vez(); +} + +void DrasculaEngine::habla_pen(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[8] = {112, 138, 164, 190, 216, 242, 268, 294}; + int cara; + + int longitud; + longitud = strlen(dicho); + + flags[1] = 1; + + refresca_pantalla(); + DIBUJA_BLOQUE(44, 145, 145, 105, 25, 29, dir_dibujo3, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(AMARILLO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(7); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_BLOQUE(x_habla[cara], 145, 145, 105, 25, 29, dir_dibujo3, dir_zona_pantalla); + + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 160, 105); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + flags[1] = 0; + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + actualiza_refresco_antes(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::habla_pen2(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[5]={122, 148, 174, 200, 226}; + int cara; + + int longitud; + longitud = strlen(dicho); + + flags[1] = 1; + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(AMARILLO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(4); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_FONDO(x_habla[cara], 171, 173, 116, 25, 28, dir_dibujo3, dir_zona_pantalla); + + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 195, 107); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + flags[1] = 0; + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + actualiza_refresco_antes(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::habla_taber2(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[6] = {1, 23, 45, 67, 89, 111}; + int cara; + + int longitud; + longitud = strlen(dicho); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(MARRON); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(5); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_FONDO(x_habla[cara], 130, 151, 43, 21, 24, dir_dibujo3, dir_zona_pantalla); + pon_hare(); + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 132, 45); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_58() { + if (hare_se_ve == 1) + DIBUJA_BLOQUE(67, 139, 140, 147, 12, 16, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_60() { + if (hare_y - 10 < y_dr && flags[5] == 0) + pon_dr(); +} + +void DrasculaEngine::refresca_61() { + DIBUJA_BLOQUE(1, 154, 83, 122, 131, 44, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_58_antes() { + if (flags[0] == 0) + DIBUJA_FONDO(1, 156, 143, 120, 120, 43, dir_dibujo3, dir_zona_pantalla); + if (flags[1] == 2) + DIBUJA_BLOQUE(252, 171, 173, 116, 25, 28, dir_dibujo3, dir_zona_pantalla); + if (flags[1] == 0 && flags[0] == 0) + DIBUJA_BLOQUE(278, 171, 173, 116, 25, 28, dir_dibujo3, dir_zona_pantalla); + if (flags[2] == 0) { + pon_igor(); + pon_dr(); + } + if (flags[3] == 1) + DIBUJA_BLOQUE(1, 29, 204, 0, 18, 125, dir_dibujo3, dir_zona_pantalla); + if (flags[8] == 1) + DIBUJA_FONDO(20, 60, 30, 64, 46, 95, dir_dibujo3, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_59_antes() { + if (flags[4] == 0) + DIBUJA_BLOQUE(1, 146, 65, 106, 83, 40, dir_dibujo3, dir_zona_pantalla); + if (flags[9] == 1) { + DIBUJA_FONDO(65, 103, 65, 103, 49, 38, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(1, 105, 65, 103, 49, 38, dir_dibujo3, dir_zona_pantalla); + } +} + +void DrasculaEngine::refresca_60_antes() { + int velas_y[] = {158, 172, 186}; + int diferencia; + + if (flags[5] == 0) + pon_dr(); + + DIBUJA_FONDO(123, velas_y[frame_velas], 142, 14, 39, 13, dir_dibujo3, dir_zona_pantalla); + + if (flag_tv == 1) + DIBUJA_FONDO(114, 158, 8, 30, 8, 23, dir_dibujo3, dir_zona_pantalla); + + diferencia = (int)vez() - conta_ciego_vez; + parpadeo = _rnd->getRandomNumber(7); + if (parpadeo == 5 && flag_tv == 0) + flag_tv = 1; + else if (parpadeo == 5 && flag_tv == 1) + flag_tv = 0; + if (diferencia > 6) { + frame_velas++; + if (frame_velas == 3) + frame_velas = 0; + conta_ciego_vez = (int)vez(); + } +} + +void DrasculaEngine::pantalla_58(int fl) { + if (objeto_que_lleva == MOVER && fl == 103) + animacion_7_6(); + else if (objeto_que_lleva == MIRAR && fl == 104) + hablar(TEXT454, "454.als"); + else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_59(int fl) { + if ((objeto_que_lleva == HABLAR && fl == 51) || (objeto_que_lleva == MIRAR && fl == 51)) { + flags[9] = 1; + hablar(TEXT259, "259.als"); + habla_bj_cama(TEXTBJ13, "bj13.als"); + hablar(TEXT263, "263.als"); + habla_bj_cama(TEXTBJ14, "bj14.als"); + pausa(40); + hablar(TEXT264, "264.als"); + habla_bj_cama(TEXTBJ15, "BJ15.als"); + hablar(TEXT265, "265.als"); + flags[9] = 0; + if (flags[11] == 0) { + comienza_sound("s12.als"); + delay(40); + fin_sound(); + delay(10); + lleva_al_hare(174, 168); + sentido_hare = 2; + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + pausa(40); + comienza_sound("s12.als"); + pausa(19); + fin_sound_corte(); + hare_se_ve = 0; + refresca_pantalla(); + DIBUJA_BLOQUE(101, 34, hare_x - 4, hare_y - 1, 37, 70, dir_dibujo3, dir_zona_pantalla); + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_zona_pantalla, dir_dibujo1); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + hare_se_ve = 1; + borra_pantalla(); + lee_dibujos("tlef0.alg"); + descomprime_dibujo(dir_dibujo1, COMPLETA); + lee_dibujos("tlef1.alg"); + descomprime_dibujo(dir_dibujo3, 1); + lee_dibujos("tlef2.alg"); + descomprime_dibujo(dir_hare_frente, 1); + lee_dibujos("tlef3.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + habla_htel(TEXT240, "240.als"); + + color_abc(VON_BRAUN); + habla_solo(TEXTVB58, "VB58.als"); + habla_htel(TEXT241, "241.als"); + color_abc(VON_BRAUN); + habla_solo(TEXTVB59, "VB59.als"); + habla_htel(TEXT242, "242.als"); + color_abc(VON_BRAUN); + habla_solo(TEXTVB60, "VB60.als"); + habla_htel(TEXT196, "196.als"); + color_abc(VON_BRAUN); + habla_solo(TEXTVB61,"VB61.als"); + habla_htel(TEXT244, "244.als"); + color_abc(VON_BRAUN); + habla_solo(TEXTVB62, "VB62.als"); + borra_pantalla(); + lee_dibujos("aux59.alg"); + descomprime_dibujo(dir_dibujo3, 1); + lee_dibujos("96.alg"); + descomprime_dibujo(dir_hare_frente, COMPLETA); + lee_dibujos("99.alg"); + descomprime_dibujo(dir_hare_fondo, 1); + lee_dibujos("59.alg"); + descomprime_dibujo(dir_dibujo1, MEDIA); + sentido_hare = 3; + hablar(TEXT245, "245.als"); + sin_verbo(); + flags[11] = 1; + } + } else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_60(int fl) { + if (objeto_que_lleva == MOVER && fl == 112) + animacion_10(); + else if (objeto_que_lleva == MIRAR && fl == 112) + hablar(TEXT440, "440.als"); + else if (objeto_que_lleva == HABLAR && fl == 52) { + hablar(TEXT266, "266.als"); + habla_taber2(TEXTT1, "t1.als"); + conversa("op_12.cal"); + sin_verbo(); + objeto_que_lleva = 0; + } else if (objeto_que_lleva == HABLAR && fl == 115) + hablar(TEXT455, "455.als"); + else if (objeto_que_lleva == HABLAR && fl == 56) + hablar(TEXT455, "455.als"); + else if (objeto_que_lleva == MIRAR && fl == 114) + hablar(TEXT167, "167.als"); + else if (objeto_que_lleva == MIRAR && fl == 113) + hablar(TEXT168, "168.als"); + else if (objeto_que_lleva == COGER && fl == 113) + hablar(TEXT170, "170.als"); + else if (objeto_que_lleva == MOVER && fl == 113) + hablar(TEXT170, "170.als"); + else if (objeto_que_lleva == HABLAR && fl == 113) + hablar(TEXT169, "169.als"); + else if (objeto_que_lleva == 21 && fl == 56) + animacion_18_6(); + else if (objeto_que_lleva == 9 && fl == 56 && flags[6] == 1) + animacion_9(); + else if (objeto_que_lleva == 9 && fl == 56 && flags[6] == 0) { + anima("cnf.bin", 14); + hablar(TEXT455, "455.als"); + } else + hay_respuesta = 0; +} + +void DrasculaEngine::pantalla_61(int fl) { + if (objeto_que_lleva == MIRAR && fl == 116) + hablar(TEXT172, "172.als"); + else if (objeto_que_lleva == MIRAR && fl == 117) + hablar(TEXT173, "173.als"); + else if (objeto_que_lleva == MOVER && fl == 117) + hablar(TEXT174, "174.als"); + else if (objeto_que_lleva == ABRIR && fl == 117) + hablar(TEXT174, "174.als"); + else + hay_respuesta = 0; +} + +void DrasculaEngine::habla_bj_cama(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + + int x_habla[5] = {51, 101, 151, 201, 251}; + int cara; + + int longitud; + longitud = strlen(dicho); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(BLANCO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(4); + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + actualiza_refresco_antes(); + + DIBUJA_FONDO(65, 103, 65, 103, 49, 38, dir_dibujo1, dir_zona_pantalla); + DIBUJA_BLOQUE(x_habla[cara], 105, 65, 103, 49, 38, dir_dibujo3, dir_zona_pantalla); + pon_hare(); + actualiza_refresco(); + + if (con_voces == 0) + centra_texto(dicho, 104, 102); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + refresca_pantalla(); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::habla_htel(const char *dicho, const char *filename) { + int tiempou; + long tiempol; + char *num_cara; + + int x_habla[3] = {1, 94, 187}; + int cara, pantalla; + + int longitud; + longitud = strlen(dicho); + + tiempol = _system->getMillis(); + tiempou = (unsigned int)tiempol / 2; + _rnd->setSeed(tiempou); + + buffer_teclado(); + + color_abc(AMARILLO); + + if (hay_sb == 1) { + sku = new Common::File; + sku->open(filename); + if (!sku->isOpen()) { + error("no puedo abrir archivo de voz"); + } + ctvd_init(2); + ctvd_speaker(1); + ctvd_output(sku); + } + +bucless: + + cara = _rnd->getRandomNumber(2); + pantalla = _rnd->getRandomNumber(2); + + if (cara == 0 && pantalla == 0) + num_cara = (char *)dir_dibujo3; + else if (pantalla == 1) + num_cara = (char *)dir_hare_frente; + else + num_cara = (char *)dir_hare_fondo; + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + + DIBUJA_FONDO(x_habla[cara], 1, 45, 24, 92, 108, (byte *)num_cara, dir_zona_pantalla); + + if (con_voces == 0) + centra_texto(dicho, 90, 50); + + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); + pausa(3); + + int key = getscan(); + if (key != 0) + ctvd_stop(); + buffer_teclado(); + if (hay_sb == 1) { + if (LookForFree() != 0) + goto bucless; + delete sku; + ctvd_terminate(); + } else { + longitud = longitud - 2; + if (longitud > 0) + goto bucless; + } + + DIBUJA_FONDO(0, 0, 0, 0, 320, 200, dir_dibujo1, dir_zona_pantalla); + VUELCA_PANTALLA(0, 0, 0, 0, 320, 200, dir_zona_pantalla); +} + +void DrasculaEngine::refresca_pendulo() { + int pendulo_x[] = {40, 96, 152, 208, 264, 40, 96, 152, 208, 208, 152, 264, 40, 96, 152, 208, 264}; + int diferencia; + + if (frame_pen <= 4) + dir_pendulo = dir_dibujo3; + else if (frame_pen <= 11) + dir_pendulo = dir_hare_dch; + else + dir_pendulo = dir_hare_frente; + + DIBUJA_FONDO(pendulo_x[frame_pen], 19, 152, 0, 55, 125, dir_pendulo, dir_zona_pantalla); + + if (flags[1] == 2) + DIBUJA_BLOQUE(18, 145, 145, 105, 25, 29, dir_dibujo3, dir_zona_pantalla); + + if (flags[1] == 0) + DIBUJA_BLOQUE(44, 145, 145, 105, 25, 29, dir_dibujo3, dir_zona_pantalla); + + diferencia = (int)vez() - conta_ciego_vez; + if (diferencia > 8) { + frame_pen++; + if (frame_pen == 17) + frame_pen = 0; + conta_ciego_vez = (int)vez(); + } +} + +void DrasculaEngine::pantalla_pendulo(int fl) { + if (objeto_que_lleva == MIRAR && fl == 100) + hablar(TEXT452, "452.als"); + else if (objeto_que_lleva == MIRAR && fl == 101) + hablar (TEXT123, "123.als"); + else if (objeto_que_lleva == COGER && fl == 101) + agarra_objeto(20); + else if (objeto_que_lleva == 20 && fl == 100) + animacion_6_6(); + else if (objeto_que_lleva == COGER || objeto_que_lleva == ABRIR) + hablar(TEXT453, "453.als"); + else + hay_respuesta = 0; +} } // End of namespace Drascula diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index d8e49ba930..229e6d71b3 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -419,7 +419,7 @@ public: char alapantallakeva[40][20]; int x_alakeva[40], y_alakeva[40], sentido_alkeva[40], alapuertakeva[40]; int x1[40], y1[40], x2[40], y2[40]; - int lleva_objeto , objeto_que_lleva; + int lleva_objeto, objeto_que_lleva; int con_voces; int menu_bar, menu_scr, hay_nombre; char texto_nombre[20]; @@ -462,7 +462,7 @@ public: int cont_sv; int term_int; int num_ejec; - int cual_ejec, hay_que_load; + int hay_que_load; char nom_partida[13]; int _color; int corta_musica; @@ -497,7 +497,6 @@ public: void animacion_4_1(); void animacion_3_2(); void animacion_4_2(); - void animacion_7(); void animacion_8(); void animacion_9(); void animacion_10(); @@ -508,7 +507,6 @@ public: void animacion_15(); void animacion_16(); void animacion_17(); - void animacion_18(); void animacion_19(); void animacion_20(); void animacion_21(); @@ -527,7 +525,7 @@ public: void animacion_32(); void animacion_33(); void animacion_34(); - void animacion_35(); + void animacion_35_2(); void animacion_36(); void refresca_1_antes(); @@ -553,8 +551,7 @@ public: void sin_verbo(); void para_cargar(char[]); - void carga_escoba_1(const char *); - void carga_escoba_2(const char *); + void carga_escoba(const char *); void borra_pantalla(); void lleva_al_hare(int, int); void mueve_cursor(); @@ -654,6 +651,9 @@ public: int GlobalSpeed; int LastFrame; + int frame_pen; + int flag_tv; + byte *carga_pcx(byte *NamePcc); void set_dac(byte *dac); void WaitForNext(int FPS); @@ -687,9 +687,86 @@ public: void ctvd_speaker(int flag); void ctvd_output(Common::File *file_handle); void ctvd_init(int b); - - - + void grr(); + void pantalla_13(int fl); + void refresca_13(); + void refresca_20(); + void animacion_1_3(); + void animacion_2_3(); + void animacion_3_3(); + void animacion_4_3(); + void animacion_5(); + void animacion_6(); + void animacion_7_4(); + void animacion_rayo(); + void animacion_2_4(); + void animacion_3_4(); + void animacion_4_4(); + void animacion_1_5(); + void animacion_2_5(); + void animacion_3_5(); + void animacion_4_5(); + void animacion_5_5(); + void animacion_6_5(); + void animacion_7_5(); + void animacion_8_5(); + void animacion_9_5(); + void animacion_10_5(); + void animacion_11_5(); + void animacion_12_5(); + void animacion_13_5(); + void animacion_14_5(); + void animacion_15_5(); + void animacion_16_5(); + void animacion_17_5(); + void pantalla_49(int); + void pantalla_53(int); + void pantalla_54(int); + void pantalla_55(int); + void pantalla_56(int); + void refresca_53_antes(); + void refresca_54_antes(); + void refresca_49_antes(); + void refresca_56_antes(); + void refresca_50(); + void refresca_57(); + void habla_igor_sentado(const char *, const char *); + void habla_lobo(const char *dicho, const char *filename); + void habla_mus(const char *dicho, const char *filename); + void pantalla_58(int); + void pantalla_59(int); + void pantalla_60(int); + void pantalla_61(int); + void pantalla_pendulo(int); + void refresca_pendulo(); + void refresca_58(); + void refresca_58_antes(); + void refresca_59_antes(); + void refresca_60_antes(); + void refresca_60(); + void refresca_61(); + void animacion_1_6(); + void animacion_2_6(); + void animacion_3_6(); + void animacion_4_6(); + void animacion_5_6(); + void animacion_6_6(); + void animacion_7_6(); + void animacion_9_6(); + void animacion_10_6(); + void animacion_11_6(); + void animacion_12_6(); + void animacion_13_6(); + void animacion_14_6(); + void animacion_15_6(); + void animacion_18_6(); + void animacion_19_6(); + void activa_pendulo(); + void habla_pen(const char *, const char *); + void habla_pen2(const char *, const char *); + void habla_taber2(const char *, const char *); + void habla_bj_cama(const char *dicho, const char * filename); + void habla_htel(const char *dicho, const char *filename); private: diff --git a/engines/engine.cpp b/engines/engine.cpp index f2b7198510..9750812f5e 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -43,7 +43,7 @@ extern bool isSmartphone(void); #endif -// FIXME - BIG HACK for MidiEmu & error() +// FIXME: HACK for MidiEmu & error() Engine *g_engine = 0; diff --git a/engines/gob/cdrom.cpp b/engines/gob/cdrom.cpp index 2ee8595ad3..1c26199bc1 100644 --- a/engines/gob/cdrom.cpp +++ b/engines/gob/cdrom.cpp @@ -151,40 +151,27 @@ void CDROM::playMultMusic() { } } -void CDROM::startTrack(const char *trackname) { - byte *curPtr, *matchPtr; - +void CDROM::startTrack(const char *trackName) { if (!_LICbuffer) return; - debugC(1, kDebugMusic, "CDROM::startTrack(%s)", trackname); - - matchPtr = 0; - curPtr = _LICbuffer; - - for (int i = 0; i < _numTracks; i++) { - if (!scumm_stricmp((char *)curPtr, trackname)) { - matchPtr = curPtr; - break; - } - curPtr += 22; - } + debugC(1, kDebugMusic, "CDROM::startTrack(%s)", trackName); + byte *matchPtr = getTrackBuffer(trackName); if (!matchPtr) { - warning("Track \"%s\" not found", trackname); + warning("Track \"%s\" not found", trackName); return; } - strncpy0(_curTrack, trackname, 15); + strncpy0(_curTrack, trackName, 15); stopPlaying(); + _curTrackBuffer = matchPtr; - while (getTrackPos() != -1); - - uint32 start, end; + while (getTrackPos() >= 0); - start = READ_LE_UINT32(matchPtr + 12); - end = READ_LE_UINT32(matchPtr + 16); + uint32 start = READ_LE_UINT32(matchPtr + 12); + uint32 end = READ_LE_UINT32(matchPtr + 16); play(start, end); @@ -205,12 +192,27 @@ void CDROM::play(uint32 from, uint32 to) { _cdPlaying = true; } -int32 CDROM::getTrackPos() { - uint32 curPos = _vm->_util->getTimeKey() - _startTime; +int32 CDROM::getTrackPos(const char *keyTrack) { + byte *keyBuffer = getTrackBuffer(keyTrack); + uint32 curPos = (_vm->_util->getTimeKey() - _startTime) * 3 / 40; + + if (_cdPlaying && (_vm->_util->getTimeKey() < _trackStop)) { + if (keyBuffer && _curTrackBuffer && (keyBuffer != _curTrackBuffer)) { + uint32 kStart = READ_LE_UINT32(keyBuffer + 12); + uint32 kEnd = READ_LE_UINT32(keyBuffer + 16); + uint32 cStart = READ_LE_UINT32(_curTrackBuffer + 12); + uint32 cEnd = READ_LE_UINT32(_curTrackBuffer + 16); + + if ((kStart >= cStart) && (kEnd <= cEnd)) { + if ((kStart - cStart) > curPos) + return -2; + if ((kEnd - cStart) < curPos) + return -1; + } + } - if (_cdPlaying && (_vm->_util->getTimeKey() < _trackStop)) - return curPos * 3 / 40; - else + return curPos; + } else return -1; } @@ -227,6 +229,7 @@ void CDROM::stopPlaying() { void CDROM::stop() { debugC(1, kDebugMusic, "CDROM::stop()"); + _curTrackBuffer = 0; AudioCD.stop(); _cdPlaying = false; } @@ -245,4 +248,22 @@ void CDROM::testCD(int trySubst, const char *label) { // CD secor reading } +byte *CDROM::getTrackBuffer(const char *trackName) { + if (!_LICbuffer || !trackName) + return 0; + + byte *matchPtr = 0; + byte *curPtr = _LICbuffer; + + for (int i = 0; i < _numTracks; i++) { + if (!scumm_stricmp((char *) curPtr, trackName)) { + matchPtr = curPtr; + break; + } + curPtr += 22; + } + + return matchPtr; +} + } // End of namespace Gob diff --git a/engines/gob/cdrom.h b/engines/gob/cdrom.h index e977adcd6d..f847addaeb 100644 --- a/engines/gob/cdrom.h +++ b/engines/gob/cdrom.h @@ -35,11 +35,11 @@ public: void readLIC(const char *fname); void freeLICbuffer(); - void startTrack(const char *s); + void startTrack(const char *trackName); void playBgMusic(); void playMultMusic(); void play(uint32 from, uint32 to); - int32 getTrackPos(); + int32 getTrackPos(const char *keyTrack = 0); const char *getCurTrack(); void stopPlaying(); void stop(); @@ -49,11 +49,14 @@ public: protected: byte *_LICbuffer; + byte *_curTrackBuffer; char _curTrack[16]; uint16 _numTracks; uint32 _trackStop; uint32 _startTime; GobEngine *_vm; + + byte *getTrackBuffer(const char *trackName); }; } // End of namespace Gob diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index 16df54d85f..b3056a5ea3 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -885,9 +885,9 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _vidBufferSize = _stream->readUint32LE(); if (_hasVideo) { - if (_frameDataSize == 0) + if ((_frameDataSize == 0) || (_frameDataSize > 1048576)) _frameDataSize = _width * _height + 500; - if (_vidBufferSize == 0) + if ((_vidBufferSize == 0) || (_vidBufferSize > 1048576)) _vidBufferSize = _frameDataSize; _frameData = new byte[_frameDataSize]; @@ -949,7 +949,7 @@ bool Vmd::load(Common::SeekableReadStream &stream) { if (_frames[i].parts[j].type == kPartTypeAudio) { _frames[i].parts[j].flags = _stream->readByte(); - _stream->skip(9); // Unknow + _stream->skip(9); // Unknown } else if (_frames[i].parts[j].type == kPartTypeVideo) { @@ -1068,9 +1068,13 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { // Next sound slice data if (part.flags == 1) { - if (_soundEnabled) + if (_soundEnabled) { filledSoundSlice(part.size); - else + + if (_soundStage == 1) + startSound = true; + + } else _stream->skip(part.size); // Initial sound data (all slices) @@ -1089,11 +1093,17 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { // Empty sound slice } else if (part.flags == 3) { - if (_soundEnabled && (part.size > 0)) - emptySoundSlice(part.size); - else - _stream->skip(part.size); + if (_soundEnabled) { + emptySoundSlice(_soundSliceSize * _soundBytesPerSample); + if (_soundStage == 1) + startSound = true; + } + + _stream->skip(part.size); + } else { + warning("Unknown sound part type %d", part.flags); + _stream->skip(part.size); } } else if (part.type == kPartTypeVideo) { @@ -1252,23 +1262,18 @@ void Vmd::filledSoundSlice(uint32 size) { } void Vmd::filledSoundSlices(uint32 size, uint32 mask) { - if (_soundBytesPerSample == 1) { - soundSlice8bit(size); - return; - } - - for (int i = 0; i < (_soundSlicesCount - 1); i++) { + int n = MIN<int>(_soundSlicesCount - 1, 31); + for (int i = 0; i < n; i++) { if (mask & 1) - emptySoundSlice(_soundSliceSize * 2); - else { - int16 init = _stream->readSint16LE(); - soundSlice16bit(_soundSliceSize, init); - } + emptySoundSlice(_soundSliceSize * _soundBytesPerSample); + else + filledSoundSlice(_soundSliceSize); mask >>= 1; } - + if (_soundSlicesCount > 32) + filledSoundSlice((_soundSlicesCount - 32) * _soundSliceSize); } void Vmd::deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) { diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 361627caf4..7fd461b93c 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -273,28 +273,27 @@ int32 DataIO::readChunk(int16 handle, byte *buf, uint16 size) { file = (handle - 50) / 10; slot = (handle - 50) % 10; - if (!_isCurrentSlot[file * MAX_SLOT_COUNT + slot]) { + int index = file * MAX_SLOT_COUNT + slot; + + _chunkPos[index] = CLIP<int32>(_chunkPos[index], 0, _chunkSize[index]); + + if (!_isCurrentSlot[index]) { for (i = 0; i < MAX_SLOT_COUNT; i++) _isCurrentSlot[file * MAX_SLOT_COUNT + i] = false; - offset = _chunkOffset[file * MAX_SLOT_COUNT + slot] + - _chunkPos[file * MAX_SLOT_COUNT + slot]; + offset = _chunkOffset[index] + _chunkPos[index]; - debugC(7, kDebugFileIO, "seek: %d, %d", - _chunkOffset[file * MAX_SLOT_COUNT + slot], - _chunkPos[file * MAX_SLOT_COUNT + slot]); + debugC(7, kDebugFileIO, "seek: %d, %d", _chunkOffset[index], _chunkPos[index]); file_getHandle(_dataFileHandles[file])->seek(offset, SEEK_SET); } - _isCurrentSlot[file * MAX_SLOT_COUNT + slot] = true; - if ((_chunkPos[file * MAX_SLOT_COUNT + slot] + size) > - (_chunkSize[file * MAX_SLOT_COUNT + slot])) - size = _chunkSize[file * MAX_SLOT_COUNT + slot] - - _chunkPos[file * MAX_SLOT_COUNT + slot]; + _isCurrentSlot[index] = true; + if ((_chunkPos[index] + size) > (_chunkSize[index])) + size = _chunkSize[index] - _chunkPos[index]; file_getHandle(_dataFileHandles[file])->read(buf, size); - _chunkPos[file * MAX_SLOT_COUNT + slot] += size; + _chunkPos[index] += size; return size; } @@ -307,13 +306,15 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { file = (handle - 50) / 10; slot = (handle - 50) % 10; - _isCurrentSlot[file * MAX_SLOT_COUNT + slot] = false; + int index = file * MAX_SLOT_COUNT + slot; + + _isCurrentSlot[index] = false; if (from == SEEK_SET) - _chunkPos[file * MAX_SLOT_COUNT + slot] = pos; + _chunkPos[index] = pos; else - _chunkPos[file * MAX_SLOT_COUNT + slot] += pos; + _chunkPos[index] += pos; - return _chunkPos[file * MAX_SLOT_COUNT + slot]; + return _chunkPos[index]; } uint32 DataIO::getChunkPos(int16 handle) const { diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 7faef57cc1..bfd2a0edfc 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -955,6 +955,19 @@ static const GOBGameDescription gameDescriptions[] = { }, { { + "lostintime", + "Demo", + AD_ENTRY1("demo.stk", "c06f8cc20eb239d4c71f225ce3093edf"), + UNK_LANG, + kPlatformPC, + Common::ADGF_DEMO + }, + kGameTypeLostInTime, + kFeaturesAdlib, + "demo" + }, + { + { "gob3", "", AD_ENTRY1s("intro.stk", "32b0f57f5ae79a9ae97e8011df38af42", 157084), diff --git a/engines/gob/driver_vga.cpp b/engines/gob/driver_vga.cpp index 13e6aca4a8..ef1c9c328c 100644 --- a/engines/gob/driver_vga.cpp +++ b/engines/gob/driver_vga.cpp @@ -113,18 +113,23 @@ void VGAVideoDriver::drawSprite(SurfaceDesc *source, SurfaceDesc *dest, byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left; byte *destPos = dest->getVidMem() + (y * dest->getWidth()) + x; - while (height--) { - if (transp) { + if (transp) { + while (height--) { for (int16 i = 0; i < width; ++i) { if (srcPos[i]) destPos[i] = srcPos[i]; - } - } else - for (int16 i = 0; i < width; ++i) - destPos[i] = srcPos[i]; + } + + srcPos += source->getWidth(); + destPos += dest->getWidth(); + } + } else { + while (height--) { + memcpy(destPos, srcPos, width); - srcPos += source->getWidth(); - destPos += dest->getWidth(); + srcPos += source->getWidth(); + destPos += dest->getWidth(); + } } } diff --git a/engines/gob/game_v1.cpp b/engines/gob/game_v1.cpp index 9c18ec1151..3f681ddd1f 100644 --- a/engines/gob/game_v1.cpp +++ b/engines/gob/game_v1.cpp @@ -345,6 +345,7 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, int16 oldIndex; int16 oldId; uint32 timeKey; + bool firstIteration = true; if (deltaTime >= -1) { _lastCollKey = 0; @@ -357,6 +358,8 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, resIndex = 0; + timeKey = _vm->_util->getTimeKey(); + if ((_vm->_draw->_cursorIndex == -1) && (handleMouse != 0) && (_lastCollKey == 0)) { _lastCollKey = checkMousePoint(1, &_lastCollId, &_lastCollAreaIndex); @@ -374,7 +377,6 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, if (handleMouse != 0) _vm->_draw->animateCursor(-1); - timeKey = _vm->_util->getTimeKey(); while (1) { if (_vm->_inter->_terminate) { if (handleMouse) @@ -397,7 +399,7 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, // and the return value is then discarded. if (deltaTime < 0) { uint32 curtime = _vm->_util->getTimeKey(); - if ((deltaTime == -1) || ((curtime + deltaTime) > timeKey)) { + if ((deltaTime == -1) || (((curtime + deltaTime) > timeKey) && !firstIteration)) { if (pResId != 0) *pResId = 0; @@ -538,7 +540,10 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, if (handleMouse != 0) _vm->_draw->animateCursor(-1); - _vm->_util->delay(10); + if (deltaTime < -10) + _vm->_util->delay(10); + + firstIteration = false; } } @@ -617,7 +622,7 @@ void Game_v1::collisionsBlock(void) { int16 var_26; int16 collStackPos; Collision *collPtr; - int16 timeKey; + uint32 timeKey; byte *savedIP; if (_shouldPushColls) @@ -910,9 +915,9 @@ void Game_v1::collisionsBlock(void) { _shouldPushColls = 0; _vm->_global->_inter_execPtr = savedIP; + deltaTime = timeVal - - ((_vm->_util->getTimeKey() - timeKey) - - _vm->_video->_lastRetraceLength); + (_vm->_util->getTimeKey() - timeKey); if (deltaTime < 2) deltaTime = 2; diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index 7e87b9e8f8..8a528a96f5 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -1259,7 +1259,7 @@ int16 Game_v2::multiEdit(int16 time, int16 index, int16 *pCurPos, if ((collArea->left > _vm->_global->_inter_mouseX) || (collArea->right < _vm->_global->_inter_mouseX) || (collArea->top > _vm->_global->_inter_mouseY) || - (collArea->bottom < _vm->_global->_inter_mouseY)); + (collArea->bottom < _vm->_global->_inter_mouseY)) continue; if ((collArea->id & 0xF000)) diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index d9385b1b0f..8dee9c9e32 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -333,7 +333,7 @@ bool GobEngine::initGameParts() { _mult = new Mult_v2(this); _draw = new Draw_v2(this); _game = new Game_v2(this); - _map = new Map_v2(this); + _map = new Map_v4(this); _goblin = new Goblin_v3(this); _scenery = new Scenery_v2(this); _saveLoad = new SaveLoad_v3(this, _targetName.c_str()); @@ -349,8 +349,6 @@ bool GobEngine::initGameParts() { if (!_noMusic && hasAdlib()) _adlib = new Adlib(this); - _map->init(); - if (is640()) { _video->_surfWidth = _width = 640; _video->_surfHeight = _video->_splitHeight1 = _height = 480; diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index 4712a19a5d..1c6d7faa3b 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -60,14 +60,23 @@ void Init::initGame(const char *totName) { int16 handle2; int16 handle; int16 imdHandle; - char *infBuf; + byte *infBuf; char *infPtr; char *infEnd; - char buffer[20]; + char buffer[128]; int32 varsCount; initVideo(); + // The Lost In Time demo uses different file prefix + if (_vm->getGameType() == kGameTypeLostInTime) { + handle2 = _vm->_dataIO->openData("demo.stk"); + if (handle2 >= 0) { + _vm->_dataIO->closeData(handle2); + _vm->_dataIO->openDataFile("demo.stk"); + } + } + handle2 = _vm->_dataIO->openData("intro.stk"); if (handle2 >= 0) { _vm->_dataIO->closeData(handle2); @@ -111,10 +120,10 @@ void Init::initGame(const char *totName) { } else { _vm->_dataIO->closeData(handle); - infPtr = (char *) _vm->_dataIO->getData("intro.inf"); - infBuf = infPtr; + infBuf = _vm->_dataIO->getData("intro.inf"); + infPtr = (char *) infBuf; - infEnd = infBuf + _vm->_dataIO->getDataSize("intro.inf"); + infEnd = (char *) (infBuf + _vm->_dataIO->getDataSize("intro.inf")); for (int i = 0; i < 4; i++, infPtr++) { int j; diff --git a/engines/gob/init_v3.cpp b/engines/gob/init_v3.cpp index 6f1af258ca..61e7fb61d0 100644 --- a/engines/gob/init_v3.cpp +++ b/engines/gob/init_v3.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/gob/init_v3.cpp $ - * $Id:init_v3.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 376aef75d9..b2ca8716be 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -1105,7 +1105,7 @@ void Inter_v2::o2_getCDTrackPos() { varPos = _vm->_parse->parseVarIndex(); varName = _vm->_parse->parseVarIndex(); - WRITE_VAR_OFFSET(varPos, _vm->_cdrom->getTrackPos()); + WRITE_VAR_OFFSET(varPos, _vm->_cdrom->getTrackPos(GET_VARO_STR(varName))); WRITE_VARO_STR(varName, _vm->_cdrom->getCurTrack()); } @@ -1561,7 +1561,8 @@ void Inter_v2::o2_openItk() { evalExpr(0); strncpy0(fileName, _vm->_global->_inter_resStr, 27); - strcat(fileName, ".ITK"); + if (!strchr(fileName, '.')) + strcat(fileName, ".ITK"); _vm->_dataIO->openDataFile(fileName, true); } diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp index 5485d66987..d467348039 100644 --- a/engines/gob/map.cpp +++ b/engines/gob/map.cpp @@ -34,9 +34,11 @@ namespace Gob { Map::Map(GobEngine *vm) : _vm(vm) { + _widthByte = 0; _mapWidth = -1; _mapHeight = -1; _screenWidth = 0; + _screenHeight = 0; _tilesWidth = 0; _tilesHeight = 0; _passWidth = 0; diff --git a/engines/gob/map.h b/engines/gob/map.h index 0e0a80aad3..acfe8b675e 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -63,9 +63,11 @@ public: #include "common/pack-end.h" // END STRUCT PACKING + byte _widthByte; int16 _mapWidth; int16 _mapHeight; int16 _screenWidth; + int16 _screenHeight; int16 _tilesWidth; int16 _tilesHeight; int16 _passWidth; @@ -107,7 +109,6 @@ public: virtual void findNearestToDest(Mult::Mult_Object *obj) = 0; virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y) = 0; - virtual void init(void) = 0; Map(GobEngine *vm); virtual ~Map(); @@ -127,18 +128,24 @@ public: virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y); virtual int8 getPass(int x, int y, int heightOff = -1) { + if (!_passMap) + return 0; + return _passMap[y * _mapWidth + x]; } virtual void setPass(int x, int y, int8 pass, int heightOff = -1) { + if (!_passMap) + return; + _passMap[y * _mapWidth + x] = pass; } - virtual void init(void); Map_v1(GobEngine *vm); virtual ~Map_v1(); protected: + void init(void); void loadSounds(Common::SeekableReadStream &data); void loadGoblins(Common::SeekableReadStream &data, uint32 gobsPos); void loadObjects(Common::SeekableReadStream &data, uint32 objsPos); @@ -153,18 +160,23 @@ public: virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y); virtual int8 getPass(int x, int y, int heightOff = -1) { + if (!_passMap) + return 0; + if (heightOff == -1) heightOff = _passWidth; return _passMap[y * heightOff + x]; } virtual void setPass(int x, int y, int8 pass, int heightOff = -1) { + if (!_passMap) + return; + if (heightOff == -1) heightOff = _passWidth; _passMap[y * heightOff + x] = pass; } - virtual void init(void); Map_v2(GobEngine *vm); virtual ~Map_v2(); @@ -172,6 +184,14 @@ protected: void loadGoblinStates(Common::SeekableReadStream &data, int index); }; +class Map_v4 : public Map_v2 { +public: + virtual void loadMapObjects(const char *avjFile); + + Map_v4(GobEngine *vm); + virtual ~Map_v4(); +}; + } // End of namespace Gob #endif // GOB_MAP_H diff --git a/engines/gob/map_v1.cpp b/engines/gob/map_v1.cpp index c5a2622e44..7134527592 100644 --- a/engines/gob/map_v1.cpp +++ b/engines/gob/map_v1.cpp @@ -42,6 +42,9 @@ Map_v1::~Map_v1() { } void Map_v1::init(void) { + if (_passMap || _itemsMap) + return; + _mapWidth = 26; _mapHeight = 28; @@ -84,6 +87,8 @@ void Map_v1::loadMapObjects(const char *avjFile) { } Common::MemoryReadStream mapData(dataBuf, 4294967295U); + init(); + if (_loadFromAvo) { mapData.read(_passMap, _mapHeight * _mapWidth); diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp index e1ed11c607..5133ac1286 100644 --- a/engines/gob/map_v2.cpp +++ b/engines/gob/map_v2.cpp @@ -38,15 +38,13 @@ namespace Gob { Map_v2::Map_v2(GobEngine *vm) : Map_v1(vm) { + _screenHeight = 200; } Map_v2::~Map_v2() { _passMap = 0; } -void Map_v2::init(void) { -} - void Map_v2::loadMapObjects(const char *avjFile) { uint8 wayPointsCount; int16 var; @@ -86,7 +84,7 @@ void Map_v2::loadMapObjects(const char *avjFile) { _tilesHeight &= 0xFF; _mapWidth = _screenWidth / _tilesWidth; - _mapHeight = 200 / _tilesHeight; + _mapHeight = _screenHeight / _tilesHeight; passPos = mapData.pos(); mapData.skip(_mapWidth * _mapHeight); @@ -96,9 +94,7 @@ void Map_v2::loadMapObjects(const char *avjFile) { else wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount; - if (_wayPoints) - delete[] _wayPoints; - + delete[] _wayPoints; _wayPoints = new Point[wayPointsCount]; for (int i = 0; i < _wayPointsCount; i++) { _wayPoints[i].x = mapData.readSByte(); @@ -113,7 +109,7 @@ void Map_v2::loadMapObjects(const char *avjFile) { byte *sizes; _passMap = (int8 *) variables; - mapHeight = 200 / _tilesHeight; + mapHeight = _screenHeight / _tilesHeight; mapWidth = _screenWidth / _tilesWidth; sizes = _vm->_global->_inter_variablesSizes + (((byte *) _passMap) - _vm->_global->_inter_variables); diff --git a/engines/gob/map_v4.cpp b/engines/gob/map_v4.cpp new file mode 100644 index 0000000000..fb398ecbaf --- /dev/null +++ b/engines/gob/map_v4.cpp @@ -0,0 +1,158 @@ +/* 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/stdafx.h" +#include "common/stream.h" + +#include "gob/gob.h" +#include "gob/map.h" +#include "gob/global.h" +#include "gob/goblin.h" +#include "gob/inter.h" +#include "gob/game.h" +#include "gob/parse.h" +#include "gob/mult.h" + +namespace Gob { + +Map_v4::Map_v4(GobEngine *vm) : Map_v2(vm) { +} + +Map_v4::~Map_v4() { +} + +void Map_v4::loadMapObjects(const char *avjFile) { + uint8 wayPointsCount; + int16 var; + int16 id; + int16 mapWidth, mapHeight; + int16 tmp; + byte *variables; + byte *extData; + uint32 tmpPos; + uint32 passPos; + + var = _vm->_parse->parseVarIndex(); + variables = _vm->_global->_inter_variables + var; + + id = _vm->_inter->load16(); + + if (((uint16) id) >= 65520) { + warning("Woodruff Stub: loadMapObjects ID >= 65520"); + return; + } else if (id == -1) { + _passMap = (int8 *)(_vm->_global->_inter_variables + var); + return; + } + + extData = _vm->_game->loadExtData(id, 0, 0); + Common::MemoryReadStream mapData(extData, 4294967295U); + + _widthByte = mapData.readByte(); + if (_widthByte == 4) { + _screenWidth = 640; + _screenHeight = 400; + } else if (_widthByte == 3) { + _screenWidth = 640; + _screenHeight = 200; + } else { + _screenWidth = 320; + _screenHeight = 200; + } + + _wayPointsCount = mapData.readByte(); + _tilesWidth = mapData.readSint16LE(); + _tilesHeight = mapData.readSint16LE(); + + _bigTiles = !(_tilesHeight & 0xFF00); + _tilesHeight &= 0xFF; + + if (_widthByte == 4) { + _screenWidth = mapData.readSint16LE(); + _screenHeight = mapData.readSint16LE(); + } + + _mapWidth = _screenWidth / _tilesWidth; + _mapHeight = _screenHeight / _tilesHeight; + + passPos = mapData.pos(); + mapData.skip(_mapWidth * _mapHeight); + + if (*extData == 1) + wayPointsCount = _wayPointsCount = 40; + else + wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount; + + delete[] _wayPoints; + _wayPoints = new Point[wayPointsCount]; + for (int i = 0; i < _wayPointsCount; i++) { + _wayPoints[i].x = mapData.readSByte(); + _wayPoints[i].y = mapData.readSByte(); + _wayPoints[i].notWalkable = mapData.readSByte(); + } + + if (_widthByte == 4) + _mapWidth = (int16) READ_VARO_UINT16(68); + + _passWidth = _mapWidth; + + // In the original asm, this writes byte-wise into the variables-array + tmpPos = mapData.pos(); + mapData.seek(passPos); + if (variables != _vm->_global->_inter_variables) { + byte *sizes; + + _passMap = (int8 *) variables; + mapHeight = _screenHeight / _tilesHeight; + mapWidth = _screenWidth / _tilesWidth; + sizes = _vm->_global->_inter_variablesSizes + + (((byte *) _passMap) - _vm->_global->_inter_variables); + for (int i = 0; i < mapHeight; i++) { + for (int j = 0; j < mapWidth; j++) + setPass(j, i, mapData.readSByte()); + memset(sizes + i * _passWidth, 0, mapWidth); + } + } + mapData.seek(tmpPos); + + tmp = mapData.readSint16LE(); + mapData.skip(tmp * 14); + tmp = mapData.readSint16LE(); + mapData.skip(tmp * 14 + 28); + tmp = mapData.readSint16LE(); + mapData.skip(tmp * 14); + + _vm->_goblin->_gobsCount = tmp; + for (int i = 0; i < _vm->_goblin->_gobsCount; i++) + loadGoblinStates(mapData, i); + + _vm->_goblin->_soundSlotsCount = _vm->_inter->load16(); + for (int i = 0; i < _vm->_goblin->_soundSlotsCount; i++) + _vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1); + + delete[] extData; +} + +} // End of namespace Gob diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 7571853f27..b51de90656 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -33,6 +33,7 @@ MODULE_OBJS := \ map.o \ map_v1.o \ map_v2.o \ + map_v4.o \ mult.o \ mult_v1.o \ mult_v2.o \ diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index cced4aac63..ddce90df0c 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -259,8 +259,11 @@ void Mult_v2::loadImds(Common::SeekableReadStream &data) { return; size = data.readSint16LE(); - _multData->somepointer10 = new char[size * 20]; - data.read(_multData->somepointer10, size * 20); + if (size > 0) { + _multData->somepointer10 = new char[size * 20]; + data.read(_multData->somepointer10, size * 20); + } + size = _vm->_inter->load16(); if (size <= 0) return; @@ -474,12 +477,11 @@ void Mult_v2::multSub(uint16 multIndex) { } if (_multData->animDirection == -1) { - for (int i = 0; i < _multData->imdKeysCount[i]; i++) { - if (_multData->imdKeys[index][i].frame > startFrame) - break; + int i = 0; + while (_multData->imdKeys[index][i].frame <= startFrame) + i++; - _multData->imdIndices[index] = i - 1; - } + _multData->imdIndices[index] = i - 1; } firstFrame = (_multData->animDirection == 1) ? startFrame : stopFrame; @@ -1091,15 +1093,11 @@ void Mult_v2::advanceObjects(int16 index) { for (int i = 0; i < 4; i++) { int obj = _multData->animObjs[index][i]; - if (_multData->animObjs[index][i] != -1) { + if ((obj != -1) && (obj != 1024)) { int keyIndex = _multData->animKeysIndices[index][i]; int count = _multData->animKeysCount[i]; for (int j = keyIndex; j < count; j++) { - - if ((obj == -1) || (obj == 1024)) - continue; - Mult_AnimKey &key = _multData->animKeys[i][j]; Mult_Object &animObj = _objects[obj]; Mult_AnimData &animData = *(animObj.pAnimData); @@ -1161,7 +1159,7 @@ void Mult_v2::advanceObjects(int16 index) { _multData->imdIndices[1] = -1; _multData->imdIndices[2] = -1; _multData->imdIndices[3] = -1; - if ((_multData->animDirection == 1) || (key2.imdFile == 1)) + if ((_multData->animDirection == 1) || (key2.imdFile == -1)) _multData->imdIndices[i] = j; else if (_multData->animKeysStopFrames[index] == frame) _multData->imdIndices[i] = -1; @@ -1187,7 +1185,8 @@ void Mult_v2::advanceObjects(int16 index) { imdFile = _multData->imdFiles + fileN * 14; dir = _multData->animDirection; startFrame = frame - key.frame; - if ((dir != 1) && (--startFrame > 0)) + + if ((dir != 1) && (--startFrame < 0)) startFrame = 0; hasImds = true; diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp index f4cb7bcf7a..ea22ede7b6 100644 --- a/engines/gob/saveload.cpp +++ b/engines/gob/saveload.cpp @@ -62,9 +62,11 @@ SaveLoad::SaveLoad(GobEngine *vm, const char *targetName) : _vm(vm) { } SaveLoad::~SaveLoad() { - for (int i = 0; i < _stagesCount; i++) - delete[] _buffer[i]; - delete[] _buffer; + if (_buffer) { + for (int i = 0; i < _stagesCount; i++) + delete[] _buffer[i]; + delete[] _buffer; + } delete _tempSprite; diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h index d7e45246ad..84a6a643e9 100644 --- a/engines/gob/saveload.h +++ b/engines/gob/saveload.h @@ -130,6 +130,8 @@ protected: virtual bool saveGame(int16 dataVar, int32 size, int32 offset); virtual bool saveNotes(int16 dataVar, int32 size, int32 offset); virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset); + + void initBuffer(); }; class SaveLoad_v3 : public SaveLoad_v2 { @@ -160,6 +162,7 @@ protected: virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset); bool saveGame(int32 screenshotSize); + void initBuffer(); }; } // End of namespace Gob diff --git a/engines/gob/saveload_v2.cpp b/engines/gob/saveload_v2.cpp index 13f23cccb6..b8d8d44557 100644 --- a/engines/gob/saveload_v2.cpp +++ b/engines/gob/saveload_v2.cpp @@ -38,12 +38,6 @@ SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : SaveLoad(vm, targetName) { _stagesCount = 1; - - _buffer = new byte*[_stagesCount]; - - assert(_buffer); - - _buffer[0] = 0; } SaveType SaveLoad_v2::getSaveType(const char *fileName) { @@ -190,6 +184,8 @@ bool SaveLoad_v2::loadScreenshot(int16 dataVar, int32 size, int32 offset) { bool SaveLoad_v2::saveGame(int16 dataVar, int32 size, int32 offset) { int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + initBuffer(); + if (size == 0) { dataVar = 0; size = varSize; @@ -289,4 +285,13 @@ bool SaveLoad_v2::saveScreenshot(int16 dataVar, int32 size, int32 offset) { return false; } +void SaveLoad_v2::initBuffer() { + if (_buffer) + return; + + _buffer = new byte*[_stagesCount]; + assert(_buffer); + _buffer[0] = 0; +} + } // End of namespace Gob diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp index d0f791d8df..f8f69342fe 100644 --- a/engines/gob/saveload_v3.cpp +++ b/engines/gob/saveload_v3.cpp @@ -45,19 +45,6 @@ SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, _saveSlot = -1; _stagesCount = 3; - _buffer = new byte*[_stagesCount]; - - assert(_buffer); - - _buffer[0] = new byte[1000]; - _buffer[1] = new byte[1200]; - _buffer[2] = 0; - - assert(_buffer[0] && _buffer[1]); - - memset(_buffer[0], 0, 1000); - memset(_buffer[1], 0, 1200); - _useScreenshots = false; _firstSizeGame = true; } @@ -146,6 +133,8 @@ bool SaveLoad_v3::loadGame(int16 dataVar, int32 size, int32 offset) { int slot = (offset - 1700) / varSize; int slotR = (offset - 1700) % varSize; + initBuffer(); + if ((size > 0) && (offset < 500) && ((size + offset) <= 500)) { memcpy(_vm->_global->_inter_variables + dataVar, @@ -279,6 +268,8 @@ bool SaveLoad_v3::saveGame(int16 dataVar, int32 size, int32 offset) { int slot = (offset - 1700) / varSize; int slotR = (offset - 1700) % varSize; + initBuffer(); + if ((size > 0) && (offset < 500) && ((size + offset) <= 500)) { memcpy(_buffer[0] + offset, @@ -360,6 +351,8 @@ bool SaveLoad_v3::saveGame(int32 screenshotSize) { _saveSlot = -1; + initBuffer(); + if ((slot < 0) || (slot > 29)) { warning("Can't save to slot %d: Out of range", slot); delete[] _buffer[2]; @@ -433,4 +426,22 @@ bool SaveLoad_v3::saveGame(int32 screenshotSize) { return true; } +void SaveLoad_v3::initBuffer() { + if (_buffer) + return; + + _buffer = new byte*[_stagesCount]; + + assert(_buffer); + + _buffer[0] = new byte[1000]; + _buffer[1] = new byte[1200]; + _buffer[2] = 0; + + assert(_buffer[0] && _buffer[1]); + + memset(_buffer[0], 0, 1000); + memset(_buffer[1], 0, 1200); +} + } // End of namespace Gob diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp index 0dc15a8657..ffedd6d1f6 100644 --- a/engines/gob/video.cpp +++ b/engines/gob/video.cpp @@ -94,7 +94,6 @@ Video::Video(GobEngine *vm) : _vm(vm) { _splitHeight1 = 200; _splitHeight2 = 0; _splitStart = 0; - _lastRetraceLength = 0; _curSparse = 0; _lastSparse = 0xFFFFFFFF; @@ -162,8 +161,6 @@ SurfaceDesc *Video::initSurfDesc(int16 vidMode, int16 width, int16 height, } void Video::retrace(bool mouse) { - uint32 time = _vm->_util->getTimeKey(); - if (mouse) CursorMan.showMouse((_vm->_draw->_showCursor & 2) != 0); if (_vm->_global->_primarySurfDesc) { @@ -176,13 +173,12 @@ void Video::retrace(bool mouse) { _vm->_height - _splitHeight2, _vm->_width, _splitHeight2); g_system->updateScreen(); } - - _lastRetraceLength = _vm->_util->getTimeKey() - time; } void Video::waitRetrace(bool mouse) { + uint32 time = _vm->_util->getTimeKey(); retrace(mouse); - _vm->_util->delay(MAX(1, 10 - (int) _lastRetraceLength)); + _vm->_util->delay(MAX(1, 10 - (int)(_vm->_util->getTimeKey() - time))); } void Video::sparseRetrace(int max) { diff --git a/engines/gob/video.h b/engines/gob/video.h index dc23bda81e..51d02bd219 100644 --- a/engines/gob/video.h +++ b/engines/gob/video.h @@ -104,7 +104,6 @@ public: int16 _splitHeight1; int16 _splitHeight2; int16 _splitStart; - uint32 _lastRetraceLength; void freeDriver(); void initPrimary(int16 mode); diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index e72354a169..5d31c31b7b 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -53,7 +53,13 @@ bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Ty strncpy0(fileName, video, 250); - char *extStart = strchr(fileName, '.'); + char *extStart = strrchr(fileName, '.'); + // There's no empty extension + if (extStart == (fileName + strlen(fileName) - 1)) { + *extStart = 0; + extStart = 0; + } + if (extStart) { // The requested file already has an extension. Verifying. @@ -132,7 +138,7 @@ bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Ty return false; } - _video->setXY(x, y); + strcpy(_curFile, fileName); if (!(flags & kFlagNoVideo)) { _backSurf = ((flags & kFlagFrontSurface) == 0); @@ -147,6 +153,7 @@ bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Ty if (!_video) return false; + _video->setXY(x, y); WRITE_VAR(7, _video->getFramesCount()); return true; @@ -170,8 +177,12 @@ void VideoPlayer::play(int16 startFrame, int16 lastFrame, int16 breakKey, endFrame = lastFrame; palCmd &= 0x3F; - if (_video->getCurrentFrame() != startFrame) - _video->seekFrame(startFrame); + if (_video->getCurrentFrame() != startFrame) { + if (_video->getFeatures() & CoktelVideo::kFeaturesSound) + startFrame = _video->getCurrentFrame(); + else + _video->seekFrame(startFrame); + } _vm->_draw->_showCursor = 0; _vm->_util->setFrameRate(12); @@ -328,6 +339,7 @@ void VideoPlayer::closeVideo() { _video = 0; _stream = 0; + *_curFile = 0; } } // End of namespace Gob diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 02b505b177..58622b3514 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ */ #include "kyra/kyra.h" @@ -55,37 +55,315 @@ namespace { #define KYRA3_CD_FLAGS FLAGS(false, false, true, false, Kyra::GI_KYRA3) const KYRAGameDescription adGameDescs[] = { - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "3c244298395520bb62b5edfe41688879"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "796e44863dd22fa635b042df1bf16673"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "abf8eb360e79a6c2a837751fbd4d3d24"), Common::FR_FRA, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "6018e1dfeaca7fe83f8d0b00eb0dd049"), Common::DE_DEU, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "f0b276781f47c130f423ec9679fe9ed9"), Common::DE_DEU, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, // from Arne.F - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "8909b41596913b3f5deaf3c9f1017b01"), Common::ES_ESP, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, // from VooD - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "747861d2a9c643c59fdab570df5b9093"), Common::ES_ESP, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, // floppy 1.8 from clemmy - { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "ef08c8c237ee1473fd52578303fc36df"), Common::IT_ITA, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_FLOPPY_FLAGS }, // from gourry + { + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "3c244298395520bb62b5edfe41688879"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "796e44863dd22fa635b042df1bf16673"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "abf8eb360e79a6c2a837751fbd4d3d24"), + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "6018e1dfeaca7fe83f8d0b00eb0dd049"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { // from Arne.F + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "f0b276781f47c130f423ec9679fe9ed9"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { // from VooD + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "8909b41596913b3f5deaf3c9f1017b01"), + Common::ES_ESP, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { // floppy 1.8 from clemmy + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "747861d2a9c643c59fdab570df5b9093"), + Common::ES_ESP, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + { // from gourry + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.EMC", "ef08c8c237ee1473fd52578303fc36df"), + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + + { + { + "kyra1", + 0, + AD_ENTRY1("GEMCUT.PAK", "2bd1da653eaefd691e050e4a9eb68a64"), + Common::EN_ANY, + Common::kPlatformAmiga, + Common::ADGF_NO_FLAGS + }, + KYRA1_AMIGA_FLAGS + }, + + { + { + "kyra1", + 0, + { + { "GEMCUT.EMC", 0, "796e44863dd22fa635b042df1bf16673", -1 }, + { "BEAD.CPS", 0, "3038466f65b7751451844707187aa401", -1 }, + { NULL, 0, NULL, 0 } + }, + Common::EN_ANY, + Common::kPlatformMacintosh, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_FLAGS + }, + + { // FM-Towns version + { + "kyra1", + 0, + AD_ENTRY1("TWMUSIC.PAK", "e53bca3a3e3fb49107d59463ec387a59"), + Common::EN_ANY, + Common::kPlatformFMTowns, + Common::ADGF_NO_FLAGS + }, + KYRA1_TOWNS_FLAGS + }, + { + { + "kyra1", + 0, + AD_ENTRY1("TWMUSIC.PAK", "e53bca3a3e3fb49107d59463ec387a59"), + Common::JA_JPN, + Common::kPlatformFMTowns, + Common::ADGF_NO_FLAGS + }, + KYRA1_TOWNS_SJIS_FLAGS + }, + + { // PC-9821 version + { + "kyra1", + 0, + { + { "EMC.PAK", 0, "a046bb0b422061aab8e4c4689400343a", -1 }, + { "MUSIC98.PAK", 0, "02fc212f799331b769b274e33d87b37f", -1 }, + { NULL, 0, NULL, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + KYRA1_TOWNS_FLAGS + }, + { + { + "kyra1", + 0, + { + { "JMC.PAK", 0, "9c5707a2a478e8167e44283246612d2c", -1 }, + { "MUSIC98.PAK", 0, "02fc212f799331b769b274e33d87b37f", -1 }, + { NULL, 0, NULL, 0 } + }, + Common::JA_JPN, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + KYRA1_TOWNS_SJIS_FLAGS + }, + + { + { + "kyra1", + "CD", + AD_ENTRY1("GEMCUT.PAK", "fac399fe62f98671e56a005c5e94e39f"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_CD_FLAGS + }, + { + { + "kyra1", + "CD", + AD_ENTRY1("GEMCUT.PAK", "230f54e6afc007ab4117159181a1c722"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_CD_FLAGS + }, + { + { + "kyra1", + "CD", + AD_ENTRY1("GEMCUT.PAK", "b037c41768b652a040360ffa3556fd2a"), + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_CD_FLAGS + }, + + { // italian fan translation see fr#1727941 "KYRA: add Italian CD Version to kyra.dat" + { + "kyra1", + "CD", + AD_ENTRY1("GEMCUT.PAK", "d8327fc4b7a72b23c900fa13aef4093a"), + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_CD_FLAGS + }, + + { + { + "kyra1", + "Demo", + AD_ENTRY1("DEMO1.WSA", "fb722947d94897512b13b50cc84fd648"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_DEMO + }, + KYRA1_DEMO_FLAGS + }, + + { // CD version + { + "kyra2", + 0, + AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_CD_FLAGS + }, + { // CD version + { + "kyra2", + 0, + AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_CD_FLAGS + }, + { // CD version + { + "kyra2", + 0, + AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_CD_FLAGS + }, + + { + { + "kyra2", + "Demo", + AD_ENTRY1("GENERAL.PAK", "35825783e5b60755fd520360079f9c15"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_DEMO + }, + KYRA2_DEMO_FLAGS + }, + + { + { + "kyra3", + 0, + AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA3_CD_FLAGS + }, + { + { + "kyra3", + 0, + AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA3_CD_FLAGS + }, + { + { + "kyra3", + 0, + AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA3_CD_FLAGS + }, - { { "kyra1", 0, AD_ENTRY1("GEMCUT.PAK", "2bd1da653eaefd691e050e4a9eb68a64"), Common::EN_ANY, Common::kPlatformAmiga, Common::ADGF_NO_FLAGS }, KYRA1_AMIGA_FLAGS }, - - { { "kyra1", 0, AD_ENTRY1("TWMUSIC.PAK", "e53bca3a3e3fb49107d59463ec387a59"), Common::EN_ANY, Common::kPlatformFMTowns, Common::ADGF_NO_FLAGS }, KYRA1_TOWNS_FLAGS }, - { { "kyra1", 0, AD_ENTRY1("TWMUSIC.PAK", "e53bca3a3e3fb49107d59463ec387a59"), Common::JA_JPN, Common::kPlatformFMTowns, Common::ADGF_NO_FLAGS }, KYRA1_TOWNS_SJIS_FLAGS }, - - { { "kyra1", "CD", AD_ENTRY1("GEMCUT.PAK", "fac399fe62f98671e56a005c5e94e39f"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_CD_FLAGS }, - { { "kyra1", "CD", AD_ENTRY1("GEMCUT.PAK", "230f54e6afc007ab4117159181a1c722"), Common::DE_DEU, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_CD_FLAGS }, - { { "kyra1", "CD", AD_ENTRY1("GEMCUT.PAK", "b037c41768b652a040360ffa3556fd2a"), Common::FR_FRA, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_CD_FLAGS }, - - { { "kyra1", "CD", AD_ENTRY1("GEMCUT.PAK", "d8327fc4b7a72b23c900fa13aef4093a"), Common::IT_ITA, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA1_CD_FLAGS }, // italian fan translation see fr#1727941 "KYRA: add Italian CD Version to kyra.dat" - - { { "kyra1", "Demo", AD_ENTRY1("DEMO1.WSA", "fb722947d94897512b13b50cc84fd648"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_DEMO }, KYRA1_DEMO_FLAGS }, - - { { "kyra2", 0, AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA2_CD_FLAGS }, // CD version - { { "kyra2", 0, AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), Common::DE_DEU, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA2_CD_FLAGS }, // CD version - { { "kyra2", 0, AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), Common::FR_FRA, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA2_CD_FLAGS }, // CD version - - { { "kyra2", "Demo", AD_ENTRY1("GENERAL.PAK", "35825783e5b60755fd520360079f9c15"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_DEMO }, KYRA2_DEMO_FLAGS }, - - { { "kyra3", 0, AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA3_CD_FLAGS }, - { { "kyra3", 0, AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), Common::DE_DEU, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA3_CD_FLAGS }, - { { "kyra3", 0, AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), Common::FR_FRA, Common::kPlatformPC, Common::ADGF_NO_FLAGS }, KYRA3_CD_FLAGS }, { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0) } }; @@ -119,29 +397,9 @@ const Common::ADParams detectionParams = { } // End of anonymous namespace -GameList Engine_KYRA_gameIDList() { - return GameList(gameList); -} - -GameDescriptor Engine_KYRA_findGameID(const char *gameid) { - return Common::AdvancedDetector::findGameID(gameid, gameList); -} - -GameList Engine_KYRA_detectGames(const FSList &fslist) { - return Common::AdvancedDetector::detectAllGames(fslist, detectionParams); -} - -PluginError Engine_KYRA_create(OSystem *syst, Engine **engine) { - assert(engine); - const char *gameid = ConfMan.get("gameid").c_str(); - - Common::EncapsulatedADGameDesc encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); +bool engineCreateKyra(OSystem *syst, Engine **engine, Common::EncapsulatedADGameDesc encapsulatedDesc) { const KYRAGameDescription *gd = (const KYRAGameDescription *)(encapsulatedDesc.realDesc); - - if (gd == 0) { - // maybe add non md5 based detection again? - return kNoGameDataFoundError; - } + bool res = true; Kyra::GameFlags flags = gd->flags; @@ -160,17 +418,25 @@ PluginError Engine_KYRA_create(OSystem *syst, Engine **engine) { flags.lang = Common::EN_ANY; } - if (!scumm_stricmp("kyra1", gameid)) { + switch (flags.gameID) { + case Kyra::GI_KYRA1: *engine = new Kyra::KyraEngine_v1(syst, flags); - } else if (!scumm_stricmp("kyra2", gameid)) { + break; + case Kyra::GI_KYRA2: *engine = new Kyra::KyraEngine_v2(syst, flags); - } else if (!scumm_stricmp("kyra3", gameid)) { + break; + case Kyra::GI_KYRA3: *engine = new Kyra::KyraEngine_v3(syst, flags); - } else - error("Kyra engine created with invalid gameid ('%s')", gameid); + break; + default: + res = false; + error("Kyra engine: unknown gameID"); + } - return kNoError; + return res; } +ADVANCED_DETECTOR_DEFINE_PLUGIN_WITH_COMPLEX_CREATION(KYRA, engineCreateKyra, detectionParams); + REGISTER_PLUGIN(KYRA, "Legend of Kyrandia Engine", "The Legend of Kyrandia (C) Westwood Studios"); diff --git a/engines/kyra/gui_v1.cpp b/engines/kyra/gui_v1.cpp index b7692cc97d..0d9d8224cd 100644 --- a/engines/kyra/gui_v1.cpp +++ b/engines/kyra/gui_v1.cpp @@ -41,7 +41,7 @@ void KyraEngine_v1::registerDefaultSettings() { // Most settings already have sensible defaults. This one, however, is // specific to the Kyra engine. ConfMan.registerDefault("walkspeed", 2); - ConfMan.registerDefault("cdaudio", _flags.platform == Common::kPlatformFMTowns); + ConfMan.registerDefault("cdaudio", (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)); } void KyraEngine_v1::readSettings() { @@ -59,7 +59,7 @@ void KyraEngine_v1::readSettings() { _configTextspeed = 2; // Fast _configWalkspeed = ConfMan.getInt("walkspeed"); - _configMusic = ConfMan.getBool("music_mute") ? 0 : ((ConfMan.getBool("cdaudio") && _flags.platform == Common::kPlatformFMTowns) ? 2 : 1); + _configMusic = ConfMan.getBool("music_mute") ? 0 : ((ConfMan.getBool("cdaudio") && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) ? 2 : 1); _configSounds = ConfMan.getBool("sfx_mute") ? 0 : 1; _sound->enableMusic(_configMusic); @@ -494,7 +494,7 @@ void KyraEngine_v1::setGUILabels() { menuLabelGarbageOffset = 72; } else if (_flags.lang == Common::DE_DEU) { offset = offsetMainMenu = offsetOn = offsetOptions = 24; - } else if (_flags.platform == Common::kPlatformFMTowns) { + } else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { offset = 1; offsetOptions = 10; offsetOn = 0; @@ -1303,7 +1303,7 @@ int KyraEngine_v1::gui_controlsChangeMusic(Button *button) { debugC(9, kDebugLevelGUI, "KyraEngine_v1::gui_controlsChangeMusic()"); processMenuButton(button); - _configMusic = ++_configMusic % (_flags.platform == Common::kPlatformFMTowns ? 3 : 2); + _configMusic = ++_configMusic % ((_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) ? 3 : 2); gui_setupControls(_menu[5]); return 0; } diff --git a/engines/kyra/kyra.cpp b/engines/kyra/kyra.cpp index 1d8d7440f0..0c2524327e 100644 --- a/engines/kyra/kyra.cpp +++ b/engines/kyra/kyra.cpp @@ -86,8 +86,13 @@ int KyraEngine::init() { int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/); if (_flags.platform == Common::kPlatformFMTowns) { - // no sfx enabled for CD audio music atm - // later on here should be a usage of MixedSoundDriver + // TODO: later on here should be a usage of MixedSoundDriver + _sound = new SoundTowns(this, _mixer); + } else if (_flags.platform == Common::kPlatformPC98) { + // TODO: currently we don't support the PC98 sound data, + // but since it has the FM-Towns data files, we just use the + // FM-Towns driver + // TODO: later on here should be a usage of MixedSoundDriver _sound = new SoundTowns(this, _mixer); } else if (midiDriver == MD_ADLIB) { _sound = new SoundAdlibPC(this, _mixer); diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 3c6e257376..c994325ca9 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/kyra_v1.cpp $ - * $Id:kyra_v1.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -180,7 +180,7 @@ int KyraEngine_v1::init() { initStaticResource(); - if (_flags.platform == Common::kPlatformFMTowns) + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) _sound->setSoundFileList(_soundFilesTowns, _soundFilesTownsCount); else _sound->setSoundFileList(_soundFiles, _soundFilesCount); diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 8c9437b6fe..6e5ba98d3c 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/kyra_v1.h $ - * $Id:kyra_v1.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 317fd218b2..e27f31b691 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/kyra_v2.cpp $ - * $Id:kyra_v2.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index c87eeb66d4..fb8fd2c454 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/kyra_v2.h $ - * $Id:kyra_v2.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/kyra/kyra_v3.cpp b/engines/kyra/kyra_v3.cpp index 32754ecf2f..9aa4b1f4da 100644 --- a/engines/kyra/kyra_v3.cpp +++ b/engines/kyra/kyra_v3.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/kyra_v3.cpp $ - * $Id:kyra_v3.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/kyra/kyra_v3.h b/engines/kyra/kyra_v3.h index f9b81b5126..79c48b0dcb 100644 --- a/engines/kyra/kyra_v3.h +++ b/engines/kyra/kyra_v3.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/kyra/kyra_v3.h $ - * $Id:kyra_v3.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index cb484b6183..32c090dc57 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -109,7 +109,7 @@ Resource::Resource(KyraEngine *vm) { } } - if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) { uint unloadHash = (_vm->gameFlags().lang == Common::EN_ANY) ? Common::hashit_lower("JMC.PAK") : Common::hashit_lower("EMC.PAK"); ResIterator file = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(unloadHash)); diff --git a/engines/kyra/saveload_v1.cpp b/engines/kyra/saveload_v1.cpp index c2ceee1d3b..e9001968e9 100644 --- a/engines/kyra/saveload_v1.cpp +++ b/engines/kyra/saveload_v1.cpp @@ -84,8 +84,8 @@ void KyraEngine_v1::loadGame(const char *fileName) { warning("Can not load cdrom savefile for this (non cdrom) gameversion"); delete in; return; - } else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns)) { - warning("can not load FM-Towns savefile for this (non FM-Towns) gameversion"); + } else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) { + warning("can not load FM-Towns/PC98 savefile for this (non FM-Towns/PC98) gameversion"); delete in; return; } @@ -206,7 +206,7 @@ void KyraEngine_v1::loadGame(const char *fileName) { if (_curSfxFile >= _soundFilesTownsCount || _curSfxFile < 0) _curSfxFile = 0; - if (_flags.platform == Common::kPlatformFMTowns) + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) _sound->loadSoundFile(_curSfxFile); } @@ -276,7 +276,7 @@ void KyraEngine_v1::saveGame(const char *fileName, const char *saveName) { out->write(saveName, 31); if (_flags.isTalkie) out->writeUint32BE(GF_TALKIE); - else if (_flags.platform == Common::kPlatformFMTowns) + else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) out->writeUint32BE(GF_FMTOWNS); else out->writeUint32BE(GF_FLOPPY); diff --git a/engines/kyra/scene.cpp b/engines/kyra/scene.cpp index bf85ab1474..22cf2e0f2b 100644 --- a/engines/kyra/scene.cpp +++ b/engines/kyra/scene.cpp @@ -65,11 +65,11 @@ int KyraEngine::findWay(int x, int y, int toX, int toY, int *moveTable, int move return 0x7D00; } // debug drawing - //if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { - // _screen->setPagePixel(0, curX, curY, 11); - // _screen->updateScreen(); - // waitTicks(5); - //} + /*if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { + screen()->setPagePixel(0, curX, curY, 11); + screen()->updateScreen(); + //waitTicks(5); + }*/ moveTable[lastUsedEntry++] = newFacing; x = curX; y = curY; @@ -81,11 +81,11 @@ int KyraEngine::findWay(int x, int y, int toX, int toY, int *moveTable, int move newFacing = getFacingFromPointToPoint(curX, curY, toX, toY); changePosTowardsFacing(curX, curY, newFacing); // debug drawing - //if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { - // _screen->setPagePixel(0, curX, curY, 8); - // _screen->updateScreen(); - // waitTicks(5); - //} + /*if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { + screen()->setPagePixel(0, curX, curY, 8); + screen()->updateScreen(); + //waitTicks(5); + }*/ if (!lineIsPassable(curX, curY)) { if (curX != toX || curY != toY) diff --git a/engines/kyra/scene_v1.cpp b/engines/kyra/scene_v1.cpp index 3754d5e2ab..af7ee89fec 100644 --- a/engines/kyra/scene_v1.cpp +++ b/engines/kyra/scene_v1.cpp @@ -48,7 +48,7 @@ void KyraEngine_v1::enterNewScene(int sceneId, int facing, int unk1, int unk2, i _abortWalkFlag = false; _abortWalkFlag2 = false; - if (_flags.platform == Common::kPlatformFMTowns) { + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { int newSfxFile = -1; if (_currentCharacter->sceneId == 7 && sceneId == 24) newSfxFile = 2; @@ -1166,7 +1166,9 @@ void KyraEngine_v1::setCharactersPositions(int character) { int KyraEngine_v1::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) { debugC(9, kDebugLevelMain, "KyraEngine_v1::findWay(%d, %d, %d, %d, %p, %d)", x, y, toX, toY, (const void *)moveTable, moveTableSize); - KyraEngine::findWay(x, y, toX, toY, moveTable, moveTableSize); + int ret = KyraEngine::findWay(x, y, toX, toY, moveTable, moveTableSize); + if (ret == 0x7D00) + return 0; return getMoveTableSize(moveTable); } diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index 5966fa2c25..0778e1abd6 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -167,7 +167,7 @@ bool ScriptHelper::startScript(ScriptState *script, int function) { return false; if (_vm->game() == GI_KYRA1) { - if (_vm->gameFlags().platform == Common::kPlatformFMTowns) + if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) script->ip = &script->dataPtr->data[functionOffset+1]; else script->ip = &script->dataPtr->data[functionOffset]; diff --git a/engines/kyra/script_v1.cpp b/engines/kyra/script_v1.cpp index bd776e2046..7a4f844400 100644 --- a/engines/kyra/script_v1.cpp +++ b/engines/kyra/script_v1.cpp @@ -52,7 +52,7 @@ int KyraEngine_v1::o1_characterSays(ScriptState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1characterSays(%p) ('%s', %d, %d)", (const void *)script, stackPosString(0), stackPos(1), stackPos(2)); const char *string = stackPosString(0); - if (_flags.platform == Common::kPlatformFMTowns && _flags.lang == Common::JA_JPN) { + if ((_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) && _flags.lang == Common::JA_JPN) { static const uint8 townsString1[] = { 0x83, 0x75, 0x83, 0x89, 0x83, 0x93, 0x83, 0x83, 0x93, 0x81, 0x41, 0x82, 0xDC, 0x82, 0xBD, 0x97, 0x88, 0x82, 0xBD, 0x82, diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp index 20a98c66c1..2136c2830d 100644 --- a/engines/kyra/seqplayer.cpp +++ b/engines/kyra/seqplayer.cpp @@ -435,7 +435,7 @@ void SeqPlayer::s1_playTrack() { _sound->beginFadeOut(); } else { _sound->haltTrack(); - if (_vm->gameFlags().platform == Common::kPlatformFMTowns) + if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) msg += 2; _sound->playTrack(msg); } diff --git a/engines/kyra/sequences_v1.cpp b/engines/kyra/sequences_v1.cpp index 3bba3406a8..00aac6cfb4 100644 --- a/engines/kyra/sequences_v1.cpp +++ b/engines/kyra/sequences_v1.cpp @@ -113,7 +113,7 @@ void KyraEngine_v1::seq_intro() { _seq->setCopyViewOffs(true); _screen->setFont(Screen::FID_8_FNT); - if (_flags.platform != Common::kPlatformFMTowns) + if (_flags.platform != Common::kPlatformFMTowns && _flags.platform != Common::kPlatformPC98) snd_playTheme(0, 2); _text->setTalkCoords(144); @@ -133,7 +133,7 @@ void KyraEngine_v1::seq_intro() { void KyraEngine_v1::seq_introLogos() { debugC(9, kDebugLevelMain, "KyraEngine_v1::seq_introLogos()"); - if (_flags.platform == Common::kPlatformFMTowns) { + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { _screen->loadBitmap("LOGO.CPS", 3, 3, _screen->_currentPalette); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); _screen->updateScreen(); @@ -1083,13 +1083,13 @@ void KyraEngine_v1::seq_playCredits() { _screen->_charWidth = -1; // we only need this for the fm-towns version - if (_flags.platform == Common::kPlatformFMTowns) + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) snd_playWanderScoreViaMap(53, 1); uint8 *buffer = 0; uint32 size = 0; - if (_flags.platform == Common::kPlatformFMTowns) { + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { int sizeTmp = 0; const uint8 *bufferTmp = _staticres->loadRawData(kCreditsStrings, sizeTmp); buffer = new uint8[sizeTmp]; @@ -1676,6 +1676,7 @@ int KyraEngine_v1::processBead(int x, int y, int &x2, int &y2, BeadState *ptr) { void KyraEngine_v1::setupPanPages() { debugC(9, kDebugLevelMain, "KyraEngine_v1::setupPanPages()"); + _screen->savePageToDisk("BKGD.PG", 2); _screen->loadBitmap("BEAD.CPS", 3, 3, 0); if (_flags.platform == Common::kPlatformMacintosh || _flags.platform == Common::kPlatformAmiga) { int pageBackUp = _screen->_curPage; @@ -1701,6 +1702,7 @@ void KyraEngine_v1::setupPanPages() { assert(_panPagesTable[i]); } } + _screen->loadPageFromDisk("BKGD.PG", 2); } void KyraEngine_v1::freePanPages() { diff --git a/engines/kyra/sound_v1.cpp b/engines/kyra/sound_v1.cpp index 3ea86189b2..032e3eda44 100644 --- a/engines/kyra/sound_v1.cpp +++ b/engines/kyra/sound_v1.cpp @@ -45,7 +45,7 @@ void KyraEngine_v1::snd_playTheme(int file, int track) { void KyraEngine_v1::snd_playSoundEffect(int track) { debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_v1::snd_playSoundEffect(%d)", track); - if (_flags.platform == Common::kPlatformFMTowns && track == 49) { + if ((_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) && track == 49) { snd_playWanderScoreViaMap(56, 1); return; } @@ -57,7 +57,7 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) { if (restart) _lastMusicCommand = -1; - if (_flags.platform == Common::kPlatformFMTowns) { + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { if (command == 1) { _sound->beginFadeOut(); } else if (command >= 35 && command <= 38) { diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 3cf8648aa8..2ffa7aee09 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -86,7 +86,7 @@ uint32 createFeatures(const GameFlags &flags) { return GF_TALKIE; if (flags.isDemo) return GF_DEMO; - if (flags.platform == Common::kPlatformFMTowns) + if (flags.platform == Common::kPlatformFMTowns || flags.platform == Common::kPlatformPC98) return GF_FMTOWNS; if (flags.platform == Common::kPlatformAmiga) return GF_AMIGA; @@ -605,7 +605,7 @@ uint8 *StaticResource::getFile(const char *name, int &size) { ext = ".CD"; else if (_vm->gameFlags().isDemo) ext = ".DEM"; - else if (_vm->gameFlags().platform == Common::kPlatformFMTowns) + else if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) ext = ".TNS"; else if (_vm->gameFlags().platform == Common::kPlatformAmiga) ext = ".AMG"; diff --git a/engines/kyra/text_v1.cpp b/engines/kyra/text_v1.cpp index c04aa2105f..ae18d793ef 100644 --- a/engines/kyra/text_v1.cpp +++ b/engines/kyra/text_v1.cpp @@ -302,7 +302,7 @@ void KyraEngine_v1::characterSays(int vocFile, const char *chatStr, int8 charNum if (textEnabled()) { _animator->restoreAllObjectBackgrounds(); - _screen->copyRegion(12, _text->_talkMessageY, 12, 136, 308, _text->_talkMessageH, 2, 2); + _screen->copyRegion(12, _text->_talkMessageY, 12, 136, 296, _text->_talkMessageH, 2, 2); _screen->hideMouse(); _text->printCharacterText(processedString, charNum, _characterList[charNum].x1); @@ -321,12 +321,12 @@ void KyraEngine_v1::characterSays(int vocFile, const char *chatStr, int8 charNum if (textEnabled()) { _animator->restoreAllObjectBackgrounds(); - _screen->copyRegion(12, 136, 12, _text->_talkMessageY, 308, _text->_talkMessageH, 2, 2); + _screen->copyRegion(12, 136, 12, _text->_talkMessageY, 296, _text->_talkMessageH, 2, 2); _animator->preserveAllBackgrounds(); _animator->prepDrawAllObjects(); _screen->hideMouse(); - _screen->copyRegion(12, _text->_talkMessageY, 12, _text->_talkMessageY, 308, _text->_talkMessageH, 2, 0); + _screen->copyRegion(12, _text->_talkMessageY, 12, _text->_talkMessageY, 296, _text->_talkMessageH, 2, 0); _screen->showMouse(); _animator->flagAllObjectsForRefresh(); _animator->copyChangedObjectsForward(0); diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp index 39d74e5ec8..1dc2abe341 100644 --- a/engines/lure/animseq.cpp +++ b/engines/lure/animseq.cpp @@ -104,14 +104,14 @@ AnimationSequence::AnimationSequence(Screen &screen, OSystem &system, uint16 scr _lineRefs = d.getEntry(_screenId + 1); - // Show the screen that preceeds the start of the animation data - _screen.setPaletteEmpty(); + // Reset the palette and set the initial starting screen + _screen.setPaletteEmpty(RES_PALETTE_ENTRIES); _screen.screen().data().copyFrom(_decodedData, 0, 0, FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH); _screen.update(); // Set the palette if (fadeIn) _screen.paletteFadeIn(&_palette); - else _screen.setPalette(&_palette); + else _screen.setPalette(&_palette, 0, _palette.numEntries()); // Set up frame poitners _pPixels = _decodedData->data() + SCREEN_SIZE; @@ -135,7 +135,7 @@ AnimAbortType AnimationSequence::show() { while ((_pPixels < _pPixelsEnd) && (_pLines < _pLinesEnd)) { decodeFrame(_pPixels, _pLines); - result = delay(130); + result = delay(7 * 1000 / 50); if (result != ABORT_NONE) return result; } diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp index d072a009d5..4291b9aedb 100644 --- a/engines/lure/detection.cpp +++ b/engines/lure/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/lure/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -97,7 +97,7 @@ GameList Engine_LURE_detectGames(const FSList &fslist) { continue; for (g = lure_games; g->gameid; g++) { - if (scumm_stricmp(file->name().c_str(), g->checkFile) == 0) + if (scumm_stricmp(file->getName().c_str(), g->checkFile) == 0) isFound = true; } if (isFound) @@ -152,8 +152,7 @@ void LureEngine::detectGame() { "Lure of the Temptress executable. See the documentation for creating it.", SUPPORT_FILENAME); - for (uint8 fileNum = 1; fileNum <= 4; ++fileNum) - { + for (uint8 fileNum = 1; fileNum <= 4; ++fileNum) { char sFilename[10]; sprintf(sFilename, "disk%d.vga", fileNum); diff --git a/engines/lure/disk.cpp b/engines/lure/disk.cpp index 8f0714c42e..b5465df8d9 100644 --- a/engines/lure/disk.cpp +++ b/engines/lure/disk.cpp @@ -31,6 +31,7 @@ #include "lure/disk.h" #include "lure/luredefs.h" +#include "lure/res.h" namespace Lure { @@ -125,6 +126,14 @@ void Disk::openFile(uint8 fileNum) { } uint32 Disk::getEntrySize(uint16 id) { + // Special room area check + uint16 tempId = id & 0x3fff; + if ((tempId == 0x120) || (tempId == 0x311) || (tempId == 8) || (tempId == 0x410)) { + ValueTableData &fieldList = Resources::getReference().fieldList(); + if (fieldList.getField(AREA_FLAG) != 0) + id ^= 0x8000; + } + // Get the index of the resource, if necessary opening the correct file uint8 index = indexOf(id); @@ -135,8 +144,15 @@ uint32 Disk::getEntrySize(uint16 id) { return size; } -MemoryBlock *Disk::getEntry(uint16 id) -{ +MemoryBlock *Disk::getEntry(uint16 id) { + // Special room area check + uint16 tempId = id & 0x3fff; + if ((tempId == 0x120) || (tempId == 0x311) || (tempId == 8) || (tempId == 0x410)) { + ValueTableData &fieldList = Resources::getReference().fieldList(); + if (fieldList.getField(AREA_FLAG) != 0) + id ^= 0x8000; + } + // Get the index of the resource, if necessary opening the correct file uint8 index = indexOf(id); diff --git a/engines/lure/fights.cpp b/engines/lure/fights.cpp index 4c478bbc17..836c109ca7 100644 --- a/engines/lure/fights.cpp +++ b/engines/lure/fights.cpp @@ -335,8 +335,7 @@ void FightsManager::fightHandler(Hotspot &h, uint16 moveOffset) { return; } - switch (moveValue) - { + switch (moveValue) { case 0xFFFA: // Walk left if ((fighter.fwmove_number == 5) || (fighter.fwmove_number == 10)) { @@ -466,7 +465,7 @@ void FightsManager::fightHandler(Hotspot &h, uint16 moveOffset) { moveOffset += 2 * sizeof(uint16); if (v1 == opponent.fwblocking) { - Sound.playSound(42); + Sound.addSound(42); moveOffset = v2; } break; @@ -478,7 +477,7 @@ void FightsManager::fightHandler(Hotspot &h, uint16 moveOffset) { if (fighter.fwdist <= FIGHT_DISTANCE) { if (h.hotspotId() == PLAYER_ID) { // Player hits opponent - Sound.playSound(52); + Sound.addSound(52); if (opponent.fwhits != 5) { opponent.fwseq_ad = v1; @@ -490,13 +489,13 @@ void FightsManager::fightHandler(Hotspot &h, uint16 moveOffset) { } } else { // Opponent hit player - Sound.playSound(37); + Sound.addSound(37); opponent.fwseq_ad = v1; if (++opponent.fwhits == 10) { // Player has been killed fighter.fwhits = 10; opponent.fwseq_ad = FIGHT_PLAYER_DIES; - Sound.playSound(36); + Sound.addSound(36); } } } @@ -526,7 +525,7 @@ void FightsManager::fightHandler(Hotspot &h, uint16 moveOffset) { case 0xFFEA: // Fight sound - Sound.playSound(getWord(moveOffset)); + Sound.addSound(getWord(moveOffset) & 0xff); moveOffset += sizeof(uint16); break; diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp index 5bffc6ade8..e4aeef2253 100644 --- a/engines/lure/game.cpp +++ b/engines/lure/game.cpp @@ -24,14 +24,16 @@ */ #include "lure/game.h" -#include "lure/strings.h" -#include "lure/room.h" -#include "lure/scripts.h" -#include "lure/res_struct.h" #include "lure/animseq.h" #include "lure/fights.h" +#include "lure/res_struct.h" +#include "lure/room.h" +#include "lure/scripts.h" +#include "lure/sound.h" +#include "lure/strings.h" #include "common/config-manager.h" +#include "common/system.h" namespace Lure { @@ -45,6 +47,7 @@ Game::Game() { int_game = this; _debugger = new Debugger(); _slowSpeedFlag = true; + _preloadFlag = false; _soundFlag = true; } @@ -52,7 +55,7 @@ Game::~Game() { delete _debugger; } -void Game::tick(bool fastSpeed) { +void Game::tick() { // Call the tick method for each hotspot - this is somewaht complicated // by the fact that a tick proc can unload both itself and/or others, // so we first get a list of the Ids, and call the tick proc for each @@ -66,7 +69,7 @@ void Game::tick(bool fastSpeed) { for (i = res.activeHotspots().begin(); i != res.activeHotspots().end(); ++i) { Hotspot *hotspot = *i; - if (!fastSpeed || ((hotspot->layer() != 0xff) && + if (!_preloadFlag || ((hotspot->layer() != 0xff) && (hotspot->hotspotId() < FIRST_NONCHARACTER_ID))) // Add hotspot to list to execute idList[idSize++] = hotspot->hotspotId(); @@ -85,6 +88,21 @@ void Game::tick(bool fastSpeed) { delete[] idList; } +void Game::tickCheck() { + Resources &res = Resources::getReference(); + Room &room = Room::getReference(); + bool remoteFlag = res.fieldList().getField(OLD_ROOM_NUMBER) != 0; + + _state |= GS_TICK; + if ((room.roomNumber() == ROOMNUM_VILLAGE_SHOP) && !remoteFlag && ((_state & GS_TICK) != 0)) { + // In the village shop, + bool tockFlag = (_state & GS_TOCK) != 0; + Sound.addSound(tockFlag ? 16 : 50); + + _state = _state ^ (GS_TICK | GS_TOCK); + } +} + void Game::nextFrame() { Resources &res = Resources::getReference(); Room &room = Room::getReference(); @@ -110,31 +128,48 @@ void Game::execute() { ValueTableData &fields = res.fieldList(); uint32 timerVal = system.getMillis(); + uint32 timerVal2 = system.getMillis(); screen.empty(); - //_screen.resetPalette(); screen.setPaletteEmpty(); - setState(0); + // Flag for starting game + setState(GS_RESTART); - Script::execute(STARTUP_SCRIPT); + while (!events.quitFlag) { + + if ((_state & GS_RESTART) != 0) { + res.reset(); - int bootParam = ConfMan.getInt("boot_param"); - handleBootParam(bootParam); + setState(0); + Script::execute(STARTUP_SCRIPT); - // Set the player direction - res.getActiveHotspot(PLAYER_ID)->setDirection(UP); + int bootParam = ConfMan.getInt("boot_param"); + handleBootParam(bootParam); +if (bootParam == 1) _state = GS_RESTORE_RESTART; //******DEBUG****** + } - room.update(); - mouse.setCursorNum(CURSOR_ARROW); - mouse.cursorOn(); - - while (!events.quitFlag) { - while (!events.quitFlag && (_state == 0)) { + // Set the player direction +// res.getActiveHotspot(PLAYER_ID)->setDirection(UP); + + room.update(); + mouse.setCursorNum(CURSOR_ARROW); + mouse.cursorOn(); + + // Main game loop + while (!events.quitFlag && ((_state & GS_RESTART) == 0)) { // If time for next frame, allow everything to update if (system.getMillis() > timerVal + GAME_FRAME_DELAY) { timerVal = system.getMillis(); nextFrame(); + + Sound.musicInterface_ContinuePlaying(); + } + + // Also check if time to do another village shop tick check + if (system.getMillis() > timerVal2 + GAME_TICK_DELAY) { + timerVal2 = system.getMillis(); + tickCheck(); } res.delayList().tick(); @@ -161,48 +196,46 @@ void Game::execute() { SaveRestoreDialog::show(false); break; - default: - handled = false; - } - if (handled) - continue; + case Common::KEYCODE_F9: + doRestart(); + break; - // Handle any remaining standard keys - switch (events.event().kbd.keycode) { - case Common::KEYCODE_ESCAPE: - events.quitFlag = true; - break; + case Common::KEYCODE_KP_PLUS: + while (++roomNum <= 51) + if (res.getRoom(roomNum) != NULL) break; + if (roomNum == 52) roomNum = 1; - case '+': - while (++roomNum <= 51) - if (res.getRoom(roomNum) != NULL) break; - if (roomNum == 52) roomNum = 1; + room.leaveRoom(); + room.setRoomNumber(roomNum); + break; - room.leaveRoom(); - room.setRoomNumber(roomNum); - break; + case Common::KEYCODE_KP_MINUS: + if (roomNum == 1) roomNum = 55; + while (res.getRoom(--roomNum) == NULL) ; - case '-': - if (roomNum == 1) roomNum = 55; - while (res.getRoom(--roomNum) == NULL) ; + room.leaveRoom(); + room.setRoomNumber(roomNum); + break; - room.leaveRoom(); - room.setRoomNumber(roomNum); - break; + case Common::KEYCODE_KP_MULTIPLY: + res.getActiveHotspot(PLAYER_ID)->setRoomNumber( + room.roomNumber()); + break; - case '*': - res.getActiveHotspot(PLAYER_ID)->setRoomNumber( - room.roomNumber()); - break; + case Common::KEYCODE_KP_DIVIDE: + case Common::KEYCODE_SLASH: + room.setShowInfo(!room.showInfo()); + break; - case Common::KEYCODE_KP_DIVIDE: - case Common::KEYCODE_SLASH: - room.setShowInfo(!room.showInfo()); - break; + case Common::KEYCODE_ESCAPE: + doQuit(); + break; - default: - break; + default: + handled = false; } + if (handled) + continue; } if ((events.type() == Common::EVENT_LBUTTONDOWN) || @@ -232,24 +265,31 @@ void Game::execute() { _debugger->onFrame(); } + room.leaveRoom(); + // If Skorl catches player, show the catching animation if ((_state & GS_CAUGHT) != 0) { Palette palette(SKORL_CATCH_PALETTE_ID); AnimationSequence *anim = new AnimationSequence(screen, system, SKORL_CATCH_ANIM_ID, palette, false); mouse.cursorOff(); + Sound.addSound(0x33); anim->show(); - mouse.cursorOn(); + delete anim; } // If the Restart/Restore dialog is needed, show it - if ((_state & GS_RESTORE_RESTART) != 0) { - // TODO: Restore/Restart dialog - for now, simply flag for exit + if ((_state & GS_RESTORE) != 0) { + // Show the Restore/Restart dialog + bool restartFlag = RestartRestoreDialog::show(); + + if (restartFlag) + setState(GS_RESTART); + + } else if ((_state & GS_RESTART) == 0) + // Exiting game events.quitFlag = true; - } } - - room.leaveRoom(); } void Game::handleMenuResponse(uint8 selection) { @@ -261,6 +301,7 @@ void Game::handleMenuResponse(uint8 selection) { break; case MENUITEM_RESTART_GAME: + doRestart(); break; case MENUITEM_SAVE_GAME: @@ -296,6 +337,8 @@ void Game::playerChangeRoom() { delayList.clear(); + Sound.removeSounds(); + RoomData *roomData = res.getRoom(roomNum); assert(roomData); roomData->flags |= HOTSPOTFLAG_FOUND; @@ -332,8 +375,7 @@ void Game::playerChangeRoom() { } } -void Game::displayChuteAnimation() -{ +void Game::displayChuteAnimation() { OSystem &system = *g_system; Resources &res = Resources::getReference(); Screen &screen = Screen::getReference(); @@ -361,11 +403,10 @@ void Game::displayChuteAnimation() delete anim; mouse.cursorOn(); - fields.setField(82, 1); + fields.setField(AREA_FLAG, 1); } -void Game::displayBarrelAnimation() -{ +void Game::displayBarrelAnimation() { OSystem &system = *g_system; Screen &screen = Screen::getReference(); Mouse &mouse = Mouse::getReference(); @@ -631,8 +672,7 @@ bool Game::GetTellActions() { --_numTellCommands; if (_numTellCommands < 0) paramIndex = -1; - else - { + else { paramIndex = 3; statusLine = statusLinePos[_numTellCommands][paramIndex]; *statusLine = '\0'; @@ -791,14 +831,12 @@ void Game::doAction(Action action, uint16 hotspotId, uint16 usedId) { room.setCursorState(CS_ACTION); // Set the action - if (action == TELL) - { + if (action == TELL) { // Tell action needs special handling because of the variable length parameter list - add in a // placeholder entry, and then replace it's details with the TELL command data player->currentActions().addFront(NONE, player->roomNumber(), 0, 0); player->currentActions().top().supportData().setDetails2(TELL, _numTellCommands * 3 + 1, &_tellCommands[0]); - } - else + } else // All other action types player->currentActions().addFront(action, player->roomNumber(), hotspotId, usedId); } @@ -823,31 +861,13 @@ void Game::doShowCredits() { } void Game::doQuit() { - Mouse &mouse = Mouse::getReference(); - Events &events = Events::getReference(); - Screen &screen = Screen::getReference(); - - mouse.cursorOff(); - Surface *s = Surface::newDialog(190, "Are you sure (y/n)?"); - s->centerOnScreen(); - delete s; - - Common::KeyCode key = Common::KEYCODE_INVALID; - do { - if (events.pollEvent()) { - if (events.event().type == Common::EVENT_KEYDOWN) { - key = events.event().kbd.keycode; - } - } - } while ((key != Common::KEYCODE_ESCAPE) && - (key != Common::KEYCODE_y) && - (key != Common::KEYCODE_n)); + if (getYN()) + Events::getReference().quitFlag = true; +} - events.quitFlag = (key == Common::KEYCODE_n); - if (!events.quitFlag) { - screen.update(); - mouse.cursorOn(); - } +void Game::doRestart() { + if (getYN()) + setState(GS_RESTART); } void Game::doTextSpeed() { @@ -864,6 +884,7 @@ void Game::doSound() { _soundFlag = !_soundFlag; menu.getMenu(2).entries()[2] = sl.getString(_soundFlag ? S_SOUND_ON : S_SOUND_OFF); + Sound.setVolume(_soundFlag ? DEFAULT_VOLUME : 0); } void Game::handleBootParam(int value) { @@ -908,7 +929,53 @@ void Game::handleBootParam(int value) { room.setRoomNumber(2); break; + + default: + room.setRoomNumber(value); + break; } } +bool Game::getYN() { + Mouse &mouse = Mouse::getReference(); + Events &events = Events::getReference(); + Screen &screen = Screen::getReference(); + + mouse.cursorOff(); + Surface *s = Surface::newDialog(190, "Are you sure (y/n)?"); + s->centerOnScreen(); + delete s; + + bool breakFlag = false; + bool result = false; + + do { + if (events.pollEvent()) { + if (events.event().type == Common::EVENT_KEYDOWN) { + Common::KeyCode key = events.event().kbd.keycode; + if ((key == Common::KEYCODE_y) || (key == Common::KEYCODE_n) || + (key == Common::KEYCODE_ESCAPE)) { + breakFlag = true; + result = key == Common::KEYCODE_y; + } + } + if (events.event().type == Common::EVENT_LBUTTONUP) { + breakFlag = true; + result = true; + } + if (events.event().type == Common::EVENT_RBUTTONUP) { + breakFlag = true; + result = false; + } + } + + g_system->delayMillis(10); + } while (!events.quitFlag && !breakFlag); + + screen.update(); + mouse.cursorOn(); + + return result; +} + } // end of namespace Lure diff --git a/engines/lure/game.h b/engines/lure/game.h index 20e56df776..50b730e354 100644 --- a/engines/lure/game.h +++ b/engines/lure/game.h @@ -39,7 +39,9 @@ namespace Lure { -enum GameState {GS_RESTORE_RESTART = 1, GS_CAUGHT = 2, GS_EXIT = 3}; +enum GameState {GS_ERROR = 1, GS_TICK = 2, GS_TOCK = 4, GS_PROT = 8, GS_RESTART = 0x10, + GS_CAUGHT = 0x20, GS_RESTORE = 0x40, GS_FLOPPY = 0x80, + GS_RESTORE_RESTART = 0x50}; class Game { private: @@ -48,6 +50,7 @@ private: uint8 _state; uint16 _tellCommands[MAX_TELL_COMMANDS * 3 + 1]; int _numTellCommands; + bool _preloadFlag; void handleMenuResponse(uint8 selection); void handleClick(); @@ -60,21 +63,25 @@ private: void displayChuteAnimation(); void displayBarrelAnimation(); void handleBootParam(int value); + bool getYN(); public: Game(); virtual ~Game(); static Game &getReference(); - void tick(bool fastSpeed = false); + void tick(); + void tickCheck(); void nextFrame(); void execute(); void setState(uint8 flags) { _state = flags; } + bool &preloadFlag() { return _preloadFlag; } // Menu item support methods void doDebugMenu(); void doShowCredits(); void doQuit(); + void doRestart(); void doTextSpeed(); void doSound(); }; diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index 7def0be9ab..93860bbd3e 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -35,6 +35,7 @@ #include "lure/events.h" #include "lure/game.h" #include "lure/fights.h" +#include "lure/sound.h" #include "common/endian.h" namespace Lure { @@ -69,12 +70,19 @@ Hotspot::Hotspot(HotspotData *res): _pathFinder(this) { _hotspotScriptOffset = res->hotspotScriptOffset; _tickCtr = res->tickTimeout; _colourOffset = res->colourOffset; + _tempDest.counter = 0; _override = resources.getHotspotOverride(res->hotspotId); setAnimation(_data->animRecordId); _tickHandler = HotspotTickHandlers::getHandler(_data->tickProcOffset); _nameBuffer[0] = '\0'; + if (_hotspotId < FIRST_NONCHARACTER_ID) { + // Default characters to facing upwards until they start moving + _direction = UP; + setFrameNumber(_anim->upFrame); + } + _frameCtr = 0; _skipFlag = false; _charRectY = 0; @@ -165,6 +173,40 @@ Hotspot::Hotspot(Hotspot *character, uint16 objType): _pathFinder(this) { _nameBuffer[0] = '\0'; } +Hotspot::Hotspot(): _pathFinder(NULL) { + _data = NULL; + _anim = NULL; + _frames = NULL; + _numFrames = 0; + _persistant = false; + _hotspotId = 0xffff; + _override = NULL; + _colourOffset = 0; + _destHotspotId = 0; + _blockedOffset = 0; + _exitCtr = 0; + _voiceCtr = 0; + _walkFlag = false; + _skipFlag = false; + _roomNumber = 0; + _destHotspotId = 0; + _startX = 0; + _startY = 0; + _destX = 0; + _destY = 0; + _layer = 0; + _height = 0; + _width = 0; + _heightCopy = 0; + _widthCopy = 0; + _yCorrection = 0; + _tickCtr = 0; + _tickHandler = NULL; + _frameWidth = _width; + _frameStartsUsed = false; + _tempDest.counter = 0; +} + Hotspot::~Hotspot() { if (_frames) delete _frames; } @@ -386,8 +428,7 @@ uint16 Hotspot::nameId() { return _data->nameId; } -const char *Hotspot::getName() -{ +const char *Hotspot::getName() { // If name hasn't been loaded yet, then do so if (!_nameBuffer[0] && (nameId() != 0)) StringData::getReference().getString(nameId(), _nameBuffer); @@ -658,6 +699,8 @@ void Hotspot::updateMovement() { setOccupied(true); } } + + resetDirection(); } void Hotspot::updateMovement2(CharacterMode value) { @@ -810,12 +853,12 @@ void Hotspot::startTalkDialog() { /* */ /*-------------------------------------------------------------------------*/ -uint16 validRoomExitHotspots[] = {0x2711, 0x2712, 0x2714, 0x2715, 0x2716, 0x2717, +static const uint16 validRoomExitHotspots[] = {0x2711, 0x2712, 0x2714, 0x2715, 0x2716, 0x2717, 0x2718, 0x2719, 0x271A, 0x271E, 0x271F, 0x2720, 0x2721, 0x2722, 0x2725, 0x2726, 0x2729, 0x272A, 0x272B, 0x272C, 0x272D, 0x272E, 0x272F, 0}; bool Hotspot::isRoomExit(uint16 id) { - for (uint16 *p = &validRoomExitHotspots[0]; *p != 0; ++p) + for (const uint16 *p = &validRoomExitHotspots[0]; *p != 0; ++p) if (*p == id) return true; return false; } @@ -869,7 +912,7 @@ HotspotPrecheckResult Hotspot::actionPrecheck(HotspotData *hotspot) { return PC_WAIT; } else if (hotspot->actionHotspotId != _hotspotId) { - if (fields.getField(82) != 2) { + if (fields.getField(AREA_FLAG) != 2) { showMessage(5, hotspot->hotspotId); setDelayCtr(4); } @@ -1056,6 +1099,29 @@ bool Hotspot::doorCloseCheck(uint16 doorId) { return true; } +void Hotspot::resetDirection() { + uint16 newFrameNumber; + switch (_direction) { + case UP: + newFrameNumber = _anim->upFrame; + break; + case DOWN: + newFrameNumber = _anim->downFrame; + break; + case LEFT: + newFrameNumber = _anim->leftFrame; + break; + case RIGHT: + newFrameNumber = _anim->rightFrame; + break; + default: + // No need to change + return; + } + + setFrameNumber(newFrameNumber); +} + /*-------------------------------------------------------------------------*/ typedef void (Hotspot::*ActionProcPtr)(HotspotData *hotspot); @@ -1121,12 +1187,10 @@ void Hotspot::doAction(Action action, HotspotData *hotspot) { void Hotspot::doNothing(HotspotData *hotspot) { _currentActions.pop(); - if (!_currentActions.isEmpty()) - { + if (!_currentActions.isEmpty()) { setBlockedFlag(false); currentActions().top().setAction(DISPATCH_ACTION); - } - else if (hotspotId() == PLAYER_ID) { + } else if (hotspotId() == PLAYER_ID) { Room::getReference().setCursorState(CS_NONE); } } @@ -1294,8 +1358,8 @@ void Hotspot::doClose(HotspotData *hotspot) { joinRec = res.getExitJoin(hotspot->hotspotId); if (!joinRec->blocked) { // Close the door - if (!doorCloseCheck(joinRec->hotspot1Id) || - !doorCloseCheck(joinRec->hotspot2Id)) { + if (!doorCloseCheck(joinRec->hotspots[0].hotspotId) || + !doorCloseCheck(joinRec->hotspots[1].hotspotId)) { // A character is preventing the door from closing showMessage(2); } else { @@ -1486,59 +1550,32 @@ void Hotspot::doLook(HotspotData *hotspot) { Dialog::show(Room::getReference().descId()); } -uint16 hotspotLookAtList[] = {0x411, 0x412, 0x41F, 0x420, 0x421, 0x422, 0x426, +static const uint16 hotspotLookAtList[] = {0x411, 0x412, 0x41F, 0x420, 0x421, 0x422, 0x426, 0x427, 0x428, 0x429, 0x436, 0x437, 0}; void Hotspot::doLookAt(HotspotData *hotspot) { - Resources &res = Resources::getReference(); - uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, LOOK_AT); - - if (hotspot->hotspotId >= FIRST_NONCHARACTER_ID) { - // Check if the hotspot appears in the list of hotspots that don't - // need to be walked to before being looked at - uint16 *tempId = &hotspotLookAtList[0]; - while ((*tempId != 0) && (*tempId != hotspot->hotspotId)) ++tempId; - if (!*tempId) { - // Hotspot wasn't in the list - HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; - else if (result != PC_EXECUTE) { - endAction(); - return; - } - } - } - - faceHotspot(hotspot); - setActionCtr(0); - endAction(); - - if (sequenceOffset >= 0x8000) { - showMessage(sequenceOffset); - } else { - if (sequenceOffset != 0) - sequenceOffset = Script::execute(sequenceOffset); - - if (sequenceOffset == 0) { - uint16 descId = (hotspot->descId2 != 0) ? hotspot->descId2 : hotspot->descId; - Dialog::show(descId); - } - } + doLookAction(hotspot, LOOK_AT); } void Hotspot::doLookThrough(HotspotData *hotspot) { + doLookAction(hotspot, LOOK_THROUGH); +} + +void Hotspot::doLookAction(HotspotData *hotspot, Action action) { Resources &res = Resources::getReference(); - uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, LOOK_THROUGH); + uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, action); if (hotspot->hotspotId >= FIRST_NONCHARACTER_ID) { // Check if the hotspot appears in the list of hotspots that don't // need to be walked to before being looked at - uint16 *tempId = &hotspotLookAtList[0]; - while ((*tempId != 0) && (*tempId != hotspot->hotspotId)) ++tempId; + const uint16 *tempId = &hotspotLookAtList[0]; + while ((*tempId != 0) && (*tempId != hotspot->hotspotId)) + ++tempId; if (!*tempId) { // Hotspot wasn't in the list HotspotPrecheckResult result = actionPrecheck(hotspot); - if (result == PC_WAIT) return; + if (result == PC_WAIT) + return; else if (result != PC_EXECUTE) { endAction(); return; @@ -1701,7 +1738,7 @@ void Hotspot::doReturn(HotspotData *hotspot) { endAction(); } -uint16 bribe_hotspot_list[] = {0x421, 0x879, 0x3E9, 0x8C7, 0x429, 0x8D1, +static const uint16 bribe_hotspot_list[] = {0x421, 0x879, 0x3E9, 0x8C7, 0x429, 0x8D1, 0x422, 0x8D4, 0x420, 0x8D6, 0x42B, 0x956, 0x3F2, 0xBE6, 0}; void Hotspot::doBribe(HotspotData *hotspot) { @@ -1717,7 +1754,7 @@ void Hotspot::doBribe(HotspotData *hotspot) { return; } - uint16 *tempId = &bribe_hotspot_list[0]; + const uint16 *tempId = &bribe_hotspot_list[0]; uint16 sequenceOffset = 0x14B; // Default sequence offset while (*tempId != 0) { if (*tempId++ == hotspotId()) { @@ -2010,8 +2047,7 @@ uint16 Hotspot::getTalkId(HotspotData *charHotspot) { TalkHeaderData *headerEntry; // If the hotspot has a talk data override, return it - if (charHotspot->talkOverride != 0) - { + if (charHotspot->talkOverride != 0) { // Has an override, so return it and reset back to zero uint16 result = charHotspot->talkOverride; charHotspot->talkOverride = 0; @@ -2384,7 +2420,7 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) { switch (action) { case NO_ACTION: - h.setCharacterMode(CHARMODE_IDLE); + h.updateMovement2(CHARMODE_IDLE); break; case DISPATCH_ACTION: @@ -2479,8 +2515,7 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) { // Increment the blocked state h.setBlockedState((BlockedState) ((int) h.blockedState() + 1)); - if (!h.blockedFlag()) - { + if (!h.blockedFlag()) { // Not already handling blocked, so add a new dummy action so that the new // action set below will not replace the existing one h.currentActions().addFront(DISPATCH_ACTION, 0); @@ -2587,38 +2622,37 @@ void HotspotTickHandlers::puzzledAnimHandler(Hotspot &h) { void HotspotTickHandlers::roomExitAnimHandler(Hotspot &h) { Resources &res = Resources::getReference(); -// ValueTableData &fields = res.fieldList(); + ValueTableData &fields = res.fieldList(); + Room &room = Room::getReference(); + RoomExitJoinData *rec = res.getExitJoin(h.hotspotId()); if (!rec) return; - byte *currentFrame, *destFrame; + RoomExitJoinStruct &rs = (rec->hotspots[0].hotspotId == h.hotspotId()) ? + rec->hotspots[0] : rec->hotspots[1]; - if (rec->hotspot1Id == h.hotspotId()) { - currentFrame = &rec->h1CurrentFrame; - destFrame = &rec->h1DestFrame; - } else { - currentFrame = &rec->h2CurrentFrame; - destFrame = &rec->h2DestFrame; - } - - if ((rec->blocked != 0) && (*currentFrame != *destFrame)) { + if ((rec->blocked != 0) && (rs.currentFrame != rs.destFrame)) { // Closing the door h.setOccupied(true); - ++*currentFrame; - if (*currentFrame == *destFrame) { - // TODO: play closed door sound - } - } else if ((rec->blocked == 0) && (*currentFrame != 0)) { + ++rs.currentFrame; + if ((rs.currentFrame == rs.destFrame) && (h.hotspotId() == room.roomNumber())) + Sound.addSound(rs.closeSound); + + } else if ((rec->blocked == 0) && (rs.currentFrame != 0)) { // Opening the door h.setOccupied(false); - --*currentFrame; - if (*currentFrame == *destFrame) { - //TODO: Check against script val 88 and play sound + --rs.currentFrame; + if ((rs.currentFrame == rs.destFrame) && (h.hotspotId() == room.roomNumber())) { + Sound.addSound(rs.openSound); + + // If in the outside village, trash reverb + if (fields.getField(AREA_FLAG) == 1) + Sound.musicInterface_TrashReverb(); } } - h.setFrameNumber(*currentFrame); + h.setFrameNumber(rs.currentFrame); } void HotspotTickHandlers::playerAnimHandler(Hotspot &h) { @@ -2859,7 +2893,7 @@ void HotspotTickHandlers::followerAnimHandler(Hotspot &h) { h.currentActions().addFront(DISPATCH_ACTION, player->roomNumber()); else { // Scan through the translation list for an alternate destination room - RoomTranslationRecord *p = &roomTranslations[0]; + const RoomTranslationRecord *p = &roomTranslations[0]; while ((p->srcRoom != 0) && (p->srcRoom != player->roomNumber())) ++p; h.currentActions().addFront(DISPATCH_ACTION, @@ -2931,10 +2965,11 @@ void HotspotTickHandlers::followerAnimHandler(Hotspot &h) { void HotspotTickHandlers::jailorAnimHandler(Hotspot &h) { Resources &res = Resources::getReference(); ValueTableData &fields = res.fieldList(); + Game &game = Game::getReference(); HotspotData *player = res.getHotspot(PLAYER_ID); if ((fields.getField(11) != 0) || (h.hotspotId() == CASTLE_SKORL_ID)) { - if (!h.skipFlag() && (h.roomNumber() == player->roomNumber)) { + if (!h.skipFlag() && !game.preloadFlag() && (h.roomNumber() == player->roomNumber)) { if (Support::charactersIntersecting(h.resource(), player)) { // Skorl has caught the player Game::getReference().setState(GS_RESTORE_RESTART | GS_CAUGHT); @@ -2966,6 +3001,9 @@ void HotspotTickHandlers::droppingTorchAnimHandler(Hotspot &h) { res.deactivateHotspot(h.hotspotId()); res.activateHotspot(0x41C); + // Add sound + Sound.addSound(8); + // Enable the fire and activate its animation HotspotData *fire = res.getHotspot(0x418); fire->flags |= 0x80; @@ -2976,12 +3014,9 @@ void HotspotTickHandlers::droppingTorchAnimHandler(Hotspot &h) { } void HotspotTickHandlers::playerSewerExitAnimHandler(Hotspot &h) { - if (h.frameCtr() > 0) - { + if (h.frameCtr() > 0) { h.decrFrameCtr(); - } - else if (h.executeScript()) - { + } else if (h.executeScript()) { Resources &res = Resources::getReference(); // Deactive the dropping animation @@ -3484,7 +3519,7 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) { // All other actions uint16 xp, id; - uint16 *frameList; + const uint16 *frameList; uint16 frameNumber; BarmanAction action = (BarmanAction) (h.frameCtr() & 0x3F); @@ -3518,12 +3553,10 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) { HotspotData *gwyn = res.getHotspot(GOEWIN_ID); HotspotData *wayne = res.getHotspot(WAYNE_ID); - if ((player->roomNumber != 35) && (gwyn->roomNumber != 35) && (wayne->roomNumber != 35)) - { + if ((player->roomNumber != 35) && (gwyn->roomNumber != 35) && (wayne->roomNumber != 35)) { if (rnd.getRandomNumber(1) == 1) id = BG_EXTRA1 << 8; - else - { + else { // Set up alternate animation h.setWidth(32); h.setAnimation(EWAN_ALT_ANIM_ID); @@ -3544,15 +3577,13 @@ void HotspotTickHandlers::barmanAnimHandler(Hotspot &h) { frameList = barEntry.graphics[h.supportValue() >> 8]; frameNumber = frameList[h.supportValue() & 0xff]; - if (frameNumber != 0) - { + if (frameNumber != 0) { h.setActionCtr(frameNumber); h.setFrameNumber(frameNumber); return; } - if (h.hotspotId() == EWAN_ID) - { + if (h.hotspotId() == EWAN_ID) { // Make sure Ewan is back to his standard animation h.setWidth(16); h.setAnimation(EWAN_ANIM_ID); @@ -4261,16 +4292,13 @@ void CurrentActionEntry::saveToStream(WriteStream *stream) { if (hasSupportData()) { // Handle the support data stream->writeByte(_dynamicSupportData); - if (_dynamicSupportData) - { + if (_dynamicSupportData) { // Write out the dynamic data stream->writeByte(supportData().action()); stream->writeSint16LE(supportData().numParams()); for (int index = 0; index < supportData().numParams(); ++index) stream->writeUint16LE(supportData().param(index)); - } - else - { + } else { // Write out the Id for the static entry stream->writeSint16LE(supportData().id()); } @@ -4294,8 +4322,7 @@ CurrentActionEntry *CurrentActionEntry::loadFromStream(ReadStream *stream) { } else { // Handle support data for the entry bool dynamicData = stream->readByte() != 0; - if (dynamicData) - { + if (dynamicData) { // Load action entry that has dynamic data result = new CurrentActionEntry( (CurrentAction) actionNum, roomNumber); @@ -4308,9 +4335,7 @@ CurrentActionEntry *CurrentActionEntry::loadFromStream(ReadStream *stream) { result->_supportData->setDetails2(action, numParams, paramList); delete paramList; - } - else - { + } else { // Load action entry with an NPC schedule entry uint16 entryId = stream->readUint16LE(); CharacterScheduleEntry *entry = res.charSchedules().getEntry(entryId); @@ -4394,8 +4419,7 @@ void CurrentActionStack::saveToStream(WriteStream *stream) { list(buffer); debugC(ERROR_DETAILED, kLureDebugAnimations, "%s", buffer); - for (i = _actions.begin(); i != _actions.end(); ++i) - { + for (i = _actions.begin(); i != _actions.end(); ++i) { CurrentActionEntry *rec = *i; rec->saveToStream(stream); } @@ -4553,8 +4577,7 @@ bool Support::isCharacterInList(uint16 *lst, int numEntries, uint16 charId) { void HotspotList::saveToStream(WriteStream *stream) { HotspotList::iterator i; - for (i = begin(); i != end(); ++i) - { + for (i = begin(); i != end(); ++i) { Hotspot *hotspot = *i; debugC(ERROR_INTERMEDIATE, kLureDebugAnimations, "Saving hotspot %xh", hotspot->hotspotId()); bool dynamicObject = hotspot->hotspotId() != hotspot->originalId(); @@ -4574,8 +4597,7 @@ void HotspotList::loadFromStream(ReadStream *stream) { clear(); uint16 hotspotId = stream->readUint16LE(); - while (hotspotId != 0) - { + while (hotspotId != 0) { debugC(ERROR_INTERMEDIATE, kLureDebugAnimations, "Loading hotspot %xh", hotspotId); bool dynamicObject = stream->readByte() != 0; uint16 destHotspotId = stream->readUint16LE(); @@ -4585,9 +4607,7 @@ void HotspotList::loadFromStream(ReadStream *stream) { Hotspot *destHotspot = res.getActiveHotspot(destHotspotId); assert(destHotspot); hotspot = new Hotspot(destHotspot, hotspotId); - } - else - { + } else { HotspotData *hotspotData = res.getHotspot(hotspotId); assert(hotspotData); hotspot = new Hotspot(hotspotData); diff --git a/engines/lure/hotspots.h b/engines/lure/hotspots.h index fb3bb1478b..c30faa58c5 100644 --- a/engines/lure/hotspots.h +++ b/engines/lure/hotspots.h @@ -342,9 +342,13 @@ private: void npcPause(HotspotData *hotspot); void npcStartTalking(HotspotData *hotspot); void npcJumpAddress(HotspotData *hotspot); + + // Auxillaries + void doLookAction(HotspotData *hotspot, Action action); public: Hotspot(HotspotData *res); Hotspot(Hotspot *character, uint16 objType); + Hotspot(); ~Hotspot(); void setAnimation(uint16 newAnimId); diff --git a/engines/lure/intro.cpp b/engines/lure/intro.cpp index 3f939c6389..ae4199051e 100644 --- a/engines/lure/intro.cpp +++ b/engines/lure/intro.cpp @@ -26,20 +26,26 @@ #include "lure/intro.h" #include "lure/animseq.h" #include "lure/events.h" +#include "lure/sound.h" namespace Lure { struct AnimRecord { uint16 resourceId; uint8 paletteIndex; - bool initialPause; - bool endingPause; + uint16 initialPause; + uint16 endingPause; + uint8 soundNumber; }; static const uint16 start_screens[] = {0x18, 0x1A, 0x1E, 0x1C, 0}; -static const AnimRecord anim_screens[] = {{0x40, 0, true, true}, {0x42, 1, false, true}, - {0x44, 2, false, false}, {0x24, 3, false, true}, {0x46, 3, false, false}, - {0, 0, false, false}}; +static const AnimRecord anim_screens[] = { + {0x40, 0, 0x35A, 0xC8, 0}, // The kingdom was at peace + {0x42, 1, 0, 0x5FA, 1}, // Cliff overhang + {0x44, 2, 0, 0, 2}, // Siluette in moonlight + {0x24, 3, 0, 0x328 + 0x24, 0xff}, // Exposition of reaching town + {0x46, 3, 0, 0, 3}, // Skorl approaches + {0, 0, 0, 0, 0xff}}; // showScreen // Shows a screen by loading it from the given resource, and then fading it in @@ -73,26 +79,38 @@ bool Introduction::show() { if (showScreen(start_screens[ctr], start_screens[ctr] + 1, 5000)) return true; - AnimationSequence *anim; - bool result; - // Animated screens + AnimationSequence *anim; + bool result; + uint8 currentSound = 0xff; PaletteCollection coll(0x32); const AnimRecord *curr_anim = anim_screens; - for (; curr_anim->resourceId; ++curr_anim) - { + for (; curr_anim->resourceId; ++curr_anim) { + // Handle sound selection + if (curr_anim->soundNumber != 0xff) { + if (currentSound != 0xff) + // Fade out the previous sound + Sound.fadeOut(); + + currentSound = curr_anim->soundNumber; + Sound.musicInterface_Play(currentSound, 0); + // DEBUG TEST +// g_system->delayMillis(1000); +// Sound.musicInterface_Play(1, 1); + } + bool fadeIn = curr_anim == anim_screens; anim = new AnimationSequence(_screen, _system, curr_anim->resourceId, coll.getPalette(curr_anim->paletteIndex), fadeIn); - if (curr_anim->initialPause) - if (events.interruptableDelay(12000)) return true; + if (curr_anim->initialPause != 0) + if (events.interruptableDelay(curr_anim->initialPause * 1000 / 50)) return true; result = false; switch (anim->show()) { case ABORT_NONE: - if (curr_anim->endingPause) { - result = events.interruptableDelay(12000); + if (curr_anim->endingPause != 0) { + result = events.interruptableDelay(curr_anim->endingPause * 1000 / 50); } break; @@ -105,7 +123,10 @@ bool Introduction::show() { } delete anim; - if (result) return true; + if (result) { + Sound.musicInterface_KillAll(); + return true; + } } // Show battle pictures one frame at a time @@ -119,12 +140,12 @@ bool Introduction::show() { if (result) break; } while (anim->step()); delete anim; - if (result) return true; - - // Show final introduction screen - - showScreen(0x22, 0x21, 10000); + + if (!result) + // Show final introduction screen + showScreen(0x22, 0x21, 10000); + Sound.musicInterface_KillAll(); return false; } diff --git a/engines/lure/lure.cpp b/engines/lure/lure.cpp index f7c4272f0e..ada8f5081b 100644 --- a/engines/lure/lure.cpp +++ b/engines/lure/lure.cpp @@ -34,6 +34,7 @@ #include "lure/lure.h" #include "lure/intro.h" #include "lure/game.h" +#include "lure/sound.h" namespace Lure { @@ -45,17 +46,16 @@ LureEngine::LureEngine(OSystem *system): Engine(system) { Common::addSpecialDebugLevel(kLureDebugAnimations, "animations", "Animations debugging"); Common::addSpecialDebugLevel(kLureDebugHotspots, "hotspots", "Hotspots debugging"); Common::addSpecialDebugLevel(kLureDebugFights, "fights", "Fights debugging"); + Common::addSpecialDebugLevel(kLureDebugSounds, "sounds", "Sounds debugging"); // Setup mixer -/* + if (!_mixer->isReady()) { warning("Sound initialization failed."); } _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); -*/ _features = 0; _game = 0; @@ -106,7 +106,9 @@ LureEngine &LureEngine::getReference() { int LureEngine::go() { if (ConfMan.getInt("boot_param") == 0) { // Show the introduction + Sound.loadSection(INTRO_SOUND_RESOURCE_ID); Introduction *intro = new Introduction(*_screen, *_system); + intro->show(); delete intro; } @@ -114,6 +116,7 @@ int LureEngine::go() { // Play the game if (!_events->quitFlag) { // Play the game + Sound.loadSection(MAIN_SOUND_RESOURCE_ID); Game *gameInstance = new Game(); gameInstance->execute(); delete gameInstance; @@ -169,8 +172,7 @@ bool LureEngine::loadGame(uint8 slotNumber) { // Check for header char buffer[5]; f->read(buffer, 5); - if (memcmp(buffer, "lure", 5) != 0) - { + if (memcmp(buffer, "lure", 5) != 0) { warning(FAILED_MSG, slotNumber); delete f; return false; @@ -179,8 +181,7 @@ bool LureEngine::loadGame(uint8 slotNumber) { // Check language version uint8 language = f->readByte(); uint8 version = f->readByte(); - if ((language != _language) || (version != LURE_DAT_MINOR)) - { + if ((language != _language) || (version != LURE_DAT_MINOR)) { warning("loadGame: Failed to load slot %d - incorrect version", slotNumber); delete f; return false; diff --git a/engines/lure/lure.h b/engines/lure/lure.h index aa7f0ae93a..7ac0977900 100644 --- a/engines/lure/lure.h +++ b/engines/lure/lure.h @@ -71,6 +71,7 @@ public: uint32 features() { return _features; } uint8 game() { return _game; } Disk &disk() { return *_disk; } + Common::Language getLanguage() { return _language; } bool loadGame(uint8 slotNumber); bool saveGame(uint8 slotNumber, Common::String &caption); diff --git a/engines/lure/luredefs.h b/engines/lure/luredefs.h index d5991a5807..ef48f6f452 100644 --- a/engines/lure/luredefs.h +++ b/engines/lure/luredefs.h @@ -34,7 +34,7 @@ namespace Lure { #define SUPPORT_FILENAME "lure.dat" #define LURE_DAT_MAJOR 1 -#define LURE_DAT_MINOR 20 +#define LURE_DAT_MINOR 21 #define LURE_DEBUG 1 @@ -45,7 +45,8 @@ enum { kLureDebugScripts = 1 << 0, kLureDebugAnimations = 1 << 1, kLureDebugHotspots = 1 << 2, - kLureDebugFights = 1 << 3 + kLureDebugFights = 1 << 3, + kLureDebugSounds = 1 << 4 }; #define ERROR_BASIC 1 @@ -222,13 +223,15 @@ enum CursorType {CURSOR_ARROW = 0, CURSOR_DISK = 1, CURSOR_TIME_START = 2, #define EXIT_HOTSPOT_ID_LIST 0x3f15 #define FIGHT_DATA_RESOURCE_ID 0x3f16 #define STRING_LIST_RESOURCE_ID 0x3f17 +#define SOUND_DESC_RESOURCE_ID 0x3f18 // Script constants #define STARTUP_SCRIPT 0x23FC // Miscellaneous resources -#define CREDITS_RESOURCE_ID 0x7800 #define NAMES_RESOURCE_ID 9 +#define MAIN_SOUND_RESOURCE_ID 0xC +#define INTRO_SOUND_RESOURCE_ID 0x31 #define NOONE_ID 0x3E7 #define PLAYER_ID 0x3E8 #define RATPOUCH_ID 0x3E9 @@ -249,12 +252,16 @@ enum CursorType {CURSOR_ARROW = 0, CURSOR_DISK = 1, CURSOR_TIME_START = 2, #define SKORL_FIGHTER_ID 0x444 #define START_EXIT_ID 0x2710 #define BOTTLE_HOTSPOT_ID 0x2710 +#define CELL_DOOR_HOTSPOT_ID 0x2712 #define BRICKS_ID 0x2714 #define BOOK_ID 0x2723 #define START_NONVISUAL_HOTSPOT_ID 0x7530 +#define CREDITS_RESOURCE_ID 0x7800 +#define RESTART_RESOURCE_ID 0x7900 // Milliseconds delay between game frames #define GAME_FRAME_DELAY 80 +#define GAME_TICK_DELAY 20 // Tick proc constants #define STANDARD_CHARACTER_TICK_PROC 0x4f82 @@ -287,12 +294,14 @@ enum CursorType {CURSOR_ARROW = 0, CURSOR_DISK = 1, CURSOR_TIME_START = 2, #define EWAN_ALT_ANIM_ID 0x59ED #define PLAYER_ANIM_ID 0x5C80 #define SELENA_ANIM_ID 0x5CAA +#define DEFAULT_VOLUME 192 #define CONVERSE_COUNTDOWN_SIZE 40 #define IDLE_COUNTDOWN_SIZE 15 #define MAX_TELL_COMMANDS 8 #define MAX_SAVEGAME_SLOTS 10 +#define ROOMNUM_VILLAGE_SHOP 35 #define ROOMNUM_CAVE 38 #define ROOMNUM_CELLAR 42 #define ROOMNUM_DINING_HALL 45 diff --git a/engines/lure/menu.cpp b/engines/lure/menu.cpp index 3bb6769ff7..7dfb6e2a57 100644 --- a/engines/lure/menu.cpp +++ b/engines/lure/menu.cpp @@ -106,8 +106,7 @@ uint8 Menu::execute() { while (events.pollEvent()) { if (events.quitFlag) return MENUITEM_NONE; - if (mouse.y() < MENUBAR_Y_SIZE) - { + if (mouse.y() < MENUBAR_Y_SIZE) { MenuRecord *p = getMenuAt(mouse.x()); if (_selectedMenu != p) { diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp index 4da38eddc7..b0e99b5be5 100644 --- a/engines/lure/res.cpp +++ b/engines/lure/res.cpp @@ -42,11 +42,19 @@ Resources &Resources::getReference() { Resources::Resources() { int_resources = this; reloadData(); + + // Load the string list + MemoryBlock *mb = Disk::getReference().getEntry(STRING_LIST_RESOURCE_ID); + _stringList.load(mb); + delete mb; } Resources::~Resources() { // Free up any loaded data freeData(); + + // Free up constant data + _stringList.clear(); } void Resources::freeData() { @@ -61,12 +69,16 @@ void Resources::freeData() { _randomActions.clear(); _indexedRoomExitHospots.clear(); _pausedList.clear(); - _stringList.clear(); + _actionsList.clear(); + _coordinateList.clear(); + _talkHeaders.clear(); + _talkData.clear(); + free(_hotspotScriptData); delete _paletteSubset; delete _scriptData; delete _script2Data; - free(_hotspotScriptData); + delete _talkDialogData; delete _messagesData; delete _cursors; delete [] _charOffsets; @@ -77,6 +89,13 @@ struct AnimRecordTemp { MovementDataList *list; }; +void Resources::reset() { + freeData(); + + _fieldList.reset(); + reloadData(); +} + void Resources::reloadData() { Disk &d = Disk::getReference(); MemoryBlock *mb, *paths; @@ -312,11 +331,6 @@ void Resources::reloadData() { indexedRec++; } - // Load the string list - mb = d.getEntry(STRING_LIST_RESOURCE_ID); - _stringList.load(mb); - delete mb; - // Initialise delay list _delayList.clear(true); @@ -341,7 +355,7 @@ RoomExitJoinData *Resources::getExitJoin(uint16 hotspotId) { for (i = _exitJoins.begin(); i != _exitJoins.end(); ++i) { RoomExitJoinData *rec = *i; - if ((rec->hotspot1Id == hotspotId) || (rec->hotspot2Id == hotspotId)) + if ((rec->hotspots[0].hotspotId == hotspotId) || (rec->hotspots[1].hotspotId == hotspotId)) return rec; } @@ -645,8 +659,7 @@ void Resources::setTalkData(uint16 offset) { error("Unknown talk entry offset %d requested", offset); } -void Resources::saveToStream(Common::WriteStream *stream) -{ +void Resources::saveToStream(Common::WriteStream *stream) { _hotspotData.saveToStream(stream); _activeHotspots.saveToStream(stream); _fieldList.saveToStream(stream); diff --git a/engines/lure/res.h b/engines/lure/res.h index 7c9970f27f..86d5ad5d95 100644 --- a/engines/lure/res.h +++ b/engines/lure/res.h @@ -88,12 +88,13 @@ private: int _talkStartEntry; uint16 _talkingCharacter; + void reloadData(); void freeData(); public: Resources(); ~Resources(); static Resources &getReference(); - void reloadData(); + void reset(); byte *getResource(uint16 resId); RoomDataList &roomData() { return _roomData; } diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp index 12cf61a58a..f4506406ef 100644 --- a/engines/lure/res_struct.cpp +++ b/engines/lure/res_struct.cpp @@ -30,47 +30,47 @@ namespace Lure { -const Action sortedActions[] = {ASK, BRIBE, BUY, CLOSE, DRINK, EXAMINE, GET, GIVE, +extern const Action sortedActions[] = {ASK, BRIBE, BUY, CLOSE, DRINK, EXAMINE, GET, GIVE, GO_TO, LOCK, LOOK, LOOK_AT, LOOK_THROUGH, OPEN, OPERATE, PULL, PUSH, RETURN, STATUS, TALK_TO, TELL, UNLOCK, USE, NONE}; -int actionNumParams[NPC_JUMP_ADDRESS+1] = {0, +extern const int actionNumParams[NPC_JUMP_ADDRESS+1] = {0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 0, 1, 0, 1, 1, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1, 1, 2, 2, 5, 2, 2, 1}; // Barman related frame lists -uint16 basicPolish[] = {8+13,8+14,8+15,8+16,8+17,8+18,8+17,8+16,8+15,8+14, +static const uint16 basicPolish[] = {8+13,8+14,8+15,8+16,8+17,8+18,8+17,8+16,8+15,8+14, 8+15,8+16,8+17,8+18,8+17,8+16,8+15,8+14,8+13,0}; -uint16 sidsFetch[] = {12+1,12+2,12+3,12+4,12+5,12+6,12+5,12+6,12+5,12+4,12+3,12+7,12+8,0}; +static const uint16 sidsFetch[] = {12+1,12+2,12+3,12+4,12+5,12+6,12+5,12+6,12+5,12+4,12+3,12+7,12+8,0}; -uint16 nelliesScratch[] = {11+1,11+2,11+3,11+4,11+5,11+4,11+5,11+4,11+5,11+4,11+3,11+2,11+1,0}; +static const uint16 nelliesScratch[] = {11+1,11+2,11+3,11+4,11+5,11+4,11+5,11+4,11+5,11+4,11+3,11+2,11+1,0}; -uint16 nelliesFetch[] = {1,2,3,4,5,4,5,4,3,2,6,7,0}; +static const uint16 nelliesFetch[] = {1,2,3,4,5,4,5,4,3,2,6,7,0}; -uint16 ewansFetch[] = {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,0}; +static const uint16 ewansFetch[] = {13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,0}; -uint16 ewanExtraGraphic1[]= { +static const uint16 ewanExtraGraphic1[]= { 28,29,30,31,32,33,34,35,36,37, 38,39,40,41,42,43,44,45,46,47, 48, 40,39,38,37,36,35,34,33,32,31,30,29,28, 0}; -uint16 ewanExtraGraphic2[] = { +static const uint16 ewanExtraGraphic2[] = { 1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19, 20,21,22,23,24,0}; -BarEntry barList[3] = { +static const BarEntry default_barList[3] = { {29, SID_ID, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, {&basicPolish[0], &sidsFetch[0], NULL, NULL}, 13, NULL}, {32, NELLIE_ID, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, {&nelliesScratch[0], &nelliesFetch[0], NULL, NULL}, 14, NULL}, {35, EWAN_ID, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, {&ewansFetch[0], &ewansFetch[0], &ewanExtraGraphic1[0], &ewanExtraGraphic2[0]}, 16, NULL} }; -RoomTranslationRecord roomTranslations[] = { +extern const RoomTranslationRecord roomTranslations[] = { {0x1E, 0x13}, {0x07, 0x08}, {0x1C, 0x12}, {0x26, 0x0F}, {0x27, 0x0F}, {0x28, 0x0F}, {0x29, 0x0F}, {0x22, 0x0A}, {0x23, 0x13}, {0x24, 0x14}, {0x31, 0x2C}, {0x2F, 0x2C}, @@ -308,28 +308,29 @@ void RoomDataList::loadFromStream(ReadStream *stream) { // Room exit joins class RoomExitJoinData::RoomExitJoinData(RoomExitJoinResource *rec) { - hotspot1Id = FROM_LE_16(rec->hotspot1Id); - h1CurrentFrame = rec->h1CurrentFrame; - h1DestFrame = rec->h1DestFrame; - h1OpenSound = rec->h1OpenSound; - h1CloseSound = rec->h1CloseSound; - hotspot2Id = FROM_LE_16(rec->hotspot2Id); - h2CurrentFrame = rec->h2CurrentFrame; - h2DestFrame = rec->h2DestFrame; - h2OpenSound = rec->h2OpenSound; - h2CloseSound = rec->h2CloseSound; + hotspots[0].hotspotId = FROM_LE_16(rec->hotspot1Id); + hotspots[0].currentFrame = rec->h1CurrentFrame; + hotspots[0].destFrame = rec->h1DestFrame; + hotspots[0].openSound = rec->h1OpenSound; + hotspots[0].closeSound = rec->h1CloseSound; + hotspots[1].hotspotId = FROM_LE_16(rec->hotspot2Id); + hotspots[1].currentFrame = rec->h2CurrentFrame; + hotspots[1].destFrame = rec->h2DestFrame; + hotspots[1].openSound = rec->h2OpenSound; + hotspots[1].closeSound = rec->h2CloseSound; blocked = rec->blocked; } void RoomExitJoinList::saveToStream(WriteStream *stream) { for (RoomExitJoinList::iterator i = begin(); i != end(); ++i) { RoomExitJoinData *rec = *i; - stream->writeUint16LE(rec->hotspot1Id); - stream->writeUint16LE(rec->hotspot2Id); - stream->writeByte(rec->h1CurrentFrame); - stream->writeByte(rec->h1DestFrame); - stream->writeByte(rec->h2CurrentFrame); - stream->writeByte(rec->h2DestFrame); + + stream->writeUint16LE(rec->hotspots[0].hotspotId); + stream->writeUint16LE(rec->hotspots[1].hotspotId); + stream->writeByte(rec->hotspots[0].currentFrame); + stream->writeByte(rec->hotspots[0].destFrame); + stream->writeByte(rec->hotspots[1].currentFrame); + stream->writeByte(rec->hotspots[1].destFrame); stream->writeByte(rec->blocked); } @@ -345,13 +346,14 @@ void RoomExitJoinList::loadFromStream(ReadStream *stream) { if (hotspot1Id == 0xffff) error("Invalid room exit join list"); uint16 hotspot2Id = stream->readUint16LE(); - if ((rec->hotspot1Id != hotspot1Id) || (rec->hotspot2Id != hotspot2Id)) + if ((rec->hotspots[0].hotspotId != hotspot1Id) || + (rec->hotspots[1].hotspotId != hotspot2Id)) break; - rec->h1CurrentFrame = stream->readByte(); - rec->h1DestFrame = stream->readByte(); - rec->h2CurrentFrame = stream->readByte(); - rec->h2DestFrame = stream->readByte(); + rec->hotspots[0].currentFrame = stream->readByte(); + rec->hotspots[0].destFrame = stream->readByte(); + rec->hotspots[1].currentFrame = stream->readByte(); + rec->hotspots[1].destFrame = stream->readByte(); rec->blocked = stream->readByte(); } @@ -429,6 +431,8 @@ HotspotData::HotspotData(HotspotResource *rec) { pauseCtr = 0; actionHotspotId = 0; talkOverride = 0; + talkGate = 0; + scriptHotspotId = 0; } void HotspotData::saveToStream(WriteStream *stream) { @@ -517,8 +521,7 @@ void HotspotData::loadFromStream(ReadStream *stream) { void HotspotDataList::saveToStream(WriteStream *stream) { iterator i; - for (i = begin(); i != end(); ++i) - { + for (i = begin(); i != end(); ++i) { HotspotData *hotspot = *i; stream->writeUint16LE(hotspot->hotspotId); hotspot->saveToStream(stream); @@ -530,8 +533,7 @@ void HotspotDataList::loadFromStream(ReadStream *stream) { Resources &res = Resources::getReference(); iterator i; uint16 hotspotId = stream->readUint16LE(); - while (hotspotId != 0) - { + while (hotspotId != 0) { HotspotData *hotspot = res.getHotspot(hotspotId); assert(hotspot); hotspot->loadFromStream(stream); @@ -963,8 +965,7 @@ RandomActionSet::~RandomActionSet() { RandomActionSet *RandomActionList::getRoom(uint16 roomNumber) { iterator i; - for (i = begin(); i != end(); ++i) - { + for (i = begin(); i != end(); ++i) { RandomActionSet *v = *i; if (v->roomNumber() == roomNumber) return v; @@ -1104,8 +1105,7 @@ int PausedCharacterList::check(uint16 charId, int numImpinging, uint16 *impingin // There was, so move to next impinging character entry continue; - if ((hotspot->hotspotId() == PLAYER_ID) && !hotspot->coveredFlag()) - { + if ((hotspot->hotspotId() == PLAYER_ID) && !hotspot->coveredFlag()) { hotspot->updateMovement(); return 1; } @@ -1137,39 +1137,37 @@ int PausedCharacterList::check(uint16 charId, int numImpinging, uint16 *impingin // Wrapper class for the barman lists -BarEntry &BarmanLists::getDetails(uint16 roomNumber) -{ +BarmanLists::BarmanLists() { + for (int index = 0; index < 3; ++index) + _barList[index] = default_barList[index]; +} + +BarEntry &BarmanLists::getDetails(uint16 roomNumber) { for (int index = 0; index < 3; ++index) - if (barList[index].roomNumber == roomNumber) - return barList[index]; + if (_barList[index].roomNumber == roomNumber) + return _barList[index]; error("Invalid room %d specified for barman details retrieval", roomNumber); } -void BarmanLists::saveToStream(Common::WriteStream *stream) -{ - for (int index = 0; index < 2; ++index) - { - uint16 value = (barList[index].currentCustomer - &barList[index].customers[0]) / sizeof(BarEntry); +void BarmanLists::saveToStream(Common::WriteStream *stream) { + for (int index = 0; index < 2; ++index) { + uint16 value = (_barList[index].currentCustomer - &_barList[index].customers[0]) / sizeof(BarEntry); stream->writeUint16LE(value); - for (int ctr = 0; ctr < NUM_SERVE_CUSTOMERS; ++ctr) - { - stream->writeUint16LE(barList[index].customers[ctr].hotspotId); - stream->writeByte(barList[index].customers[ctr].serveFlags); + for (int ctr = 0; ctr < NUM_SERVE_CUSTOMERS; ++ctr) { + stream->writeUint16LE(_barList[index].customers[ctr].hotspotId); + stream->writeByte(_barList[index].customers[ctr].serveFlags); } } } -void BarmanLists::loadFromStream(Common::ReadStream *stream) -{ - for (int index = 0; index < 2; ++index) - { +void BarmanLists::loadFromStream(Common::ReadStream *stream) { + for (int index = 0; index < 2; ++index) { int16 value = stream->readUint16LE(); - barList[index].currentCustomer = (value == 0) ? NULL : &barList[index].customers[value]; + _barList[index].currentCustomer = (value == 0) ? NULL : &_barList[index].customers[value]; - for (int ctr = 0; ctr < NUM_SERVE_CUSTOMERS; ++ctr) - { - barList[index].customers[ctr].hotspotId = stream->readUint16LE(); - barList[index].customers[ctr].serveFlags = stream->readByte(); + for (int ctr = 0; ctr < NUM_SERVE_CUSTOMERS; ++ctr) { + _barList[index].customers[ctr].hotspotId = stream->readUint16LE(); + _barList[index].customers[ctr].serveFlags = stream->readByte(); } } } @@ -1202,12 +1200,16 @@ void StringList::clear() { // Field list and miscellaneous variables ValueTableData::ValueTableData() { + reset(); +} + +void ValueTableData::reset() { _numGroats = 0; _playerNewPos.roomNumber = 0; _playerNewPos.position.x = 0; _playerNewPos.position.y = 0; _flags = GAMEFLAG_4 | GAMEFLAG_1; - _hdrFlagMask = 1; + _hdrFlagMask = 1; for (uint16 index = 0; index < NUM_VALUE_FIELDS; ++index) _fieldList[index] = 0; @@ -1242,8 +1244,7 @@ void ValueTableData::setField(FieldName fieldName, uint16 value) { setField((uint16) fieldName, value); } -void ValueTableData::saveToStream(Common::WriteStream *stream) -{ +void ValueTableData::saveToStream(Common::WriteStream *stream) { // Write out the special fields stream->writeUint16LE(_numGroats); stream->writeSint16LE(_playerNewPos.position.x); @@ -1257,8 +1258,7 @@ void ValueTableData::saveToStream(Common::WriteStream *stream) stream->writeUint16LE(_fieldList[index]); } -void ValueTableData::loadFromStream(Common::ReadStream *stream) -{ +void ValueTableData::loadFromStream(Common::ReadStream *stream) { // Load special fields _numGroats = stream->readUint16LE(); _playerNewPos.position.x = stream->readSint16LE(); diff --git a/engines/lure/res_struct.h b/engines/lure/res_struct.h index 4d2c55e6b1..81ecd87563 100644 --- a/engines/lure/res_struct.h +++ b/engines/lure/res_struct.h @@ -225,6 +225,18 @@ struct RoomExitIndexedHotspotResource { uint16 hotspotId; } PACKED_STRUCT; +enum SoundDescFlags {SF_IN_USE = 1, SF_RESTORE = 2}; + +// In desc entry, numChannels: bits 0-1 # roland, bits 2-3 #adlib, bits 4-5 #internal + +struct SoundDescResource { + uint8 soundNumber; + uint8 channel; + uint8 numChannels; + uint8 flags; + uint8 volume; +} PACKED_STRUCT; + #include "common/pack-end.h" // END STRUCT PACKING /** @@ -242,23 +254,28 @@ public: } void clear() { - typename Common::List<T>::iterator i; - for (i = Common_List::begin(); i != Common_List::end(); ++i) - delete *i; - Common_List::clear(); + typename Common_List::iterator i = Common_List::begin(); + while (i != Common_List::end()) { + T v = *i; + i = Common_List::erase(i); + delete v; + } } - typename Common::List<T>::iterator erase(typename Common::List<T>::iterator pos) { - delete *pos; - return Common_List::erase(pos); + typename Common_List::iterator erase(typename Common_List::iterator pos) { + T obj = *pos; + typename Common_List::iterator result = Common_List::erase(pos); + delete obj; + return result; } - typename Common::List<T>::iterator erase(typename Common::List<T>::iterator first, - typename Common::List<T>::iterator last) { - typename Common::List<T>::iterator i; - for (i = first; i != last; ++i) - delete *i; - return Common_List::erase(first, last); + typename Common_List::iterator erase(typename Common_List::iterator first, + typename Common_List::iterator last) { + + while (first != last) + erase(first++); + + return last; } }; @@ -353,22 +370,21 @@ public: void loadFromStream(ReadStream *stream); }; +struct RoomExitJoinStruct { + uint16 hotspotId; + byte currentFrame; + byte destFrame; + uint8 openSound; + uint8 closeSound; +}; + class RoomExitJoinData { public: RoomExitJoinData(RoomExitJoinResource *rec); - uint16 hotspot1Id; - byte h1CurrentFrame; - byte h1DestFrame; - uint8 h1OpenSound; - uint8 h1CloseSound; - uint16 hotspot2Id; - byte h2CurrentFrame; - byte h2DestFrame; - uint8 h2OpenSound; - uint8 h2CloseSound; + RoomExitJoinStruct hotspots[2]; + byte blocked; - uint32 unknown; }; class RoomExitJoinList: public ManagedList<RoomExitJoinData *> { @@ -618,7 +634,7 @@ public: // The following classes holds the data for NPC schedules -extern int actionNumParams[NPC_JUMP_ADDRESS+1]; +extern const int actionNumParams[NPC_JUMP_ADDRESS+1]; class CharacterScheduleSet; @@ -730,13 +746,16 @@ struct BarEntry { uint16 roomNumber; uint16 barmanId; ServeEntry customers[NUM_SERVE_CUSTOMERS]; - uint16 *graphics[4]; + const uint16 *graphics[4]; uint16 gridLine; ServeEntry *currentCustomer; }; class BarmanLists { + BarEntry _barList[3]; public: + BarmanLists(); + BarEntry &getDetails(uint16 roomNumber); void saveToStream(Common::WriteStream *stream); void loadFromStream(Common::ReadStream *stream); @@ -749,7 +768,7 @@ struct RoomTranslationRecord { uint8 destRoom; }; -extern RoomTranslationRecord roomTranslations[]; +extern const RoomTranslationRecord roomTranslations[]; enum StringEnum {S_CREDITS = 25, S_RESTART_GAME = 26, S_SAVE_GAME = 27, S_RESTORE_GAME = 28, S_QUIT = 29, S_FAST_TEXT = 30, S_SLOW_TEXT = 31, S_SOUND_ON = 32, S_SOUND_OFF = 33, @@ -797,7 +816,8 @@ enum FieldName { BOTTLE_FILLED = 18, TALK_INDEX = 19, SACK_CUT = 20, - ROOM_EXIT_ANIMATION = 76 + ROOM_EXIT_ANIMATION = 76, + AREA_FLAG = 82 }; enum GameFlags { @@ -827,6 +847,7 @@ private: bool isKnownField(uint16 fieldIndex); public: ValueTableData(); + void reset(); uint16 getField(uint16 fieldIndex); uint16 getField(FieldName fieldName); diff --git a/engines/lure/room.cpp b/engines/lure/room.cpp index b48b50197b..acab44deea 100644 --- a/engines/lure/room.cpp +++ b/engines/lure/room.cpp @@ -492,13 +492,13 @@ void Room::update() { } void Room::setRoomNumber(uint16 newRoomNumber, bool showOverlay) { - Resources &r = Resources::getReference(); + Resources &res = Resources::getReference(); Game &game = Game::getReference(); Mouse &mouse = Mouse::getReference(); mouse.pushCursorNum(CURSOR_DISK); - _roomData = r.getRoom(newRoomNumber); + _roomData = res.getRoom(newRoomNumber); if (!_roomData) error("Tried to change to non-existant room: %d", newRoomNumber); bool leaveFlag = (_layers[0] && (newRoomNumber != _roomNumber) && (_roomNumber != 0)); @@ -512,6 +512,7 @@ void Room::setRoomNumber(uint16 newRoomNumber, bool showOverlay) { } _screen.empty(); + _screen.setPaletteEmpty(GAME_COLOURS); _numLayers = _roomData->numLayers; if (showOverlay) ++_numLayers; @@ -521,36 +522,38 @@ void Room::setRoomNumber(uint16 newRoomNumber, bool showOverlay) { _layers[layerNum] = new RoomLayer(_roomData->layers[layerNum], layerNum == 0); - // Load in the game palette and set the non-room specific colours at the top end of the palette + // Load in the game palette, which contains at it's top end general GUI element colours Palette mainPalette(GAME_PALETTE_RESOURCE_ID); - _screen.setPalette(&mainPalette, MAIN_PALETTE_SIZE, GAME_COLOURS - MAIN_PALETTE_SIZE); + _screen.setPalette(&mainPalette, 0, GAME_COLOURS); + + // Generate the palette for the room that will be faded in + Palette p(MAIN_PALETTE_SIZE, NULL, RGB64); + Palette tempPalette(paletteId); + p.copyFrom(&tempPalette); + res.insertPaletteSubset(p); // Set the new room number - r.fieldList().setField(ROOM_NUMBER, newRoomNumber); + res.fieldList().setField(ROOM_NUMBER, newRoomNumber); if (_roomData->sequenceOffset != 0xffff) Script::execute(_roomData->sequenceOffset); loadRoomHotspots(); - if (_roomData->exitTime != 0xffff) - { + if ((_roomData->exitTime != 0xffff) && (_roomData->exitTime != 0)) { // If time has passed, animation ticks needed before room is displayed int numSeconds = (g_system->getMillis() - _roomData->exitTime) / 1000; if (numSeconds > 300) numSeconds = 300; + game.preloadFlag() = true; while (numSeconds-- > 0) - game.tick(true); + game.tick(); + game.preloadFlag() = false; } + game.tick(); update(); _screen.update(); - - // Generate the palette for the room and fade it in - Palette p(MAIN_PALETTE_SIZE, NULL, RGB64); - Palette tempPalette(paletteId); - p.copyFrom(&tempPalette); - r.insertPaletteSubset(p); _screen.paletteFadeIn(&p); mouse.popCursor(); diff --git a/engines/lure/screen.cpp b/engines/lure/screen.cpp index 0cd2dd9357..552e609b84 100644 --- a/engines/lure/screen.cpp +++ b/engines/lure/screen.cpp @@ -55,11 +55,11 @@ Screen::~Screen() { // setPaletteEmpty // Defaults the palette to an empty set -void Screen::setPaletteEmpty() { +void Screen::setPaletteEmpty(int numEntries) { delete _palette; _palette = new Palette(); - _system.setPalette(_palette->data(), 0, GAME_COLOURS); + _system.setPalette(_palette->data(), 0, numEntries); _system.updateScreen(); } @@ -76,9 +76,8 @@ void Screen::setPalette(Palette *p) { // Variation that allows the specification of a subset of a palette passed in to be copied void Screen::setPalette(Palette *p, uint16 start, uint16 num) { - _palette->palette()->copyFrom(p->palette(), start * PALETTE_FADE_INC_SIZE, - start * PALETTE_FADE_INC_SIZE, num * PALETTE_FADE_INC_SIZE); - _system.setPalette(_palette->data(), 0, GAME_COLOURS); + _palette->palette()->copyFrom(p->palette(), start * 4, start * 4, num * 4); + _system.setPalette(_palette->data(), start, num); _system.updateScreen(); } @@ -96,8 +95,7 @@ void Screen::paletteFadeIn(Palette *p) { byte *pFinal = p->data(); byte *pCurrent = _palette->data(); - for (int palCtr = 0; palCtr < p->numEntries() * PALETTE_FADE_INC_SIZE; ++palCtr, ++pCurrent, ++pFinal) - { + for (int palCtr = 0; palCtr < p->numEntries() * PALETTE_FADE_INC_SIZE; ++palCtr, ++pCurrent, ++pFinal) { if (palCtr % PALETTE_FADE_INC_SIZE == (PALETTE_FADE_INC_SIZE - 1)) continue; bool isDifferent = *pCurrent < *pFinal; @@ -111,7 +109,7 @@ void Screen::paletteFadeIn(Palette *p) { } if (changed) { - _system.setPalette(_palette->data(), 0, GAME_COLOURS); + _system.setPalette(_palette->data(), 0, p->numEntries()); _system.updateScreen(); _system.delayMillis(20); events.pollEvent(); @@ -143,7 +141,7 @@ void Screen::paletteFadeOut(int numEntries) { } if (changed) { - _system.setPalette(_palette->data(), 0, GAME_COLOURS); + _system.setPalette(_palette->data(), 0, numEntries); _system.updateScreen(); _system.delayMillis(20); events.pollEvent(); diff --git a/engines/lure/screen.h b/engines/lure/screen.h index 7182c4236b..90db7ee314 100644 --- a/engines/lure/screen.h +++ b/engines/lure/screen.h @@ -47,12 +47,12 @@ public: ~Screen(); static Screen &getReference(); - void setPaletteEmpty(); + void setPaletteEmpty(int numEntries = RES_PALETTE_ENTRIES); void setPalette(Palette *p); void setPalette(Palette *p, uint16 start, uint16 num); Palette &getPalette() { return *_palette; } void paletteFadeIn(Palette *p); - void paletteFadeOut(int numEntries = MAIN_PALETTE_SIZE); + void paletteFadeOut(int numEntries = RES_PALETTE_ENTRIES); void resetPalette(); void empty(); void update(); diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp index 3ce1b916b3..bba364bcf2 100644 --- a/engines/lure/scripts.cpp +++ b/engines/lure/scripts.cpp @@ -38,12 +38,12 @@ namespace Lure { // This list of hotspot Ids are used by sequence method #5 to deallocate a set // of hotspot Ids at once -uint16 dealloc_list_1[] = {0x13F2, 0x418, 0x2711, 0x2712, 0x40D, 0x3EA, 0x411, 0}; -uint16 dealloc_list_2[] = {0x2729, 0x272A, 0x272B, 0x272C, 0x272E, 0x272E, 0x272F, 0}; -uint16 dealloc_list_3[] = {0x3EF, 0x3E9, 0x3EB, 0x3EC, 0x3ED, 0x3EE, 0x3F0, 0x3F1, +static const uint16 dealloc_list_1[] = {0x13F2, 0x418, 0x2711, 0x2712, 0x40D, 0x3EA, 0x411, 0}; +static const uint16 dealloc_list_2[] = {0x2729, 0x272A, 0x272B, 0x272C, 0x272E, 0x272E, 0x272F, 0}; +static const uint16 dealloc_list_3[] = {0x3EF, 0x3E9, 0x3EB, 0x3EC, 0x3ED, 0x3EE, 0x3F0, 0x3F1, 0x420, 0x429, 0x436, 0x2715, 0x2716, 0x2717, 0x2718, 0x2719, 0x271A, 0x271E, 0x271F, 0x2720, 0x2721, 0x2722, 0x2725, 0x2726, 0}; -uint16 *hotspot_dealloc_set[4] = {&dealloc_list_1[0], &dealloc_list_2[0], +static const uint16 *hotspot_dealloc_set[4] = {&dealloc_list_1[0], &dealloc_list_2[0], &dealloc_list_3[1], &dealloc_list_3[0]}; /*------------------------------------------------------------------------*/ @@ -75,8 +75,8 @@ void Script::setHotspotScript(uint16 hotspotId, uint16 scriptIndex, uint16 v3) { } } -void Script::addSound2(uint16 soundId, uint16 v2, uint16 v3) { - // TODO: Not yet implemented +void Script::addSound2(uint16 soundIndex, uint16 v2, uint16 v3) { + Sound.addSound2(soundIndex); } // Sets the bitmask indicating what group of rooms/hotspots to display when the @@ -99,7 +99,7 @@ void Script::deactivateHotspotSet(uint16 listIndex, uint16 v2, uint16 v3) { if (listIndex > 3) error("Script::deactiveHotspotSet - Invalid list index"); Resources &res = Resources::getReference(); - uint16 *hotspotId = hotspot_dealloc_set[listIndex]; + const uint16 *hotspotId = hotspot_dealloc_set[listIndex]; while (*hotspotId != 0) { res.deactivateHotspot(*hotspotId); @@ -132,8 +132,7 @@ void Script::deactivateHotspot(uint16 hotspotId, uint16 v2, uint16 v3) { hs->layer = 0xff; } -// Sets the offset for the table of action sequence offsets for the given -// hotspot +// Sets the offset for the table of action sequence offsets for the given hotspot void Script::setDesc(uint16 hotspotId, uint16 descId, uint16 v3) { Resources &res = Resources::getReference(); @@ -151,8 +150,8 @@ void Script::addDelayedSequence(uint16 seqOffset, uint16 delay, uint16 canClear) // Stops the specified sound -void Script::killSound(uint16 soundId, uint16 v2, uint16 v3) { - // TODO +void Script::killSound(uint16 soundNumber, uint16 v2, uint16 v3) { + Sound.musicInterface_Stop(soundNumber); } // Checks whether the given character is in the specified room, and stores @@ -179,8 +178,8 @@ void Script::setHotspotName(uint16 hotspotId, uint16 nameId, uint16 v3) { // Unsure about this method, but at the moment I think it plays a sound -void Script::addSound(uint16 v1, uint16 v2, uint16 v3) { - // TODO: No implementation currently +void Script::addSound(uint16 soundIndex, uint16 v2, uint16 v3) { + Sound.addSound(soundIndex); } void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) { @@ -251,10 +250,10 @@ void Script::startSpeakingToNoone(uint16 characterId, uint16 stringId, uint16 v3 charHotspot->converse(NOONE_ID, stringId, false); } +// Stops playing the specified sound index -void Script::playMusic(uint16 musicNum, uint16 v2, uint16 v3) { - // TODO: Play a given music - warning("TODO: Play music #%d", musicNum); +void Script::stopSound(uint16 soundIndex, uint16 v2, uint16 v3) { + Sound.stopSound(soundIndex); } // Gets the current blocked state for the given door and stores it in the @@ -277,8 +276,7 @@ void Script::isSkorlInCell(uint16 v1, uint16 v2, uint16 v3) { // Called by the script when Ratpouch is pushing the bricks in the Outer Cell -void Script::ratpouchPushBricks(uint16 v1, uint16 v2, uint16 v3) -{ +void Script::ratpouchPushBricks(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); // Mark the bricks exit as now open @@ -309,8 +307,7 @@ void Script::characterChangeRoom(uint16 y, uint16 x, uint16 roomNumber) { // Pauses Ratpouch for a long period (as good as idefinite) -void Script::pauseRatpouch(uint16 v1, uint16 v2, uint16 v3) -{ +void Script::pauseRatpouch(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); Hotspot *ratpouch = res.getActiveHotspot(RATPOUCH_ID); assert(ratpouch); @@ -599,7 +596,7 @@ void Script::moveCharacterToPlayer(uint16 characterId, uint16 v2, uint16 v3) { return; uint16 destRoom = playerHotspot->roomNumber(); - RoomTranslationRecord *rec; + const RoomTranslationRecord *rec; for (rec = &roomTranslations[0]; rec->srcRoom != 0; ++rec) { if (rec->srcRoom == destRoom) { destRoom = rec->destRoom; @@ -714,17 +711,20 @@ void Script::randomToGeneral(uint16 maxVal, uint16 minVal, uint16 v3) { // Checks the status of the cell door, and starts music depending on it's state void Script::checkCellDoor(uint16 v1, uint16 v2, uint16 v3) { - // In the original game, this method checks to see if the cell door - // is currently open, if it is, starts a music sequence. - // TODO: Implement starting music if cell door is open + Resources &res = Resources::getReference(); + RoomExitJoinData *joinRec = res.getExitJoin(CELL_DOOR_HOTSPOT_ID); + + if ((joinRec->blocked == 0) && (res.fieldList().getField(TORCH_HIDE) != 0)) + Sound.addSound(0x15); } // Checks if a sound is running -void Script::checkSound(uint16 hotspotId, uint16 actions, uint16 v3) { - // For now, simply set the general value field so that the Skorl schedule - // will work properly - Resources::getReference().fieldList().setField(GENERAL, 0); +void Script::checkSound(uint16 soundNumber, uint16 v2, uint16 v3) { + Sound.tidySounds(); + + SoundDescResource *rec = Sound.findSound(soundNumber); + Resources::getReference().fieldList().setField(GENERAL, (rec != NULL) ? 1 : 0); } typedef void(*SequenceMethodPtr)(uint16, uint16, uint16); @@ -734,7 +734,7 @@ struct SequenceMethodRecord { SequenceMethodPtr proc; }; -SequenceMethodRecord scriptMethods[] = { +static const SequenceMethodRecord scriptMethods[] = { {0, Script::activateHotspot}, {1, Script::setHotspotScript}, {2, Script::addSound2}, @@ -756,7 +756,7 @@ SequenceMethodRecord scriptMethods[] = { {18, Script::remoteRoomViewSetup}, {19, Script::startSpeakingToNoone}, {20, Script::checkCellDoor}, - {21, Script::playMusic}, + {21, Script::stopSound}, {22, Script::getDoorBlocked}, {23, Script::isSkorlInCell}, {24, Script::ratpouchPushBricks}, @@ -804,14 +804,14 @@ SequenceMethodRecord scriptMethods[] = { {66, Script::checkSound}, {0xff, NULL}}; -const char *scriptOpcodes[] = { +static const char *scriptOpcodes[] = { "ABORT", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "EQUALS", "NOT_EQUALS", "LT", "GT", "LTE", "GTE", "AND", "OR", "LOGICAL_AND", "LOGICAL_OR", "GET_FIELD", "SET_FIELD", "PUSH", "SUBROUTINE", "EXEC", "END", "COND_JUMP", "JUMP", "ABORT2", "ABORT3", "RANDOM" }; -const char *scriptMethodNames[67] = { +static const char *scriptMethodNames[67] = { "ACTIVATE HOTSPOT", "SET HOTSPOT SCRIPT", "ADD SOUND 2", "SET HOTSPOT FLAG MASK", "CLEAR SEQUENCE DELAY LIST", "DEACTIVATE HOTSPOT SET", "DEACTIVATE HOTSPOT", "RESET PATHFINDER", "ADD DELAYED SCRIPT", "KILL SOUND", @@ -860,7 +860,7 @@ uint16 Script::execute(uint16 startOffset) { uint16 fieldNum; uint32 tempVal; SequenceMethodPtr ptr; - SequenceMethodRecord *rec; + const SequenceMethodRecord *rec; char debugInfo[MAX_DESC_SIZE]; uint16 offset = startOffset; @@ -1152,9 +1152,9 @@ int16 HotspotScript::nextVal(MemoryBlock *data, uint16 &offset) { return value; } -bool HotspotScript::execute(Hotspot *h) -{ +bool HotspotScript::execute(Hotspot *h) { Resources &r = Resources::getReference(); + Room &room = Room::getReference(); MemoryBlock *scriptData = r.hotspotScriptData(); uint16 offset = h->hotspotScript(); int16 opcode = 0; @@ -1225,14 +1225,17 @@ bool HotspotScript::execute(Hotspot *h) case S2_OPCODE_PLAY_SOUND: param1 = nextVal(scriptData, offset); param2 = nextVal(scriptData, offset); - debugC(ERROR_DETAILED, kLureDebugScripts, "PLAY_SOUND(%d,%d)", param1, param2); -// warning("UNKNOWN_247 stub called"); + + if ((param2 == 0) || (room.roomNumber() == param2)) { + debugC(ERROR_DETAILED, kLureDebugScripts, "PLAY_SOUND(%d,%d)", param2, param1); + Sound.addSound2((uint8)param1); + } break; case S2_OPCODE_STOP_SOUND: param1 = nextVal(scriptData, offset); debugC(ERROR_DETAILED, kLureDebugScripts, "STOP_SOUND()"); -// warning("UNKNOWN_258 stub called"); + Sound.stopSound((uint8)param1); break; case S2_OPCODE_ACTIONS: diff --git a/engines/lure/scripts.h b/engines/lure/scripts.h index 1191017d11..4ad5226e70 100644 --- a/engines/lure/scripts.h +++ b/engines/lure/scripts.h @@ -79,25 +79,25 @@ public: static void activateHotspot(uint16 hotspotId, uint16 v2, uint16 v3); static void setHotspotScript(uint16 hotspotId, uint16 scriptIndex, uint16 v3); - static void addSound2(uint16 v1, uint16 v2, uint16 v3); + static void addSound2(uint16 soundIndex, uint16 v2, uint16 v3); static void setHotspotFlagMask(uint16 maskVal, uint16 v2, uint16 v3); static void clearSequenceDelayList(uint16 v1, uint16 scriptIndex, uint16 v3); static void deactivateHotspotSet(uint16 listIndex, uint16 v2, uint16 v3); static void deactivateHotspot(uint16 hotspotId, uint16 v2, uint16 v3); static void resetPathfinder(uint16 v1, uint16 v2, uint16 v3); static void addDelayedSequence(uint16 seqOffset, uint16 delay, uint16 canClear); - static void killSound(uint16 soundId, uint16 v2, uint16 v3); + static void killSound(uint16 soundNumber, uint16 v2, uint16 v3); static void characterInRoom(uint16 characterId, uint16 roomNumber, uint16 v3); static void setDesc(uint16 hotspotId, uint16 descId, uint16 v3); static void setHotspotName(uint16 hotspotId, uint16 nameId, uint16 v3); - static void addSound(uint16 soundId, uint16 v2, uint16 v3); + static void addSound(uint16 soundIndex, uint16 v2, uint16 v3); static void endgameSequence(uint16 v1, uint16 v2, uint16 v3); static void setupPigFight(uint16 v1, uint16 v2, uint16 v3); static void displayDialog(uint16 stringId, uint16 v2, uint16 v3); static void setupSkorlFight(uint16 v1, uint16 v2, uint16 v3); static void remoteRoomViewSetup(uint16 v1, uint16 v2, uint16 v3); static void startSpeakingToNoone(uint16 characterId, uint16 stringId, uint16 v3); - static void playMusic(uint16 musicNum, uint16 v2, uint16 v3); + static void stopSound(uint16 soundIndex, uint16 v2, uint16 v3); static void getDoorBlocked(uint16 hotspotId, uint16 v2, uint16 v3); static void isSkorlInCell(uint16 v1, uint16 v2, uint16 v3); static void ratpouchPushBricks(uint16 v1, uint16 v2, uint16 v3); @@ -142,7 +142,7 @@ public: static void addActions(uint16 hotspotId, uint16 actions, uint16 v3); static void randomToGeneral(uint16 maxVal, uint16 minVal, uint16 v3); static void checkCellDoor(uint16 v1, uint16 v2, uint16 v3); - static void checkSound(uint16 v1, uint16 v2, uint16 v3); + static void checkSound(uint16 soundNumber, uint16 v2, uint16 v3); }; class HotspotScript { diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp index 6961e4c7cc..bf9a2032ab 100644 --- a/engines/lure/sound.cpp +++ b/engines/lure/sound.cpp @@ -21,17 +21,607 @@ */ #include "lure/sound.h" +#include "lure/game.h" +#include "lure/memory.h" +#include "lure/res.h" +#include "lure/room.h" + +#include "common/config-manager.h" +#include "common/endian.h" +#include "sound/midiparser.h" DECLARE_SINGLETON(Lure::SoundManager); namespace Lure { +SoundManager::SoundManager() { + _descs = Disk::getReference().getEntry(SOUND_DESC_RESOURCE_ID); + _numDescs = _descs->size() / sizeof(SoundDescResource); + _soundData = NULL; + + int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); + _nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); + + memset(_channelsInUse, false, NUM_CHANNELS_OUTER); + + _driver = MidiDriver::createMidi(midiDriver); + int statusCode = _driver->open(); + if (statusCode) { + warning("Sound driver returned error code %d", statusCode); + _driver = NULL; + + } else { + if (_nativeMT32) + _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + + for (int index = 0; index < NUM_CHANNELS_INNER; ++index) { + _channelsInner[index].midiChannel = _driver->allocateChannel(); + _channelsInner[index].volume = DEFAULT_VOLUME; + } + } +} + +SoundManager::~SoundManager() { + if (_driver) + _driver->setTimerCallback(this, NULL); + + removeSounds(); + _activeSounds.clear(); + _playingSounds.clear(); + + + delete _descs; + if (_soundData) + delete _soundData; + + if (_driver) + _driver->close(); + _driver = NULL; +} + +void SoundManager::loadSection(uint16 sectionId) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::loadSection = %xh", sectionId); + killSounds(); + + if (_soundData) { + delete _soundData; + _driver->setTimerCallback(this, NULL); + } + + _soundData = Disk::getReference().getEntry(sectionId); + _soundsTotal = *_soundData->data(); + + _driver->setTimerCallback(this, &onTimer); +} + +void SoundManager::bellsBodge() { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::bellsBodge"); + Resources &res = Resources::getReference(); + Room &room = Room::getReference(); + + RoomData *roomData = res.getRoom(room.roomNumber()); + if (roomData->areaFlag != res.fieldList().getField(AREA_FLAG)) { + res.fieldList().setField(AREA_FLAG, roomData->areaFlag); + + switch (roomData->areaFlag) { + case 0: + killSound(1); + break; + case 1: + addSound(2); + killSound(33); + break; + case 2: + setVolume(0, 15); + // Deliberate fall through + default: + killSound(1); + break; + } + } +} + void SoundManager::killSounds() { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::killSounds"); + + // Stop the player playing all sounds + musicInterface_KillAll(); + + // Clear the active sounds + _activeSounds.clear(); + for (int channelNum = 0; channelNum < NUM_CHANNELS_INNER; ++channelNum) + _channelsInUse[channelNum] = false; +} + +void SoundManager::addSound(uint8 soundIndex, bool tidyFlag) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::addSound index=%d", soundIndex); + Game &game = Game::getReference(); + + if (tidyFlag) + tidySounds(); + + if (game.preloadFlag()) + // Don't add a sound if in room preloading + return; + + SoundDescResource &rec = soundDescs()[soundIndex]; + int numChannels = (rec.numChannels >> 2) & 3; + + int channelCtr = 0; + while (channelCtr <= (NUM_CHANNELS_OUTER - numChannels)) { + if (!_channelsInUse[channelCtr]) { + bool foundSpace = true; + + int channelCtr2 = 1; + while (channelCtr2 < numChannels) { + foundSpace = !_channelsInUse[channelCtr + channelCtr2]; + if (!foundSpace) break; + ++channelCtr2; + } + + if (foundSpace) + break; + } + + ++channelCtr; + } + + if (channelCtr > NUM_CHANNELS_OUTER - numChannels) { + // No channels free + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::addSound - no channels free"); + return; + } + + // Mark the found channels as in use + for (int channelCtr2 = 0; channelCtr2 < numChannels; ++channelCtr2) + _channelsInUse[channelCtr + channelCtr2] = true; + + SoundDescResource *newEntry = new SoundDescResource(); + newEntry->soundNumber = rec.soundNumber; + newEntry->channel = channelCtr; + newEntry->numChannels = numChannels; + newEntry->flags = rec.flags; + newEntry->volume = rec.volume; + _activeSounds.push_back(newEntry); + + // TODO: Figure a better way of sharing channels between multiple parsers - currently + // each parser seems to use 8 channels of a maximum 16 available, but here I'm + // overlapping channels 4 - 7 (3rd & 4th parser) across the other two + byte innerChannel = (channelCtr < 4) ? ((channelCtr / 2) * 8) : + (4 + (channelCtr / 2) * 8); + + musicInterface_Play(rec.soundNumber, innerChannel); + setVolume(rec.soundNumber, rec.volume); +} + +void SoundManager::addSound2(uint8 soundIndex) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::addSound2 index=%d", soundIndex); + tidySounds(); + + if (soundIndex == 6) + // Chinese torture + addSound(6); + else { + SoundDescResource &descEntry = soundDescs()[soundIndex]; + SoundDescResource *rec = findSound(descEntry.soundNumber); + if (rec == NULL) + // Sound isn't active, so go and add it + addSound(soundIndex, false); + } +} + + +void SoundManager::stopSound(uint8 soundIndex) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::stopSound index=%d", soundIndex); + SoundDescResource &rec = soundDescs()[soundIndex]; + musicInterface_Stop(rec.soundNumber & 0x7f); +} + +void SoundManager::killSound(uint8 soundNumber) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::stopSound soundNumber=%d", soundNumber); + musicInterface_Stop(soundNumber & 0x7f); +} + +void SoundManager::setVolume(uint8 soundNumber, uint8 volume) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::setVolume soundNumber=%d, volume=%d", + soundNumber, volume); + musicInterface_TidySounds(); + + SoundDescResource *entry = findSound(soundNumber); + if (entry) + musicInterface_SetVolume(entry->channel, volume); +} + +void SoundManager::setVolume(uint8 volume) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::setVolume volume=%d", volume); + + for (int index = 0; index < NUM_CHANNELS_INNER; ++index) { + _channelsInner[index].midiChannel->volume(volume); + _channelsInner[index].volume = volume; + } +} + +SoundDescResource *SoundManager::findSound(uint8 soundNumber) { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::findSound soundNumber=%d", soundNumber); + ManagedList<SoundDescResource *>::iterator i; + + for (i = _activeSounds.begin(); i != _activeSounds.end(); ++i) { + SoundDescResource *rec = *i; + + if (rec->soundNumber == soundNumber) { + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "SoundManager::findSound - sound found"); + return rec; + } + } + + // Signal that sound wasn't found + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "SoundManager::findSound - sound not found"); + return NULL; +} + +void SoundManager::tidySounds() { + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "SoundManager::tidySounds"); + ManagedList<SoundDescResource *>::iterator i = _activeSounds.begin(); + + while (i != _activeSounds.end()) { + SoundDescResource *rec = *i; + + if (musicInterface_CheckPlaying(rec->soundNumber & 0x7f)) + // Still playing, so move to next entry + ++i; + else { + // Mark the channels that it used as now being free + for (int channelCtr = 0; channelCtr < rec->numChannels; ++channelCtr) + _channelsInUse[rec->channel + channelCtr] = false; + + i = _activeSounds.erase(i); + } + } +} + +void SoundManager::removeSounds() { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::removeSounds"); + bellsBodge(); + + ManagedList<SoundDescResource *>::iterator i = _activeSounds.begin(); + + while (i != _activeSounds.end()) { + SoundDescResource *rec = *i; + + if ((rec->flags & SF_IN_USE) != 0) + musicInterface_Stop(rec->soundNumber); + + ++i; + } +} + +void SoundManager::restoreSounds() { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::restoreSounds"); + ManagedList<SoundDescResource *>::iterator i = _activeSounds.begin(); + + while (i != _activeSounds.end()) { + SoundDescResource *rec = *i; + + if ((rec->numChannels != 0) && ((rec->flags & SF_RESTORE) != 0)) { + for (int channelCtr = 0; channelCtr < rec->numChannels; ++channelCtr) + _channelsInUse[rec->channel + channelCtr] = true; + + musicInterface_Play(rec->soundNumber, rec->channel); + musicInterface_SetVolume(rec->soundNumber, rec->volume); + } + + ++i; + } +} + +void SoundManager::fadeOut() { + debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::fadeOut"); + + // Fade out all the active sounds + musicInterface_TidySounds(); + + bool inProgress = true; + while (inProgress) + { + inProgress = false; + + ManagedList<MidiMusic *>::iterator i; + for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) { + MidiMusic *music = *i; + if (music->getVolume() > 0) { + inProgress = true; + music->setVolume(music->getVolume() > 4 ? (music->getVolume() - 10) : 0); + } + } + + g_system->delayMillis(10); + } + + // Kill all the sounds + musicInterface_KillAll(); +} + +/*------------------------------------------------------------------------*/ + +// musicInterface_Play +// Play the specified sound + +void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber) { + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_Play soundNumber=%d, channel=%d", + soundNumber, channelNumber); + + if (!_soundData) + error("Sound section has not been specified"); + + uint8 soundNum = soundNumber & 0x7f; + if (soundNum > _soundsTotal) + error("Invalid sound index %d requested", soundNum); + + if (_driver == NULL) + // Only play sounds if a sound driver is active + return; + + uint32 dataOfs = READ_LE_UINT32(_soundData->data() + soundNum * 4 + 2); + uint8 *soundStart = _soundData->data() + dataOfs; + uint32 dataSize; + + if (soundNumber == _soundsTotal - 1) + dataSize = _soundData->size() - dataOfs; + else { + uint32 nextDataOfs = READ_LE_UINT32(_soundData->data() + (soundNum + 1) * 4 + 2); + dataSize = nextDataOfs - dataOfs; + } + + MidiMusic *sound = new MidiMusic(_driver, _channelsInner, channelNumber, soundNumber, + soundStart, dataSize); + _playingSounds.push_back(sound); +} + +// musicInterface_Stop +// Stops the specified sound from playing + +void SoundManager::musicInterface_Stop(uint8 soundNumber) { + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_Stop soundNumber=%d", soundNumber); + musicInterface_TidySounds(); + uint8 soundNum = soundNumber & 0x7f; + + ManagedList<MidiMusic *>::iterator i; + for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) { + MidiMusic *music = *i; + if (music->soundNumber() == soundNum) { + _playingSounds.erase(i); + return; + } + } +} + +// musicInterface_CheckPlaying +// Returns true if a sound is still playing + +bool SoundManager::musicInterface_CheckPlaying(uint8 soundNumber) { + debugC(ERROR_DETAILED, kLureDebugSounds, "musicInterface_CheckPlaying soundNumber=%d", soundNumber); + musicInterface_TidySounds(); + uint8 soundNum = soundNumber & 0x7f; + + ManagedList<MidiMusic *>::iterator i; + for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) { + MidiMusic *music = *i; + if (music->soundNumber() == soundNum) + return true; + } + + return false; +} + +// musicInterface_SetVolume +// Sets the volume of the specified channel + +void SoundManager::musicInterface_SetVolume(uint8 channelNum, uint8 volume) { + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_SetVolume channel=%d, volume=%d", + channelNum, volume); + musicInterface_TidySounds(); + + ManagedList<MidiMusic *>::iterator i; + for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) { + MidiMusic *music = *i; + if (music->channelNumber() == channelNum) + music->setVolume(volume); + } +} + +// musicInterface_KillAll +// Stops all currently active sounds playing + +void SoundManager::musicInterface_KillAll() { + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_KillAll"); + musicInterface_TidySounds(); + + ManagedList<MidiMusic *>::iterator i; + for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) { + MidiMusic *music = *i; + music->stopMusic(); + } + + _playingSounds.clear(); + _activeSounds.clear(); +} + +// musicInterface_ContinuePlaying +// The original player used this method for any sound managers needing continual calls + +void SoundManager::musicInterface_ContinuePlaying() { + // No implementation needed +} + +// musicInterface_TrashReverb +// Trashes reverb on actively playing sounds + +void SoundManager::musicInterface_TrashReverb() { + // TODO: Handle support for trashing reverb + debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_TrashReverb"); +} + +// musicInterface_KillAll +// Scans all the active sounds and deallocates any objects that have finished playing + +void SoundManager::musicInterface_TidySounds() { + debugC(ERROR_DETAILED, kLureDebugSounds, "musicInterface_TidySounds"); + ManagedList<MidiMusic *>::iterator i = _playingSounds.begin(); + while (i != _playingSounds.end()) { + MidiMusic *music = *i; + if (!music->isPlaying()) + i = _playingSounds.erase(i); + else + ++i; + } +} + +void SoundManager::onTimer(void *data) { + SoundManager *snd = (SoundManager *) data; + + ManagedList<MidiMusic *>::iterator i; + for (i = snd->_playingSounds.begin(); i != snd->_playingSounds.end(); ++i) { + MidiMusic *music = *i; + if (music->isPlaying()) + music->onTimer(); + } +} + +/*------------------------------------------------------------------------*/ + +MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS_INNER], + uint8 channelNum, uint8 soundNum, void *soundData, uint32 size) { + + _driver = driver; + _channels = channels; + _soundNumber = soundNum; + _channelNumber = channelNum; + _numChannels = 8; + _volume = _channels[channelNum].volume; + + _passThrough = false; + + _parser = MidiParser::createParser_SMF(); + _parser->setMidiDriver(this); + _parser->setTimerRate(_driver->getBaseTempo()); + + this->open(); + + _soundData = (uint8 *) soundData; + _soundSize = size; + + // Check whether the music data is compressed - if so, decompress it for the duration + // of playing the sound + _decompressedSound = NULL; + if ((*_soundData == 'C') || (*_soundData == 'c')) { + uint32 packedSize = size - 0x201; + _decompressedSound = Memory::allocate(packedSize * 2); + + uint16 *data = (uint16 *)(_soundData + 1); + uint16 *dataDest = (uint16 *) _decompressedSound->data(); + byte *idx = ((byte *)data) + 0x200; + + for (uint i = 0; i < packedSize; i++) +#if defined(SCUMM_NEED_ALIGNMENT) + memcpy(dataDest++, (byte*)((byte*)data + *(idx + i) * sizeof(uint16)), sizeof(uint16)); +#else + *dataDest++ = data[*(idx + i)]; +#endif + + _soundData = _decompressedSound->data() + ((*_soundData == 'c') ? 1 : 0); + _soundSize = _decompressedSound->size(); + } + + playMusic(); +} + +MidiMusic::~MidiMusic() { + _parser->unloadMusic(); + delete _parser; + this->close(); + if (_decompressedSound != NULL) + delete _decompressedSound; } -void SoundManager::playSound(uint16 soundId) { +void MidiMusic::setVolume(int volume) { + if (volume < 0) + volume = 0; + else if (volume > 255) + volume = 255; + + if (_volume == volume) + return; + + _volume = volume; + + for (int i = 0; i < _numChannels; ++i) + _channels[_channelNumber + i].midiChannel->volume( + _channels[_channelNumber + i].volume * _volume / 255); +} + +void MidiMusic::playMusic() { + debugC(ERROR_DETAILED, kLureDebugSounds, "MidiMusic::PlayMusic playing sound %d", _soundNumber); + _parser->loadMusic(_soundData, _soundSize); + _parser->setTrack(0); + _isPlaying = true; +} + +int MidiMusic::open() { + // Don't ever call open without first setting the output driver! + if (!_driver) + return 255; + + return 0; +} + +void MidiMusic::close() { +} + +void MidiMusic::send(uint32 b) { + if (_passThrough) { + _driver->send(b); + return; + } + + byte channel = _channelNumber + (byte)(b & 0x0F); + if ((channel >= NUM_CHANNELS_INNER) || (_channels[channel].midiChannel == NULL)) + return; + + if ((b & 0xFFF0) == 0x07B0) { + // Adjust volume changes by master volume + byte volume = (byte)((b >> 16) & 0x7F); + _channels[channel].volume = volume; + volume = volume * _volume / 255; + b = (b & 0xFF00FFFF) | (volume << 16); + } else if ((b & 0xF0) == 0xC0 && !_nativeMT32) { + b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; + } + else if ((b & 0xFFF0) == 0x007BB0) { + // No implementation + } + + _channels[channel].midiChannel->send(b); +} + +void MidiMusic::metaEvent(byte type, byte *data, uint16 length) { + //Only thing we care about is End of Track. + if (type != 0x2F) + return; + + stopMusic(); +} + +void MidiMusic::onTimer() { + if (_isPlaying) + _parser->onTimer(); +} +void MidiMusic::stopMusic() { + debugC(ERROR_DETAILED, kLureDebugSounds, "MidiMusic::stopMusic sound %d", _soundNumber); + _isPlaying = false; + _parser->unloadMusic(); + close(); } } // end of namespace Lure diff --git a/engines/lure/sound.h b/engines/lure/sound.h index 4a7422d77f..cfe0739298 100644 --- a/engines/lure/sound.h +++ b/engines/lure/sound.h @@ -24,14 +24,131 @@ #define LURE_SOUND_H #include "lure/luredefs.h" +#include "lure/disk.h" +#include "lure/memory.h" + #include "common/singleton.h" +#include "sound/mididrv.h" +#include "sound/mixer.h" + +class MidiParser; namespace Lure { +#define NUM_CHANNELS_OUTER 8 +#define NUM_CHANNELS_INNER 16 + +struct ChannelEntry { + MidiChannel *midiChannel; + byte volume; +}; + +class MidiMusic: public MidiDriver { +private: + uint8 _soundNumber; + uint8 _channelNumber; + uint8 _numChannels; + byte _volume; + MemoryBlock *_decompressedSound; + uint8 *_soundData; + uint8 _soundSize; + MidiDriver *_driver; + MidiParser *_parser; + ChannelEntry *_channels; + bool _isPlaying; + bool _nativeMT32; + + void queueUpdatePos(); + uint8 randomQueuePos(); + uint32 songOffset(uint16 songNum) const; + uint32 songLength(uint16 songNum) const; + + bool _passThrough; + +public: + MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS_INNER], + uint8 channelNum, uint8 soundNum, void *soundData, uint32 size); + ~MidiMusic(); + void setVolume(int volume); + int getVolume() { return _volume; } + + void hasNativeMT32(bool b) { _nativeMT32 = b; } + void playSong(uint16 songNum); + void stopSong() { stopMusic(); } + void playMusic(); + void stopMusic(); + void queueTuneList(int16 tuneList); + bool queueSong(uint16 songNum); + void setPassThrough(bool b) { _passThrough = b; } + void toggleVChange(); + + //MidiDriver interface implementation + int open(); + void close(); + void send(uint32 b); + void onTimer(); + + void metaEvent(byte type, byte *data, uint16 length); + + void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { } + uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; } + + //Channel allocation functions + MidiChannel *allocateChannel() { return 0; } + MidiChannel *getPercussionChannel() { return 0; } + + uint8 channelNumber() { return _channelNumber; } + uint8 soundNumber() { return _soundNumber; } + bool isPlaying() { return _isPlaying; } +}; + class SoundManager: public Common::Singleton<SoundManager> { +private: + // Outer sound interface properties + MemoryBlock *_descs; + MemoryBlock *_soundData; + uint8 _soundsTotal; + int _numDescs; + SoundDescResource *soundDescs() { return (SoundDescResource *) _descs->data(); } + MidiDriver *_driver; + ManagedList<SoundDescResource *> _activeSounds; + ManagedList<MidiMusic *> _playingSounds; + ChannelEntry _channelsInner[NUM_CHANNELS_INNER]; + bool _channelsInUse[NUM_CHANNELS_OUTER]; + bool _isPlaying; + bool _nativeMT32; + + // Internal support methods + void bellsBodge(); + void musicInterface_TidySounds(); + static void onTimer(void *data); public: - static void killSounds(); - static void playSound(uint16 soundId); + SoundManager(); + ~SoundManager(); + + void loadSection(uint16 sectionId); + void killSounds(); + void addSound(uint8 soundIndex, bool tidyFlag = true); + void addSound2(uint8 soundIndex); + void stopSound(uint8 soundIndex); + void killSound(uint8 soundNumber); + void setVolume(uint8 soundNumber, uint8 volume); + void setVolume(uint8 volume); + void tidySounds(); + SoundDescResource *findSound(uint8 soundNumber); + void removeSounds(); + void restoreSounds(); + void fadeOut(); + + // The following methods implement the external sound player module + void musicInterface_Initialise(); + void musicInterface_Play(uint8 soundNumber, uint8 channelNumber); + void musicInterface_Stop(uint8 soundNumber); + bool musicInterface_CheckPlaying(uint8 soundNumber); + void musicInterface_SetVolume(uint8 channelNum, uint8 volume); + void musicInterface_KillAll(); + void musicInterface_ContinuePlaying(); + void musicInterface_TrashReverb(); }; } // End of namespace Lure diff --git a/engines/lure/surface.cpp b/engines/lure/surface.cpp index 3486a5abb9..d5b9db4955 100644 --- a/engines/lure/surface.cpp +++ b/engines/lure/surface.cpp @@ -29,6 +29,7 @@ #include "lure/screen.h" #include "lure/lure.h" #include "lure/room.h" +#include "lure/sound.h" #include "lure/strings.h" #include "common/endian.h" @@ -50,8 +51,7 @@ void Surface::initialise() { byte *pChar = int_font->data() + (ctr * 8); fontSize[ctr] = 0; - for (int yp = 0; yp < FONT_HEIGHT; ++yp) - { + for (int yp = 0; yp < FONT_HEIGHT; ++yp) { byte v = *pChar++; for (int xp = 0; xp < FONT_WIDTH; ++xp) { @@ -155,13 +155,11 @@ void Surface::transparentCopyTo(Surface *dest) { } } -void Surface::copyTo(Surface *dest) -{ +void Surface::copyTo(Surface *dest) { copyTo(dest, 0, 0); } -void Surface::copyTo(Surface *dest, uint16 x, uint16 y) -{ +void Surface::copyTo(Surface *dest, uint16 x, uint16 y) { if ((x == 0) && (dest->width() == _width)) { // Use fast data transfer uint32 dataSize = dest->data().size() - (y * _width); @@ -631,7 +629,6 @@ bool SaveRestoreDialog::show(bool saveDialog) { Screen &screen = Screen::getReference(); Mouse &mouse = Mouse::getReference(); Events &events = Events::getReference(); - Room &room = Room::getReference(); Resources &res = Resources::getReference(); LureEngine &engine = LureEngine::getReference(); int selectedLine = -1; @@ -655,7 +652,6 @@ bool SaveRestoreDialog::show(bool saveDialog) { return false; } - room.update(); Surface *s = new Surface(INFO_DIALOG_WIDTH, SR_SAVEGAME_NAMES_Y + numSaves * FONT_HEIGHT + FONT_HEIGHT + 2); @@ -778,4 +774,139 @@ bool SaveRestoreDialog::show(bool saveDialog) { return doneFlag; } +/*--------------------------------------------------------------------------*/ + +struct RestartRecordPos { + int16 x, y; +}; + +struct RestartRecord { + Common::Language Language; + int16 width, height; + RestartRecordPos BtnRestart; + RestartRecordPos BtnRestore; +}; + +static const RestartRecord buttonBounds[] = { + { EN_ANY, 48, 14, { 118, 152 }, { 168, 152 } }, + { DE_DEU, 48, 14, { 106, 152 }, { 168, 152 } }, + { UNK_LANG, 48, 14, { 112, 152 }, { 168, 152 } } +}; + + +bool RestartRestoreDialog::show() { + Resources &res = Resources::getReference(); + Events &events = Events::getReference(); + Mouse &mouse = Mouse::getReference(); + Screen &screen = Screen::getReference(); + LureEngine &engine = LureEngine::getReference(); + + Sound.killSounds(); + Sound.musicInterface_Play(60, 0); + mouse.setCursorNum(CURSOR_ARROW); + + // See if there are any savegames that can be restored + String *firstSave = engine.detectSave(1); + bool restartFlag = (firstSave == NULL); + int highlightedButton = -1; + + if (!restartFlag) { + Memory::dealloc(firstSave); + + // Get the correct button bounds record to use + const RestartRecord *btnRecord = &buttonBounds[0]; + while ((btnRecord->Language != engine.getLanguage()) && + (btnRecord->Language != UNK_LANG)) + ++btnRecord; + + // Fade out the screen + screen.paletteFadeOut(RES_PALETTE_ENTRIES); + + // Get the palette that will be used, and first fade out the prior screen + Palette p(RESTART_RESOURCE_ID - 1); + + // Turn on the mouse + mouse.cursorOn(); + + // Load the restore/restart screen image + Surface *s = Surface::getScreen(RESTART_RESOURCE_ID); + s->copyTo(&screen.screen(), 0, MENUBAR_Y_SIZE); + delete s; + + res.activeHotspots().clear(); + Hotspot *btnHotspot = new Hotspot(); + + // Restart button + btnHotspot->setSize(btnRecord->width, btnRecord->height); + btnHotspot->setPosition(btnRecord->BtnRestart.x, btnRecord->BtnRestart.y); + btnHotspot->setAnimation(0x184B); + btnHotspot->copyTo(&screen.screen()); + + // Restore button + btnHotspot->setFrameNumber(1); + btnHotspot->setPosition(btnRecord->BtnRestore.x, btnRecord->BtnRestore.y); + btnHotspot->copyTo(&screen.screen()); + + screen.update(); + screen.paletteFadeIn(&p); + + // Event loop for making selection + while (!events.quitFlag) { + // Handle events + if (events.pollEvent()) { + if ((events.type() == Common::EVENT_LBUTTONDOWN) && (highlightedButton != -1)) { + mouse.waitForRelease(); + break; + } + } + + // Check if the pointer is over either button + int currentButton = -1; + if ((mouse.y() >= btnRecord->BtnRestart.y) && + (mouse.y() < btnRecord->BtnRestart.y + btnRecord->height)) { + // Check whether the Restart or Restore button is highlighted + if ((mouse.x() >= btnRecord->BtnRestart.x) && + (mouse.x() < btnRecord->BtnRestart.x + btnRecord->width)) + currentButton = 0; + else if ((mouse.x() >= btnRecord->BtnRestore.x) && + (mouse.x() < btnRecord->BtnRestore.x + btnRecord->width)) + currentButton = 1; + } + + // Take care of highlighting as the selected button changes + if (currentButton != highlightedButton) { + highlightedButton = currentButton; + + // Restart button + btnHotspot->setFrameNumber((highlightedButton == 0) ? 2 : 0); + btnHotspot->setPosition(btnRecord->BtnRestart.x, btnRecord->BtnRestart.y); + btnHotspot->copyTo(&screen.screen()); + + // Restore button + btnHotspot->setFrameNumber((highlightedButton == 1) ? 3 : 1); + btnHotspot->setPosition(btnRecord->BtnRestore.x, btnRecord->BtnRestore.y); + btnHotspot->copyTo(&screen.screen()); + } + + + screen.update(); + g_system->delayMillis(10); + } + + restartFlag = highlightedButton == 0; + delete btnHotspot; + } + + Sound.killSounds(); + + if (!restartFlag && !events.quitFlag) { + // Need to show Restore game dialog + if (!SaveRestoreDialog::show(false)) + // User cancelled, so fall back on Restart + restartFlag = true; + } + + return restartFlag; +} + } // end of namespace Lure diff --git a/engines/lure/surface.h b/engines/lure/surface.h index f97666d1e7..564f65dd99 100644 --- a/engines/lure/surface.h +++ b/engines/lure/surface.h @@ -104,6 +104,11 @@ public: static bool show(bool saveDialog); }; +class RestartRestoreDialog { +public: + static bool show(); +}; + } // End of namespace Lure #endif diff --git a/engines/parallaction/animation.cpp b/engines/parallaction/animation.cpp deleted file mode 100644 index 118f35e705..0000000000 --- a/engines/parallaction/animation.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "parallaction/parallaction.h" - - -namespace Parallaction { - - -#define INST_ON 1 -#define INST_OFF 2 -#define INST_X 3 -#define INST_Y 4 -#define INST_Z 5 -#define INST_F 6 -#define INST_LOOP 7 -#define INST_ENDLOOP 8 -#define INST_SHOW 9 -#define INST_INC 10 -#define INST_DEC 11 -#define INST_SET 12 -#define INST_PUT 13 -#define INST_CALL 14 -#define INST_WAIT 15 -#define INST_START 16 -#define INST_SOUND 17 -#define INST_MOVE 18 -#define INST_END 1000 - - -void wrapLocalVar(LocalVariable *local); - - - - -uint16 _numLocals = 0; -char _localNames[10][10]; - -Animation *Parallaction::findAnimation(const char *name) { - - for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) - if (!scumm_stricmp((*it)->_label._text, name)) return *it; - - return NULL; -} - - -Animation *Parallaction::parseAnimation(Script& script, AnimationList &list, char *name) { -// printf("parseAnimation(%s)\n", name); - - Animation *vD0 = new Animation; - - vD0->_label._text = (char*)malloc(strlen(name)+1); - strcpy(vD0->_label._text, name); - - list.push_front(vD0); - - fillBuffers(script, true); - while (scumm_stricmp(_tokens[0], "endanimation")) { -// printf("token[0] = %s\n", _tokens[0]); - - if (!scumm_stricmp(_tokens[0], "script")) { - loadProgram(vD0, _tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "commands")) { - parseCommands(script, vD0->_commands); - } - if (!scumm_stricmp(_tokens[0], "type")) { - if (_tokens[2][0] != '\0') { - vD0->_type = ((4 + _objectsNames->lookup(_tokens[2])) << 16) & 0xFFFF0000; - } - int16 _si = _zoneTypeNames->lookup(_tokens[1]); - if (_si != -1) { - vD0->_type |= 1 << (_si-1); - if (((vD0->_type & 0xFFFF) != kZoneNone) && ((vD0->_type & 0xFFFF) != kZoneCommand)) { - parseZoneTypeBlock(script, vD0); - } - } - } - if (!scumm_stricmp(_tokens[0], "label")) { - _gfx->makeCnvFromString(&vD0->_label._cnv, _tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "flags")) { - uint16 _si = 1; - - do { - byte _al = _zoneFlagNames->lookup(_tokens[_si]); - _si++; - vD0->_flags |= 1 << (_al - 1); - } while (!scumm_stricmp(_tokens[_si++], "|")); - } - if (!scumm_stricmp(_tokens[0], "file")) { - char vC8[200]; - strcpy(vC8, _tokens[1]); - if (_engineFlags & kEngineTransformedDonna) { - if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) { - strcat(vC8, "tras"); - } - } - vD0->_cnv = _disk->loadFrames(vC8); - } - if (!scumm_stricmp(_tokens[0], "position")) { - vD0->_left = atoi(_tokens[1]); - vD0->_top = atoi(_tokens[2]); - vD0->_z = atoi(_tokens[3]); - } - if (!scumm_stricmp(_tokens[0], "moveto")) { - vD0->_moveTo.x = atoi(_tokens[1]); - vD0->_moveTo.y = atoi(_tokens[2]); - } - - fillBuffers(script, true); - } - - vD0->_oldPos.x = -1000; - vD0->_oldPos.y = -1000; - - vD0->_flags |= 0x1000000; - - return vD0; -} - - -void Parallaction::freeAnimations() { - _animations.clear(); - return; -} - - - -void jobDisplayAnimations(void *parm, Job *j) { -// printf("jobDisplayAnimations()...\n"); - - StaticCnv v14; - - uint16 _si = 0; - - for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { - - Animation *v18 = *it; - - if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) { - v14._width = v18->width(); - v14._height = v18->height(); - - int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1); - - v14._data0 = v18->getFrameData(frame); -// v14._data1 = v18->_cnv->field_8[frame]; - - if (v18->_flags & kFlagsNoMasked) - _si = 3; - else - _si = _vm->_gfx->queryMask(v18->_top + v18->height()); - - debugC(9, kDebugLocation, "jobDisplayAnimations(%s, x:%i, y:%i, z:%i, w:%i, h:%i, f:%i/%i, %p)", v18->_label._text, v18->_left, v18->_top, _si, v14._width, v14._height, - frame, v18->getFrameNum(), v14._data0); - _vm->_gfx->blitCnv(&v14, v18->_left, v18->_top, _si, Gfx::kBitBack); - - } - - if (((v18->_flags & kFlagsActive) == 0) && (v18->_flags & kFlagsRemove)) { - v18->_flags &= ~kFlagsRemove; - v18->_oldPos.x = -1000; - } - - if ((v18->_flags & kFlagsActive) && (v18->_flags & kFlagsRemove)) { - v18->_flags &= ~kFlagsActive; - v18->_flags |= kFlagsRemove; - } - - } - -// printf("done\n"); - - return; -} - - -void jobEraseAnimations(void *arg_0, Job *j) { - debugC(3, kDebugJobs, "jobEraseAnimations"); - - for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { - - Animation *a = *it; - - if (((a->_flags & kFlagsActive) == 0) && ((a->_flags & kFlagsRemove) == 0)) continue; - - Common::Rect r(a->width(), a->height()); - r.moveTo(a->_oldPos); - _vm->_gfx->restoreBackground(r); - - if (arg_0) { - a->_oldPos.x = a->_left; - a->_oldPos.y = a->_top; - } - - } - -// printf("done\n"); - - return; -} - - -void Parallaction::loadProgram(Animation *a, char *filename) { -// printf("loadProgram(%s)\n", filename); - - Script *script = _disk->loadScript(filename); - - _numLocals = 0; - - fillBuffers(*script); - - a->_program = new Program; - - Instruction *vCC = new Instruction; - - while (scumm_stricmp(_tokens[0], "endscript")) { - parseScriptLine(vCC, a, a->_program->_locals); - a->_program->_instructions.push_back(vCC); - vCC = new Instruction; - fillBuffers(*script); - } - - // TODO: use List<>::end() to detect the end of the program - vCC->_index = INST_END; - a->_program->_instructions.push_back(vCC); - a->_program->_ip = a->_program->_instructions.begin(); - - delete script; - - return; -} - - - - - - -void Parallaction::parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals) { -// printf("parseScriptLine()\n"); - - if (_tokens[0][1] == '.') { - _tokens[0][1] = '\0'; - a = findAnimation(&_tokens[0][2]); - } - - if (_tokens[1][1] == '.') { - _tokens[1][1] = '\0'; - a = findAnimation(&_tokens[1][2]); - } - - int16 _si = _instructionNames->lookup(_tokens[0]); - inst->_index = _si; - -// printf("token[0] = %s (%i)\n", _tokens[0], inst->_index); - - switch (inst->_index) { - case INST_ON: // on - case INST_OFF: // off - case INST_START: // start - if (!scumm_stricmp(_tokens[1], a->_label._text)) { - inst->_opBase._a = a; - } else { - inst->_opBase._a = findAnimation(_tokens[1]); - } - break; - - case INST_LOOP: // loop - inst->_opBase._loopCounter = getLValue(inst, _tokens[1], locals, a); - break; - - case INST_X: // x - inst->_opA._pvalue = &a->_left; - inst->_opB = getLValue(inst, _tokens[1], locals, a); - break; - - case INST_Y: // y - inst->_opA._pvalue = &a->_top; - inst->_opB = getLValue(inst, _tokens[1], locals, a); - break; - - case INST_Z: // z - inst->_opA._pvalue = &a->_z; - inst->_opB = getLValue(inst, _tokens[1], locals, a); - break; - - case INST_F: // f - inst->_opA._pvalue = &a->_frame; - inst->_opB = getLValue(inst, _tokens[1], locals, a); - break; - - case INST_INC: // inc - case INST_DEC: // dec - if (!scumm_stricmp(_tokens[1], "X")) { - inst->_opA._pvalue = &a->_left; - } else - if (!scumm_stricmp(_tokens[1], "Y")) { - inst->_opA._pvalue = &a->_top; - } else - if (!scumm_stricmp(_tokens[1], "Z")) { - inst->_opA._pvalue = &a->_z; - } else - if (!scumm_stricmp(_tokens[1], "F")) { - inst->_opA._pvalue = &a->_frame; - } else { - inst->_flags |= kInstUsesLocal; - inst->_opA = getLValue(inst, _tokens[1], locals, a); - } - - inst->_opB = getLValue(inst, _tokens[2], locals, a); - - if (!scumm_stricmp(_tokens[3], "mod")) { - inst->_flags |= kInstMod; - } - break; - - case INST_SET: // set - inst->_opA = getLValue(inst, _tokens[1], locals, a); - inst->_flags |= kInstUsesLocal; - inst->_opB = getLValue(inst, _tokens[2], locals, a); - break; - - case INST_MOVE: // move - inst->_opA = getLValue(inst, _tokens[1], locals, a); - inst->_opB = getLValue(inst, _tokens[2], locals, a); - break; - - case INST_PUT: // put - if (!scumm_stricmp(_tokens[1], a->_label._text)) { - inst->_opBase._a = a; - } else { - inst->_opBase._a = findAnimation(_tokens[1]); - } - - inst->_opA = getLValue(inst, _tokens[2], locals, a); - inst->_opB = getLValue(inst, _tokens[3], locals, a); - if (!scumm_stricmp(_tokens[4], "masked")) { - inst->_flags |= kInstMaskedPut; - } - break; - - case INST_CALL: { // call - int16 _ax = _callableNames->lookup(_tokens[1]); - inst->_opBase._index = _ax - 1; - if (_ax - 1 < 0) exit(0); - } - break; - - case INST_SOUND: // sound - inst->_opBase._z = findZone(_tokens[1]); - break; - - case INST_ENDLOOP: // endloop - case INST_SHOW: // show - case INST_WAIT: // wait - break; - - default: // local definition - strcpy(_localNames[_numLocals], _tokens[0]); - locals[_numLocals]._value = atoi(_tokens[2]); - - if (_tokens[3][0] != '\0') { - locals[_numLocals]._min = atoi(_tokens[3]); - locals[_numLocals]._max = atoi(_tokens[4]); - } else { - locals[_numLocals]._min = -10000; - locals[_numLocals]._max = 10000; - } - - inst->_opA._local = &locals[_numLocals]; - inst->_opB._value = locals[_numLocals]._value; - - inst->_flags = kInstUsesLiteral | kInstUsesLocal; - inst->_index = INST_SET; - _numLocals++; - break; - - } - - - return; -} - -LValue Parallaction::getLValue(Instruction *inst, char *str, LocalVariable *locals, Animation *a) { - - LValue v; - - v._pvalue = 0; // should stop compiler from complaining - - if (isdigit(str[0]) || str[0] == '-') { - inst->_flags |= kInstUsesLiteral; - v._value = atoi(str); - return v; - } - - for (uint16 _si = 0; _si < 10; _si++) { - if (!scumm_stricmp(str, _localNames[_si])) { - v._local = &locals[_si]; - return v; - } - } - - if (str[1] == '.') { - a = findAnimation(&str[2]); - } - - if (str[0] == 'X') { - v._pvalue = &a->_left; - } else - if (str[0] == 'Y') { - v._pvalue = &a->_top; - } else - if (str[0] == 'Z') { - v._pvalue = &a->_z; - } else - if (str[0] == 'F') { - v._pvalue = &a->_frame; - } - - return v; -} - - - -void jobRunScripts(void *parm, Job *j) { - debugC(3, kDebugJobs, "jobRunScripts"); - - static uint16 modCounter = 0; - - StaticCnv v18; - - for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { - - Animation *a = *it; - - if (a->_flags & kFlagsCharacter) a->_z = a->_top + a->height(); - - if ((a->_flags & kFlagsActing) == 0) continue; - InstructionList::iterator inst = a->_program->_ip; - -// printf("Animation: %s, flags: %x\n", a->_name, a->_flags); - - while (((*inst)->_index != INST_SHOW) && (a->_flags & kFlagsActing)) { - - debugC(9, kDebugJobs, "Animation: %s, instruction: %s", a->_label._text, (*inst)->_index == INST_END ? "end" : _vm->_instructionNamesRes[(*inst)->_index - 1]); - - switch ((*inst)->_index) { - case INST_ENDLOOP: // endloop - if (--a->_program->_loopCounter > 0) { - inst = a->_program->_loopStart; - } - break; - - case INST_OFF: {// off - (*inst)->_opBase._a->_flags |= kFlagsRemove; -// v1C = (*inst)->_opBase; - } - break; - - case INST_ON: // on - (*inst)->_opBase._a->_flags |= kFlagsActive; - (*inst)->_opBase._a->_flags &= ~kFlagsRemove; - break; - - case INST_START: // start -// v1C = (*inst)->_opBase; - (*inst)->_opBase._a->_flags |= (kFlagsActing | kFlagsActive); - break; - - case INST_LOOP: // loop - if ((*inst)->_flags & kInstUsesLiteral) { - a->_program->_loopCounter = (*inst)->_opBase._loopCounter._value; - } else { - a->_program->_loopCounter = *(*inst)->_opBase._loopCounter._pvalue; - } - a->_program->_loopStart = inst; - break; - - case INST_INC: // inc - case INST_DEC: { // dec - int16 _si = 0; - int16 _ax = 0, _bx = 0; - if ((*inst)->_flags & kInstUsesLiteral) { - _si = (*inst)->_opB._value; - } else { - _si = *(*inst)->_opB._pvalue; - } - if ((*inst)->_flags & kInstMod) { // mod - _bx = (_si > 0 ? _si : -_si); - if (modCounter % _bx != 0) break; - - _si = (_si > 0 ? 1 : -1); - } - if ((*inst)->_flags & kInstUsesLocal) { // local - if ((*inst)->_index == INST_INC) _ax = _si; - else _ax = -_si; - - (*inst)->_opA._local->_value += _ax; - wrapLocalVar((*inst)->_opA._local); - break; - } - - // built-in variable (x, y, z, f) - if ((*inst)->_index == INST_INC) _ax = _si; - else _ax = -_si; - *(*inst)->_opA._pvalue += _ax; - } - break; - - case INST_MOVE: { // move - WalkNodeList *v4 = _vm->_char._builder.buildPath(*(*inst)->_opA._pvalue, *(*inst)->_opB._pvalue); - _vm->addJob(&jobWalk, v4, kPriority19 ); - _engineFlags |= kEngineWalking; - } - break; - - case INST_PUT: // put - v18._width = (*inst)->_opBase._a->width(); - v18._height = (*inst)->_opBase._a->height(); - v18._data0 = (*inst)->_opBase._a->getFrameData((*inst)->_opBase._a->_frame); - v18._data1 = NULL; // (*inst)->_opBase._a->_cnv.field_8[(*inst)->_opBase._a->_frame]; - - if ((*inst)->_flags & kInstMaskedPut) { - uint16 _si = _vm->_gfx->queryMask((*inst)->_opB._value); - _vm->_gfx->blitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, _si, Gfx::kBitBack); - _vm->_gfx->blitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, _si, Gfx::kBit2); - } else { - _vm->_gfx->flatBlitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, Gfx::kBitBack); - _vm->_gfx->flatBlitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, Gfx::kBit2); - } - break; - - case INST_END: // exit - if ((a->_flags & kFlagsLooping) == 0) { - a->_flags &= ~kFlagsActing; - _vm->runCommands(a->_commands, a); - } - a->_program->_ip = a->_program->_instructions.begin(); - goto label1; - - - case INST_CALL: // call - _vm->callFunction((*inst)->_opBase._index, 0); - break; - - case INST_WAIT: // wait - if (_engineFlags & kEngineWalking) goto label1; - break; - - case INST_SOUND: // sound - _activeZone = (*inst)->_opBase._z; - break; - - default: { // INST_SET, INST_X, INST_Y, INST_Z, INST_F - int16 _si; - if ((*inst)->_flags & kInstUsesLiteral) { - _si = (*inst)->_opB._value; - } else { - _si = *(*inst)->_opB._pvalue; - } - - if ((*inst)->_flags & kInstUsesLocal) { - (*inst)->_opA._local->_value = _si; - } else { - *(*inst)->_opA._pvalue = _si; - } - } - break; - - } - - inst++; - } - - a->_program->_ip = ++inst; - -label1: - if (a->_flags & kFlagsCharacter) - a->_z = a->_top + a->height(); - } - - _vm->sortAnimations(); - modCounter++; - - return; -} - -void wrapLocalVar(LocalVariable *local) { -// printf("wrapLocalVar(v: %i, min: %i, max: %i)\n", local->_value, local->_min, local->_max); - - if (local->_value >= local->_max) - local->_value = local->_min; - if (local->_value < local->_min) - local->_value = local->_max - 1; - - return; -} - -int compareAnimationZ(const AnimationPointer &a1, const AnimationPointer &a2) { - if (a1->_z == a2->_z) return 0; - return (a1->_z < a2->_z ? -1 : 1); -} - - -void Parallaction::sortAnimations() { - _char._ani._z = _char._ani.height() + _char._ani._top; - _animations.sort(compareAnimationZ); - return; -} - -Animation::Animation() { - _cnv = NULL; - _program = NULL; - _frame = 0; - _z = 0; -} - -Animation::~Animation() { - if (_program) - delete _program; - - if (_cnv) - delete _cnv; -} - -uint16 Animation::width() const { - if (!_cnv) return 0; - return _cnv->_width; -} - -uint16 Animation::height() const { - if (!_cnv) return 0; - return _cnv->_height; -} - -uint16 Animation::getFrameNum() const { - if (!_cnv) return 0; - return _cnv->_count; -} - -byte* Animation::getFrameData(uint32 index) const { - if (!_cnv) return NULL; - return _cnv->getFramePtr(index); -} - - -Program::Program() { - _loopCounter = 0; - _locals = new LocalVariable[10]; -} - -Program::~Program() { - delete[] _locals; -} - - -} // namespace Parallaction diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 94a0747ab1..8f5c80fc0c 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -199,13 +199,11 @@ void Parallaction_ns::_c_score(void *parm) { void Parallaction_ns::_c_fade(void *parm) { - _gfx->setBlackPalette(); - - Gfx::Palette pal; - memset(pal, 0, sizeof(Gfx::Palette)); + Palette pal; + _gfx->setPalette(pal); for (uint16 _di = 0; _di < 64; _di++) { - _gfx->fadePalette(pal, _gfx->_palette, 1); + pal.fadeTo(_gfx->_palette, 1); _gfx->setPalette(pal); _gfx->updateScreen(); @@ -331,35 +329,21 @@ void Parallaction_ns::_c_onMouse(void *parm) { void Parallaction_ns::_c_setMask(void *parm) { - _gfx->intGrottaHackMask(); + memset(_backgroundInfo->mask.data + 3600, 0, 3600); + _gfx->_bgLayers[1] = 500; return; } void Parallaction_ns::_c_endComment(void *param) { - int16 w = 0, h = 0; - _gfx->getStringExtent(_location._endComment, 130, &w, &h); - - Common::Rect r(w+5, h+5); - r.moveTo(5, 5); - _gfx->floodFill(Gfx::kBitFront, r, 0); - - r.setWidth(w+3); - r.setHeight(h+3); - r.moveTo(7, 7); - _gfx->floodFill(Gfx::kBitFront, r, 1); - - _gfx->setFont(kFontDialogue); - _gfx->displayWrappedString(_location._endComment, 3, 5, 0, 130); - _gfx->updateScreen(); - + showLocationComment(_location._endComment, true); - Gfx::Palette pal; - _gfx->makeGrayscalePalette(pal); + Palette pal(_gfx->_palette); + pal.makeGrayscale(); for (uint di = 0; di < 64; di++) { - _gfx->fadePalette(_gfx->_palette, pal, 1); + _gfx->_palette.fadeTo(pal, 1); _gfx->setPalette(_gfx->_palette); _gfx->updateScreen(); @@ -373,24 +357,19 @@ void Parallaction_ns::_c_endComment(void *param) { void Parallaction_ns::_c_frankenstein(void *parm) { - Gfx::Palette pal0; - Gfx::Palette pal1; + Palette pal0(_gfx->_palette); + Palette pal1; - for (uint16 i = 0; i <= BASE_PALETTE_COLORS; i++) { - pal0[(i+FIRST_BASE_COLOR)] = _gfx->_palette[i]; - pal0[(i+FIRST_BASE_COLOR)*3+1] = 0; - pal0[(i+FIRST_BASE_COLOR)*3+2] = 0; - - pal1[(i+FIRST_BASE_COLOR)*3+1] = 0; - pal1[(i+FIRST_BASE_COLOR)*3+2] = 0; + for (uint16 i = 0; i <= 32; i++) { + pal0.setEntry(i, -1, 0, 0); // leaves reds unchanged while zeroing other components } for (uint16 _di = 0; _di < 30; _di++) { g_system->delayMillis(20); - _gfx->setPalette(pal0, FIRST_BASE_COLOR, BASE_PALETTE_COLORS); + _gfx->setPalette(pal0); _gfx->updateScreen(); g_system->delayMillis(20); - _gfx->setPalette(pal1, FIRST_BASE_COLOR, BASE_PALETTE_COLORS); + _gfx->setPalette(pal1); _gfx->updateScreen(); } @@ -435,7 +414,7 @@ void Parallaction_ns::_c_finito(void *parm) { _gfx->setPalette(_gfx->_palette); if (gameCompleted) { - _gfx->setFont(kFontMenu); + _gfx->setFont(_menuFont); _gfx->displayCenteredString(70, v4C[_language]); _gfx->displayCenteredString(100, v3C[_language]); _gfx->displayCenteredString(130, v2C[_language]); @@ -448,7 +427,7 @@ void Parallaction_ns::_c_finito(void *parm) { _engineFlags |= kEngineChangeLocation; } else { - _gfx->setFont(kFontMenu); + _gfx->setFont(_menuFont); _gfx->displayCenteredString(70, v8C[_language]); _gfx->displayCenteredString(100, v7C[_language]); _gfx->displayCenteredString(130, v6C[_language]); @@ -493,7 +472,7 @@ void Parallaction_ns::_c_testResult(void *parm) { _disk->selectArchive("disk1"); parseLocation("common"); - _gfx->setFont(kFontMenu); + _gfx->setFont(_menuFont); _gfx->displayCenteredString(38, _slideText[0]); _gfx->displayCenteredString(58, _slideText[1]); @@ -538,9 +517,9 @@ void Parallaction_ns::_c_startIntro(void *parm) { void Parallaction_ns::_c_endIntro(void *parm) { - _gfx->setFont(kFontMenu); + _gfx->setFont(_menuFont); - debugC(1, kDebugLocation, "endIntro()"); + debugC(1, kDebugExec, "endIntro()"); for (uint16 _si = 0; _si < 6; _si++) { _gfx->displayCenteredString(80, _credits[_si]._role); @@ -559,7 +538,7 @@ void Parallaction_ns::_c_endIntro(void *parm) { _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); } - debugC(1, kDebugLocation, "endIntro(): done showing credits"); + debugC(1, kDebugExec, "endIntro(): done showing credits"); if ((getFeatures() & GF_DEMO) == 0) { _gfx->displayCenteredString(80, "CLICK MOUSE BUTTON TO START"); @@ -604,21 +583,40 @@ void Parallaction_ns::_c_moveSheet(void *parm) { return; } -void plotPixel(int x, int y, int color, void *data) { - _vm->_gfx->plotMaskPixel(x, y, color); +void zeroMask(int x, int y, int color, void *data) { + //_vm->_gfx->zeroMaskValue(x, y, color); + + BackgroundInfo* info = (BackgroundInfo*)data; + + uint16 _ax = x + y * info->width; + info->mask.data[_ax >> 2] &= ~(3 << ((_ax & 3) << 1)); + } void Parallaction_ns::_c_sketch(void *parm) { static uint16 index = 1; - uint16 newy = _rightHandPositions[2*index+1]; - uint16 newx = _rightHandPositions[2*index]; + uint16 newx; + uint16 newy; uint16 oldy = _rightHandPositions[2*(index-1)+1]; uint16 oldx = _rightHandPositions[2*(index-1)]; - Graphics::drawLine(oldx, oldy, newx, newy, 0, plotPixel, NULL); + // WORKAROUND: original code overflowed _rightHandPositions by trying + // to access elements at positions 684 and 685. That used to happen + // when index == 342. Code now checks for this possibility and assigns + // the last valid value to the new coordinates for drawing without + // accessing the array. + if (index == 342) { + newy = oldy; + newx = oldx; + } else { + newy = _rightHandPositions[2*index+1]; + newx = _rightHandPositions[2*index]; + } + + Graphics::drawLine(oldx, oldy, newx, newy, 0, zeroMask, _backgroundInfo); _rightHandAnim->_left = newx; _rightHandAnim->_top = newy - 20; @@ -640,7 +638,12 @@ void Parallaction_ns::_c_shade(void *parm) { _rightHandAnim->_top ); - _gfx->fillMaskRect(r, 0); + uint16 _di = r.left/4 + r.top * _backgroundInfo->mask.internalWidth; + + for (uint16 _si = r.top; _si < r.bottom; _si++) { + memset(_backgroundInfo->mask.data + _di, 0, r.width()/4+1); + _di += _backgroundInfo->mask.internalWidth; + } return; diff --git a/engines/parallaction/commands.cpp b/engines/parallaction/commands.cpp deleted file mode 100644 index dc392fde2c..0000000000 --- a/engines/parallaction/commands.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "parallaction/parallaction.h" - - -namespace Parallaction { - -#define CMD_SET 1 -#define CMD_CLEAR 2 -#define CMD_START 3 -#define CMD_SPEAK 4 -#define CMD_GET 5 -#define CMD_LOCATION 6 -#define CMD_OPEN 7 -#define CMD_CLOSE 8 -#define CMD_ON 9 -#define CMD_OFF 10 -#define CMD_CALL 11 -#define CMD_TOGGLE 12 -#define CMD_DROP 13 -#define CMD_QUIT 14 -#define CMD_MOVE 15 -#define CMD_STOP 16 - - -void Parallaction::parseCommands(Script &script, CommandList& list) { -// printf("parseCommands()"); - - fillBuffers(script, true); - - while (scumm_stricmp(_tokens[0], "ENDCOMMANDS") && scumm_stricmp(_tokens[0], "ENDZONE")) { -// printf("token[0] = %s", _tokens[0]); - - Command *cmd = new Command; - - cmd->_id = _commandsNames->lookup(_tokens[0]); - uint16 _si = 1; - -// printf("cmd id = %i", cmd->_id); - - switch (cmd->_id) { - case CMD_SET: // set - case CMD_CLEAR: // clear - case CMD_TOGGLE: // toggle - if (_globalTable->lookup(_tokens[1]) == -1) { - do { - char _al = _localFlagNames->lookup(_tokens[_si]); - _si++; - cmd->u._flags |= 1 << (_al - 1); - } while (!scumm_stricmp(_tokens[_si++], "|")); - _si--; - } else { - cmd->u._flags |= kFlagsGlobal; - do { - char _al = _globalTable->lookup(_tokens[1]); - _si++; - cmd->u._flags |= 1 << (_al - 1); - } while (!scumm_stricmp(_tokens[_si++], "|")); - _si--; - } - break; - - case CMD_START: // start - case CMD_STOP: // stop - cmd->u._animation = findAnimation(_tokens[_si]); - _si++; - if (cmd->u._animation == NULL) { - strcpy(_forwardedAnimationNames[_numForwards], _tokens[_si-1]); - _forwardedCommands[_numForwards] = cmd; - _numForwards++; - } - break; - - case CMD_SPEAK: // speak - case CMD_GET: // get - case CMD_OPEN: // open - case CMD_CLOSE: // close - case CMD_ON: // on - case CMD_OFF: // off - cmd->u._zone = findZone(_tokens[_si]); - _si++; - break; - - case CMD_LOCATION: // location - cmd->u._string = (char*)malloc(strlen(_tokens[_si])+1); - strcpy(cmd->u._string, _tokens[_si]); - _si++; - break; - - case CMD_CALL: // call - cmd->u._callable = _callableNames->lookup(_tokens[_si]) - 1; - _si++; - break; - - case CMD_DROP: // drop - cmd->u._object = _objectsNames->lookup(_tokens[_si]); - _si++; - break; - - case CMD_QUIT: // quit - break; - - case CMD_MOVE: // move - cmd->u._move._x = atoi(_tokens[_si]); - _si++; - cmd->u._move._y = atoi(_tokens[_si]); - _si++; - break; - - } - - if (!scumm_stricmp(_tokens[_si], "flags")) { - _si++; - - do { - if (!scumm_stricmp(_tokens[_si], "exit") || !scumm_stricmp(_tokens[_si], "exittrap")) { - cmd->_flagsOn |= kFlagsExit; - } else - if (!scumm_stricmp(_tokens[_si], "enter") || !scumm_stricmp(_tokens[_si], "entertrap")) { - cmd->_flagsOn |= kFlagsEnter; - } else - if (!scumm_strnicmp(_tokens[_si], "no", 2)) { - byte _al = _localFlagNames->lookup(&_tokens[_si][2]); - cmd->_flagsOff |= 1 << (_al - 1); - } else { - byte _al = _localFlagNames->lookup(_tokens[_si]); - cmd->_flagsOn |= 1 << (_al - 1); - } - - _si++; - - } while (!scumm_stricmp(_tokens[_si++], "|")); - - } - - if (!scumm_stricmp(_tokens[_si], "gflags")) { - _si++; - cmd->_flagsOn |= kFlagsGlobal; - - do { - if (!scumm_stricmp(_tokens[_si], "exit")) { - cmd->_flagsOn |= kFlagsExit; - } else - if (!scumm_stricmp(_tokens[_si], "enter")) { - cmd->_flagsOn |= kFlagsEnter; - } else - if (!scumm_strnicmp(_tokens[_si], "no", 2)) { - byte _al = _globalTable->lookup(&_tokens[_si][2]); - cmd->_flagsOff |= 1 << (_al - 1); - } else { - byte _al = _globalTable->lookup(_tokens[_si]); - cmd->_flagsOn |= 1 << (_al - 1); - } - - _si++; - - } while (!scumm_stricmp(_tokens[_si++], "|")); - - } - - list.push_front(cmd); // NOTE: command lists are written backwards in scripts - fillBuffers(script, true); - - } - -} - - -void Parallaction::runCommands(CommandList& list, Zone *z) { - debugC(1, kDebugLocation, "runCommands"); - - CommandList::iterator it = list.begin(); - for ( ; it != list.end(); it++) { - - Command *cmd = *it; - CommandData *u = &cmd->u; - uint32 v8 = _localFlags[_currentLocationIndex]; - - if (_engineFlags & kEngineQuit) - break; - - if (cmd->_flagsOn & kFlagsGlobal) { - v8 = _commandFlags | kFlagsGlobal; - } - - if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue; - if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue; - - debugC(1, kDebugLocation, "runCommands: %s (on: %x, off: %x)", _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff); - - switch (cmd->_id) { - - case CMD_SET: // set - if (cmd->u._flags & kFlagsGlobal) { - cmd->u._flags &= ~kFlagsGlobal; - _commandFlags |= cmd->u._flags; - } else { - _localFlags[_currentLocationIndex] |= cmd->u._flags; - } - break; - - case CMD_CLEAR: // clear - if (cmd->u._flags & kFlagsGlobal) { - cmd->u._flags &= ~kFlagsGlobal; - _commandFlags &= ~cmd->u._flags; - } else { - _localFlags[_currentLocationIndex] &= ~cmd->u._flags; - } - break; - - case CMD_TOGGLE: // toggle - if (cmd->u._flags & kFlagsGlobal) { - cmd->u._flags &= ~kFlagsGlobal; - _commandFlags ^= cmd->u._flags; - } else { - _localFlags[_currentLocationIndex] ^= cmd->u._flags; - } - break; - - case CMD_START: // start - cmd->u._zone->_flags |= kFlagsActing; - break; - - case CMD_STOP: // stop - cmd->u._zone->_flags &= ~kFlagsActing; - break; - - case CMD_SPEAK: // speak - _activeZone = u->_zone; - break; - - case CMD_GET: // get - u->_zone->_flags &= ~kFlagsFixed; - if (!runZone(u->_zone)) { - runCommands(u->_zone->_commands); - } - break; - - case CMD_DROP: // drop - dropItem( u->_object ); - break; - - case CMD_OPEN: // open - u->_zone->_flags &= ~kFlagsClosed; - if (u->_zone->u.door->_cnv) { - addJob(&jobToggleDoor, (void*)u->_zone, kPriority18 ); - } - break; - - case CMD_CLOSE: // close - u->_zone->_flags |= kFlagsClosed; - if (u->_zone->u.door->_cnv) { - addJob(&jobToggleDoor, (void*)u->_zone, kPriority18 ); - } - break; - - case CMD_ON: // on - // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing - // the pointer to get structure members, thus leading to crashes in systems with memory - // protection. - // As a side note, the overwritten address is the 5th entry in the DOS interrupt table - // (print screen handler): this suggests that a system would hang when the print screen - // key is pressed after playing Nippon Safes, provided that this code path is taken. - if (u->_zone != NULL) { - u->_zone->_flags &= ~kFlagsRemove; - u->_zone->_flags |= kFlagsActive; - if ((u->_zone->_type & 0xFFFF) == kZoneGet) { - addJob(&jobDisplayDroppedItem, u->_zone, kPriority17 ); - } - } - break; - - case CMD_OFF: // off - u->_zone->_flags |= kFlagsRemove; - break; - - case CMD_LOCATION: // location - strcpy(_location._name, u->_string); - _engineFlags |= kEngineChangeLocation; - break; - - case CMD_CALL: // call - callFunction(u->_callable, z); - break; - - case CMD_QUIT: // quit - _engineFlags |= kEngineQuit; - break; - - case CMD_MOVE: { // move - if ((_char._ani._flags & kFlagsRemove) || (_char._ani._flags & kFlagsActive) == 0) { - continue; - } - - WalkNodeList *vC = _char._builder.buildPath(u->_move._x, u->_move._y); - - addJob(&jobWalk, vC, kPriority19 ); - _engineFlags |= kEngineWalking; - } - break; - - } - } - - debugC(1, kDebugLocation, "runCommands completed"); - - return; - -} - -Command::Command() { - _id = 0; - _flagsOn = 0; - _flagsOff = 0; -} - -Command::~Command() { - - if (_id == CMD_LOCATION) free(u._string); - -} - -} // namespace Parallaction - - - diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp index 95091789a9..5e419def52 100644 --- a/engines/parallaction/debug.cpp +++ b/engines/parallaction/debug.cpp @@ -116,7 +116,7 @@ bool Debugger::Cmd_Give(int argc, const char **argv) { DebugPrintf("give <item name>\n"); } else { int index = _vm->_objectsNames->lookup(argv[1]); - if (index != -1) + if (index != Table::notFound) _vm->addInventoryItem(index + 4); else DebugPrintf("invalid item name '%s'\n", argv[1]); @@ -135,7 +135,7 @@ bool Debugger::Cmd_Jobs(int argc, const char **argv) { "|tag| description |\n" "+---+-------------------------------------------------------------+\n"); for ( ; b != e; b++) { - DebugPrintf("|%3i| %-60s|\n", (*b)->_tag, _jobDescriptions[(*b)->_tag] ); + DebugPrintf("|%3i| %-60s|\n", (*b)->_job->_tag, _jobDescriptions[(*b)->_job->_tag] ); } DebugPrintf("+---+-------------------------------------------------------------+\n"); diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 84c45584a4..8ad79f34eb 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -48,6 +48,7 @@ Common::Platform Parallaction::getPlatform() const { return _gameDescription->de } static const PlainGameDescriptor parallactionGames[] = { + {"parallaction", "Parallaction engine game"}, {"nippon", "Nippon Safes Inc."}, {"bra", "The Big Red Adventure"}, {0, 0} @@ -176,7 +177,7 @@ static const Common::ADParams detectionParams = { // Structure for autoupgrading obsolete targets 0, // Name of single gameid (optional) - 0, + "parallaction", // List of files for file-based fallback detection (optional) 0, // Fallback callback @@ -185,33 +186,27 @@ static const Common::ADParams detectionParams = { Common::kADFlagAugmentPreferredTarget }; -GameList Engine_PARALLACTION_gameIDList() { - return GameList(parallactionGames); -} - -GameDescriptor Engine_PARALLACTION_findGameID(const char *gameid) { - return Common::AdvancedDetector::findGameID(gameid, parallactionGames); -} - -GameList Engine_PARALLACTION_detectGames(const FSList &fslist) { - return Common::AdvancedDetector::detectAllGames(fslist, detectionParams); -} - -PluginError Engine_PARALLACTION_create(OSystem *syst, Engine **engine) { - assert(engine); - const char *gameid = ConfMan.get("gameid").c_str(); +bool engineCreateParallaction(OSystem *syst, Engine **engine, Common::EncapsulatedADGameDesc encapsulatedDesc) { + const Parallaction::PARALLACTIONGameDescription *gd = (const Parallaction::PARALLACTIONGameDescription *)(encapsulatedDesc.realDesc); + bool res = true; - if (!scumm_stricmp("nippon", gameid)) { + switch (gd->gameType) { + case Parallaction::GType_Nippon: *engine = new Parallaction::Parallaction_ns(syst); - } else - if (!scumm_stricmp("bra", gameid)) { + break; + case Parallaction::GType_BRA: *engine = new Parallaction::Parallaction_br(syst); - } else - error("Parallaction engine created with invalid gameid ('%s')", gameid); + break; + default: + res = false; + error("Parallaction engine: unknown gameType"); + } - return kNoError; + return res; } +ADVANCED_DETECTOR_DEFINE_PLUGIN_WITH_COMPLEX_CREATION(PARALLACTION, engineCreateParallaction, detectionParams); + REGISTER_PLUGIN(PARALLACTION, "Parallaction engine", "Nippon Safes Inc. (C) Dynabyte"); diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 84ecde6e64..15a280d3be 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -46,7 +46,7 @@ namespace Parallaction { #define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_Y 80 -int16 selectAnswer(Question *q, StaticCnv*); +int16 selectAnswer(Question *q, Graphics::Surface*); int16 getHoverAnswer(int16 x, int16 y, Question *q); int16 _answerBalloonX[10] = { 80, 120, 150, 150, 150, 0, 0, 0, 0, 0 }; @@ -56,136 +56,6 @@ int16 _answerBalloonH[10] = { 0 }; -Dialogue *Parallaction::parseDialogue(Script &script) { -// printf("parseDialogue()\n"); - uint16 numQuestions = 0; - - Dialogue *dialogue = new Dialogue; - - Table forwards(20); - - fillBuffers(script, true); - - while (scumm_stricmp(_tokens[0], "enddialogue")) { - if (scumm_stricmp(_tokens[0], "Question")) continue; - - Question *question = new Question; - dialogue->_questions[numQuestions] = question; - - forwards.addData(_tokens[1]); - - question->_text = parseDialogueString(script); - - fillBuffers(script, true); - question->_mood = atoi(_tokens[0]); - - uint16 numAnswers = 0; - - fillBuffers(script, true); - while (scumm_stricmp(_tokens[0], "endquestion")) { // parse answers - - Answer *answer = new Answer; - question->_answers[numAnswers] = answer; - - if (_tokens[1][0]) { - - Table* flagNames; - uint16 token; - - if (!scumm_stricmp(_tokens[1], "global")) { - token = 2; - flagNames = _globalTable; - answer->_yesFlags |= kFlagsGlobal; - } else { - token = 1; - flagNames = _localFlagNames; - } - - do { - - if (!scumm_strnicmp(_tokens[token], "no", 2)) { - byte _al = flagNames->lookup(_tokens[token]+2); - answer->_noFlags |= 1 << (_al - 1); - } else { - byte _al = flagNames->lookup(_tokens[token]); - answer->_yesFlags |= 1 << (_al - 1); - } - - token++; - - } while (!scumm_stricmp(_tokens[token++], "|")); - - } - - answer->_text = parseDialogueString(script); - - fillBuffers(script, true); - answer->_mood = atoi(_tokens[0]); - answer->_following._name = parseDialogueString(script); - - fillBuffers(script, true); - if (!scumm_stricmp(_tokens[0], "commands")) { - parseCommands(script, answer->_commands); - fillBuffers(script, true); - } - - numAnswers++; - } - - fillBuffers(script, true); - numQuestions++; - - } - - // link questions - byte v50[20]; - memset(v50, 0, 20); - - for (uint16 i = 0; i < numQuestions; i++) { - Question *question = dialogue->_questions[i]; - - for (uint16 j = 0; j < NUM_ANSWERS; j++) { - Answer *answer = question->_answers[j]; - if (answer == 0) continue; - - int16 index = forwards.lookup(answer->_following._name); - free(answer->_following._name); - - if (index == -1) - answer->_following._question = 0; - else - answer->_following._question = dialogue->_questions[index - 1]; - - - } - } - - return dialogue; -} - - -char *Parallaction::parseDialogueString(Script &script) { - - char vC8[200]; - char *vD0 = NULL; - do { - - vD0 = script.readLine(vC8, 200); - if (vD0 == 0) return NULL; - - vD0 = Common::ltrim(vD0); - - } while (strlen(vD0) == 0); - - vD0[strlen(vD0)-1] = '\0'; // deletes the trailing '0xA' - // this is critical for Gfx::displayWrappedString to work properly - - char *vCC = (char*)malloc(strlen(vD0)+1); - strcpy(vCC, vD0); - - return vCC; -} - class DialogueManager { Parallaction *_vm; @@ -195,8 +65,8 @@ class DialogueManager { bool _askPassword; bool isNpc; - Cnv *_questioner; - Cnv *_answerer; + Frames *_questioner; + Frames *_answerer; Question *_q; @@ -233,7 +103,7 @@ protected: }; uint16 DialogueManager::askPassword() { - debugC(1, kDebugDialogue, "checkDialoguePassword()"); + debugC(3, kDebugExec, "checkDialoguePassword()"); char password[100]; uint16 passwordLen; @@ -258,9 +128,10 @@ uint16 DialogueManager::askPassword() { // FIXME: see comment for updateInput() if (!g_system->getEventManager()->pollEvent(e)) continue; - if (e.type != Common::EVENT_KEYDOWN) continue; if (e.type == Common::EVENT_QUIT) g_system->quit(); + + if (e.type != Common::EVENT_KEYDOWN) continue; if (!isdigit(e.kbd.ascii)) continue; password[passwordLen] = e.kbd.ascii; @@ -291,7 +162,7 @@ uint16 DialogueManager::askPassword() { bool DialogueManager::displayAnswer(uint16 i) { - uint32 v28 = _localFlags[_vm->_currentLocationIndex]; + uint32 v28 = _vm->_localFlags[_vm->_currentLocationIndex]; if (_q->_answers[i]->_yesFlags & kFlagsGlobal) v28 = _commandFlags | kFlagsGlobal; @@ -370,7 +241,7 @@ uint16 DialogueManager::getAnswer() { clear(); - debugC(1, kDebugDialogue, "runDialogue: user selected answer #%i", answer); + debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer); return answer; } @@ -383,6 +254,8 @@ void DialogueManager::run() { _q = _dialogue->_questions[0]; int16 answer; + _vm->_gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); + while (_q) { answer = 0; @@ -488,9 +361,9 @@ int16 DialogueManager::getHoverAnswer(int16 x, int16 y) { void Parallaction::runDialogue(SpeakData *data) { - debugC(1, kDebugDialogue, "runDialogue: starting dialogue '%s'", data->_name); + debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name); - _gfx->setFont(kFontDialogue); + _gfx->setFont(_dialogueFont); if (getPlatform() == Common::kPlatformPC) showCursor(false); @@ -503,34 +376,5 @@ void Parallaction::runDialogue(SpeakData *data) { return; } -Answer::Answer() { - _text = NULL; - _mood = 0; - _following._question = NULL; - _noFlags = 0; - _yesFlags = 0; -} - -Answer::~Answer() { - if (_text) - free(_text); -} - -Question::Question() { - _text = NULL; - _mood = 0; - - for (uint32 i = 0; i < NUM_ANSWERS; i++) - _answers[i] = NULL; - -} - -Question::~Question() { - - for (uint32 i = 0; i < NUM_ANSWERS; i++) - if (_answers[i]) delete _answers[i]; - - free(_text); -} } // namespace Parallaction diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index ae572b1122..6adab69f51 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -28,6 +28,7 @@ #include "parallaction/defs.h" #include "common/file.h" +#include "graphics/surface.h" namespace Parallaction { @@ -37,9 +38,10 @@ class Gfx; class Script; class Font; +struct Frames; struct Cnv; -struct StaticCnv; - +struct Sprites; +struct BackgroundInfo; class Disk { @@ -52,15 +54,15 @@ public: virtual Script* loadLocation(const char *name) = 0; virtual Script* loadScript(const char* name) = 0; - virtual Cnv* loadTalk(const char *name) = 0; - virtual Cnv* loadObjects(const char *name) = 0; - virtual StaticCnv* loadPointer() = 0; - virtual StaticCnv* loadHead(const char* name) = 0; + virtual Frames* loadTalk(const char *name) = 0; + virtual Frames* loadObjects(const char *name) = 0; + virtual Graphics::Surface* loadPointer(const char *name) = 0; + virtual Graphics::Surface* loadHead(const char* name) = 0; virtual Font* loadFont(const char* name) = 0; - virtual StaticCnv* loadStatic(const char* name) = 0; - virtual Cnv* loadFrames(const char* name) = 0; - virtual void loadSlide(const char *filename) = 0; - virtual void loadScenery(const char* background, const char* mask) = 0; + virtual Graphics::Surface* loadStatic(const char* name) = 0; + virtual Frames* loadFrames(const char* name) = 0; + virtual void loadSlide(BackgroundInfo& info, const char *filename) = 0; + virtual void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) = 0; virtual Table* loadTable(const char* name) = 0; virtual Common::SeekableReadStream* loadMusic(const char* name) = 0; virtual Common::ReadStream* loadSound(const char* name) = 0; @@ -128,11 +130,11 @@ private: void unpackBackground(Common::ReadStream *stream, byte *screen, byte *mask, byte *path); Cnv* loadExternalCnv(const char *filename); Cnv* loadCnv(const char *filename); - StaticCnv *loadExternalStaticCnv(const char *filename); - void loadBackground(const char *filename); - void loadMaskAndPath(const char *name); + Graphics::Surface *loadExternalStaticCnv(const char *filename); + void loadBackground(BackgroundInfo& info, const char *filename); + void loadMaskAndPath(BackgroundInfo& info, const char *name); void parseDepths(Common::SeekableReadStream &stream); - void parseBackground(Common::SeekableReadStream &stream); + void parseBackground(BackgroundInfo& info, Common::SeekableReadStream &stream); Font *createFont(const char *name, Cnv* cnv); protected: @@ -144,15 +146,15 @@ public: Script* loadLocation(const char *name); Script* loadScript(const char* name); - Cnv* loadTalk(const char *name); - Cnv* loadObjects(const char *name); - StaticCnv* loadPointer(); - StaticCnv* loadHead(const char* name); + Frames* loadTalk(const char *name); + Frames* loadObjects(const char *name); + Graphics::Surface* loadPointer(const char *name); + Graphics::Surface* loadHead(const char* name); Font* loadFont(const char* name); - StaticCnv* loadStatic(const char* name); - Cnv* loadFrames(const char* name); - void loadSlide(const char *filename); - void loadScenery(const char* background, const char* mask); + Graphics::Surface* loadStatic(const char* name); + Frames* loadFrames(const char* name); + void loadSlide(BackgroundInfo& info, const char *filename); + void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path); Table* loadTable(const char* name); Common::SeekableReadStream* loadMusic(const char* name); Common::ReadStream* loadSound(const char* name); @@ -162,15 +164,15 @@ class AmigaDisk_ns : public Disk_ns { protected: Cnv* makeCnv(Common::SeekableReadStream &stream); - StaticCnv* makeStaticCnv(Common::SeekableReadStream &stream); + Graphics::Surface* makeStaticCnv(Common::SeekableReadStream &stream); void patchFrame(byte *dst, byte *dlta, uint16 bytesPerPlane, uint16 height); void unpackFrame(byte *dst, byte *src, uint16 planeSize); void unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 bytesPerPlane, uint16 height); Common::SeekableReadStream *openArchivedFile(const char* name, bool errorOnFileNotFound = false); Font *createFont(const char *name, Common::SeekableReadStream &stream); - void loadMask(const char *name); - void loadPath(const char *name); - void loadBackground(const char *name); + void loadMask(BackgroundInfo& info, const char *name); + void loadPath(BackgroundInfo& info, const char *name); + void loadBackground(BackgroundInfo& info, const char *name); public: AmigaDisk_ns(Parallaction *vm); @@ -178,15 +180,15 @@ public: Script* loadLocation(const char *name); Script* loadScript(const char* name); - Cnv* loadTalk(const char *name); - Cnv* loadObjects(const char *name); - StaticCnv* loadPointer(); - StaticCnv* loadHead(const char* name); + Frames* loadTalk(const char *name); + Frames* loadObjects(const char *name); + Graphics::Surface* loadPointer(const char *name); + Graphics::Surface* loadHead(const char* name); Font* loadFont(const char* name); - StaticCnv* loadStatic(const char* name); - Cnv* loadFrames(const char* name); - void loadSlide(const char *filename); - void loadScenery(const char* background, const char* mask); + Graphics::Surface* loadStatic(const char* name); + Frames* loadFrames(const char* name); + void loadSlide(BackgroundInfo& info, const char *filename); + void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path); Table* loadTable(const char* name); Common::SeekableReadStream* loadMusic(const char* name); Common::ReadStream* loadSound(const char* name); @@ -200,9 +202,13 @@ class DosDisk_br : public Disk { protected: Parallaction *_vm; + char _partPath[PATH_LEN]; + char _languageDir[2]; protected: void errorFileNotFound(const char *s); + Font *createFont(const char *name, Common::ReadStream &stream); + Sprites* createSprites(const char *name); public: DosDisk_br(Parallaction *vm); @@ -212,15 +218,15 @@ public: void setLanguage(uint16 language); Script* loadLocation(const char *name); Script* loadScript(const char* name); - Cnv* loadTalk(const char *name); - Cnv* loadObjects(const char *name); - StaticCnv* loadPointer(); - StaticCnv* loadHead(const char* name); + Frames* loadTalk(const char *name); + Frames* loadObjects(const char *name); + Graphics::Surface* loadPointer(const char *name); + Graphics::Surface* loadHead(const char* name); Font* loadFont(const char* name); - StaticCnv* loadStatic(const char* name); - Cnv* loadFrames(const char* name); - void loadSlide(const char *filename); - void loadScenery(const char* background, const char* mask); + Graphics::Surface* loadStatic(const char* name); + Frames* loadFrames(const char* name); + void loadSlide(BackgroundInfo& info, const char *filename); + void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path); Table* loadTable(const char* name); Common::SeekableReadStream* loadMusic(const char* name); Common::ReadStream* loadSound(const char* name); diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 452b74be51..5b79ad7df6 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -30,18 +30,95 @@ namespace Parallaction { +struct Sprite { + uint16 size; + uint16 x; + uint16 y; + uint16 w; + uint16 h; + + byte *packedData; + + Sprite() : size(0), x(0), y(0), w(0), h(0), packedData(0) { + } + + ~Sprite() { + if (packedData) + free(packedData); + } +}; + +struct Sprites : public Frames { + uint16 _num; + Sprite* _sprites; + + Sprites(uint num) { + _num = num; + _sprites = new Sprite[_num]; + } + + ~Sprites() { + delete _sprites; + } + + uint16 getNum() { + return _num; + } + + byte* getData(uint16 index) { + assert(index < _num); + return _sprites[index].packedData; + } + + void getRect(uint16 index, Common::Rect &r) { + assert(index < _num); + r.setWidth(_sprites[index].w); + r.setHeight(_sprites[index].h); + r.moveTo(_sprites[index].x, _sprites[index].y); +} + +}; + + + void DosDisk_br::errorFileNotFound(const char *s) { error("File '%s' not found", s); } Common::String DosDisk_br::selectArchive(const Common::String& name) { debugC(5, kDebugDisk, "DosDisk_br::selectArchive"); - return ""; + + Common::String oldPath(_partPath); + strcpy(_partPath, name.c_str()); + + return oldPath; } void DosDisk_br::setLanguage(uint16 language) { debugC(5, kDebugDisk, "DosDisk_br::setLanguage"); + switch (language) { + case 0: + strcpy(_languageDir, "it"); + break; + + case 1: + strcpy(_languageDir, "fr"); + break; + + case 2: + strcpy(_languageDir, "en"); + break; + + case 3: + strcpy(_languageDir, "ge"); + break; + + default: + error("unknown language"); + + } + return; } @@ -52,71 +129,239 @@ DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) { DosDisk_br::~DosDisk_br() { } -Cnv* DosDisk_br::loadTalk(const char *name) { +Frames* DosDisk_br::loadTalk(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadTalk"); - return 0; + char path[PATH_LEN]; + sprintf(path, "%s/tal/%s.tal", _partPath, name); + + return createSprites(path); } Script* DosDisk_br::loadLocation(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadLocation"); - return 0; + + Common::File *stream = new Common::File; + + char path[PATH_LEN]; + sprintf(path, "%s/%s/%s.slf", _partPath, _languageDir, name); + if (!stream->open(path)) { + sprintf(path, "%s/%s/%s.loc", _partPath, _languageDir, name); + if (!stream->open(path)) + errorFileNotFound(path); + } + + return new Script(stream, true); } Script* DosDisk_br::loadScript(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadScript"); - return 0; + + Common::File *stream = new Common::File; + + char path[PATH_LEN]; + sprintf(path, "%s/scripts/%s.scr", _partPath, name); + if (!stream->open(path)) + errorFileNotFound(path); + + return new Script(stream, true); } // there are no Head resources in Big Red Adventure -StaticCnv* DosDisk_br::loadHead(const char* name) { +Graphics::Surface* DosDisk_br::loadHead(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadHead"); return 0; } -StaticCnv* DosDisk_br::loadPointer() { +Graphics::Surface* DosDisk_br::loadPointer(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadPointer"); - return 0; + + char path[PATH_LEN]; + sprintf(path, "%s.ras", name); + + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + stream.skip(4); + uint width = stream.readUint32BE(); + uint height = stream.readUint32BE(); + stream.skip(20); + stream.skip(768); + + Graphics::Surface *surf = new Graphics::Surface; + + surf->create(width, height, 1); + stream.read(surf->pixels, width * height); + + return surf; } Font* DosDisk_br::loadFont(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFont"); - return 0; + + char path[PATH_LEN]; + sprintf(path, "%s.fnt", name); + + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + return createFont(name, stream); } -Cnv* DosDisk_br::loadObjects(const char *name) { +Frames* DosDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); return 0; } +void genSlidePath(char *path, const char* name) { + sprintf(path, "%s.bmp", name); +} -StaticCnv* DosDisk_br::loadStatic(const char* name) { +Graphics::Surface* DosDisk_br::loadStatic(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadStatic"); return 0; } -Cnv* DosDisk_br::loadFrames(const char* name) { +Sprites* DosDisk_br::createSprites(const char *path) { + + Common::File stream; + if (!stream.open(path)) { + errorFileNotFound(path); + } + + uint16 num = stream.readUint16LE(); + + Sprites *sprites = new Sprites(num); + + for (uint i = 0; i < num; i++) { + Sprite *spr = &sprites->_sprites[i]; + spr->size = stream.readUint16LE(); + spr->x = stream.readUint16LE(); + spr->y = stream.readUint16LE(); + spr->w = stream.readUint16LE(); + spr->h = stream.readUint16LE(); + + spr->packedData = (byte*)malloc(spr->size); + stream.read(spr->packedData, spr->size); + } + + return sprites; +} + +Frames* DosDisk_br::loadFrames(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); - return 0; + + char path[PATH_LEN]; + sprintf(path, "%s/ani/%s.ani", _partPath, name); + + return createSprites(path); } -// there are no Slide resources in Big Red Adventure -void DosDisk_br::loadSlide(const char *filename) { +// Slides in Nippon Safes are basically screen-sized pictures with valid +// palette data used for menu and for location switches. Big Red Adventure +// doesn't need slides in that sense, but it still has some special +// graphics resources with palette data, so those will be named slides. +// +void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadSlide"); + + char path[PATH_LEN]; + genSlidePath(path, name); + + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + stream.skip(4); + info.width = stream.readUint32BE(); + info.height = stream.readUint32BE(); + stream.skip(20); + + byte rgb[768]; + stream.read(rgb, 768); + + for (uint i = 0; i < 256; i++) { + info.palette.setEntry(i, rgb[i] >> 2, rgb[i+256] >> 2, rgb[i+512] >> 2); + } + + info.bg.create(info.width, info.height, 1); + stream.read(info.bg.pixels, info.width * info.height); + return; } -void DosDisk_br::loadScenery(const char *name, const char *mask) { +void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) { debugC(5, kDebugDisk, "DosDisk_br::loadScenery"); + + char filename[PATH_LEN]; + Common::File stream; + + if (name) { + sprintf(filename, "%s/bkg/%s.bkg", _partPath, name); + if (!stream.open(filename)) + errorFileNotFound(filename); + + stream.skip(4); + info.width = stream.readUint32BE(); + info.height = stream.readUint32BE(); + stream.skip(20); + + byte rgb[768]; + stream.read(rgb, 768); + + for (uint i = 0; i < 256; i++) { + info.palette.setEntry(i, rgb[i] >> 2, rgb[i+256] >> 2, rgb[i+512] >> 2); + } + + info.bg.create(info.width, info.height, 1); + stream.read(info.bg.pixels, info.width * info.height); + } + + if (mask) { + sprintf(filename, "%s/msk/%s.msk", _partPath, mask); + if (!stream.open(filename)) + errorFileNotFound(filename); + + // NOTE: info.width and info.height are only valid if the background graphics + // have already been loaded + info.mask.create(info.width, info.height); + stream.read(info.mask.data, info.width * info.height); + } + + if (path) { + sprintf(filename, "%s/pth/%s.pth", _partPath, path); + if (!stream.open(filename)) + errorFileNotFound(filename); + + // NOTE: info.width and info.height are only valid if the background graphics + // have already been loaded + info.path.create(info.width, info.height); + stream.read(info.path.data, info.width * info.height); + } + return; } Table* DosDisk_br::loadTable(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadTable"); - return 0; + + char path[PATH_LEN]; + sprintf(path, "%s/%s.tab", _partPath, name); + + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + Table *t = createTableFromStream(100, stream); + + stream.close(); + + return t; } Common::SeekableReadStream* DosDisk_br::loadMusic(const char* name) { diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index c0bb2691ef..8b5ce850ff 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -345,7 +345,7 @@ Cnv* DosDisk_ns::loadExternalCnv(const char *filename) { return new Cnv(numFrames, width, height, data); } -StaticCnv *DosDisk_ns::loadExternalStaticCnv(const char *filename) { +Graphics::Surface *DosDisk_ns::loadExternalStaticCnv(const char *filename) { char path[PATH_LEN]; @@ -356,16 +356,14 @@ StaticCnv *DosDisk_ns::loadExternalStaticCnv(const char *filename) { if (!stream.open(path)) errorFileNotFound(path); - StaticCnv *cnv = new StaticCnv; + Graphics::Surface *cnv = new Graphics::Surface; stream.skip(1); - cnv->_width = stream.readByte(); - cnv->_height = stream.readByte(); + byte w = stream.readByte(); + byte h = stream.readByte(); - uint16 size = cnv->_width*cnv->_height; - - cnv->_data0 = (byte*)malloc(size); - stream.read(cnv->_data0, size); + cnv->create(w, h, 1); + stream.read(cnv->pixels, w*h); return cnv; } @@ -395,7 +393,7 @@ Cnv* DosDisk_ns::loadCnv(const char *filename) { return new Cnv(numFrames, width, height, data); } -Cnv* DosDisk_ns::loadTalk(const char *name) { +Frames* DosDisk_ns::loadTalk(const char *name) { const char *ext = strstr(name, ".talk"); if (ext != NULL) { @@ -462,7 +460,7 @@ Script* DosDisk_ns::loadScript(const char* name) { return new Script(new DummyArchiveStream(_resArchive), true); } -StaticCnv* DosDisk_ns::loadHead(const char* name) { +Graphics::Surface* DosDisk_ns::loadHead(const char* name) { char path[PATH_LEN]; @@ -477,8 +475,8 @@ StaticCnv* DosDisk_ns::loadHead(const char* name) { } -StaticCnv* DosDisk_ns::loadPointer() { - return loadExternalStaticCnv("pointer"); +Graphics::Surface* DosDisk_ns::loadPointer(const char *name) { + return loadExternalStaticCnv(name); } @@ -489,7 +487,7 @@ Font* DosDisk_ns::loadFont(const char* name) { } -Cnv* DosDisk_ns::loadObjects(const char *name) { +Frames* DosDisk_ns::loadObjects(const char *name) { if (IS_MINI_CHARACTER(name)) { name += 4; @@ -501,7 +499,7 @@ Cnv* DosDisk_ns::loadObjects(const char *name) { } -StaticCnv* DosDisk_ns::loadStatic(const char* name) { +Graphics::Surface* DosDisk_ns::loadStatic(const char* name) { char path[PATH_LEN]; @@ -512,22 +510,21 @@ StaticCnv* DosDisk_ns::loadStatic(const char* name) { errorFileNotFound(path); } - StaticCnv* cnv = new StaticCnv; + Graphics::Surface* cnv = new Graphics::Surface; _resArchive.skip(1); - cnv->_width = _resArchive.readByte(); - cnv->_height = _resArchive.readByte(); + byte w = _resArchive.readByte(); + byte h = _resArchive.readByte(); - uint16 size = cnv->_width*cnv->_height; - cnv->_data0 = (byte*)malloc(size); + cnv->create(w, h, 1); Graphics::PackBitsReadStream decoder(_resArchive); - decoder.read(cnv->_data0, size); + decoder.read(cnv->pixels, w*h); return cnv; } -Cnv* DosDisk_ns::loadFrames(const char* name) { +Frames* DosDisk_ns::loadFrames(const char* name) { return loadCnv(name); } @@ -565,10 +562,16 @@ void DosDisk_ns::parseDepths(Common::SeekableReadStream &stream) { } -void DosDisk_ns::parseBackground(Common::SeekableReadStream &stream) { +void DosDisk_ns::parseBackground(BackgroundInfo& info, Common::SeekableReadStream &stream) { + + byte tmp[3]; - stream.read(_vm->_gfx->_palette, BASE_PALETTE_SIZE); - _vm->_gfx->setPalette(_vm->_gfx->_palette); + for (uint i = 0; i < 32; i++) { + tmp[0] = stream.readByte(); + tmp[1] = stream.readByte(); + tmp[2] = stream.readByte(); + info.palette.setEntry(i, tmp[0], tmp[1], tmp[2]); + } parseDepths(stream); @@ -582,28 +585,22 @@ void DosDisk_ns::parseBackground(Common::SeekableReadStream &stream) { } -void DosDisk_ns::loadBackground(const char *filename) { +void DosDisk_ns::loadBackground(BackgroundInfo& info, const char *filename) { if (!_resArchive.openArchivedFile(filename)) errorFileNotFound(filename); - parseBackground(_resArchive); + info.width = _vm->_screenWidth; // 320 + info.height = _vm->_screenHeight; // 200 - byte *bg = (byte*)calloc(1, _vm->_screenSize); - byte *mask = (byte*)calloc(1, _vm->_screenMaskSize); - byte *path = (byte*)calloc(1, _vm->_screenPathSize); + parseBackground(info, _resArchive); + info.bg.create(info.width, info.height, 1); + info.mask.create(info.width, info.height); + info.path.create(info.width, info.height); Graphics::PackBitsReadStream stream(_resArchive); - unpackBackground(&stream, bg, mask, path); - - _vm->_gfx->setBackground(bg); - _vm->_gfx->setMask(mask); - _vm->setPath(path); - - free(bg); - free(mask); - free(path); + unpackBackground(&stream, (byte*)info.bg.pixels, info.mask.data, info.path.data); return; } @@ -614,43 +611,44 @@ void DosDisk_ns::loadBackground(const char *filename) { // mask and path are normally combined (via OR) into the background picture itself // read the comment on the top of this file for more // -void DosDisk_ns::loadMaskAndPath(const char *name) { +void DosDisk_ns::loadMaskAndPath(BackgroundInfo& info, const char *name) { char path[PATH_LEN]; sprintf(path, "%s.msk", name); if (!_resArchive.openArchivedFile(path)) errorFileNotFound(name); - byte *maskBuf = (byte*)calloc(1, _vm->_screenMaskSize); - byte *pathBuf = (byte*)calloc(1, _vm->_screenPathSize); - parseDepths(_resArchive); - _resArchive.read(pathBuf, _vm->_screenPathSize); - _resArchive.read(maskBuf, _vm->_screenMaskSize); + info.path.create(info.width, info.height); + _resArchive.read(info.path.data, info.path.size); - _vm->_gfx->setMask(maskBuf); - _vm->setPath(pathBuf); + info.mask.create(info.width, info.height); + _resArchive.read(info.mask.data, info.mask.size); return; } -void DosDisk_ns::loadSlide(const char *filename) { +void DosDisk_ns::loadSlide(BackgroundInfo& info, const char *filename) { char path[PATH_LEN]; sprintf(path, "%s.slide", filename); - loadBackground(path); + loadBackground(info, path); + + return; } -void DosDisk_ns::loadScenery(const char *name, const char *mask) { - char path[PATH_LEN]; - sprintf(path, "%s.dyn", name); - loadBackground(path); +void DosDisk_ns::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) { + char filename[PATH_LEN]; + sprintf(filename, "%s.dyn", name); + + loadBackground(info, filename); if (mask != NULL) { // load external masks and paths only for certain locations - loadMaskAndPath(mask); + loadMaskAndPath(info, mask); } + return; } Table* DosDisk_ns::loadTable(const char* name) { @@ -661,13 +659,7 @@ Table* DosDisk_ns::loadTable(const char* name) { if (!stream.open(path)) errorFileNotFound(path); - Table *t = new Table(100); - - fillBuffers(stream); - while (scumm_stricmp(_tokens[0], "ENDTABLE")) { - t->addData(_tokens[0]); - fillBuffers(stream); - } + Table *t = createTableFromStream(100, stream); stream.close(); @@ -974,7 +966,7 @@ void AmigaDisk_ns::unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 b } -StaticCnv* AmigaDisk_ns::makeStaticCnv(Common::SeekableReadStream &stream) { +Graphics::Surface* AmigaDisk_ns::makeStaticCnv(Common::SeekableReadStream &stream) { stream.skip(1); uint16 width = stream.readByte(); @@ -988,19 +980,13 @@ StaticCnv* AmigaDisk_ns::makeStaticCnv(Common::SeekableReadStream &stream) { byte *buf = (byte*)malloc(rawsize); stream.read(buf, rawsize); - uint32 decsize = width * height; - byte *data = (byte*)calloc(decsize, 1); + Graphics::Surface *cnv = new Graphics::Surface; + cnv->create(width, height, 1); - unpackBitmap(data, buf, 1, bytesPerPlane, height); + unpackBitmap((byte*)cnv->pixels, buf, 1, bytesPerPlane, height); free(buf); - StaticCnv *cnv = new StaticCnv(); - cnv->_width = width; - cnv->_height = height; - cnv->_data0 = data; - cnv->_data1 = NULL; - return cnv; } @@ -1063,21 +1049,21 @@ Script* AmigaDisk_ns::loadScript(const char* name) { return new Script(new DummyArchiveStream(_resArchive), true); } -StaticCnv* AmigaDisk_ns::loadPointer() { +Graphics::Surface* AmigaDisk_ns::loadPointer(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadPointer"); Common::File stream; - if (!stream.open("pointer")) - errorFileNotFound("pointer"); + if (!stream.open(name)) + errorFileNotFound(name); return makeStaticCnv(stream); } -StaticCnv* AmigaDisk_ns::loadStatic(const char* name) { +Graphics::Surface* AmigaDisk_ns::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadStatic '%s'", name); Common::SeekableReadStream *s = openArchivedFile(name, true); - StaticCnv *cnv = makeStaticCnv(*s); + Graphics::Surface *cnv = makeStaticCnv(*s); delete s; @@ -1186,28 +1172,38 @@ public: }; -void AmigaDisk_ns::loadBackground(const char *name) { +void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) { Common::SeekableReadStream *s = openArchivedFile(name, true); - Graphics::Surface surf; byte *pal; - BackgroundDecoder decoder(*s, surf, pal, _vm->_gfx->_palettefx); + + BackgroundDecoder decoder(*s, info.bg, pal, _vm->_gfx->_palettefx); decoder.decode(); - for (uint32 i = 0; i < BASE_PALETTE_COLORS * 3; i++) - _vm->_gfx->_palette[i] = pal[i] >> 2; + info.width = info.bg.w; + info.height = info.bg.h; + + byte *p = pal; + for (uint i = 0; i < 32; i++) { + byte r = *p >> 2; + p++; + byte g = *p >> 2; + p++; + byte b = *p >> 2; + p++; + info.palette.setEntry(i, r, g, b); + } + free(pal); - _vm->_gfx->setPalette(_vm->_gfx->_palette); - _vm->_gfx->setBackground(static_cast<byte*>(surf.pixels)); - surf.free(); + delete s; return; } -void AmigaDisk_ns::loadMask(const char *name) { +void AmigaDisk_ns::loadMask(BackgroundInfo& info, const char *name) { debugC(5, kDebugDisk, "AmigaDisk_ns::loadMask(%s)", name); char path[PATH_LEN]; @@ -1236,18 +1232,16 @@ void AmigaDisk_ns::loadMask(const char *name) { s->seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic Graphics::PackBitsReadStream stream(*s); - byte *buf = (byte*)malloc(_vm->_screenMaskSize); - stream.read(buf, _vm->_screenMaskSize); - buildMask(buf); + info.mask.create(info.width, info.height); + stream.read(info.mask.data, info.mask.size); + buildMask(info.mask.data); - _vm->_gfx->setMask(buf); - free(buf); delete s; return; } -void AmigaDisk_ns::loadPath(const char *name) { +void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) { char path[PATH_LEN]; sprintf(path, "%s.path", name); @@ -1260,49 +1254,52 @@ void AmigaDisk_ns::loadPath(const char *name) { s->seek(0x120, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic Graphics::PackBitsReadStream stream(*s); - byte *buf = (byte*)malloc(_vm->_screenPathSize); - stream.read(buf, _vm->_screenPathSize); - _vm->setPath(buf); - free(buf); + + info.path.create(info.width, info.height); + stream.read(info.path.data, info.path.size); + delete s; return; } -void AmigaDisk_ns::loadScenery(const char* background, const char* mask) { +void AmigaDisk_ns::loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadScenery '%s', '%s'", background, mask); - char path[PATH_LEN]; - sprintf(path, "%s.bkgnd", background); + char filename[PATH_LEN]; + sprintf(filename, "%s.bkgnd", background); - loadBackground(path); + loadBackground(info, filename); if (mask == NULL) { - loadMask(background); - loadPath(background); + loadMask(info, background); + loadPath(info, background); } else { - loadMask(mask); - loadPath(mask); + loadMask(info, mask); + loadPath(info, mask); } return; } -void AmigaDisk_ns::loadSlide(const char *name) { +void AmigaDisk_ns::loadSlide(BackgroundInfo& info, const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadSlide '%s'", name); char path[PATH_LEN]; sprintf(path, "slides/%s", name); Common::SeekableReadStream *s = openArchivedFile(path, false); + if (s) - loadBackground(path); + loadBackground(info, path); else - loadBackground(name); + loadBackground(info, name); + + delete s; return; } -Cnv* AmigaDisk_ns::loadFrames(const char* name) { +Frames* AmigaDisk_ns::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadFrames '%s'", name); Common::SeekableReadStream *s; @@ -1320,14 +1317,14 @@ Cnv* AmigaDisk_ns::loadFrames(const char* name) { return cnv; } -StaticCnv* AmigaDisk_ns::loadHead(const char* name) { +Graphics::Surface* AmigaDisk_ns::loadHead(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadHead '%s'", name); char path[PATH_LEN]; sprintf(path, "%s.head", name); Common::SeekableReadStream *s = openArchivedFile(path, true); - StaticCnv *cnv = makeStaticCnv(*s); + Graphics::Surface *cnv = makeStaticCnv(*s); delete s; @@ -1335,7 +1332,7 @@ StaticCnv* AmigaDisk_ns::loadHead(const char* name) { } -Cnv* AmigaDisk_ns::loadObjects(const char *name) { +Frames* AmigaDisk_ns::loadObjects(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadObjects"); char path[PATH_LEN]; @@ -1353,7 +1350,7 @@ Cnv* AmigaDisk_ns::loadObjects(const char *name) { } -Cnv* AmigaDisk_ns::loadTalk(const char *name) { +Frames* AmigaDisk_ns::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadTalk '%s'", name); Common::SeekableReadStream *s; @@ -1401,13 +1398,7 @@ Table* AmigaDisk_ns::loadTable(const char* name) { stream = &_resArchive; } - Table *t = new Table(100); - - fillBuffers(*stream); - while (scumm_stricmp(_tokens[0], "ENDTABLE")) { - t->addData(_tokens[0]); - fillBuffers(*stream); - } + Table *t = createTableFromStream(100, *stream); if (dispose) delete stream; diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp new file mode 100644 index 0000000000..7862a4a0c6 --- /dev/null +++ b/engines/parallaction/exec_br.cpp @@ -0,0 +1,588 @@ + +#include "common/stdafx.h" +#include "parallaction/parallaction.h" + +namespace Parallaction { + +#define INST_ON 1 +#define INST_OFF 2 +#define INST_X 3 +#define INST_Y 4 +#define INST_Z 5 +#define INST_F 6 +#define INST_LOOP 7 +#define INST_ENDLOOP 8 +#define INST_SHOW 9 +#define INST_INC 10 +#define INST_DEC 11 +#define INST_SET 12 +#define INST_PUT 13 +#define INST_CALL 14 +#define INST_WAIT 15 +#define INST_START 16 +#define INST_PROCESS 17 +#define INST_MOVE 18 +#define INST_COLOR 19 +#define INST_SOUND 20 +#define INST_MASK 21 +#define INST_PRINT 22 +#define INST_TEXT 23 +#define INST_MUL 24 +#define INST_DIV 25 +#define INST_IFEQ 26 +#define INST_IFLT 27 +#define INST_IFGT 28 +#define INST_ENDIF 29 +#define INST_STOP 30 +#define INST_ENDSCRIPT 31 + + + +typedef OpcodeImpl<Parallaction_br> OpcodeV2; +#define COMMAND_OPCODE(op) OpcodeV2(this, &Parallaction_br::cmdOp_##op) +#define DECLARE_COMMAND_OPCODE(op) void Parallaction_br::cmdOp_##op() + +#define INSTRUCTION_OPCODE(op) OpcodeV2(this, &Parallaction_br::instOp_##op) +#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_br::instOp_##op() + +void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { + debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y); + + if (!scumm_stricmp("clear", s)) { + + removeJob(_jDisplaySubtitle); + addJob(kJobWaitRemoveSubtitleJob, _jEraseSubtitle, 15); + _jDisplaySubtitle = 0; + + _subtitle0.free(); + _subtitle1.free(); + return; + } + + _subtitle0.free(); + _subtitle1.free(); + + renderLabel(&_subtitle0._cnv, s); + _subtitle0._text = strdup(s); + + if (s2) { + renderLabel(&_subtitle1._cnv, s2); + _subtitle1._text = strdup(s2); + } + + _subtitleLipSync = 0; + + if (y != -1) { + _subtitle0._pos.y = y; + _subtitle1._pos.y = y + 5 + _labelFont->height(); + } + + _subtitle0._pos.x = (_gfx->_screenX << 2) + ((640 - _subtitle0._cnv.w) >> 1); + if (_subtitle1._text) + _subtitle1._pos.x = (_gfx->_screenX << 2) + ((640 - _subtitle1._cnv.w) >> 1); + + if (_jDisplaySubtitle == 0) { + _subtitle0._old.x = -1000; + _subtitle0._old.y = -1000; + _jDisplaySubtitle = addJob(kJobDisplaySubtitle, 0, 1); + _jEraseSubtitle = addJob(kJobEraseSubtitle, 0, 20); + } +} + + + +DECLARE_COMMAND_OPCODE(location) { + warning("Parallaction_br::cmdOp_location command not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(open) { + warning("Parallaction_br::cmdOp_open command not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(close) { + warning("Parallaction_br::cmdOp_close not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(on) { + warning("Parallaction_br::cmdOp_on not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(off) { + warning("Parallaction_br::cmdOp_off not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(call) { + callFunction(_cmdRunCtxt.cmd->u._callable, _cmdRunCtxt.z); +} + + +DECLARE_COMMAND_OPCODE(drop) { + warning("Parallaction_br::cmdOp_drop not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(move) { + warning("Parallaction_br::cmdOp_move not yet implemented"); +} + +DECLARE_COMMAND_OPCODE(start) { + warning("Parallaction_br::cmdOp_start not yet implemented"); +} + +DECLARE_COMMAND_OPCODE(stop) { + warning("Parallaction_br::cmdOp_stop not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(character) { + warning("Parallaction_br::cmdOp_character not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(followme) { + warning("Parallaction_br::cmdOp_followme not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(onmouse) { + showCursor(true); +} + + +DECLARE_COMMAND_OPCODE(offmouse) { + showCursor(false); +} + + +DECLARE_COMMAND_OPCODE(add) { + warning("Parallaction_br::cmdOp_add not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(leave) { + warning("Parallaction_br::cmdOp_leave not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(inc) { + _counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue; +} + + +DECLARE_COMMAND_OPCODE(dec) { + _counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue; +} + + +DECLARE_COMMAND_OPCODE(ifeq) { + if (_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) { + _localFlags[_currentLocationIndex] |= kFlagsTestTrue; + } else { + _localFlags[_currentLocationIndex] &= ~kFlagsTestTrue; + } +} + +DECLARE_COMMAND_OPCODE(iflt) { + if (_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) { + _localFlags[_currentLocationIndex] |= kFlagsTestTrue; + } else { + _localFlags[_currentLocationIndex] &= ~kFlagsTestTrue; + } +} + +DECLARE_COMMAND_OPCODE(ifgt) { + if (_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) { + _localFlags[_currentLocationIndex] |= kFlagsTestTrue; + } else { + _localFlags[_currentLocationIndex] &= ~kFlagsTestTrue; + } +} + + +DECLARE_COMMAND_OPCODE(let) { + _counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue; +} + + +DECLARE_COMMAND_OPCODE(music) { + warning("Parallaction_br::cmdOp_music not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(fix) { + _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsFixed; +} + + +DECLARE_COMMAND_OPCODE(unfix) { + _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; +} + + +DECLARE_COMMAND_OPCODE(zeta) { + _zeta0 = _cmdRunCtxt.cmd->u._zeta0; + _zeta1 = _cmdRunCtxt.cmd->u._zeta1; + _zeta2 = _cmdRunCtxt.cmd->u._zeta2; +} + + +DECLARE_COMMAND_OPCODE(scroll) { + warning("Parallaction_br::cmdOp_scroll not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(swap) { + warning("Parallaction_br::cmdOp_swap not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(give) { + warning("Parallaction_br::cmdOp_give not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(text) { + CommandData *data = &_cmdRunCtxt.cmd->u; + setupSubtitles(data->_string, data->_string2, data->_zeta0); +} + + +DECLARE_COMMAND_OPCODE(part) { + warning("Parallaction_br::cmdOp_part not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(testsfx) { + warning("Parallaction_br::cmdOp_testsfx not completely implemented"); + _localFlags[_currentLocationIndex] &= ~kFlagsTestTrue; // should test if sfx are enabled +} + + +DECLARE_COMMAND_OPCODE(ret) { + warning("Parallaction_br::cmdOp_ret not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(onsave) { + warning("Parallaction_br::cmdOp_onsave not yet implemented"); +} + + +DECLARE_COMMAND_OPCODE(offsave) { + warning("Parallaction_br::cmdOp_offsave not yet implemented"); +} + + + + +DECLARE_INSTRUCTION_OPCODE(on) { + warning("Parallaction_br::instOp_on not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(off) { + warning("Parallaction_br::instOp_off not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(set) { + Instruction *inst = *_instRunCtxt.inst; + + int16 rvalue = inst->_opB.getRValue(); + int16* lvalue = inst->_opA.getLValue(); + + *lvalue = rvalue; + +} + + +DECLARE_INSTRUCTION_OPCODE(loop) { + Instruction *inst = *_instRunCtxt.inst; + + _instRunCtxt.a->_program->_loopCounter = inst->_opB.getRValue(); + _instRunCtxt.a->_program->_loopStart = _instRunCtxt.inst; +} + + +DECLARE_INSTRUCTION_OPCODE(inc) { + Instruction *inst = *_instRunCtxt.inst; + + int16 rvalue = inst->_opB.getRValue(); + + if (inst->_flags & kInstMod) { // mod + int16 _bx = (rvalue > 0 ? rvalue : -rvalue); + if (_instRunCtxt.modCounter % _bx != 0) return; + + rvalue = (rvalue > 0 ? 1 : -1); + } + + int16 *lvalue = inst->_opA.getLValue(); + + switch (inst->_index) { + case INST_INC: + *lvalue += rvalue; + break; + + case INST_DEC: + *lvalue -= rvalue; + break; + + case INST_MUL: + *lvalue *= rvalue; + break; + + case INST_DIV: + *lvalue /= rvalue; + break; + + default: + error("This should never happen. Report immediately");; + } + + if (inst->_opA._flags & kParaLocal) { + wrapLocalVar(inst->_opA._local); + } + +} + + +DECLARE_INSTRUCTION_OPCODE(put) { + warning("Parallaction_br::instOp_put not yet implemented"); +} + + + +DECLARE_INSTRUCTION_OPCODE(wait) { + warning("Parallaction_br::instOp_wait not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(start) { + (*_instRunCtxt.inst)->_z->_flags |= kFlagsActing; +} + + +DECLARE_INSTRUCTION_OPCODE(process) { + _activeZone2 = (*_instRunCtxt.inst)->_z; +} + + +DECLARE_INSTRUCTION_OPCODE(move) { + warning("Parallaction_br::instOp_move not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(color) { + Instruction *inst = *_instRunCtxt.inst; + + int16 entry = inst->_opB.getRValue(); + + _gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]); + +} + + +DECLARE_INSTRUCTION_OPCODE(mask) { + Instruction *inst = *_instRunCtxt.inst; + + _gfx->_bgLayers[0] = inst->_opA.getRValue(); + _gfx->_bgLayers[1] = inst->_opB.getRValue(); + _gfx->_bgLayers[2] = inst->_opC.getRValue(); +} + + +DECLARE_INSTRUCTION_OPCODE(print) { + warning("Parallaction_br::instOp_print not yet implemented"); +} + + + +void Parallaction_br::jobDisplaySubtitle(void *parm, Job *job) { + _gfx->drawLabel(_subtitle0); + _gfx->drawLabel(_subtitle1); +} + +void Parallaction_br::jobEraseSubtitle(void *parm, Job *job) { + Common::Rect r; + + if (_subtitle0._old.x != -1000) { + _subtitle0.getRect(r); + +// printf("sub0: (%i, %i, %i, %i)\n", r.left, r.top, r.right, r.bottom); + + _gfx->restoreBackground(r); + } + _subtitle0._old = _subtitle0._pos; + + if (_subtitle1._old.x != -1000) { + _subtitle0.getRect(r); + +// printf("sub1: (%i, %i, %i, %i)\n", r.left, r.top, r.right, r.bottom); + + _gfx->restoreBackground(r); + } + _subtitle1._old = _subtitle1._pos; +} + +DECLARE_INSTRUCTION_OPCODE(text) { + Instruction *inst = (*_instRunCtxt.inst); + setupSubtitles(inst->_text, inst->_text2, inst->_y); +} + + +DECLARE_INSTRUCTION_OPCODE(ifeq) { + warning("Parallaction_br::instOp_ifeq not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(iflt) { + warning("Parallaction_br::instOp_iflt not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(ifgt) { + warning("Parallaction_br::instOp_ifgt not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(endif) { + warning("Parallaction_br::instOp_endif not yet implemented"); +} + + +DECLARE_INSTRUCTION_OPCODE(stop) { + warning("Parallaction_br::instOp_stop not yet implemented"); +} + +DECLARE_INSTRUCTION_OPCODE(endscript) { + warning("Parallaction_br::instOp_endscript not yet implemented"); +} + +void Parallaction_br::initOpcodes() { + + static const OpcodeV2 op1[] = { + COMMAND_OPCODE(invalid), + COMMAND_OPCODE(set), + COMMAND_OPCODE(clear), + COMMAND_OPCODE(start), + COMMAND_OPCODE(speak), + COMMAND_OPCODE(get), + COMMAND_OPCODE(location), + COMMAND_OPCODE(open), + COMMAND_OPCODE(close), + COMMAND_OPCODE(on), + COMMAND_OPCODE(off), + COMMAND_OPCODE(call), + COMMAND_OPCODE(toggle), + COMMAND_OPCODE(drop), + COMMAND_OPCODE(quit), + COMMAND_OPCODE(move), + COMMAND_OPCODE(stop), + COMMAND_OPCODE(character), + COMMAND_OPCODE(followme), + COMMAND_OPCODE(onmouse), + COMMAND_OPCODE(offmouse), + COMMAND_OPCODE(add), + COMMAND_OPCODE(leave), + COMMAND_OPCODE(inc), + COMMAND_OPCODE(dec), + COMMAND_OPCODE(ifeq), + COMMAND_OPCODE(iflt), + COMMAND_OPCODE(ifgt), + COMMAND_OPCODE(let), + COMMAND_OPCODE(music), + COMMAND_OPCODE(fix), + COMMAND_OPCODE(unfix), + COMMAND_OPCODE(zeta), + COMMAND_OPCODE(scroll), + COMMAND_OPCODE(swap), + COMMAND_OPCODE(give), + COMMAND_OPCODE(text), + COMMAND_OPCODE(part), + COMMAND_OPCODE(testsfx), + COMMAND_OPCODE(ret), + COMMAND_OPCODE(onsave), + COMMAND_OPCODE(offsave) + }; + + uint i; + for (i = 0; i < ARRAYSIZE(op1); i++) + _commandOpcodes.push_back(&op1[i]); + + + static const OpcodeV2 op2[] = { + INSTRUCTION_OPCODE(invalid), + INSTRUCTION_OPCODE(on), + INSTRUCTION_OPCODE(off), + INSTRUCTION_OPCODE(set), // x + INSTRUCTION_OPCODE(set), // y + INSTRUCTION_OPCODE(set), // z + INSTRUCTION_OPCODE(set), // f + INSTRUCTION_OPCODE(loop), + INSTRUCTION_OPCODE(endloop), + INSTRUCTION_OPCODE(null), // show + INSTRUCTION_OPCODE(inc), + INSTRUCTION_OPCODE(inc), // dec + INSTRUCTION_OPCODE(set), + INSTRUCTION_OPCODE(put), + INSTRUCTION_OPCODE(call), + INSTRUCTION_OPCODE(wait), + INSTRUCTION_OPCODE(start), + INSTRUCTION_OPCODE(process), + INSTRUCTION_OPCODE(move), + INSTRUCTION_OPCODE(color), + INSTRUCTION_OPCODE(process), // sound + INSTRUCTION_OPCODE(mask), + INSTRUCTION_OPCODE(print), + INSTRUCTION_OPCODE(text), + INSTRUCTION_OPCODE(inc), // mul + INSTRUCTION_OPCODE(inc), // div + INSTRUCTION_OPCODE(ifeq), + INSTRUCTION_OPCODE(iflt), + INSTRUCTION_OPCODE(ifgt), + INSTRUCTION_OPCODE(endif), + INSTRUCTION_OPCODE(stop), + INSTRUCTION_OPCODE(endscript) + }; + + for (i = 0; i < ARRAYSIZE(op2); i++) + _instructionOpcodes.push_back(&op2[i]); + + +} + + +void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) { + +} + + +void Parallaction_br::jobWaitRemoveSubtitleJob(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) { + +} + + + + + +} // namespace Parallaction diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp new file mode 100644 index 0000000000..2b88469702 --- /dev/null +++ b/engines/parallaction/exec_ns.cpp @@ -0,0 +1,925 @@ +/* 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/stdafx.h" +#include "parallaction/parallaction.h" +#include "parallaction/sound.h" + + +namespace Parallaction { + +#define INST_ON 1 +#define INST_OFF 2 +#define INST_X 3 +#define INST_Y 4 +#define INST_Z 5 +#define INST_F 6 +#define INST_LOOP 7 +#define INST_ENDLOOP 8 +#define INST_SHOW 9 +#define INST_INC 10 +#define INST_DEC 11 +#define INST_SET 12 +#define INST_PUT 13 +#define INST_CALL 14 +#define INST_WAIT 15 +#define INST_START 16 +#define INST_SOUND 17 +#define INST_MOVE 18 +#define INST_ENDSCRIPT 19 + + +typedef OpcodeImpl<Parallaction_ns> OpcodeV1; +#define COMMAND_OPCODE(op) OpcodeV1(this, &Parallaction_ns::cmdOp_##op) +#define DECLARE_COMMAND_OPCODE(op) void Parallaction_ns::cmdOp_##op() + +#define INSTRUCTION_OPCODE(op) OpcodeV1(this, &Parallaction_ns::instOp_##op) +#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_ns::instOp_##op() + + + + +DECLARE_INSTRUCTION_OPCODE(on) { + Instruction *inst = *_instRunCtxt.inst; + + inst->_a->_flags |= kFlagsActive; + inst->_a->_flags &= ~kFlagsRemove; +} + + +DECLARE_INSTRUCTION_OPCODE(off) { + (*_instRunCtxt.inst)->_a->_flags |= kFlagsRemove; +} + + +DECLARE_INSTRUCTION_OPCODE(loop) { + Instruction *inst = *_instRunCtxt.inst; + + _instRunCtxt.a->_program->_loopCounter = inst->_opB.getRValue(); + _instRunCtxt.a->_program->_loopStart = _instRunCtxt.inst; +} + + +DECLARE_INSTRUCTION_OPCODE(endloop) { + if (--_instRunCtxt.a->_program->_loopCounter > 0) { + _instRunCtxt.inst = _instRunCtxt.a->_program->_loopStart; + } +} + +DECLARE_INSTRUCTION_OPCODE(inc) { + Instruction *inst = *_instRunCtxt.inst; + int16 _si = inst->_opB.getRValue(); + + if (inst->_flags & kInstMod) { // mod + int16 _bx = (_si > 0 ? _si : -_si); + if (_instRunCtxt.modCounter % _bx != 0) return; + + _si = (_si > 0 ? 1 : -1); + } + + int16* lvalue = inst->_opA.getLValue(); + + if (inst->_index == INST_INC) { + *lvalue += _si; + } else { + *lvalue -= _si; + } + + if (inst->_opA._flags & kParaLocal) { + wrapLocalVar(inst->_opA._local); + } + +} + + +DECLARE_INSTRUCTION_OPCODE(set) { + Instruction *inst = *_instRunCtxt.inst; + + int16 _si = inst->_opB.getRValue(); + int16 *lvalue = inst->_opA.getLValue(); + + *lvalue = _si; + +} + + +DECLARE_INSTRUCTION_OPCODE(put) { + Instruction *inst = *_instRunCtxt.inst; + Graphics::Surface v18; + v18.w = inst->_a->width(); + v18.h = inst->_a->height(); + v18.pixels = inst->_a->getFrameData(inst->_a->_frame); + + int16 x = inst->_opA.getRValue(); + int16 y = inst->_opB.getRValue(); + + if (inst->_flags & kInstMaskedPut) { + uint16 z = _gfx->queryMask(y); + _gfx->blitCnv(&v18, x, y, z, Gfx::kBitBack); + _gfx->blitCnv(&v18, x, y, z, Gfx::kBit2); + } else { + _gfx->flatBlitCnv(&v18, x, y, Gfx::kBitBack); + _gfx->flatBlitCnv(&v18, x, y, Gfx::kBit2); + } +} + +DECLARE_INSTRUCTION_OPCODE(null) { + +} + +DECLARE_INSTRUCTION_OPCODE(invalid) { + error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index); +} + +DECLARE_INSTRUCTION_OPCODE(call) { + callFunction((*_instRunCtxt.inst)->_immediate, 0); +} + + +DECLARE_INSTRUCTION_OPCODE(wait) { + if (_engineFlags & kEngineWalking) + _instRunCtxt.suspend = true; +} + + +DECLARE_INSTRUCTION_OPCODE(start) { + (*_instRunCtxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive); +} + + +DECLARE_INSTRUCTION_OPCODE(sound) { + _activeZone = (*_instRunCtxt.inst)->_z; +} + + +DECLARE_INSTRUCTION_OPCODE(move) { + Instruction *inst = (*_instRunCtxt.inst); + + int16 x = inst->_opA.getRValue(); + int16 y = inst->_opB.getRValue(); + + WalkNodeList *v4 = _char._builder.buildPath(x, y); + addJob(kJobWalk, v4, kPriority19 ); + _engineFlags |= kEngineWalking; +} + +DECLARE_INSTRUCTION_OPCODE(endscript) { + if ((_instRunCtxt.a->_flags & kFlagsLooping) == 0) { + _instRunCtxt.a->_flags &= ~kFlagsActing; + runCommands(_instRunCtxt.a->_commands, _instRunCtxt.a); + } + _instRunCtxt.a->_program->_ip = _instRunCtxt.a->_program->_instructions.begin(); + + _instRunCtxt.suspend = true; +} + + + +void Parallaction_ns::wrapLocalVar(LocalVariable *local) { + + if (local->_value >= local->_max) + local->_value = local->_min; + if (local->_value < local->_min) + local->_value = local->_max - 1; + + return; +} + + +DECLARE_COMMAND_OPCODE(invalid) { + error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id); +} + +DECLARE_COMMAND_OPCODE(set) { + if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { + _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags |= _cmdRunCtxt.cmd->u._flags; + } else { + _localFlags[_currentLocationIndex] |= _cmdRunCtxt.cmd->u._flags; + } +} + + +DECLARE_COMMAND_OPCODE(clear) { + if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { + _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags &= ~_cmdRunCtxt.cmd->u._flags; + } else { + _localFlags[_currentLocationIndex] &= ~_cmdRunCtxt.cmd->u._flags; + } +} + + +DECLARE_COMMAND_OPCODE(start) { + _cmdRunCtxt.cmd->u._animation->_flags |= kFlagsActing; +} + + +DECLARE_COMMAND_OPCODE(speak) { + _activeZone = _cmdRunCtxt.cmd->u._zone; +} + + +DECLARE_COMMAND_OPCODE(get) { + _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; + if (!runZone(_cmdRunCtxt.cmd->u._zone)) { + runCommands(_cmdRunCtxt.cmd->u._zone->_commands); + } +} + + +DECLARE_COMMAND_OPCODE(location) { + strcpy(_location._name, _cmdRunCtxt.cmd->u._string); + _engineFlags |= kEngineChangeLocation; +} + + +DECLARE_COMMAND_OPCODE(open) { + _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed; + if (_cmdRunCtxt.cmd->u._zone->u.door->_cnv) { + addJob(kJobToggleDoor, (void*)_cmdRunCtxt.cmd->u._zone, kPriority18 ); + } +} + + +DECLARE_COMMAND_OPCODE(close) { + _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed; + if (_cmdRunCtxt.cmd->u._zone->u.door->_cnv) { + addJob(kJobToggleDoor, (void*)_cmdRunCtxt.cmd->u._zone, kPriority18 ); + } +} + + +DECLARE_COMMAND_OPCODE(on) { + // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing + // the pointer to get structure members, thus leading to crashes in systems with memory + // protection. + // As a side note, the overwritten address is the 5th entry in the DOS interrupt table + // (print screen handler): this suggests that a system would hang when the print screen + // key is pressed after playing Nippon Safes, provided that this code path is taken. + if (_cmdRunCtxt.cmd->u._zone != NULL) { + _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsRemove; + _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActive; + if ((_cmdRunCtxt.cmd->u._zone->_type & 0xFFFF) == kZoneGet) { + addJob(kJobDisplayDroppedItem, _cmdRunCtxt.cmd->u._zone, kPriority17 ); + } + } +} + + +DECLARE_COMMAND_OPCODE(off) { + _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove; +} + + +DECLARE_COMMAND_OPCODE(call) { + callFunction(_cmdRunCtxt.cmd->u._callable, _cmdRunCtxt.z); +} + + +DECLARE_COMMAND_OPCODE(toggle) { + if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { + _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags ^= _cmdRunCtxt.cmd->u._flags; + } else { + _localFlags[_currentLocationIndex] ^= _cmdRunCtxt.cmd->u._flags; + } +} + + +DECLARE_COMMAND_OPCODE(drop){ + dropItem( _cmdRunCtxt.cmd->u._object ); +} + + +DECLARE_COMMAND_OPCODE(quit) { + _engineFlags |= kEngineQuit; +} + + +DECLARE_COMMAND_OPCODE(move) { + if ((_char._ani._flags & kFlagsRemove) || (_char._ani._flags & kFlagsActive) == 0) { + return; + } + + WalkNodeList *vC = _char._builder.buildPath(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y); + + addJob(kJobWalk, vC, kPriority19 ); + _engineFlags |= kEngineWalking; +} + + +DECLARE_COMMAND_OPCODE(stop) { + _cmdRunCtxt.cmd->u._animation->_flags &= ~kFlagsActing; +} + + +void Parallaction_ns::jobDisplayAnimations(void *parm, Job *j) { + + Graphics::Surface v14; + + uint16 _si = 0; + + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) { + + Animation *v18 = *it; + + if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) { + v14.w = v18->width(); + v14.h = v18->height(); + + int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1); + + v14.pixels = v18->getFrameData(frame); + + if (v18->_flags & kFlagsNoMasked) + _si = 3; + else + _si = _gfx->queryMask(v18->_top + v18->height()); + + debugC(9, kDebugExec, "jobDisplayAnimations(%s, x:%i, y:%i, z:%i, w:%i, h:%i, f:%i/%i, %p)", v18->_label._text, v18->_left, v18->_top, _si, v14.w, v14.h, + frame, v18->getFrameNum(), v14.pixels); + _gfx->blitCnv(&v14, v18->_left, v18->_top, _si, Gfx::kBitBack); + + } + + if (((v18->_flags & kFlagsActive) == 0) && (v18->_flags & kFlagsRemove)) { + v18->_flags &= ~kFlagsRemove; + v18->_oldPos.x = -1000; + } + + if ((v18->_flags & kFlagsActive) && (v18->_flags & kFlagsRemove)) { + v18->_flags &= ~kFlagsActive; + v18->_flags |= kFlagsRemove; + } + } + + return; +} + + +void Parallaction_ns::jobEraseAnimations(void *arg_0, Job *j) { + debugC(9, kDebugExec, "jobEraseAnimations"); + + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) { + + Animation *a = *it; + + if (((a->_flags & kFlagsActive) == 0) && ((a->_flags & kFlagsRemove) == 0)) continue; + + Common::Rect r(a->width(), a->height()); + r.moveTo(a->_oldPos); + _gfx->restoreBackground(r); + + if (arg_0) { + a->_oldPos.x = a->_left; + a->_oldPos.y = a->_top; + } + + } + + return; +} + + +void Parallaction_ns::jobRunScripts(void *parm, Job *j) { + debugC(9, kDebugExec, "jobRunScripts"); + + static uint16 modCounter = 0; + + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) { + + Animation *a = *it; + + if (a->_flags & kFlagsCharacter) + a->_z = a->_top + a->height(); + + if ((a->_flags & kFlagsActing) == 0) + continue; + + InstructionList::iterator inst = a->_program->_ip; + while (((*inst)->_index != INST_SHOW) && (a->_flags & kFlagsActing)) { + + debugC(9, kDebugExec, "Animation: %s, instruction: %s", a->_label._text, _instructionNamesRes[(*inst)->_index - 1]); + + _instRunCtxt.inst = inst; + _instRunCtxt.a = a; + _instRunCtxt.modCounter = modCounter; + _instRunCtxt.suspend = false; + + (*_instructionOpcodes[(*inst)->_index])(); + + inst = _instRunCtxt.inst; // handles endloop correctly + + if (_instRunCtxt.suspend) + goto label1; + + inst++; + } + + a->_program->_ip = ++inst; + +label1: + if (a->_flags & kFlagsCharacter) + a->_z = a->_top + a->height(); + } + + sortAnimations(); + modCounter++; + + return; +} + + +void Parallaction::runCommands(CommandList& list, Zone *z) { + debugC(3, kDebugExec, "runCommands"); + + CommandList::iterator it = list.begin(); + for ( ; it != list.end(); it++) { + + Command *cmd = *it; + uint32 v8 = _localFlags[_currentLocationIndex]; + + if (_engineFlags & kEngineQuit) + break; + + if (cmd->_flagsOn & kFlagsGlobal) { + v8 = _commandFlags | kFlagsGlobal; + } + + if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue; + if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue; + + debugC(3, kDebugExec, "runCommands[%i]: %s (on: %x, off: %x)", cmd->_id, _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff); + + _cmdRunCtxt.z = z; + _cmdRunCtxt.cmd = cmd; + + (*_commandOpcodes[cmd->_id])(); + } + + debugC(3, kDebugExec, "runCommands completed"); + + return; + +} + + + + +// displays character head commenting an examined object +// +// works on the frontbuffer +// +void Parallaction::displayCharacterComment(ExamineData *data) { + if (data->_description == NULL) return; + + // NOTE: saving visible screen before displaying comment allows + // to restore the exact situation after the comment is deleted. + // This means animations are restored in the exact position as + // they were, thus avoiding clipping effect as signalled in + // BUG item #1762614. + _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); + + _gfx->setFont(_dialogueFont); + _gfx->flatBlitCnv(_char._talk, 0, 190, 80, Gfx::kBitFront); + + int16 v26, v28; + _gfx->getStringExtent(data->_description, 130, &v28, &v26); + Common::Rect r(v28, v26); + r.moveTo(140, 10); + _gfx->drawBalloon(r, 0); + _gfx->displayWrappedString(data->_description, 140, 10, 0, 130); + + waitUntilLeftClick(); + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->updateScreen(); + + return; +} + +// +// ZONE TYPE: EXAMINE +// + +// display detail view of an item (and eventually comments) +// +// works on the frontbuffer +// + +void Parallaction::displayItemComment(ExamineData *data) { + + if (data->_description == NULL) return; + + _gfx->setHalfbriteMode(true); + + char v68[PATH_LEN]; + strcpy(v68, data->_filename); + data->_cnv = _disk->loadStatic(v68); + _gfx->flatBlitCnv(data->_cnv, 140, (_screenHeight - data->_cnv->h)/2, Gfx::kBitFront); + delete data->_cnv; + + int16 v6A = 0, v6C = 0; + + _gfx->setFont(_dialogueFont); + _gfx->getStringExtent(data->_description, 130, &v6C, &v6A); + Common::Rect r(v6C, v6A); + r.moveTo(0, 90); + _gfx->drawBalloon(r, 0); + _gfx->flatBlitCnv(_char._head, 100, 152, Gfx::kBitFront); + _gfx->displayWrappedString(data->_description, 0, 90, 0, 130); + + jobEraseAnimations((void*)1, NULL); + _gfx->updateScreen(); + + waitUntilLeftClick(); + + _gfx->setHalfbriteMode(false); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->updateScreen(); + + return; +} + + + +uint16 Parallaction::runZone(Zone *z) { + debugC(3, kDebugExec, "runZone (%s)", z->_label._text); + + uint16 subtype = z->_type & 0xFFFF; + + debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); + switch(subtype) { + + case kZoneExamine: + if (z->u.examine->_filename) { + displayItemComment(z->u.examine); + } else { + displayCharacterComment(z->u.examine); + } + break; + + case kZoneGet: + if (z->_flags & kFlagsFixed) break; + if (pickupItem(z) != 0) { + return 1; + } + z->_flags |= kFlagsRemove; + break; + + case kZoneDoor: + if (z->_flags & kFlagsLocked) break; + z->_flags ^= kFlagsClosed; + if (z->u.door->_cnv == NULL) break; + addJob(kJobToggleDoor, z, kPriority18 ); + break; + + case kZoneHear: + _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); + break; + + case kZoneSpeak: + runDialogue(z->u.speak); + break; + + } + + debugC(3, kDebugExec, "runZone completed"); + + return 0; +} + +// +// ZONE TYPE: DOOR +// +void Parallaction_ns::jobToggleDoor(void *parm, Job *j) { + + static byte count = 0; + + Zone *z = (Zone*)parm; + + if (z->u.door->_cnv) { + Common::Rect r; + z->u.door->_cnv->getRect(0, r); + r.moveTo(z->_left, z->_top); + + uint16 _ax = (z->_flags & kFlagsClosed ? 1 : 0); + _gfx->restoreDoorBackground(r, z->u.door->_cnv->getData(_ax), z->u.door->_background); + + _ax = (z->_flags & kFlagsClosed ? 0 : 1); + _gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); + _gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBit2); + } + + count++; + if (count == 2) { + j->_finished = 1; + count = 0; + } + + return; +} + + + +// +// ZONE TYPE: GET +// + +int16 Parallaction::pickupItem(Zone *z) { + int r = addInventoryItem(z->u.get->_icon); + if (r == 0) + addJob(kJobRemovePickedItem, z, kPriority17 ); + + return r; +} + +void Parallaction_ns::jobRemovePickedItem(void *parm, Job *j) { + + Zone *z = (Zone*)parm; + + static uint16 count = 0; + + if (z->u.get->_cnv) { + Common::Rect r(z->_left, z->_top, z->_left + z->u.get->_cnv->w, z->_top + z->u.get->_cnv->h); + + _gfx->restoreGetBackground(r, z->u.get->_backup); + } + + count++; + if (count == 2) { + count = 0; + j->_finished = 1; + } + + return; +} + +void Parallaction_ns::jobDisplayDroppedItem(void *parm, Job *j) { +// printf("jobDisplayDroppedItem..."); + + Zone *z = (Zone*)parm; + + if (z->u.get->_cnv) { + if (j->_count == 0) { + _gfx->backupGetBackground(z->u.get, z->_left, z->_top); + } + + _gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBitBack); + _gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBit2); + } + + j->_count++; + if (j->_count == 2) { + j->_count = 0; + j->_finished = 1; + } + +// printf("done"); + + return; +} + + + + +Zone *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 = _zones.begin(); it != _zones.end(); it++) { +// printf("Zone name: %s", z->_name); + + Zone *z = *it; + + if (z->_flags & kFlagsRemove) continue; + + Common::Rect r; + z->getRect(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->_left == -2) || (z->_left == -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->_left != -1) + continue; + if (_si < _char._ani._left) + continue; + if (_si > (_char._ani._left + _char._ani.width())) + continue; + if (_di < _char._ani._top) + continue; + if (_di > (_char._ani._top + _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 it = _animations.begin(); it != _animations.end(); it++) { + + Animation *a = *it; + + _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation + _e = ((_si >= a->_left + a->width()) || (_si <= a->_left)) ? 0 : 1; // _e: horizontal range + _f = ((_di >= a->_top + a->height()) || (_di <= a->_top)) ? 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 NULL; +} + + +void Parallaction_ns::initOpcodes() { + + static const OpcodeV1 op1[] = { + INSTRUCTION_OPCODE(invalid), + INSTRUCTION_OPCODE(on), + INSTRUCTION_OPCODE(off), + INSTRUCTION_OPCODE(set), // x + INSTRUCTION_OPCODE(set), // y + INSTRUCTION_OPCODE(set), // z + INSTRUCTION_OPCODE(set), // f + INSTRUCTION_OPCODE(loop), + INSTRUCTION_OPCODE(endloop), + INSTRUCTION_OPCODE(null), + INSTRUCTION_OPCODE(inc), + INSTRUCTION_OPCODE(inc), // dec + INSTRUCTION_OPCODE(set), + INSTRUCTION_OPCODE(put), + INSTRUCTION_OPCODE(call), + INSTRUCTION_OPCODE(wait), + INSTRUCTION_OPCODE(start), + INSTRUCTION_OPCODE(sound), + INSTRUCTION_OPCODE(move), + INSTRUCTION_OPCODE(endscript) + }; + + uint i; + for (i = 0; i < ARRAYSIZE(op1); i++) + _instructionOpcodes.push_back(&op1[i]); + + static const OpcodeV1 op3[] = { + COMMAND_OPCODE(invalid), + COMMAND_OPCODE(set), + COMMAND_OPCODE(clear), + COMMAND_OPCODE(start), + COMMAND_OPCODE(speak), + COMMAND_OPCODE(get), + COMMAND_OPCODE(location), + COMMAND_OPCODE(open), + COMMAND_OPCODE(close), + COMMAND_OPCODE(on), + COMMAND_OPCODE(off), + COMMAND_OPCODE(call), + COMMAND_OPCODE(toggle), + COMMAND_OPCODE(drop), + COMMAND_OPCODE(quit), + COMMAND_OPCODE(move), + COMMAND_OPCODE(stop) + }; + + for (i = 0; i < ARRAYSIZE(op3); i++) + _commandOpcodes.push_back(&op3[i]); + +} + + + +void Parallaction_ns::jobDisplayLabel(void *parm, Job *j) { + + Label *label = (Label*)parm; + debugC(9, kDebugExec, "jobDisplayLabel (%p)", (const void*) label); + + _gfx->drawLabel(*label); + + return; +} + +void Parallaction_ns::jobEraseLabel(void *parm, Job *j) { + Label *label = (Label*)parm; + + debugC(9, kDebugExec, "jobEraseLabel (%p)", (const void*) label); + + int16 _si, _di; + + if (_activeItem._id != 0) { + _si = _mousePos.x + 16 - label->_cnv.w/2; + _di = _mousePos.y + 34; + } else { + _si = _mousePos.x + 8 - label->_cnv.w/2; + _di = _mousePos.y + 21; + } + + if (_si < 0) _si = 0; + if (_di > 190) _di = 190; + + if (label->_cnv.w + _si > _screenWidth) + _si = _screenWidth - label->_cnv.w; + + Common::Rect r; + label->getRect(r, true); + _gfx->restoreBackground(r); + + label->_old = label->_pos; + label->_pos.x = _si; + label->_pos.y = _di; + + return; +} + + + +// this Job uses a static counter to delay removal +// and is in fact only used to remove jEraseLabel jobs +// +void Parallaction_ns::jobWaitRemoveJob(void *parm, Job *j) { + Job *arg = (Job*)parm; + + static uint16 count = 0; + + debugC(9, kDebugExec, "jobWaitRemoveJob: count = %i", count); + + _engineFlags |= kEngineBlockInput; + + count++; + if (count == 2) { + count = 0; + removeJob(arg); + _engineFlags &= ~kEngineBlockInput; + j->_finished = 1; + } + + return; +} + + + +} // namespace Parallaction diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index 13e94a4cda..afa00f81af 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/parallaction/font.cpp $ - * $Id:font.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -34,6 +34,146 @@ namespace Parallaction { extern byte _amigaTopazFont[]; +class BraFont : public Font { + + byte *_cp; + uint _bufPitch; + + uint32 _height; + byte _numGlyphs; + + byte *_widths; + uint *_offsets; + + byte *_data; + + static byte _charMap[]; + + byte mapChar(byte c) { + return _charMap[c]; + } + +public: + BraFont(Common::ReadStream &stream) { + + _numGlyphs = stream.readByte(); + _height = stream.readUint32BE(); + + _widths = (byte*)malloc(_numGlyphs); + stream.read(_widths, _numGlyphs); + + _offsets = (uint*)malloc(_numGlyphs * sizeof(uint)); + _offsets[0] = 0; + for (uint i = 1; i < _numGlyphs; i++) + _offsets[i] = _offsets[i-1] + _widths[i-1] * _height; + + uint size = _offsets[_numGlyphs-1] + _widths[_numGlyphs-1] * _height; + + _data = (byte*)malloc(size); + stream.read(_data, size); + + } + + ~BraFont() { + free(_widths); + free(_offsets); + free(_data); + } + + + uint32 getStringWidth(const char *s) { + uint32 len = 0; + + while (*s) { + byte c = mapChar(*s); + len += (_widths[c] + 2); + s++; + } + + return len; + } + + uint16 height() { + return (uint16)_height; + } + + uint16 drawChar(char c) { + assert(c < _numGlyphs); + + byte *src = _data + _offsets[c]; + byte *dst = _cp; + uint16 w = _widths[c]; + + for (uint16 j = 0; j < height(); j++) { + for (uint16 k = 0; k < w; k++) { + + if (*src) { + *dst = (_color) ? _color : *src; + } + + dst++; + src++; + } + + dst += (_bufPitch - w); + } + + return w + 2; + + } + + void drawString(byte* buffer, uint32 pitch, const char *s) { + if (s == NULL) + return; + + _bufPitch = pitch; + + _cp = buffer; + while (*s) { + byte c = mapChar(*s); + _cp += drawChar(c); + s++; + } + } + +}; + +byte BraFont::_charMap[] = { +// 0 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// 1 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// 2 + 0x34, 0x49, 0x48, 0x34, 0x34, 0x34, 0x34, 0x47, 0x34, 0x34, 0x34, 0x34, 0x40, 0x34, 0x3F, 0x34, +// 3 + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x46, 0x45, 0x34, 0x34, 0x34, 0x42, +// 4 + 0x34, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, +// 5 + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x34, 0x34, 0x34, 0x34, 0x34, +// 6 + 0x34, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, +// 7 + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, +// 8 + 0x5E, 0x5D, 0x4E, 0x4B, 0x4D, 0x4C, 0x34, 0x5E, 0x4F, 0x51, 0x50, 0x34, 0x34, 0x34, 0x34, 0x34, +// 9 + 0x34, 0x34, 0x34, 0x57, 0x59, 0x58, 0x5B, 0x5C, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// A + 0x4A, 0x52, 0x34, 0x5A, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// B + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// C + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// D + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// E + 0x34, 0x5F, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// F + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 +}; + + class DosFont : public Font { protected: @@ -430,19 +570,22 @@ Font *AmigaDisk_ns::createFont(const char *name, Common::SeekableReadStream &str return new AmigaFont(stream); } -void Gfx::initFonts() { +Font *DosDisk_br::createFont(const char *name, Common::ReadStream &stream) { +// printf("DosDisk_br::createFont(%s)\n", name); + return new BraFont(stream); +} - if (_vm->getPlatform() == Common::kPlatformPC) { - _fonts[kFontDialogue] = _vm->_disk->loadFont("comic"); - _fonts[kFontLabel] = _vm->_disk->loadFont("topaz"); - _fonts[kFontMenu] = _vm->_disk->loadFont("slide"); - } else { - _fonts[kFontDialogue] = _vm->_disk->loadFont("comic"); +void Parallaction_ns::initFonts() { + if (getPlatform() == Common::kPlatformPC) { + _dialogueFont = _disk->loadFont("comic"); + _labelFont = _disk->loadFont("topaz"); + _menuFont = _disk->loadFont("slide"); + } else { + _dialogueFont = _disk->loadFont("comic"); Common::MemoryReadStream stream(_amigaTopazFont, 2600, false); - _fonts[kFontLabel] = new AmigaFont(stream); - - _fonts[kFontMenu] = _vm->_disk->loadFont("slide"); + _labelFont = new AmigaFont(stream); + _menuFont = _disk->loadFont("slide"); } } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 8d45c4aaa9..6a8ef0718b 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -32,12 +32,147 @@ namespace Parallaction { -byte * Gfx::_buffers[]; -#define BALLOON_WIDTH 12 -#define BALLOON_HEIGHT 10 -byte _resBalloon[2][BALLOON_WIDTH*BALLOON_HEIGHT] = { +Palette::Palette() { + + int gameType = _vm->getGameType(); + + if (gameType == GType_Nippon) { + _colors = 32; + _hb = (_vm->getPlatform() == Common::kPlatformAmiga); + } else + if (gameType == GType_BRA) { + _colors = 256; + _hb = false; + } else + error("can't create palette for id = '%i'", gameType); + + _size = _colors * 3; + + makeBlack(); +} + +Palette::Palette(const Palette &pal) { + clone(pal); +} + +void Palette::clone(const Palette &pal) { + _colors = pal._colors; + _hb = pal._hb; + _size = pal._size; + memcpy(_data, pal._data, _size); +} + + +void Palette::makeBlack() { + memset(_data, 0, _size); +} + +void Palette::setEntry(uint index, int red, int green, int blue) { + assert(index < _colors); + + if (red >= 0) + _data[index*3] = red & 0xFF; + + if (green >= 0) + _data[index*3+1] = green & 0xFF; + + if (blue >= 0) + _data[index*3+2] = blue & 0xFF; +} + +void Palette::makeGrayscale() { + byte v; + for (uint16 i = 0; i < _colors; i++) { + v = MAX(_data[i*3+1], _data[i*3+2]); + v = MAX(v, _data[i*3]); + setEntry(i, v, v, v); + } +} + +void Palette::fadeTo(const Palette& target, uint step) { + + if (step == 0) + return; + + for (uint16 i = 0; i < _size; i++) { + if (_data[i] == target._data[i]) continue; + + if (_data[i] < target._data[i]) + _data[i] = CLIP(_data[i] + step, (uint)0, (uint)target._data[i]); + else + _data[i] = CLIP(_data[i] - step, (uint)target._data[i], (uint)255); + } + + return; +} + +uint Palette::fillRGBA(byte *rgba) { + + byte r, g, b; + byte *hbPal = rgba + _size; + + for (uint32 i = 0; i < _colors; i++) { + r = (_data[i*3] << 2) | (_data[i*3] >> 4); + g = (_data[i*3+1] << 2) | (_data[i*3+1] >> 4); + b = (_data[i*3+2] << 2) | (_data[i*3+2] >> 4); + + rgba[i*4] = r; + rgba[i*4+1] = g; + rgba[i*4+2] = b; + rgba[i*4+3] = 0; + + if (_hb) { + hbPal[i*4] = r >> 1; + hbPal[i*4+1] = g >> 1; + hbPal[i*4+2] = b >> 1; + hbPal[i*4+3] = 0; + } + + } + + return ((_hb) ? 2 : 1) * _colors; +} + +void Palette::rotate(uint first, uint last, bool forward) { + + byte tmp[3]; + + if (forward) { // forward + + tmp[0] = _data[first * 3]; + tmp[1] = _data[first * 3 + 1]; + tmp[2] = _data[first * 3 + 2]; + + memmove(_data+first*3, _data+(first+1)*3, (last - first)*3); + + _data[last * 3] = tmp[0]; + _data[last * 3 + 1] = tmp[1]; + _data[last * 3 + 2] = tmp[2]; + + } else { // backward + + tmp[0] = _data[last * 3]; + tmp[1] = _data[last * 3 + 1]; + tmp[2] = _data[last * 3 + 2]; + + memmove(_data+(first+1)*3, _data+first*3, (last - first)*3); + + _data[first * 3] = tmp[0]; + _data[first * 3 + 1] = tmp[1]; + _data[first * 3 + 2] = tmp[2]; + + } + +} + + +#define BALLOON_TAIL_WIDTH 12 +#define BALLOON_TAIL_HEIGHT 10 + + +byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = { { 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, @@ -69,96 +204,41 @@ void Gfx::drawBalloon(const Common::Rect& r, uint16 winding) { Common::Rect q = r; + // draws balloon q.right += 5; floodFill(kBitFront, q, 0); - - q.left++; - q.top+=2; - q.right--; - q.bottom--; + q.grow(-1); floodFill(kBitFront, q, 1); + // draws tail + // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill. winding = (winding == 0 ? 1 : 0); - byte *s = _resBalloon[winding]; - byte *d = _buffers[kBitFront] + (r.left + (r.width()+5)/2 - 5) + (r.bottom - 1) * _vm->_screenWidth; - - for (uint16 i = 0; i < BALLOON_HEIGHT; i++) { - for (uint16 j = 0; j < BALLOON_WIDTH; j++) { - if (*s != 2) *d = *s; - d++; - s++; - } - - d += (_vm->_screenWidth - BALLOON_WIDTH); - } - -// printf("done\n"); + Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); + s.moveTo(r.left + (r.width()+5)/2 - 5, r.bottom - 1); + flatBlit(s, _resBalloonTail[winding], kBitFront, 2); return; } -void Gfx::setPalette(Palette pal, uint32 first, uint32 num) { -// printf("setPalette(%i, %i)\n", first, num); - - if (first + num > BASE_PALETTE_COLORS) - error("wrong parameters for setPalette()"); - - byte sysBasePal[EHB_PALETTE_COLORS*4]; - byte sysExtraPal[BASE_PALETTE_COLORS*4]; - - byte r, g, b; - uint32 j = 0; - for (uint32 i = first; i < first+num; i++) { - r = (pal[i*3] << 2) | (pal[i*3] >> 4); - g = (pal[i*3+1] << 2) | (pal[i*3+1] >> 4); - b = (pal[i*3+2] << 2) | (pal[i*3+2] >> 4); - - sysBasePal[j*4] = r; - sysBasePal[j*4+1] = g; - sysBasePal[j*4+2] = b; - sysBasePal[j*4+3] = 0; - - if (_vm->getPlatform() == Common::kPlatformAmiga) { - sysExtraPal[j*4] = r >> 1; - sysExtraPal[j*4+1] = g >> 1; - sysExtraPal[j*4+2] = b >> 1; - sysExtraPal[j*4+3] = 0; - } else { - sysExtraPal[j*4] = 0; - sysExtraPal[j*4+1] = 0; - sysExtraPal[j*4+2] = 0; - sysExtraPal[j*4+3] = 0; - } - - j++; - } - - g_system->setPalette(sysBasePal, first, num); - if (_vm->getPlatform() == Common::kPlatformAmiga) - g_system->setPalette(sysExtraPal, first+FIRST_EHB_COLOR, num); -// g_system->updateScreen(); +void Gfx::setPalette(Palette pal) { + byte sysPal[256*4]; - return; + uint n = pal.fillRGBA(sysPal); + g_system->setPalette(sysPal, 0, n); } void Gfx::setBlackPalette() { Palette pal; - memset(pal, 0, PALETTE_SIZE); setPalette(pal); } -// -// palette Animation -// -// FIXME: the effect is different from the original -// -void Gfx::animatePalette() { -// printf("Gfx::animatePalette()\n"); - byte tmp[3]; + + +void Gfx::animatePalette() { for (uint16 i = 0; i < 4; i++) { @@ -170,32 +250,7 @@ void Gfx::animatePalette() { _palettefx[i]._timer = 0; // reset timer - if (_palettefx[i]._flags & 2) { // forward - - tmp[0] = _palette[_palettefx[i]._first * 3]; - tmp[1] = _palette[_palettefx[i]._first * 3 + 1]; - tmp[2] = _palette[_palettefx[i]._first * 3 + 2]; - - memmove(_palette+_palettefx[i]._first*3, _palette+(_palettefx[i]._first+1)*3, (_palettefx[i]._last - _palettefx[i]._first)*3); - - _palette[_palettefx[i]._last * 3] = tmp[0]; - _palette[_palettefx[i]._last * 3 + 1] = tmp[1]; - _palette[_palettefx[i]._last * 3 + 2] = tmp[2]; - - } else { // backward - - tmp[0] = _palette[_palettefx[i]._last * 3]; - tmp[1] = _palette[_palettefx[i]._last * 3 + 1]; - tmp[2] = _palette[_palettefx[i]._last * 3 + 2]; - - memmove(_palette+(_palettefx[i]._first+1)*3, _palette+_palettefx[i]._first*3, (_palettefx[i]._last - _palettefx[i]._first)*3); - - _palette[_palettefx[i]._first * 3] = tmp[0]; - _palette[_palettefx[i]._first * 3 + 1] = tmp[1]; - _palette[_palettefx[i]._first * 3 + 2] = tmp[2]; - - } - + _palette.rotate(_palettefx[i]._first, _palettefx[i]._last, (_palettefx[i]._flags & 2) != 0); } setPalette(_palette); @@ -203,39 +258,9 @@ void Gfx::animatePalette() { return; } -void Gfx::makeGrayscalePalette(Palette pal) { - - for (uint16 i = 0; i < BASE_PALETTE_COLORS; i++) { - byte max; - - max = MAX(_palette[i*3+1], _palette[i*3+2]); - max = MAX(max, _palette[i*3]); - - pal[i*3] = max; - pal[i*3+1] = max; - pal[i*3+2] = max; - } - - return; -} - -void Gfx::fadePalette(Palette pal, Palette target, uint step) { - - if (step == 0) - return; - - for (uint16 i = 0; i < BASE_PALETTE_COLORS * 3; i++) { - if (pal[i] == target[i]) continue; - if (pal[i] < target[i]) - pal[i] = CLIP(pal[i] + step, (uint)0, (uint)target[i]); - else - pal[i] = CLIP(pal[i] - step, (uint)target[i], (uint)255); - } - return; -} void Gfx::setHalfbriteMode(bool enable) { #ifdef HALFBRITE @@ -255,15 +280,14 @@ void Gfx::setHalfbriteMode(bool enable) { } void Gfx::updateScreen() { -// printf("Gfx::updateScreen()\n"); - g_system->copyRectToScreen(_buffers[kBitFront], _vm->_screenWidth, 0, 0, _vm->_screenWidth, _vm->_screenHeight); + g_system->copyRectToScreen((const byte*)_buffers[kBitFront]->pixels, _buffers[kBitFront]->pitch, _screenX, _screenY, _vm->_screenWidth, _vm->_screenHeight); g_system->updateScreen(); return; } void Gfx::swapBuffers() { - byte *temp = _buffers[kBitFront]; + Graphics::Surface *temp = _buffers[kBitFront]; _buffers[kBitFront] = _buffers[kBitBack]; _buffers[kBitBack] = temp; updateScreen(); @@ -275,7 +299,7 @@ void Gfx::swapBuffers() { // graphic primitives // void Gfx::clearScreen(Gfx::Buffers buffer) { - memset(_buffers[buffer], 0, _vm->_screenSize); + memset(_buffers[buffer]->pixels, 0, _vm->_screenSize); if (buffer == kBitFront) updateScreen(); @@ -284,24 +308,21 @@ void Gfx::clearScreen(Gfx::Buffers buffer) { void Gfx::copyScreen(Gfx::Buffers srcbuffer, Gfx::Buffers dstbuffer) { - memcpy(_buffers[dstbuffer], _buffers[srcbuffer], _vm->_screenSize); - -// if (dstbuffer == kBitFront) updateScreen(); + memcpy(_buffers[dstbuffer]->pixels, _buffers[srcbuffer]->pixels, _vm->_screenSize); return; } void Gfx::floodFill(Gfx::Buffers buffer, const Common::Rect& r, byte color) { -// printf("Gfx::floodFill(%i, %i, %i, %i, %i)\n", color, left, top, right, bottom); - byte *d = _buffers[buffer] + (r.left + r.top * _vm->_screenWidth); + byte *d = (byte*)_buffers[buffer]->getBasePtr(r.left, r.top); uint16 w = r.width() + 1; uint16 h = r.height() + 1; for (uint16 i = 0; i < h; i++) { memset(d, color, w); - d += _vm->_screenWidth; + d += _backgroundWidth; } return; @@ -325,7 +346,7 @@ void Gfx::screenClip(Common::Rect& r, Common::Point& p) { } -void Gfx::flatBlit(const Common::Rect& r, byte *data, Gfx::Buffers buffer) { +void Gfx::flatBlit(const Common::Rect& r, byte *data, Gfx::Buffers buffer, byte transparentColor) { Common::Point dp; Common::Rect q(r); @@ -333,17 +354,22 @@ void Gfx::flatBlit(const Common::Rect& r, byte *data, Gfx::Buffers buffer) { screenClip(q, dp); byte *s = data + q.left + q.top * r.width(); - byte *d = _buffers[buffer] + dp.x + dp.y * _vm->_screenWidth; + byte *d = (byte*)_buffers[buffer]->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = _backgroundWidth - q.width(); for (uint16 i = q.top; i < q.bottom; i++) { for (uint16 j = q.left; j < q.right; j++) { - if (*s != 0) *d = *s; + if (*s != transparentColor) + *d = *s; + s++; d++; } - s += (r.width() - q.width()); - d += (_vm->_screenWidth - q.width()); + s += sPitch; + d += dPitch; } return; @@ -358,182 +384,91 @@ void Gfx::blit(const Common::Rect& r, uint16 z, byte *data, Gfx::Buffers buffer) screenClip(q, dp); byte *s = data + q.left + q.top * r.width(); - byte *d = _buffers[buffer] + dp.x + dp.y * _vm->_screenWidth; + byte *d = (byte*)_buffers[buffer]->getBasePtr(dp.x, dp.y); - for (uint16 i = q.top; i < q.bottom; i++) { + uint sPitch = r.width() - q.width(); + uint dPitch = _backgroundWidth - q.width(); - uint16 n = dp.x % 4; - byte *m = _buffers[kMask0] + dp.x/4 + (dp.y + i - q.top)*_vm->_screenMaskWidth; + for (uint16 i = 0; i < q.height(); i++) { - for (uint16 j = q.left; j < q.right; j++) { + for (uint16 j = 0; j < q.width(); j++) { if (*s != 0) { - uint16 v = ((3 << (n << 1)) & *m) >> (n << 1); + byte v = _depthMask->getValue(dp.x + j, dp.y + i); if (z >= v) *d = *s; } - n++; - if (n==4) m++; - n &= 0x3; - s++; d++; } - s += (r.width() - q.right + q.left); - d += (_vm->_screenWidth - q.right + q.left); + s += sPitch; + d += dPitch; } return; } - -void jobDisplayLabel(void *parm, Job *j) { - - Label *label = (Label*)parm; - debugC(9, kDebugJobs, "jobDisplayLabel (%p)", (const void*) label); - - if (label->_cnv._width == 0) +void Gfx::drawLabel(Label &label) { + if (label._text == 0) return; - _vm->_gfx->flatBlitCnv(&label->_cnv, _vm->_gfx->_labelPosition[0].x, _vm->_gfx->_labelPosition[0].y, Gfx::kBitBack); - - return; -} - -void jobEraseLabel(void *parm, Job *j) { - Label *label = (Label*)parm; - - debugC(9, kDebugJobs, "jobEraseLabel (%p)", (const void*) label); - - int16 _si, _di; - - if (_vm->_activeItem._id != 0) { - _si = _vm->_mousePos.x + 16 - label->_cnv._width/2; - _di = _vm->_mousePos.y + 34; - } else { - _si = _vm->_mousePos.x + 8 - label->_cnv._width/2; - _di = _vm->_mousePos.y + 21; - } - - if (_si < 0) _si = 0; - if (_di > 190) _di = 190; - - if (label->_cnv._width + _si > _vm->_screenWidth) - _si = _vm->_screenWidth - label->_cnv._width; - - Common::Rect r(label->_cnv._width, label->_cnv._height); - r.moveTo(_vm->_gfx->_labelPosition[1]); - _vm->_gfx->restoreBackground(r); - - _vm->_gfx->_labelPosition[1] = _vm->_gfx->_labelPosition[0]; - _vm->_gfx->_labelPosition[0].x = _si; - _vm->_gfx->_labelPosition[0].y = _di; - - return; -} - -void Gfx::initMouse(uint16 arg_0) { - - _mouseComposedArrow = _vm->_disk->loadPointer(); - - byte temp[MOUSEARROW_WIDTH*MOUSEARROW_HEIGHT]; - memcpy(temp, _mouseArrow, MOUSEARROW_WIDTH*MOUSEARROW_HEIGHT); - - uint16 k = 0; - for (uint16 i = 0; i < 4; i++) { - for (uint16 j = 0; j < 64; j++) _mouseArrow[k++] = temp[i + j * 4]; - } - - return; -} - - -void Gfx::setMousePointer(int16 index) { - - if (index == kCursorArrow) { // standard mouse pointer - - g_system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); - g_system->showMouse(true); - - } else { - // inventory item pointer - byte *v8 = _mouseComposedArrow->_data0; - // FIXME: destination offseting is not clear - byte* s = _vm->_char._objs->getFramePtr(getInventoryItemIndex(index)); - byte* d = v8 + 7 + MOUSECOMBO_WIDTH * 7; - - for (uint32 i = 0; i < INVENTORYITEM_HEIGHT; i++) { - memcpy(d, s, INVENTORYITEM_WIDTH); - - s += INVENTORYITEM_PITCH; - d += MOUSECOMBO_WIDTH; - } - - g_system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); - } - - return; + flatBlitCnv(&label._cnv, label._pos.x, label._pos.y, Gfx::kBitBack); } - - // // Cnv management // -void Gfx::flatBlitCnv(Cnv *cnv, uint16 frame, int16 x, int16 y, Gfx::Buffers buffer) { +void Gfx::flatBlitCnv(Frames *cnv, uint16 frame, int16 x, int16 y, Gfx::Buffers buffer) { - StaticCnv scnv; + Graphics::Surface scnv; + Common::Rect r; - scnv._width = cnv->_width; - scnv._height = cnv->_height; - scnv._data0 = cnv->getFramePtr(frame); - scnv._data1 = NULL; // _questioner->field_8[v60->_mood & 0xF]; + cnv->getRect(frame, r); + + scnv.w = r.width(); + scnv.h = r.height(); + scnv.pixels = cnv->getData(frame); flatBlitCnv(&scnv, x, y, buffer); } -void Gfx::flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Gfx::Buffers buffer) { - Common::Rect r(cnv->_width, cnv->_height); +void Gfx::flatBlitCnv(Graphics::Surface *cnv, int16 x, int16 y, Gfx::Buffers buffer) { + Common::Rect r(cnv->w, cnv->h); r.moveTo(x, y); - flatBlit(r, cnv->_data0, buffer); + flatBlit(r, (byte*)cnv->pixels, buffer, 0); return; } -void Gfx::blitCnv(StaticCnv *cnv, int16 x, int16 y, uint16 z, Gfx::Buffers buffer) { - Common::Rect r(cnv->_width, cnv->_height); +void Gfx::blitCnv(Graphics::Surface *cnv, int16 x, int16 y, uint16 z, Gfx::Buffers buffer) { + Common::Rect r(cnv->w, cnv->h); r.moveTo(x, y); - blit(r, z, cnv->_data0, buffer); + blit(r, z, (byte*)cnv->pixels, buffer); return; } void Gfx::backupDoorBackground(DoorData *data, int16 x, int16 y) { - - byte *s = _buffers[kBit2] + x + y * _vm->_screenWidth; - byte *d = data->_background; - - for (uint16 i = 0; i < data->_cnv->_height ; i++) { - memcpy(d, s, data->_cnv->_width); - - s += _vm->_screenWidth; - d += data->_cnv->_width; - } - + byte *s = (byte*)_buffers[kBit2]->getBasePtr(x, y); + Common::Rect r; + data->_cnv->getRect(0, r); + copyRect(r.width(), r.height(), data->_background, r.width(), s,_backgroundWidth); return; } void Gfx::backupGetBackground(GetData *data, int16 x, int16 y) { - byte *t = data->_cnv->_data0; - byte *s = _buffers[kBitBack] + x + y * _vm->_screenWidth; + byte *t = (byte*)data->_cnv->pixels; + byte *s = (byte*)_buffers[kBitBack]->getBasePtr(x, y); byte *d = data->_backup; - for (uint16 i = 0; i < data->_cnv->_height ; i++) { - for (uint16 j = 0; j < data->_cnv->_width ; j++) { + uint pitch = _backgroundWidth - data->_cnv->w; + + for (uint16 i = 0; i < data->_cnv->h ; i++) { + for (uint16 j = 0; j < data->_cnv->w ; j++) { *d = (*t) ? *s : 0; d++; @@ -541,7 +476,7 @@ void Gfx::backupGetBackground(GetData *data, int16 x, int16 y) { s++; } - s += (_vm->_screenWidth - data->_cnv->_width); + s += pitch; } return; @@ -550,12 +485,14 @@ void Gfx::backupGetBackground(GetData *data, int16 x, int16 y) { // // restores background according to specified frame // -void Gfx::restoreDoorBackground(StaticCnv *cnv, const Common::Rect& r, byte* background) { +void Gfx::restoreDoorBackground(const Common::Rect& r, byte *data, byte* background) { - byte *t = cnv->_data0; + byte *t = data; byte *s = background; - byte *d0 = _buffers[kBitBack] + r.left + r.top * _vm->_screenWidth; - byte *d1 = _buffers[kBit2] + r.left + r.top * _vm->_screenWidth; + byte *d0 = (byte*)_buffers[kBitBack]->getBasePtr(r.left, r.top); + byte *d1 = (byte*)_buffers[kBit2]->getBasePtr(r.left, r.top); + + uint pitch = _backgroundWidth - r.width(); for (uint16 i = 0; i < r.height() ; i++) { for (uint16 j = 0; j < r.width() ; j++) { @@ -570,8 +507,8 @@ void Gfx::restoreDoorBackground(StaticCnv *cnv, const Common::Rect& r, byte* bac s++; } - d0 += (_vm->_screenWidth - r.width()); - d1 += (_vm->_screenWidth - r.width()); + d0 += pitch; + d1 += pitch; } @@ -584,47 +521,16 @@ void Gfx::restoreDoorBackground(StaticCnv *cnv, const Common::Rect& r, byte* bac // void Gfx::restoreGetBackground(const Common::Rect& r, byte *data) { - StaticCnv cnv; - - cnv._data0 = data; - cnv._data1 = NULL; - cnv._width = r.width(); - cnv._height = r.height(); - - flatBlitCnv(&cnv, r.left, r.top, kBitBack); - flatBlitCnv(&cnv, r.left, r.top, kBit2); + flatBlit(r, data, kBitBack, 0); + flatBlit(r, data, kBit2, 0); return; } -void Gfx::makeCnvFromString(StaticCnv *cnv, char *text) { - assert(_font == _fonts[kFontLabel]); - - if (_vm->getPlatform() == Common::kPlatformAmiga) { - cnv->_width = _font->getStringWidth(text) + 16; - cnv->_height = 10; - cnv->_data0 = (byte*)malloc(cnv->_width * cnv->_height); - memset(cnv->_data0, 0, cnv->_width * cnv->_height); - - _font->setColor(7); - _font->drawString(cnv->_data0 + 1, cnv->_width, text); - _font->drawString(cnv->_data0 + 1 + cnv->_width * 2, cnv->_width, text); - _font->drawString(cnv->_data0 + cnv->_width, cnv->_width, text); - _font->drawString(cnv->_data0 + 2 + cnv->_width, cnv->_width, text); - _font->setColor(1); - _font->drawString(cnv->_data0 + 1 + cnv->_width, cnv->_width, text); - } else { - cnv->_width = _font->getStringWidth(text); - cnv->_height = _font->height(); - cnv->_data0 = (byte*)malloc(cnv->_width * cnv->_height); - memset(cnv->_data0, 0, cnv->_width * cnv->_height); - _font->drawString(cnv->_data0, cnv->_width, text); - } -} void Gfx::displayString(uint16 x, uint16 y, const char *text, byte color) { - byte *dst = _buffers[kBitFront] + x + y*_vm->_screenWidth; + byte *dst = (byte*)_buffers[kBitFront]->getBasePtr(x, y); _font->setColor(color); _font->drawString(dst, _vm->_screenWidth, text); } @@ -635,7 +541,6 @@ void Gfx::displayCenteredString(uint16 y, const char *text) { } bool Gfx::displayWrappedString(char *text, uint16 x, uint16 y, byte color, int16 wrapwidth) { -// printf("Gfx::displayWrappedString(%s, %i, %i, %i, %i)...", text, x, y, color, wrapwidth); uint16 lines = 0; bool rv = false; @@ -676,8 +581,6 @@ bool Gfx::displayWrappedString(char *text, uint16 x, uint16 y, byte color, int16 text = Common::ltrim(text); } -// printf("done\n"); - return rv; } @@ -721,9 +624,9 @@ void Gfx::getStringExtent(char *text, uint16 maxwidth, int16* width, int16* heig } -void Gfx::setFont(Fonts name) { - assert(name < 3); - _font = _fonts[name]; +void Gfx::setFont(Font *font) { + assert(font); + _font = font; } @@ -737,107 +640,55 @@ void Gfx::restoreBackground(const Common::Rect& r) { if (left < 0) left = 0; if (top < 0) top = 0; - if (left >= _vm->_screenWidth) return; - if (top >= _vm->_screenHeight) return; + if (left >= _backgroundWidth) return; + if (top >= _backgroundHeight) return; - if (left+width >= _vm->_screenWidth) width = _vm->_screenWidth - left; - if (top+height >= _vm->_screenHeight) height = _vm->_screenHeight - top; + if (left+width >= _backgroundWidth) width = _backgroundWidth - left; + if (top+height >= _backgroundHeight) height = _backgroundHeight - top; Common::Rect q(width, height); q.moveTo(left, top); - copyRect( - kBitBack, - q, - _buffers[kBit2] + q.left + q.top * _vm->_screenWidth, - _vm->_screenWidth - ); - - return; -} - -void Gfx::freeStaticCnv(StaticCnv *cnv) { -// printf("free_static_cnv()\n"); - - if (!cnv) return; - - if (!cnv || !cnv->_data0) return; - free(cnv->_data0); - cnv->_data0 = NULL; + copyRect(kBitBack, q, (byte*)_buffers[kBit2]->getBasePtr(q.left, q.top), _backgroundWidth); return; } -void Gfx::setBackground(byte *background) { - memcpy(_buffers[kBitBack], background, _vm->_screenSize); - copyScreen(kBitBack, kBit2); -} +void Gfx::setBackground(Graphics::Surface *surface) { + _buffers[kBit2] = surface; -void Gfx::setMask(byte *mask) { - memcpy(_buffers[kMask0], mask, _vm->_screenMaskSize); + initBuffers(surface->w, surface->h); + copyScreen(kBit2, kBitBack); } - - -void Gfx::copyRect(Gfx::Buffers dstbuffer, const Common::Rect& r, byte *src, uint16 pitch) { - - byte *d = _buffers[dstbuffer] + r.left + _vm->_screenWidth * r.top; - byte *s = src; - - for (uint16 _si = 0; _si < r.height(); _si++) { - memcpy(d, s, r.width()); - - s += pitch; - d += _vm->_screenWidth; - } - - +void Gfx::setMask(MaskBuffer *buffer) { + _depthMask = buffer; } +void Gfx::copyRect(uint width, uint height, byte *dst, uint dstPitch, byte *src, uint srcPitch) { -void Gfx::grabRect(byte *dst, const Common::Rect& r, Gfx::Buffers srcbuffer, uint16 pitch) { - - byte *s = _buffers[srcbuffer] + r.left + _vm->_screenWidth * r.top; - - for (uint16 i = 0; i < r.height(); i++) { - memcpy(dst, s, r.width()); + for (uint16 _si = 0; _si < height; _si++) { + memcpy(dst, src, width); - s += _vm->_screenWidth; - dst += pitch; + src += srcPitch; + dst += dstPitch; } return; } -/* - the following 3 routines are hacks for Nippon Safes coming from the original code, - so they shouldn't be modified when adding support for other games -*/ - -void Gfx::plotMaskPixel(uint16 x, uint16 y, byte color) { - - uint16 _ax = x + y * _vm->_screenWidth; - _buffers[kMask0][_ax >> 2] &= ~(3 << ((_ax & 3) << 1)); - +void Gfx::copyRect(Gfx::Buffers dstbuffer, const Common::Rect& r, byte *src, uint16 pitch) { + byte *d = (byte*)_buffers[dstbuffer]->getBasePtr(r.left, r.top); + copyRect(r.width(), r.height(), d, _backgroundWidth, src, pitch); return; } -void Gfx::fillMaskRect(const Common::Rect& r, byte color) { - - uint16 _di = r.left/4 + r.top * _vm->_screenMaskWidth; - - for (uint16 _si = r.top; _si < r.bottom; _si++) { - memset(&_buffers[kMask0][_di], color, r.width()/4+1); - _di += _vm->_screenMaskWidth; - } - return; -} -void Gfx::intGrottaHackMask() { - memset(_buffers[kMask0] + 3600, 0, 3600); - _bgLayers[1] = 500; +void Gfx::grabRect(byte *dst, const Common::Rect& r, Gfx::Buffers srcbuffer, uint16 pitch) { + byte *s = (byte*)_buffers[srcbuffer]->getBasePtr(r.left, r.top); + copyRect(r.width(), r.height(), dst, pitch, s, _backgroundWidth); return; } @@ -856,23 +707,26 @@ Gfx::Gfx(Parallaction* vm) : g_system->beginGFXTransaction(); g_system->initSize(_vm->_screenWidth, _vm->_screenHeight); + _vm->initCommonGFX(_vm->getGameType() == GType_BRA); g_system->endGFXTransaction(); - _buffers[kBitFront] = (byte*)malloc(_vm->_screenSize); - _buffers[kBitBack] = (byte*)malloc(_vm->_screenSize); - _buffers[kBit2] = (byte*)malloc(_vm->_screenSize); - _buffers[kMask0] = (byte*)malloc(_vm->_screenMaskWidth * _vm->_screenHeight); + _buffers[kBit2] = 0; + _depthMask = 0; + + _buffers[kBitFront] = 0; + _buffers[kBitBack] = 0; + + initBuffers(_vm->_screenWidth, _vm->_screenHeight); + + setPalette(_palette); - setBlackPalette(); + _screenX = 0; + _screenY = 0; _bgLayers[0] = _bgLayers[1] = _bgLayers[2] = _bgLayers[3] = 0; - memset(_palette, 0, sizeof(_palette)); memset(_palettefx, 0, sizeof(_palettefx)); - initMouse( 0 ); - initFonts(); - _halfbrite = false; _font = NULL; @@ -882,19 +736,48 @@ Gfx::Gfx(Parallaction* vm) : Gfx::~Gfx() { - free(_buffers[kMask0]); - free(_buffers[kBitFront]); - free(_buffers[kBitBack]); - free(_buffers[kBit2]); + freeBuffers(); - delete _fonts[kFontDialogue]; - delete _fonts[kFontLabel]; - delete _fonts[kFontMenu]; + return; +} - freeStaticCnv(_mouseComposedArrow); - delete _mouseComposedArrow; +void Gfx::initBuffers(int w, int h) { - return; + _backgroundWidth = w; + _backgroundHeight = h; + + if (!_buffers[kBitFront]) { + _buffers[kBitFront] = new Graphics::Surface; + } + + if (!_buffers[kBitBack]) { + _buffers[kBitBack] = new Graphics::Surface; + } + + if (_buffers[kBitFront]->w != w || _buffers[kBitFront]->h != h) { + _buffers[kBitFront]->create(w, h, 1); + } + + if (_buffers[kBitBack]->w != w || _buffers[kBitBack]->h != h) { + _buffers[kBitBack]->create(w, h, 1); + } + +} + +void Gfx::freeBuffers() { + + if (_buffers[kBitFront]) { + _buffers[kBitFront]->free(); + delete _buffers[kBitFront]; + } + + if (_buffers[kBitBack]) { + _buffers[kBitBack]->free(); + delete _buffers[kBitBack]; + } + + _buffers[kBitFront] = 0; + _buffers[kBitBack] = 0; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index f518bd6625..9f1101efa2 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -29,6 +29,7 @@ #include "common/rect.h" #include "common/stream.h" +#include "graphics/surface.h" #include "parallaction/defs.h" @@ -36,25 +37,6 @@ namespace Parallaction { -#define BASE_PALETTE_COLORS 32 -#define FIRST_BASE_COLOR 0 -#define LAST_BASE_COLOR (FIRST_BASE_COLOR+BASE_PALETTE_COLORS-1) - -#define EHB_PALETTE_COLORS 32 // extra half-brite colors for amiga -#define FIRST_EHB_COLOR (LAST_BASE_COLOR+1) -#define LAST_EHB_COLOR (FIRST_EHB_COLOR+EHB_PALETTE_COLORS-1) - -#define PALETTE_COLORS (BASE_PALETTE_COLORS+EHB_PALETTE_COLORS) - -#define BASE_PALETTE_SIZE BASE_PALETTE_COLORS*3 -#define PALETTE_SIZE PALETTE_COLORS*3 - -#define MOUSEARROW_WIDTH 16 -#define MOUSEARROW_HEIGHT 16 - -#define MOUSECOMBO_WIDTH 32 // sizes for cursor + selected inventory item -#define MOUSECOMBO_HEIGHT 32 - #include "common/pack-start.h" // START STRUCT PACKING struct PaletteFxRange { @@ -90,19 +72,19 @@ public: }; -struct StaticCnv { - uint16 _width; // - uint16 _height; // - byte* _data0; // bitmap - byte* _data1; // unused - StaticCnv() { - _width = _height = 0; - _data0 = _data1 = NULL; - } +struct Frames { + + virtual uint16 getNum() = 0; + virtual byte* getData(uint16 index) = 0; + virtual void getRect(uint16 index, Common::Rect &r) = 0; + + virtual ~Frames() { } + }; -struct Cnv { + +struct Cnv : public Frames { uint16 _count; // # of frames uint16 _width; // uint16 _height; // @@ -129,6 +111,21 @@ public: return NULL; return &_data[index * _width * _height]; } + + uint16 getNum() { + return _count; + } + + byte *getData(uint16 index) { + return getFramePtr(index); + } + + void getRect(uint16 index, Common::Rect &r) { + r.left = 0; + r.top = 0; + r.setWidth(_width); + r.setHeight(_height); + } }; @@ -138,31 +135,83 @@ class Parallaction; struct DoorData; struct GetData; +struct Label; + +struct MaskBuffer { + // handles a 2-bit depth buffer used for z-buffering + + uint16 w; + uint16 internalWidth; + uint16 h; + uint size; + byte *data; + +public: + MaskBuffer() : w(0), internalWidth(0), h(0), size(0), data(0) { + } + + void create(uint16 width, uint16 height) { + w = width; + internalWidth = w >> 2; + h = height; + size = (internalWidth * h); + data = (byte*)calloc(size, 1); + } + + void free() { + if (data) + ::free(data); + data = 0; + w = 0; + h = 0; + internalWidth = 0; + size = 0; + } + + inline byte getValue(uint16 x, uint16 y) { + byte m = data[(x >> 2) + y * internalWidth]; + uint n = (x & 3) << 1; + return ((3 << n) & m) >> n; + } -enum Fonts { - kFontDialogue = 0, - kFontLabel = 1, - kFontMenu = 2 }; -class Gfx { +class Palette { + + byte _data[768]; + uint _colors; + uint _size; + bool _hb; public: - typedef byte Palette[PALETTE_SIZE]; + Palette(); + Palette(const Palette &pal); + + void clone(const Palette &pal); + + void makeBlack(); + void setEntries(byte* data, uint first, uint num); + void setEntry(uint index, int red, int green, int blue); + void makeGrayscale(); + void fadeTo(const Palette& target, uint step); + uint fillRGBA(byte *rgba); + + void rotate(uint first, uint last, bool forward); +}; + +class Gfx { +public: enum Buffers { // bit buffers kBitFront, kBitBack, - kBit2, - // mask buffers - kMask0 + kBit2 }; public: - void screenClip(Common::Rect& r, Common::Point& p); - // dialogue and text + // balloons and text void drawBalloon(const Common::Rect& r, uint16 arg_8); void displayString(uint16 x, uint16 y, const char *text, byte color); void displayCenteredString(uint16 y, const char *text); @@ -170,82 +219,73 @@ public: uint16 getStringWidth(const char *text); void getStringExtent(char *text, uint16 maxwidth, int16* width, int16* height); - // cnv management - void makeCnvFromString(StaticCnv *cnv, char *text); - void freeStaticCnv(StaticCnv *cnv); + void drawLabel(Label &label); + + // cut/paste + void flatBlitCnv(Graphics::Surface *cnv, int16 x, int16 y, Gfx::Buffers buffer); + void flatBlitCnv(Frames *cnv, uint16 frame, int16 x, int16 y, Gfx::Buffers buffer); + void blitCnv(Graphics::Surface *cnv, int16 x, int16 y, uint16 z, Gfx::Buffers buffer); + void restoreBackground(const Common::Rect& r); void backupDoorBackground(DoorData *data, int16 x, int16 y); + void restoreDoorBackground(const Common::Rect& r, byte *data, byte* background); void backupGetBackground(GetData *data, int16 x, int16 y); void restoreGetBackground(const Common::Rect& r, byte *data); - void restoreDoorBackground(StaticCnv *cnv, const Common::Rect& r, byte* background); - - // location - void setBackground(byte *background); - void setMask(byte *mask); - int16 queryMask(int16 v); - void intGrottaHackMask(); - void restoreBackground(const Common::Rect& r); - // intro - void fillMaskRect(const Common::Rect& r, byte color); - void plotMaskPixel(uint16 x, uint16 y, byte color); - // low level - void swapBuffers(); - void updateScreen(); + // low level surfaces void clearScreen(Gfx::Buffers buffer); void copyScreen(Gfx::Buffers srcbuffer, Gfx::Buffers dstbuffer); void copyRect(Gfx::Buffers dstbuffer, const Common::Rect& r, byte *src, uint16 pitch); void grabRect(byte *dst, const Common::Rect& r, Gfx::Buffers srcbuffer, uint16 pitch); void floodFill(Gfx::Buffers buffer, const Common::Rect& r, byte color); - // NOTE: flatBlitCnv used to have an additional unused parameter, - // that was always the _data1 member of the StaticCnv parameter. - // DOS version didn't make use of it, but it is probably needed for Amiga stuff. - void flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Gfx::Buffers buffer); - void blitCnv(StaticCnv *cnv, int16 x, int16 y, uint16 z, Gfx::Buffers buffer); - void flatBlitCnv(Cnv *cnv, uint16 frame, int16 x, int16 y, Gfx::Buffers buffer); - - // palette - void setPalette(Palette palette, uint32 first = FIRST_BASE_COLOR, uint32 num = BASE_PALETTE_COLORS); + void setPalette(Palette palette); void setBlackPalette(); void animatePalette(); - void fadePalette(Palette palette, Palette target, uint step); // fades palette to target palette, with specified step - void makeGrayscalePalette(Palette palette); // transform palette into black and white // amiga specific void setHalfbriteMode(bool enable); + // misc + int16 queryMask(int16 v); + void setFont(Font* font); + void swapBuffers(); + void updateScreen(); + void setBackground(Graphics::Surface *surf); + void setMask(MaskBuffer *buffer); + // init Gfx(Parallaction* vm); virtual ~Gfx(); - void setMousePointer(int16 index); - - void initFonts(); - void setFont(Fonts name); public: - Common::Point _labelPosition[2]; uint16 _bgLayers[4]; PaletteFxRange _palettefx[6]; Palette _palette; + int _backgroundWidth; + int _backgroundHeight; + + uint _screenX; // scrolling position + uint _screenY; + protected: Parallaction* _vm; - static byte * _buffers[NUM_BUFFERS]; - static byte _mouseArrow[256]; - StaticCnv *_mouseComposedArrow; + Graphics::Surface *_buffers[NUM_BUFFERS]; + MaskBuffer *_depthMask; Font *_font; - Font *_fonts[3]; bool _halfbrite; protected: - byte mapChar(byte c); - void flatBlit(const Common::Rect& r, byte *data, Gfx::Buffers buffer); + void initBuffers(int w, int h); + void freeBuffers(); + + void copyRect(uint width, uint height, byte *dst, uint dstPitch, byte *src, uint srcPitch); + void flatBlit(const Common::Rect& r, byte *data, Gfx::Buffers buffer, byte transparentColor); void blit(const Common::Rect& r, uint16 z, byte *data, Gfx::Buffers buffer); - void initBuffers(); - void initMouse(uint16 arg_0); + void screenClip(Common::Rect& r, Common::Point& p); }; @@ -254,3 +294,7 @@ protected: #endif + + + + diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index c9e74b2074..06d48744be 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -117,9 +117,12 @@ void drawInventoryItem(uint16 pos, InventoryItem *item) { uint16 line = pos / INVENTORY_ITEMS_PER_LINE; uint16 col = pos % INVENTORY_ITEMS_PER_LINE; + Common::Rect r; + _vm->_char._objs->getRect(0, r); + // FIXME: this will end up in a general blit function - byte* s = _vm->_char._objs->getFramePtr(item->_index); - byte* d = _buffer + col * INVENTORYITEM_WIDTH + line * _vm->_char._objs->_height * INVENTORY_WIDTH; + byte* s = _vm->_char._objs->getData(item->_index); + byte* d = _buffer + col * INVENTORYITEM_WIDTH + line * r.height() * INVENTORY_WIDTH; for (uint32 i = 0; i < INVENTORYITEM_HEIGHT; i++) { memcpy(d, s, INVENTORYITEM_WIDTH); @@ -157,7 +160,7 @@ void Parallaction::dropItem(uint16 v) { bool found = false; for (uint16 slot = 0; slot < INVENTORY_MAX_ITEMS - 1; slot++) { - if (v + INVENTORY_FIRST_ITEM == _inventory[slot]._index) { + if (v == _inventory[slot]._index) { found = true; } @@ -210,8 +213,10 @@ void highlightInventoryItem(int16 pos, byte color) { uint16 line = pos / INVENTORY_ITEMS_PER_LINE; uint16 col = pos % INVENTORY_ITEMS_PER_LINE; - Common::Rect r(INVENTORYITEM_WIDTH, _vm->_char._objs->_height); - r.moveTo(col * INVENTORYITEM_WIDTH, line * _vm->_char._objs->_height); + Common::Rect r; + _vm->_char._objs->getRect(0, r); + r.setWidth(INVENTORYITEM_WIDTH); + r.moveTo(col * INVENTORYITEM_WIDTH, line * r.height()); drawBorder(r, _buffer, color); @@ -228,7 +233,7 @@ int16 getInventoryItemIndex(int16 pos) { -void jobShowInventory(void *parm, Job *j) { +void Parallaction_ns::jobShowInventory(void *parm, Job *j) { // printf("job_showInventory()..."); int16 slot = getNumUsedSlots(); @@ -238,19 +243,14 @@ void jobShowInventory(void *parm, Job *j) { r.moveTo(_invPosition); - _vm->_gfx->copyRect( - Gfx::kBitBack, - r, - _buffer, - INVENTORY_WIDTH - ); + _gfx->copyRect(Gfx::kBitBack, r, _buffer, INVENTORY_WIDTH); return; } -void jobHideInventory(void *parm, Job *j) { +void Parallaction_ns::jobHideInventory(void *parm, Job *j) { // printf("job_hideInventory()\n"); static uint16 count = 0; @@ -267,7 +267,7 @@ void jobHideInventory(void *parm, Job *j) { Common::Rect r(INVENTORY_WIDTH, _numInvLines * INVENTORYITEM_HEIGHT); r.moveTo(_invPosition); - _vm->_gfx->restoreBackground(r); + _gfx->restoreBackground(r); return; } diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h index 4a3e07cc97..2ca3559b8f 100644 --- a/engines/parallaction/inventory.h +++ b/engines/parallaction/inventory.h @@ -31,8 +31,6 @@ namespace Parallaction { -struct Cnv; - struct InventoryItem { uint32 _id; // object name (lowest 16 bits are always zero) uint16 _index; // index to frame in objs file diff --git a/engines/parallaction/location.cpp b/engines/parallaction/location.cpp deleted file mode 100644 index 024938074b..0000000000 --- a/engines/parallaction/location.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "common/system.h" - -#include "parallaction/parallaction.h" -#include "parallaction/sound.h" - -namespace Parallaction { - - -void Parallaction::parseLocation(const char *filename) { - debugC(1, kDebugLocation, "parseLocation('%s')", filename); - - uint16 _si = 1; - _gfx->setFont(kFontLabel); - - Script *_locationScript = _disk->loadLocation(filename); - _hasLocationSound = false; - - fillBuffers(*_locationScript, true); - while (scumm_stricmp(_tokens[0], "ENDLOCATION")) { - - if (!scumm_stricmp(_tokens[0], "LOCATION")) { - // The parameter for location is 'location.mask'. - // If mask is not present, then it is assumed - // that path & mask are encoded in the background - // bitmap, otherwise a separate .msk file exists. - - char *mask = strchr(_tokens[1], '.'); - if (mask) { - mask[0] = '\0'; - mask++; - } - - // WORKAROUND: the original code erroneously incremented - // _currentLocationIndex, thus producing inconsistent - // savegames. This workaround modified the following loop - // and if-statement, so the code exactly matches the one - // in Big Red Adventure. - _currentLocationIndex = -1; - uint16 _di = 0; - while (_locationNames[_di][0] != '\0') { - if (!scumm_stricmp(_locationNames[_di], filename)) { - _currentLocationIndex = _di; - } - _di++; - } - - if (_currentLocationIndex == -1) { - strcpy(_locationNames[_numLocations], filename); - _currentLocationIndex = _numLocations; - - _numLocations++; - _locationNames[_numLocations][0] = '\0'; - _localFlags[_numLocations] = 0; - } else { - _localFlags[_currentLocationIndex] |= kFlagsVisited; // 'visited' - } - - strcpy(_location._name, _tokens[1]); - switchBackground(_location._name, mask); - - if (_tokens[2][0] != '\0') { - _char._ani._left = atoi(_tokens[2]); - _char._ani._top = atoi(_tokens[3]); - } - - if (_tokens[4][0] != '\0') { - _char._ani._frame = atoi(_tokens[4]); - } - } - if (!scumm_stricmp(_tokens[0], "DISK")) { - _disk->selectArchive(_tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "LOCALFLAGS")) { - _si = 1; // _localFlagNames[0] = 'visited' - while (_tokens[_si][0] != '\0') { - _localFlagNames->addData(_tokens[_si]); - _si++; - } - } - if (!scumm_stricmp(_tokens[0], "COMMANDS")) { - parseCommands(*_locationScript, _location._commands); - } - if (!scumm_stricmp(_tokens[0], "ACOMMANDS")) { - parseCommands(*_locationScript, _location._aCommands); - } - if (!scumm_stricmp(_tokens[0], "FLAGS")) { - if ((_localFlags[_currentLocationIndex] & kFlagsVisited) == 0) { - // only for 1st visit - _localFlags[_currentLocationIndex] = 0; - _si = 1; - - do { - byte _al = _localFlagNames->lookup(_tokens[_si]); - _localFlags[_currentLocationIndex] |= 1 << (_al - 1); - - _si++; - if (scumm_stricmp(_tokens[_si], "|")) break; - _si++; - } while (true); - } - } - if (!scumm_stricmp(_tokens[0], "COMMENT")) { - _location._comment = parseComment(*_locationScript); - debugC(3, kDebugLocation, "Location comment: '%s'", _location._comment); - } - if (!scumm_stricmp(_tokens[0], "ENDCOMMENT")) { - _location._endComment = parseComment(*_locationScript); - } - if (!scumm_stricmp(_tokens[0], "ZONE")) { - parseZone(*_locationScript, _zones, _tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "NODES")) { - parseWalkNodes(*_locationScript, _location._walkNodes); - } - if (!scumm_stricmp(_tokens[0], "ANIMATION")) { - parseAnimation(*_locationScript, _animations, _tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "SOUND")) { - if (getPlatform() == Common::kPlatformAmiga) { - strcpy(_locationSound, _tokens[1]); - _hasLocationSound = true; - } - } - if (!scumm_stricmp(_tokens[0], "MUSIC")) { - if (getPlatform() == Common::kPlatformAmiga) - _soundMan->setMusicFile(_tokens[1]); - } - fillBuffers(*_locationScript, true); - } - - resolveLocationForwards(); - - delete _locationScript; - - return; -} - -void Parallaction::resolveLocationForwards() { - - for (uint16 _si = 0; _forwardedCommands[_si]; _si++) { - _forwardedCommands[_si]->u._animation = findAnimation(_forwardedAnimationNames[_si]); - _forwardedCommands[_si] = NULL; - } - - _numForwards = 0; - return; -} - - -void Parallaction::freeLocation() { - debugC(7, kDebugLocation, "freeLocation"); - - _soundMan->stopSfx(0); - _soundMan->stopSfx(1); - _soundMan->stopSfx(2); - _soundMan->stopSfx(3); - - if (_localFlagNames) - delete _localFlagNames; - - // HACK: prevents leakage. A routine like this - // should allocate memory at all, though. - if ((_engineFlags & kEngineQuit) == 0) { - _localFlagNames = new Table(120); - _localFlagNames->addData("visited"); - } - - _location._walkNodes.clear(); - - // TODO (LIST): helperNode should be rendered useless by the use of a Common::List<> - // to store Zones and Animations. Right now, it holds a list of Zones to be preserved - // but that'll pretty meaningless with a single list approach. - freeZones(); - freeAnimations(); - - if (_location._comment) { - free(_location._comment); - } - _location._comment = NULL; - - _location._commands.clear(); - _location._aCommands.clear(); - - return; -} - - - -void Parallaction::parseWalkNodes(Script& script, WalkNodeList &list) { - - fillBuffers(script, true); - while (scumm_stricmp(_tokens[0], "ENDNODES")) { - - if (!scumm_stricmp(_tokens[0], "COORD")) { - - WalkNode *v4 = new WalkNode( - atoi(_tokens[1]) - _char._ani.width()/2, - atoi(_tokens[2]) - _char._ani.height() - ); - - list.push_front(v4); - } - - fillBuffers(script, true); - } - - return; - -} - -void Parallaction::switchBackground(const char* background, const char* mask) { -// printf("switchBackground(%s)", name); - - Gfx::Palette pal; - - uint16 v2 = 0; - if (!scumm_stricmp(background, "final")) { - _gfx->clearScreen(Gfx::kBitBack); - for (uint16 _si = 0; _si <= 93; ) { - pal[_si] = v2; - pal[_si+1] = v2; - pal[_si+2] = v2; - v2 += 4; - _si += 3; - } - - g_system->delayMillis(20); - _gfx->setPalette(pal); - _gfx->updateScreen(); - } - - _disk->loadScenery(background, mask); - - return; -} - -extern Zone *_hoverZone; -extern Job *_jDrawLabel; -extern Job *_jEraseLabel; - -void Parallaction::showSlide(const char *name) { - - _disk->loadSlide(name); - _gfx->setPalette(_gfx->_palette); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - - debugC(1, kDebugLocation, "changeLocation: new background set"); - - _gfx->setFont(kFontMenu); - - _gfx->displayCenteredString(14, _slideText[0]); // displays text on screen - _gfx->updateScreen(); - - waitUntilLeftClick(); - - debugC(2, kDebugLocation, "changeLocation: intro text shown"); - - return; -} - -/* - changeLocation handles transitions between locations, and is able to display slides - between one and the other. The input parameter 'location' exists in some flavours: - - 1 - [S].slide.[L]{.[C]} - 2 - [L]{.[C]} - - where: - - [S] is the slide to be shown - [L] is the location to switch to (immediately in case 2, or right after slide [S] in case 1) - [C] is the character to be selected, and is optional - - The routine tells one form from the other by searching for the '.slide.' - - NOTE: there exists one script in which [L] is not used in the case 1, but its use - is commented out, and would definitely crash the current implementation. -*/ -void Parallaction::changeLocation(char *location) { - debugC(1, kDebugLocation, "changeLocation(%s)", location); - - _soundMan->playLocationMusic(location); - - // WORKAROUND: this if-statement has been added to avoid crashes caused by - // execution of label jobs after a location switch. The other workaround in - // Parallaction::runGame should have been rendered useless by this one. - if (_jDrawLabel != NULL) { - removeJob(_jDrawLabel); - removeJob(_jEraseLabel); - _jDrawLabel = NULL; - _jEraseLabel = NULL; - } - - - _hoverZone = NULL; - if (_engineFlags & kEngineBlockInput) { - changeCursor( kCursorArrow ); - } - - _animations.remove(&_char._ani); - - freeLocation(); - char buf[100]; - strcpy(buf, location); - - Common::StringList list; - char *tok = strtok(location, "."); - while (tok) { - list.push_back(tok); - tok = strtok(NULL, "."); - } - - if (list.size() < 1 || list.size() > 4) - error("changeLocation: ill-formed location string '%s'", location); - - if (list.size() > 1) { - if (list[1] == "slide") { - showSlide(list[0].c_str()); - list.remove_at(0); // removes slide name - list.remove_at(0); // removes 'slide' - } - - // list is now only [L].{[C]} (see above comment) - if (list.size() == 2) { - changeCharacter(list[1].c_str()); - strcpy(_characterName, list[1].c_str()); - } - } - - _animations.push_front(&_char._ani); - - strcpy(_saveData1, list[0].c_str()); - parseLocation(list[0].c_str()); - - _char._ani._oldPos.x = -1000; - _char._ani._oldPos.y = -1000; - - _char._ani.field_50 = 0; - if (_location._startPosition.x != -1000) { - _char._ani._left = _location._startPosition.x; - _char._ani._top = _location._startPosition.y; - _char._ani._frame = _location._startFrame; - _location._startPosition.y = -1000; - _location._startPosition.x = -1000; - } - - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); - _gfx->setBlackPalette(); - _gfx->updateScreen(); - - if (_location._commands.size() > 0) { - runCommands(_location._commands); - runJobs(); - _gfx->swapBuffers(); - runJobs(); - _gfx->swapBuffers(); - } - - if (_location._comment) { - doLocationEnterTransition(); - } - - runJobs(); - _gfx->swapBuffers(); - - _gfx->setPalette(_gfx->_palette); - if (_location._aCommands.size() > 0) { - runCommands(_location._aCommands); - } - - if (_hasLocationSound) - _soundMan->playSfx(_locationSound, 0, true); - - debugC(1, kDebugLocation, "changeLocation() done"); - - return; - -} - -// displays transition before a new location -// -// clears screen (in white??) -// shows location comment (if any) -// waits for mouse click -// fades towards game palette -// -// THE FINAL PALETTE IS NOT THE SAME AS THE MAIN PALETTE!!!!!! -// -void Parallaction::doLocationEnterTransition() { - debugC(1, kDebugLocation, "doLocationEnterTransition"); - - if (_localFlags[_currentLocationIndex] & kFlagsVisited) { - debugC(3, kDebugLocation, "skipping location transition"); - return; // visited - } - - byte pal[PALETTE_SIZE]; - _gfx->makeGrayscalePalette(pal); - _gfx->setPalette(pal); - - jobRunScripts(NULL, NULL); - jobEraseAnimations(NULL, NULL); - jobDisplayAnimations(NULL, NULL); - - _gfx->setFont(kFontDialogue); - _gfx->swapBuffers(); - _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); - - int16 w, h; - _gfx->getStringExtent(_location._comment, 130, &w, &h); - - Common::Rect r(10 + w, 5 + h); - r.moveTo(5, 5); - _gfx->floodFill(Gfx::kBitFront, r, 0); - r.grow(-1); - _gfx->floodFill(Gfx::kBitFront, r, 1); - _gfx->displayWrappedString(_location._comment, 3, 5, 0, 130); - - _gfx->updateScreen(); - waitUntilLeftClick(); - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront ); - - // fades maximum intensity palette towards approximation of main palette - for (uint16 _si = 0; _si<6; _si++) { - _gfx->fadePalette(pal, _gfx->_palette, 4); - _gfx->setPalette(pal); - waitTime( 1 ); - _gfx->updateScreen(); - } - - debugC(1, kDebugLocation, "doLocationEnterTransition completed"); - - return; -} - -} // namespace Parallaction diff --git a/engines/parallaction/menu.cpp b/engines/parallaction/menu.cpp index 12b03ab4b0..14d50c6373 100644 --- a/engines/parallaction/menu.cpp +++ b/engines/parallaction/menu.cpp @@ -114,7 +114,7 @@ void Menu::start() { splash(); - _vm->_gfx->setFont(kFontMenu); + _vm->_gfx->setFont(_vm->_menuFont); _language = chooseLanguage(); _vm->_disk->setLanguage(_language); @@ -128,15 +128,11 @@ void Menu::start() { void Menu::splash() { - _vm->_disk->loadSlide("intro"); - _vm->_gfx->setPalette(_vm->_gfx->_palette); - _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _vm->showSlide("intro"); _vm->_gfx->updateScreen(); g_system->delayMillis(2000); - _vm->_disk->loadSlide("minintro"); - _vm->_gfx->setPalette(_vm->_gfx->_palette); - _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _vm->showSlide("minintro"); _vm->_gfx->updateScreen(); g_system->delayMillis(2000); @@ -155,8 +151,8 @@ void Menu::newGame() { _vm->_disk->selectArchive("disk1"); - _vm->_disk->loadScenery("test", NULL); - _vm->_gfx->setPalette(_vm->_gfx->_palette); + _vm->setBackground("test", NULL, NULL); + _vm->_gfx->swapBuffers(); _vm->_gfx->displayCenteredString(50, v14[0]); @@ -200,11 +196,7 @@ uint16 Menu::chooseLanguage() { } // user can choose language in dos version - - _vm->_disk->loadSlide("lingua"); - _vm->_gfx->setPalette(_vm->_gfx->_palette); - _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - + _vm->showSlide("lingua"); _vm->_gfx->displayString(60, 30, "SELECT LANGUAGE", 1); _vm->changeCursor(kCursorArrow); @@ -260,8 +252,7 @@ uint16 Menu::selectGame() { return 0; // can't load a savegame in demo versions } - _vm->_disk->loadSlide("restore"); - _vm->_gfx->setPalette(_vm->_gfx->_palette); + _vm->showSlide("restore"); uint16 _si = 0; uint16 _di = 3; @@ -343,23 +334,17 @@ void Menu::selectCharacter() { uint16 _donna_points, _dino_points, _dough_points; - StaticCnv v14; - - v14._data0 = (byte*)malloc(BLOCK_WIDTH*BLOCK_HEIGHT); - v14._width = BLOCK_WIDTH; - v14._height = BLOCK_HEIGHT; + Graphics::Surface v14; + v14.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); _vm->changeCursor(kCursorArrow); _vm->_soundMan->stopMusic(); - _vm->_gfx->setFont(kFontMenu); + _vm->_gfx->setFont(_vm->_menuFont); _vm->_disk->selectArchive((_vm->getFeatures() & GF_LANG_MULT) ? "disk1" : "disk0"); - _vm->_disk->loadSlide("password"); // loads background into kBitBack buffer - _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); // - - _vm->_gfx->setPalette(_vm->_gfx->_palette); + _vm->showSlide("password"); // loads background into kBitBack buffer while (true) { @@ -383,7 +368,7 @@ void Menu::selectCharacter() { Common::Rect r; int _si = getSelectedBlock(_vm->_mousePos, r); if (_si != -1) { - _vm->_gfx->grabRect(v14._data0, r, Gfx::kBitFront, BLOCK_WIDTH); + _vm->_gfx->grabRect((byte*)v14.pixels, r, Gfx::kBitFront, BLOCK_WIDTH); _vm->_gfx->flatBlitCnv(&v14, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, Gfx::kBitFront); // beep(); @@ -435,7 +420,7 @@ void Menu::selectCharacter() { _engineFlags |= kEngineChangeLocation; - free(v14._data0); + v14.free(); return; diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index b7f60eeb32..56eaddac95 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -1,29 +1,30 @@ MODULE := engines/parallaction MODULE_OBJS := \ - animation.o \ callables_br.o \ callables_ns.o \ - commands.o \ debug.o \ detection.o \ dialogue.o \ disk_br.o \ disk_ns.o \ + exec_br.o \ + exec_ns.o \ font.o \ graphics.o \ inventory.o \ - location.o \ menu.o \ - parser.o \ + objects.o \ parallaction.o \ parallaction_br.o \ parallaction_ns.o \ + parser.o \ + parser_br.o \ + parser_ns.o \ saveload.o \ sound.o \ staticres.o \ - walk.o \ - zone.o + walk.o # This module can be built as a plugin ifdef BUILD_PLUGINS diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp new file mode 100644 index 0000000000..0e0d7c4c38 --- /dev/null +++ b/engines/parallaction/objects.cpp @@ -0,0 +1,408 @@ +/* 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/stdafx.h" +#include "parallaction/objects.h" +#include "parallaction/parser.h" + +namespace Parallaction { + + + +Command::Command() { + _id = 0; + _flagsOn = 0; + _flagsOff = 0; +} + +Command::~Command() { + +} + + +Animation::Animation() { + _cnv = NULL; + _program = NULL; + _scriptName = 0; + _frame = 0; + _z = 0; +} + +Animation::~Animation() { + if (_program) + delete _program; + + if (_scriptName) + free(_scriptName); + + if (_cnv) + delete _cnv; +} + +uint16 Animation::width() const { + if (!_cnv) return 0; + Common::Rect r; + _cnv->getRect(0, r); + return r.width(); +} + +uint16 Animation::height() const { + if (!_cnv) return 0; + Common::Rect r; + _cnv->getRect(0, r); + return r.height(); +} + +uint16 Animation::getFrameNum() const { + if (!_cnv) return 0; + return _cnv->getNum(); +} + +byte* Animation::getFrameData(uint32 index) const { + if (!_cnv) return NULL; + return _cnv->getData(index); +} + + +#define NUM_LOCALS 10 +char _localNames[NUM_LOCALS][10]; + +Program::Program() { + _loopCounter = 0; + _locals = new LocalVariable[NUM_LOCALS]; + _numLocals = 0; +} + +Program::~Program() { + delete[] _locals; +} + +int16 Program::findLocal(const char* name) { + for (uint16 _si = 0; _si < NUM_LOCALS; _si++) { + if (!scumm_stricmp(name, _localNames[_si])) + return _si; + } + + return -1; +} + +int16 Program::addLocal(const char *name, int16 value, int16 min, int16 max) { + assert(_numLocals < NUM_LOCALS); + + strcpy(_localNames[_numLocals], name); + _locals[_numLocals]._value = value; + + _locals[_numLocals]._min = min; + _locals[_numLocals]._max = max; + + return _numLocals++; +} + + + +Zone::Zone() { + _left = _top = _right = _bottom = 0; + + _type = 0; + _flags = 0; +} + +Zone::~Zone() { +// printf("~Zone(%s)\n", _label._text); + + switch (_type & 0xFFFF) { + case kZoneExamine: + free(u.examine->_filename); + free(u.examine->_description); + delete u.examine; + break; + + case kZoneDoor: + free(u.door->_location); + free(u.door->_background); + if (u.door->_cnv) + delete u.door->_cnv; + delete u.door; + break; + + case kZoneSpeak: + delete u.speak->_dialogue; + delete u.speak; + break; + + case kZoneGet: + free(u.get->_backup); + if (u.get->_cnv) { + u.get->_cnv->free(); + delete u.get->_cnv; + } + delete u.get; + break; + + case kZoneHear: + delete u.hear; + break; + + case kZoneMerge: + delete u.merge; + break; + + default: + break; + } +} + +void Zone::getRect(Common::Rect& r) const { + r.left = _left; + r.right = _right; + r.top = _top; + r.bottom = _bottom; +} + +void Zone::translate(int16 x, int16 y) { + _left += x; + _right += x; + _top += y; + _bottom += y; +} + +uint16 Zone::width() const { + return _right - _left; +} + +uint16 Zone::height() const { + return _bottom - _top; +} + +Label::Label() { + resetPosition(); + _text = 0; +} + +Label::~Label() { + free(); +} + +void Label::free() { + _cnv.free(); + if (_text) + ::free(_text); + _text = 0; + + resetPosition(); +} + +void Label::resetPosition() { + _pos.x = -1000; + _pos.y = -1000; + _old.x = -1000; + _old.y = -1000; +} + +void Label::getRect(Common::Rect &r, bool old) { + r.setWidth(_cnv.w); + r.setHeight(_cnv.h); + + if (old) { + r.moveTo(_old); + } else { + r.moveTo(_pos); + } +} + +Answer::Answer() { + _text = NULL; + _mood = 0; + _following._question = NULL; + _noFlags = 0; + _yesFlags = 0; +} + +Answer::~Answer() { + if (_text) + free(_text); +} + +Question::Question() { + _text = NULL; + _mood = 0; + + for (uint32 i = 0; i < NUM_ANSWERS; i++) + _answers[i] = NULL; + +} + +Question::~Question() { + + for (uint32 i = 0; i < NUM_ANSWERS; i++) + if (_answers[i]) delete _answers[i]; + + free(_text); +} + +Instruction::Instruction() { + memset(this, 0, sizeof(Instruction)); +} + +Instruction::~Instruction() { + if (_text) + free(_text); + if (_text2) + free(_text2); +} + +int16 ScriptVar::getRValue() { + + if (_flags & kParaImmediate) { + return _value; + } + + if (_flags & kParaLocal) { + return _local->_value; + } + + if (_flags & kParaField) { + return *_pvalue; + } + + if (_flags & kParaRandom) { + return (rand() * _value) / 32767; + } + + error("Parameter is not an r-value"); + + return 0; +} + +int16* ScriptVar::getLValue() { + + if (_flags & kParaLocal) { + return &_local->_value; + } + + if (_flags & kParaField) { + return _pvalue; + } + + error("Parameter is not an l-value"); + +} + +void ScriptVar::setLocal(LocalVariable *local) { + _local = local; + _flags |= kParaLocal; +} + +void ScriptVar::setField(int16 *field) { + _pvalue = field; + _flags |= kParaField; +} + +void ScriptVar::setImmediate(int16 value) { + _value = value; + _flags |= kParaImmediate; +} + +void ScriptVar::setRandom(int16 seed) { + _value = seed; + _flags |= kParaRandom; +} + + +ScriptVar::ScriptVar() { + _flags = 0; + _local = 0; + _value = 0; + _pvalue = 0; +} + +Table::Table(uint32 size) : _size(size), _used(0), _disposeMemory(true) { + _data = (char**)calloc(size, sizeof(char*)); +} + +Table::Table(uint32 size, const char **data) : _size(size), _used(size), _disposeMemory(false) { + _data = const_cast<char**>(data); +} + +Table::~Table() { + + if (!_disposeMemory) return; + + clear(); + + free(_data); + +} + +void Table::addData(const char* s) { + + if (!(_used < _size)) + error("Table overflow"); + + _data[_used++] = strdup(s); + +} + +uint16 Table::lookup(const char* s) { + + for (uint16 i = 0; i < _used; i++) { + if (!scumm_stricmp(_data[i], s)) return i + 1; + } + + return notFound; +} + +void Table::clear() { + for (uint32 i = 0; i < _used; i++) + free(_data[i]); + + _used = 0; +} + +FixedTable::FixedTable(uint32 size, uint32 fixed) : Table(size), _numFixed(fixed) { +} + +void FixedTable::clear() { + for (uint32 i = _numFixed; i < _used; i++) { + free(_data[i]); + _used--; + } +} + +Table* createTableFromStream(uint32 size, Common::SeekableReadStream &stream) { + + Table *t = new Table(size); + + fillBuffers(stream); + while (scumm_stricmp(_tokens[0], "ENDTABLE")) { + t->addData(_tokens[0]); + fillBuffers(stream); + } + + return t; +} + + +} // namespace Parallaction diff --git a/engines/parallaction/zone.h b/engines/parallaction/objects.h index 634a1364aa..41e8bbcf5d 100644 --- a/engines/parallaction/zone.h +++ b/engines/parallaction/objects.h @@ -30,12 +30,19 @@ #include "parallaction/defs.h" -#include "parallaction/commands.h" #include "parallaction/graphics.h" namespace Parallaction { +struct Zone; +struct Animation; +struct Command; +struct Question; +struct Answer; +struct Instruction; +struct Program; + enum ZoneTypes { kZoneExamine = 1, // zone displays comment if activated kZoneDoor = 2, // zone activated on click (after some walk if needed) @@ -64,16 +71,77 @@ enum ZoneFlags { kFlagsLooping = 0x100, // Animation: script is to be executed repeatedly kFlagsAdded = 0x200, // NEVER USED in Nippon Safes kFlagsCharacter = 0x400, // - kFlagsNoWalk = 0x800 // Zone: character doesn't need to walk towards object to interact + kFlagsNoWalk = 0x800, // Zone: character doesn't need to walk towards object to interact + + // BRA specific + kFlagsYourself = 0x1000, + kFlagsScaled = 0x2000, + kFlagsSelfuse = 0x4000, + kFlagsAnimLinked = 0x2000000 +}; + + +enum CommandFlags { + kFlagsVisited = 1, + kFlagsExit = 0x10000000, + kFlagsEnter = 0x20000000, + kFlagsGlobal = 0x40000000, + + // BRA specific + kFlagsTestTrue = 2 +}; + +struct CommandData { + uint32 _flags; + Animation * _animation; + Zone* _zone; + char* _string; + uint16 _callable; + uint16 _object; + Common::Point _move; + + // BRA specific + Common::Point _startPos; + Common::Point _startPos2; + uint _lvalue; + int _rvalue; + int _zeta0; + int _zeta1; + int _zeta2; + int _characterId; + char* _string2; + int _musicCommand; + int _musicParm; + + + CommandData() { + memset(this, 0, sizeof(CommandData)); + } + + ~CommandData() { + if (_string) + free(_string); + if (_string2) + free(_string2); + } }; +struct Command { + uint16 _id; + CommandData u; + uint32 _flagsOn; + uint32 _flagsOff; + + Command(); + ~Command(); +}; + +typedef ManagedList<Command*> CommandList; + #define NUM_QUESTIONS 20 #define NUM_ANSWERS 5 -struct Command; -struct Question; - struct Answer { char* _text; uint16 _mood; @@ -104,7 +172,7 @@ struct Dialogue { struct GetData { // size = 24 uint32 _icon; - StaticCnv *_cnv; + Graphics::Surface *_cnv; byte *_backup; uint16 field_14; // unused uint16 field_16; // unused @@ -125,7 +193,7 @@ struct SpeakData { // size = 36 } }; struct ExamineData { // size = 28 - StaticCnv *_cnv; + Graphics::Surface *_cnv; uint16 _opBase; // unused uint16 field_12; // unused char* _description; @@ -140,7 +208,7 @@ struct ExamineData { // size = 28 }; struct DoorData { // size = 28 char* _location; - Cnv *_cnv; + Frames *_cnv; byte* _background; Common::Point _startPos; uint16 _startFrame; @@ -192,11 +260,18 @@ struct TypeData { }; struct Label { - char* _text; - StaticCnv _cnv; + char* _text; + Graphics::Surface _cnv; + + Common::Point _pos; + Common::Point _old; Label(); ~Label(); + + void free(); + void resetPosition(); + void getRect(Common::Rect &r, bool old = false); }; struct Zone { @@ -213,6 +288,11 @@ struct Zone { CommandList _commands; Common::Point _moveTo; + // BRA specific + uint _index; + char *_linkedName; + Animation *_linkedAnim; + Zone(); virtual ~Zone(); @@ -237,57 +317,81 @@ struct LocalVariable { } }; -union LValue { +enum ParaFlags { + kParaImmediate = 1, // instruction is using an immediate parameter + kParaLocal = 2, // instruction is using a local variable + kParaField = 0x10, // instruction is using an animation's field + kParaRandom = 0x100 +}; + + +struct ScriptVar { + uint32 _flags; + int16 _value; int16* _pvalue; LocalVariable* _local; - LValue() { - _local = NULL; - } + ScriptVar(); + + int16 getRValue(); + int16* getLValue(); + + void setLocal(LocalVariable *local); + void setField(int16 *field); + void setImmediate(int16 value); + void setRandom(int16 seed); }; enum InstructionFlags { - kInstUsesLiteral = 1, - kInstUsesLocal = 2, kInstMod = 4, - kInstMaskedPut = 8 + kInstMaskedPut = 8, + kInstUnk20 = 0x20 }; -struct Animation; +typedef ManagedList<Instruction*> InstructionList; struct Instruction { uint32 _index; uint32 _flags; - struct { - Animation *_a; - Zone *_z; - uint32 _index; - LValue _loopCounter; - } _opBase; - LValue _opA; - LValue _opB; - - Instruction() { - _index = 0; - _flags = 0; - _opBase._a = NULL; - } + + // common + Animation *_a; + Zone *_z; + int16 _immediate; + ScriptVar _opA; + ScriptVar _opB; + + // BRA specific + byte _colors[3]; + ScriptVar _opC; + char *_text; + char *_text2; + int _y; + InstructionList::iterator _endif; + + Instruction(); + ~Instruction(); + }; -//typedef Common::List<Instruction*> InstructionList; -typedef ManagedList<Instruction*> InstructionList; struct Program { LocalVariable *_locals; + uint16 _loopCounter; + uint16 _numLocals; + InstructionList::iterator _ip; InstructionList::iterator _loopStart; InstructionList _instructions; Program(); ~Program(); + + int16 findLocal(const char* name); + int16 addLocal(const char *name, int16 value = 0, int16 min = -10000, int16 max = 10000); }; @@ -296,7 +400,8 @@ struct Animation : public Zone { Common::Point _oldPos; Program *_program; - Cnv *_cnv; + Frames *_cnv; + char *_scriptName; int16 _frame; uint16 field_50; // unused int16 _z; @@ -319,6 +424,40 @@ typedef Animation* AnimationPointer; typedef ManagedList<AnimationPointer> AnimationList; +class Table { + +protected: + char **_data; + uint16 _size; + uint16 _used; + bool _disposeMemory; + +public: + Table(uint32 size); + Table(uint32 size, const char** data); + + virtual ~Table(); + + enum { + notFound = 0 + }; + + virtual void addData(const char* s); + virtual void clear(); + virtual uint16 lookup(const char* s); +}; + +class FixedTable : public Table { + + uint16 _numFixed; + +public: + FixedTable(uint32 size, uint32 fixed); + void clear(); +}; + +Table* createTableFromStream(uint32 size, Common::SeekableReadStream &stream); + } // namespace Parallaction #endif diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 986bc6ebd7..7b641bf838 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -35,7 +35,6 @@ #include "parallaction/parallaction.h" #include "parallaction/debug.h" -#include "parallaction/menu.h" #include "parallaction/sound.h" @@ -54,11 +53,9 @@ char _saveData1[30] = { '\0' }; uint16 _language = 0; char _slideText[2][40]; uint32 _engineFlags = 0; -Zone *_activeZone = NULL; uint16 _score = 1; -uint32 _localFlags[120] = { 0 }; Command * _forwardedCommands[20] = { NULL, NULL, @@ -92,15 +89,14 @@ uint16 _introSarcData2 = 1; // private stuff static Job *_jDrawInventory = NULL; -Job *_jDrawLabel = NULL; -Job *_jEraseLabel = NULL; -Zone *_hoverZone = NULL; static Job *_jRunScripts = NULL; Parallaction::Parallaction(OSystem *syst) : Engine(syst) { + // FIXME: Fingolfin asks: why is there a FIXME here? Please either clarify what + // needs fixing, or remove it! // FIXME _vm = this; @@ -109,11 +105,11 @@ Parallaction::Parallaction(OSystem *syst) : Common::File::addDefaultDirectory( _gameDataPath ); Common::addSpecialDebugLevel(kDebugDialogue, "dialogue", "Dialogues debug level"); - Common::addSpecialDebugLevel(kDebugLocation, "location", "Location debug level"); + Common::addSpecialDebugLevel(kDebugParser, "parser", "Parser debug level"); Common::addSpecialDebugLevel(kDebugDisk, "disk", "Disk debug level"); Common::addSpecialDebugLevel(kDebugWalk, "walk", "Walk debug level"); Common::addSpecialDebugLevel(kDebugGraphics, "gfx", "Gfx debug level"); - Common::addSpecialDebugLevel(kDebugJobs, "jobs", "Jobs debug level"); + Common::addSpecialDebugLevel(kDebugExec, "exec", "Execution debug level"); Common::addSpecialDebugLevel(kDebugInput, "input", "Input debug level"); Common::addSpecialDebugLevel(kDebugAudio, "audio", "Audio debug level"); Common::addSpecialDebugLevel(kDebugMenu, "menu", "Menu debug level"); @@ -123,11 +119,13 @@ Parallaction::Parallaction(OSystem *syst) : Parallaction::~Parallaction() { delete _debugger; + freeBackground(); + delete _backgroundInfo; + delete _globalTable; delete _callableNames; - delete _commandsNames; - delete _instructionNames; + delete _localFlagNames; delete _zoneTypeNames; delete _zoneFlagNames; @@ -150,7 +148,6 @@ int Parallaction::init() { _objectsNames = NULL; _globalTable = NULL; _hasLocationSound = false; - _skipMenu = false; _transCurrentHoverItem = 0; _actionAfterWalk = false; // actived when the character needs to move before taking an action _activeItem._index = 0; @@ -164,20 +161,25 @@ int Parallaction::init() { _location._comment = NULL; _location._endComment = NULL; - _screenMaskWidth = _screenWidth / 4; - _screenPathWidth = _screenWidth / 8; + _backgroundInfo = 0; + _pathBuffer = 0; + _activeZone = 0; + _screenSize = _screenWidth * _screenHeight; - _screenMaskSize = _screenMaskWidth * _screenHeight; - _screenPathSize = _screenPathWidth * _screenHeight; + + _backgroundInfo = new BackgroundInfo; strcpy(_characterName1, "null"); strcpy(_characterName, "dough"); - memset(_locationNames, 0, 120*32); + memset(_locationNames, 0, NUM_LOCATIONS * 32); - initWalk(); // needs to be pushed into subclass initInventory(); // needs to be pushed into subclass + _jDrawLabel = NULL; + _jEraseLabel = NULL; + _hoverZone = NULL; + _animations.push_front(&_char._ani); _gfx = new Gfx(this); @@ -190,48 +192,7 @@ int Parallaction::init() { -int Parallaction::go() { - - initGame(); - runGame(); - - return 0; -} - -void Parallaction::initGame() { - - _menu = new Menu(this); - - initGlobals(); - if (_skipMenu == false) { - _menu->start(); - } - - char *v4 = strchr(_location._name, '.'); - if (v4) { - *v4 = '\0'; - } - - _engineFlags &= ~kEngineChangeLocation; - changeCharacter(_characterName); - - strcpy(_saveData1, _location._name); - parseLocation(_location._name); - if (_location._startPosition.x != -1000) { - _char._ani._left = _location._startPosition.x; - _char._ani._top = _location._startPosition.y; - _char._ani._frame = _location._startFrame; - _location._startPosition.y = -1000; - _location._startPosition.x = -1000; - } - - return; -} - -void Parallaction::initGlobals() { - _globalTable = _disk->loadTable("global"); -} // 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 @@ -324,9 +285,9 @@ void waitUntilLeftClick() { void Parallaction::runGame() { - addJob(&jobEraseAnimations, (void*)1, kPriority20); - _jRunScripts = addJob(&jobRunScripts, 0, kPriority15); - addJob(&jobDisplayAnimations, 0, kPriority3); + addJob(kJobEraseAnimations, (void*)1, kPriority20); + _jRunScripts = addJob(kJobRunScripts, 0, kPriority15); + addJob(kJobDisplayAnimations, 0, kPriority3); _gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); @@ -391,11 +352,34 @@ void Parallaction::runGame() { } - delete _menu; - return; } +void Parallaction::showLabel(Label &label) { + label.resetPosition(); + _jDrawLabel = addJob(kJobDisplayLabel, (void*)&label, kPriority0); + _jEraseLabel = addJob(kJobEraseLabel, (void*)&label, kPriority20); +} + +void Parallaction::hideLabel(uint priority) { + + if (!_jDrawLabel) + return; + + removeJob(_jDrawLabel); + _jDrawLabel = 0; + + if (priority == kPriority99) { + // remove job immediately + removeJob(_jEraseLabel); + _jEraseLabel = 0; + } else { + // schedule job for deletion + addJob(kJobWaitRemoveJob, _jEraseLabel, priority); + } + +} + void Parallaction::processInput(InputData *data) { Zone *z; @@ -403,19 +387,12 @@ void Parallaction::processInput(InputData *data) { switch (data->_event) { case kEvEnterZone: debugC(2, kDebugInput, "processInput: kEvEnterZone"); - _gfx->_labelPosition[1].x = -1000; - _gfx->_labelPosition[1].y = -1000; - _gfx->_labelPosition[0].x = -1000; - _gfx->_labelPosition[0].y = -1000; - _jDrawLabel = addJob(&jobDisplayLabel, (void*)data->_label, kPriority0); - _jEraseLabel = addJob(&jobEraseLabel, (void*)data->_label, kPriority20); + showLabel(*data->_label); break; case kEvExitZone: debugC(2, kDebugInput, "processInput: kEvExitZone"); - removeJob(_jDrawLabel); - addJob(&jobWaitRemoveJob, _jEraseLabel, kPriority15); - _jDrawLabel = NULL; + hideLabel(kPriority15); break; case kEvAction: @@ -433,15 +410,12 @@ void Parallaction::processInput(InputData *data) { case kEvOpenInventory: _procCurrentHoverItem = -1; _hoverZone = NULL; - if (_jDrawLabel != 0) { - removeJob(_jDrawLabel); - _jDrawLabel = NULL; - addJob(&jobWaitRemoveJob, _jEraseLabel, kPriority2); + hideLabel(kPriority2); + if (hitZone(kZoneYou, _mousePos.x, _mousePos.y) == 0) { + changeCursor(kCursorArrow); } - if (hitZone(kZoneYou, _mousePos.x, _mousePos.y) == 0) - changeCursor(kCursorArrow); removeJob(_jRunScripts); - _jDrawInventory = addJob(&jobShowInventory, 0, kPriority2); + _jDrawInventory = addJob(kJobShowInventory, 0, kPriority2); openInventory(); break; @@ -451,8 +425,8 @@ void Parallaction::processInput(InputData *data) { // activates item changeCursor(data->_inventoryIndex); } - _jRunScripts = addJob(&jobRunScripts, 0, kPriority15); - addJob(&jobHideInventory, 0, kPriority20); + _jRunScripts = addJob(kJobRunScripts, 0, kPriority15); + addJob(kJobHideInventory, 0, kPriority20); removeJob(_jDrawInventory); break; @@ -469,7 +443,7 @@ void Parallaction::processInput(InputData *data) { if (_char._ani._flags & kFlagsRemove) break; if ((_char._ani._flags & kFlagsActive) == 0) break; WalkNodeList *v4 = _char._builder.buildPath(data->_mousePos.x, data->_mousePos.y); - addJob(&jobWalk, v4, kPriority19); + addJob(kJobWalk, v4, kPriority19); _engineFlags |= kEngineWalking; // inhibits processing of input until walking is over } break; @@ -662,11 +636,7 @@ void Parallaction::changeCursor(int32 index) { debugC(1, kDebugInput, "changeCursor(%i), label: %p", index, (const void*)_jDrawLabel); - if (_jDrawLabel != NULL) { - removeJob(_jDrawLabel); - addJob(&jobWaitRemoveJob, _jEraseLabel, kPriority15 ); - _jDrawLabel = NULL; - } + hideLabel(kPriority15); _activeItem._id = 0; @@ -674,7 +644,7 @@ void Parallaction::changeCursor(int32 index) { _activeItem._id = _inventory[index]._id; } - _gfx->setMousePointer(index); + setMousePointer(index); return; } @@ -682,7 +652,7 @@ void Parallaction::changeCursor(int32 index) { void Parallaction::freeCharacter() { - debugC(3, kDebugLocation, "freeCharacter()"); + debugC(1, kDebugExec, "freeCharacter()"); if (!IS_DUMMY_CHARACTER(_characterName)) { if (_objectsNames) @@ -697,9 +667,7 @@ void Parallaction::freeCharacter() { delete _char._talk; _char._talk = NULL; - _gfx->freeStaticCnv(_char._head); - if (_char._head) - delete _char._head; + delete _char._head; _char._head = NULL; if (_char._objs) @@ -710,96 +678,49 @@ void Parallaction::freeCharacter() { return; } -void Parallaction::changeCharacter(const char *name) { - debugC(1, kDebugLocation, "changeCharacter(%s)", name); - - char baseName[20]; - if (IS_MINI_CHARACTER(name)) { - strcpy(baseName, name+4); - } else { - strcpy(baseName, name); - } - - char fullName[20]; - strcpy(fullName, name); - if (_engineFlags & kEngineTransformedDonna) - strcat(fullName, "tras"); - - if (scumm_stricmp(fullName, _characterName1)) { - - // freeCharacter takes responsibility for checking - // character for sanity before memory is freed - freeCharacter(); - - Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_LANG_MULT) ? "disk1" : "disk0"); - _char._ani._cnv = _disk->loadFrames(fullName); - - if (!IS_DUMMY_CHARACTER(name)) { - if (getPlatform() == Common::kPlatformAmiga && (getFeatures() & GF_LANG_MULT)) - _disk->selectArchive("disk0"); - _char._head = _disk->loadHead(baseName); - _char._talk = _disk->loadTalk(baseName); - _char._objs = _disk->loadObjects(baseName); - _objectsNames = _disk->loadTable(baseName); - - _soundMan->playCharacterMusic(name); - - if (!(getFeatures() & GF_DEMO)) - parseLocation("common"); - } - - if (!oldArchive.empty()) - _disk->selectArchive(oldArchive); - } - - strcpy(_characterName1, fullName); - - debugC(1, kDebugLocation, "changeCharacter() done"); - - return; -} /* helper function to provide *descending* ordering of the job list (higher priorities values comes first in the list) */ int compareJobPriority(const JobPointer &j1, const JobPointer &j2) { - return (j1->_tag >= j2->_tag ? -1 : 1); + return (j1->_job->_tag >= j2->_job->_tag ? -1 : 1); } -Job *Parallaction::addJob(JobFn fn, void *parm, uint16 tag) { - debugC(3, kDebugJobs, "addJob(%i)", tag); +Job *Parallaction::addJob(uint functionId, void *parm, uint16 tag) { + debugC(9, kDebugExec, "addJob(%i)", tag); Job *v8 = new Job; v8->_parm = parm; - v8->_fn = fn; v8->_tag = tag; v8->_finished = 0; v8->_count = 0; - _jobs.insertSorted(v8, compareJobPriority); + JobOpcode *op = createJobOpcode(functionId, v8); + + _jobs.insertSorted(op, compareJobPriority); return v8; } void Parallaction::removeJob(Job *j) { - debugC(3, kDebugJobs, "addJob(%i)", j->_tag); + debugC(9, kDebugExec, "addJob(%i)", j->_tag); j->_finished = 1; return; } void Parallaction::pauseJobs() { - debugC(3, kDebugJobs, "pausing jobs execution"); + debugC(9, kDebugExec, "pausing jobs execution"); _engineFlags |= kEnginePauseJobs; return; } void Parallaction::resumeJobs() { - debugC(3, kDebugJobs, "resuming jobs execution"); + debugC(9, kDebugExec, "resuming jobs execution"); _engineFlags &= ~kEnginePauseJobs; return; @@ -811,7 +732,8 @@ void Parallaction::runJobs() { JobList::iterator it = _jobs.begin(); while (it != _jobs.end()) { - if ((*it)->_finished == 1) + Job *job = (*it)->_job; + if (job->_finished == 1) it = _jobs.erase(it); else it++; @@ -819,8 +741,9 @@ void Parallaction::runJobs() { it = _jobs.begin(); while (it != _jobs.end()) { - debugC(9, kDebugJobs, "runJobs: %i", (*it)->_tag); - (*(*it)->_fn)((*it)->_parm, (*it)); + Job *job = (*it)->_job; + debugC(9, kDebugExec, "runJobs: %i", job->_tag); + (*(*it))(); it++; } @@ -828,66 +751,317 @@ void Parallaction::runJobs() { return; } -// this Job uses a static counter to delay removal -// and is in fact only used to remove jEraseLabel jobs -// -void jobWaitRemoveJob(void *parm, Job *j) { - Job *arg = (Job*)parm; - static uint16 count = 0; - debugC(3, kDebugJobs, "jobWaitRemoveJob: count = %i", count); - _engineFlags |= kEngineBlockInput; +void Parallaction::pushParserTables(OpcodeSet *opcodes, Table *statements) { + _opcodes.push(_currentOpcodes); + _statements.push(_currentStatements); + + _currentOpcodes = opcodes; + _currentStatements = statements; +} + +void Parallaction::popParserTables() { + assert(_opcodes.size() > 0); + + _currentOpcodes = _opcodes.pop(); + _currentStatements = _statements.pop(); +} + +void Parallaction::parseStatement() { + assert(_currentOpcodes != 0); + + _lookup = _currentStatements->lookup(_tokens[0]); + + debugC(9, kDebugParser, "parseStatement: %s (lookup = %i)", _tokens[0], _lookup); + + (*(*_currentOpcodes)[_lookup])(); +} + + + + +Animation *Parallaction::findAnimation(const char *name) { + + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) + if (!scumm_stricmp((*it)->_label._text, name)) return *it; + + return NULL; +} + +void Parallaction::freeAnimations() { + _animations.clear(); + return; +} + +int compareAnimationZ(const AnimationPointer &a1, const AnimationPointer &a2) { + if (a1->_z == a2->_z) return 0; + return (a1->_z < a2->_z ? -1 : 1); +} + +void Parallaction::sortAnimations() { + _char._ani._z = _char._ani.height() + _char._ani._top; + _animations.sort(compareAnimationZ); + return; +} + - count++; - if (count == 2) { - count = 0; - _vm->removeJob(arg); - _engineFlags &= ~kEngineBlockInput; - j->_finished = 1; +void Parallaction::allocateLocationSlot(const char *name) { + // WORKAROUND: the original code erroneously incremented + // _currentLocationIndex, thus producing inconsistent + // savegames. This workaround modified the following loop + // and if-statement, so the code exactly matches the one + // in Big Red Adventure. + _currentLocationIndex = -1; + uint16 _di = 0; + while (_locationNames[_di][0] != '\0') { + if (!scumm_stricmp(_locationNames[_di], name)) { + _currentLocationIndex = _di; + } + _di++; } + if (_di == 120) + error("No more location slots available. Please report this immediately to ScummVM team."); + + if (_currentLocationIndex == -1) { + strcpy(_locationNames[_numLocations], name); + _currentLocationIndex = _numLocations; + + _numLocations++; + _locationNames[_numLocations][0] = '\0'; + _localFlags[_numLocations] = 0; + } else { + _localFlags[_currentLocationIndex] |= kFlagsVisited; // 'visited' + } +} + + + +void Parallaction::freeLocation() { + debugC(2, kDebugExec, "freeLocation"); + + _soundMan->stopSfx(0); + _soundMan->stopSfx(1); + _soundMan->stopSfx(2); + _soundMan->stopSfx(3); + + _localFlagNames->clear(); + + _location._walkNodes.clear(); + + freeZones(); + freeAnimations(); + + if (_location._comment) { + free(_location._comment); + } + _location._comment = NULL; + + _location._commands.clear(); + _location._aCommands.clear(); + return; } -Table::Table(uint32 size) : _size(size), _used(0), _disposeMemory(true) { - _data = (char**)malloc(sizeof(char*)*size); + +void Parallaction::freeBackground() { + + if (!_backgroundInfo) + return; + + _backgroundInfo->bg.free(); + _backgroundInfo->mask.free(); + _backgroundInfo->path.free(); + + _pathBuffer = 0; + +} + +void Parallaction::setBackground(const char* name, const char* mask, const char* path) { + + _disk->loadScenery(*_backgroundInfo, name, mask, path); + + _gfx->setPalette(_backgroundInfo->palette); + _gfx->_palette.clone(_backgroundInfo->palette); + _gfx->setBackground(&_backgroundInfo->bg); + + if (_backgroundInfo->mask.data) + _gfx->setMask(&_backgroundInfo->mask); + + if (_backgroundInfo->path.data) + _pathBuffer = &_backgroundInfo->path; + + return; } -Table::Table(uint32 size, const char **data) : _size(size), _used(size), _disposeMemory(false) { - _data = const_cast<char**>(data); +void Parallaction::showLocationComment(const char *text, bool end) { + + _gfx->setFont(_dialogueFont); + + int16 w, h; + _gfx->getStringExtent(const_cast<char*>(text), 130, &w, &h); + + Common::Rect r(w + (end ? 5 : 10), h + 5); + r.moveTo(5, 5); + + _gfx->floodFill(Gfx::kBitFront, r, 0); + r.grow(-2); + _gfx->floodFill(Gfx::kBitFront, r, 1); + _gfx->displayWrappedString(const_cast<char*>(text), 3, 5, 0, 130); + + _gfx->updateScreen(); + + return; } -Table::~Table() { +void Parallaction::switchBackground(const char* background, const char* mask) { +// printf("switchBackground(%s)", name); + + Palette pal; - if (!_disposeMemory) return; + uint16 v2 = 0; + if (!scumm_stricmp(background, "final")) { + _gfx->clearScreen(Gfx::kBitBack); + for (uint16 _si = 0; _si <= 32; _si++) { + pal.setEntry(_si, v2, v2, v2); + v2 += 4; + } - for (uint32 i = 0; i < _used; i++) - free(_data[i]); + g_system->delayMillis(20); + _gfx->setPalette(pal); + _gfx->updateScreen(); + } - free(_data); + setBackground(background, mask, mask); + return; } -void Table::addData(const char* s) { - if (!(_used < _size)) - error("Table overflow"); +void Parallaction::showSlide(const char *name) { - _data[_used++] = strdup(s); + BackgroundInfo info; + + _disk->loadSlide(info, name); + + // TODO: avoid using screen buffers for displaying slides. Using a generic buffer + // allows for positioning of graphics as needed by Big Red Adventure. + // The main problem lies with menu, which relies on multiple buffers, mainly because + // it is crappy code. + _gfx->setBackground(&info.bg); + _gfx->setPalette(info.palette); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + info.bg.free(); + info.mask.free(); + info.path.free(); + + return; } -int16 Table::lookup(const char* s) { - for (uint16 i = 0; i < _used; i++) { - if (!scumm_stricmp(_data[i], s)) return i + 1; + +// displays transition before a new location +// +// clears screen (in white??) +// shows location comment (if any) +// waits for mouse click +// fades towards game palette +// +void Parallaction::doLocationEnterTransition() { + debugC(2, kDebugExec, "doLocationEnterTransition"); + + if (_localFlags[_currentLocationIndex] & kFlagsVisited) { + debugC(2, kDebugExec, "skipping location transition"); + return; // visited + } + + Palette pal(_gfx->_palette); + pal.makeGrayscale(); + _gfx->setPalette(pal); + + jobRunScripts(NULL, NULL); + jobEraseAnimations(NULL, NULL); + jobDisplayAnimations(NULL, NULL); + + _gfx->swapBuffers(); + _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); + + showLocationComment(_location._comment, false); + waitUntilLeftClick(); + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront ); + + // fades maximum intensity palette towards approximation of main palette + for (uint16 _si = 0; _si<6; _si++) { + pal.fadeTo(_gfx->_palette, 4); + _gfx->setPalette(pal); + waitTime( 1 ); + _gfx->updateScreen(); + } + + debugC(2, kDebugExec, "doLocationEnterTransition completed"); + + return; +} + + + +Zone *Parallaction::findZone(const char *name) { + + for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) { + if (!scumm_stricmp((*it)->_label._text, name)) return *it; } - return -1; + return findAnimation(name); } + +void Parallaction::freeZones() { + debugC(2, kDebugExec, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); + + ZoneList::iterator it = _zones.begin(); + + while ( it != _zones.end() ) { + + Zone* z = *it; + + // 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 hitZone. + if (((z->_top == -1) || + ((z->_left == -2) && ( + (((z->_type & 0xFFFF) == kZoneMerge) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj1)) != 0) || (isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj2)) != 0))) || + (((z->_type & 0xFFFF) == kZoneGet) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.get->_icon)) != 0))) + ))) && + ((_engineFlags & kEngineQuit) == 0)) { + + debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_label._text); + + it++; + + } else + + it = _zones.erase(it); + + } + + return; +} + + + + + + + + + + + + } // namespace Parallaction diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 31b125c92a..c0975d4c85 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -27,21 +27,18 @@ #define PARALLACTION_H #include "common/str.h" - +#include "common/stack.h" +#include "common/array.h" #include "engines/engine.h" #include "parallaction/defs.h" #include "parallaction/inventory.h" #include "parallaction/parser.h" +#include "parallaction/objects.h" #include "parallaction/disk.h" #include "parallaction/walk.h" -#include "parallaction/zone.h" -namespace GUI { - class ListWidget; - class CommandSender; -} extern OSystem *g_system; @@ -50,10 +47,10 @@ namespace Parallaction { enum { kDebugDisk = 1 << 0, kDebugWalk = 1 << 1, - kDebugLocation = 1 << 2, + kDebugParser = 1 << 2, kDebugDialogue = 1 << 3, kDebugGraphics = 1 << 4, - kDebugJobs = 1 << 5, + kDebugExec = 1 << 5, kDebugInput = 1 << 6, kDebugAudio = 1 << 7, kDebugMenu = 1 << 8 @@ -93,7 +90,8 @@ enum { kPriority18 = 18, kPriority19 = 19, kPriority20 = 20, - kPriority21 = 21 + kPriority21 = 21, + kPriority99 = 99 // fictitious priority value used as a flag to handle quick label deletion }; enum { @@ -143,32 +141,23 @@ struct PARALLACTIONGameDescription; struct Job; -typedef void (*JobFn)(void*, Job*); struct Job { uint16 _count; // # of executions left uint16 _tag; // used for ordering uint16 _finished; void * _parm; - JobFn _fn; public: - Job() : _count(0), _tag(0), _finished(0), _parm(NULL), _fn(NULL) { + Job() : _count(0), _tag(0), _finished(0), _parm(NULL) { } }; -typedef Job* JobPointer; -typedef ManagedList<JobPointer> JobList; - -typedef void (*callable)(void*); extern uint16 _mouseButtons; extern uint16 _score; extern uint16 _language; -extern Zone *_activeZone; extern uint32 _engineFlags; -extern callable _callables[]; -extern uint32 _localFlags[]; extern Command *_forwardedCommands[]; extern char _forwardedAnimationNames[][20]; extern uint16 _numForwards; @@ -200,19 +189,6 @@ extern const char *_minidrkiName; void waitUntilLeftClick(); -void jobRemovePickedItem(void*, Job *j); -void jobDisplayDroppedItem(void*, Job *j); -void jobToggleDoor(void*, Job *j); -void jobEraseAnimations(void *arg_0, Job *j); -void jobWalk(void*, Job *j); -void jobRunScripts(void*, Job *j); -void jobDisplayAnimations(void*, Job *j); -void jobDisplayLabel(void *parm, Job *j); -void jobWaitRemoveJob(void *parm, Job *j); -void jobShowInventory(void *parm, Job *j); -void jobHideInventory(void *parm, Job *j); -void jobEraseLabel(void *parm, Job *j); - class Debugger; @@ -221,12 +197,10 @@ class Menu; class SoundMan; - struct Location { Common::Point _startPosition; uint16 _startFrame; - WalkNodeList _walkNodes; char _name[100]; CommandList _aCommands; @@ -234,13 +208,18 @@ struct Location { char *_comment; char *_endComment; + // NS specific + WalkNodeList _walkNodes; + + // BRA specific + CommandList _escapeCommands; }; struct Character { Animation _ani; - StaticCnv *_head; - Cnv *_talk; - Cnv *_objs; + Graphics::Surface *_head; + Frames *_talk; + Frames *_objs; PathBuilder _builder; Character() : _builder(&_ani) { @@ -256,31 +235,133 @@ struct Character { _ani._frame = 0; _ani._flags = kFlagsActive | kFlagsNoName; _ani._type = kZoneYou; - _ani._label._cnv._data0 = NULL; + _ani._label._cnv.pixels = NULL; _ani._label._text = strdup("yourself"); } + void getFoot(Common::Point &foot) { + foot.x = _ani._left + _ani.width() / 2; + foot.y = _ani._top + _ani.height(); + } + + void setFoot(const Common::Point &foot) { + _ani._left = foot.x - _ani.width() / 2; + _ani._top = foot.y - _ani.height(); + } + + +}; + + + + +struct BackgroundInfo { + uint width; + uint height; + + Graphics::Surface bg; + MaskBuffer mask; + PathBuffer path; + + Palette palette; }; +class Opcode { + +public: + virtual void operator()() const = 0; + virtual ~Opcode() { } +}; -class Table { +template <class T> +class OpcodeImpl : public Opcode { - char **_data; - uint16 _size; - uint16 _used; - bool _disposeMemory; + typedef void (T::*Fn)(); + + T* _instance; + Fn _fn; public: - Table(uint32 size); - Table(uint32 size, const char** data); + OpcodeImpl(T* instance, const Fn &fn) : _instance(instance), _fn(fn) { } + + void operator()() const { + (_instance->*_fn)(); + } + +}; + +typedef Common::Array<const Opcode*> OpcodeSet; - ~Table(); +class JobOpcode { - void addData(const char* s); +public: + Job *_job; - int16 lookup(const char* s); + JobOpcode(Job *job) : _job(job) { } + + virtual void operator()() const = 0; + virtual ~JobOpcode() { + delete _job; + } }; +template <class T> +class OpcodeImpl2 : public JobOpcode { + + typedef void (T::*Fn)(void *, Job*); + + T* _instance; + Fn _fn; + +public: + OpcodeImpl2(T* instance, const Fn &fn, Job* job) : JobOpcode(job), _instance(instance), _fn(fn) { } + + void operator()() const { + (_instance->*_fn)(_job->_parm, _job); + } + +}; + +typedef JobOpcode* JobPointer; +typedef ManagedList<JobPointer> JobList; + +enum Jobs { + kJobDisplayAnimations = 0, + kJobEraseAnimations = 1, + kJobDisplayDroppedItem = 2, + kJobRemovePickedItem = 3, + kJobRunScripts = 4, + kJobWalk = 5, + kJobDisplayLabel = 6, + kJobEraseLabel = 7, + kJobWaitRemoveJob = 8, + kJobToggleDoor = 9, + + // NS specific + kJobShowInventory = 10, + kJobHideInventory, + + // BRA specific + kJobEraseSubtitle = 10, + kJobDisplaySubtitle, + kJobWaitRemoveSubtitleJob, + kJobPauseSfx, + kJobStopFollower, + kJobScroll +}; + + +#define DECLARE_UNQUALIFIED_ZONE_PARSER(sig) void locZoneParse_##sig() +#define DECLARE_UNQUALIFIED_ANIM_PARSER(sig) void locAnimParse_##sig() +#define DECLARE_UNQUALIFIED_COMMAND_PARSER(sig) void cmdParse_##sig() +#define DECLARE_UNQUALIFIED_LOCATION_PARSER(sig) void locParse_##sig() +#define DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(sig) void instParse_##sig() + +#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op() +#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op() + + +#define NUM_LOCATIONS 120 class Parallaction : public Engine { friend class Debugger; @@ -291,31 +372,50 @@ public: ~Parallaction(); int init(); - int go(); - void loadGame(); - void saveGame(); + virtual void loadGame() = 0; + virtual void saveGame() = 0; uint16 updateInput(); void waitTime(uint32 t); - void parseLocation(const char *filename); + uint _lookup; + Common::Stack<OpcodeSet*> _opcodes; + Common::Stack<Table*> _statements; + OpcodeSet *_currentOpcodes; + Table *_currentStatements; + void pushParserTables(OpcodeSet *opcodes, Table* statements); + void popParserTables(); + void parseStatement(); + + OpcodeSet _commandOpcodes; + + struct { + Command *cmd; + Zone *z; + } _cmdRunCtxt; + + OpcodeSet _instructionOpcodes; + + struct { + Animation *a; + InstructionList::iterator inst; + uint16 modCounter; + bool suspend; + } _instRunCtxt; + + void changeCursor(int32 index); void showCursor(bool visible); - void changeCharacter(const char *name); - - char *parseComment(Script &script); - char *parseDialogueString(Script &script); - Dialogue *parseDialogue(Script &script); - Job *addJob(JobFn fn, void *parm, uint16 tag); + Job *addJob(uint functionId, void *parm, uint16 tag); void removeJob(Job *j); void pauseJobs(); void resumeJobs(); void runJobs(); + virtual JobOpcode* createJobOpcode(uint functionId, Job *job) = 0; - void setPath(byte *path); void finalizeWalk(WalkNodeList *list); int16 selectWalkFrame(const Common::Point& pos, const WalkNode* from); void clipMove(Common::Point& pos, const WalkNode* from); @@ -333,16 +433,20 @@ public: void sortAnimations(); void freeAnimations(); + void showSlide(const char *name); + void setBackground(const char *background, const char *mask, const char *path); + void freeBackground(); + Table *_globalTable; Table *_objectsNames; Table *_zoneTypeNames; Table *_zoneFlagNames; - Table *_commandsNames; Table *_callableNames; - Table *_instructionNames; Table *_localFlagNames; + void showLabel(Label &label); + void hideLabel(uint priority); public: int getGameType() const; @@ -359,21 +463,18 @@ public: int32 _screenHeight; int32 _screenSize; - int32 _screenMaskWidth; - int32 _screenMaskSize; - int32 _screenPathWidth; - int32 _screenPathSize; + PathBuffer *_pathBuffer; SoundMan *_soundMan; Gfx* _gfx; - Menu* _menu; Disk* _disk; Character _char; char _characterName[30]; - char _locationNames[120][32]; + uint32 _localFlags[NUM_LOCATIONS]; + char _locationNames[NUM_LOCATIONS][32]; int16 _currentLocationIndex; uint16 _numLocations; Location _location; @@ -382,9 +483,16 @@ public: Common::Point _mousePos; + Zone *_activeZone; + ZoneList _zones; AnimationList _animations; + Font *_labelFont; + Font *_menuFont; + Font *_dialogueFont; + + protected: // data Debugger *_debugger; @@ -397,8 +505,6 @@ protected: // data Label* _label; }; - bool _skipMenu; - bool _mouseHidden; // input-only @@ -422,11 +528,15 @@ protected: // data bool _hasLocationSound; char _locationSound[50]; + BackgroundInfo *_backgroundInfo; + + Job *_jDrawLabel; + Job *_jEraseLabel; + Zone *_hoverZone; protected: // members bool detectGame(void); - void initGame(); void initGlobals(); void runGame(); uint32 getElapsedTime(); @@ -435,34 +545,20 @@ protected: // members InputData *translateInput(); void processInput(InputData*); - int buildSaveFileList(Common::StringList& l); - int selectSaveFile(uint16 arg_0, const char* caption, const char* button); - void doLoadGame(uint16 slot); - void doSaveGame(uint16 slot, const char* name); - void doLocationEnterTransition(); - void changeLocation(char *location); - void showSlide(const char *name); - void resolveLocationForwards(); + virtual void changeLocation(char *location) = 0; + virtual void changeCharacter(const char *name) = 0; + void allocateLocationSlot(const char *name); + void finalizeLocationParsing(); void switchBackground(const char* background, const char* mask); void freeLocation(); + void showLocationComment(const char *text, bool end); - void parseZone(Script &script, ZoneList &list, char *name); - void parseZoneTypeBlock(Script &script, Zone *z); void displayCharacterComment(ExamineData *data); void displayItemComment(ExamineData *data); - void parseWalkNodes(Script& script, WalkNodeList &list); - void initWalk(); uint16 checkDoor(); - Animation * parseAnimation(Script &script, AnimationList &list, char *name); - void parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals); - void loadProgram(Animation *a, char *filename); - LValue getLValue(Instruction *inst, char *str, LocalVariable *locals, Animation *a); - - void parseCommands(Script &script, CommandList&); - void freeCharacter(); int addInventoryItem(uint16 item); @@ -473,6 +569,23 @@ protected: // members public: virtual void callFunction(uint index, void* parm) { } + virtual void renderLabel(Graphics::Surface *cnv, char *text) { } + virtual void setMousePointer(int16 index) = 0; + + + virtual void parseLocation(const char* name) = 0; + + virtual void jobDisplayAnimations(void*, Job *j) = 0; + virtual void jobEraseAnimations(void *arg_0, Job *j) = 0; + virtual void jobRunScripts(void*, Job *j) = 0; + virtual void jobDisplayDroppedItem(void*, Job *j) = 0; + virtual void jobRemovePickedItem(void*, Job *j) = 0; + virtual void jobToggleDoor(void*, Job *j) = 0; + virtual void jobWalk(void*, Job *j) = 0; + virtual void jobDisplayLabel(void *parm, Job *j) = 0; + virtual void jobEraseLabel(void *parm, Job *j) = 0; + virtual void jobWaitRemoveJob(void *parm, Job *j) = 0; + public: const char **_zoneFlagNamesRes; @@ -483,21 +596,54 @@ public: }; + class Parallaction_ns : public Parallaction { public: Parallaction_ns(OSystem* syst) : Parallaction(syst) { } - ~Parallaction_ns() { } + ~Parallaction_ns(); int init(); + int go(); public: typedef void (Parallaction_ns::*Callable)(void*); virtual void callFunction(uint index, void* parm); + void renderLabel(Graphics::Surface *cnv, char *text); + void setMousePointer(int16 index); + + void initJobs(); + + typedef void (Parallaction_ns::*JobFn)(void*, Job*); + + const JobFn *_jobsFn; + JobOpcode* createJobOpcode(uint functionId, Job *job); + + void loadGame(); + void saveGame(); + private: - void initResources(); + Menu* _menu; + + void initFonts(); + void freeFonts(); + +private: + void changeLocation(char *location); + void changeCharacter(const char *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 _mouseArrow[256]; + Graphics::Surface *_mouseComposedArrow; static const Callable _dosCallables[25]; static const Callable _amigaCallables[25]; @@ -536,26 +682,266 @@ private: void _c_HBOn(void*); const Callable *_callables; + +protected: + void jobDisplayAnimations(void*, Job *j); + void jobEraseAnimations(void *arg_0, Job *j); + void jobRunScripts(void*, Job *j); + void jobDisplayDroppedItem(void*, Job *j); + void jobRemovePickedItem(void*, Job *j); + void jobToggleDoor(void*, Job *j); + void jobWalk(void*, Job *j); + void jobDisplayLabel(void *parm, Job *j); + void jobEraseLabel(void *parm, Job *j); + void jobWaitRemoveJob(void *parm, Job *j); + void jobShowInventory(void *parm, Job *j); + void jobHideInventory(void *parm, Job *j); + + // location parser + OpcodeSet _locationParsers; + OpcodeSet _locationZoneParsers; + OpcodeSet _locationAnimParsers; + OpcodeSet _commandParsers; + Table *_commandsNames; + Table *_locationStmt; + Table *_locationZoneStmt; + Table *_locationAnimStmt; + + struct LocationParserContext { + bool end; + + const char *filename; + Script *script; + Zone *z; + Animation *a; + int nextToken; + CommandList *list; + bool endcommands; + Command *cmd; + + // BRA specific + int numZones; + } _locParseCtxt; + + DECLARE_UNQUALIFIED_LOCATION_PARSER(invalid); + DECLARE_UNQUALIFIED_LOCATION_PARSER(endlocation); + DECLARE_UNQUALIFIED_LOCATION_PARSER(location); + DECLARE_UNQUALIFIED_LOCATION_PARSER(disk); + DECLARE_UNQUALIFIED_LOCATION_PARSER(nodes); + DECLARE_UNQUALIFIED_LOCATION_PARSER(zone); + DECLARE_UNQUALIFIED_LOCATION_PARSER(animation); + DECLARE_UNQUALIFIED_LOCATION_PARSER(localflags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(commands); + DECLARE_UNQUALIFIED_LOCATION_PARSER(acommands); + DECLARE_UNQUALIFIED_LOCATION_PARSER(flags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(comment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(endcomment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(sound); + DECLARE_UNQUALIFIED_LOCATION_PARSER(music); + DECLARE_UNQUALIFIED_LOCATION_PARSER(redundant); + DECLARE_UNQUALIFIED_ZONE_PARSER(invalid); + DECLARE_UNQUALIFIED_ZONE_PARSER(limits); + DECLARE_UNQUALIFIED_ZONE_PARSER(moveto); + DECLARE_UNQUALIFIED_ZONE_PARSER(type); + DECLARE_UNQUALIFIED_ZONE_PARSER(commands); + DECLARE_UNQUALIFIED_ZONE_PARSER(label); + DECLARE_UNQUALIFIED_ZONE_PARSER(flags); + DECLARE_UNQUALIFIED_ZONE_PARSER(endzone); + DECLARE_UNQUALIFIED_ANIM_PARSER(invalid); + DECLARE_UNQUALIFIED_ANIM_PARSER(script); + DECLARE_UNQUALIFIED_ANIM_PARSER(commands); + DECLARE_UNQUALIFIED_ANIM_PARSER(type); + DECLARE_UNQUALIFIED_ANIM_PARSER(label); + DECLARE_UNQUALIFIED_ANIM_PARSER(flags); + DECLARE_UNQUALIFIED_ANIM_PARSER(file); + DECLARE_UNQUALIFIED_ANIM_PARSER(position); + DECLARE_UNQUALIFIED_ANIM_PARSER(moveto); + DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); + DECLARE_UNQUALIFIED_COMMAND_PARSER(invalid); + DECLARE_UNQUALIFIED_COMMAND_PARSER(flags); + DECLARE_UNQUALIFIED_COMMAND_PARSER(animation); + DECLARE_UNQUALIFIED_COMMAND_PARSER(zone); + DECLARE_UNQUALIFIED_COMMAND_PARSER(location); + DECLARE_UNQUALIFIED_COMMAND_PARSER(drop); + DECLARE_UNQUALIFIED_COMMAND_PARSER(call); + DECLARE_UNQUALIFIED_COMMAND_PARSER(simple); + DECLARE_UNQUALIFIED_COMMAND_PARSER(move); + DECLARE_UNQUALIFIED_COMMAND_PARSER(endcommands); + + virtual void parseGetData(Script &script, Zone *z); + virtual void parseExamineData(Script &script, Zone *z); + virtual void parseDoorData(Script &script, Zone *z); + virtual void parseMergeData(Script &script, Zone *z); + virtual void parseHearData(Script &script, Zone *z); + virtual void parseSpeakData(Script &script, Zone *z); + + void parseLocation(const char *filename); + char *parseComment(Script &script); + char *parseDialogueString(Script &script); + Dialogue *parseDialogue(Script &script); + void parseZone(Script &script, ZoneList &list, char *name); + void parseZoneTypeBlock(Script &script, Zone *z); + void parseWalkNodes(Script& script, WalkNodeList &list); + Animation *parseAnimation(Script &script, AnimationList &list, char *name); + void parseCommands(Script &script, CommandList&); + void parseCommandFlags(); + void createCommand(uint id); + void addCommand(); + void initOpcodes(); + void initParsers(); + + + // program parser + OpcodeSet _instructionParsers; + Table *_instructionNames; + + struct { + bool end; + Animation *a; + Instruction *inst; + LocalVariable *locals; + Program *program; + + // BRA specific + Instruction *openIf; + } _instParseCtxt; + + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(defLocal); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(animation); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(x); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(y); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(z); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(f); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(set); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(move); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(put); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(call); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(sound); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(null); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(endscript); + + void parseInstruction(Animation *a, LocalVariable *locals); + void loadProgram(Animation *a, const char *filename); + void parseLValue(ScriptVar &var, const char *str); + virtual void parseRValue(ScriptVar &var, const char *str); + void wrapLocalVar(LocalVariable *local); + + DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(set); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(get); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); + + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); + }; -class Parallaction_br : public Parallaction { + + +#define NUM_ZONES 100 + +class Parallaction_br : public Parallaction_ns { + + typedef Parallaction_ns Super; public: - Parallaction_br(OSystem* syst) : Parallaction(syst) { } - ~Parallaction_br() { } + Parallaction_br(OSystem* syst) : Parallaction_ns(syst) { } + ~Parallaction_br(); int init(); + int go(); public: typedef void (Parallaction_br::*Callable)(void*); virtual void callFunction(uint index, void* parm); public: + Table *_countersNames; + Table *_audioCommandsNames; const char **_audioCommandsNamesRes; + int _part; + int _progress; + + int _zeta0; + int _zeta1; + int _zeta2; + + int16 _lipSyncVal; + uint _subtitleLipSync; + + Label _subtitle0; + Label _subtitle1; + + Zone *_activeZone2; + + int32 _counters[32]; + + uint32 _zoneFlags[NUM_LOCATIONS][NUM_ZONES]; + private: void initResources(); + void initFonts(); + void freeFonts(); + void initOpcodes(); + void initParsers(); + void initJobs(); + + typedef void (Parallaction_br::*JobFn)(void*, Job*); + const JobFn *_jobsFn; + JobOpcode* createJobOpcode(uint functionId, Job *job); + + + void changeLocation(char *location); + void changeCharacter(const char *name); + + void initPart(); + void freePart(); + void startPart(); + + void setMousePointer(int16 index); + void initCursors(); + + Graphics::Surface *_dinoCursor; + Graphics::Surface *_dougCursor; + Graphics::Surface *_donnaCursor; + Graphics::Surface *_mouseArrow; + + + int showMenu(); + void renderMenuItem(Graphics::Surface &surf, const char *text); + void invertMenuItem(Graphics::Surface &surf); + + void splash(const char *name); static const Callable _dosCallables[6]; @@ -567,6 +953,130 @@ private: void _c_password(void*); const Callable *_callables; + + DECLARE_UNQUALIFIED_LOCATION_PARSER(location); + DECLARE_UNQUALIFIED_LOCATION_PARSER(zone); + DECLARE_UNQUALIFIED_LOCATION_PARSER(animation); + DECLARE_UNQUALIFIED_LOCATION_PARSER(localflags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(flags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(comment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(endcomment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(sound); + DECLARE_UNQUALIFIED_LOCATION_PARSER(music); + DECLARE_UNQUALIFIED_LOCATION_PARSER(redundant); + DECLARE_UNQUALIFIED_LOCATION_PARSER(ifchar); + DECLARE_UNQUALIFIED_LOCATION_PARSER(character); + DECLARE_UNQUALIFIED_LOCATION_PARSER(mask); + DECLARE_UNQUALIFIED_LOCATION_PARSER(path); + DECLARE_UNQUALIFIED_LOCATION_PARSER(escape); + DECLARE_UNQUALIFIED_LOCATION_PARSER(zeta); + DECLARE_UNQUALIFIED_LOCATION_PARSER(null); + DECLARE_UNQUALIFIED_COMMAND_PARSER(ifchar); + DECLARE_UNQUALIFIED_COMMAND_PARSER(endif); + DECLARE_UNQUALIFIED_COMMAND_PARSER(zone); + DECLARE_UNQUALIFIED_COMMAND_PARSER(location); + DECLARE_UNQUALIFIED_COMMAND_PARSER(toggle); + DECLARE_UNQUALIFIED_COMMAND_PARSER(string); + DECLARE_UNQUALIFIED_COMMAND_PARSER(math); + DECLARE_UNQUALIFIED_COMMAND_PARSER(test); + DECLARE_UNQUALIFIED_COMMAND_PARSER(music); + DECLARE_UNQUALIFIED_COMMAND_PARSER(zeta); + DECLARE_UNQUALIFIED_COMMAND_PARSER(swap); + DECLARE_UNQUALIFIED_COMMAND_PARSER(give); + DECLARE_UNQUALIFIED_COMMAND_PARSER(text); + DECLARE_UNQUALIFIED_COMMAND_PARSER(unary); + + void parseLocation(const char* name); + + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(zone); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(color); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(mask); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(print); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(text); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(if_op); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(endif); + + virtual void parseRValue(ScriptVar &var, const char *str); + + DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(character); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(add); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(let); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(music); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(give); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(text); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(part); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave); + DECLARE_UNQUALIFIED_ZONE_PARSER(limits); + DECLARE_UNQUALIFIED_ZONE_PARSER(moveto); + DECLARE_UNQUALIFIED_ZONE_PARSER(type); + DECLARE_UNQUALIFIED_ANIM_PARSER(file); + DECLARE_UNQUALIFIED_ANIM_PARSER(position); + DECLARE_UNQUALIFIED_ANIM_PARSER(moveto); + DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); + + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); + + Job *_jDisplaySubtitle; + Job *_jEraseSubtitle; + void setupSubtitles(char *s, char *s2, int y); + + void jobWaitRemoveLabelJob(void *parm, Job *job); + void jobDisplaySubtitle(void *parm, Job *job); + void jobEraseSubtitle(void *parm, Job *job); + void jobWaitRemoveSubtitleJob(void *parm, Job *job); + void jobPauseSfx(void *parm, Job *job); + void jobStopFollower(void *parm, Job *job); + void jobScroll(void *parm, Job *job); + }; // FIXME: remove global diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 7dcc94d7c6..f2b9626ead 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -24,11 +24,39 @@ */ #include "common/stdafx.h" +#include "common/system.h" + #include "parallaction/parallaction.h" #include "parallaction/sound.h" namespace Parallaction { +enum MenuOptions { + kMenuPart0 = 0, + kMenuPart1 = 1, + kMenuPart2 = 2, + kMenuPart3 = 3, + kMenuPart4 = 4, + kMenuLoadGame = 5, + kMenuQuit = 6 +}; + +const char *partNames[] = { + "PART0", + "PART1", + "PART2", + "PART3", + "PART4" +}; + +const char *partFirstLocation[] = { + "intro", + "museo", + "start", + "bolscoi", + "treno" +}; + int Parallaction_br::init() { // Detect game @@ -43,6 +71,7 @@ int Parallaction_br::init() { if (getGameType() == GType_BRA) { if (getPlatform() == Common::kPlatformPC) { _disk = new DosDisk_br(this); + _disk->setLanguage(2); // NOTE: language is now hardcoded to English. Original used command-line parameters. } else error("unsupported platform for Big Red Adventure"); } else @@ -50,17 +79,311 @@ int Parallaction_br::init() { _soundMan = new DummySoundMan(this); + _activeZone2 = 0; + + initJobs(); initResources(); + initFonts(); + initCursors(); + initOpcodes(); + initParsers(); + + _part = -1; Parallaction::init(); return 0; } +Parallaction_br::~Parallaction_br() { + freeFonts(); + + _dinoCursor->free(); + _dougCursor->free(); + _donnaCursor->free(); + + delete _dinoCursor; + delete _dougCursor; + delete _donnaCursor; + +} + void Parallaction_br::callFunction(uint index, void* parm) { assert(index < 6); // magic value 6 is maximum # of callables for Big Red Adventure (this->*_callables[index])(parm); } +int Parallaction_br::go() { + splash("dyna"); + splash("core"); + + // TODO: load progress value from special save game + _progress = 3; + + while ((_engineFlags & kEngineQuit) == 0) { + +// initCharacter(); + + int option = showMenu(); + switch (option) { + case kMenuQuit: + _engineFlags |= kEngineQuit; + break; + + case kMenuLoadGame: + warning("loadgame not yet implemented"); + break; + + default: + _part = option; + _disk->selectArchive(partNames[_part]); + startPart(); + break; + } + + + runGame(); + + freePart(); +// freeLocation(); +// freeCharacter(); + + } + + return 0; +} + +void Parallaction_br::splash(const char *name) { + + BackgroundInfo info; + + _gfx->clearScreen(Gfx::kBitFront); + + _disk->loadSlide(info, name); + _gfx->setPalette(info.palette); + _gfx->flatBlitCnv(&info.bg, (640 - info.width) >> 1, (400 - info.height) >> 1, Gfx::kBitFront); + _gfx->updateScreen(); + _system->delayMillis(600); + + Palette pal; + for (uint i = 0; i < 64; i++) { + info.palette.fadeTo(pal, 1); + _gfx->setPalette(info.palette); + _gfx->updateScreen(); + _system->delayMillis(20); + } + info.bg.free(); + + return; +} + +#define MENUITEMS_X 250 +#define MENUITEMS_Y 200 + +#define MENUITEM_WIDTH 190 +#define MENUITEM_HEIGHT 18 + +void Parallaction_br::renderMenuItem(Graphics::Surface &surf, const char *text) { + surf.create(MENUITEM_WIDTH, MENUITEM_HEIGHT, 1); + _menuFont->setColor(0); + _menuFont->drawString((byte*)surf.getBasePtr(5, 2), MENUITEM_WIDTH, text); +} + +void Parallaction_br::invertMenuItem(Graphics::Surface &surf) { + for (int i = 0; i < surf.w * surf.h; i++) + ((byte*)surf.pixels)[i] ^= 0xD; +} + +int Parallaction_br::showMenu() { + // TODO: filter menu entries according to progress in game + + _gfx->clearScreen(Gfx::kBitFront); + + BackgroundInfo info; + + Graphics::Surface _menuItems[7]; + + const char *menuStrings[7] = { + "SEE INTRO", + "NEW GAME", + "SAVED GAME", + "EXIT TO DOS", + "PART 2", + "PART 3", + "PART 4" + }; + + MenuOptions options[7] = { + kMenuPart0, + kMenuPart1, + kMenuLoadGame, + kMenuQuit, + kMenuPart2, + kMenuPart3, + kMenuPart4 + }; + + _disk->loadSlide(info, "tbra"); + _gfx->setPalette(info.palette); + _gfx->flatBlitCnv(&info.bg, 20, 50, Gfx::kBitFront); + + int availItems = 4 + _progress; + + for (int i = 0; i < availItems; i++) + renderMenuItem(_menuItems[i], menuStrings[i]); + + int selectedItem = -1, oldSelectedItem = -2; + + setMousePointer(0); + + while (true) { + + if ((_mouseButtons == kMouseLeftUp) && selectedItem >= 0) + break; + + updateInput(); + + if ((_mousePos.x > MENUITEMS_X) && (_mousePos.x < (MENUITEMS_X+MENUITEM_WIDTH)) && (_mousePos.y > MENUITEMS_Y)) { + selectedItem = (_mousePos.y - MENUITEMS_Y) / MENUITEM_HEIGHT; + + if (!(selectedItem < availItems)) + selectedItem = -1; + } else + selectedItem = -1; + + + if (selectedItem != oldSelectedItem) { + + if (selectedItem >= 0 && selectedItem < availItems) + invertMenuItem(_menuItems[selectedItem]); + + if (oldSelectedItem >= 0 && oldSelectedItem < availItems) + invertMenuItem(_menuItems[oldSelectedItem]); + + Common::Rect r(MENUITEM_WIDTH, MENUITEM_HEIGHT); + + for (int i = 0; i < availItems; i++) { + r.moveTo(MENUITEMS_X, MENUITEMS_Y + i * 20); + _gfx->copyRect(Gfx::kBitFront, r, (byte*)_menuItems[i].pixels, _menuItems[i].pitch); + } + + oldSelectedItem = selectedItem; + } + + _gfx->updateScreen(); + _system->delayMillis(20); + } + + _system->showMouse(false); + + info.bg.free(); + + for (int i = 0; i < availItems; i++) + _menuItems[i].free(); + + return options[selectedItem]; +} + + +void Parallaction_br::initFonts() { + + _menuFont = _disk->loadFont("russia"); + _dialogueFont = _disk->loadFont("comic"); + _labelFont = _menuFont; + +} + +void Parallaction_br::freeFonts() { + + delete _menuFont; + delete _dialogueFont; + + return; +} + +void Parallaction_br::initCursors() { + + _dinoCursor = _disk->loadPointer("pointer1"); + _dougCursor = _disk->loadPointer("pointer2"); + _donnaCursor = _disk->loadPointer("pointer3"); + + _mouseArrow = _donnaCursor; + +} + +void Parallaction_br::setMousePointer(int16 index) { + + _system->setMouseCursor((byte*)_mouseArrow->pixels, _mouseArrow->w, _mouseArrow->h, 0, 0, 0); + _system->showMouse(true); + +} + +void Parallaction_br::initPart() { + + memset(_counters, 0, ARRAYSIZE(_counters)); + + _globalTable = _disk->loadTable("global"); + _objectsNames = _disk->loadTable("objects"); + _countersNames = _disk->loadTable("counters"); + +// _disk->loadObjects("icone.ico"); + +} + +void Parallaction_br::freePart() { + + delete _globalTable; + delete _objectsNames; + delete _countersNames; + +} + +void Parallaction_br::startPart() { + + initPart(); + + strcpy(_location._name, partFirstLocation[_part]); + + parseLocation("common"); + parseLocation(_location._name); + +} + +void Parallaction_br::changeLocation(char *location) { + +} + +void Parallaction_br::changeCharacter(const char *name) { + +} + +void Parallaction_br::initJobs() { + + static const JobFn jobs[] = { + &Parallaction_br::jobDisplayAnimations, + &Parallaction_br::jobEraseAnimations, + &Parallaction_br::jobDisplayDroppedItem, + &Parallaction_br::jobRemovePickedItem, + &Parallaction_br::jobRunScripts, + &Parallaction_br::jobWalk, + &Parallaction_br::jobDisplayLabel, + &Parallaction_br::jobEraseLabel, + &Parallaction_br::jobWaitRemoveLabelJob, + &Parallaction_br::jobToggleDoor, + &Parallaction_br::jobEraseSubtitle, + &Parallaction_br::jobDisplaySubtitle, + &Parallaction_br::jobWaitRemoveSubtitleJob, + &Parallaction_br::jobPauseSfx, + &Parallaction_br::jobStopFollower, + &Parallaction_br::jobScroll + }; + + _jobsFn = jobs; +} + +JobOpcode* Parallaction_br::createJobOpcode(uint functionId, Job *job) { + return new OpcodeImpl2<Parallaction_br>(this, _jobsFn[functionId], job); +} + } // namespace Parallaction diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 947cb22a7f..46161c5021 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -24,13 +24,23 @@ */ #include "common/stdafx.h" +#include "common/system.h" + #include "common/config-manager.h" #include "parallaction/parallaction.h" #include "parallaction/sound.h" +#include "parallaction/menu.h" + namespace Parallaction { +#define MOUSEARROW_WIDTH 16 +#define MOUSEARROW_HEIGHT 16 + +#define MOUSECOMBO_WIDTH 32 // sizes for cursor + selected inventory item +#define MOUSECOMBO_HEIGHT 32 + int Parallaction_ns::init() { // Detect game @@ -61,13 +71,103 @@ int Parallaction_ns::init() { _soundMan = new AmigaSoundMan(this); } + initJobs(); initResources(); + initFonts(); + initCursors(); + initOpcodes(); + initParsers(); Parallaction::init(); return 0; } +Parallaction_ns::~Parallaction_ns() { + freeFonts(); + + _mouseComposedArrow->free(); + delete _mouseComposedArrow; + + + delete _commandsNames; + delete _instructionNames; + delete _locationStmt; + +} + + +void Parallaction_ns::freeFonts() { + + delete _dialogueFont; + delete _labelFont; + delete _menuFont; + + return; +} + +void Parallaction_ns::renderLabel(Graphics::Surface *cnv, char *text) { + + if (getPlatform() == Common::kPlatformAmiga) { + cnv->create(_labelFont->getStringWidth(text) + 16, 10, 1); + + _labelFont->setColor(7); + _labelFont->drawString((byte*)cnv->pixels + 1, cnv->w, text); + _labelFont->drawString((byte*)cnv->pixels + 1 + cnv->w * 2, cnv->w, text); + _labelFont->drawString((byte*)cnv->pixels + cnv->w, cnv->w, text); + _labelFont->drawString((byte*)cnv->pixels + 2 + cnv->w, cnv->w, text); + _labelFont->setColor(1); + _labelFont->drawString((byte*)cnv->pixels + 1 + cnv->w, cnv->w, text); + } else { + cnv->create(_labelFont->getStringWidth(text), _labelFont->height(), 1); + _labelFont->drawString((byte*)cnv->pixels, cnv->w, text); + } + +} + +void Parallaction_ns::initCursors() { + + _mouseComposedArrow = _disk->loadPointer("pointer"); + + byte temp[MOUSEARROW_WIDTH*MOUSEARROW_HEIGHT]; + memcpy(temp, _mouseArrow, MOUSEARROW_WIDTH*MOUSEARROW_HEIGHT); + + uint16 k = 0; + for (uint16 i = 0; i < 4; i++) { + for (uint16 j = 0; j < 64; j++) _mouseArrow[k++] = temp[i + j * 4]; + } + + return; +} + +void Parallaction_ns::setMousePointer(int16 index) { + + if (index == kCursorArrow) { // standard mouse pointer + + _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); + _system->showMouse(true); + + } else { + // inventory item pointer + byte *v8 = (byte*)_mouseComposedArrow->pixels; + + // FIXME: destination offseting is not clear + byte* s = _char._objs->getData(getInventoryItemIndex(index)); + byte* d = v8 + 7 + MOUSECOMBO_WIDTH * 7; + + for (uint i = 0; i < INVENTORYITEM_HEIGHT; i++) { + memcpy(d, s, INVENTORYITEM_WIDTH); + + s += INVENTORYITEM_PITCH; + d += MOUSECOMBO_WIDTH; + } + + _system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); + } + + return; +} + void Parallaction_ns::callFunction(uint index, void* parm) { assert(index < 25); // magic value 25 is maximum # of callables for Nippon Safes @@ -75,4 +175,232 @@ void Parallaction_ns::callFunction(uint index, void* parm) { } +int Parallaction_ns::go() { + + _menu = new Menu(this); + _menu->start(); + + char *v4 = strchr(_location._name, '.'); + if (v4) { + *v4 = '\0'; + } + + _globalTable = _disk->loadTable("global"); + + _engineFlags &= ~kEngineChangeLocation; + changeCharacter(_characterName); + + strcpy(_saveData1, _location._name); + parseLocation(_location._name); + + if (_location._startPosition.x != -1000) { + _char._ani._left = _location._startPosition.x; + _char._ani._top = _location._startPosition.y; + _char._ani._frame = _location._startFrame; + _location._startPosition.y = -1000; + _location._startPosition.x = -1000; + }; + + runGame(); + + delete _menu; + + return 0; +} + + +/* + changeLocation handles transitions between locations, and is able to display slides + between one and the other. The input parameter 'location' exists in some flavours: + + 1 - [S].slide.[L]{.[C]} + 2 - [L]{.[C]} + + where: + + [S] is the slide to be shown + [L] is the location to switch to (immediately in case 2, or right after slide [S] in case 1) + [C] is the character to be selected, and is optional + + The routine tells one form from the other by searching for the '.slide.' + + NOTE: there exists one script in which [L] is not used in the case 1, but its use + is commented out, and would definitely crash the current implementation. +*/ +void Parallaction_ns::changeLocation(char *location) { + debugC(1, kDebugExec, "changeLocation(%s)", location); + + _soundMan->playLocationMusic(location); + + // WORKAROUND: this hideLabel has been added to avoid crashes caused by + // execution of label jobs after a location switch. The other workaround in + // Parallaction::runGame should have been rendered useless by this one. + hideLabel(kPriority99); + + _hoverZone = NULL; + if (_engineFlags & kEngineBlockInput) { + changeCursor( kCursorArrow ); + } + + _animations.remove(&_char._ani); + + freeLocation(); + char buf[100]; + strcpy(buf, location); + + Common::StringList list; + char *tok = strtok(location, "."); + while (tok) { + list.push_back(tok); + tok = strtok(NULL, "."); + } + + if (list.size() < 1 || list.size() > 4) + error("changeLocation: ill-formed location string '%s'", location); + + if (list.size() > 1) { + if (list[1] == "slide") { + showSlide(list[0].c_str()); + _gfx->setFont(_menuFont); + _gfx->displayCenteredString(14, _slideText[0]); // displays text on screen + _gfx->updateScreen(); + waitUntilLeftClick(); + + list.remove_at(0); // removes slide name + list.remove_at(0); // removes 'slide' + } + + // list is now only [L].{[C]} (see above comment) + if (list.size() == 2) { + changeCharacter(list[1].c_str()); + strcpy(_characterName, list[1].c_str()); + } + } + + _animations.push_front(&_char._ani); + + strcpy(_saveData1, list[0].c_str()); + parseLocation(list[0].c_str()); + + _char._ani._oldPos.x = -1000; + _char._ani._oldPos.y = -1000; + + _char._ani.field_50 = 0; + if (_location._startPosition.x != -1000) { + _char._ani._left = _location._startPosition.x; + _char._ani._top = _location._startPosition.y; + _char._ani._frame = _location._startFrame; + _location._startPosition.y = -1000; + _location._startPosition.x = -1000; + } + + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); + _gfx->setBlackPalette(); + _gfx->updateScreen(); + + if (_location._commands.size() > 0) { + runCommands(_location._commands); + runJobs(); + _gfx->swapBuffers(); + runJobs(); + _gfx->swapBuffers(); + } + + if (_location._comment) { + doLocationEnterTransition(); + } + + runJobs(); + _gfx->swapBuffers(); + + _gfx->setPalette(_gfx->_palette); + if (_location._aCommands.size() > 0) { + runCommands(_location._aCommands); + } + + if (_hasLocationSound) + _soundMan->playSfx(_locationSound, 0, true); + + debugC(1, kDebugExec, "changeLocation() done"); + + return; + +} + +void Parallaction_ns::changeCharacter(const char *name) { + debugC(1, kDebugExec, "changeCharacter(%s)", name); + + char baseName[20]; + if (IS_MINI_CHARACTER(name)) { + strcpy(baseName, name+4); + } else { + strcpy(baseName, name); + } + + char fullName[20]; + strcpy(fullName, name); + if (_engineFlags & kEngineTransformedDonna) + strcat(fullName, "tras"); + + if (scumm_stricmp(fullName, _characterName1)) { + + // freeCharacter takes responsibility for checking + // character for sanity before memory is freed + freeCharacter(); + + Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_LANG_MULT) ? "disk1" : "disk0"); + _char._ani._cnv = _disk->loadFrames(fullName); + + if (!IS_DUMMY_CHARACTER(name)) { + if (getPlatform() == Common::kPlatformAmiga && (getFeatures() & GF_LANG_MULT)) + _disk->selectArchive("disk0"); + + _char._head = _disk->loadHead(baseName); + _char._talk = _disk->loadTalk(baseName); + _char._objs = _disk->loadObjects(baseName); + _objectsNames = _disk->loadTable(baseName); + + _soundMan->playCharacterMusic(name); + + if (!(getFeatures() & GF_DEMO)) + parseLocation("common"); + } + + if (!oldArchive.empty()) + _disk->selectArchive(oldArchive); + } + + strcpy(_characterName1, fullName); + + debugC(1, kDebugExec, "changeCharacter() done"); + + return; +} + +void Parallaction_ns::initJobs() { + + static const JobFn jobs[] = { + &Parallaction_ns::jobDisplayAnimations, + &Parallaction_ns::jobEraseAnimations, + &Parallaction_ns::jobDisplayDroppedItem, + &Parallaction_ns::jobRemovePickedItem, + &Parallaction_ns::jobRunScripts, + &Parallaction_ns::jobWalk, + &Parallaction_ns::jobDisplayLabel, + &Parallaction_ns::jobEraseLabel, + &Parallaction_ns::jobWaitRemoveJob, + &Parallaction_ns::jobToggleDoor, + &Parallaction_ns::jobShowInventory, + &Parallaction_ns::jobHideInventory + }; + + _jobsFn = jobs; +} + +JobOpcode* Parallaction_ns::createJobOpcode(uint functionId, Job *job) { + return new OpcodeImpl2<Parallaction_ns>(this, _jobsFn[functionId], job); +} + } // namespace Parallaction diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index 44aae6c1cc..dfda083392 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -48,7 +48,7 @@ char *Script::readLine(char *buf, size_t bufSize) { v2 = _input->readSByte(); - if (v2 == 0xA || _input->eos()) break; + if (v2 == 0xA || v2 == 0xD || _input->eos()) break; if (!_input->eos() && _si < bufSize) buf[_si] = v2; } @@ -82,34 +82,6 @@ void Script::seek(int32 offset, int whence) { error("seek not supported on Script streams"); } -// -// a comment can appear both at location and Zone levels -// comments are displayed into rectangles on the screen -// -char *Parallaction::parseComment(Script &script) { - - char _tmp_comment[1000] = "\0"; - char *v194; - - do { - char v190[400]; - v194 = script.readLine(v190, 400); - - v194[strlen(v194)-1] = '\0'; - if (!scumm_stricmp(v194, "endtext")) - break; - - strcat(_tmp_comment, v194); - strcat(_tmp_comment, " "); - } while (true); - - v194 = (char*)malloc(strlen(_tmp_comment)+1); - strcpy(v194, _tmp_comment); - _tmp_comment[0] = '\0'; - - return v194; -} - void clearTokens() { for (uint16 i = 0; i < 20; i++) @@ -119,6 +91,14 @@ void clearTokens() { } +void skip(Script* script, const char* endToken) { + + while (scumm_stricmp(_tokens[0], endToken)) { + fillBuffers(*script, true); + } + +} + // // Scans 's' until one of the stop-chars in 'brk' is found, building a token. // If the routine encounters quotes, it will extract the contained text and diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index aa3929a52c..3d1b32ec3a 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -57,6 +57,9 @@ public: void seek(int32 offset, int whence = SEEK_SET); }; +void skip(Script* script, const char* endToken); + + } // namespace Parallaction #endif diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp new file mode 100644 index 0000000000..94f5b0d790 --- /dev/null +++ b/engines/parallaction/parser_br.cpp @@ -0,0 +1,935 @@ +#include "common/stdafx.h" + +#include "parallaction/parallaction.h" +#include "parallaction/sound.h" + +namespace Parallaction { + +#define CMD_SET 1 +#define CMD_CLEAR 2 +#define CMD_START 3 +#define CMD_SPEAK 4 +#define CMD_GET 5 +#define CMD_LOCATION 6 +#define CMD_OPEN 7 +#define CMD_CLOSE 8 +#define CMD_ON 9 +#define CMD_OFF 10 +#define CMD_CALL 11 +#define CMD_TOGGLE 12 +#define CMD_DROP 13 +#define CMD_QUIT 14 +#define CMD_MOVE 15 +#define CMD_STOP 16 +#define CMD_CHARACTER 17 +#define CMD_FOLLOWME 18 +#define CMD_ONMOUSE 19 +#define CMD_OFFMOUSE 20 +#define CMD_ADD 21 +#define CMD_LEAVE 22 +#define CMD_INC 23 +#define CMD_DEC 24 +#define CMD_TEST 25 +#define CMD_TEST_GT 26 +#define CMD_TEST_LT 27 +#define CMD_LET 28 +#define CMD_MUSIC 29 +#define CMD_FIX 30 +#define CMD_UNFIX 31 +#define CMD_ZETA 32 +#define CMD_SCROLL 33 +#define CMD_SWAP 34 +#define CMD_GIVE 35 +#define CMD_TEXT 36 +#define CMD_PART 37 +#define CMD_TEST_SFX 38 +#define CMD_RETURN 39 +#define CMD_ONSAVE 40 +#define CMD_OFFSAVE 41 + + +#define INST_ON 1 +#define INST_OFF 2 +#define INST_X 3 +#define INST_Y 4 +#define INST_Z 5 +#define INST_F 6 +#define INST_LOOP 7 +#define INST_ENDLOOP 8 +#define INST_SHOW 9 +#define INST_INC 10 +#define INST_DEC 11 +#define INST_SET 12 +#define INST_PUT 13 +#define INST_CALL 14 +#define INST_WAIT 15 +#define INST_START 16 +#define INST_PROCESS 17 +#define INST_MOVE 18 +#define INST_COLOR 19 +#define INST_SOUND 20 +#define INST_MASK 21 +#define INST_PRINT 22 +#define INST_TEXT 23 +#define INST_MUL 24 +#define INST_DIV 25 +#define INST_IF 26 +#define INST_IFEQ 27 +#define INST_IFLT 28 +#define INST_IFGT 29 +#define INST_ENDIF 30 +#define INST_STOP 31 + +#define DECLARE_ZONE_PARSER(sig) void Parallaction_br::locZoneParse_##sig() +#define DECLARE_ANIM_PARSER(sig) void Parallaction_br::locAnimParse_##sig() +#define DECLARE_COMMAND_PARSER(sig) void Parallaction_br::cmdParse_##sig() +#define DECLARE_INSTRUCTION_PARSER(sig) void Parallaction_br::instParse_##sig() +#define DECLARE_LOCATION_PARSER(sig) void Parallaction_br::locParse_##sig() + + +DECLARE_LOCATION_PARSER(location) { + debugC(7, kDebugParser, "LOCATION_PARSER(location) "); + + strcpy(_location._name, _tokens[1]); + + bool flip = false; + int nextToken; + + if (!scumm_stricmp("flip", _tokens[2])) { + flip = true; + nextToken = 3; + } else { + nextToken = 2; + } + + _disk->loadScenery(*_backgroundInfo, _location._name, NULL, NULL); + +// if (flip) { +// flip(); +// } + + _gfx->setBackground(&_backgroundInfo->bg); + _gfx->_palette.clone(_backgroundInfo->palette); + _gfx->setPalette(_backgroundInfo->palette); + + + if (_tokens[nextToken][0] != '\0') { + _char._ani._left = atoi(_tokens[nextToken]); + nextToken++; + _char._ani._top = atoi(_tokens[nextToken]); + nextToken++; + } + + if (_tokens[nextToken][0] != '\0') { + _char._ani._frame = atoi(_tokens[nextToken]); + } +} + + + +DECLARE_LOCATION_PARSER(zone) { + debugC(7, kDebugParser, "LOCATION_PARSER(zone) "); + + parseZone(*_locParseCtxt.script, _zones, _tokens[1]); + + _locParseCtxt.z->_index = _locParseCtxt.numZones++; + + if (_localFlags[_currentLocationIndex] & kFlagsVisited) { + _locParseCtxt.z->_flags = _zoneFlags[_currentLocationIndex][_locParseCtxt.z->_index]; + } else { + _zoneFlags[_currentLocationIndex][_locParseCtxt.z->_index] = _locParseCtxt.z->_flags; + } + +} + + +DECLARE_LOCATION_PARSER(animation) { + debugC(7, kDebugParser, "LOCATION_PARSER(animation) "); + + parseAnimation(*_locParseCtxt.script, _animations, _tokens[1]); + + _locParseCtxt.a->_index = _locParseCtxt.numZones++; + + if (_localFlags[_currentLocationIndex] & kFlagsVisited) { + _locParseCtxt.a->_flags = _zoneFlags[_currentLocationIndex][_locParseCtxt.a->_index]; + } else { + _zoneFlags[_currentLocationIndex][_locParseCtxt.a->_index] = _locParseCtxt.a->_flags; + } + +} + + +DECLARE_LOCATION_PARSER(localflags) { + debugC(7, kDebugParser, "LOCATION_PARSER(localflags) "); + + int _si = 1; + while (_tokens[_si][0] != '\0') { + _localFlagNames->addData(_tokens[_si]); + _si++; + } +} + + +DECLARE_LOCATION_PARSER(flags) { + debugC(7, kDebugParser, "LOCATION_PARSER(flags) "); + + if ((_localFlags[_currentLocationIndex] & kFlagsVisited) == 0) { + // only for 1st visit + _localFlags[_currentLocationIndex] = 0; + int _si = 1; + + do { + byte _al = _localFlagNames->lookup(_tokens[_si]); + _localFlags[_currentLocationIndex] |= 1 << (_al - 1); + + _si++; + if (scumm_stricmp(_tokens[_si], "|")) break; + _si++; + } while (true); + } +} + + +DECLARE_LOCATION_PARSER(comment) { + debugC(7, kDebugParser, "LOCATION_PARSER(comment) "); + + _location._comment = parseComment(*_locParseCtxt.script); +} + + +DECLARE_LOCATION_PARSER(endcomment) { + debugC(7, kDebugParser, "LOCATION_PARSER(endcomment) "); + + _location._endComment = parseComment(*_locParseCtxt.script); +} + + +DECLARE_LOCATION_PARSER(sound) { + debugC(7, kDebugParser, "LOCATION_PARSER(sound) "); + +// _soundMan->loadSound(_tokens[1]); +} + + +DECLARE_LOCATION_PARSER(music) { + debugC(7, kDebugParser, "LOCATION_PARSER(music) "); + +// _soundMan->loadMusic(_tokens[1]); +} + +DECLARE_LOCATION_PARSER(redundant) { + debugC(7, kDebugParser, "LOCATION_PARSER(redundant) "); + + warning("redundant '%s' line found in script '%s'", _tokens[0], _locParseCtxt.filename); +} + + +DECLARE_LOCATION_PARSER(character) { + debugC(7, kDebugParser, "LOCATION_PARSER(character) "); + +// changeCharacter(character); +} + + +DECLARE_LOCATION_PARSER(ifchar) { + debugC(7, kDebugParser, "LOCATION_PARSER(ifchar) "); + + skip(_locParseCtxt.script, "ENDIF"); +} + + +DECLARE_LOCATION_PARSER(null) { + debugC(7, kDebugParser, "LOCATION_PARSER(null) "); + + +} + + +DECLARE_LOCATION_PARSER(mask) { + debugC(7, kDebugParser, "LOCATION_PARSER(mask) "); + + _disk->loadScenery(*_backgroundInfo, NULL, _tokens[1], NULL); + _gfx->setMask(&_backgroundInfo->mask); + + _gfx->_bgLayers[0] = atoi(_tokens[2]); + _gfx->_bgLayers[1] = atoi(_tokens[3]); + _gfx->_bgLayers[2] = atoi(_tokens[4]); +} + + +DECLARE_LOCATION_PARSER(path) { + debugC(7, kDebugParser, "LOCATION_PARSER(path) "); + + _disk->loadScenery(*_backgroundInfo, NULL, NULL, _tokens[1]); + _pathBuffer = &_backgroundInfo->path; +} + + +DECLARE_LOCATION_PARSER(escape) { + debugC(7, kDebugParser, "LOCATION_PARSER(escape) "); + + parseCommands(*_locParseCtxt.script, _location._escapeCommands); +} + + +DECLARE_LOCATION_PARSER(zeta) { + debugC(7, kDebugParser, "LOCATION_PARSER(zeta) "); + + _zeta0 = atoi(_tokens[1]); + _zeta1 = atoi(_tokens[2]); + + if (_tokens[3][0] != '\0') { + _zeta2 = atoi(_tokens[1]); + } else { + _zeta2 = 50; + } +} + +DECLARE_COMMAND_PARSER(ifchar) { + debugC(7, kDebugParser, "COMMAND_PARSER(ifchar) "); + + if (!scumm_stricmp(_characterName, _tokens[1])) + skip(_locParseCtxt.script, "endif"); +} + + +DECLARE_COMMAND_PARSER(endif) { + debugC(7, kDebugParser, "COMMAND_PARSER(endif) "); + + +} + + +DECLARE_COMMAND_PARSER(location) { + debugC(7, kDebugParser, "COMMAND_PARSER(location) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._string = strdup(_tokens[1]); + _locParseCtxt.nextToken++; + + if (_tokens[_locParseCtxt.nextToken][0] != '\0') { + _locParseCtxt.cmd->u._startPos.x = atoi(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._startPos.y = atoi(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + } + + if (_tokens[_locParseCtxt.nextToken][0] != '\0') { + _locParseCtxt.cmd->u._startPos2.x = atoi(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._startPos2.y = atoi(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(string) { + debugC(7, kDebugParser, "COMMAND_PARSER(string) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._string = strdup(_tokens[1]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + +DECLARE_COMMAND_PARSER(math) { + debugC(7, kDebugParser, "COMMAND_PARSER(math) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._lvalue = _countersNames->lookup(_tokens[1]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._rvalue = atoi(_tokens[2]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(test) { + debugC(7, kDebugParser, "COMMAND_PARSER(test) "); + + createCommand(_lookup); + + uint counter = _countersNames->lookup(_tokens[1]); + _locParseCtxt.nextToken++; + + if (counter == Table::notFound) { + if (!scumm_stricmp("SFX", _tokens[1])) { + _locParseCtxt.cmd->_id = CMD_TEST_SFX; + } else { + error("unknown counter '%s' in test opcode", _tokens[1]); + } + } else { + _locParseCtxt.cmd->u._lvalue = counter; + _locParseCtxt.cmd->u._rvalue = atoi(_tokens[3]); + _locParseCtxt.nextToken++; + + if (_tokens[2][0] == '>') { + _locParseCtxt.cmd->_id = CMD_TEST_GT; + } else + if (_tokens[2][0] == '<') { + _locParseCtxt.cmd->_id = CMD_TEST_LT; + } + _locParseCtxt.nextToken++; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(music) { + debugC(7, kDebugParser, "COMMAND_PARSER(music) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._musicCommand = _audioCommandsNames->lookup(_tokens[1]); + _locParseCtxt.nextToken++; + + if (_tokens[2][0] != '\0' && scumm_stricmp("flags", _tokens[2]) && scumm_stricmp("gflags", _tokens[2])) { + _locParseCtxt.cmd->u._musicParm = atoi(_tokens[2]); + _locParseCtxt.nextToken++; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(zone) { + debugC(7, kDebugParser, "COMMAND_PARSER(zone) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._zone = findZone(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + + if (_locParseCtxt.cmd->u._zone == NULL) { + strcpy(_forwardedAnimationNames[_numForwards], _tokens[_locParseCtxt.nextToken-1]); + _forwardedCommands[_numForwards] = _locParseCtxt.cmd; + _numForwards++; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(zeta) { + debugC(7, kDebugParser, "COMMAND_PARSER(zeta) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._zeta0 = atoi(_tokens[1]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._zeta1 = atoi(_tokens[2]); + _locParseCtxt.nextToken++; + + if (_tokens[3][0] != '\0') { + _locParseCtxt.cmd->u._zeta2 = atoi(_tokens[3]); + _locParseCtxt.nextToken++; + } else { + _locParseCtxt.cmd->u._zeta2 = 50; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(give) { + debugC(7, kDebugParser, "COMMAND_PARSER(give) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._object = 4 + atoi(_tokens[1]); + _locParseCtxt.nextToken++; + + if (!scumm_stricmp("dino", _tokens[2])) { + _locParseCtxt.cmd->u._characterId = 1; + } else + if (!scumm_stricmp("doug", _tokens[2])) { + _locParseCtxt.cmd->u._characterId = 2; + } else + if (!scumm_stricmp("donna", _tokens[2])) { + _locParseCtxt.cmd->u._characterId = 3; + } else + error("unknown recipient '%s' in give command", _tokens[2]); + + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(text) { + debugC(7, kDebugParser, "COMMAND_PARSER(text) "); + + createCommand(_lookup); + + if (isdigit(_tokens[1][1])) { + _locParseCtxt.cmd->u._zeta0 = atoi(_tokens[1]); + _locParseCtxt.nextToken++; + } else { + _locParseCtxt.cmd->u._zeta0 = 0; + } + + _locParseCtxt.cmd->u._string = strdup(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + + if (_tokens[_locParseCtxt.nextToken][0] != '\0' && scumm_stricmp("flags", _tokens[_locParseCtxt.nextToken])) { + _locParseCtxt.cmd->u._string2 = strdup(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + } + + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(unary) { + debugC(7, kDebugParser, "COMMAND_PARSER(unary) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._rvalue = atoi(_tokens[1]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_ZONE_PARSER(limits) { + debugC(7, kDebugParser, "ZONE_PARSER(limits) "); + + if (isalpha(_tokens[1][1])) { + _locParseCtxt.z->_flags |= kFlagsAnimLinked; + _locParseCtxt.z->_linkedAnim = findAnimation(_tokens[1]); + _locParseCtxt.z->_linkedName = strdup(_tokens[1]); + } else { + _locParseCtxt.z->_left = atoi(_tokens[1]); + _locParseCtxt.z->_top = atoi(_tokens[2]); + _locParseCtxt.z->_right = atoi(_tokens[3]); + _locParseCtxt.z->_bottom = atoi(_tokens[4]); + } +} + + +DECLARE_ZONE_PARSER(moveto) { + debugC(7, kDebugParser, "ZONE_PARSER(moveto) "); + + _locParseCtxt.z->_moveTo.x = atoi(_tokens[1]); + _locParseCtxt.z->_moveTo.y = atoi(_tokens[2]); +// _locParseCtxt.z->_moveTo.z = atoi(_tokens[3]); +} + + +DECLARE_ZONE_PARSER(type) { + debugC(7, kDebugParser, "ZONE_PARSER(type) "); + + if (_tokens[2][0] != '\0') { + _locParseCtxt.z->_type = (4 + _objectsNames->lookup(_tokens[2])) << 16; + } + int16 _si = _zoneTypeNames->lookup(_tokens[1]); + if (_si != Table::notFound) { + _locParseCtxt.z->_type |= 1 << (_si - 1); + parseZoneTypeBlock(*_locParseCtxt.script, _locParseCtxt.z); + +// if (_locParseCtxt.z->_type & kZoneHear) { +// _soundMan->sfxCommand(START...); +// } + } + + popParserTables(); +} + + +DECLARE_ANIM_PARSER(file) { + debugC(7, kDebugParser, "ANIM_PARSER(file) "); + + _locParseCtxt.a->_cnv = _disk->loadFrames(_tokens[1]); +} + + +DECLARE_ANIM_PARSER(position) { + debugC(7, kDebugParser, "ANIM_PARSER(position) "); + + _locParseCtxt.a->_left = atoi(_tokens[1]); + _locParseCtxt.a->_top = atoi(_tokens[2]); + _locParseCtxt.a->_z = atoi(_tokens[3]); + _locParseCtxt.a->_frame = atoi(_tokens[4]); +} + + +DECLARE_ANIM_PARSER(moveto) { + debugC(7, kDebugParser, "ANIM_PARSER(moveto) "); + + _locParseCtxt.a->_moveTo.x = atoi(_tokens[1]); + _locParseCtxt.a->_moveTo.y = atoi(_tokens[2]); +// _locParseCtxt.a->_moveTo.z = atoi(_tokens[3]); +} + + +DECLARE_ANIM_PARSER(endanimation) { + debugC(7, kDebugParser, "ANIM_PARSER(endanimation) "); + + + if (_locParseCtxt.a->_cnv) { + _locParseCtxt.a->_right = _locParseCtxt.a->width(); + _locParseCtxt.a->_bottom = _locParseCtxt.a->height(); + } + + _locParseCtxt.a->_oldPos.x = -1000; + _locParseCtxt.a->_oldPos.y = -1000; + + _locParseCtxt.a->_flags |= 0x1000000; + + popParserTables(); +} + + + + + + + + + + +DECLARE_INSTRUCTION_PARSER(zone) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(zone) "); + + _instParseCtxt.inst->_z = findZone(_tokens[1]); +} + + + +DECLARE_INSTRUCTION_PARSER(color) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(color) "); + + + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); + + _instParseCtxt.inst->_colors[0] = atoi(_tokens[2]); + _instParseCtxt.inst->_colors[1] = atoi(_tokens[3]); + _instParseCtxt.inst->_colors[2] = atoi(_tokens[4]); + +} + + +DECLARE_INSTRUCTION_PARSER(mask) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(mask) "); + + + parseRValue(_instParseCtxt.inst->_opA, _tokens[1]); + parseRValue(_instParseCtxt.inst->_opB, _tokens[2]); + parseRValue(_instParseCtxt.inst->_opC, _tokens[3]); + +} + + +DECLARE_INSTRUCTION_PARSER(print) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(print) "); + + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(text) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(text) "); + + + int _si = 1; + + if (isdigit(_tokens[1][1])) { + _instParseCtxt.inst->_y = atoi(_tokens[1]); + _si = 2; + } else { + _instParseCtxt.inst->_y = -1; + } + + _instParseCtxt.inst->_text = strdup(_tokens[_si]); + _si++; + + if (_tokens[_si][0] != '\0' && scumm_stricmp("flags", _tokens[_si])) { + _instParseCtxt.inst->_text2 = strdup(_tokens[_si]); + } + +} + + +DECLARE_INSTRUCTION_PARSER(if_op) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(if_op) "); + + + if (_instParseCtxt.openIf) + error("cannot nest 'if' blocks"); + + parseLValue(_instParseCtxt.inst->_opA, _tokens[1]); + parseRValue(_instParseCtxt.inst->_opB, _tokens[3]); + + if (_tokens[2][0] == '=') { + _instParseCtxt.inst->_index = INST_IFEQ; + } else + if (_tokens[2][0] == '>') { + _instParseCtxt.inst->_index = INST_IFGT; + } else + if (_tokens[2][0] == '<') { + _instParseCtxt.inst->_index = INST_IFLT; + } else + error("unknown test operator '%s' in if-clause", _tokens[2]); + + _instParseCtxt.openIf = _instParseCtxt.inst; + +} + + +DECLARE_INSTRUCTION_PARSER(endif) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(endif) "); + + if (_instParseCtxt.openIf == 0) + error("unexpected 'endif'"); + +// _instParseCtxt.openIf->_endif = _instParseCtxt.inst; + _instParseCtxt.openIf = NULL; +} + + +void Parallaction_br::parseRValue(ScriptVar &v, const char *str) { + + if (isdigit(str[0]) || str[0] == '-') { + v.setImmediate(atoi(str)); + return; + } + + int index = _instParseCtxt.program->findLocal(str); + if (index != -1) { + v.setLocal(&_instParseCtxt.locals[index]); + return; + } + + Animation *a; + if (str[1] == '.') { + a = findAnimation(&str[2]); + if (!a) { + error("unknown animation '%s' in script", &str[2]); + } + } else + a = _instParseCtxt.a; + + if (str[0] == 'X') { + v.setField(&a->_left); + } else + if (str[0] == 'Y') { + v.setField(&a->_top); + } else + if (str[0] == 'Z') { + v.setField(&a->_z); + } else + if (str[0] == 'F') { + v.setField(&a->_frame); + } else + if (str[0] == 'N') { + v.setImmediate(a->getFrameNum()); + } else + if (str[0] == 'R') { + v.setRandom(atoi(&str[1])); + } else + if (str[0] == 'L') { + v.setField(&_lipSyncVal); + } + +} + +typedef OpcodeImpl<Parallaction_br> OpcodeV2; +#define INSTRUCTION_PARSER(sig) OpcodeV2(this, &Parallaction_br::instParse_##sig) +#define ZONE_PARSER(sig) OpcodeV2(this, &Parallaction_br::locZoneParse_##sig) +#define ANIM_PARSER(sig) OpcodeV2(this, &Parallaction_br::locAnimParse_##sig) +#define LOCATION_PARSER(sig) OpcodeV2(this, &Parallaction_br::locParse_##sig) +#define COMMAND_PARSER(sig) OpcodeV2(this, &Parallaction_br::cmdParse_##sig) + +void Parallaction_br::initParsers() { + + static const OpcodeV2 op0[] = { + INSTRUCTION_PARSER(defLocal), // invalid opcode -> local definition + INSTRUCTION_PARSER(zone), // on + INSTRUCTION_PARSER(zone), // off + INSTRUCTION_PARSER(x), + INSTRUCTION_PARSER(y), + INSTRUCTION_PARSER(z), + INSTRUCTION_PARSER(f), + INSTRUCTION_PARSER(loop), + INSTRUCTION_PARSER(null), // endloop + INSTRUCTION_PARSER(null), // show + INSTRUCTION_PARSER(inc), + INSTRUCTION_PARSER(inc), // dec + INSTRUCTION_PARSER(set), + INSTRUCTION_PARSER(put), + INSTRUCTION_PARSER(call), + INSTRUCTION_PARSER(null), // wait + INSTRUCTION_PARSER(zone), // start + INSTRUCTION_PARSER(zone), // process + INSTRUCTION_PARSER(move), + INSTRUCTION_PARSER(color), + INSTRUCTION_PARSER(zone), // sound + INSTRUCTION_PARSER(mask), + INSTRUCTION_PARSER(print), + INSTRUCTION_PARSER(text), + INSTRUCTION_PARSER(inc), // mul + INSTRUCTION_PARSER(inc), // div + INSTRUCTION_PARSER(if_op), + INSTRUCTION_PARSER(null), + INSTRUCTION_PARSER(null), + INSTRUCTION_PARSER(endif), + INSTRUCTION_PARSER(zone), // stop + INSTRUCTION_PARSER(endscript) + }; + + uint i; + for (i = 0; i < ARRAYSIZE(op0); i++) + _instructionParsers.push_back(&op0[i]); + + + static const OpcodeV2 op2[] = { + COMMAND_PARSER(invalid), + COMMAND_PARSER(flags), // set + COMMAND_PARSER(flags), // clear + COMMAND_PARSER(animation), // start + COMMAND_PARSER(zone), // speak + COMMAND_PARSER(zone), // get + COMMAND_PARSER(location), + COMMAND_PARSER(zone), // open + COMMAND_PARSER(zone), // close + COMMAND_PARSER(zone), // on + COMMAND_PARSER(zone), // off + COMMAND_PARSER(call), + COMMAND_PARSER(flags), // toggle + COMMAND_PARSER(drop), + COMMAND_PARSER(simple), // quit + COMMAND_PARSER(move), + COMMAND_PARSER(animation), // stop + COMMAND_PARSER(string), // character + COMMAND_PARSER(string), // followme + COMMAND_PARSER(simple), // onmouse + COMMAND_PARSER(simple), // offmouse + COMMAND_PARSER(drop), // add + COMMAND_PARSER(zone), // leave + COMMAND_PARSER(math), // inc + COMMAND_PARSER(math), // dec + COMMAND_PARSER(test), // test + COMMAND_PARSER(invalid), + COMMAND_PARSER(invalid), + COMMAND_PARSER(math), // let + COMMAND_PARSER(music), + COMMAND_PARSER(zone), // fix + COMMAND_PARSER(zone), // unfix + COMMAND_PARSER(zeta), + COMMAND_PARSER(unary), // scroll + COMMAND_PARSER(string), // swap + COMMAND_PARSER(give), + COMMAND_PARSER(text), + COMMAND_PARSER(unary), // part + COMMAND_PARSER(invalid), + COMMAND_PARSER(simple), // return + COMMAND_PARSER(simple), // onsave + COMMAND_PARSER(simple), // offsave + COMMAND_PARSER(endcommands), // endcommands + COMMAND_PARSER(ifchar), + COMMAND_PARSER(endif) + }; + + for (i = 0; i < ARRAYSIZE(op2); i++) + _commandParsers.push_back(&op2[i]); + + static const OpcodeV2 op4[] = { + LOCATION_PARSER(invalid), + LOCATION_PARSER(character), + LOCATION_PARSER(endlocation), + LOCATION_PARSER(ifchar), + LOCATION_PARSER(null), // endif + LOCATION_PARSER(location), + LOCATION_PARSER(mask), + LOCATION_PARSER(path), + LOCATION_PARSER(null), // disk + LOCATION_PARSER(localflags), + LOCATION_PARSER(commands), + LOCATION_PARSER(escape), + LOCATION_PARSER(acommands), + LOCATION_PARSER(flags), + LOCATION_PARSER(comment), + LOCATION_PARSER(endcomment), + LOCATION_PARSER(zone), + LOCATION_PARSER(animation), + LOCATION_PARSER(zeta), + LOCATION_PARSER(music), + LOCATION_PARSER(sound) +// LOCATION_PARSER(redundant) // for redundant endanimation + }; + + for (i = 0; i < ARRAYSIZE(op4); i++) + _locationParsers.push_back(&op4[i]); + + static const OpcodeV2 op5[] = { + ZONE_PARSER(invalid), + ZONE_PARSER(endzone), + ZONE_PARSER(limits), + ZONE_PARSER(moveto), + ZONE_PARSER(type), + ZONE_PARSER(commands), + ZONE_PARSER(label), + ZONE_PARSER(flags) + }; + + for (i = 0; i < ARRAYSIZE(op5); i++) + _locationZoneParsers.push_back(&op5[i]); + + static const OpcodeV2 op6[] = { + ANIM_PARSER(invalid), + ANIM_PARSER(endanimation), + ANIM_PARSER(endanimation), // endzone + ANIM_PARSER(script), + ANIM_PARSER(commands), + ANIM_PARSER(type), + ANIM_PARSER(label), + ANIM_PARSER(flags), + ANIM_PARSER(file), + ANIM_PARSER(position), + ANIM_PARSER(moveto) + }; + + for (i = 0; i < ARRAYSIZE(op6); i++) + _locationAnimParsers.push_back(&op6[i]); + + _currentOpcodes = 0; + _currentStatements = 0; + +} + +void Parallaction_br::parseLocation(const char* filename) { + + _locParseCtxt.numZones = 0; + + Super::parseLocation(filename); + +// drawZones(); + + return; +} + + + + + +} // namespace Parallaction diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp new file mode 100644 index 0000000000..1b47f2fe3d --- /dev/null +++ b/engines/parallaction/parser_ns.cpp @@ -0,0 +1,1494 @@ +/* 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/stdafx.h" + +#include "parallaction/parallaction.h" +#include "parallaction/sound.h" + +namespace Parallaction { + +#define CMD_SET 1 +#define CMD_CLEAR 2 +#define CMD_START 3 +#define CMD_SPEAK 4 +#define CMD_GET 5 +#define CMD_LOCATION 6 +#define CMD_OPEN 7 +#define CMD_CLOSE 8 +#define CMD_ON 9 +#define CMD_OFF 10 +#define CMD_CALL 11 +#define CMD_TOGGLE 12 +#define CMD_DROP 13 +#define CMD_QUIT 14 +#define CMD_MOVE 15 +#define CMD_STOP 16 + +#define INST_ON 1 +#define INST_OFF 2 +#define INST_X 3 +#define INST_Y 4 +#define INST_Z 5 +#define INST_F 6 +#define INST_LOOP 7 +#define INST_ENDLOOP 8 +#define INST_SHOW 9 +#define INST_INC 10 +#define INST_DEC 11 +#define INST_SET 12 +#define INST_PUT 13 +#define INST_CALL 14 +#define INST_WAIT 15 +#define INST_START 16 +#define INST_SOUND 17 +#define INST_MOVE 18 +#define INST_END 19 + + +#define DECLARE_ZONE_PARSER(sig) void Parallaction_ns::locZoneParse_##sig() +#define DECLARE_ANIM_PARSER(sig) void Parallaction_ns::locAnimParse_##sig() +#define DECLARE_COMMAND_PARSER(sig) void Parallaction_ns::cmdParse_##sig() +#define DECLARE_INSTRUCTION_PARSER(sig) void Parallaction_ns::instParse_##sig() +#define DECLARE_LOCATION_PARSER(sig) void Parallaction_ns::locParse_##sig() + + + + +DECLARE_ANIM_PARSER(invalid) { + debugC(7, kDebugParser, "ANIM_PARSER(invalid) "); + + error("unknown statement '%s' in animation %s", _tokens[0], _locParseCtxt.a->_label._text); +} + + +DECLARE_ANIM_PARSER(script) { + debugC(7, kDebugParser, "ANIM_PARSER(script) "); + + _locParseCtxt.a->_scriptName = strdup(_tokens[1]); +} + + +DECLARE_ANIM_PARSER(commands) { + debugC(7, kDebugParser, "ANIM_PARSER(commands) "); + + parseCommands(*_locParseCtxt.script, _locParseCtxt.a->_commands); +} + + +DECLARE_ANIM_PARSER(type) { + debugC(7, kDebugParser, "ANIM_PARSER(type) "); + + if (_tokens[2][0] != '\0') { + _locParseCtxt.a->_type = ((4 + _objectsNames->lookup(_tokens[2])) << 16) & 0xFFFF0000; + } + int16 _si = _zoneTypeNames->lookup(_tokens[1]); + if (_si != Table::notFound) { + _locParseCtxt.a->_type |= 1 << (_si-1); + if (((_locParseCtxt.a->_type & 0xFFFF) != kZoneNone) && ((_locParseCtxt.a->_type & 0xFFFF) != kZoneCommand)) { + parseZoneTypeBlock(*_locParseCtxt.script, _locParseCtxt.a); + } + } + + _locParseCtxt.a->_oldPos.x = -1000; + _locParseCtxt.a->_oldPos.y = -1000; + + _locParseCtxt.a->_flags |= 0x1000000; + + popParserTables(); +} + + +DECLARE_ANIM_PARSER(label) { + debugC(7, kDebugParser, "ANIM_PARSER(label) "); + + renderLabel(&_locParseCtxt.a->_label._cnv, _tokens[1]); +} + + +DECLARE_ANIM_PARSER(flags) { + debugC(7, kDebugParser, "ANIM_PARSER(flags) "); + + uint16 _si = 1; + + do { + byte _al = _zoneFlagNames->lookup(_tokens[_si]); + _si++; + _locParseCtxt.a->_flags |= 1 << (_al - 1); + } while (!scumm_stricmp(_tokens[_si++], "|")); +} + + +DECLARE_ANIM_PARSER(file) { + debugC(7, kDebugParser, "ANIM_PARSER(file) "); + + char vC8[200]; + strcpy(vC8, _tokens[1]); + if (_engineFlags & kEngineTransformedDonna) { + if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) { + strcat(vC8, "tras"); + } + } + _locParseCtxt.a->_cnv = _disk->loadFrames(vC8); +} + + +DECLARE_ANIM_PARSER(position) { + debugC(7, kDebugParser, "ANIM_PARSER(position) "); + + _locParseCtxt.a->_left = atoi(_tokens[1]); + _locParseCtxt.a->_top = atoi(_tokens[2]); + _locParseCtxt.a->_z = atoi(_tokens[3]); +} + + +DECLARE_ANIM_PARSER(moveto) { + debugC(7, kDebugParser, "ANIM_PARSER(moveto) "); + + _locParseCtxt.a->_moveTo.x = atoi(_tokens[1]); + _locParseCtxt.a->_moveTo.y = atoi(_tokens[2]); +} + + +DECLARE_ANIM_PARSER(endanimation) { + debugC(7, kDebugParser, "ANIM_PARSER(endanimation) "); + + + _locParseCtxt.a->_oldPos.x = -1000; + _locParseCtxt.a->_oldPos.y = -1000; + + _locParseCtxt.a->_flags |= 0x1000000; + + popParserTables(); +} + +Animation *Parallaction_ns::parseAnimation(Script& script, AnimationList &list, char *name) { + debugC(5, kDebugParser, "parseAnimation(name: %s)", name); + + Animation *a = new Animation; + + a->_label._text = strdup(name); + + list.push_front(a); + + _locParseCtxt.a = a; + _locParseCtxt.script = &script; + + pushParserTables(&_locationAnimParsers, _locationAnimStmt); + + return a; +} + +void Parallaction_ns::parseInstruction(Animation *a, LocalVariable *locals) { + + Instruction *inst = new Instruction; + + if (_tokens[0][1] == '.') { + _tokens[0][1] = '\0'; + _instParseCtxt.a = findAnimation(&_tokens[0][2]); + } else + if (_tokens[1][1] == '.') { + _tokens[1][1] = '\0'; + _instParseCtxt.a = findAnimation(&_tokens[1][2]); + } else + _instParseCtxt.a = a; + + inst->_index = _instructionNames->lookup(_tokens[0]); + _instParseCtxt.inst = inst; + _instParseCtxt.locals = locals; + + (*(_instructionParsers[inst->_index]))(); + + a->_program->_instructions.push_back(inst); + + return; +} + +void Parallaction_ns::loadProgram(Animation *a, const char *filename) { + debugC(1, kDebugParser, "loadProgram(Animation: %s, script: %s)", a->_label._text, filename); + + Script *script = _disk->loadScript(filename); + + a->_program = new Program; + + _instParseCtxt.openIf = NULL; + _instParseCtxt.end = false; + _instParseCtxt.program = a->_program; + + do { + fillBuffers(*script); + parseInstruction(a, a->_program->_locals); + } while (!_instParseCtxt.end); + + a->_program->_ip = a->_program->_instructions.begin(); + + delete script; + + debugC(1, kDebugParser, "loadProgram() done"); + + return; +} + +DECLARE_INSTRUCTION_PARSER(animation) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(animation) "); + + if (!scumm_stricmp(_tokens[1], _instParseCtxt.a->_label._text)) { + _instParseCtxt.inst->_a = _instParseCtxt.a; + } else { + _instParseCtxt.inst->_a = findAnimation(_tokens[1]); + } +} + + +DECLARE_INSTRUCTION_PARSER(loop) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(loop) "); + + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(x) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(x) "); + + parseLValue(_instParseCtxt.inst->_opA, "X"); + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(y) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(y) "); + + parseLValue(_instParseCtxt.inst->_opA, "Y"); + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(z) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(z) "); + + parseLValue(_instParseCtxt.inst->_opA, "Z"); + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(f) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(f) "); + + parseLValue(_instParseCtxt.inst->_opA, "F"); + parseRValue(_instParseCtxt.inst->_opB, _tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(inc) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(inc) "); + + parseLValue(_instParseCtxt.inst->_opA, _tokens[1]); + parseRValue(_instParseCtxt.inst->_opB, _tokens[2]); + + if (!scumm_stricmp(_tokens[3], "mod")) { + _instParseCtxt.inst->_flags |= kInstMod; + } +} + + +DECLARE_INSTRUCTION_PARSER(set) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(set) "); + + // WORKAROUND: At least one script (balzo.script) in Amiga versions didn't declare + // local variables before using them, thus leading to crashes. The line launching the + // script was commented out on Dos version. This workaround enables the engine + // to dynamically add a local variable when it is encountered the first time in + // the script, so should fix any other occurrence as well. + if (_instParseCtxt.program->findLocal(_tokens[1]) == -1) { + _instParseCtxt.program->addLocal(_tokens[1]); + } + + parseLValue(_instParseCtxt.inst->_opA, _tokens[1]); + parseRValue(_instParseCtxt.inst->_opB, _tokens[2]); +} + + +DECLARE_INSTRUCTION_PARSER(move) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(move) "); + + parseRValue(_instParseCtxt.inst->_opA, _tokens[1]); + parseRValue(_instParseCtxt.inst->_opB, _tokens[2]); +} + + +DECLARE_INSTRUCTION_PARSER(put) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(put) "); + + if (!scumm_stricmp(_tokens[1], _instParseCtxt.a->_label._text)) { + _instParseCtxt.inst->_a = _instParseCtxt.a; + } else { + _instParseCtxt.inst->_a = findAnimation(_tokens[1]); + } + + parseRValue(_instParseCtxt.inst->_opA, _tokens[2]); + parseRValue(_instParseCtxt.inst->_opB, _tokens[3]); + if (!scumm_stricmp(_tokens[4], "masked")) { + _instParseCtxt.inst->_flags |= kInstMaskedPut; + } +} + + +DECLARE_INSTRUCTION_PARSER(call) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(call) "); + + int index = _callableNames->lookup(_tokens[1]); + if (index == Table::notFound) + error("unknown callable '%s'", _tokens[1]); + _instParseCtxt.inst->_immediate = index - 1; +} + + +DECLARE_INSTRUCTION_PARSER(sound) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(sound) "); + + _instParseCtxt.inst->_z = findZone(_tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(null) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(null) "); + + +} + + +DECLARE_INSTRUCTION_PARSER(defLocal) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(defLocal) "); + + int16 val = atoi(_tokens[2]); + int16 index; + + if (_tokens[3][0] != '\0') { + index = _instParseCtxt.program->addLocal(_tokens[0], val, atoi(_tokens[3]), atoi(_tokens[4])); + } else { + index = _instParseCtxt.program->addLocal(_tokens[0], val); + } + + _instParseCtxt.inst->_opA.setLocal(&_instParseCtxt.locals[index]); + _instParseCtxt.inst->_opB.setImmediate(_instParseCtxt.locals[index]._value); + + _instParseCtxt.inst->_index = INST_SET; +} + +DECLARE_INSTRUCTION_PARSER(endscript) { + debugC(7, kDebugParser, "INSTRUCTION_PARSER(endscript) "); + + _instParseCtxt.end = true; +} + + + +void Parallaction_ns::parseRValue(ScriptVar &v, const char *str) { + + if (isdigit(str[0]) || str[0] == '-') { + v.setImmediate(atoi(str)); + return; + } + + int index = _instParseCtxt.program->findLocal(str); + if (index != -1) { + v.setLocal(&_instParseCtxt.locals[index]); + return; + } + + Animation *a; + if (str[1] == '.') { + a = findAnimation(&str[2]); + } else { + a = _instParseCtxt.a; + } + + if (str[0] == 'X') { + v.setField(&a->_left); + } else + if (str[0] == 'Y') { + v.setField(&a->_top); + } else + if (str[0] == 'Z') { + v.setField(&a->_z); + } else + if (str[0] == 'F') { + v.setField(&a->_frame); + } + +} + +void Parallaction_ns::parseLValue(ScriptVar &v, const char *str) { + + int index = _instParseCtxt.program->findLocal(str); + if (index != -1) { + v.setLocal(&_instParseCtxt.locals[index]); + return; + } + + Animation *a; + if (str[1] == '.') { + a = findAnimation(&str[2]); + } else { + a = _instParseCtxt.a; + } + + if (str[0] == 'X') { + v.setField(&a->_left); + } else + if (str[0] == 'Y') { + v.setField(&a->_top); + } else + if (str[0] == 'Z') { + v.setField(&a->_z); + } else + if (str[0] == 'F') { + v.setField(&a->_frame); + } + +} + + +DECLARE_COMMAND_PARSER(flags) { + debugC(7, kDebugParser, "COMMAND_PARSER(flags) "); + + createCommand(_lookup); + + if (_globalTable->lookup(_tokens[1]) == Table::notFound) { + do { + char _al = _localFlagNames->lookup(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._flags |= 1 << (_al - 1); + } while (!scumm_stricmp(_tokens[_locParseCtxt.nextToken++], "|")); + _locParseCtxt.nextToken--; + } else { + _locParseCtxt.cmd->u._flags |= kFlagsGlobal; + do { + char _al = _globalTable->lookup(_tokens[1]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._flags |= 1 << (_al - 1); + } while (!scumm_stricmp(_tokens[_locParseCtxt.nextToken++], "|")); + _locParseCtxt.nextToken--; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(animation) { + debugC(7, kDebugParser, "COMMAND_PARSER(animation) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._animation = findAnimation(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + if (_locParseCtxt.cmd->u._animation == NULL) { + strcpy(_forwardedAnimationNames[_numForwards], _tokens[_locParseCtxt.nextToken-1]); + _forwardedCommands[_numForwards] = _locParseCtxt.cmd; + _numForwards++; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(zone) { + debugC(7, kDebugParser, "COMMAND_PARSER(zone) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._zone = findZone(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(location) { + debugC(7, kDebugParser, "COMMAND_PARSER(location) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._string = (char*)malloc(strlen(_tokens[_locParseCtxt.nextToken])+1); + strcpy(_locParseCtxt.cmd->u._string, _tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(drop) { + debugC(7, kDebugParser, "COMMAND_PARSER(drop) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._object = 4 + _objectsNames->lookup(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(call) { + debugC(7, kDebugParser, "COMMAND_PARSER(call) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._callable = _callableNames->lookup(_tokens[_locParseCtxt.nextToken]) - 1; + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(simple) { + debugC(7, kDebugParser, "COMMAND_PARSER(simple) "); + + createCommand(_lookup); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(move) { + debugC(7, kDebugParser, "COMMAND_PARSER(move) "); + + createCommand(_lookup); + + _locParseCtxt.cmd->u._move.x = atoi(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + _locParseCtxt.cmd->u._move.y = atoi(_tokens[_locParseCtxt.nextToken]); + _locParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + +DECLARE_COMMAND_PARSER(invalid) { + debugC(7, kDebugParser, "COMMAND_PARSER(invalid) "); + + error("Can't parse unknown command '%s'", _tokens[0]); +} + +DECLARE_COMMAND_PARSER(endcommands) { + debugC(7, kDebugParser, "COMMAND_PARSER(endcommands) "); + + popParserTables(); + + // temporary trick to handle dialogue commands + _locParseCtxt.endcommands = true; +} + +void Parallaction_ns::parseCommandFlags() { + + int _si = _locParseCtxt.nextToken; + Command *cmd = _locParseCtxt.cmd; + + if (!scumm_stricmp(_tokens[_si], "flags")) { + _si++; + + do { + if (!scumm_stricmp(_tokens[_si], "exit") || !scumm_stricmp(_tokens[_si], "exittrap")) { + cmd->_flagsOn |= kFlagsExit; + } else + if (!scumm_stricmp(_tokens[_si], "enter") || !scumm_stricmp(_tokens[_si], "entertrap")) { + cmd->_flagsOn |= kFlagsEnter; + } else + if (!scumm_strnicmp(_tokens[_si], "no", 2)) { + byte _al = _localFlagNames->lookup(&_tokens[_si][2]); + cmd->_flagsOff |= 1 << (_al - 1); + } else { + byte _al = _localFlagNames->lookup(_tokens[_si]); + cmd->_flagsOn |= 1 << (_al - 1); + } + + _si++; + + } while (!scumm_stricmp(_tokens[_si++], "|")); + + } + + if (!scumm_stricmp(_tokens[_si], "gflags")) { + _si++; + cmd->_flagsOn |= kFlagsGlobal; + + do { + if (!scumm_stricmp(_tokens[_si], "exit")) { + cmd->_flagsOn |= kFlagsExit; + } else + if (!scumm_stricmp(_tokens[_si], "enter")) { + cmd->_flagsOn |= kFlagsEnter; + } else + if (!scumm_strnicmp(_tokens[_si], "no", 2)) { + byte _al = _globalTable->lookup(&_tokens[_si][2]); + cmd->_flagsOff |= 1 << (_al - 1); + } else { + byte _al = _globalTable->lookup(_tokens[_si]); + cmd->_flagsOn |= 1 << (_al - 1); + } + + _si++; + + } while (!scumm_stricmp(_tokens[_si++], "|")); + + } + + _si = _locParseCtxt.nextToken; + +} + +void Parallaction_ns::addCommand() { + _locParseCtxt.list->push_front(_locParseCtxt.cmd); // NOTE: command lists are written backwards in scripts +} + +void Parallaction_ns::createCommand(uint id) { + + _locParseCtxt.nextToken = 1; + _locParseCtxt.cmd = new Command; + _locParseCtxt.cmd->_id = id; + +} + +void Parallaction_ns::parseCommands(Script &script, CommandList& list) { + debugC(5, kDebugParser, "parseCommands()"); + + _locParseCtxt.list = &list; + _locParseCtxt.endcommands = false; + _locParseCtxt.script = &script; + + pushParserTables(&_commandParsers, _commandsNames); +} + +Dialogue *Parallaction_ns::parseDialogue(Script &script) { + debugC(7, kDebugParser, "parseDialogue()"); + + uint16 numQuestions = 0; + + Dialogue *dialogue = new Dialogue; + + Table forwards(20); + + fillBuffers(script, true); + + while (scumm_stricmp(_tokens[0], "enddialogue")) { + if (scumm_stricmp(_tokens[0], "Question")) continue; + + Question *question = new Question; + dialogue->_questions[numQuestions] = question; + + forwards.addData(_tokens[1]); + + question->_text = parseDialogueString(script); + + fillBuffers(script, true); + question->_mood = atoi(_tokens[0]); + + uint16 numAnswers = 0; + + fillBuffers(script, true); + while (scumm_stricmp(_tokens[0], "endquestion")) { // parse answers + + Answer *answer = new Answer; + question->_answers[numAnswers] = answer; + + if (_tokens[1][0]) { + + Table* flagNames; + uint16 token; + + if (!scumm_stricmp(_tokens[1], "global")) { + token = 2; + flagNames = _globalTable; + answer->_yesFlags |= kFlagsGlobal; + } else { + token = 1; + flagNames = _localFlagNames; + } + + do { + + if (!scumm_strnicmp(_tokens[token], "no", 2)) { + byte _al = flagNames->lookup(_tokens[token]+2); + answer->_noFlags |= 1 << (_al - 1); + } else { + byte _al = flagNames->lookup(_tokens[token]); + answer->_yesFlags |= 1 << (_al - 1); + } + + token++; + + } while (!scumm_stricmp(_tokens[token++], "|")); + + } + + answer->_text = parseDialogueString(script); + + fillBuffers(script, true); + answer->_mood = atoi(_tokens[0]); + answer->_following._name = parseDialogueString(script); + + fillBuffers(script, true); + if (!scumm_stricmp(_tokens[0], "commands")) { + + parseCommands(script, answer->_commands); + _locParseCtxt.endcommands = false; + do { + fillBuffers(script, true); + parseStatement(); + } while (!_locParseCtxt.endcommands); + + fillBuffers(script, true); + } + + numAnswers++; + } + + fillBuffers(script, true); + numQuestions++; + + } + + // link questions + byte v50[20]; + memset(v50, 0, 20); + + for (uint16 i = 0; i < numQuestions; i++) { + Question *question = dialogue->_questions[i]; + + for (uint16 j = 0; j < NUM_ANSWERS; j++) { + Answer *answer = question->_answers[j]; + if (answer == 0) continue; + + int16 index = forwards.lookup(answer->_following._name); + free(answer->_following._name); + + if (index == Table::notFound) + answer->_following._question = 0; + else + answer->_following._question = dialogue->_questions[index - 1]; + + + } + } + + debugC(7, kDebugParser, "parseDialogue() done"); + + return dialogue; +} + + +char *Parallaction_ns::parseDialogueString(Script &script) { + + char vC8[200]; + char *vD0 = NULL; + do { + + vD0 = script.readLine(vC8, 200); + if (vD0 == 0) return NULL; + + vD0 = Common::ltrim(vD0); + + } while (strlen(vD0) == 0); + + vD0[strlen(vD0)-1] = '\0'; // deletes the trailing '0xA' + // this is critical for Gfx::displayWrappedString to work properly + return strdup(vD0); +} + + +DECLARE_LOCATION_PARSER(invalid) { + debugC(7, kDebugParser, "LOCATION_PARSER(invalid) "); + + error("unknown keyword '%s' in location '%s'", _tokens[0], _locParseCtxt.filename); +} + +DECLARE_LOCATION_PARSER(endlocation) { + debugC(7, kDebugParser, "LOCATION_PARSER(endlocation) "); + + _locParseCtxt.end = true; +} + + +DECLARE_LOCATION_PARSER(location) { + debugC(7, kDebugParser, "LOCATION_PARSER(location) "); + + // The parameter for location is 'location.mask'. + // If mask is not present, then it is assumed + // that path & mask are encoded in the background + // bitmap, otherwise a separate .msk file exists. + + char *mask = strchr(_tokens[1], '.'); + if (mask) { + mask[0] = '\0'; + mask++; + } + + strcpy(_location._name, _tokens[1]); + switchBackground(_location._name, mask); + + if (_tokens[2][0] != '\0') { + _char._ani._left = atoi(_tokens[2]); + _char._ani._top = atoi(_tokens[3]); + } + + if (_tokens[4][0] != '\0') { + _char._ani._frame = atoi(_tokens[4]); + } +} + + +DECLARE_LOCATION_PARSER(disk) { + debugC(7, kDebugParser, "LOCATION_PARSER(disk) "); + + _disk->selectArchive(_tokens[1]); +} + + +DECLARE_LOCATION_PARSER(nodes) { + debugC(7, kDebugParser, "LOCATION_PARSER(nodes) "); + + parseWalkNodes(*_locParseCtxt.script, _location._walkNodes); +} + + +DECLARE_LOCATION_PARSER(zone) { + debugC(7, kDebugParser, "LOCATION_PARSER(zone) "); + + parseZone(*_locParseCtxt.script, _zones, _tokens[1]); +} + + +DECLARE_LOCATION_PARSER(animation) { + debugC(7, kDebugParser, "LOCATION_PARSER(animation) "); + + parseAnimation(*_locParseCtxt.script, _animations, _tokens[1]); +} + + +DECLARE_LOCATION_PARSER(localflags) { + debugC(7, kDebugParser, "LOCATION_PARSER(localflags) "); + + int _si = 1; + while (_tokens[_si][0] != '\0') { + _localFlagNames->addData(_tokens[_si]); + _si++; + } +} + + +DECLARE_LOCATION_PARSER(commands) { + debugC(7, kDebugParser, "LOCATION_PARSER(commands) "); + + parseCommands(*_locParseCtxt.script, _location._commands); +} + + +DECLARE_LOCATION_PARSER(acommands) { + debugC(7, kDebugParser, "LOCATION_PARSER(acommands) "); + + parseCommands(*_locParseCtxt.script, _location._aCommands); +} + + +DECLARE_LOCATION_PARSER(flags) { + debugC(7, kDebugParser, "LOCATION_PARSER(flags) "); + + if ((_localFlags[_currentLocationIndex] & kFlagsVisited) == 0) { + // only for 1st visit + _localFlags[_currentLocationIndex] = 0; + int _si = 1; + + do { + byte _al = _localFlagNames->lookup(_tokens[_si]); + _localFlags[_currentLocationIndex] |= 1 << (_al - 1); + + _si++; + if (scumm_stricmp(_tokens[_si], "|")) break; + _si++; + } while (true); + } +} + + +DECLARE_LOCATION_PARSER(comment) { + debugC(7, kDebugParser, "LOCATION_PARSER(comment) "); + + _location._comment = parseComment(*_locParseCtxt.script); +} + + +DECLARE_LOCATION_PARSER(endcomment) { + debugC(7, kDebugParser, "LOCATION_PARSER(endcomment) "); + + _location._endComment = parseComment(*_locParseCtxt.script); +} + + +DECLARE_LOCATION_PARSER(sound) { + debugC(7, kDebugParser, "LOCATION_PARSER(sound) "); + + if (getPlatform() == Common::kPlatformAmiga) { + strcpy(_locationSound, _tokens[1]); + _hasLocationSound = true; + } +} + + +DECLARE_LOCATION_PARSER(music) { + debugC(7, kDebugParser, "LOCATION_PARSER(music) "); + + if (getPlatform() == Common::kPlatformAmiga) + _soundMan->setMusicFile(_tokens[1]); +} + +DECLARE_LOCATION_PARSER(redundant) { + debugC(7, kDebugParser, "LOCATION_PARSER(redundant) "); + + warning("redundant '%s' line found in script '%s'", _tokens[0], _locParseCtxt.filename); +} + + +void Parallaction_ns::parseLocation(const char *filename) { + debugC(1, kDebugParser, "parseLocation('%s')", filename); + + allocateLocationSlot(filename); +// printf("got location slot #%i for %s\n", _currentLocationIndex, filename); + + Script *script = _disk->loadLocation(filename); + + // TODO: the following two lines are specific to Nippon Safes + // and should be moved into something like 'initializeParsing()' + _gfx->setFont(_labelFont); + _hasLocationSound = false; + + _locParseCtxt.end = false; + _locParseCtxt.script = script; + _locParseCtxt.filename = filename; + + pushParserTables(&_locationParsers, _locationStmt); + do { + fillBuffers(*script, true); + parseStatement(); + } while (!_locParseCtxt.end); + popParserTables(); + + delete script; + + // this resolves any forward references in the script + for (uint16 _si = 0; _forwardedCommands[_si]; _si++) { + _forwardedCommands[_si]->u._animation = findAnimation(_forwardedAnimationNames[_si]); + _forwardedCommands[_si] = NULL; + } + _numForwards = 0; + + // this loads animation scripts + AnimationList::iterator it = _animations.begin(); + for ( ; it != _animations.end(); it++) { + if ((*it)->_scriptName) + loadProgram(*it, (*it)->_scriptName); + } + + debugC(1, kDebugParser, "parseLocation('%s') done", filename); + return; +} + + +void Parallaction_ns::parseWalkNodes(Script& script, WalkNodeList &list) { + debugC(5, kDebugParser, "parseWalkNodes()"); + + fillBuffers(script, true); + while (scumm_stricmp(_tokens[0], "ENDNODES")) { + + if (!scumm_stricmp(_tokens[0], "COORD")) { + + WalkNode *v4 = new WalkNode( + atoi(_tokens[1]), + atoi(_tokens[2]) + ); + + list.push_front(v4); + } + + fillBuffers(script, true); + } + + debugC(5, kDebugParser, "parseWalkNodes() done"); + + return; +} + +typedef OpcodeImpl<Parallaction_ns> OpcodeV1; +#define INSTRUCTION_PARSER(sig) OpcodeV1(this, &Parallaction_ns::instParse_##sig) +#define ZONE_PARSER(sig) OpcodeV1(this, &Parallaction_ns::locZoneParse_##sig) +#define ANIM_PARSER(sig) OpcodeV1(this, &Parallaction_ns::locAnimParse_##sig) +#define LOCATION_PARSER(sig) OpcodeV1(this, &Parallaction_ns::locParse_##sig) +#define COMMAND_PARSER(sig) OpcodeV1(this, &Parallaction_ns::cmdParse_##sig) + +void Parallaction_ns::initParsers() { + + static const OpcodeV1 op0[] = { + INSTRUCTION_PARSER(defLocal), // invalid opcode -> local definition + INSTRUCTION_PARSER(animation), // on + INSTRUCTION_PARSER(animation), // off + INSTRUCTION_PARSER(x), + INSTRUCTION_PARSER(y), + INSTRUCTION_PARSER(z), + INSTRUCTION_PARSER(f), + INSTRUCTION_PARSER(loop), + INSTRUCTION_PARSER(null), // endloop + INSTRUCTION_PARSER(null), // show + INSTRUCTION_PARSER(inc), + INSTRUCTION_PARSER(inc), // dec + INSTRUCTION_PARSER(set), + INSTRUCTION_PARSER(put), + INSTRUCTION_PARSER(call), + INSTRUCTION_PARSER(null), // wait + INSTRUCTION_PARSER(animation), // start + INSTRUCTION_PARSER(sound), + INSTRUCTION_PARSER(move), + INSTRUCTION_PARSER(endscript) + }; + + uint i; + for (i = 0; i < ARRAYSIZE(op0); i++) + _instructionParsers.push_back(&op0[i]); + + + static const OpcodeV1 op2[] = { + COMMAND_PARSER(invalid), + COMMAND_PARSER(flags), // set + COMMAND_PARSER(flags), // clear + COMMAND_PARSER(animation), // start + COMMAND_PARSER(zone), // speak + COMMAND_PARSER(zone), // get + COMMAND_PARSER(location), // location + COMMAND_PARSER(zone), // open + COMMAND_PARSER(zone), // close + COMMAND_PARSER(zone), // on + COMMAND_PARSER(zone), // off + COMMAND_PARSER(call), // call + COMMAND_PARSER(flags), // toggle + COMMAND_PARSER(drop), // drop + COMMAND_PARSER(simple), // quit + COMMAND_PARSER(move), // move + COMMAND_PARSER(animation), // stop + COMMAND_PARSER(endcommands), // endcommands + COMMAND_PARSER(endcommands) // endzone + }; + + for (i = 0; i < ARRAYSIZE(op2); i++) + _commandParsers.push_back(&op2[i]); + + + static const OpcodeV1 op4[] = { + LOCATION_PARSER(invalid), + LOCATION_PARSER(endlocation), + LOCATION_PARSER(location), + LOCATION_PARSER(disk), + LOCATION_PARSER(nodes), + LOCATION_PARSER(zone), + LOCATION_PARSER(animation), + LOCATION_PARSER(localflags), + LOCATION_PARSER(commands), + LOCATION_PARSER(acommands), + LOCATION_PARSER(flags), + LOCATION_PARSER(comment), + LOCATION_PARSER(endcomment), + LOCATION_PARSER(sound), + LOCATION_PARSER(music), + LOCATION_PARSER(redundant) // for redundant endanimation + }; + + for (i = 0; i < ARRAYSIZE(op4); i++) + _locationParsers.push_back(&op4[i]); + + static const OpcodeV1 op5[] = { + ZONE_PARSER(invalid), + ZONE_PARSER(limits), + ZONE_PARSER(moveto), + ZONE_PARSER(type), + ZONE_PARSER(commands), + ZONE_PARSER(label), + ZONE_PARSER(flags), + ZONE_PARSER(endzone) + }; + + for (i = 0; i < ARRAYSIZE(op5); i++) + _locationZoneParsers.push_back(&op5[i]); + + static const OpcodeV1 op6[] = { + ANIM_PARSER(invalid), + ANIM_PARSER(script), + ANIM_PARSER(commands), + ANIM_PARSER(type), + ANIM_PARSER(label), + ANIM_PARSER(flags), + ANIM_PARSER(file), + ANIM_PARSER(position), + ANIM_PARSER(moveto), + ANIM_PARSER(endanimation) + }; + + for (i = 0; i < ARRAYSIZE(op6); i++) + _locationAnimParsers.push_back(&op6[i]); + + _currentOpcodes = 0; + _currentStatements = 0; + +} + +// +// a comment can appear both at location and Zone levels +// comments are displayed into rectangles on the screen +// +char *Parallaction_ns::parseComment(Script &script) { + + char _tmp_comment[1000] = "\0"; + char *v194; + + do { + char v190[400]; + v194 = script.readLine(v190, 400); + + v194[strlen(v194)-1] = '\0'; + if (!scumm_stricmp(v194, "endtext")) + break; + + strcat(_tmp_comment, v194); + strcat(_tmp_comment, " "); + } while (true); + + v194 = strdup(_tmp_comment); + _tmp_comment[0] = '\0'; + + return v194; +} + + +DECLARE_ZONE_PARSER(invalid) { + debugC(7, kDebugParser, "ZONE_PARSER(invalid) "); + + error("unknown statement '%s' in zone %s", _tokens[0], _locParseCtxt.z->_label._text); +} + +DECLARE_ZONE_PARSER(endzone) { + debugC(7, kDebugParser, "ZONE_PARSER(endzone) "); + + popParserTables(); +} + +DECLARE_ZONE_PARSER(limits) { + debugC(7, kDebugParser, "ZONE_PARSER(limits) "); + + _locParseCtxt.z->_left = atoi(_tokens[1]); + _locParseCtxt.z->_top = atoi(_tokens[2]); + _locParseCtxt.z->_right = atoi(_tokens[3]); + _locParseCtxt.z->_bottom = atoi(_tokens[4]); +} + + +DECLARE_ZONE_PARSER(moveto) { + debugC(7, kDebugParser, "ZONE_PARSER(moveto) "); + + _locParseCtxt.z->_moveTo.x = atoi(_tokens[1]); + _locParseCtxt.z->_moveTo.y = atoi(_tokens[2]); +} + + +DECLARE_ZONE_PARSER(type) { + debugC(7, kDebugParser, "ZONE_PARSER(type) "); + + if (_tokens[2][0] != '\0') { + _locParseCtxt.z->_type = (4 + _objectsNames->lookup(_tokens[2])) << 16; + } + int16 _si = _zoneTypeNames->lookup(_tokens[1]); + if (_si != Table::notFound) { + _locParseCtxt.z->_type |= 1 << (_si - 1); + parseZoneTypeBlock(*_locParseCtxt.script, _locParseCtxt.z); + } + + popParserTables(); +} + + +DECLARE_ZONE_PARSER(commands) { + debugC(7, kDebugParser, "ZONE_PARSER(commands) "); + + parseCommands(*_locParseCtxt.script, _locParseCtxt.z->_commands); +} + + +DECLARE_ZONE_PARSER(label) { + debugC(7, kDebugParser, "ZONE_PARSER(label) "); + +// printf("label: %s", _tokens[1]); + renderLabel(&_locParseCtxt.z->_label._cnv, _tokens[1]); +} + + +DECLARE_ZONE_PARSER(flags) { + debugC(7, kDebugParser, "ZONE_PARSER(flags) "); + + uint16 _si = 1; + + do { + char _al = _zoneFlagNames->lookup(_tokens[_si]); + _si++; + _locParseCtxt.z->_flags |= 1 << (_al - 1); + } while (!scumm_stricmp(_tokens[_si++], "|")); +} + +void Parallaction_ns::parseZone(Script &script, ZoneList &list, char *name) { + debugC(5, kDebugParser, "parseZone(name: %s)", name); + + if (findZone(name)) { + while (scumm_stricmp(_tokens[0], "endzone")) { + fillBuffers(script, true); + } + return; + } + + Zone *z = new Zone; + + z->_label._text = strdup(name); + + _locParseCtxt.z = z; + _locParseCtxt.script = &script; + + list.push_front(z); + + pushParserTables(&_locationZoneParsers, _locationZoneStmt); + + return; +} + + + + +void Parallaction_ns::parseGetData(Script &script, Zone *z) { + + GetData *data = new GetData; + + do { + + if (!scumm_stricmp(_tokens[0], "file")) { + data->_cnv = _disk->loadStatic(_tokens[1]); + data->_backup = (byte*)malloc(data->_cnv->w*data->_cnv->h); + + if ((z->_flags & kFlagsRemove) == 0) { + _gfx->backupGetBackground(data, z->_left, z->_top); + _gfx->flatBlitCnv(data->_cnv, z->_left, z->_top, Gfx::kBitBack); + } + } + + if (!scumm_stricmp(_tokens[0], "icon")) { + data->_icon = 4 + _objectsNames->lookup(_tokens[1]); + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + z->u.get = data; + +} + + +void Parallaction_ns::parseExamineData(Script &script, Zone *z) { + + ExamineData *data = new ExamineData; + + do { + + if (!scumm_stricmp(_tokens[0], "file")) { + data->_filename = strdup(_tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "desc")) { + data->_description = parseComment(script); + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + z->u.examine = data; + +} + + +void Parallaction_ns::parseDoorData(Script &script, Zone *z) { + + DoorData *data = new DoorData; + + do { + + if (!scumm_stricmp(_tokens[0], "slidetext")) { + strcpy(_slideText[0], _tokens[1]); +// printf("%s\t", _slideText[0]); + strcpy(_slideText[1], _tokens[2]); + } + + if (!scumm_stricmp(_tokens[0], "location")) { + data->_location = strdup(_tokens[1]); + } + + if (!scumm_stricmp(_tokens[0], "file")) { +// printf("file: '%s'", _tokens[0]); + + data->_cnv = _disk->loadFrames(_tokens[1]); + uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1); + + Common::Rect r; + data->_cnv->getRect(0, r); + + data->_background = (byte*)malloc(r.width() * r.height()); + _gfx->backupDoorBackground(data, z->_left, z->_top); + + _gfx->flatBlitCnv(data->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); + } + + if (!scumm_stricmp(_tokens[0], "startpos")) { + data->_startPos.x = atoi(_tokens[1]); + data->_startPos.y = atoi(_tokens[2]); + data->_startFrame = atoi(_tokens[3]); + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + z->u.door = data; + +} + + +void Parallaction_ns::parseMergeData(Script &script, Zone *z) { + + MergeData *data = new MergeData; + + do { + + if (!scumm_stricmp(_tokens[0], "obj1")) { + data->_obj1 = 4 + _objectsNames->lookup(_tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "obj2")) { + data->_obj2 = 4 + _objectsNames->lookup(_tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "newobj")) { + data->_obj3 = 4 + _objectsNames->lookup(_tokens[1]); + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + z->u.merge = data; + +} + +void Parallaction_ns::parseHearData(Script &script, Zone *z) { + + HearData *data = new HearData; + + do { + + if (!scumm_stricmp(_tokens[0], "sound")) { + strcpy(data->_name, _tokens[1]); + data->_channel = atoi(_tokens[2]); + } + if (!scumm_stricmp(_tokens[0], "freq")) { + data->_freq = atoi(_tokens[1]); + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + z->u.hear = data; + +} + +void Parallaction_ns::parseSpeakData(Script &script, Zone *z) { + + SpeakData *data = new SpeakData; + + do { + + if (!scumm_stricmp(_tokens[0], "file")) { + strcpy(data->_name, _tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "Dialogue")) { + data->_dialogue = parseDialogue(script); + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + z->u.speak = data; + +} + + +void Parallaction_ns::parseZoneTypeBlock(Script &script, Zone *z) { + debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_label._text, z->_type); + + switch (z->_type & 0xFFFF) { + case kZoneExamine: // examine Zone alloc + parseExamineData(script, z); + break; + + case kZoneDoor: // door Zone alloc + parseDoorData(script, z); + break; + + case kZoneGet: // get Zone alloc + parseGetData(script, z); + break; + + case kZoneMerge: // merge Zone alloc + parseMergeData(script, z); + break; + + case kZoneHear: // hear Zone alloc + parseHearData(script, z); + break; + + case kZoneSpeak: // speak Zone alloc + parseSpeakData(script, z); + break; + + default: + // eats up 'ENDZONE' line for unprocessed zone types + fillBuffers(script, true); + break; + } + + debugC(7, kDebugParser, "parseZoneTypeBlock() done"); + + return; +} + + +} // namespace Parallaction diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index 279dbda1b9..299eba18a3 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -47,8 +47,6 @@ namespace Parallaction { -extern char _gameNames[][20]; - class SaveLoadChooser : public GUI::Dialog { typedef Common::String String; @@ -61,12 +59,12 @@ protected: GUI::StaticTextWidget *_time; GUI::StaticTextWidget *_playtime; GUI::ContainerWidget *_container; - Parallaction *_vm; + Parallaction_ns *_vm; uint8 _fillR, _fillG, _fillB; public: - SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction *engine); + SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine); ~SaveLoadChooser(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); @@ -80,7 +78,7 @@ public: -void Parallaction::doLoadGame(uint16 slot) { +void Parallaction_ns::doLoadGame(uint16 slot) { _introSarcData3 = 200; _introSarcData2 = 1; @@ -179,7 +177,7 @@ void Parallaction::doLoadGame(uint16 slot) { } -void Parallaction::doSaveGame(uint16 slot, const char* name) { +void Parallaction_ns::doSaveGame(uint16 slot, const char* name) { char path[PATH_LEN]; sprintf(path, "game.%i", slot); @@ -251,8 +249,7 @@ enum { }; - -SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction *engine) +SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine) : Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) { // _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR; @@ -340,7 +337,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -int Parallaction::buildSaveFileList(Common::StringList& l) { +int Parallaction_ns::buildSaveFileList(Common::StringList& l) { char name[16]; char buf[30]; @@ -367,7 +364,7 @@ int Parallaction::buildSaveFileList(Common::StringList& l) { } -int Parallaction::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { +int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { SaveLoadChooser* slc = new SaveLoadChooser(caption, button, this); @@ -388,7 +385,7 @@ int Parallaction::selectSaveFile(uint16 arg_0, const char* caption, const char* -void Parallaction::loadGame() { +void Parallaction_ns::loadGame() { int _di = selectSaveFile( 0, "Load file", "Load" ); if (_di == -1) { @@ -406,7 +403,7 @@ void Parallaction::loadGame() { } -void Parallaction::saveGame() { +void Parallaction_ns::saveGame() { if (!scumm_stricmp(_location._name, "caveau")) return; diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp index 21dcc3c788..9b8e179ccb 100644 --- a/engines/parallaction/sound.cpp +++ b/engines/parallaction/sound.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/parallaction/sound.cpp $ - * $Id:sound.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -265,7 +265,7 @@ void DosSoundMan::playCharacterMusic(const char *character) { setMusicFile("dino"); } else if (!scumm_stricmp(name, _donnaName)) { - setMusicFile("dough"); + setMusicFile("donna"); } else if (!scumm_stricmp(name, _doughName)) { setMusicFile("nuts"); @@ -281,14 +281,14 @@ void DosSoundMan::playLocationMusic(const char *location) { if (_musicData1 != 0) { playCharacterMusic(_vm->_characterName); _musicData1 = 0; - debugC(2, kDebugLocation, "changeLocation: started character specific music"); + debugC(2, kDebugExec, "changeLocation: started character specific music"); } if (!scumm_stricmp(location, "night") || !scumm_stricmp(location, "intsushi")) { setMusicFile("nuts"); playMusic(); - debugC(2, kDebugLocation, "changeLocation: started music 'soft'"); + debugC(2, kDebugExec, "changeLocation: started music 'soft'"); } if (!scumm_stricmp(location, "museo") || @@ -302,7 +302,7 @@ void DosSoundMan::playLocationMusic(const char *location) { stopMusic(); _musicData1 = 1; - debugC(2, kDebugLocation, "changeLocation: music stopped"); + debugC(2, kDebugExec, "changeLocation: music stopped"); } } diff --git a/engines/parallaction/sound.h b/engines/parallaction/sound.h index 7a903ec790..f8f1a9e6b0 100644 --- a/engines/parallaction/sound.h +++ b/engines/parallaction/sound.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/parallaction/sound.h $ - * $Id:sound.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp index 046176a933..94d2692ff1 100644 --- a/engines/parallaction/staticres.cpp +++ b/engines/parallaction/staticres.cpp @@ -30,7 +30,7 @@ namespace Parallaction { -byte Gfx::_mouseArrow[256] = { +byte Parallaction_ns::_mouseArrow[256] = { 0x12, 0x11, 0x11, 0x11, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x11, 0x13, 0x12, 0x12, 0x00, 0x13, 0x12, 0x12, 0x11, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x12, 0x00, @@ -50,8 +50,7 @@ byte Gfx::_mouseArrow[256] = { }; -byte _amigaTopazFont[2600] = -{ +byte _amigaTopazFont[2600] = { 0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79, 0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, @@ -249,19 +248,6 @@ const char *_zoneTypeNamesRes_ns[] = { "Command" }; -const char _gameNames[10][20] = { - "GAME1", - "GAME2", - "GAME3", - "GAME4", - "GAME5", - "GAME6", - "GAME7", - "GAME8", - "GAME9", - "GAME10" -}; - const char *_commandsNamesRes_ns[] = { "set", "clear", @@ -278,7 +264,9 @@ const char *_commandsNamesRes_ns[] = { "drop", "quit", "move", - "stop" + "stop", + "endcommands", + "endzone" }; const char *_instructionNamesRes_ns[] = { @@ -299,7 +287,8 @@ const char *_instructionNamesRes_ns[] = { "wait", "start", "sound", - "move" + "move", + "endscript" }; const char *_callableNamesRes_ns[] = { @@ -330,6 +319,46 @@ const char *_callableNamesRes_ns[] = { "TestResult" }; +const char *_locationStmtRes_ns[] = { + "endlocation", + "location", + "disk", + "nodes", + "zone", + "animation", + "localflags", + "commands", + "acommands", + "flags", + "comment", + "endcomment", + "sound", + "music", + "endanimation" +}; + +const char *_locationZoneStmtRes_ns[] = { + "limits", + "moveto", + "type", + "commands", + "label", + "flags", + "endzone" +}; + +const char *_locationAnimStmtRes_ns[] = { + "script", + "commands", + "type", + "label", + "flags", + "file", + "position", + "moveto", + "endanimation" +}; + const char *_zoneTypeNamesRes_br[] = { "examine", "door", @@ -392,11 +421,11 @@ const char *_instructionNamesRes_br[] = { "mul", "div", "if", - "ifeq", - "iflt", - "ifgt", + "dummy", + "dummy", "endif", - "stop" + "stop", + "endscript" }; const char *_commandsNamesRes_br[] = { @@ -404,7 +433,7 @@ const char *_commandsNamesRes_br[] = { "clear", "start", "speak", - "get" + "get", "location", "open", "close", @@ -424,7 +453,7 @@ const char *_commandsNamesRes_br[] = { "leave", "inc", "dec", - "text", + "test", "dummy", "dummy", "let", @@ -440,7 +469,10 @@ const char *_commandsNamesRes_br[] = { "dummy", "return", "onsave", - "offsave" + "offsave", + "endcommands", + "ifchar", + "endif" }; const char *_callableNamesRes_br[] = { @@ -472,6 +504,52 @@ const char *_audioCommandsNamesRes_br[] = { "loop" }; +const char *_locationStmtRes_br[] = { + "character", + "endlocation", + "ifchar", + "endif", + "location", + "mask", + "path", + "disk", + "localflags", + "commands", + "escape", + "acommands", + "flags", + "comment", + "endcomment", + "zone", + "animation", + "zeta", + "music", + "sound" +}; + +const char *_locationZoneStmtRes_br[] = { + "endzone", + "limits", + "moveto", + "type", + "commands", + "label", + "flags" +}; + +const char *_locationAnimStmtRes_br[] = { + "endanimation", + "endzone", + "script", + "commands", + "type", + "label", + "flags", + "file", + "position", + "moveto" +}; + const char *_dinoName = "dino"; const char *_donnaName = "donna"; const char *_doughName = "dough"; @@ -525,7 +603,7 @@ const Parallaction_ns::Callable Parallaction_ns::_amigaCallables[] = { CALLABLE_NS(_c_startMusic), CALLABLE_NS(_c_closeMusic), CALLABLE_NS(_c_fade), - CALLABLE_NS(_c_play_boogie), + CALLABLE_NS(_c_HBOn), CALLABLE_NS(_c_moveSarc), CALLABLE_NS(_c_contaFoglie), CALLABLE_NS(_c_zeroFoglie), @@ -564,8 +642,11 @@ void Parallaction_ns::initResources() { _zoneFlagNames = new Table(ARRAYSIZE(_zoneFlagNamesRes_ns), _zoneFlagNamesRes_ns); _zoneTypeNames = new Table(ARRAYSIZE(_zoneTypeNamesRes_ns), _zoneTypeNamesRes_ns); _commandsNames = new Table(ARRAYSIZE(_commandsNamesRes_ns), _commandsNamesRes_ns); + _locationStmt = new Table(ARRAYSIZE(_locationStmtRes_ns), _locationStmtRes_ns); + _locationZoneStmt = new Table(ARRAYSIZE(_locationZoneStmtRes_ns), _locationZoneStmtRes_ns); + _locationAnimStmt = new Table(ARRAYSIZE(_locationAnimStmtRes_ns), _locationAnimStmtRes_ns); - _localFlagNames = new Table(120); + _localFlagNames = new FixedTable(NUM_LOCATIONS, 1); _localFlagNames->addData("visited"); if (getPlatform() == Common::kPlatformPC) { @@ -591,10 +672,13 @@ void Parallaction_br::initResources() { _zoneTypeNames = new Table(ARRAYSIZE(_zoneTypeNamesRes_br), _zoneTypeNamesRes_br); _commandsNames = new Table(ARRAYSIZE(_commandsNamesRes_br), _commandsNamesRes_br); _audioCommandsNames = new Table(ARRAYSIZE(_audioCommandsNamesRes_br), _audioCommandsNamesRes_br); + _locationStmt = new Table(ARRAYSIZE(_locationStmtRes_br), _locationStmtRes_br); + _locationZoneStmt = new Table(ARRAYSIZE(_locationZoneStmtRes_br), _locationZoneStmtRes_br); + _locationAnimStmt = new Table(ARRAYSIZE(_locationAnimStmtRes_br), _locationAnimStmtRes_br); - // TODO: make sure there are 120 max locations in Big Red Adventure - _localFlagNames = new Table(120); + _localFlagNames = new FixedTable(NUM_LOCATIONS, 2); _localFlagNames->addData("visited"); + _localFlagNames->addData("testtrue"); if (getPlatform() == Common::kPlatformPC) { _callables = _dosCallables; diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index d57e9d2532..73b7407308 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -29,8 +29,6 @@ namespace Parallaction { -static byte *_buffer; - static uint16 _doorData1 = 1000; static Zone *_zoneTrap = NULL; @@ -38,32 +36,27 @@ static uint16 walkData1 = 0; static uint16 walkData2 = 0; // next walk frame -uint16 queryPath(uint16 x, uint16 y) { - - // NOTE: a better solution would have us mirror each byte in the mask in the loading routine - // AmigaDisk_ns::loadPath() instead of doing it here. - - byte _al = _buffer[y*40 + x/8]; - byte _dl = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7)); - - return _al & (1 << _dl); +inline byte PathBuffer::getValue(uint16 x, uint16 y) { + byte m = data[(x >> 3) + y * internalWidth]; + uint n = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7)); + return ((1 << n) & m) >> n; } // adjusts position towards nearest walkable point // void PathBuilder::correctPathPoint(Common::Point &to) { - if (queryPath(to.x, to.y)) return; + if (_vm->_pathBuffer->getValue(to.x, to.y)) return; int16 right = to.x; int16 left = to.x; do { right++; - } while ((queryPath(right, to.y) == 0) && (right < _vm->_screenWidth)); + } while ((_vm->_pathBuffer->getValue(right, to.y) == 0) && (right < _vm->_pathBuffer->w)); do { left--; - } while ((queryPath(left, to.y) == 0) && (left > 0)); - right = (right == _vm->_screenWidth) ? 1000 : right - to.x; + } while ((_vm->_pathBuffer->getValue(left, to.y) == 0) && (left > 0)); + right = (right == _vm->_pathBuffer->w) ? 1000 : right - to.x; left = (left == 0) ? 1000 : to.x - left; @@ -71,12 +64,12 @@ void PathBuilder::correctPathPoint(Common::Point &to) { int16 bottom = to.y; do { top--; - } while ((queryPath(to.x, top) == 0) && (top > 0)); + } while ((_vm->_pathBuffer->getValue(to.x, top) == 0) && (top > 0)); do { bottom++; - } while ((queryPath(to.x, bottom) == 0) && (bottom < _vm->_screenHeight)); + } while ((_vm->_pathBuffer->getValue(to.x, bottom) == 0) && (bottom < _vm->_pathBuffer->h)); top = (top == 0) ? 1000 : to.y - top; - bottom = (bottom == _vm->_screenHeight) ? 1000 : bottom - to.y; + bottom = (bottom == _vm->_pathBuffer->h) ? 1000 : bottom - to.y; int16 closeX = (right >= left) ? left : right; @@ -163,7 +156,7 @@ WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) { correctPathPoint(to); debugC(1, kDebugWalk, "found closest path point at (%i, %i)", to.x, to.y); - WalkNode *v48 = new WalkNode(to.x - _vm->_char._ani.width() / 2, to.y - _vm->_char._ani.height()); + WalkNode *v48 = new WalkNode(to.x, to.y); WalkNode *v44 = new WalkNode(*v48); uint16 v38 = walkFunc1(to.x, to.y, v44); @@ -185,7 +178,9 @@ WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) { #endif Common::Point stop(v48->_x, v48->_y); - Common::Point pos(_vm->_char._ani._left, _vm->_char._ani._top); + Common::Point pos; + _vm->_char.getFoot(pos); + uint32 v34 = buildSubPath(pos, stop); if (v38 != 0 && v34 > v38) { // no alternative path (gap?) @@ -223,19 +218,17 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNode *Node) { Common::Point v4(0, 0); - Common::Point foot( - _vm->_char._ani._left + _vm->_char._ani.width()/2, - _vm->_char._ani._top + _vm->_char._ani.height() - ); + Common::Point foot; + _vm->_char.getFoot(foot); Common::Point v8(foot); while (foot != arg) { - if (foot.x < x && queryPath(foot.x + 1, foot.y) != 0) foot.x++; - if (foot.x > x && queryPath(foot.x - 1, foot.y) != 0) foot.x--; - if (foot.y < y && queryPath(foot.x, foot.y + 1) != 0) foot.y++; - if (foot.y > y && queryPath(foot.x, foot.y - 1) != 0) foot.y--; + if (foot.x < x && _vm->_pathBuffer->getValue(foot.x + 1, foot.y) != 0) foot.x++; + if (foot.x > x && _vm->_pathBuffer->getValue(foot.x - 1, foot.y) != 0) foot.x--; + if (foot.y < y && _vm->_pathBuffer->getValue(foot.x, foot.y + 1) != 0) foot.y++; + if (foot.y > y && _vm->_pathBuffer->getValue(foot.x, foot.y - 1) != 0) foot.y--; if (foot == v8 && foot != arg) { @@ -245,10 +238,10 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNode *Node) { while (foot != arg) { - if (foot.x < x && queryPath(foot.x + 1, foot.y) == 0) foot.x++; - if (foot.x > x && queryPath(foot.x - 1, foot.y) == 0) foot.x--; - if (foot.y < y && queryPath(foot.x, foot.y + 1) == 0) foot.y++; - if (foot.y > y && queryPath(foot.x, foot.y - 1) == 0) foot.y--; + if (foot.x < x && _vm->_pathBuffer->getValue(foot.x + 1, foot.y) == 0) foot.x++; + if (foot.x > x && _vm->_pathBuffer->getValue(foot.x - 1, foot.y) == 0) foot.x--; + if (foot.y < y && _vm->_pathBuffer->getValue(foot.x, foot.y + 1) == 0) foot.y++; + if (foot.y > y && _vm->_pathBuffer->getValue(foot.x, foot.y - 1) == 0) foot.y--; if (foot == v8 && foot != arg) return 0; @@ -256,8 +249,8 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNode *Node) { v8 = foot; } - Node->_x = v4.x - _vm->_char._ani.width() / 2; - Node->_y = v4.y - _vm->_char._ani.height(); + Node->_x = v4.x; + Node->_y = v4.y; return (x - v4.x) * (x - v4.x) + (y - v4.y) * (y - v4.y); } @@ -272,19 +265,19 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNode *Node) { void Parallaction::clipMove(Common::Point& pos, const WalkNode* from) { - if ((pos.x < from->_x) && (pos.x < _screenWidth) && (queryPath(_char._ani.width()/2 + pos.x + 2, _char._ani.height() + pos.y) != 0)) { + if ((pos.x < from->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { pos.x = (pos.x + 2 < from->_x) ? pos.x + 2 : from->_x; } - if ((pos.x > from->_x) && (pos.x > -20) && (queryPath(_char._ani.width()/2 + pos.x - 2, _char._ani.height() + pos.y) != 0)) { + if ((pos.x > from->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { pos.x = (pos.x - 2 > from->_x) ? pos.x - 2 : from->_x; } - if ((pos.y < from->_y) && (pos.y < (_screenHeight - _char._ani.height())) && (queryPath(_char._ani.width()/2 + pos.x, _char._ani.height() + pos.y + 2) != 0)) { + if ((pos.y < from->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { pos.y = (pos.y + 2 <= from->_y) ? pos.y + 2 : from->_y; } - if ((pos.y > from->_y) && (pos.y > -20) && (queryPath(_char._ani.width()/2 + pos.x, _char._ani.height() + pos.y- 2) != 0)) { + if ((pos.y > from->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { pos.y = (pos.y - 2 >= from->_y) ? pos.y - 2 :from->_y; } @@ -342,13 +335,16 @@ uint16 Parallaction::checkDoor() { } _engineFlags &= ~kEngineWalking; - Zone *z = hitZone(kZoneDoor, _char._ani._left + _char._ani.width() / 2, _char._ani._top + _char._ani.height()); + + Common::Point foot; + + _char.getFoot(foot); + Zone *z = hitZone(kZoneDoor, foot.x, foot.y); if (z != NULL) { if ((z->_flags & kFlagsClosed) == 0) { - _location._startPosition.x = z->u.door->_startPos.x; - _location._startPosition.y = z->u.door->_startPos.y; + _location._startPosition = z->u.door->_startPos; _location._startFrame = z->u.door->_startFrame; strcpy(_location._name, z->u.door->_location); @@ -360,7 +356,8 @@ uint16 Parallaction::checkDoor() { } } - z = hitZone(kZoneTrap, _char._ani._left + _char._ani.width() / 2, _char._ani._top + _char._ani.height()); + _char.getFoot(foot); + z = hitZone(kZoneTrap, foot.x, foot.y); if (z != NULL) { _localFlags[_currentLocationIndex] |= kFlagsEnter; @@ -387,11 +384,14 @@ void Parallaction::finalizeWalk(WalkNodeList *list) { delete list; } -void jobWalk(void *parm, Job *j) { +void Parallaction_ns::jobWalk(void *parm, Job *j) { WalkNodeList *list = (WalkNodeList*)parm; - Common::Point pos(_vm->_char._ani._left, _vm->_char._ani._top); - _vm->_char._ani._oldPos = pos; + _char._ani._oldPos.x = _char._ani._left; + _char._ani._oldPos.y = _char._ani._top; + + Common::Point pos; + _char.getFoot(pos); WalkNodeList::iterator it = list->begin(); @@ -404,39 +404,31 @@ void jobWalk(void *parm, Job *j) { if (it == list->end()) { debugC(1, kDebugWalk, "jobWalk reached last node"); j->_finished = 1; - _vm->finalizeWalk(list); + finalizeWalk(list); return; } j->_parm = list; // selectWalkFrame must be performed before position is changed by clipMove - int16 v16 = _vm->selectWalkFrame(pos, *it); - _vm->clipMove(pos, *it); + int16 v16 = selectWalkFrame(pos, *it); + clipMove(pos, *it); - _vm->_char._ani._left = pos.x; - _vm->_char._ani._top = pos.y; + _char.setFoot(pos); - if (pos == _vm->_char._ani._oldPos) { + Common::Point newpos(_char._ani._left, _char._ani._top); + + if (newpos == _char._ani._oldPos) { debugC(1, kDebugWalk, "jobWalk was blocked by an unforeseen obstacle"); j->_finished = 1; - _vm->finalizeWalk(list); + finalizeWalk(list); } else { - _vm->_char._ani._frame = v16 + walkData2 + 1; + _char._ani._frame = v16 + walkData2 + 1; } return; } -void Parallaction::setPath(byte *path) { - memcpy(_buffer, path, _screenPathSize); -} - -void Parallaction::initWalk() { - _buffer = (byte*)malloc(_screenPathSize); -} - - WalkNode::WalkNode() : _x(0), _y(0) { } @@ -459,3 +451,4 @@ PathBuilder::PathBuilder(Animation *anim) : _anim(anim), _list(0) { + diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index 476f5cc47a..dcbc3d5aa9 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -50,6 +50,40 @@ typedef ManagedList<WalkNode*> WalkNodeList; void jobWalk(void*, Job *j); +struct PathBuffer { + // handles a 1-bit depth buffer used for masking non-walkable areas + + uint16 w; + uint16 internalWidth; + uint16 h; + uint size; + byte *data; + +public: + PathBuffer() : w(0), internalWidth(0), h(0), size(0), data(0) { + } + + void create(uint16 width, uint16 height) { + w = width; + internalWidth = w >> 3; + h = height; + size = (internalWidth * h); + data = (byte*)calloc(size, 1); + } + + void free() { + if (data) + ::free(data); + data = 0; + w = 0; + h = 0; + internalWidth = 0; + size = 0; + } + + inline byte getValue(uint16 x, uint16 y); +}; + class PathBuilder { diff --git a/engines/parallaction/zone.cpp b/engines/parallaction/zone.cpp deleted file mode 100644 index 50f63b3b75..0000000000 --- a/engines/parallaction/zone.cpp +++ /dev/null @@ -1,690 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - - -#include "common/stdafx.h" - -#include "parallaction/parallaction.h" -#include "parallaction/sound.h" - -namespace Parallaction { - - - - -Zone *Parallaction::findZone(const char *name) { - - for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) - if (!scumm_stricmp((*it)->_label._text, name)) return *it; - - return findAnimation(name); -} - - - - -void Parallaction::parseZone(Script &script, ZoneList &list, char *name) { -// printf("parseZone(%s)", name); - - if (findZone(name)) { - while (scumm_stricmp(_tokens[0], "endzone")) { - fillBuffers(script, true); - } - return; - } - - Zone *z = new Zone; - - z->_label._text = (char*)malloc(strlen(name)+1); - strcpy(z->_label._text, name); - - list.push_front(z); - - fillBuffers(script, true); - while (scumm_stricmp(_tokens[0], "endzone")) { -// printf("token[0] = %s", _tokens[0]); - - if (!scumm_stricmp(_tokens[0], "limits")) { - z->_left = atoi(_tokens[1]); - z->_top = atoi(_tokens[2]); - z->_right = atoi(_tokens[3]); - z->_bottom = atoi(_tokens[4]); - } - if (!scumm_stricmp(_tokens[0], "moveto")) { - z->_moveTo.x = atoi(_tokens[1]); - z->_moveTo.y = atoi(_tokens[2]); - } - if (!scumm_stricmp(_tokens[0], "type")) { - if (_tokens[2][0] != '\0') { - z->_type = (4 + _objectsNames->lookup(_tokens[2])) << 16; - } - int16 _si = _zoneTypeNames->lookup(_tokens[1]); - if (_si != -1) { - z->_type |= 1 << (_si - 1); - parseZoneTypeBlock(script, z); - continue; - } - } - if (!scumm_stricmp(_tokens[0], "commands")) { - parseCommands(script, z->_commands); - } - if (!scumm_stricmp(_tokens[0], "label")) { -// printf("label: %s", _tokens[1]); - _gfx->makeCnvFromString(&z->_label._cnv, _tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "flags")) { - uint16 _si = 1; - - do { - char _al = _zoneFlagNames->lookup(_tokens[_si]); - _si++; - z->_flags |= 1 << (_al - 1); - } while (!scumm_stricmp(_tokens[_si++], "|")); - } - - fillBuffers(script, true); - } - - return; -} - -void Parallaction::freeZones() { - debugC(1, kDebugLocation, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); - - ZoneList::iterator it = _zones.begin(); - - while ( it != _zones.end() ) { - - Zone* z = *it; - - // 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 hitZone. - if (((z->_top == -1) || - ((z->_left == -2) && ( - (((z->_type & 0xFFFF) == kZoneMerge) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj1)) != 0) || (isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj2)) != 0))) || - (((z->_type & 0xFFFF) == kZoneGet) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.get->_icon)) != 0))) - ))) && - ((_engineFlags & kEngineQuit) == 0)) { - - debugC(1, kDebugLocation, "freeZones preserving zone '%s'", z->_label._text); - - it++; - - } else - - it = _zones.erase(it); - - } - - return; -} - - - - - - - - - -void Parallaction::parseZoneTypeBlock(Script &script, Zone *z) { -// printf("parseZoneTypeBlock()"); - - TypeData *u = &z->u; - - switch (z->_type & 0xFFFF) { - case kZoneExamine: // examine Zone alloc - u->examine = new ExamineData; - break; - - case kZoneDoor: // door Zone alloc - u->door = new DoorData; - break; - - case kZoneGet: // get Zone alloc - u->get = new GetData; - break; - - case kZoneMerge: // merge Zone alloc - u->merge = new MergeData; - break; - - case kZoneHear: // hear Zone alloc - u->hear = new HearData; - break; - - case kZoneSpeak: // speak Zone alloc - u->speak = new SpeakData; - break; - - } - - char vC8[PATH_LEN]; - -// printf("type = %x", z->_type); - - do { - - switch (z->_type & 0xFFFF) { - case kZoneExamine: // examine Zone init - if (!scumm_stricmp(_tokens[0], "file")) { - u->examine->_filename = (char*)malloc(strlen(_tokens[1])+1); - strcpy(u->examine->_filename, _tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "desc")) { - u->examine->_description = parseComment(script); - } - break; - - case kZoneDoor: // door Zone init - if (!scumm_stricmp(_tokens[0], "slidetext")) { - strcpy(_slideText[0], _tokens[1]); -// printf("%s\t", _slideText[0]); - strcpy(_slideText[1], _tokens[2]); - } - - if (!scumm_stricmp(_tokens[0], "location")) { - u->door->_location = (char*)malloc(strlen(_tokens[1])+1); - strcpy(u->door->_location, _tokens[1]); - } - - if (!scumm_stricmp(_tokens[0], "file")) { -// printf("file: '%s'", _tokens[0]); - - strcpy(vC8, _tokens[1]); - - u->door->_cnv = _disk->loadFrames(vC8); - uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1); - - u->door->_background = (byte*)malloc(u->door->_cnv->_width * u->door->_cnv->_height); - _gfx->backupDoorBackground(u->door, z->_left, z->_top); - - _gfx->flatBlitCnv(u->door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); - } - - if (!scumm_stricmp(_tokens[0], "startpos")) { - u->door->_startPos.x = atoi(_tokens[1]); - u->door->_startPos.y = atoi(_tokens[2]); - u->door->_startFrame = atoi(_tokens[3]); - } - break; - - case kZoneGet: // get Zone init - if (!scumm_stricmp(_tokens[0], "file")) { - strcpy(vC8, _tokens[1]); - u->get->_cnv = _disk->loadStatic(vC8); - u->get->_backup = (byte*)malloc(u->get->_cnv->_width*u->get->_cnv->_height); - - if ((z->_flags & kFlagsRemove) == 0) { - _gfx->backupGetBackground(u->get, z->_left, z->_top); - _gfx->flatBlitCnv(u->get->_cnv, z->_left, z->_top, Gfx::kBitBack); - } - } - - if (!scumm_stricmp(_tokens[0], "icon")) { - u->get->_icon = 4 + _objectsNames->lookup(_tokens[1]); - } - break; - - case kZoneMerge: // merge Zone init - if (!scumm_stricmp(_tokens[0], "obj1")) { - u->merge->_obj1 = 4 + _objectsNames->lookup(_tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "obj2")) { - u->merge->_obj2 = 4 + _objectsNames->lookup(_tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "newobj")) { - u->merge->_obj3 = 4 + _objectsNames->lookup(_tokens[1]); - } - break; - - case kZoneHear: // hear Zone init - if (!scumm_stricmp(_tokens[0], "sound")) { - strcpy(u->hear->_name, _tokens[1]); - z->u.hear->_channel = atoi(_tokens[2]); - } - if (!scumm_stricmp(_tokens[0], "freq")) { - z->u.hear->_freq = atoi(_tokens[1]); - } - break; - - case kZoneSpeak: // speak Zone init - if (!scumm_stricmp(_tokens[0], "file")) { - strcpy(u->speak->_name, _tokens[1]); -// printf("speak file name: %s", u.speak._name); - } - if (!scumm_stricmp(_tokens[0], "Dialogue")) { - u->speak->_dialogue = parseDialogue(script); - } - break; - } - - fillBuffers(script, true); - } while (scumm_stricmp(_tokens[0], "endzone")); - - return; -} - -// displays character head commenting an examined object -// -// works on the frontbuffer -// -void Parallaction::displayCharacterComment(ExamineData *data) { - if (data->_description == NULL) return; - - // NOTE: saving visible screen before displaying comment allows - // to restore the exact situation after the comment is deleted. - // This means animations are restored in the exact position as - // they were, thus avoiding clipping effect as signalled in - // BUG item #1762614. - _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); - - _gfx->setFont(kFontDialogue); - _gfx->flatBlitCnv(_char._talk, 0, 190, 80, Gfx::kBitFront); - - int16 v26, v28; - _gfx->getStringExtent(data->_description, 130, &v28, &v26); - Common::Rect r(v28, v26); - r.moveTo(140, 10); - _gfx->drawBalloon(r, 0); - _gfx->displayWrappedString(data->_description, 140, 10, 0, 130); - - waitUntilLeftClick(); - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _gfx->updateScreen(); - - return; -} - -// -// ZONE TYPE: EXAMINE -// - -// display detail view of an item (and eventually comments) -// -// works on the frontbuffer -// - -void Parallaction::displayItemComment(ExamineData *data) { - - if (data->_description == NULL) return; - - _gfx->setHalfbriteMode(true); - - char v68[PATH_LEN]; - strcpy(v68, data->_filename); - data->_cnv = _disk->loadStatic(v68); - _gfx->flatBlitCnv(data->_cnv, 140, (_screenHeight - data->_cnv->_height)/2, Gfx::kBitFront); - _gfx->freeStaticCnv(data->_cnv); - delete data->_cnv; - - int16 v6A = 0, v6C = 0; - - _gfx->setFont(kFontDialogue); - _gfx->getStringExtent(data->_description, 130, &v6C, &v6A); - Common::Rect r(v6C, v6A); - r.moveTo(0, 90); - _gfx->drawBalloon(r, 0); - _gfx->flatBlitCnv(_char._head, 100, 152, Gfx::kBitFront); - _gfx->displayWrappedString(data->_description, 0, 90, 0, 130); - - jobEraseAnimations((void*)1, NULL); - _gfx->updateScreen(); - - waitUntilLeftClick(); - - _gfx->setHalfbriteMode(false); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _gfx->updateScreen(); - - return; -} - - - -uint16 Parallaction::runZone(Zone *z) { - debugC(3, kDebugLocation, "runZone (%s)", z->_label._text); - - uint16 subtype = z->_type & 0xFFFF; - - debugC(3, kDebugLocation, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); - switch(subtype) { - - case kZoneExamine: - if (z->u.examine->_filename) { - displayItemComment(z->u.examine); - } else { - displayCharacterComment(z->u.examine); - } - break; - - case kZoneGet: - if (z->_flags & kFlagsFixed) break; - if (pickupItem(z) != 0) { - return 1; - } - z->_flags |= kFlagsRemove; - break; - - case kZoneDoor: - if (z->_flags & kFlagsLocked) break; - z->_flags ^= kFlagsClosed; - if (z->u.door->_cnv == NULL) break; - addJob(&jobToggleDoor, z, kPriority18 ); - break; - - case kZoneHear: - _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); - break; - - case kZoneSpeak: - runDialogue(z->u.speak); - break; - - } - - debugC(3, kDebugLocation, "runZone completed"); - - return 0; -} - -// -// ZONE TYPE: DOOR -// -void jobToggleDoor(void *parm, Job *j) { - - static byte count = 0; - - Zone *z = (Zone*)parm; - - StaticCnv v14; - - if (z->u.door->_cnv) { - Common::Rect r(z->_left, z->_top, z->_left+z->u.door->_cnv->_width, z->_top+z->u.door->_cnv->_height); - - uint16 _ax = (z->_flags & kFlagsClosed ? 1 : 0); - - v14._width = z->u.door->_cnv->_width; - v14._height = z->u.door->_cnv->_height; - v14._data0 = z->u.door->_cnv->getFramePtr(_ax); - - _vm->_gfx->restoreDoorBackground(&v14, r, z->u.door->_background); - - _ax = (z->_flags & kFlagsClosed ? 0 : 1); - - _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); - _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBit2); - } - - count++; - if (count == 2) { - j->_finished = 1; - count = 0; - } - - return; -} - - - -// -// ZONE TYPE: GET -// - -int16 Parallaction::pickupItem(Zone *z) { - int r = addInventoryItem(z->u.get->_icon); - if (r == 0) - addJob(&jobRemovePickedItem, z, kPriority17 ); - - return r; -} - -void jobRemovePickedItem(void *parm, Job *j) { - - Zone *z = (Zone*)parm; - - static uint16 count = 0; - - if (z->u.get->_cnv) { - Common::Rect r(z->_left, z->_top, z->_left + z->u.get->_cnv->_width, z->_top + z->u.get->_cnv->_height); - - _vm->_gfx->restoreGetBackground(r, z->u.get->_backup); - } - - count++; - if (count == 2) { - count = 0; - j->_finished = 1; - } - - return; -} - -void jobDisplayDroppedItem(void *parm, Job *j) { -// printf("jobDisplayDroppedItem..."); - - Zone *z = (Zone*)parm; - - if (z->u.get->_cnv) { - if (j->_count == 0) { - _vm->_gfx->backupGetBackground(z->u.get, z->_left, z->_top); - } - - _vm->_gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBitBack); - _vm->_gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBit2); - } - - j->_count++; - if (j->_count == 2) { - j->_count = 0; - j->_finished = 1; - } - -// printf("done"); - - return; -} - - - - -Zone *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 = _zones.begin(); it != _zones.end(); it++) { -// printf("Zone name: %s", z->_name); - - Zone *z = *it; - - if (z->_flags & kFlagsRemove) continue; - - Common::Rect r; - z->getRect(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->_left == -2) || (z->_left == -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->_left != -1) - continue; - if (_si < _char._ani._left) - continue; - if (_si > (_char._ani._left + _char._ani.width())) - continue; - if (_di < _char._ani._top) - continue; - if (_di > (_char._ani._top + _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 it = _animations.begin(); it != _animations.end(); it++) { - - Animation *a = *it; - - _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation - _e = ((_si >= a->_left + a->width()) || (_si <= a->_left)) ? 0 : 1; // _e: horizontal range - _f = ((_di >= a->_top + a->height()) || (_di <= a->_top)) ? 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 NULL; -} - - -Zone::Zone() { - _left = _top = _right = _bottom = 0; - - _type = 0; - _flags = 0; -} - -Zone::~Zone() { -// printf("~Zone(%s)\n", _label._text); - - switch (_type & 0xFFFF) { - case kZoneExamine: - free(u.examine->_filename); - free(u.examine->_description); - delete u.examine; - break; - - case kZoneDoor: - free(u.door->_location); - free(u.door->_background); - if (u.door->_cnv) - delete u.door->_cnv; - delete u.door; - break; - - case kZoneSpeak: - delete u.speak->_dialogue; - delete u.speak; - break; - - case kZoneGet: - free(u.get->_backup); - _vm->_gfx->freeStaticCnv(u.get->_cnv); - if (u.get->_cnv) - delete u.get->_cnv; - delete u.get; - break; - - case kZoneHear: - delete u.hear; - break; - - case kZoneMerge: - delete u.merge; - break; - - default: - break; - } -} - -void Zone::getRect(Common::Rect& r) const { - r.left = _left; - r.right = _right; - r.top = _top; - r.bottom = _bottom; -} - -void Zone::translate(int16 x, int16 y) { - _left += x; - _right += x; - _top += y; - _bottom += y; -} - -uint16 Zone::width() const { - return _right - _left; -} - -uint16 Zone::height() const { - return _bottom - _top; -} - -Label::Label() { - _text = NULL; -} - -Label::~Label() { - _vm->_gfx->freeStaticCnv(&_cnv); - if (_text) - free(_text); -} - - -} // namespace Parallaction diff --git a/engines/queen/cutaway.cpp b/engines/queen/cutaway.cpp index 1f34128820..721d7bb318 100644 --- a/engines/queen/cutaway.cpp +++ b/engines/queen/cutaway.cpp @@ -181,8 +181,7 @@ void Cutaway::loadStrings(uint16 offset) { debug(6, "_talkTo = %i", _talkTo); } -const byte *Cutaway::getCutawayObject(const byte *ptr, CutawayObject &object) -{ +const byte *Cutaway::getCutawayObject(const byte *ptr, CutawayObject &object) { const byte *oldPtr = ptr; object.objectNumber = (int16)READ_BE_INT16(ptr); ptr += 2; @@ -216,8 +215,7 @@ const byte *Cutaway::getCutawayObject(const byte *ptr, CutawayObject &object) return ptr; } -void Cutaway::dumpCutawayObject(int index, CutawayObject &object) -{ +void Cutaway::dumpCutawayObject(int index, CutawayObject &object) { debug(6, "----- CutawayObject[%i] -----", index); const char *objectNumberStr; @@ -367,7 +365,7 @@ void Cutaway::changeRooms(CutawayObject &object) { _vm->logic()->oldRoom(_initialRoom); - // FIXME - Cutaway c41f is played at the end of the command 0x178. This command + // FIXME: Cutaway c41f is played at the end of the command 0x178. This command // setups some persons and associates bob slots to them. They should be hidden as // their y coordinate is > 150, but they aren't ! As a workaround, we display the room // with the panel area enabled. We do the same problem for cutaway c62c. diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp index a8c2747753..9c4101f1d3 100644 --- a/engines/queen/display.cpp +++ b/engines/queen/display.cpp @@ -36,14 +36,6 @@ namespace Queen { -#ifdef PALMOS_68K -static const uint8 *_fontRegular; -static const uint8 *_fontHebrew; -static const uint8 *_fontRussian; -static const uint8 *_palJoeClothes; -static const uint8 *_palJoeDress; -#endif - Display::Display(QueenEngine *vm, OSystem *system) : _fullscreen(true), _horizontalScroll(0), _bdWidth(0), _bdHeight(0), _system(system), _vm(vm) { @@ -1230,7 +1222,6 @@ void Display::blankScreenEffect3() { } } -#ifndef PALMOS_68K const uint8 Display::_fontRegular[] = { 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, @@ -1636,25 +1627,4 @@ const uint8 Display::_palJoeDress[] = { 0x22, 0xED, 0x42, 0x42, 0x80, 0x45, 0x45, 0xA3, 0x5F, 0x5F, 0xC8, 0x7C, 0x7C, 0xEC, 0x9C, 0x9C }; -#endif - } // End of namespace Queen - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Queen_Display) -_GSETPTR(Queen::_fontRegular, GBVARS_DISPLAYFONTREGULAR_INDEX, uint8, GBVARS_QUEEN) -_GSETPTR(Queen::_fontHebrew, GBVARS_DISPLAYFONTHEBREW_INDEX, uint8, GBVARS_QUEEN) -_GSETPTR(Queen::_palJoeClothes, GBVARS_DISPLAYPALJOECLOTHES_INDEX, uint8, GBVARS_QUEEN) -_GSETPTR(Queen::_palJoeDress, GBVARS_DISPLAYPALJOEDRESS_INDEX, uint8, GBVARS_QUEEN) -_GEND - -_GRELEASE(Queen_Display) -_GRELEASEPTR(GBVARS_DISPLAYFONTREGULAR_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_DISPLAYFONTHEBREW_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_DISPLAYPALJOECLOTHES_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_DISPLAYPALJOEDRESS_INDEX, GBVARS_QUEEN) -_GEND - -#endif diff --git a/engines/queen/display.h b/engines/queen/display.h index 23316f880a..b26ae1fac0 100644 --- a/engines/queen/display.h +++ b/engines/queen/display.h @@ -254,13 +254,12 @@ private: QueenEngine *_vm; const uint8 *_font; -#ifndef PALMOS_68K + static const uint8 _fontRegular[]; static const uint8 _fontHebrew[]; static const uint8 _fontRussian[]; static const uint8 _palJoeClothes[]; static const uint8 _palJoeDress[]; -#endif }; diff --git a/engines/queen/graphics.cpp b/engines/queen/graphics.cpp index 4beca6556d..6199a75e7c 100644 --- a/engines/queen/graphics.cpp +++ b/engines/queen/graphics.cpp @@ -36,13 +36,6 @@ namespace Queen { -#ifdef PALMOS_68K -static const BamScene::BamDataBlock *_carData; -static const BamScene::BamDataBlock *_fight1Data; -static const BamScene::BamDataBlock *_fight2Data; -static const BamScene::BamDataBlock *_fight3Data; -#endif - const Box BobSlot::_defaultBox(-1, -1, -1, -1); void BobSlot::curPos(int16 xx, int16 yy) { @@ -1311,7 +1304,6 @@ void BamScene::loadState(uint32 ver, byte *&ptr) { _flag = READ_BE_UINT16(ptr); ptr += 2; } -#ifndef PALMOS_68K const BamScene::BamDataBlock BamScene::_carData[] = { { { 310, 105, 1 }, { 314, 106, 17 }, { 366, 101, 1 }, 0 }, { { 303, 105, 1 }, { 307, 106, 17 }, { 214, 0, 10 }, 0 }, @@ -1630,25 +1622,5 @@ const BamScene::BamDataBlock BamScene::_fight4Data[] = { { { 75, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 }, { { 75, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 99 } }; -#endif } // End of namespace Queen - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Queen_Graphics) -_GSETPTR(Queen::_carData, GBVARS_GRAPHICSCARDATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN) -_GSETPTR(Queen::_fight1Data, GBVARS_GRAPHICSFIGHT1DATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN) -_GSETPTR(Queen::_fight2Data, GBVARS_GRAPHICSFIGHT2DATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN) -_GSETPTR(Queen::_fight3Data, GBVARS_GRAPHICSFIGHT3DATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN) -_GEND - -_GRELEASE(Queen_Graphics) -_GRELEASEPTR(GBVARS_GRAPHICSCARDATA_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_GRAPHICSFIGHT1DATA_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_GRAPHICSFIGHT2DATA_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_GRAPHICSFIGHT3DATA_INDEX, GBVARS_QUEEN) -_GEND - -#endif diff --git a/engines/queen/graphics.h b/engines/queen/graphics.h index 3963224069..9684217ef0 100644 --- a/engines/queen/graphics.h +++ b/engines/queen/graphics.h @@ -261,18 +261,12 @@ private: int16 frame; }; -#ifdef PALMOS_68K -public: -#endif struct BamDataBlock { BamDataObj obj1; // truck / Frank BamDataObj obj2; // Rico / robot BamDataObj fx; int16 sfx; }; -#ifdef PALMOS_68K -private: -#endif BobSlot *_obj1; BobSlot *_obj2; @@ -283,13 +277,11 @@ private: QueenEngine *_vm; -#ifndef PALMOS_68K static const BamDataBlock _carData[]; static const BamDataBlock _fight1Data[]; static const BamDataBlock _fight2Data[]; static const BamDataBlock _fight3Data[]; static const BamDataBlock _fight4Data[]; -#endif }; } // End of namespace Queen diff --git a/engines/queen/musicdata.cpp b/engines/queen/musicdata.cpp index bfb843766c..a0b2a73697 100644 --- a/engines/queen/musicdata.cpp +++ b/engines/queen/musicdata.cpp @@ -28,16 +28,6 @@ namespace Queen { -#ifdef PALMOS_68K - -const songData *Sound::_songDemo; -const songData *Sound::_song; -const tuneData *Sound::_tuneDemo; -const tuneData *Sound::_tune; -const char *Sound::_sfxName; -const int16 *Sound::_jungleList; - -#else const songData Sound::_songDemo[] = { /* 1 - Hotel Gangsters */ { { 1, 0 }, 128, 128, 128, 1, 0 }, @@ -1919,29 +1909,6 @@ const char *Sound::_sfxName[] = { }; const int16 Sound::_jungleList[] = { 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 13, 14, 0 }; -#endif -} // End of namespace Queen -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Queen_Musicdata) -_GSETPTR(Queen::Sound::_songDemo, GBVARS_MUSICDATASONGDEMO_INDEX, Queen::songData, GBVARS_QUEEN) -_GSETPTR(Queen::Sound::_song, GBVARS_MUSICDATASONG_INDEX, Queen::songData, GBVARS_QUEEN) -_GSETPTR(Queen::Sound::_tuneDemo, GBVARS_MUSICDATATUNEDEMO_INDEX, Queen::tuneData, GBVARS_QUEEN) -_GSETPTR(Queen::Sound::_tune, GBVARS_MUSICDATATUNE_INDEX, Queen::tuneData, GBVARS_QUEEN) -_GSETPTR(Queen::Sound::_sfxName, GBVARS_MUSICDATASFXNAME_INDEX, char, GBVARS_QUEEN) -_GSETPTR(Queen::Sound::_jungleList, GBVARS_MUSICDATAJUNGLELIST_INDEX, int16, GBVARS_QUEEN) -_GEND - -_GRELEASE(Queen_Musicdata) -_GRELEASEPTR(GBVARS_MUSICDATASONGDEMO_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_MUSICDATASONG_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_MUSICDATATUNEDEMO_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_MUSICDATATUNE_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_MUSICDATASFXNAME_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_MUSICDATAJUNGLELIST_INDEX, GBVARS_QUEEN) -_GEND - -#endif +} // End of namespace Queen diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp index 999a86d432..20b047cb71 100644 --- a/engines/queen/resource.cpp +++ b/engines/queen/resource.cpp @@ -30,9 +30,6 @@ namespace Queen { -#ifdef PALMOS_68K -static ResourceEntry *_resourceTablePEM10; -#endif const char *Resource::_tableFilename = "queen.tbl"; @@ -325,16 +322,3 @@ Common::File *Resource::findSound(const char *filename, uint32 *size) { } } // End of namespace Queen - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Queen_Restables) -_GSETPTR(Queen::_resourceTablePEM10, GBVARS_RESOURCETABLEPM10_INDEX, Queen::ResourceEntry, GBVARS_QUEEN) -_GEND - -_GRELEASE(Queen_Restables) -_GRELEASEPTR(GBVARS_RESOURCETABLEPM10_INDEX, GBVARS_QUEEN) -_GEND - -#endif diff --git a/engines/queen/resource.h b/engines/queen/resource.h index 16094193d9..43c8e68939 100644 --- a/engines/queen/resource.h +++ b/engines/queen/resource.h @@ -165,10 +165,8 @@ protected: //! known FOTAQ versions static const RetailGameVersion _gameVersions[]; -#ifndef PALMOS_68K //! resource table for english floppy version static ResourceEntry _resourceTablePEM10[]; -#endif }; } // End of namespace Queen diff --git a/engines/queen/restables.cpp b/engines/queen/restables.cpp index 721bde626f..d4c30c7bea 100644 --- a/engines/queen/restables.cpp +++ b/engines/queen/restables.cpp @@ -27,7 +27,6 @@ namespace Queen { -#ifndef PALMOS_68K //English Floppy Version ResourceEntry Resource::_resourceTablePEM10[] = { { "1000SSSS.SB", 1, 0x00000000, 0x000027fe }, @@ -1107,5 +1106,5 @@ ResourceEntry Resource::_resourceTablePEM10[] = { { "ZOMBIE1.DOG", 1, 0x0159ecef, 0x00000f6a }, { "ZOMBIE2.DOG", 1, 0x0159fc59, 0x00000c40 } }; -#endif + } // End of namespace Queen diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index a4cac2417e..1da07cf97c 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -173,13 +173,8 @@ PCSound::~PCSound() { } void PCSound::playSfx(uint16 sfx) { - if (sfxOn() && sfx != 0) { -#ifndef PALMOS_68K + if (sfxOn() && sfx != 0) playSound(_sfxName[sfx - 1], false); -#else - playSound(_sfxName + 10 * (sfx - 1), false); // saved as 8char + /0/0 -#endif - } } void PCSound::playSong(int16 songNum) { diff --git a/engines/queen/sound.h b/engines/queen/sound.h index 145a2d1384..d87ab63a18 100644 --- a/engines/queen/sound.h +++ b/engines/queen/sound.h @@ -103,21 +103,12 @@ public: void saveState(byte *&ptr); void loadState(uint32 ver, byte *&ptr); -#ifndef PALMOS_68K static const songData _songDemo[]; static const songData _song[]; static const tuneData _tuneDemo[]; static const tuneData _tune[]; static const char *_sfxName[]; static const int16 _jungleList[]; -#else - static const songData *_songDemo; - static const songData *_song; - static const tuneData *_tuneDemo; - static const tuneData *_tune; - static const char *_sfxName; - static const int16 *_jungleList; -#endif protected: diff --git a/engines/queen/talk.cpp b/engines/queen/talk.cpp index a47584a003..8396356685 100644 --- a/engines/queen/talk.cpp +++ b/engines/queen/talk.cpp @@ -46,10 +46,6 @@ namespace Queen { -#ifdef PALMOS_68K -static const Talk::SpeechParameters *_speechParameters; -#endif - void Talk::talk( const char *filename, int personInRoom, @@ -1357,7 +1353,6 @@ int16 Talk::selectSentence() { return selectedSentence; } -#ifndef PALMOS_68K const Talk::SpeechParameters Talk::_speechParameters[] = { { "JOE", 0, 1, 1, 10, 2, 3, "", 0 }, { "JOE", 0, 3, 3, 28, 2, 3, "", 0 }, @@ -1818,19 +1813,5 @@ const Talk::SpeechParameters Talk::_speechParameters[] = { { "*", 0, 0, 0, 0, 0, 0, "", 0 } }; -#endif } // End of namespace Queen - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Queen_Talk) -_GSETPTR(Queen::_speechParameters, GBVARS_SPEECHPARAMETERS_INDEX, Queen::Talk::SpeechParameters, GBVARS_QUEEN) -_GEND - -_GRELEASE(Queen_Talk) -_GRELEASEPTR(GBVARS_SPEECHPARAMETERS_INDEX, GBVARS_QUEEN) -_GEND - -#endif diff --git a/engines/queen/talk.h b/engines/queen/talk.h index 1548d0ba27..036dfadbcd 100644 --- a/engines/queen/talk.h +++ b/engines/queen/talk.h @@ -81,7 +81,6 @@ private: int16 gameStateValue; }; -#ifndef PALMOS_68K struct SpeechParameters { const char *name; signed char state,faceDirection; @@ -89,17 +88,6 @@ private: const char *animation; signed char ff; }; -#else -public: - struct SpeechParameters { - const char name[11]; - signed char state,faceDirection; - signed char body,bf,rf,af; - const char animation[80]; - signed char ff; - }; -private: -#endif QueenEngine *_vm; @@ -154,9 +142,7 @@ private: char _talkString[5][MAX_STRING_SIZE]; char _joeVoiceFilePrefix[5][MAX_STRING_SIZE]; -#ifndef PALMOS_68K static const SpeechParameters _speechParameters[]; -#endif Talk(QueenEngine *vm); ~Talk(); diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp index c2ecff4a1a..6d996d2d40 100644 --- a/engines/saga/actor.cpp +++ b/engines/saga/actor.cpp @@ -29,18 +29,12 @@ #include "saga/animation.h" #include "saga/console.h" #include "saga/events.h" -#include "saga/gfx.h" -#include "saga/interface.h" #include "saga/isomap.h" -#include "saga/itedata.h" #include "saga/objectmap.h" #include "saga/sagaresnames.h" #include "saga/rscfile.h" #include "saga/script.h" #include "saga/sndres.h" -#include "saga/sprite.h" -#include "saga/stream.h" -#include "saga/font.h" #include "saga/sound.h" #include "saga/scene.h" @@ -48,24 +42,6 @@ namespace Saga { -enum ActorFrameIds { -//ITE - kFrameITEStand = 0, - kFrameITEWalk = 1, - kFrameITESpeak = 2, - kFrameITEGive = 3, - kFrameITEGesture = 4, - kFrameITEWait = 5, - kFrameITEPickUp = 6, - kFrameITELook = 7, -//IHNM - kFrameIHNMStand = 0, - kFrameIHNMSpeak = 1, - kFrameIHNMWait = 2, - kFrameIHNMGesture = 3, - kFrameIHNMWalk = 4 -}; - static int commonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) { int p1 = obj1->_location.y - obj1->_location.z; int p2 = obj2->_location.y - obj2->_location.z; @@ -76,6 +52,16 @@ static int commonObjectCompare(const CommonObjectDataPointer& obj1, const Common return 1; } +static int commonObjectCompareIHNM(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) { + int p1 = obj1->_location.y; + int p2 = obj2->_location.y; + if (p1 == p2) + return 0; + if (p1 < p2) + return -1; + return 1; +} + static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) { int p1 = -obj1->_location.u() - obj1->_location.v() - obj1->_location.z; int p2 = -obj2->_location.u() - obj2->_location.v() - obj2->_location.z; @@ -89,140 +75,6 @@ static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const Co return 1; } -inline int16 int16Compare(int16 i1, int16 i2) { - return ((i1) > (i2) ? 1 : ((i1) < (i2) ? -1 : 0)); -} - -inline int16 quickDistance(const Point &point1, const Point &point2, int16 compressX) { - Point delta; - delta.x = ABS(point1.x - point2.x) / compressX; - delta.y = ABS(point1.y - point2.y); - return ((delta.x < delta.y) ? (delta.y + delta.x / 2) : (delta.x + delta.y / 2)); -} - -inline void calcDeltaS(const Point &point1, const Point &point2, Point &delta, Point &s) { - - delta.x = point2.x - point1.x; - if (delta.x == 0) { - s.x = 0; - } else { - if (delta.x > 0) { - s.x = 1; - } else { - s.x = -1; - delta.x = -delta.x; - } - } - - - delta.y = point2.y - point1.y; - if (delta.y == 0) { - s.y = 0; - } else { - if (delta.y > 0) { - s.y = 1; - } else { - s.y = -1; - delta.y = -delta.y; - } - } -} - -// Lookup table to convert 8 cardinal directions to 4 -static const int actorDirectectionsLUT[8] = { - ACTOR_DIRECTION_BACK, // kDirUp - ACTOR_DIRECTION_RIGHT, // kDirUpRight - ACTOR_DIRECTION_RIGHT, // kDirRight - ACTOR_DIRECTION_RIGHT, // kDirDownRight - ACTOR_DIRECTION_FORWARD,// kDirDown - ACTOR_DIRECTION_LEFT, // kDirDownLeft - ACTOR_DIRECTION_LEFT, // kDirLeft - ACTOR_DIRECTION_LEFT, // kDirUpLeft -}; - -static const PathDirectionData pathDirectionLUT[8][3] = { - { { 0, Point( 0, -1) }, { 7, Point(-1, -1) }, { 4, Point( 1, -1) } }, - { { 1, Point( 1, 0) }, { 4, Point( 1, -1) }, { 5, Point( 1, 1) } }, - { { 2, Point( 0, 1) }, { 5, Point( 1, 1) }, { 6, Point(-1, 1) } }, - { { 3, Point(-1, 0) }, { 6, Point(-1, 1) }, { 7, Point(-1, -1) } }, - { { 0, Point( 0, -1) }, { 1, Point( 1, 0) }, { 4, Point( 1, -1) } }, - { { 1, Point( 1, 0) }, { 2, Point( 0, 1) }, { 5, Point( 1, 1) } }, - { { 2, Point( 0, 1) }, { 3, Point(-1, 0) }, { 6, Point(-1, 1) } }, - { { 3, Point(-1, 0) }, { 0, Point( 0, -1) }, { 7, Point(-1, -1) } } -}; - -static const int pathDirectionLUT2[8][2] = { - { 0, -1 }, - { 1, 0 }, - { 0, 1 }, - { -1, 0 }, - { 1, -1 }, - { 1, 1 }, - { -1, 1 }, - { -1, -1 } -}; - -static const int angleLUT[16][2] = { - { 0, -256 }, - { 98, -237 }, - { 181, -181 }, - { 237, -98 }, - { 256, 0 }, - { 237, 98 }, - { 181, 181 }, - { 98, 237 }, - { 0, 256 }, - { -98, 237 }, - { -181, 181 }, - { -237, 98 }, - { -256, 0 }, - { -237, -98 }, - { -181, -181 }, - { -98, -237 } -}; - -static const int directionLUT[8][2] = { - { 0 * 2, -2 * 2 }, - { 2 * 2, -1 * 2 }, - { 3 * 2, 0 * 2 }, - { 2 * 2, 1 * 2 }, - { 0 * 2, 2 * 2 }, - { -2 * 2, 1 * 2 }, - { -4 * 2, 0 * 2 }, - { -2 * 2, -1 * 2 } -}; - -static const int tileDirectionLUT[8][2] = { - { 1, 1 }, - { 2, 0 }, - { 1, -1 }, - { 0, -2 }, - { -1, -1 }, - { -2, 0 }, - { -1, 1 }, - { 0, 2 } -}; - -struct DragonMove { - uint16 baseFrame; - int16 offset[4][2]; -}; - -static const DragonMove dragonMoveTable[12] = { - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 28, { { -0, 0 }, { -1, 6 }, { -5, 11 }, { -10, 15 } } }, - { 56, { { 0, 0 }, { 1, 6 }, { 5, 11 }, { 10, 15 } } }, - { 40, { { 0, 0 }, { 6, 1 }, { 11, 5 }, { 15, 10 } } }, - { 44, { { 0, 0 }, { 6, -1 }, { 11, -5 }, { 15, -10 } } }, - { 32, { { -0, -0 }, { -6, -1 }, { -11, -5 }, { -15, -10 } } }, - { 52, { { -0, 0 }, { -6, 1 }, { -11, 5 }, { -15, 10 } } }, - { 36, { { 0, -0 }, { 1, -6 }, { 5, -11 }, { 10, -15 } } }, - { 48, { { -0, -0 }, { -1, -6 }, { -5, -11 }, { -10, -15 } } } -}; - Actor::Actor(SagaEngine *vm) : _vm(vm) { int i; byte *stringsPointer; @@ -268,8 +120,6 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) { _pathRect.top = _vm->getDisplayInfo().pathStartY; _pathRect.bottom = _vm->_scene->getHeight(); - _showActors = true; - // Get actor resource file context _actorContext = _vm->_resource->getContext(GAME_RESOURCEFILE); if (_actorContext == NULL) { @@ -723,76 +573,6 @@ void Actor::stepZoneAction(ActorData *actor, const HitZone *hitZone, bool exit, } } -void Actor::realLocation(Location &location, uint16 objectId, uint16 walkFlags) { - int angle; - int distance; - ActorData *actor; - ObjectData *obj; - debug (8, "Actor::realLocation objectId=%i", objectId); - if (walkFlags & kWalkUseAngle) { - if (_vm->_scene->getFlags() & kSceneFlagISO) { - angle = (location.x + 2) & 15; - distance = location.y; - - location.u() = (angleLUT[angle][0] * distance) >> 8; - location.v() = -(angleLUT[angle][1] * distance) >> 8; - } else { - angle = location.x & 15; - distance = location.y; - - location.x = (angleLUT[angle][0] * distance) >> 6; - location.y = (angleLUT[angle][1] * distance) >> 6; - } - } - - if (objectId != ID_NOTHING) { - if (validActorId(objectId)) { - actor = getActor(objectId); - location.addXY(actor->_location); - } else if (validObjId(objectId)) { - obj = getObj(objectId); - location.addXY(obj->_location); - } - } -} - -void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) { - ActorData *actor; - Location delta; - //debug (8, "Actor::actorFaceTowardsPoint actorId=%i", actorId); - actor = getActor(actorId); - - toLocation.delta(actor->_location, delta); - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - if (delta.u() > 0) { - actor->_facingDirection = (delta.v() > 0) ? kDirUp : kDirRight; - } else { - actor->_facingDirection = (delta.v() > 0) ? kDirLeft : kDirDown; - } - } else { - if (ABS(delta.y) > ABS(delta.x * 2)) { - actor->_facingDirection = (delta.y > 0) ? kDirDown : kDirUp; - } else { - actor->_facingDirection = (delta.x > 0) ? kDirRight : kDirLeft; - } - } -} - -void Actor::actorFaceTowardsObject(uint16 actorId, uint16 objectId) { - ActorData *actor; - ObjectData *obj; - - if (validActorId(objectId)) { - actor = getActor(objectId); - actorFaceTowardsPoint(actorId, actor->_location); - } else if (validObjId(objectId)) { - obj = getObj(objectId); - actorFaceTowardsPoint(actorId, obj->_location); - } -} - - ObjectData *Actor::getObj(uint16 objId) { ObjectData *obj; @@ -830,18 +610,6 @@ ActorData *Actor::getActor(uint16 actorId) { return actor; } -bool Actor::validFollowerLocation(const Location &location) { - Point point; - location.toScreenPointXY(point); - - if ((point.x < 5) || (point.x >= _vm->getDisplayWidth() - 5) || - (point.y < 0) || (point.y > _vm->_scene->getHeight())) { - return false; - } - - return (_vm->_scene->canWalk(point)); -} - void Actor::setProtagState(int state) { _protagState = state; @@ -855,149 +623,6 @@ void Actor::setProtagState(int state) { } } -void Actor::updateActorsScene(int actorsEntrance) { - int i, j; - int followerDirection; - ActorData *actor; - Location tempLocation; - Location possibleLocation; - Point delta; - const SceneEntry *sceneEntry; - - if (_vm->_scene->currentSceneNumber() == 0) { - error("Actor::updateActorsScene _vm->_scene->currentSceneNumber() == 0"); - } - - _vm->_sound->stopVoice(); - _activeSpeech.stringsCount = 0; - _activeSpeech.playing = false; - _protagonist = NULL; - - for (i = 0; i < _actorsCount; i++) { - actor = _actors[i]; - actor->_inScene = false; - actor->_spriteList.freeMem(); - if (actor->_disabled) { - continue; - } - if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) { - if (actor->_flags & kProtagonist) { - actor->_finalTarget = actor->_location; - _centerActor = _protagonist = actor; - } else if (_vm->getGameType() == GType_ITE && - _vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { - continue; - } - - actor->_sceneNumber = _vm->_scene->currentSceneNumber(); - } - if (actor->_sceneNumber == _vm->_scene->currentSceneNumber()) { - actor->_inScene = true; - actor->_actionCycle = (_vm->_rnd.getRandomNumber(7) & 0x7) * 4; // 1/8th chance - } - } - - // _protagonist can be null while loading a game from the command line - if (_protagonist == NULL) - return; - - if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) { - if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) { - actorsEntrance = 0; //OCEAN bug - } - - sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance); - if (_vm->_scene->getFlags() & kSceneFlagISO) { - _protagonist->_location = sceneEntry->location; - } else { - _protagonist->_location.x = sceneEntry->location.x * ACTOR_LMULT; - _protagonist->_location.y = sceneEntry->location.y * ACTOR_LMULT; - _protagonist->_location.z = sceneEntry->location.z * ACTOR_LMULT; - } - // Workaround for bug #1328045: - // "When entering any of the houses at the start of the - // game if you click on anything inside the building you - // start walking through the door, turn around and leave." - // - // After steping of action zone - Rif trying to exit. - // This piece of code shift Rif's entry position to non action zone area. - if (_vm->getGameType() == GType_ITE) { - if ((_vm->_scene->currentSceneNumber() >= 53) && (_vm->_scene->currentSceneNumber() <= 66)) - _protagonist->_location.y += 10; - } - - _protagonist->_facingDirection = _protagonist->_actionDirection = sceneEntry->facing; - } - - _protagonist->_currentAction = kActionWait; - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - //nothing? - } else { - _vm->_scene->initDoorsState(); //TODO: move to _scene - } - - followerDirection = _protagonist->_facingDirection + 3; - calcScreenPosition(_protagonist); - - for (i = 0; i < _actorsCount; i++) { - actor = _actors[i]; - if (actor->_flags & (kFollower)) { - actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection; - actor->_currentAction = kActionWait; - actor->_walkStepsCount = actor->_walkStepIndex = 0; - actor->_location.z = _protagonist->_location.z; - - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - _vm->_isoMap->placeOnTileMap(_protagonist->_location, actor->_location, 3, followerDirection & 0x07); - } else { - followerDirection &= 0x07; - - possibleLocation = _protagonist->_location; - - - delta.x = directionLUT[followerDirection][0]; - delta.y = directionLUT[followerDirection][1]; - - - for (j = 0; j < 30; j++) { - tempLocation = possibleLocation; - tempLocation.x += delta.x; - tempLocation.y += delta.y; - - if (validFollowerLocation(tempLocation)) { - possibleLocation = tempLocation; - } else { - tempLocation = possibleLocation; - tempLocation.x += delta.x; - if (validFollowerLocation(tempLocation)) { - possibleLocation = tempLocation; - } else { - tempLocation = possibleLocation; - tempLocation.y += delta.y; - if (validFollowerLocation(tempLocation)) { - possibleLocation = tempLocation; - } else { - break; - } - } - } - } - - actor->_location = possibleLocation; - } - followerDirection += 2; - } - - } - - handleActions(0, true); - if (_vm->_scene->getFlags() & kSceneFlagISO) { - _vm->_isoMap->adjustScroll(true); - } -} - int Actor::getFrameType(ActorFrameTypes frameType) { if (_vm->getGameType() == GType_ITE) { @@ -1235,413 +860,6 @@ void Actor::handleSpeech(int msec) { _activeSpeech.playing = true; } -void Actor::handleActions(int msec, bool setup) { - int i; - ActorData *actor; - ActorFrameRange *frameRange; - int state; - int speed; - int32 framesLeft; - Location delta; - Location addDelta; - int hitZoneIndex; - const HitZone *hitZone; - Point hitPoint; - Location pickLocation; - - for (i = 0; i < _actorsCount; i++) { - actor = _actors[i]; - if (!actor->_inScene) - continue; - - if ((_vm->getGameType() == GType_ITE) && (i == ACTOR_DRAGON_INDEX)) { - moveDragon(actor); - continue; - } - - switch (actor->_currentAction) { - case kActionWait: - if (!setup && (actor->_flags & kFollower)) { - followProtagonist(actor); - if (actor->_currentAction != kActionWait) - break; - } - - if (actor->_targetObject != ID_NOTHING) { - actorFaceTowardsObject(actor->_id, actor->_targetObject); - } - - if (actor->_flags & kCycle) { - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); - if (frameRange->frameCount > 0) { - actor->_actionCycle++; - actor->_actionCycle = (actor->_actionCycle) % frameRange->frameCount; - } else { - actor->_actionCycle = 0; - } - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - break; - } - - if ((actor->_actionCycle & 3) == 0) { - actor->cycleWrap(100); - - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameWait)); - if ((frameRange->frameCount < 1 || actor->_actionCycle > 33)) - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); - - if (frameRange->frameCount) { - actor->_frameNumber = frameRange->frameIndex + (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount - 1); - } else { - actor->_frameNumber = frameRange->frameIndex; - } - } - actor->_actionCycle++; - break; - - case kActionWalkToPoint: - case kActionWalkToLink: - if (_vm->_scene->getFlags() & kSceneFlagISO) { - actor->_partialTarget.delta(actor->_location, delta); - - while ((delta.u() == 0) && (delta.v() == 0)) { - - if ((actor == _protagonist) && (_vm->mouseButtonPressed())) { - _vm->_isoMap->screenPointToTileCoords(_vm->mousePos(), pickLocation); - - if (!actorWalkTo(_protagonist->_id, pickLocation)) { - break; - } - } else if (!_vm->_isoMap->nextTileTarget(actor) && !actorEndWalk(actor->_id, true)) { - break; - } - - actor->_partialTarget.delta(actor->_location, delta); - actor->_partialTarget.z = 0; - } - - if (actor->_flags & kFastest) { - speed = 8; - } else if (actor->_flags & kFaster) { - speed = 6; - } else { - speed = 4; - } - - if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { - speed = 2; - } - - if ((actor->_actionDirection == 2) || (actor->_actionDirection == 6)) { - speed = speed / 2; - } - - if (ABS(delta.v()) > ABS(delta.u())) { - addDelta.v() = clamp(-speed, delta.v(), speed); - if (addDelta.v() == delta.v()) { - addDelta.u() = delta.u(); - } else { - addDelta.u() = delta.u() * addDelta.v(); - addDelta.u() += (addDelta.u() > 0) ? (delta.v() / 2) : (-delta.v() / 2); - addDelta.u() /= delta.v(); - } - } else { - addDelta.u() = clamp(-speed, delta.u(), speed); - if (addDelta.u() == delta.u()) { - addDelta.v() = delta.v(); - } else { - addDelta.v() = delta.v() * addDelta.u(); - addDelta.v() += (addDelta.v() > 0) ? (delta.u() / 2) : (-delta.u() / 2); - addDelta.v() /= delta.u(); - } - } - - actor->_location.add(addDelta); - } else { - actor->_partialTarget.delta(actor->_location, delta); - - while ((delta.x == 0) && (delta.y == 0)) { - - if (actor->_walkStepIndex >= actor->_walkStepsCount) { - actorEndWalk(actor->_id, true); - break; - } - - actor->_partialTarget.fromScreenPoint(actor->_walkStepsPoints[actor->_walkStepIndex++]); - if (_vm->getGameType() == GType_ITE) { - if (actor->_partialTarget.x > 224 * 2 * ACTOR_LMULT) { - actor->_partialTarget.x -= 256 * 2 * ACTOR_LMULT; - } - } else { - if (actor->_partialTarget.x > 224 * 4 * ACTOR_LMULT) { - actor->_partialTarget.x -= 256 * 4 * ACTOR_LMULT; - } - } - - actor->_partialTarget.delta(actor->_location, delta); - - if (ABS(delta.y) > ABS(delta.x)) { - actor->_actionDirection = delta.y > 0 ? kDirDown : kDirUp; - } else { - actor->_actionDirection = delta.x > 0 ? kDirRight : kDirLeft; - } - } - - if(_vm->getGameType() == GType_ITE) - speed = (ACTOR_LMULT * 2 * actor->_screenScale + 63) / 256; - else - speed = (ACTOR_SPEED * actor->_screenScale + 128) >> 8; - - if (speed < 1) - speed = 1; - - if(_vm->getGameType() == GType_IHNM) - speed = speed / 2; - - if ((actor->_actionDirection == kDirUp) || (actor->_actionDirection == kDirDown)) { - addDelta.y = clamp(-speed, delta.y, speed); - if (addDelta.y == delta.y) { - addDelta.x = delta.x; - } else { - addDelta.x = delta.x * addDelta.y; - addDelta.x += (addDelta.x > 0) ? (delta.y / 2) : (-delta.y / 2); - addDelta.x /= delta.y; - actor->_facingDirection = actor->_actionDirection; - } - } else { - addDelta.x = clamp(-2 * speed, delta.x, 2 * speed); - if (addDelta.x == delta.x) { - addDelta.y = delta.y; - } else { - addDelta.y = delta.y * addDelta.x; - addDelta.y += (addDelta.y > 0) ? (delta.x / 2) : (-delta.x / 2); - addDelta.y /= delta.x; - actor->_facingDirection = actor->_actionDirection; - } - } - - actor->_location.add(addDelta); - } - - if (actor->_actorFlags & kActorBackwards) { - actor->_facingDirection = (actor->_actionDirection + 4) & 7; - actor->_actionCycle--; - } else { - actor->_actionCycle++; - } - - frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); - - if (actor->_actionCycle < 0) { - actor->_actionCycle = frameRange->frameCount - 1; - } else if (actor->_actionCycle >= frameRange->frameCount) { - actor->_actionCycle = 0; - } - - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - break; - - case kActionWalkDir: - if (_vm->_scene->getFlags() & kSceneFlagISO) { - actor->_location.u() += tileDirectionLUT[actor->_actionDirection][0]; - actor->_location.v() += tileDirectionLUT[actor->_actionDirection][1]; - - frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); - - actor->_actionCycle++; - actor->cycleWrap(frameRange->frameCount); - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - } else { - if (_vm->getGameType() == GType_ITE) { - actor->_location.x += directionLUT[actor->_actionDirection][0] * 2; - actor->_location.y += directionLUT[actor->_actionDirection][1] * 2; - } else { - // FIXME: The original does not multiply by 8 here, but we do - actor->_location.x += (directionLUT[actor->_actionDirection][0] * 8 * actor->_screenScale + 128) >> 8; - actor->_location.y += (directionLUT[actor->_actionDirection][1] * 8 * actor->_screenScale + 128) >> 8; - } - - frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); - actor->_actionCycle++; - actor->cycleWrap(frameRange->frameCount); - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - } - break; - - case kActionSpeak: - actor->_actionCycle++; - actor->cycleWrap(64); - - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameGesture)); - if (actor->_actionCycle >= frameRange->frameCount) { - if (actor->_actionCycle & 1) - break; - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameSpeak)); - - state = (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount); - - if (state == 0) { - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); - } else { - state--; - } - } else { - state = actor->_actionCycle; - } - - actor->_frameNumber = frameRange->frameIndex + state; - break; - - case kActionAccept: - case kActionStoop: - break; - - case kActionCycleFrames: - case kActionPongFrames: - if (actor->_cycleTimeCount > 0) { - actor->_cycleTimeCount--; - break; - } - - actor->_cycleTimeCount = actor->_cycleDelay; - actor->_actionCycle++; - - frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); - - if (actor->_currentAction == kActionPongFrames) { - if (actor->_actionCycle >= frameRange->frameCount * 2 - 2) { - if (actor->_actorFlags & kActorContinuous) { - actor->_actionCycle = 0; - } else { - actor->_currentAction = kActionFreeze; - break; - } - } - - state = actor->_actionCycle; - if (state >= frameRange->frameCount) { - state = frameRange->frameCount * 2 - 2 - state; - } - } else { - if (actor->_actionCycle >= frameRange->frameCount) { - if (actor->_actorFlags & kActorContinuous) { - actor->_actionCycle = 0; - } else { - actor->_currentAction = kActionFreeze; - break; - } - } - state = actor->_actionCycle; - } - - if (frameRange->frameCount && (actor->_actorFlags & kActorRandom)) { - state = _vm->_rnd.getRandomNumber(frameRange->frameCount - 1); - } - - if (actor->_actorFlags & kActorBackwards) { - actor->_frameNumber = frameRange->frameIndex + frameRange->frameCount - 1 - state; - } else { - actor->_frameNumber = frameRange->frameIndex + state; - } - break; - - case kActionFall: - if (actor->_actionCycle > 0) { - framesLeft = actor->_actionCycle--; - actor->_finalTarget.delta(actor->_location, delta); - delta.x /= framesLeft; - delta.y /= framesLeft; - actor->_location.addXY(delta); - actor->_fallVelocity += actor->_fallAcceleration; - actor->_fallPosition += actor->_fallVelocity; - actor->_location.z = actor->_fallPosition >> 4; - } else { - actor->_location = actor->_finalTarget; - actor->_currentAction = kActionFreeze; - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - } - break; - - case kActionClimb: - actor->_cycleDelay++; - if (actor->_cycleDelay & 3) { - break; - } - - if (actor->_location.z >= actor->_finalTarget.z + ACTOR_CLIMB_SPEED) { - actor->_location.z -= ACTOR_CLIMB_SPEED; - actor->_actionCycle--; - } else if (actor->_location.z <= actor->_finalTarget.z - ACTOR_CLIMB_SPEED) { - actor->_location.z += ACTOR_CLIMB_SPEED; - actor->_actionCycle++; - } else { - actor->_location.z = actor->_finalTarget.z; - actor->_currentAction = kActionFreeze; - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - } - - frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); - - if (actor->_actionCycle < 0) { - actor->_actionCycle = frameRange->frameCount - 1; - } - actor->cycleWrap(frameRange->frameCount); - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - break; - } - - if ((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) { - hitZone = NULL; - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - actor->_location.toScreenPointUV(hitPoint); - } else { - actor->_location.toScreenPointXY(hitPoint); - } - hitZoneIndex = _vm->_scene->_actionMap->hitTest(hitPoint); - if (hitZoneIndex != -1) { - hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); - } - - if (hitZone != actor->_lastZone) { - if (actor->_lastZone) - stepZoneAction(actor, actor->_lastZone, true, false); - actor->_lastZone = hitZone; - // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves - // (room 51) to avoid the glitch - if (hitZone && !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51)) - stepZoneAction(actor, hitZone, false, false); - } - } - } - // Update frameCount for sfWaitFrames in IHNM - _vm->_frameCount++; -} - -void Actor::direct(int msec) { - - if (_vm->_scene->_entryList.entryListCount == 0) { - return; - } - - if (_vm->_interface->_statusTextInput) { - return; - } - - // FIXME: HACK. This should be turned into cycle event. - _lastTickMsec += msec; - - if (_lastTickMsec > 1000 / _handleActionDiv) { - _lastTickMsec = 0; - //process actions - handleActions(msec, false); - } - -//process speech - handleSpeech(msec); -} - - bool Actor::calcScreenPosition(CommonObjectData *commonObjectData) { int beginSlope, endSlope, middle; bool result; @@ -1738,7 +956,10 @@ void Actor::createDrawOrderList() { if (_vm->_scene->getFlags() & kSceneFlagISO) { compareFunction = &tileCommonObjectCompare; } else { - compareFunction = &commonObjectCompare; + if (_vm->getGameType() == GType_ITE) + compareFunction = &commonObjectCompare; + else + compareFunction = &commonObjectCompareIHNM; } _drawOrderList.clear(); @@ -1814,10 +1035,6 @@ void Actor::drawActors() { return; } - if (!_showActors) { - return; - } - CommonObjectOrderList::iterator drawOrderIterator; CommonObjectDataPointer drawObject; int frameNumber; @@ -1891,382 +1108,6 @@ void Actor::drawSpeech(void) { free(outputString); } -bool Actor::followProtagonist(ActorData *actor) { - Location protagonistLocation; - Location newLocation; - Location delta; - int protagonistBGMaskType; - Point prefer1; - Point prefer2; - Point prefer3; - int16 prefU; - int16 prefV; - int16 newU; - int16 newV; - - assert(_protagonist); - - actor->_flags &= ~(kFaster | kFastest); - protagonistLocation = _protagonist->_location; - calcScreenPosition(_protagonist); - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - prefU = 60; - prefV = 60; - - - actor->_location.delta(protagonistLocation, delta); - - if (actor->_id == actorIndexToId(2)) { - prefU = prefV = 48; - } - - if ((delta.u() > prefU) || (delta.u() < -prefU) || (delta.v() > prefV) || (delta.v() < -prefV)) { - - if ((delta.u() > prefU * 2) || (delta.u() < -prefU * 2) || (delta.v() > prefV * 2) || (delta.v() < -prefV * 2)) { - actor->_flags |= kFaster; - - if ((delta.u() > prefU * 3) || (delta.u() < -prefU*3) || (delta.v() > prefV * 3) || (delta.v() < -prefV * 3)) { - actor->_flags |= kFastest; - } - } - - prefU /= 2; - prefV /= 2; - - newU = clamp(-prefU, delta.u(), prefU) + protagonistLocation.u(); - newV = clamp(-prefV, delta.v(), prefV) + protagonistLocation.v(); - - newLocation.u() = newU + _vm->_rnd.getRandomNumber(prefU - 1) - prefU / 2; - newLocation.v() = newV + _vm->_rnd.getRandomNumber(prefV - 1) - prefV / 2; - newLocation.z = 0; - - return actorWalkTo(actor->_id, newLocation); - } - - } else { - prefer1.x = (100 * _protagonist->_screenScale) >> 8; - prefer1.y = (50 * _protagonist->_screenScale) >> 8; - - if (_protagonist->_currentAction == kActionWalkDir) { - prefer1.x /= 2; - } - - if (prefer1.x < 8) { - prefer1.x = 8; - } - - if (prefer1.y < 8) { - prefer1.y = 8; - } - - prefer2.x = prefer1.x * 2; - prefer2.y = prefer1.y * 2; - prefer3.x = prefer1.x + prefer1.x / 2; - prefer3.y = prefer1.y + prefer1.y / 2; - - actor->_location.delta(protagonistLocation, delta); - - protagonistBGMaskType = 0; - if (_vm->_scene->isBGMaskPresent() && _vm->_scene->validBGMaskPoint(_protagonist->_screenPosition)) { - protagonistBGMaskType = _vm->_scene->getBGMaskType(_protagonist->_screenPosition); - } - - if ((_vm->_rnd.getRandomNumber(7) & 0x7) == 0) // 1/8th chance - actor->_actorFlags &= ~kActorNoFollow; - - if (actor->_actorFlags & kActorNoFollow) { - return false; - } - - if ((delta.x > prefer2.x) || (delta.x < -prefer2.x) || - (delta.y > prefer2.y) || (delta.y < -prefer2.y) || - ((_protagonist->_currentAction == kActionWait) && - (delta.x * 2 < prefer1.x) && (delta.x * 2 > -prefer1.x) && - (delta.y < prefer1.y) && (delta.y > -prefer1.y))) { - - if (ABS(delta.x) > ABS(delta.y)) { - - delta.x = (delta.x > 0) ? prefer3.x : -prefer3.x; - - newLocation.x = delta.x + protagonistLocation.x; - newLocation.y = clamp(-prefer2.y, delta.y, prefer2.y) + protagonistLocation.y; - } else { - delta.y = (delta.y > 0) ? prefer3.y : -prefer3.y; - - newLocation.x = clamp(-prefer2.x, delta.x, prefer2.x) + protagonistLocation.x; - newLocation.y = delta.y + protagonistLocation.y; - } - newLocation.z = 0; - - if (protagonistBGMaskType != 3) { - newLocation.x += _vm->_rnd.getRandomNumber(prefer1.x - 1) - prefer1.x / 2; - newLocation.y += _vm->_rnd.getRandomNumber(prefer1.y - 1) - prefer1.y / 2; - } - - newLocation.x = clamp(-31*4, newLocation.x, (_vm->getDisplayWidth() + 31) * 4); //fixme - - return actorWalkTo(actor->_id, newLocation); - } - } - return false; -} - -bool Actor::actorEndWalk(uint16 actorId, bool recurse) { - bool walkMore = false; - ActorData *actor; - const HitZone *hitZone; - int hitZoneIndex; - Point testPoint; - - actor = getActor(actorId); - actor->_actorFlags &= ~kActorBackwards; - - if (_vm->getGameType() == GType_ITE) { - - if (actor->_location.distance(actor->_finalTarget) > 8 && (actor->_flags & kProtagonist) && recurse && !(actor->_actorFlags & kActorNoCollide)) { - actor->_actorFlags |= kActorNoCollide; - return actorWalkTo(actorId, actor->_finalTarget); - } - } - - actor->_currentAction = kActionWait; - if (actor->_actorFlags & kActorFinalFace) { - actor->_facingDirection = actor->_actionDirection = (actor->_actorFlags >> 6) & 0x07; //? - } - - actor->_actorFlags &= ~(kActorNoCollide | kActorCollided | kActorFinalFace | kActorFacingMask); - actor->_flags &= ~(kFaster | kFastest); - - if (actor == _protagonist) { - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - if (_vm->_script->_pendingVerb == _vm->_script->getVerbType(kVerbWalkTo)) { - if (_vm->getGameType() == GType_ITE) - actor->_location.toScreenPointUV(testPoint); // it's wrong calculation, but it is used in ITE - else - actor->_location.toScreenPointXY(testPoint); - - hitZoneIndex = _vm->_scene->_actionMap->hitTest(testPoint); - if (hitZoneIndex != -1) { - hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); - stepZoneAction(actor, hitZone, false, true); - } else { - _vm->_script->setNoPendingVerb(); - } - } else if (_vm->_script->_pendingVerb != _vm->_script->getVerbType(kVerbNone)) { - _vm->_script->doVerb(); - } - } else { - if (recurse && (actor->_flags & kFollower)) - walkMore = followProtagonist(actor); - - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - } - return walkMore; -} - -bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) { - ActorData *actor; - ActorData *anotherActor; - int i; - - Rect testBox; - Rect testBox2; - Point anotherActorScreenPosition; - Point collision; - Point pointFrom, pointTo, pointBest, pointAdd; - Point delta, bestDelta; - Point tempPoint; - bool extraStartNode; - bool extraEndNode; - - actor = getActor(actorId); - - if (actor == _protagonist) { - _vm->_scene->setDoorState(2, 0xff); - _vm->_scene->setDoorState(3, 0); - } else { - _vm->_scene->setDoorState(2, 0); - _vm->_scene->setDoorState(3, 0xff); - } - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - - if ((_vm->getGameType() == GType_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) { - return false; - } - - actor->_finalTarget = toLocation; - actor->_walkStepsCount = 0; - _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); - - - if ((actor->_walkStepsCount == 0) && (actor->_flags & kProtagonist)) { - actor->_actorFlags |= kActorNoCollide; - _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); - } - - actor->_walkStepIndex = 0; - if (_vm->_isoMap->nextTileTarget(actor)) { - actor->_currentAction = kActionWalkToPoint; - actor->_walkFrameSequence = getFrameType(kFrameWalk); - } else { - actorEndWalk(actorId, false); - return false; - } - } else { - - actor->_location.toScreenPointXY(pointFrom); - pointFrom.x &= ~1; - - extraStartNode = _vm->_scene->offscreenPath(pointFrom); - - toLocation.toScreenPointXY(pointTo); - pointTo.x &= ~1; - - extraEndNode = _vm->_scene->offscreenPath(pointTo); - - if (_vm->_scene->isBGMaskPresent()) { - - if ((((actor->_currentAction >= kActionWalkToPoint) && - (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) && - !_vm->_scene->canWalk(pointFrom)) { - - int max = _vm->getGameType() == GType_ITE ? 8 : 4; - - for (i = 1; i < max; i++) { - pointAdd = pointFrom; - pointAdd.y += i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - pointAdd = pointFrom; - pointAdd.y -= i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - if (_vm->getGameType() == GType_ITE) { - pointAdd = pointFrom; - pointAdd.x += i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - pointAdd = pointFrom; - pointAdd.x -= i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - } - } - } - - _barrierCount = 0; - if (!(actor->_actorFlags & kActorNoCollide)) { - collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2); - collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2); - - - for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) { - anotherActor = _actors[i]; - if (!anotherActor->_inScene) - continue; - if (anotherActor == actor) - continue; - - anotherActorScreenPosition = anotherActor->_screenPosition; - testBox.left = (anotherActorScreenPosition.x - collision.x) & ~1; - testBox.right = (anotherActorScreenPosition.x + collision.x) & ~1 + 1; - testBox.top = anotherActorScreenPosition.y - collision.y; - testBox.bottom = anotherActorScreenPosition.y + collision.y + 1; - testBox2 = testBox; - testBox2.right += 2; - testBox2.left -= 2; - testBox2.top -= 1; - testBox2.bottom += 1; - - if (testBox2.contains(pointFrom)) { - if (pointFrom.x > anotherActorScreenPosition.x + 4) { - testBox.right = pointFrom.x - 1; - } else if (pointFrom.x < anotherActorScreenPosition.x - 4) { - testBox.left = pointFrom.x + 2; - } else if (pointFrom.y > anotherActorScreenPosition.y) { - testBox.bottom = pointFrom.y; - } else { - testBox.top = pointFrom.y + 1 ; - } - } - - if ((testBox.width() > 0) && (testBox.height() > 0)) { - _barrierList[_barrierCount++] = testBox; - } - } - } - - - pointBest = pointTo; - actor->_walkStepsCount = 0; - findActorPath(actor, pointFrom, pointTo); - - if (actor->_walkStepsCount == 0) { - error("actor->_walkStepsCount == 0"); - } - - if (extraStartNode) { - actor->_walkStepIndex = 0; - } else { - actor->_walkStepIndex = 1; - } - - if (extraEndNode) { - toLocation.toScreenPointXY(tempPoint); - actor->_walkStepsCount--; - actor->addWalkStepPoint(tempPoint); - } - - - pointBest = actor->_walkStepsPoints[actor->_walkStepsCount - 1]; - - pointBest.x &= ~1; - delta.x = ABS(pointFrom.x - pointTo.x); - delta.y = ABS(pointFrom.y - pointTo.y); - - bestDelta.x = ABS(pointBest.x - pointTo.x); - bestDelta.y = ABS(pointBest.y - pointTo.y); - - if ((delta.x + delta.y <= bestDelta.x + bestDelta.y) && (actor->_flags & kFollower)) { - actor->_actorFlags |= kActorNoFollow; - } - - if (pointBest == pointFrom) { - actor->_walkStepsCount = 0; - } - } else { - actor->_walkStepsCount = 0; - actor->addWalkStepPoint(pointTo); - actor->_walkStepIndex = 0; - } - - actor->_partialTarget = actor->_location; - actor->_finalTarget = toLocation; - if (actor->_walkStepsCount == 0) { - actorEndWalk(actorId, false); - return false; - } else { - if (actor->_flags & kProtagonist) { - _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2 - _actors[2]->_actorFlags &= ~kActorNoFollow; - } - actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint; - actor->_walkFrameSequence = getFrameType(kFrameWalk); - } - } - return true; -} - void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, int sampleResourceId, int speechFlags) { ActorData *actor; int i; @@ -2303,11 +1144,11 @@ void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, _activeSpeech.speechBox.right = _vm->getDisplayWidth() - 10; } - // WORKAROUND for the compact disk in Ellen's chapter + // HACK for the compact disk in Ellen's chapter // Once Ellen starts saying that "Something is different", bring the compact disk in the // scene. After speaking with AM, the compact disk is visible. She always says this line // when entering room 59, after speaking with AM, if the compact disk is not picked up yet - // Check Script::sfDropObject for the other part of this workaround + // Check Script::sfDropObject for the other part of this hack if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 3 && _vm->_scene->currentSceneNumber() == 59 && _activeSpeech.sampleResourceId == 286) { for (i = 0; i < _objsCount; i++) { @@ -2383,759 +1224,6 @@ void Actor::abortSpeech() { _activeSpeech.playingTime = 0; } -void Actor::moveDragon(ActorData *actor) { - int16 dir0, dir1, dir2, dir3; - int16 moveType; - Event event; - const DragonMove *dragonMove; - - if ((actor->_actionCycle < 0) || - ((actor->_actionCycle == 0) && (actor->_dragonMoveType >= ACTOR_DRAGON_TURN_MOVES))) { - - moveType = kDragonMoveInvalid; - if (actor->_location.distance(_protagonist->_location) < 24) { - if (_dragonHunt && (_protagonist->_currentAction != kActionFall)) { - event.type = kEvTOneshot; - event.code = kScriptEvent; - event.op = kEventExecNonBlocking; - event.time = 0; - event.param = _vm->_scene->getScriptModuleNumber(); // module number - event.param2 = ACTOR_EXP_KNOCK_RIF; // script entry point number - event.param3 = -1; // Action - event.param4 = -1; // Object - event.param5 = -1; // With Object - event.param6 = -1; // Actor - - _vm->_events->queue(&event); - _dragonHunt = false; - } - } else { - _dragonHunt = true; - } - - if (actor->_walkStepIndex + 2 > actor->_walkStepsCount) { - - _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, actor->_actionDirection); - - if (actor->_walkStepsCount == 0) { - _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, 0); - } - - if (actor->_walkStepsCount < 2) { - return; - } - - actor->_partialTarget = actor->_location; - actor->_finalTarget = _protagonist->_location; - actor->_walkStepIndex = 0; - } - - dir0 = actor->_actionDirection; - dir1 = actor->_tileDirections[actor->_walkStepIndex++]; - dir2 = actor->_tileDirections[actor->_walkStepIndex]; - dir3 = actor->_tileDirections[actor->_walkStepIndex + 1]; - - if (dir0 != dir1){ - actor->_actionDirection = dir0 = dir1; - } - - actor->_location = actor->_partialTarget; - - if ((dir1 != dir2) && (dir1 == dir3)) { - switch (dir1) { - case kDirUpLeft: - actor->_partialTarget.v() += 16; - moveType = kDragonMoveUpLeft; - break; - case kDirDownLeft: - actor->_partialTarget.u() -= 16; - moveType = kDragonMoveDownLeft; - break; - case kDirDownRight: - actor->_partialTarget.v() -= 16; - moveType = kDragonMoveDownRight; - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - moveType = kDragonMoveUpRight; - break; - } - - switch (dir2) { - case kDirUpLeft: - actor->_partialTarget.v() += 16; - break; - case kDirDownLeft: - actor->_partialTarget.u() -= 16; - break; - case kDirDownRight: - actor->_partialTarget.v() -= 16; - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - break; - } - - actor->_walkStepIndex++; - } else { - switch (dir1) { - case kDirUpLeft: - actor->_partialTarget.v() += 16; - switch (dir2) { - case kDirDownLeft: - moveType = kDragonMoveUpLeft_Left; - actor->_partialTarget.u() -= 16; - break; - case kDirUpLeft: - moveType = kDragonMoveUpLeft; - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - moveType = kDragonMoveUpLeft_Right; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - case kDirDownLeft: - actor->_partialTarget.u() -= 16; - switch (dir2) { - case kDirDownRight: - moveType = kDragonMoveDownLeft_Left; - actor->_partialTarget.v() -= 16; - break; - case kDirDownLeft: - moveType = kDragonMoveDownLeft; - break; - case kDirUpLeft: - moveType = kDragonMoveDownLeft_Right; - actor->_partialTarget.v() += 16; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - case kDirDownRight: - actor->_partialTarget.v() -= 16; - switch (dir2) { - case kDirUpRight: - moveType = kDragonMoveDownRight_Left; - actor->_partialTarget.u() += 16; - break; - case kDirDownRight: - moveType = kDragonMoveDownRight; - break; - case kDirDownLeft: - moveType = kDragonMoveDownRight_Right; - actor->_partialTarget.u() -= 16; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - switch (dir2) { - case kDirUpLeft: - moveType = kDragonMoveUpRight_Left; - actor->_partialTarget.v() += 16; - break; - case kDirUpRight: - moveType = kDragonMoveUpRight; - break; - case kDirDownRight: - moveType = kDragonMoveUpRight_Right; - actor->_partialTarget.v() -= 16; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - } - - actor->_dragonMoveType = moveType; - - if (moveType >= ACTOR_DRAGON_TURN_MOVES) { - actor->_dragonStepCycle = 0; - actor->_actionCycle = 4; - actor->_walkStepIndex++; - } else { - actor->_actionCycle = 4; - } - } - - actor->_actionCycle--; - - if ((actor->_walkStepsCount < 1) || (actor->_actionCycle < 0)) { - return; - } - - if (actor->_dragonMoveType < ACTOR_DRAGON_TURN_MOVES) { - - actor->_dragonStepCycle++; - if (actor->_dragonStepCycle >= 7) { - actor->_dragonStepCycle = 0; - } - - actor->_dragonBaseFrame = actor->_dragonMoveType * 7; - - if (actor->_location.u() > actor->_partialTarget.u() + 3) { - actor->_location.u() -= 4; - } else if (actor->_location.u() < actor->_partialTarget.u() - 3) { - actor->_location.u() += 4; - } else { - actor->_location.u() = actor->_partialTarget.u(); - } - - if (actor->_location.v() > actor->_partialTarget.v() + 3) { - actor->_location.v() -= 4; - } else if (actor->_location.v() < actor->_partialTarget.v() - 3) { - actor->_location.v() += 4; - } else { - actor->_location.v() = actor->_partialTarget.v(); - } - } else { - dragonMove = &dragonMoveTable[actor->_dragonMoveType]; - actor->_dragonBaseFrame = dragonMove->baseFrame; - - - actor->_location.u() = actor->_partialTarget.u() - dragonMove->offset[actor->_actionCycle][0]; - actor->_location.v() = actor->_partialTarget.v() - dragonMove->offset[actor->_actionCycle][1]; - - actor->_dragonStepCycle++; - if (actor->_dragonStepCycle >= 3) { - actor->_dragonStepCycle = 3; - } - } - - actor->_frameNumber = actor->_dragonBaseFrame + actor->_dragonStepCycle; -} - -void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { - Point iteratorPoint; - Point bestPoint; - int maskType; - int i; - Rect intersect; - -#ifdef ACTOR_DEBUG - _debugPointsCount = 0; -#endif - - actor->_walkStepsCount = 0; - if (fromPoint == toPoint) { - actor->addWalkStepPoint(toPoint); - return; - } - - for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { - for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { - if (_vm->_scene->validBGMaskPoint(iteratorPoint)) { - maskType = _vm->_scene->getBGMaskType(iteratorPoint); - setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty); - } else { - setPathCell(iteratorPoint, kPathCellBarrier); - } - } - } - - for (i = 0; i < _barrierCount; i++) { - intersect.left = MAX(_pathRect.left, _barrierList[i].left); - intersect.top = MAX(_pathRect.top, _barrierList[i].top); - intersect.right = MIN(_pathRect.right, _barrierList[i].right); - intersect.bottom = MIN(_pathRect.bottom, _barrierList[i].bottom); - - for (iteratorPoint.y = intersect.top; iteratorPoint.y < intersect.bottom; iteratorPoint.y++) { - for (iteratorPoint.x = intersect.left; iteratorPoint.x < intersect.right; iteratorPoint.x++) { - setPathCell(iteratorPoint, kPathCellBarrier); - } - } - } - -#ifdef ACTOR_DEBUG - for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { - for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { - if (getPathCell(iteratorPoint) == kPathCellBarrier) { - addDebugPoint(iteratorPoint, 24); - } - } - } -#endif - - if (scanPathLine(fromPoint, toPoint)) { - actor->addWalkStepPoint(fromPoint); - actor->addWalkStepPoint(toPoint); - return; - } - - i = fillPathArray(fromPoint, toPoint, bestPoint); - - if (fromPoint == bestPoint) { - actor->addWalkStepPoint(bestPoint); - return; - } - - if (i == 0) { - error("fillPathArray returns zero"); - } - - setActorPath(actor, fromPoint, bestPoint); -} - -bool Actor::scanPathLine(const Point &point1, const Point &point2) { - Point point; - Point delta; - Point s; - Point fDelta; - int16 errterm; - - calcDeltaS(point1, point2, delta, s); - point = point1; - - fDelta.x = delta.x * 2; - fDelta.y = delta.y * 2; - - if (delta.y > delta.x) { - - errterm = fDelta.x - delta.y; - - while (delta.y > 0) { - while (errterm >= 0) { - point.x += s.x; - errterm -= fDelta.y; - } - - point.y += s.y; - errterm += fDelta.x; - - if (!validPathCellPoint(point)) { - return false; - } - if (getPathCell(point) == kPathCellBarrier) { - return false; - } - delta.y--; - } - } else { - - errterm = fDelta.y - delta.x; - - while (delta.x > 0) { - while (errterm >= 0) { - point.y += s.y; - errterm -= fDelta.x; - } - - point.x += s.x; - errterm += fDelta.y; - - if (!validPathCellPoint(point)) { - return false; - } - if (getPathCell(point) == kPathCellBarrier) { - return false; - } - delta.x--; - } - } - return true; -} - -int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) { - int bestRating; - int currentRating; - int i; - Point bestPath; - int pointCounter; - int startDirection; - PathDirectionData *pathDirection; - PathDirectionData *newPathDirection; - const PathDirectionData *samplePathDirection; - Point nextPoint; - int directionCount; - int16 compressX = (_vm->getGameType() == GType_ITE) ? 2 : 1; - - _pathDirectionListCount = 0; - pointCounter = 0; - bestRating = quickDistance(fromPoint, toPoint, compressX); - bestPath = fromPoint; - - for (startDirection = 0; startDirection < 4; startDirection++) { - newPathDirection = addPathDirectionListData(); - newPathDirection->coord = fromPoint; - newPathDirection->direction = startDirection; - } - - if (validPathCellPoint(fromPoint)) { - setPathCell(fromPoint, kDirUp); - -#ifdef ACTOR_DEBUG - addDebugPoint(fromPoint, 24+36); -#endif - } - - i = 0; - - do { - pathDirection = &_pathDirectionList[i]; - for (directionCount = 0; directionCount < 3; directionCount++) { - samplePathDirection = &pathDirectionLUT[pathDirection->direction][directionCount]; - nextPoint = pathDirection->coord; - nextPoint.x += samplePathDirection->coord.x; - nextPoint.y += samplePathDirection->coord.y; - - if (!validPathCellPoint(nextPoint)) { - continue; - } - - if (getPathCell(nextPoint) != kPathCellEmpty) { - continue; - } - - setPathCell(nextPoint, samplePathDirection->direction); - -#ifdef ACTOR_DEBUG - addDebugPoint(nextPoint, samplePathDirection->direction + 96); -#endif - newPathDirection = addPathDirectionListData(); - newPathDirection->coord = nextPoint; - newPathDirection->direction = samplePathDirection->direction; - ++pointCounter; - if (nextPoint == toPoint) { - bestPoint = toPoint; - return pointCounter; - } - currentRating = quickDistance(nextPoint, toPoint, compressX); - if (currentRating < bestRating) { - bestRating = currentRating; - bestPath = nextPoint; - } - pathDirection = &_pathDirectionList[i]; - } - ++i; - } while (i < _pathDirectionListCount); - - bestPoint = bestPath; - return pointCounter; -} - -void Actor::setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { - Point nextPoint; - int8 direction; - int i; - - _pathListIndex = -1; - addPathListPoint(toPoint); - nextPoint = toPoint; - - while (!(nextPoint == fromPoint)) { - direction = getPathCell(nextPoint); - if ((direction < 0) || (direction >= 8)) { - error("Actor::setActorPath error direction 0x%X", direction); - } - nextPoint.x -= pathDirectionLUT2[direction][0]; - nextPoint.y -= pathDirectionLUT2[direction][1]; - addPathListPoint(nextPoint); - -#ifdef ACTOR_DEBUG - addDebugPoint(nextPoint, 0x8a); -#endif - } - - pathToNode(); - removeNodes(); - nodeToPath(); - removePathPoints(); - - for (i = 0; i <= _pathNodeListIndex; i++) { - actor->addWalkStepPoint(_pathNodeList[i].point); - } -} - -void Actor::pathToNode() { - Point point1, point2, delta; - int direction; - int i; - Point *point; - - point= &_pathList[_pathListIndex]; - direction = 0; - - _pathNodeListIndex = -1; - addPathNodeListPoint(*point); - - for (i = _pathListIndex; i > 0; i--) { - point1 = *point; - --point; - point2 = *point; - if (direction == 0) { - delta.x = int16Compare(point2.x, point1.x); - delta.y = int16Compare(point2.y, point1.y); - direction++; - } - if ((point1.x + delta.x != point2.x) || (point1.y + delta.y != point2.y)) { - addPathNodeListPoint(point1); - direction--; - i++; - point++; - } - } - addPathNodeListPoint(*_pathList); -} - -int pathLine(Point *pointList, const Point &point1, const Point &point2) { - Point point; - Point delta; - Point tempPoint; - Point s; - int16 errterm; - int16 res; - - calcDeltaS(point1, point2, delta, s); - - point = point1; - - tempPoint.x = delta.x * 2; - tempPoint.y = delta.y * 2; - - if (delta.y > delta.x) { - - errterm = tempPoint.x - delta.y; - res = delta.y; - - while (delta.y > 0) { - while (errterm >= 0) { - point.x += s.x; - errterm -= tempPoint.y; - } - - point.y += s.y; - errterm += tempPoint.x; - - *pointList = point; - pointList++; - delta.y--; - } - } else { - - errterm = tempPoint.y - delta.x; - res = delta.x; - - while (delta.x > 0) { - while (errterm >= 0) { - point.y += s.y; - errterm -= tempPoint.x; - } - - point.x += s.x; - errterm += tempPoint.y; - - *pointList = point; - pointList++; - delta.x--; - } - } - return res; -} - -void Actor::nodeToPath() { - int i; - Point point1, point2; - PathNode *node; - Point *point; - - for (i = 0, point = _pathList; i < _pathListAlloced; i++, point++) { - point->x = point->y = PATH_NODE_EMPTY; - } - - _pathListIndex = 1; - _pathList[0] = _pathNodeList[0].point; - _pathNodeList[0].link = 0; - for (i = 0, node = _pathNodeList; i < _pathNodeListIndex; i++) { - point1 = node->point; - node++; - point2 = node->point; - _pathListIndex += pathLine(&_pathList[_pathListIndex], point1, point2); - node->link = _pathListIndex - 1; - } - _pathListIndex--; - _pathNodeList[_pathNodeListIndex].link = _pathListIndex; - -} - -void Actor::removeNodes() { - int i, j, k; - PathNode *iNode, *jNode, *kNode, *fNode; - fNode = &_pathNodeList[_pathNodeListIndex]; - - if (scanPathLine(_pathNodeList[0].point, fNode->point)) { - _pathNodeList[1] = *fNode; - _pathNodeListIndex = 1; - } - - if (_pathNodeListIndex < 4) { - return; - } - - for (i = _pathNodeListIndex - 1, iNode = fNode-1; i > 1 ; i--, iNode--) { - if (iNode->point.x == PATH_NODE_EMPTY) { - continue; - } - - if (scanPathLine(_pathNodeList[0].point, iNode->point)) { - for (j = 1, jNode = _pathNodeList + 1; j < i; j++, jNode++) { - jNode->point.x = PATH_NODE_EMPTY; - } - } - } - - for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { - if (iNode->point.x == PATH_NODE_EMPTY) { - continue; - } - - if (scanPathLine(fNode->point, iNode->point)) { - for (j = i + 1, jNode = iNode + 1; j < _pathNodeListIndex; j++, jNode++) { - jNode->point.x = PATH_NODE_EMPTY; - } - } - } - condenseNodeList(); - - for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { - if (iNode->point.x == PATH_NODE_EMPTY) { - continue; - } - for (j = i + 2, jNode = iNode + 2; j < _pathNodeListIndex; j++, jNode++) { - if (jNode->point.x == PATH_NODE_EMPTY) { - continue; - } - - if (scanPathLine(iNode->point, jNode->point)) { - for (k = i + 1,kNode = iNode + 1; k < j; k++, kNode++) { - kNode->point.x = PATH_NODE_EMPTY; - } - } - } - } - condenseNodeList(); -} - -void Actor::condenseNodeList() { - int i, j, count; - PathNode *iNode, *jNode; - - count = _pathNodeListIndex; - - for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex; i++, iNode++) { - if (iNode->point.x == PATH_NODE_EMPTY) { - j = i + 1; - jNode = iNode + 1; - while (jNode->point.x == PATH_NODE_EMPTY) { - j++; - jNode++; - } - *iNode = *jNode; - count = i; - jNode->point.x = PATH_NODE_EMPTY; - if (j == _pathNodeListIndex) { - break; - } - } - } - _pathNodeListIndex = count; -} - -void Actor::removePathPoints() { - int i, j, k, l; - PathNode *node; - int start; - int end; - Point point1, point2; - - if (_pathNodeListIndex < 2) - return; - - _newPathNodeListIndex = -1; - addNewPathNodeListPoint(_pathNodeList[0]); - - for (i = 1, node = _pathNodeList + 1; i < _pathNodeListIndex; i++, node++) { - addNewPathNodeListPoint(*node); - - for (j = 5; j > 0; j--) { - start = node->link - j; - end = node->link + j; - - if (start < 0 || end > _pathListIndex) { - continue; - } - - point1 = _pathList[start]; - point2 = _pathList[end]; - if ((point1.x == PATH_NODE_EMPTY) || (point2.x == PATH_NODE_EMPTY)) { - continue; - } - - if (scanPathLine(point1, point2)) { - for (l = 1; l <= _newPathNodeListIndex; l++) { - if (start <= _newPathNodeList[l].link) { - _newPathNodeListIndex = l; - _newPathNodeList[_newPathNodeListIndex].point = point1; - _newPathNodeList[_newPathNodeListIndex].link = start; - incrementNewPathNodeListIndex(); - break; - } - } - _newPathNodeList[_newPathNodeListIndex].point = point2; - _newPathNodeList[_newPathNodeListIndex].link = end; - - for (k = start + 1; k < end; k++) { - _pathList[k].x = PATH_NODE_EMPTY; - } - break; - } - } - } - - addNewPathNodeListPoint(_pathNodeList[_pathNodeListIndex]); - - for (i = 0, j = 0; i <= _newPathNodeListIndex; i++) { - if (_newPathNodeListIndex == i || (_newPathNodeList[i].point != _newPathNodeList[i+1].point)) { - _pathNodeList[j++] = _newPathNodeList[i]; - } - } - _pathNodeListIndex = j - 1; -} - -void Actor::drawPathTest() { -#ifdef ACTOR_DEBUG - int i; - Surface *surface; - surface = _vm->_gfx->getBackBuffer(); - if (_debugPoints == NULL) { - return; - } - - for (i = 0; i < _debugPointsCount; i++) { - *((byte *)surface->pixels + (_debugPoints[i].point.y * surface->pitch) + _debugPoints[i].point.x) = _debugPoints[i].color; - } -#endif -} - void Actor::saveState(Common::OutSaveFile *out) { uint16 i; @@ -3156,7 +1244,7 @@ void Actor::loadState(Common::InSaveFile *in) { int32 i; int16 protagState = in->readSint16LE(); - if (protagState != 0) + if (protagState != 0 || _protagonist->_shareFrames) setProtagState(protagState); for (i = 0; i < _actorsCount; i++) { @@ -3178,24 +1266,4 @@ void Actor::loadState(Common::InSaveFile *in) { } } -// Console wrappers - must be safe to run - -void Actor::cmdActorWalkTo(int argc, const char **argv) { - uint16 actorId = (uint16) atoi(argv[1]); - Location location; - Point movePoint; - - movePoint.x = atoi(argv[2]); - movePoint.y = atoi(argv[3]); - - location.fromScreenPoint(movePoint); - - if (!validActorId(actorId)) { - _vm->_console->DebugPrintf("Actor::cmActorWalkTo Invalid actorId 0x%X.\n", actorId); - return; - } - - actorWalkTo(actorId, location); -} - } // End of namespace Saga diff --git a/engines/saga/actor.h b/engines/saga/actor.h index ef62661c6c..7022ef1289 100644 --- a/engines/saga/actor.h +++ b/engines/saga/actor.h @@ -94,6 +94,24 @@ enum ActorActions { kActionClimb = 12 }; +enum ActorFrameIds { +//ITE + kFrameITEStand = 0, + kFrameITEWalk = 1, + kFrameITESpeak = 2, + kFrameITEGive = 3, + kFrameITEGesture = 4, + kFrameITEWait = 5, + kFrameITEPickUp = 6, + kFrameITELook = 7, +//IHNM + kFrameIHNMStand = 0, + kFrameIHNMSpeak = 1, + kFrameIHNMWait = 2, + kFrameIHNMGesture = 3, + kFrameIHNMWalk = 4 +}; + enum SpeechFlags { kSpeakNoAnimate = 1, kSpeakAsync = 2, @@ -112,6 +130,18 @@ enum ActorFrameTypes { kFrameLook }; +// Lookup table to convert 8 cardinal directions to 4 +static const int actorDirectectionsLUT[8] = { + ACTOR_DIRECTION_BACK, // kDirUp + ACTOR_DIRECTION_RIGHT, // kDirUpRight + ACTOR_DIRECTION_RIGHT, // kDirRight + ACTOR_DIRECTION_RIGHT, // kDirDownRight + ACTOR_DIRECTION_FORWARD,// kDirDown + ACTOR_DIRECTION_LEFT, // kDirDownLeft + ACTOR_DIRECTION_LEFT, // kDirLeft + ACTOR_DIRECTION_LEFT, // kDirUpLeft +}; + enum ActorFlagsEx { kActorNoCollide = (1 << 0), kActorNoFollow = (1 << 1), @@ -612,8 +642,6 @@ public: void freeObjList(); void loadObjList(int objectCount, int objectsResourceID); - void showActors(bool flag) { _showActors = flag; } - protected: friend class Script; bool loadActorResources(ActorData *actor); @@ -709,7 +737,6 @@ private: int _xCellCount; int _yCellCount; Rect _pathRect; - bool _showActors; PathDirectionData *_pathDirectionList; int _pathDirectionListCount; diff --git a/engines/saga/actor_walk.cpp b/engines/saga/actor_walk.cpp new file mode 100644 index 0000000000..47bf804edb --- /dev/null +++ b/engines/saga/actor_walk.cpp @@ -0,0 +1,1942 @@ +/* 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 "saga/saga.h" + +#include "saga/actor.h" +#include "saga/console.h" +#include "saga/events.h" +#include "saga/isomap.h" +#include "saga/objectmap.h" +#include "saga/sagaresnames.h" +#include "saga/script.h" +#include "saga/sound.h" +#include "saga/scene.h" + +namespace Saga { + +static const PathDirectionData pathDirectionLUT[8][3] = { + { { 0, Point( 0, -1) }, { 7, Point(-1, -1) }, { 4, Point( 1, -1) } }, + { { 1, Point( 1, 0) }, { 4, Point( 1, -1) }, { 5, Point( 1, 1) } }, + { { 2, Point( 0, 1) }, { 5, Point( 1, 1) }, { 6, Point(-1, 1) } }, + { { 3, Point(-1, 0) }, { 6, Point(-1, 1) }, { 7, Point(-1, -1) } }, + { { 0, Point( 0, -1) }, { 1, Point( 1, 0) }, { 4, Point( 1, -1) } }, + { { 1, Point( 1, 0) }, { 2, Point( 0, 1) }, { 5, Point( 1, 1) } }, + { { 2, Point( 0, 1) }, { 3, Point(-1, 0) }, { 6, Point(-1, 1) } }, + { { 3, Point(-1, 0) }, { 0, Point( 0, -1) }, { 7, Point(-1, -1) } } +}; + +static const int pathDirectionLUT2[8][2] = { + { 0, -1 }, + { 1, 0 }, + { 0, 1 }, + { -1, 0 }, + { 1, -1 }, + { 1, 1 }, + { -1, 1 }, + { -1, -1 } +}; + +static const int angleLUT[16][2] = { + { 0, -256 }, + { 98, -237 }, + { 181, -181 }, + { 237, -98 }, + { 256, 0 }, + { 237, 98 }, + { 181, 181 }, + { 98, 237 }, + { 0, 256 }, + { -98, 237 }, + { -181, 181 }, + { -237, 98 }, + { -256, 0 }, + { -237, -98 }, + { -181, -181 }, + { -98, -237 } +}; + +static const int directionLUT[8][2] = { + { 0 * 2, -2 * 2 }, + { 2 * 2, -1 * 2 }, + { 3 * 2, 0 * 2 }, + { 2 * 2, 1 * 2 }, + { 0 * 2, 2 * 2 }, + { -2 * 2, 1 * 2 }, + { -4 * 2, 0 * 2 }, + { -2 * 2, -1 * 2 } +}; + +static const int tileDirectionLUT[8][2] = { + { 1, 1 }, + { 2, 0 }, + { 1, -1 }, + { 0, -2 }, + { -1, -1 }, + { -2, 0 }, + { -1, 1 }, + { 0, 2 } +}; + +struct DragonMove { + uint16 baseFrame; + int16 offset[4][2]; +}; + +static const DragonMove dragonMoveTable[12] = { + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 28, { { -0, 0 }, { -1, 6 }, { -5, 11 }, { -10, 15 } } }, + { 56, { { 0, 0 }, { 1, 6 }, { 5, 11 }, { 10, 15 } } }, + { 40, { { 0, 0 }, { 6, 1 }, { 11, 5 }, { 15, 10 } } }, + { 44, { { 0, 0 }, { 6, -1 }, { 11, -5 }, { 15, -10 } } }, + { 32, { { -0, -0 }, { -6, -1 }, { -11, -5 }, { -15, -10 } } }, + { 52, { { -0, 0 }, { -6, 1 }, { -11, 5 }, { -15, 10 } } }, + { 36, { { 0, -0 }, { 1, -6 }, { 5, -11 }, { 10, -15 } } }, + { 48, { { -0, -0 }, { -1, -6 }, { -5, -11 }, { -10, -15 } } } +}; + +inline int16 quickDistance(const Point &point1, const Point &point2, int16 compressX) { + Point delta; + delta.x = ABS(point1.x - point2.x) / compressX; + delta.y = ABS(point1.y - point2.y); + return ((delta.x < delta.y) ? (delta.y + delta.x / 2) : (delta.x + delta.y / 2)); +} + +inline void calcDeltaS(const Point &point1, const Point &point2, Point &delta, Point &s) { + + delta.x = point2.x - point1.x; + if (delta.x == 0) { + s.x = 0; + } else { + if (delta.x > 0) { + s.x = 1; + } else { + s.x = -1; + delta.x = -delta.x; + } + } + + + delta.y = point2.y - point1.y; + if (delta.y == 0) { + s.y = 0; + } else { + if (delta.y > 0) { + s.y = 1; + } else { + s.y = -1; + delta.y = -delta.y; + } + } +} + +inline int16 int16Compare(int16 i1, int16 i2) { + return ((i1) > (i2) ? 1 : ((i1) < (i2) ? -1 : 0)); +} + +bool Actor::validFollowerLocation(const Location &location) { + Point point; + location.toScreenPointXY(point); + + if ((point.x < 5) || (point.x >= _vm->getDisplayWidth() - 5) || + (point.y < 0) || (point.y > _vm->_scene->getHeight())) { + return false; + } + + return (_vm->_scene->canWalk(point)); +} + +void Actor::realLocation(Location &location, uint16 objectId, uint16 walkFlags) { + int angle; + int distance; + ActorData *actor; + ObjectData *obj; + debug (8, "Actor::realLocation objectId=%i", objectId); + if (walkFlags & kWalkUseAngle) { + if (_vm->_scene->getFlags() & kSceneFlagISO) { + angle = (location.x + 2) & 15; + distance = location.y; + + location.u() = (angleLUT[angle][0] * distance) >> 8; + location.v() = -(angleLUT[angle][1] * distance) >> 8; + } else { + angle = location.x & 15; + distance = location.y; + + location.x = (angleLUT[angle][0] * distance) >> 6; + location.y = (angleLUT[angle][1] * distance) >> 6; + } + } + + if (objectId != ID_NOTHING) { + if (validActorId(objectId)) { + actor = getActor(objectId); + location.addXY(actor->_location); + } else if (validObjId(objectId)) { + obj = getObj(objectId); + location.addXY(obj->_location); + } + } +} + +void Actor::actorFaceTowardsObject(uint16 actorId, uint16 objectId) { + ActorData *actor; + ObjectData *obj; + + if (validActorId(objectId)) { + actor = getActor(objectId); + actorFaceTowardsPoint(actorId, actor->_location); + } else if (validObjId(objectId)) { + obj = getObj(objectId); + actorFaceTowardsPoint(actorId, obj->_location); + } +} + +void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) { + ActorData *actor; + Location delta; + //debug (8, "Actor::actorFaceTowardsPoint actorId=%i", actorId); + actor = getActor(actorId); + + toLocation.delta(actor->_location, delta); + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + if (delta.u() > 0) { + actor->_facingDirection = (delta.v() > 0) ? kDirUp : kDirRight; + } else { + actor->_facingDirection = (delta.v() > 0) ? kDirLeft : kDirDown; + } + } else { + if (ABS(delta.y) > ABS(delta.x * 2)) { + actor->_facingDirection = (delta.y > 0) ? kDirDown : kDirUp; + } else { + actor->_facingDirection = (delta.x > 0) ? kDirRight : kDirLeft; + } + } +} + +void Actor::updateActorsScene(int actorsEntrance) { + int i, j; + int followerDirection; + ActorData *actor; + Location tempLocation; + Location possibleLocation; + Point delta; + const SceneEntry *sceneEntry; + + if (_vm->_scene->currentSceneNumber() == 0) { + error("Actor::updateActorsScene _vm->_scene->currentSceneNumber() == 0"); + } + + _vm->_sound->stopVoice(); + _activeSpeech.stringsCount = 0; + _activeSpeech.playing = false; + _protagonist = NULL; + + for (i = 0; i < _actorsCount; i++) { + actor = _actors[i]; + actor->_inScene = false; + actor->_spriteList.freeMem(); + if (actor->_disabled) { + continue; + } + if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) { + if (actor->_flags & kProtagonist) { + actor->_finalTarget = actor->_location; + _centerActor = _protagonist = actor; + } else if (_vm->getGameType() == GType_ITE && + _vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { + continue; + } + + actor->_sceneNumber = _vm->_scene->currentSceneNumber(); + } + if (actor->_sceneNumber == _vm->_scene->currentSceneNumber()) { + actor->_inScene = true; + actor->_actionCycle = (_vm->_rnd.getRandomNumber(7) & 0x7) * 4; // 1/8th chance + } + } + + // _protagonist can be null while loading a game from the command line + if (_protagonist == NULL) + return; + + if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) { + if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) { + actorsEntrance = 0; //OCEAN bug + } + + sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance); + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _protagonist->_location = sceneEntry->location; + } else { + _protagonist->_location.x = sceneEntry->location.x * ACTOR_LMULT; + _protagonist->_location.y = sceneEntry->location.y * ACTOR_LMULT; + _protagonist->_location.z = sceneEntry->location.z * ACTOR_LMULT; + } + // Workaround for bug #1328045: + // "When entering any of the houses at the start of the + // game if you click on anything inside the building you + // start walking through the door, turn around and leave." + // + // After stepping on an action zone, Rif is trying to exit. + // Shift Rif's entry position to a non action zone area. + if (_vm->getGameType() == GType_ITE) { + if ((_vm->_scene->currentSceneNumber() >= 53) && (_vm->_scene->currentSceneNumber() <= 66)) + _protagonist->_location.y += 10; + } + + _protagonist->_facingDirection = _protagonist->_actionDirection = sceneEntry->facing; + } + + _protagonist->_currentAction = kActionWait; + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + //nothing? + } else { + _vm->_scene->initDoorsState(); //TODO: move to _scene + } + + followerDirection = _protagonist->_facingDirection + 3; + calcScreenPosition(_protagonist); + + for (i = 0; i < _actorsCount; i++) { + actor = _actors[i]; + if (actor->_flags & (kFollower)) { + actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection; + actor->_currentAction = kActionWait; + actor->_walkStepsCount = actor->_walkStepIndex = 0; + actor->_location.z = _protagonist->_location.z; + + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _vm->_isoMap->placeOnTileMap(_protagonist->_location, actor->_location, 3, followerDirection & 0x07); + } else { + followerDirection &= 0x07; + + possibleLocation = _protagonist->_location; + + delta.x = directionLUT[followerDirection][0]; + delta.y = directionLUT[followerDirection][1]; + + for (j = 0; j < 30; j++) { + tempLocation = possibleLocation; + tempLocation.x += delta.x; + tempLocation.y += delta.y; + + if (validFollowerLocation(tempLocation)) { + possibleLocation = tempLocation; + } else { + tempLocation = possibleLocation; + tempLocation.x += delta.x; + if (validFollowerLocation(tempLocation)) { + possibleLocation = tempLocation; + } else { + tempLocation = possibleLocation; + tempLocation.y += delta.y; + if (validFollowerLocation(tempLocation)) { + possibleLocation = tempLocation; + } else { + break; + } + } + } + } + + actor->_location = possibleLocation; + } + followerDirection += 2; + } + + } + + handleActions(0, true); + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _vm->_isoMap->adjustScroll(true); + } +} + +void Actor::handleActions(int msec, bool setup) { + int i; + ActorData *actor; + ActorFrameRange *frameRange; + int state; + int speed; + int32 framesLeft; + Location delta; + Location addDelta; + int hitZoneIndex; + const HitZone *hitZone; + Point hitPoint; + Location pickLocation; + + for (i = 0; i < _actorsCount; i++) { + actor = _actors[i]; + if (!actor->_inScene) + continue; + + if ((_vm->getGameType() == GType_ITE) && (i == ACTOR_DRAGON_INDEX)) { + moveDragon(actor); + continue; + } + + switch (actor->_currentAction) { + case kActionWait: + if (!setup && (actor->_flags & kFollower)) { + followProtagonist(actor); + if (actor->_currentAction != kActionWait) + break; + } + + if (actor->_targetObject != ID_NOTHING) { + actorFaceTowardsObject(actor->_id, actor->_targetObject); + } + + if (actor->_flags & kCycle) { + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); + if (frameRange->frameCount > 0) { + actor->_actionCycle++; + actor->_actionCycle = (actor->_actionCycle) % frameRange->frameCount; + } else { + actor->_actionCycle = 0; + } + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + break; + } + + if ((actor->_actionCycle & 3) == 0) { + actor->cycleWrap(100); + + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameWait)); + if ((frameRange->frameCount < 1 || actor->_actionCycle > 33)) + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); + + if (frameRange->frameCount) { + actor->_frameNumber = frameRange->frameIndex + (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount - 1); + } else { + actor->_frameNumber = frameRange->frameIndex; + } + } + actor->_actionCycle++; + break; + + case kActionWalkToPoint: + case kActionWalkToLink: + if (_vm->_scene->getFlags() & kSceneFlagISO) { + actor->_partialTarget.delta(actor->_location, delta); + + while ((delta.u() == 0) && (delta.v() == 0)) { + + if ((actor == _protagonist) && (_vm->mouseButtonPressed())) { + _vm->_isoMap->screenPointToTileCoords(_vm->mousePos(), pickLocation); + + if (!actorWalkTo(_protagonist->_id, pickLocation)) { + break; + } + } else if (!_vm->_isoMap->nextTileTarget(actor) && !actorEndWalk(actor->_id, true)) { + break; + } + + actor->_partialTarget.delta(actor->_location, delta); + actor->_partialTarget.z = 0; + } + + if (actor->_flags & kFastest) { + speed = 8; + } else if (actor->_flags & kFaster) { + speed = 6; + } else { + speed = 4; + } + + if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { + speed = 2; + } + + if ((actor->_actionDirection == 2) || (actor->_actionDirection == 6)) { + speed = speed / 2; + } + + if (ABS(delta.v()) > ABS(delta.u())) { + addDelta.v() = clamp(-speed, delta.v(), speed); + if (addDelta.v() == delta.v()) { + addDelta.u() = delta.u(); + } else { + addDelta.u() = delta.u() * addDelta.v(); + addDelta.u() += (addDelta.u() > 0) ? (delta.v() / 2) : (-delta.v() / 2); + addDelta.u() /= delta.v(); + } + } else { + addDelta.u() = clamp(-speed, delta.u(), speed); + if (addDelta.u() == delta.u()) { + addDelta.v() = delta.v(); + } else { + addDelta.v() = delta.v() * addDelta.u(); + addDelta.v() += (addDelta.v() > 0) ? (delta.u() / 2) : (-delta.u() / 2); + addDelta.v() /= delta.u(); + } + } + + actor->_location.add(addDelta); + } else { + actor->_partialTarget.delta(actor->_location, delta); + + while ((delta.x == 0) && (delta.y == 0)) { + + if (actor->_walkStepIndex >= actor->_walkStepsCount) { + actorEndWalk(actor->_id, true); + break; + } + + actor->_partialTarget.fromScreenPoint(actor->_walkStepsPoints[actor->_walkStepIndex++]); + if (_vm->getGameType() == GType_ITE) { + if (actor->_partialTarget.x > 224 * 2 * ACTOR_LMULT) { + actor->_partialTarget.x -= 256 * 2 * ACTOR_LMULT; + } + } else { + if (actor->_partialTarget.x > 224 * 4 * ACTOR_LMULT) { + actor->_partialTarget.x -= 256 * 4 * ACTOR_LMULT; + } + } + + actor->_partialTarget.delta(actor->_location, delta); + + if (ABS(delta.y) > ABS(delta.x)) { + actor->_actionDirection = delta.y > 0 ? kDirDown : kDirUp; + } else { + actor->_actionDirection = delta.x > 0 ? kDirRight : kDirLeft; + } + } + + if(_vm->getGameType() == GType_ITE) + speed = (ACTOR_LMULT * 2 * actor->_screenScale + 63) / 256; + else + speed = (ACTOR_SPEED * actor->_screenScale + 128) >> 8; + + if (speed < 1) + speed = 1; + + if(_vm->getGameType() == GType_IHNM) + speed = speed / 2; + + if ((actor->_actionDirection == kDirUp) || (actor->_actionDirection == kDirDown)) { + addDelta.y = clamp(-speed, delta.y, speed); + if (addDelta.y == delta.y) { + addDelta.x = delta.x; + } else { + addDelta.x = delta.x * addDelta.y; + addDelta.x += (addDelta.x > 0) ? (delta.y / 2) : (-delta.y / 2); + addDelta.x /= delta.y; + actor->_facingDirection = actor->_actionDirection; + } + } else { + addDelta.x = clamp(-2 * speed, delta.x, 2 * speed); + if (addDelta.x == delta.x) { + addDelta.y = delta.y; + } else { + addDelta.y = delta.y * addDelta.x; + addDelta.y += (addDelta.y > 0) ? (delta.x / 2) : (-delta.x / 2); + addDelta.y /= delta.x; + actor->_facingDirection = actor->_actionDirection; + } + } + + actor->_location.add(addDelta); + } + + if (actor->_actorFlags & kActorBackwards) { + actor->_facingDirection = (actor->_actionDirection + 4) & 7; + actor->_actionCycle--; + } else { + actor->_actionCycle++; + } + + frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); + + if (actor->_actionCycle < 0) { + actor->_actionCycle = frameRange->frameCount - 1; + } else if (actor->_actionCycle >= frameRange->frameCount) { + actor->_actionCycle = 0; + } + + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + break; + + case kActionWalkDir: + if (_vm->_scene->getFlags() & kSceneFlagISO) { + actor->_location.u() += tileDirectionLUT[actor->_actionDirection][0]; + actor->_location.v() += tileDirectionLUT[actor->_actionDirection][1]; + + frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); + + actor->_actionCycle++; + actor->cycleWrap(frameRange->frameCount); + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + } else { + if (_vm->getGameType() == GType_ITE) { + actor->_location.x += directionLUT[actor->_actionDirection][0] * 2; + actor->_location.y += directionLUT[actor->_actionDirection][1] * 2; + } else { + // FIXME: The original does not multiply by 8 here, but we do + actor->_location.x += (directionLUT[actor->_actionDirection][0] * 8 * actor->_screenScale + 128) >> 8; + actor->_location.y += (directionLUT[actor->_actionDirection][1] * 8 * actor->_screenScale + 128) >> 8; + } + + frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); + actor->_actionCycle++; + actor->cycleWrap(frameRange->frameCount); + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + } + break; + + case kActionSpeak: + actor->_actionCycle++; + actor->cycleWrap(64); + + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameGesture)); + if (actor->_actionCycle >= frameRange->frameCount) { + if (actor->_actionCycle & 1) + break; + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameSpeak)); + + state = (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount); + + if (state == 0) { + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); + } else { + state--; + } + } else { + state = actor->_actionCycle; + } + + actor->_frameNumber = frameRange->frameIndex + state; + break; + + case kActionAccept: + case kActionStoop: + break; + + case kActionCycleFrames: + case kActionPongFrames: + if (actor->_cycleTimeCount > 0) { + actor->_cycleTimeCount--; + break; + } + + actor->_cycleTimeCount = actor->_cycleDelay; + actor->_actionCycle++; + + frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); + + if (actor->_currentAction == kActionPongFrames) { + if (actor->_actionCycle >= frameRange->frameCount * 2 - 2) { + if (actor->_actorFlags & kActorContinuous) { + actor->_actionCycle = 0; + } else { + actor->_currentAction = kActionFreeze; + break; + } + } + + state = actor->_actionCycle; + if (state >= frameRange->frameCount) { + state = frameRange->frameCount * 2 - 2 - state; + } + } else { + if (actor->_actionCycle >= frameRange->frameCount) { + if (actor->_actorFlags & kActorContinuous) { + actor->_actionCycle = 0; + } else { + actor->_currentAction = kActionFreeze; + break; + } + } + state = actor->_actionCycle; + } + + if (frameRange->frameCount && (actor->_actorFlags & kActorRandom)) { + state = _vm->_rnd.getRandomNumber(frameRange->frameCount - 1); + } + + if (actor->_actorFlags & kActorBackwards) { + actor->_frameNumber = frameRange->frameIndex + frameRange->frameCount - 1 - state; + } else { + actor->_frameNumber = frameRange->frameIndex + state; + } + break; + + case kActionFall: + if (actor->_actionCycle > 0) { + framesLeft = actor->_actionCycle--; + actor->_finalTarget.delta(actor->_location, delta); + delta.x /= framesLeft; + delta.y /= framesLeft; + actor->_location.addXY(delta); + actor->_fallVelocity += actor->_fallAcceleration; + actor->_fallPosition += actor->_fallVelocity; + actor->_location.z = actor->_fallPosition >> 4; + } else { + actor->_location = actor->_finalTarget; + actor->_currentAction = kActionFreeze; + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + } + break; + + case kActionClimb: + actor->_cycleDelay++; + if (actor->_cycleDelay & 3) { + break; + } + + if (actor->_location.z >= actor->_finalTarget.z + ACTOR_CLIMB_SPEED) { + actor->_location.z -= ACTOR_CLIMB_SPEED; + actor->_actionCycle--; + } else if (actor->_location.z <= actor->_finalTarget.z - ACTOR_CLIMB_SPEED) { + actor->_location.z += ACTOR_CLIMB_SPEED; + actor->_actionCycle++; + } else { + actor->_location.z = actor->_finalTarget.z; + actor->_currentAction = kActionFreeze; + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + } + + frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); + + if (actor->_actionCycle < 0) { + actor->_actionCycle = frameRange->frameCount - 1; + } + actor->cycleWrap(frameRange->frameCount); + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + break; + } + + if ((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) { + hitZone = NULL; + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + actor->_location.toScreenPointUV(hitPoint); + } else { + actor->_location.toScreenPointXY(hitPoint); + } + hitZoneIndex = _vm->_scene->_actionMap->hitTest(hitPoint); + if (hitZoneIndex != -1) { + hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); + } + + if (hitZone != actor->_lastZone) { + if (actor->_lastZone) + stepZoneAction(actor, actor->_lastZone, true, false); + actor->_lastZone = hitZone; + // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves + // (room 51) for hitzone 24577 (the door with the copy protection) to avoid the glitch. This glitch + // happens because the copy protection is supposed to kick in at this point, but it's bypassed + // (with permission from Wyrmkeep Entertainment) + if (hitZone && + !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51 && hitZone->getHitZoneId() == 24577)) + stepZoneAction(actor, hitZone, false, false); + } + } + } + // Update frameCount for sfWaitFrames in IHNM + _vm->_frameCount++; +} + +void Actor::direct(int msec) { + + if (_vm->_scene->_entryList.entryListCount == 0) { + return; + } + + if (_vm->_interface->_statusTextInput) { + return; + } + + // FIXME: HACK. This should be turned into cycle event. + _lastTickMsec += msec; + + if (_lastTickMsec > 1000 / _handleActionDiv) { + _lastTickMsec = 0; + //process actions + handleActions(msec, false); + } + +//process speech + handleSpeech(msec); +} + +bool Actor::followProtagonist(ActorData *actor) { + Location protagonistLocation; + Location newLocation; + Location delta; + int protagonistBGMaskType; + Point prefer1; + Point prefer2; + Point prefer3; + int16 prefU; + int16 prefV; + int16 newU; + int16 newV; + + assert(_protagonist); + + actor->_flags &= ~(kFaster | kFastest); + protagonistLocation = _protagonist->_location; + calcScreenPosition(_protagonist); + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + prefU = 60; + prefV = 60; + + + actor->_location.delta(protagonistLocation, delta); + + if (actor->_id == actorIndexToId(2)) { + prefU = prefV = 48; + } + + if ((delta.u() > prefU) || (delta.u() < -prefU) || (delta.v() > prefV) || (delta.v() < -prefV)) { + + if ((delta.u() > prefU * 2) || (delta.u() < -prefU * 2) || (delta.v() > prefV * 2) || (delta.v() < -prefV * 2)) { + actor->_flags |= kFaster; + + if ((delta.u() > prefU * 3) || (delta.u() < -prefU*3) || (delta.v() > prefV * 3) || (delta.v() < -prefV * 3)) { + actor->_flags |= kFastest; + } + } + + prefU /= 2; + prefV /= 2; + + newU = clamp(-prefU, delta.u(), prefU) + protagonistLocation.u(); + newV = clamp(-prefV, delta.v(), prefV) + protagonistLocation.v(); + + newLocation.u() = newU + _vm->_rnd.getRandomNumber(prefU - 1) - prefU / 2; + newLocation.v() = newV + _vm->_rnd.getRandomNumber(prefV - 1) - prefV / 2; + newLocation.z = 0; + + return actorWalkTo(actor->_id, newLocation); + } + + } else { + prefer1.x = (100 * _protagonist->_screenScale) >> 8; + prefer1.y = (50 * _protagonist->_screenScale) >> 8; + + if (_protagonist->_currentAction == kActionWalkDir) { + prefer1.x /= 2; + } + + if (prefer1.x < 8) { + prefer1.x = 8; + } + + if (prefer1.y < 8) { + prefer1.y = 8; + } + + prefer2.x = prefer1.x * 2; + prefer2.y = prefer1.y * 2; + prefer3.x = prefer1.x + prefer1.x / 2; + prefer3.y = prefer1.y + prefer1.y / 2; + + actor->_location.delta(protagonistLocation, delta); + + protagonistBGMaskType = 0; + if (_vm->_scene->isBGMaskPresent() && _vm->_scene->validBGMaskPoint(_protagonist->_screenPosition)) { + protagonistBGMaskType = _vm->_scene->getBGMaskType(_protagonist->_screenPosition); + } + + if ((_vm->_rnd.getRandomNumber(7) & 0x7) == 0) // 1/8th chance + actor->_actorFlags &= ~kActorNoFollow; + + if (actor->_actorFlags & kActorNoFollow) { + return false; + } + + if ((delta.x > prefer2.x) || (delta.x < -prefer2.x) || + (delta.y > prefer2.y) || (delta.y < -prefer2.y) || + ((_protagonist->_currentAction == kActionWait) && + (delta.x * 2 < prefer1.x) && (delta.x * 2 > -prefer1.x) && + (delta.y < prefer1.y) && (delta.y > -prefer1.y))) { + + if (ABS(delta.x) > ABS(delta.y)) { + + delta.x = (delta.x > 0) ? prefer3.x : -prefer3.x; + + newLocation.x = delta.x + protagonistLocation.x; + newLocation.y = clamp(-prefer2.y, delta.y, prefer2.y) + protagonistLocation.y; + } else { + delta.y = (delta.y > 0) ? prefer3.y : -prefer3.y; + + newLocation.x = clamp(-prefer2.x, delta.x, prefer2.x) + protagonistLocation.x; + newLocation.y = delta.y + protagonistLocation.y; + } + newLocation.z = 0; + + if (protagonistBGMaskType != 3) { + newLocation.x += _vm->_rnd.getRandomNumber(prefer1.x - 1) - prefer1.x / 2; + newLocation.y += _vm->_rnd.getRandomNumber(prefer1.y - 1) - prefer1.y / 2; + } + + newLocation.x = clamp(-31 * 4, newLocation.x, (_vm->getDisplayWidth() + 31) * 4); + + return actorWalkTo(actor->_id, newLocation); + } + } + return false; +} + +bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) { + ActorData *actor; + ActorData *anotherActor; + int i; + + Rect testBox; + Rect testBox2; + Point anotherActorScreenPosition; + Point collision; + Point pointFrom, pointTo, pointBest, pointAdd; + Point delta, bestDelta; + Point tempPoint; + bool extraStartNode; + bool extraEndNode; + + actor = getActor(actorId); + + if (actor == _protagonist) { + _vm->_scene->setDoorState(2, 0xff); + _vm->_scene->setDoorState(3, 0); + } else { + _vm->_scene->setDoorState(2, 0); + _vm->_scene->setDoorState(3, 0xff); + } + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + + if ((_vm->getGameType() == GType_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) { + return false; + } + + actor->_finalTarget = toLocation; + actor->_walkStepsCount = 0; + _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); + + + if ((actor->_walkStepsCount == 0) && (actor->_flags & kProtagonist)) { + actor->_actorFlags |= kActorNoCollide; + _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); + } + + actor->_walkStepIndex = 0; + if (_vm->_isoMap->nextTileTarget(actor)) { + actor->_currentAction = kActionWalkToPoint; + actor->_walkFrameSequence = getFrameType(kFrameWalk); + } else { + actorEndWalk(actorId, false); + return false; + } + } else { + + actor->_location.toScreenPointXY(pointFrom); + pointFrom.x &= ~1; + + extraStartNode = _vm->_scene->offscreenPath(pointFrom); + + toLocation.toScreenPointXY(pointTo); + pointTo.x &= ~1; + + extraEndNode = _vm->_scene->offscreenPath(pointTo); + + if (_vm->_scene->isBGMaskPresent()) { + + if ((((actor->_currentAction >= kActionWalkToPoint) && + (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) && + !_vm->_scene->canWalk(pointFrom)) { + + int max = _vm->getGameType() == GType_ITE ? 8 : 4; + + for (i = 1; i < max; i++) { + pointAdd = pointFrom; + pointAdd.y += i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + pointAdd = pointFrom; + pointAdd.y -= i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + if (_vm->getGameType() == GType_ITE) { + pointAdd = pointFrom; + pointAdd.x += i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + pointAdd = pointFrom; + pointAdd.x -= i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + } + } + } + + _barrierCount = 0; + if (!(actor->_actorFlags & kActorNoCollide)) { + collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2); + collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2); + + + for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) { + anotherActor = _actors[i]; + if (!anotherActor->_inScene) + continue; + if (anotherActor == actor) + continue; + + anotherActorScreenPosition = anotherActor->_screenPosition; + testBox.left = (anotherActorScreenPosition.x - collision.x) & ~1; + testBox.right = (anotherActorScreenPosition.x + collision.x) & ~1 + 1; + testBox.top = anotherActorScreenPosition.y - collision.y; + testBox.bottom = anotherActorScreenPosition.y + collision.y + 1; + testBox2 = testBox; + testBox2.right += 2; + testBox2.left -= 2; + testBox2.top -= 1; + testBox2.bottom += 1; + + if (testBox2.contains(pointFrom)) { + if (pointFrom.x > anotherActorScreenPosition.x + 4) { + testBox.right = pointFrom.x - 1; + } else if (pointFrom.x < anotherActorScreenPosition.x - 4) { + testBox.left = pointFrom.x + 2; + } else if (pointFrom.y > anotherActorScreenPosition.y) { + testBox.bottom = pointFrom.y; + } else { + testBox.top = pointFrom.y + 1 ; + } + } + + if ((testBox.width() > 0) && (testBox.height() > 0)) { + _barrierList[_barrierCount++] = testBox; + } + } + } + + + pointBest = pointTo; + actor->_walkStepsCount = 0; + findActorPath(actor, pointFrom, pointTo); + + if (actor->_walkStepsCount == 0) { + error("actor->_walkStepsCount == 0"); + } + + if (extraStartNode) { + actor->_walkStepIndex = 0; + } else { + actor->_walkStepIndex = 1; + } + + if (extraEndNode) { + toLocation.toScreenPointXY(tempPoint); + actor->_walkStepsCount--; + actor->addWalkStepPoint(tempPoint); + } + + + pointBest = actor->_walkStepsPoints[actor->_walkStepsCount - 1]; + + pointBest.x &= ~1; + delta.x = ABS(pointFrom.x - pointTo.x); + delta.y = ABS(pointFrom.y - pointTo.y); + + bestDelta.x = ABS(pointBest.x - pointTo.x); + bestDelta.y = ABS(pointBest.y - pointTo.y); + + if ((delta.x + delta.y <= bestDelta.x + bestDelta.y) && (actor->_flags & kFollower)) { + actor->_actorFlags |= kActorNoFollow; + } + + if (pointBest == pointFrom) { + actor->_walkStepsCount = 0; + } + } else { + actor->_walkStepsCount = 0; + actor->addWalkStepPoint(pointTo); + actor->_walkStepIndex = 0; + } + + actor->_partialTarget = actor->_location; + actor->_finalTarget = toLocation; + if (actor->_walkStepsCount == 0) { + actorEndWalk(actorId, false); + return false; + } else { + if (actor->_flags & kProtagonist) { + _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2 + _actors[2]->_actorFlags &= ~kActorNoFollow; + } + actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint; + actor->_walkFrameSequence = getFrameType(kFrameWalk); + } + } + return true; +} + +bool Actor::actorEndWalk(uint16 actorId, bool recurse) { + bool walkMore = false; + ActorData *actor; + const HitZone *hitZone; + int hitZoneIndex; + Point testPoint; + + actor = getActor(actorId); + actor->_actorFlags &= ~kActorBackwards; + + if (_vm->getGameType() == GType_ITE) { + + if (actor->_location.distance(actor->_finalTarget) > 8 && (actor->_flags & kProtagonist) && recurse && !(actor->_actorFlags & kActorNoCollide)) { + actor->_actorFlags |= kActorNoCollide; + return actorWalkTo(actorId, actor->_finalTarget); + } + } + + actor->_currentAction = kActionWait; + if (actor->_actorFlags & kActorFinalFace) { + actor->_facingDirection = actor->_actionDirection = (actor->_actorFlags >> 6) & 0x07; //? + } + + actor->_actorFlags &= ~(kActorNoCollide | kActorCollided | kActorFinalFace | kActorFacingMask); + actor->_flags &= ~(kFaster | kFastest); + + if (actor == _protagonist) { + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + if (_vm->_script->_pendingVerb == _vm->_script->getVerbType(kVerbWalkTo)) { + if (_vm->getGameType() == GType_ITE) + actor->_location.toScreenPointUV(testPoint); // it's wrong calculation, but it is used in ITE + else + actor->_location.toScreenPointXY(testPoint); + + hitZoneIndex = _vm->_scene->_actionMap->hitTest(testPoint); + if (hitZoneIndex != -1) { + hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); + stepZoneAction(actor, hitZone, false, true); + } else { + _vm->_script->setNoPendingVerb(); + } + } else if (_vm->_script->_pendingVerb != _vm->_script->getVerbType(kVerbNone)) { + _vm->_script->doVerb(); + } + } else { + if (recurse && (actor->_flags & kFollower)) + walkMore = followProtagonist(actor); + + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + } + return walkMore; +} + +void Actor::moveDragon(ActorData *actor) { + int16 dir0, dir1, dir2, dir3; + int16 moveType; + Event event; + const DragonMove *dragonMove; + + if ((actor->_actionCycle < 0) || + ((actor->_actionCycle == 0) && (actor->_dragonMoveType >= ACTOR_DRAGON_TURN_MOVES))) { + + moveType = kDragonMoveInvalid; + if (actor->_location.distance(_protagonist->_location) < 24) { + if (_dragonHunt && (_protagonist->_currentAction != kActionFall)) { + event.type = kEvTOneshot; + event.code = kScriptEvent; + event.op = kEventExecNonBlocking; + event.time = 0; + event.param = _vm->_scene->getScriptModuleNumber(); // module number + event.param2 = ACTOR_EXP_KNOCK_RIF; // script entry point number + event.param3 = -1; // Action + event.param4 = -1; // Object + event.param5 = -1; // With Object + event.param6 = -1; // Actor + _vm->_events->queue(&event); + + _dragonHunt = false; + } + } else { + _dragonHunt = true; + } + + if (actor->_walkStepIndex + 2 > actor->_walkStepsCount) { + + _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, actor->_actionDirection); + + if (actor->_walkStepsCount == 0) { + _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, 0); + } + + if (actor->_walkStepsCount < 2) { + return; + } + + actor->_partialTarget = actor->_location; + actor->_finalTarget = _protagonist->_location; + actor->_walkStepIndex = 0; + } + + dir0 = actor->_actionDirection; + dir1 = actor->_tileDirections[actor->_walkStepIndex++]; + dir2 = actor->_tileDirections[actor->_walkStepIndex]; + dir3 = actor->_tileDirections[actor->_walkStepIndex + 1]; + + if (dir0 != dir1){ + actor->_actionDirection = dir0 = dir1; + } + + actor->_location = actor->_partialTarget; + + if ((dir1 != dir2) && (dir1 == dir3)) { + switch (dir1) { + case kDirUpLeft: + actor->_partialTarget.v() += 16; + moveType = kDragonMoveUpLeft; + break; + case kDirDownLeft: + actor->_partialTarget.u() -= 16; + moveType = kDragonMoveDownLeft; + break; + case kDirDownRight: + actor->_partialTarget.v() -= 16; + moveType = kDragonMoveDownRight; + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + moveType = kDragonMoveUpRight; + break; + } + + switch (dir2) { + case kDirUpLeft: + actor->_partialTarget.v() += 16; + break; + case kDirDownLeft: + actor->_partialTarget.u() -= 16; + break; + case kDirDownRight: + actor->_partialTarget.v() -= 16; + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + break; + } + + actor->_walkStepIndex++; + } else { + switch (dir1) { + case kDirUpLeft: + actor->_partialTarget.v() += 16; + switch (dir2) { + case kDirDownLeft: + moveType = kDragonMoveUpLeft_Left; + actor->_partialTarget.u() -= 16; + break; + case kDirUpLeft: + moveType = kDragonMoveUpLeft; + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + moveType = kDragonMoveUpLeft_Right; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + case kDirDownLeft: + actor->_partialTarget.u() -= 16; + switch (dir2) { + case kDirDownRight: + moveType = kDragonMoveDownLeft_Left; + actor->_partialTarget.v() -= 16; + break; + case kDirDownLeft: + moveType = kDragonMoveDownLeft; + break; + case kDirUpLeft: + moveType = kDragonMoveDownLeft_Right; + actor->_partialTarget.v() += 16; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + case kDirDownRight: + actor->_partialTarget.v() -= 16; + switch (dir2) { + case kDirUpRight: + moveType = kDragonMoveDownRight_Left; + actor->_partialTarget.u() += 16; + break; + case kDirDownRight: + moveType = kDragonMoveDownRight; + break; + case kDirDownLeft: + moveType = kDragonMoveDownRight_Right; + actor->_partialTarget.u() -= 16; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + switch (dir2) { + case kDirUpLeft: + moveType = kDragonMoveUpRight_Left; + actor->_partialTarget.v() += 16; + break; + case kDirUpRight: + moveType = kDragonMoveUpRight; + break; + case kDirDownRight: + moveType = kDragonMoveUpRight_Right; + actor->_partialTarget.v() -= 16; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + } + + actor->_dragonMoveType = moveType; + + if (moveType >= ACTOR_DRAGON_TURN_MOVES) { + actor->_dragonStepCycle = 0; + actor->_actionCycle = 4; + actor->_walkStepIndex++; + } else { + actor->_actionCycle = 4; + } + } + + actor->_actionCycle--; + + if ((actor->_walkStepsCount < 1) || (actor->_actionCycle < 0)) { + return; + } + + if (actor->_dragonMoveType < ACTOR_DRAGON_TURN_MOVES) { + + actor->_dragonStepCycle++; + if (actor->_dragonStepCycle >= 7) { + actor->_dragonStepCycle = 0; + } + + actor->_dragonBaseFrame = actor->_dragonMoveType * 7; + + if (actor->_location.u() > actor->_partialTarget.u() + 3) { + actor->_location.u() -= 4; + } else if (actor->_location.u() < actor->_partialTarget.u() - 3) { + actor->_location.u() += 4; + } else { + actor->_location.u() = actor->_partialTarget.u(); + } + + if (actor->_location.v() > actor->_partialTarget.v() + 3) { + actor->_location.v() -= 4; + } else if (actor->_location.v() < actor->_partialTarget.v() - 3) { + actor->_location.v() += 4; + } else { + actor->_location.v() = actor->_partialTarget.v(); + } + } else { + dragonMove = &dragonMoveTable[actor->_dragonMoveType]; + actor->_dragonBaseFrame = dragonMove->baseFrame; + + + actor->_location.u() = actor->_partialTarget.u() - dragonMove->offset[actor->_actionCycle][0]; + actor->_location.v() = actor->_partialTarget.v() - dragonMove->offset[actor->_actionCycle][1]; + + actor->_dragonStepCycle++; + if (actor->_dragonStepCycle >= 3) { + actor->_dragonStepCycle = 3; + } + } + + actor->_frameNumber = actor->_dragonBaseFrame + actor->_dragonStepCycle; +} + +void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { + Point iteratorPoint; + Point bestPoint; + int maskType; + int i; + Rect intersect; + +#ifdef ACTOR_DEBUG + _debugPointsCount = 0; +#endif + + actor->_walkStepsCount = 0; + if (fromPoint == toPoint) { + actor->addWalkStepPoint(toPoint); + return; + } + + for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { + for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { + if (_vm->_scene->validBGMaskPoint(iteratorPoint)) { + maskType = _vm->_scene->getBGMaskType(iteratorPoint); + setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty); + } else { + setPathCell(iteratorPoint, kPathCellBarrier); + } + } + } + + for (i = 0; i < _barrierCount; i++) { + intersect.left = MAX(_pathRect.left, _barrierList[i].left); + intersect.top = MAX(_pathRect.top, _barrierList[i].top); + intersect.right = MIN(_pathRect.right, _barrierList[i].right); + intersect.bottom = MIN(_pathRect.bottom, _barrierList[i].bottom); + + for (iteratorPoint.y = intersect.top; iteratorPoint.y < intersect.bottom; iteratorPoint.y++) { + for (iteratorPoint.x = intersect.left; iteratorPoint.x < intersect.right; iteratorPoint.x++) { + setPathCell(iteratorPoint, kPathCellBarrier); + } + } + } + +#ifdef ACTOR_DEBUG + for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { + for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { + if (getPathCell(iteratorPoint) == kPathCellBarrier) { + addDebugPoint(iteratorPoint, 24); + } + } + } +#endif + + if (scanPathLine(fromPoint, toPoint)) { + actor->addWalkStepPoint(fromPoint); + actor->addWalkStepPoint(toPoint); + return; + } + + i = fillPathArray(fromPoint, toPoint, bestPoint); + + if (fromPoint == bestPoint) { + actor->addWalkStepPoint(bestPoint); + return; + } + + if (i == 0) { + error("fillPathArray returns zero"); + } + + setActorPath(actor, fromPoint, bestPoint); +} + +bool Actor::scanPathLine(const Point &point1, const Point &point2) { + Point point; + Point delta; + Point s; + Point fDelta; + int16 errterm; + + calcDeltaS(point1, point2, delta, s); + point = point1; + + fDelta.x = delta.x * 2; + fDelta.y = delta.y * 2; + + if (delta.y > delta.x) { + + errterm = fDelta.x - delta.y; + + while (delta.y > 0) { + while (errterm >= 0) { + point.x += s.x; + errterm -= fDelta.y; + } + + point.y += s.y; + errterm += fDelta.x; + + if (!validPathCellPoint(point)) { + return false; + } + if (getPathCell(point) == kPathCellBarrier) { + return false; + } + delta.y--; + } + } else { + + errterm = fDelta.y - delta.x; + + while (delta.x > 0) { + while (errterm >= 0) { + point.y += s.y; + errterm -= fDelta.x; + } + + point.x += s.x; + errterm += fDelta.y; + + if (!validPathCellPoint(point)) { + return false; + } + if (getPathCell(point) == kPathCellBarrier) { + return false; + } + delta.x--; + } + } + return true; +} + +int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) { + int bestRating; + int currentRating; + int i; + Point bestPath; + int pointCounter; + int startDirection; + PathDirectionData *pathDirection; + PathDirectionData *newPathDirection; + const PathDirectionData *samplePathDirection; + Point nextPoint; + int directionCount; + int16 compressX = (_vm->getGameType() == GType_ITE) ? 2 : 1; + + _pathDirectionListCount = 0; + pointCounter = 0; + bestRating = quickDistance(fromPoint, toPoint, compressX); + bestPath = fromPoint; + + for (startDirection = 0; startDirection < 4; startDirection++) { + newPathDirection = addPathDirectionListData(); + newPathDirection->coord = fromPoint; + newPathDirection->direction = startDirection; + } + + if (validPathCellPoint(fromPoint)) { + setPathCell(fromPoint, kDirUp); + +#ifdef ACTOR_DEBUG + addDebugPoint(fromPoint, 24+36); +#endif + } + + i = 0; + + do { + pathDirection = &_pathDirectionList[i]; + for (directionCount = 0; directionCount < 3; directionCount++) { + samplePathDirection = &pathDirectionLUT[pathDirection->direction][directionCount]; + nextPoint = pathDirection->coord; + nextPoint.x += samplePathDirection->coord.x; + nextPoint.y += samplePathDirection->coord.y; + + if (!validPathCellPoint(nextPoint)) { + continue; + } + + if (getPathCell(nextPoint) != kPathCellEmpty) { + continue; + } + + setPathCell(nextPoint, samplePathDirection->direction); + +#ifdef ACTOR_DEBUG + addDebugPoint(nextPoint, samplePathDirection->direction + 96); +#endif + newPathDirection = addPathDirectionListData(); + newPathDirection->coord = nextPoint; + newPathDirection->direction = samplePathDirection->direction; + ++pointCounter; + if (nextPoint == toPoint) { + bestPoint = toPoint; + return pointCounter; + } + currentRating = quickDistance(nextPoint, toPoint, compressX); + if (currentRating < bestRating) { + bestRating = currentRating; + bestPath = nextPoint; + } + pathDirection = &_pathDirectionList[i]; + } + ++i; + } while (i < _pathDirectionListCount); + + bestPoint = bestPath; + return pointCounter; +} + +void Actor::setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { + Point nextPoint; + int8 direction; + int i; + + _pathListIndex = -1; + addPathListPoint(toPoint); + nextPoint = toPoint; + + while (!(nextPoint == fromPoint)) { + direction = getPathCell(nextPoint); + if ((direction < 0) || (direction >= 8)) { + error("Actor::setActorPath error direction 0x%X", direction); + } + nextPoint.x -= pathDirectionLUT2[direction][0]; + nextPoint.y -= pathDirectionLUT2[direction][1]; + addPathListPoint(nextPoint); + +#ifdef ACTOR_DEBUG + addDebugPoint(nextPoint, 0x8a); +#endif + } + + pathToNode(); + removeNodes(); + nodeToPath(); + removePathPoints(); + + for (i = 0; i <= _pathNodeListIndex; i++) { + actor->addWalkStepPoint(_pathNodeList[i].point); + } +} + +void Actor::pathToNode() { + Point point1, point2, delta; + int direction; + int i; + Point *point; + + point= &_pathList[_pathListIndex]; + direction = 0; + + _pathNodeListIndex = -1; + addPathNodeListPoint(*point); + + for (i = _pathListIndex; i > 0; i--) { + point1 = *point; + --point; + point2 = *point; + if (direction == 0) { + delta.x = int16Compare(point2.x, point1.x); + delta.y = int16Compare(point2.y, point1.y); + direction++; + } + if ((point1.x + delta.x != point2.x) || (point1.y + delta.y != point2.y)) { + addPathNodeListPoint(point1); + direction--; + i++; + point++; + } + } + addPathNodeListPoint(*_pathList); +} + +int pathLine(Point *pointList, const Point &point1, const Point &point2) { + Point point; + Point delta; + Point tempPoint; + Point s; + int16 errterm; + int16 res; + + calcDeltaS(point1, point2, delta, s); + + point = point1; + + tempPoint.x = delta.x * 2; + tempPoint.y = delta.y * 2; + + if (delta.y > delta.x) { + + errterm = tempPoint.x - delta.y; + res = delta.y; + + while (delta.y > 0) { + while (errterm >= 0) { + point.x += s.x; + errterm -= tempPoint.y; + } + + point.y += s.y; + errterm += tempPoint.x; + + *pointList = point; + pointList++; + delta.y--; + } + } else { + + errterm = tempPoint.y - delta.x; + res = delta.x; + + while (delta.x > 0) { + while (errterm >= 0) { + point.y += s.y; + errterm -= tempPoint.x; + } + + point.x += s.x; + errterm += tempPoint.y; + + *pointList = point; + pointList++; + delta.x--; + } + } + return res; +} + +void Actor::nodeToPath() { + int i; + Point point1, point2; + PathNode *node; + Point *point; + + for (i = 0, point = _pathList; i < _pathListAlloced; i++, point++) { + point->x = point->y = PATH_NODE_EMPTY; + } + + _pathListIndex = 1; + _pathList[0] = _pathNodeList[0].point; + _pathNodeList[0].link = 0; + for (i = 0, node = _pathNodeList; i < _pathNodeListIndex; i++) { + point1 = node->point; + node++; + point2 = node->point; + _pathListIndex += pathLine(&_pathList[_pathListIndex], point1, point2); + node->link = _pathListIndex - 1; + } + _pathListIndex--; + _pathNodeList[_pathNodeListIndex].link = _pathListIndex; + +} + +void Actor::removeNodes() { + int i, j, k; + PathNode *iNode, *jNode, *kNode, *fNode; + fNode = &_pathNodeList[_pathNodeListIndex]; + + if (scanPathLine(_pathNodeList[0].point, fNode->point)) { + _pathNodeList[1] = *fNode; + _pathNodeListIndex = 1; + } + + if (_pathNodeListIndex < 4) { + return; + } + + for (i = _pathNodeListIndex - 1, iNode = fNode-1; i > 1 ; i--, iNode--) { + if (iNode->point.x == PATH_NODE_EMPTY) { + continue; + } + + if (scanPathLine(_pathNodeList[0].point, iNode->point)) { + for (j = 1, jNode = _pathNodeList + 1; j < i; j++, jNode++) { + jNode->point.x = PATH_NODE_EMPTY; + } + } + } + + for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { + if (iNode->point.x == PATH_NODE_EMPTY) { + continue; + } + + if (scanPathLine(fNode->point, iNode->point)) { + for (j = i + 1, jNode = iNode + 1; j < _pathNodeListIndex; j++, jNode++) { + jNode->point.x = PATH_NODE_EMPTY; + } + } + } + condenseNodeList(); + + for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { + if (iNode->point.x == PATH_NODE_EMPTY) { + continue; + } + for (j = i + 2, jNode = iNode + 2; j < _pathNodeListIndex; j++, jNode++) { + if (jNode->point.x == PATH_NODE_EMPTY) { + continue; + } + + if (scanPathLine(iNode->point, jNode->point)) { + for (k = i + 1,kNode = iNode + 1; k < j; k++, kNode++) { + kNode->point.x = PATH_NODE_EMPTY; + } + } + } + } + condenseNodeList(); +} + +void Actor::condenseNodeList() { + int i, j, count; + PathNode *iNode, *jNode; + + count = _pathNodeListIndex; + + for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex; i++, iNode++) { + if (iNode->point.x == PATH_NODE_EMPTY) { + j = i + 1; + jNode = iNode + 1; + while (jNode->point.x == PATH_NODE_EMPTY) { + j++; + jNode++; + } + *iNode = *jNode; + count = i; + jNode->point.x = PATH_NODE_EMPTY; + if (j == _pathNodeListIndex) { + break; + } + } + } + _pathNodeListIndex = count; +} + +void Actor::removePathPoints() { + int i, j, k, l; + PathNode *node; + int start; + int end; + Point point1, point2; + + if (_pathNodeListIndex < 2) + return; + + _newPathNodeListIndex = -1; + addNewPathNodeListPoint(_pathNodeList[0]); + + for (i = 1, node = _pathNodeList + 1; i < _pathNodeListIndex; i++, node++) { + addNewPathNodeListPoint(*node); + + for (j = 5; j > 0; j--) { + start = node->link - j; + end = node->link + j; + + if (start < 0 || end > _pathListIndex) { + continue; + } + + point1 = _pathList[start]; + point2 = _pathList[end]; + if ((point1.x == PATH_NODE_EMPTY) || (point2.x == PATH_NODE_EMPTY)) { + continue; + } + + if (scanPathLine(point1, point2)) { + for (l = 1; l <= _newPathNodeListIndex; l++) { + if (start <= _newPathNodeList[l].link) { + _newPathNodeListIndex = l; + _newPathNodeList[_newPathNodeListIndex].point = point1; + _newPathNodeList[_newPathNodeListIndex].link = start; + incrementNewPathNodeListIndex(); + break; + } + } + _newPathNodeList[_newPathNodeListIndex].point = point2; + _newPathNodeList[_newPathNodeListIndex].link = end; + + for (k = start + 1; k < end; k++) { + _pathList[k].x = PATH_NODE_EMPTY; + } + break; + } + } + } + + addNewPathNodeListPoint(_pathNodeList[_pathNodeListIndex]); + + for (i = 0, j = 0; i <= _newPathNodeListIndex; i++) { + if (_newPathNodeListIndex == i || (_newPathNodeList[i].point != _newPathNodeList[i+1].point)) { + _pathNodeList[j++] = _newPathNodeList[i]; + } + } + _pathNodeListIndex = j - 1; +} + +void Actor::drawPathTest() { +#ifdef ACTOR_DEBUG + int i; + Surface *surface; + surface = _vm->_gfx->getBackBuffer(); + if (_debugPoints == NULL) { + return; + } + + for (i = 0; i < _debugPointsCount; i++) { + *((byte *)surface->pixels + (_debugPoints[i].point.y * surface->pitch) + _debugPoints[i].point.x) = _debugPoints[i].color; + } +#endif +} + +// Console wrappers - must be safe to run + +void Actor::cmdActorWalkTo(int argc, const char **argv) { + uint16 actorId = (uint16) atoi(argv[1]); + Location location; + Point movePoint; + + movePoint.x = atoi(argv[2]); + movePoint.y = atoi(argv[3]); + + location.fromScreenPoint(movePoint); + + if (!validActorId(actorId)) { + _vm->_console->DebugPrintf("Actor::cmActorWalkTo Invalid actorId 0x%X.\n", actorId); + return; + } + + actorWalkTo(actorId, location); +} + +} // End of namespace Saga diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp index 7b3bdcd665..09b2ba412d 100644 --- a/engines/saga/animation.cpp +++ b/engines/saga/animation.cpp @@ -78,92 +78,75 @@ void Anim::freeCutawayList(void) { _cutawayListLength = 0; } -void Anim::playCutaway(int cut, bool fade) { +int Anim::playCutaway(int cut, bool fade) { debug(0, "playCutaway(%d, %d)", cut, fade); + Event event; + Event *q_event = NULL; bool startImmediately = false; + byte *resourceData; + size_t resourceDataLength; + ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE); _cutAwayFade = fade; - // Chained cutaway, clean up the previous cutaway - if (_cutawayActive) { - clearCutaway(); - - // This is used because when AM is zapping the child's mother in Benny's chapter, - // there is a cutaway followed by a video. The video needs to start immediately after - // the cutaway so that it looks like the original - startImmediately = true; - } - - // WORKAROUND: The IHNM demo deals with chained cutaways in a different manner. Don't save - // the palette of cutaway 11 (the woman looking at the marble) - if (!(_vm->getGameId() == GID_IHNM_DEMO && cut == 11)) - _vm->_gfx->savePalette(); + _vm->_gfx->savePalette(); + _vm->_gfx->getCurrentPal(saved_pal); if (fade) { - _vm->_gfx->getCurrentPal(saved_pal); - // TODO - /* - Event event; static PalEntry cur_pal[PAL_ENTRIES]; - _vm->_gfx->getCurrentPal(cur_pal); + _vm->_interface->setFadeMode(kFadeOut); + // Fade to black out + _vm->_gfx->getCurrentPal(cur_pal); event.type = kEvTImmediate; event.code = kPalEvent; event.op = kEventPalToBlack; event.time = 0; event.duration = kNormalFadeDuration; event.data = cur_pal; + q_event = _vm->_events->queue(&event); - _vm->_events->queue(&event); - */ + // set fade mode + event.type = kEvTImmediate; + event.code = kInterfaceEvent; + event.op = kEventSetFadeMode; + event.param = kNoFade; + event.time = 0; + event.duration = 0; + q_event = _vm->_events->chain(q_event, &event); } // Prepare cutaway - _vm->_gfx->showCursor(false); - _vm->_interface->setStatusText(""); - _vm->_interface->setSaveReminderState(0); - _vm->_interface->rememberMode(); + if (!_cutawayActive) { + _vm->_gfx->showCursor(false); + _vm->_interface->setStatusText(""); + _vm->_interface->setSaveReminderState(0); + _vm->_interface->rememberMode(); + _cutawayActive = true; + } else { + // If another cutaway is up, start the next cutaway immediately + startImmediately = true; + } + if (_cutAwayMode == kPanelVideo) _vm->_interface->setMode(kPanelVideo); else _vm->_interface->setMode(kPanelCutaway); - _cutawayActive = true; - - // Set the initial background and palette for the cutaway - ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE); - - byte *resourceData; - size_t resourceDataLength; - - _vm->_resource->loadResource(context, _cutawayList[cut].backgroundResourceId, resourceData, resourceDataLength); - - byte *buf; - size_t buflen; - int width; - int height; - - _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height); - - const PalEntry *palette = (const PalEntry *)_vm->getImagePal(resourceData, resourceDataLength); - - Surface *bgSurface = _vm->_render->getBackGroundSurface(); - const Rect rect(width, height); - - bgSurface->blit(rect, buf); - _vm->_frameCount++; - - _vm->_gfx->setPalette(palette); - // WORKAROUND for a bug found in the original IHNM demo. The palette of cutaway 12 is incorrect (the incorrect - // palette can be seen in the original demo too, for a split second). Therefore, use the saved palette for this - // cutaway - if (_vm->getGameId() == GID_IHNM_DEMO && cut == 12) - _vm->_gfx->restorePalette(); - - free(buf); - free(resourceData); + if (fade) { + // Set the initial background and palette for the cutaway + event.type = kEvTImmediate; + event.code = kCutawayEvent; + event.op = kEventShowCutawayBg; + event.time = 0; + event.duration = 0; + event.param = _cutawayList[cut].backgroundResourceId; + q_event = _vm->_events->chain(q_event, &event); + } else { + showCutawayBg(_cutawayList[cut].backgroundResourceId); + } // Play the animation @@ -183,7 +166,7 @@ void Anim::playCutaway(int cut, bool fade) { if (cutawaySlot == -1) { warning("Could not allocate cutaway animation slot"); - return; + return 0; } // Some cutaways in IHNM have animResourceId equal to 0, which means that they only have @@ -191,48 +174,47 @@ void Anim::playCutaway(int cut, bool fade) { // An example is the "nightfall" animation in Ben's chapter (fadein-fadeout), the animation // for the second from the left monitor in Ellen's chapter etc // Therefore, skip the animation bit if animResourceId is 0 and only show the background - if (_cutawayList[cut].animResourceId == 0) - return; - - _vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData, resourceDataLength); - - load(MAX_ANIMATIONS + cutawaySlot, resourceData, resourceDataLength); - - free(resourceData); + if (_cutawayList[cut].animResourceId != 0) { + _vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData, resourceDataLength); + load(MAX_ANIMATIONS + cutawaySlot, resourceData, resourceDataLength); + free(resourceData); - setCycles(MAX_ANIMATIONS + cutawaySlot, _cutawayList[cut].cycles); - setFrameTime(MAX_ANIMATIONS + cutawaySlot, 1000 / _cutawayList[cut].frameRate); + setCycles(MAX_ANIMATIONS + cutawaySlot, _cutawayList[cut].cycles); + setFrameTime(MAX_ANIMATIONS + cutawaySlot, 1000 / _cutawayList[cut].frameRate); + } if (_cutAwayMode != kPanelVideo || startImmediately) play(MAX_ANIMATIONS + cutawaySlot, 0); else { - Event event; event.type = kEvTOneshot; event.code = kAnimEvent; event.op = kEventPlay; event.param = MAX_ANIMATIONS + cutawaySlot; event.time = (40 / 3) * 1000 / _cutawayList[cut].frameRate; - _vm->_events->queue(&event); + if (fade) + q_event = _vm->_events->chain(q_event, &event); + else + _vm->_events->queue(&event); } + + return MAX_ANIMATIONS + cutawaySlot; } void Anim::endCutaway(void) { - // I believe this is called by scripts after running one cutaway. At - // this time, nothing needs to be done here. + // This is called by scripts after a cutaway is finished. At this time, + // nothing needs to be done here. debug(0, "endCutaway()"); } void Anim::returnFromCutaway(void) { - // I believe this is called by scripts after running a cutaway to - // ensure that we return to the scene as if nothing had happened. It's - // not called by the IHNM intro, presumably because there is no old - // scene to return to. + // This is called by scripts after a cutaway is finished, to return back + // to the scene that the cutaway was called from. It's not called by the + // IHNM intro, as there is no old scene to return to. debug(0, "returnFromCutaway()"); - if (_cutawayActive) { Event event; Event *q_event = NULL; @@ -240,16 +222,26 @@ void Anim::returnFromCutaway(void) { if (_cutAwayFade) { static PalEntry cur_pal[PAL_ENTRIES]; - _vm->_gfx->getCurrentPal(cur_pal); + _vm->_interface->setFadeMode(kFadeOut); + // Fade to black out + _vm->_gfx->getCurrentPal(cur_pal); event.type = kEvTImmediate; event.code = kPalEvent; event.op = kEventPalToBlack; event.time = 0; event.duration = kNormalFadeDuration; event.data = cur_pal; - q_event = _vm->_events->queue(&event); + + // set fade mode + event.type = kEvTImmediate; + event.code = kInterfaceEvent; + event.op = kEventSetFadeMode; + event.param = kNoFade; + event.time = 0; + event.duration = 0; + q_event = _vm->_events->chain(q_event, &event); } // Clear the cutaway. Note that this sets _cutawayActive to false @@ -272,7 +264,6 @@ void Anim::returnFromCutaway(void) { event.op = kEventResumeAll; event.time = 0; event.duration = 0; - q_event = _vm->_events->chain(q_event, &event); // chain with the other events // Draw the scene @@ -281,7 +272,6 @@ void Anim::returnFromCutaway(void) { event.op = kEventDraw; event.time = 0; event.duration = 0; - q_event = _vm->_events->chain(q_event, &event); // chain with the other events // Handle fade up, if we previously faded down @@ -292,22 +282,22 @@ void Anim::returnFromCutaway(void) { event.time = 0; event.duration = kNormalFadeDuration; event.data = saved_pal; - q_event = _vm->_events->chain(q_event, &event); - } event.type = kEvTOneshot; event.code = kScriptEvent; event.op = kEventThreadWake; event.param = kWaitTypeWakeUp; - q_event = _vm->_events->chain(q_event, &event); } } void Anim::clearCutaway(void) { + PalEntry *pal; + debug(1, "clearCutaway()"); + if (_cutawayActive) { _cutawayActive = false; @@ -317,18 +307,56 @@ void Anim::clearCutaway(void) { } _vm->_interface->restoreMode(); - - if (_vm->getGameId() != GID_IHNM_DEMO) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) { - // Don't show the mouse cursor in the non-interactive part of the IHNM demo - } else { - _vm->_gfx->showCursor(true); - } - } else { + _vm->_gfx->showCursor(true); + + if (_vm->getGameId() == GID_IHNM_DEMO) { // Enable the save reminder state after each cutaway for the IHNM demo _vm->_interface->setSaveReminderState(true); } + + // Set the scene's palette + _vm->_scene->getBGPal(pal); + _vm->_gfx->setPalette(pal); + } +} + +void Anim::showCutawayBg(int bg) { + ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE); + + byte *resourceData; + size_t resourceDataLength; + byte *buf; + size_t buflen; + int width; + int height; + Event event; + static PalEntry pal[PAL_ENTRIES]; + + _vm->_resource->loadResource(context, bg, resourceData, resourceDataLength); + _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height); + + const byte *palPointer = _vm->getImagePal(resourceData, resourceDataLength); + memcpy(pal, palPointer, sizeof(pal)); + Surface *bgSurface = _vm->_render->getBackGroundSurface(); + const Rect rect(width, height); + bgSurface->blit(rect, buf); + _vm->_frameCount++; + + if (_cutAwayFade) { + // Handle fade up, if we previously faded down + event.type = kEvTImmediate; + event.code = kPalEvent; + event.op = kEventBlackToPal; + event.time = 0; + event.duration = kNormalFadeDuration; + event.data = pal; + _vm->_events->queue(&event); + } else { + _vm->_gfx->setPalette(pal); } + + free(buf); + free(resourceData); } void Anim::startVideo(int vid, bool fade) { @@ -380,6 +408,12 @@ void Anim::load(uint16 animId, const byte *animResourceData, size_t animResource anim->start += temp; // Cache frame offsets + + // WORKAROUND: Cutaway with background resource ID 37 (loaded as cutaway #4) is ending credits. + // For some reason it has wrong number of frames specified in its header. So we calculate it here: + if (animId > MAX_ANIMATIONS && _cutawayListLength > 4 && _cutawayList[4].backgroundResourceId == 37 && anim->maxFrame == 143) + anim->maxFrame = fillFrameOffsets(anim, false); + anim->frameOffsets = (size_t *)malloc((anim->maxFrame + 1) * sizeof(*anim->frameOffsets)); if (anim->frameOffsets == NULL) { memoryError("Anim::load"); @@ -388,7 +422,9 @@ void Anim::load(uint16 animId, const byte *animResourceData, size_t animResource fillFrameOffsets(anim); // Set animation data - anim->currentFrame = 0; + // HACK: We set currentFrame to -1, as the first frame of the animation is never drawn otherwise + // (check Anim::play) + anim->currentFrame = -1; anim->completed = 0; anim->cycles = anim->maxFrame; @@ -422,6 +458,13 @@ void Anim::setCycles(uint16 animId, int cycles) { anim->cycles = cycles; } +int Anim::getCycles(uint16 animId) { + if (animId >= MAX_ANIMATIONS && _cutawayAnimations[animId - MAX_ANIMATIONS] == NULL) + return 0; + + return getAnimation(animId)->cycles; +} + void Anim::play(uint16 animId, int vectorTime, bool playing) { Event event; Surface *backGroundSurface; @@ -440,6 +483,23 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { if (animId < MAX_ANIMATIONS && _cutawayActive) return; + if (animId >= MAX_ANIMATIONS && _cutawayAnimations[animId - MAX_ANIMATIONS] == NULL) { + // In IHNM, cutaways without an animation bit are not rendered, but the framecount + // needs to be updated + _vm->_frameCount++; + + event.type = kEvTOneshot; + event.code = kAnimEvent; + event.op = kEventFrame; + event.param = animId; + event.time = 10; + _vm->_events->queue(&event); + + // Nothing to render here (apart from the background, which is already rendered), + // so return + return; + } + anim = getAnimation(animId); backGroundSurface = _vm->_render->getBackGroundSurface(); @@ -453,19 +513,28 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { return; } + // HACK: The first frame of the animation is never shown when entering a scene + // For now, we initialize currentFrame to be -1 instead of 0 and we draw the + // first frame of the animation on the next iteration of Anim::play + // FIXME: find out why this occurs and remove this hack. Note that when this + // hack is removed, currentFrame should be initialized to 0 again in Anim::load + if (anim->currentFrame < 0) { + anim->currentFrame = 0; + event.type = kEvTOneshot; + event.code = kAnimEvent; + event.op = kEventFrame; + event.param = animId; + event.time = 0; + _vm->_events->queue(&event); + + return; + } + if (anim->completed < anim->cycles) { - frame = anim->currentFrame; + if (anim->currentFrame < 0) + anim->currentFrame = 0; - // WORKAROUND for a buggy animation in IHNM. Animation 0 in scene 67 (the mob of angry prisoners) should - // start from frame 0, not frame 1. Frame 0 is the background of the animation (the mob of prisoners), whereas - // the rest of the frames are their animated arms. Therefore, in order for the prisoners to appear correctly, - // frame 0 should be displayed as the first frame, but anim->currentframe is set to 1, which means that the - // prisoners will never be shown. In the original, the prisoners (first frame in the animation) are shown a - // bit after the animation is started (which is wrong again, but not that apparent), whereas in ScummVM the - // first frame is never shown. Therefore, make sure that for this animation, frame 0 is shown first - if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 4 && - _vm->_scene->currentSceneNumber() == 67 && animId == 0 && anim->completed == 1) - frame = 0; + frame = anim->currentFrame; // FIXME: if start > 0, then this works incorrectly decodeFrame(anim, anim->frameOffsets[frame], displayBuffer, _vm->getDisplayWidth() * _vm->getDisplayHeight()); @@ -488,6 +557,9 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { _vm->_frameCount += 100; // make sure the waiting thread stops waiting // Animation done playing anim->state = ANIM_PAUSE; + anim->currentFrame = 0; + anim->completed = 0; + if (anim->linkId == -1) { if (anim->flags & ANIM_FLAG_ENDSCENE) { // This animation ends the scene @@ -498,9 +570,6 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { _vm->_events->queue(&event); } return; - } else { - anim->currentFrame = 0; - anim->completed = 0; } } @@ -521,7 +590,6 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { event.op = kEventFrame; event.param = animId; event.time = frameTime; - _vm->_events->queue(&event); } @@ -592,6 +660,22 @@ void Anim::setFrameTime(uint16 animId, int time) { anim->frameTime = time; } +int Anim::getFrameTime(uint16 animId) { + AnimationData *anim; + + anim = getAnimation(animId); + + return anim->frameTime; +} + +bool Anim::isPlaying(uint16 animId) { + AnimationData *anim; + + anim = getAnimation(animId); + + return (anim->state == ANIM_PLAYING); +} + int16 Anim::getCurrentFrame(uint16 animId) { AnimationData *anim; @@ -631,11 +715,12 @@ void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_ MemoryReadStream readS(anim->resourceData + frameOffset, anim->resourceLength - frameOffset); - +// FIXME: This is thrown when the first video of the IHNM end sequence is shown (the "turn off screen" +// video), however the video is played correctly and the rest of the end sequence continues normally #if 1 #define VALIDATE_WRITE_POINTER \ if ((writePointer < buf) || (writePointer >= (buf + screenWidth * screenHeight))) { \ - error("VALIDATE_WRITE_POINTER: writePointer=%p buf=%p", (void *)writePointer, (void *)buf); \ + warning("VALIDATE_WRITE_POINTER: writePointer=%p buf=%p", (void *)writePointer, (void *)buf); \ } #else #define VALIDATE_WRITE_POINTER @@ -758,8 +843,8 @@ void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_ } while (1); } -void Anim::fillFrameOffsets(AnimationData *anim) { - uint16 currentFrame; +int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) { + uint16 currentFrame = 0; byte markByte; uint16 control; uint16 runcount; @@ -772,12 +857,18 @@ void Anim::fillFrameOffsets(AnimationData *anim) { readS._bigEndian = !_vm->isBigEndian(); // RLE has inversion BE<>LE - for (currentFrame = 0; currentFrame <= anim->maxFrame; currentFrame++) { - anim->frameOffsets[currentFrame] = readS.pos(); + while (!readS.eos()) { + if (reallyFill) { + anim->frameOffsets[currentFrame] = readS.pos(); + + if (currentFrame == anim->maxFrame) + break; + } + currentFrame++; // For some strange reason, the animation header is in little // endian format, but the actual RLE encoded frame data, - // including the frame header, is in big endian format. */ + // including the frame header, is in big endian format do { markByte = readS.readByte(); // debug(7, "_pos=%x currentFrame=%i markByte=%x", readS.pos(), currentFrame, markByte); @@ -816,8 +907,7 @@ void Anim::fillFrameOffsets(AnimationData *anim) { case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // (16) 0001 0000 // Long Uncompressed Run runcount = readS.readSint16BE(); - for (i = 0; i < runcount; i++) - readS.readByte(); + readS.seek(runcount, SEEK_CUR); continue; break; case SAGA_FRAME_NOOP: // Does nothing @@ -855,6 +945,8 @@ void Anim::fillFrameOffsets(AnimationData *anim) { } } while (markByte != SAGA_FRAME_END); } + + return currentFrame; } void Anim::animInfo() { diff --git a/engines/saga/animation.h b/engines/saga/animation.h index f8cf90425f..4306d8e00d 100644 --- a/engines/saga/animation.h +++ b/engines/saga/animation.h @@ -115,10 +115,11 @@ public: void loadCutawayList(const byte *resourcePointer, size_t resourceLength); void freeCutawayList(void); - void playCutaway(int cut, bool fade); + int playCutaway(int cut, bool fade); void endCutaway(void); void returnFromCutaway(void); void clearCutaway(void); + void showCutawayBg(int bg); void startVideo(int vid, bool fade); void endVideo(void); @@ -140,12 +141,10 @@ public: void resume(uint16 animId, int cycles); void resumeAll(); int16 getCurrentFrame(uint16 animId); - bool hasCutaway(void) { - return _cutawayActive; - } - void setCutAwayMode(int mode) { - _cutAwayMode = mode; - } + int getFrameTime(uint16 animId); + int getCycles(uint16 animId); + bool isPlaying(uint16 animId); + bool hasAnimation(uint16 animId) { if (animId >= MAX_ANIMATIONS) { if (animId < MAX_ANIMATIONS + ARRAYSIZE(_cutawayAnimations)) @@ -154,10 +153,16 @@ public: } return (_animations[animId] != NULL); } - int cutawayResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; } + + bool hasCutaway(void) { return _cutawayActive; } + void setCutAwayMode(int mode) { _cutAwayMode = mode; } + int cutawayListLength() { return _cutawayListLength; } + int cutawayBgResourceID(int cutaway) { return _cutawayList[cutaway].backgroundResourceId; } + int cutawayAnimResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; } + private: void decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength); - void fillFrameOffsets(AnimationData *anim); + int fillFrameOffsets(AnimationData *anim, bool reallyFill = true); void validateAnimationId(uint16 animId) { if (animId >= MAX_ANIMATIONS) { @@ -168,7 +173,7 @@ private: } } if (_animations[animId] == NULL) { - error("validateAnimationId: animId=%i unassigned", animId); + error("validateAnimationId: animId=%i unassigned.", animId); } } diff --git a/engines/saga/console.cpp b/engines/saga/console.cpp index 421245ab30..0a6b733e00 100644 --- a/engines/saga/console.cpp +++ b/engines/saga/console.cpp @@ -75,6 +75,14 @@ Console::Console(SagaEngine *vm) : GUI::Debugger() { // Panel commands DCmd_Register("current_panel_mode", WRAP_METHOD(Console, cmdCurrentPanelMode)); DCmd_Register("set_panel_mode", WRAP_METHOD(Console, cmdSetPanelMode)); + + // Font commands + DCmd_Register("set_font_mapping", WRAP_METHOD(Console, cmdSetFontMapping)); + + // Global flags commands + DCmd_Register("global_flags_info", WRAP_METHOD(Console, cmdGlobalFlagsInfo)); + DCmd_Register("set_global_flag", WRAP_METHOD(Console, cmdSetGlobalFlag)); + DCmd_Register("clear_global_flag", WRAP_METHOD(Console, cmdClearGlobalFlag)); } Console::~Console() { @@ -158,4 +166,92 @@ bool Console::cmdSetPanelMode(int argc, const char **argv) { return true; } +bool Console::cmdSetFontMapping(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Sets font mapping\nUsage: %s <Font mapping flag>\n", argv[0]); + DebugPrintf("Mapping flags:\n0 - default game behavior\n1 - force font mapping\n2 - ignore font mapping\n"); + } else { + _vm->_font->setFontMapping(atoi(argv[1])); + } + return true; +} + +bool Console::cmdGlobalFlagsInfo(int argc, const char **argv) { + DebugPrintf("Global flags status for IHNM:\n"); + + // Global flags in IHNM: + // 00: Unknown + // 01: Unknown + // 02: Unknown + // 03: Unknown + // 04: Unknown + // 05: Unknown + // 06: Unknown + // 07: Unknown + // 08: Unknown + // 09: Unknown + // 10: Unknown + // 11: Unknown + // 12: Unknown + // 13: Unknown + // 14: Unknown + // 15: Unknown + // 16: Used in the final chapter. If it's 0 when a character dies, the "bad" ending for that character is shown + // 17: Unknown + // 18: Unknown + // 19: Unknown, used in the final chapter + // 20: Unknown + // 21: Unknown + // 22: Unknown + // 23: Unknown + // 24: Unknown + // 25: Unknown + // 26: Unknown + // 27: Unknown + // 28: Unknown + // 29: Unknown + // 30: Unknown + // 31: Unknown + + int i = 0, k = 0, flagStatus = 0; + + for (i = 0; i < 32; i += 8) { + for (k = i; k < i + 8; k ++) { + flagStatus = _vm->_globalFlags & (1 << k) ? 1 : 0; + _vm->_console->DebugPrintf("%02d: %u |", k, flagStatus); + } + _vm->_console->DebugPrintf("\n"); + } + + return true; +} + +bool Console::cmdSetGlobalFlag(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Usage: %s <Global flag number>\nValid flag numbers are 0 - 31\n", argv[0]); + } else { + int flagNumber = atoi(argv[1]); + if (flagNumber >= 0 && flagNumber <= 31) { + _vm->_globalFlags |= (1 << flagNumber); + } else { + DebugPrintf("Valid flag numbers are 0 - 31\n"); + } + } + return true; +} + +bool Console::cmdClearGlobalFlag(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Usage: %s <Global flag number>\nValid flag numbers are 0 - 31\n", argv[0]); + } else { + int flagNumber = atoi(argv[1]); + if (flagNumber >= 0 && flagNumber <= 31) { + _vm->_globalFlags &= ~(1 << flagNumber); + } else { + DebugPrintf("Valid flag numbers are 0 - 31\n"); + } + } + return true; +} + } // End of namespace Saga diff --git a/engines/saga/console.h b/engines/saga/console.h index 3db9833f22..7936d3a959 100644 --- a/engines/saga/console.h +++ b/engines/saga/console.h @@ -55,6 +55,12 @@ private: bool cmdCurrentPanelMode(int argc, const char **argv); bool cmdSetPanelMode(int argc, const char **argv); + bool cmdSetFontMapping(int argc, const char **argv); + + bool cmdGlobalFlagsInfo(int argc, const char **argv); + bool cmdSetGlobalFlag(int argc, const char **argv); + bool cmdClearGlobalFlag(int argc, const char **argv); + private: SagaEngine *_vm; }; diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index c8918998f1..29ca0e8bbe 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/saga/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -49,7 +49,6 @@ struct SAGAGameDescription { const GameFontDescription *fontDescriptions; const GameSoundInfo *voiceInfo; const GameSoundInfo *sfxInfo; - const GameSoundInfo *musicInfo; int patchesCount; const GamePatchDescription *patchDescriptions; }; @@ -59,7 +58,18 @@ const bool SagaEngine::isMacResources() const { return (getPlatform() == Common: const GameResourceDescription *SagaEngine::getResourceDescription() { return _gameDescription->resourceDescription; } const GameSoundInfo *SagaEngine::getVoiceInfo() const { return _gameDescription->voiceInfo; } const GameSoundInfo *SagaEngine::getSfxInfo() const { return _gameDescription->sfxInfo; } -const GameSoundInfo *SagaEngine::getMusicInfo() const { return _gameDescription->musicInfo; } +const GameSoundInfo *SagaEngine::getMusicInfo() const { + static GameSoundInfo musicInfo; + musicInfo.resourceType = kSoundPCM; + musicInfo.frequency = 11025; + musicInfo.sampleBits = 16; + // The digital music in the ITE Mac demo version is not stereo + musicInfo.stereo = _gameDescription->gameType == GID_ITE_MACDEMO2 ? false : true; + musicInfo.isBigEndian = false; + musicInfo.isSigned = true; + + return &musicInfo; +} const GameFontDescription *SagaEngine::getFontDescription(int index) { assert(index < _gameDescription->fontsCount); diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index 0d57adb87d..5bb408e947 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/saga/detection_tables.h $ - * $Id:detection_tables.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -34,6 +34,7 @@ static const GameResourceDescription ITE_Resources = { RID_ITE_CONVERSE_PANEL, RID_ITE_OPTION_PANEL, 0, // Warning panel (IHNM only) + 0, // Warning panel sprites (IHNM only) RID_ITE_MAIN_SPRITES, RID_ITE_MAIN_PANEL_SPRITES, 0, // Option panel sprites (IHNM only) @@ -50,6 +51,7 @@ static const GameResourceDescription ITEDemo_Resources = { RID_ITEDEMO_CONVERSE_PANEL, RID_ITEDEMO_OPTION_PANEL, 0, // Warning panel (IHNM only) + 0, // Warning panel sprites (IHNM only) RID_ITEDEMO_MAIN_SPRITES, RID_ITEDEMO_MAIN_PANEL_SPRITES, 0, // Option panel sprites (IHNM only) @@ -59,188 +61,6 @@ static const GameResourceDescription ITEDemo_Resources = { RID_ITEDEMO_ACTOR_NAMES }; -// Inherit the Earth - DOS Demo version -static const GameFontDescription ITEDEMO_GameFonts[] = { - {0}, - {1} -}; - -// Inherit the Earth - Wyrmkeep Win32 Demo version - -static const GameFontDescription ITEWINDEMO_GameFonts[] = { - {2}, - {0} -}; - -static const GameSoundInfo ITEWINDEMO1_GameSound = { - kSoundPCM, - 22050, - 8, - false, - false, - false -}; - -static const GameSoundInfo ITEWINDEMO2_GameVoice = { - kSoundVOX, - 22050, - 16, - false, - false, - true -}; - -static const GameSoundInfo ITEWINDEMO2_GameSound = { - kSoundPCM, - 22050, - 16, - false, - false, - true -}; - -// Inherit the Earth - Wyrmkeep Mac Demo version -static const GameSoundInfo ITEMACDEMO_GameVoice = { - kSoundVOX, - 22050, - 16, - false, - false, - true -}; - -static const GameSoundInfo ITEMACDEMO_GameSound = { - kSoundPCM, - 22050, - 16, - false, - true, - true -}; - -static const GameSoundInfo ITEMACDEMO_GameMusic = { - kSoundPCM, - 11025, - 16, - false, - false, - true -}; - -static const GameSoundInfo ITEMACCD_G_GameSound = { - kSoundMacPCM, - 22050, - 8, - false, - false, - false -}; - -// Inherit the Earth - Mac Wyrmkeep version -static const GameSoundInfo ITEMACCD_GameSound = { - kSoundPCM, - 22050, - 16, - false, - true, - true -}; - -static const GameSoundInfo ITEMACCD_GameMusic = { - kSoundPCM, - 11025, - 16, - true, - false, - true -}; - -// Inherit the Earth - Diskette version -static const GameFontDescription ITEDISK_GameFonts[] = { - {2}, - {0}, - {1} -}; - -static const GameSoundInfo ITEDISK_GameSound = { - kSoundVOC, - -1, - -1, - false, - false, - true -}; - -static const GameFontDescription ITECD_GameFonts[] = { - {2}, - {0}, - {1} -}; - -static const GameSoundInfo ITECD_GameSound = { - kSoundPCM, - 22050, - 16, - false, - false, - true -}; - -// Patch files. Files not found will be ignored -static const GamePatchDescription ITEPatch_Files[] = { - { "cave.mid", GAME_RESOURCEFILE, 9, NULL}, - { "intro.mid", GAME_RESOURCEFILE, 10, NULL}, - { "fvillage.mid", GAME_RESOURCEFILE, 11, NULL}, - { "elkhall.mid", GAME_RESOURCEFILE, 12, NULL}, - { "mouse.mid", GAME_RESOURCEFILE, 13, NULL}, - { "darkclaw.mid", GAME_RESOURCEFILE, 14, NULL}, - { "birdchrp.mid", GAME_RESOURCEFILE, 15, NULL}, - { "orbtempl.mid", GAME_RESOURCEFILE, 16, NULL}, - { "spooky.mid", GAME_RESOURCEFILE, 17, NULL}, - { "catfest.mid", GAME_RESOURCEFILE, 18, NULL}, - { "elkfanfare.mid", GAME_RESOURCEFILE, 19, NULL}, - { "bcexpl.mid", GAME_RESOURCEFILE, 20, NULL}, - { "boargtnt.mid", GAME_RESOURCEFILE, 21, NULL}, - { "boarking.mid", GAME_RESOURCEFILE, 22, NULL}, - { "explorea.mid", GAME_RESOURCEFILE, 23, NULL}, - { "exploreb.mid", GAME_RESOURCEFILE, 24, NULL}, - { "explorec.mid", GAME_RESOURCEFILE, 25, NULL}, - { "sunstatm.mid", GAME_RESOURCEFILE, 26, NULL}, - { "nitstrlm.mid", GAME_RESOURCEFILE, 27, NULL}, - { "humruinm.mid", GAME_RESOURCEFILE, 28, NULL}, - { "damexplm.mid", GAME_RESOURCEFILE, 29, NULL}, - { "tychom.mid", GAME_RESOURCEFILE, 30, NULL}, - { "kitten.mid", GAME_RESOURCEFILE, 31, NULL}, - { "sweet.mid", GAME_RESOURCEFILE, 32, NULL}, - { "brutalmt.mid", GAME_RESOURCEFILE, 33, NULL}, - { "shiala.mid", GAME_RESOURCEFILE, 34, NULL}, - - { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL}, - { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL}, - { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL}, - { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, - { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL}, - { "credit3n.dlt", GAME_RESOURCEFILE, 1796, NULL}, - { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, // Macintosh - { "credit4n.dlt", GAME_RESOURCEFILE, 1797, NULL}, - { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, // Macintosh - { "p2_a.voc", GAME_VOICEFILE, 4, NULL}, - { "p2_a.iaf", GAME_VOICEFILE, 4, &ITECD_GameSound} -}; - -static const GamePatchDescription ITEMacPatch_Files[] = { - { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL}, - { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL}, - { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL}, - { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, - { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL}, - { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, - { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, - { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEMACCD_GameSound} -}; - -// IHNM section - static const GameResourceDescription IHNM_Resources = { RID_IHNM_SCENE_LUT, // Scene lookup table RN RID_IHNM_SCRIPT_LUT, // Script lookup table RN @@ -248,6 +68,7 @@ static const GameResourceDescription IHNM_Resources = { RID_IHNM_CONVERSE_PANEL, RID_IHNM_OPTION_PANEL, RID_IHNM_WARNING_PANEL, + RID_IHNM_WARNING_PANEL_SPRITES, RID_IHNM_MAIN_SPRITES, RID_IHNM_MAIN_PANEL_SPRITES, RID_IHNM_OPTION_PANEL_SPRITES, @@ -264,6 +85,7 @@ static const GameResourceDescription IHNMDEMO_Resources = { RID_IHNMDEMO_CONVERSE_PANEL, RID_IHNMDEMO_OPTION_PANEL, RID_IHNMDEMO_WARNING_PANEL, + RID_IHNMDEMO_WARNING_PANEL_SPRITES, RID_IHNMDEMO_MAIN_SPRITES, RID_IHNMDEMO_MAIN_PANEL_SPRITES, RID_IHNMDEMO_OPTION_PANEL_SPRITES, @@ -273,29 +95,73 @@ static const GameResourceDescription IHNMDEMO_Resources = { 0 // Actors strings (ITE only) }; -static const GameFontDescription IHNMDEMO_GameFonts[] = { - {2}, - {3}, - {4} -}; +static const GameFontDescription ITEDEMO_GameFonts[] = { {0}, {1} }; +static const GameFontDescription ITEWINDEMO_GameFonts[] = { {2}, {0} }; +static const GameFontDescription ITE_GameFonts[] = { {2}, {0}, {1} }; +static const GameFontDescription IHNMDEMO_GameFonts[] = { {2}, {3}, {4} }; +// Font 6 is kIHNMFont8, font 8 is kIHNMMainFont +static const GameFontDescription IHNMCD_GameFonts[] = { {2}, {3}, {4}, {5}, {6}, {7}, {8} }; + +// frequency, sampleBits, stereo, isBigEndian, isSigned +static const GameSoundInfo ITEPC_GameSound = { kSoundPCM, 22050, 16, false, false, true }; +static const GameSoundInfo ITEMAC_GameSound = { kSoundPCM, 22050, 16, false, true, true }; +static const GameSoundInfo ITEWINDEMO1_GameSound = { kSoundPCM, 22050, 8, false, false, false }; +static const GameSoundInfo ITEMACCD_G_GameSound = { kSoundMacPCM, 22050, 8, false, false, false }; +static const GameSoundInfo ITEDISK_GameSound = { kSoundVOC, -1, -1, false, false, true }; +static const GameSoundInfo ITEDEMO_GameVoice = { kSoundVOX, 22050, 16, false, false, true }; +static const GameSoundInfo IHNM_GameSound = { kSoundWAV, -1, -1, false, false, true }; -static const GameFontDescription IHNMCD_GameFonts[] = { - {2}, - {3}, - {4}, - {5}, - {6}, // kIHNMFont8 - {7}, - {8} // kIHNMMainFont +// Patch files. Files not found will be ignored +static const GamePatchDescription ITEPatch_Files[] = { + { "cave.mid", GAME_RESOURCEFILE, 9, NULL}, + { "intro.mid", GAME_RESOURCEFILE, 10, NULL}, + { "fvillage.mid", GAME_RESOURCEFILE, 11, NULL}, + { "elkhall.mid", GAME_RESOURCEFILE, 12, NULL}, + { "mouse.mid", GAME_RESOURCEFILE, 13, NULL}, + { "darkclaw.mid", GAME_RESOURCEFILE, 14, NULL}, + { "birdchrp.mid", GAME_RESOURCEFILE, 15, NULL}, + { "orbtempl.mid", GAME_RESOURCEFILE, 16, NULL}, + { "spooky.mid", GAME_RESOURCEFILE, 17, NULL}, + { "catfest.mid", GAME_RESOURCEFILE, 18, NULL}, + { "elkfanfare.mid", GAME_RESOURCEFILE, 19, NULL}, + { "bcexpl.mid", GAME_RESOURCEFILE, 20, NULL}, + { "boargtnt.mid", GAME_RESOURCEFILE, 21, NULL}, + { "boarking.mid", GAME_RESOURCEFILE, 22, NULL}, + { "explorea.mid", GAME_RESOURCEFILE, 23, NULL}, + { "exploreb.mid", GAME_RESOURCEFILE, 24, NULL}, + { "explorec.mid", GAME_RESOURCEFILE, 25, NULL}, + { "sunstatm.mid", GAME_RESOURCEFILE, 26, NULL}, + { "nitstrlm.mid", GAME_RESOURCEFILE, 27, NULL}, + { "humruinm.mid", GAME_RESOURCEFILE, 28, NULL}, + { "damexplm.mid", GAME_RESOURCEFILE, 29, NULL}, + { "tychom.mid", GAME_RESOURCEFILE, 30, NULL}, + { "kitten.mid", GAME_RESOURCEFILE, 31, NULL}, + { "sweet.mid", GAME_RESOURCEFILE, 32, NULL}, + { "brutalmt.mid", GAME_RESOURCEFILE, 33, NULL}, + { "shiala.mid", GAME_RESOURCEFILE, 34, NULL}, + + { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL}, + { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL}, + { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL}, + { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, + { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL}, + { "credit3n.dlt", GAME_RESOURCEFILE, 1796, NULL}, // PC + { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, // Macintosh + { "credit4n.dlt", GAME_RESOURCEFILE, 1797, NULL}, // PC + { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, // Macintosh + { "p2_a.voc", GAME_VOICEFILE, 4, NULL}, + { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEPC_GameSound} }; -static const GameSoundInfo IHNM_GameSound = { - kSoundWAV, - -1, - -1, - false, - false, - true +static const GamePatchDescription ITEMacPatch_Files[] = { + { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL}, + { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL}, + { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL}, + { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL}, + { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL}, + { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, + { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, + { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEMAC_GameSound} }; static const SAGAGameDescription gameDescriptions[] = { @@ -333,7 +199,6 @@ static const SAGAGameDescription gameDescriptions[] = { ITEDEMO_GameFonts, &ITEDISK_GameSound, &ITEDISK_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music 0, NULL, }, @@ -363,18 +228,15 @@ static const SAGAGameDescription gameDescriptions[] = { &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, - &ITEMACDEMO_GameVoice, - &ITEMACDEMO_GameSound, - &ITEMACDEMO_GameMusic, + &ITEDEMO_GameVoice, + &ITEMAC_GameSound, ARRAYSIZE(ITEMacPatch_Files), ITEMacPatch_Files, }, - // Note: This version is NOT supported yet - // Exiting the faire leads to a crash - // Inherit the earth - MAC Demo version 1 + // Non-interactive demo { { "ite", @@ -393,14 +255,13 @@ static const SAGAGameDescription gameDescriptions[] = { }, GType_ITE, GID_ITE_MACDEMO1, - GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX, + GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX | GF_NON_INTERACTIVE, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, - &ITEMACDEMO_GameVoice, - &ITEMACDEMO_GameSound, - &ITEMACCD_GameMusic, + &ITEDEMO_GameVoice, + &ITEMAC_GameSound, ARRAYSIZE(ITEMacPatch_Files), ITEMacPatch_Files, }, @@ -431,18 +292,15 @@ static const SAGAGameDescription gameDescriptions[] = { &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, - &ITEWINDEMO2_GameVoice, - &ITEWINDEMO2_GameSound, - &ITEMACCD_GameMusic, + &ITEDEMO_GameVoice, + &ITEPC_GameSound, ARRAYSIZE(ITEPatch_Files), ITEPatch_Files, }, - // Note: This version is NOT supported yet - // Exiting the faire leads to a crash - // Inherit the earth - Win32 Demo version 1 + // Non-interactive demo { { "ite", @@ -460,14 +318,13 @@ static const SAGAGameDescription gameDescriptions[] = { }, GType_ITE, GID_ITE_WINDEMO1, - GF_WYRMKEEP | GF_CD_FX, + GF_WYRMKEEP | GF_CD_FX | GF_NON_INTERACTIVE, ITE_DEFAULT_SCENE, &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, &ITEWINDEMO1_GameSound, &ITEWINDEMO1_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music ARRAYSIZE(ITEPatch_Files), ITEPatch_Files, }, @@ -504,7 +361,6 @@ static const SAGAGameDescription gameDescriptions[] = { ITEWINDEMO_GameFonts, &ITEMACCD_G_GameSound, &ITEMACCD_G_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music 0, NULL, }, @@ -533,9 +389,8 @@ static const SAGAGameDescription gameDescriptions[] = { &ITE_Resources, ARRAYSIZE(ITEWINDEMO_GameFonts), ITEWINDEMO_GameFonts, - &ITEMACCD_GameSound, - &ITEMACCD_GameSound, - &ITEMACCD_GameMusic, + &ITEMAC_GameSound, + &ITEMAC_GameSound, ARRAYSIZE(ITEMacPatch_Files), ITEMacPatch_Files, }, @@ -570,11 +425,10 @@ static const SAGAGameDescription gameDescriptions[] = { GF_WYRMKEEP | GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITEMACCD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, + &ITEMAC_GameSound, + &ITEPC_GameSound, 0, NULL, }, @@ -601,11 +455,10 @@ static const SAGAGameDescription gameDescriptions[] = { GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, + &ITEPC_GameSound, + &ITEPC_GameSound, ARRAYSIZE(ITEPatch_Files), ITEPatch_Files, }, @@ -631,11 +484,10 @@ static const SAGAGameDescription gameDescriptions[] = { GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, + &ITEPC_GameSound, + &ITEPC_GameSound, ARRAYSIZE(ITEPatch_Files), ITEPatch_Files, }, @@ -662,11 +514,10 @@ static const SAGAGameDescription gameDescriptions[] = { GF_CD_FX, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITECD_GameFonts), - ITECD_GameFonts, - &ITECD_GameSound, - &ITECD_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, + &ITEPC_GameSound, + &ITEPC_GameSound, 0, NULL, }, @@ -694,11 +545,10 @@ static const SAGAGameDescription gameDescriptions[] = { 0, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, &ITEDISK_GameSound, &ITEDISK_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music 0, NULL, }, @@ -723,11 +573,10 @@ static const SAGAGameDescription gameDescriptions[] = { 0, ITE_DEFAULT_SCENE, &ITE_Resources, - ARRAYSIZE(ITEDISK_GameFonts), - ITEDISK_GameFonts, + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, &ITEDISK_GameSound, &ITEDISK_GameSound, - &ITEMACCD_GameMusic, // note: this version did not originally have digital music ARRAYSIZE(ITEPatch_Files), ITEPatch_Files, }, @@ -766,7 +615,6 @@ static const SAGAGameDescription gameDescriptions[] = { IHNMDEMO_GameFonts, &IHNM_GameSound, &IHNM_GameSound, - NULL, 0, NULL, }, @@ -805,7 +653,6 @@ static const SAGAGameDescription gameDescriptions[] = { IHNMCD_GameFonts, &IHNM_GameSound, &IHNM_GameSound, - NULL, 0, NULL, }, @@ -845,7 +692,6 @@ static const SAGAGameDescription gameDescriptions[] = { IHNMCD_GameFonts, &IHNM_GameSound, &IHNM_GameSound, - NULL, 0, NULL, }, @@ -884,7 +730,6 @@ static const SAGAGameDescription gameDescriptions[] = { IHNMCD_GameFonts, &IHNM_GameSound, &IHNM_GameSound, - NULL, 0, NULL, }, @@ -923,12 +768,12 @@ static const SAGAGameDescription gameDescriptions[] = { IHNMCD_GameFonts, &IHNM_GameSound, &IHNM_GameSound, - NULL, 0, NULL, }, // I Have No Mouth And I Must Scream - Fr CD version + // Censored CD version (without Nimdok) { { "ihnm", @@ -961,11 +806,10 @@ static const SAGAGameDescription gameDescriptions[] = { IHNMCD_GameFonts, &IHNM_GameSound, &IHNM_GameSound, - NULL, 0, NULL, }, - { AD_TABLE_END_MARKER, 0, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL } + { AD_TABLE_END_MARKER, 0, 0, 0, 0, NULL, 0, NULL, NULL, NULL, 0, NULL } }; } // End of namespace Saga diff --git a/engines/saga/displayinfo.h b/engines/saga/displayinfo.h index 74bbcc4343..d7d51a1e9f 100644 --- a/engines/saga/displayinfo.h +++ b/engines/saga/displayinfo.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/saga/displayinfo.h $ - * $Id:displayinfo.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -280,7 +280,7 @@ static const GameDisplayInfo ITE_DisplayInfo = { }; -//TODO: ihnm +// IHNM #define IHNM_CONVERSE_MAX_TEXT_WIDTH (485 - 8) #define IHNM_CONVERSE_TEXT_HEIGHT 10 #define IHNM_CONVERSE_TEXT_LINES 11 @@ -330,20 +330,20 @@ static PanelButton IHNM_OptionPanelButtons[] = { {kPanelButtonOptionText,60,61, 0,0, kTextMusic,'-',0, 0,0,0}, // text: music {kPanelButtonOptionText,60,86, 0,0, kTextSound,'-',0, 0,0,0}, // text: noise {kPanelButtonOptionText,56,111, 0,0, kTextVoices,'-',0, 0,0,0}, // text: voices - {kPanelButtonOption, 153,29, 79,23, kTextReadingSpeed,'r',0, 0,0,0}, //read speed - {kPanelButtonOption, 153,54, 79,23, kTextMusic,'m',0, 0,0,0}, //music - {kPanelButtonOption, 153,79, 79,23, kTextSound,'n',0, 0,0,0}, //sound-noise - {kPanelButtonOption, 153,104,79,23, kTextVoices,'v',0, 0,0,0}, //voices - {kPanelButtonOption, 19,149, 200,25, kTextQuitGame,'q',0, 0,0,0}, //quit - {kPanelButtonOption, 19,177, 200,25, kTextContinuePlaying,'c',0, 0,0,0}, //continue + {kPanelButtonOption, 154,30, 79,23, kTextReadingSpeed,'r',0, 0,0,0}, //read speed + {kPanelButtonOption, 154,55, 79,23, kTextMusic,'m',0, 0,0,0}, //music + {kPanelButtonOption, 154,80, 79,23, kTextSound,'n',0, 0,0,0}, //sound-noise + {kPanelButtonOption, 154,105,79,23, kTextVoices,'v',0, 0,0,0}, //voices + {kPanelButtonOption, 20,150, 200,25, kTextQuitGame,'q',0, 0,0,0}, //quit + {kPanelButtonOption, 20,178, 200,25, kTextContinuePlaying,'c',0, 0,0,0}, //continue {kPanelButtonOptionSaveFiles, 244,18, 170,138, 0,'-',0, 0,0,0}, //savefiles - {kPanelButtonOption, 242,162, 79,23, kTextLoad,'l',0, 0,0,0}, //load - {kPanelButtonOption, 333,162, 79,23, kTextSave,'s',0, 0,0,0}, //save + {kPanelButtonOption, 243,163, 79,23, kTextLoad,'l',0, 0,0,0}, //load + {kPanelButtonOption, 334,163, 79,23, kTextSave,'s',0, 0,0,0}, //save }; static PanelButton IHNM_QuitPanelButtons[] = { - {kPanelButtonQuit, 25,79, 80,25, kTextQuit,'q',0, 0,0,0}, - {kPanelButtonQuit, 155,79, 80,25, kTextCancel,'c',0, 0,0,0}, + {kPanelButtonQuit, 26,80, 80,25, kTextQuit,'q',0, 0,0,0}, + {kPanelButtonQuit, 156,80, 80,25, kTextCancel,'c',0, 0,0,0}, {kPanelButtonQuitText, 75,30, 0,0, kTextQuitTheGameQuestion,'-',0, 0,0,0}, }; @@ -354,11 +354,10 @@ static PanelButton IHNM_LoadPanelButtons[] = { }; static PanelButton IHNM_SavePanelButtons[] = { - // TODO {kPanelButtonSave, 25,79, 80,25, kTextSave,'s',0, 0,0,0}, {kPanelButtonSave, 155,79, 80,25, kTextCancel,'c',0, 0,0,0}, - {kPanelButtonSaveEdit, 26,57, 209,17, 0,'-',0, 0,0,0}, - {kPanelButtonSaveText, 75,30, 0,0, kTextEnterSaveGameName,'-',0, 0,0,0}, + {kPanelButtonSaveEdit, 22,56, 216,17, 0,'-',0, 0,0,0}, + {kPanelButtonSaveText, 74,30, 0,0, kTextEnterSaveGameName,'-',0, 0,0,0}, }; diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp index 80e6b58595..50297b7ef0 100644 --- a/engines/saga/events.cpp +++ b/engines/saga/events.cpp @@ -154,10 +154,12 @@ int Events::handleContinuous(Event *event) { case kEventBlackToPal: _vm->_gfx->blackToPal((PalEntry *)event->data, event_pc); break; - case kEventPalToBlack: _vm->_gfx->palToBlack((PalEntry *)event->data, event_pc); break; + case kEventPalFade: + _vm->_gfx->palFade((PalEntry *)event->data, event->param, event->param2, event->param3, event->param4, event_pc); + break; default: break; } @@ -237,10 +239,12 @@ int Events::handleImmediate(Event *event) { case kEventBlackToPal: _vm->_gfx->blackToPal((PalEntry *)event->data, event_pc); break; - case kEventPalToBlack: _vm->_gfx->palToBlack((PalEntry *)event->data, event_pc); break; + case kEventPalFade: + _vm->_gfx->palFade((PalEntry *)event->data, event->param, event->param2, event->param3, event->param4, event_pc); + break; default: break; } @@ -251,6 +255,7 @@ int Events::handleImmediate(Event *event) { case kSceneEvent: case kAnimEvent: case kCutawayEvent: + case kActorEvent: handleOneShot(event); event_done = true; break; @@ -338,11 +343,22 @@ int Events::handleOneShot(Event *event) { if (event->param == kEvPSetPalette) { PalEntry *palPointer; + + if (_vm->getGameType() == GType_IHNM) { + if (_vm->_spiritualBarometer > 255) + _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff); + else + _vm->_gfx->setPaletteColor(kIHNMColorPortrait, + _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.red / 256, + _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.green / 256, + _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.blue / 256); + } + _vm->_scene->getBGPal(palPointer); _vm->_gfx->setPalette(palPointer); } } - _vm->_actor->showActors(true); + _vm->_render->clearFlag(RF_DISABLE_ACTORS); } break; case kPsychicProfileBgEvent: @@ -374,7 +390,7 @@ int Events::handleOneShot(Event *event) { free(buf); free(resourceData); - // Draw the scene. It won't be drawn by Render::drawScene(), as the RF_PLACARD is set + // Draw the scene. It won't be drawn by Render::drawScene(), as a placard is up _vm->_scene->draw(); } break; @@ -455,6 +471,9 @@ int Events::handleOneShot(Event *event) { case kEventSetFadeMode: _vm->_interface->setFadeMode(event->param); break; + case kEventRestoreMode: + _vm->_interface->restoreMode(); + break; default: break; } @@ -530,6 +549,17 @@ int Events::handleOneShot(Event *event) { case kEventClear: _vm->_anim->clearCutaway(); break; + case kEventShowCutawayBg: + _vm->_anim->showCutawayBg(event->param); + break; + default: + break; + } + case kActorEvent: + switch (event->op) { + case kEventMove: + // TODO (check Actor::direct) + break; default: break; } diff --git a/engines/saga/events.h b/engines/saga/events.h index 2486525751..de4d296eab 100644 --- a/engines/saga/events.h +++ b/engines/saga/events.h @@ -69,21 +69,20 @@ enum EventOps { // BG events kEventDisplay = 1, // ANIM events - // kEventPlay = 1, // reused - // kEventStop = 2, // reused + kEventPlay = 1, // used in music and sound events too + kEventStop = 2, // used in music and sound events too kEventFrame = 3, - kEventSetFlag = 4, - kEventClearFlag = 5, + kEventSetFlag = 4, // used in graphics events too + kEventClearFlag = 5, // used in graphics events too kEventResumeAll = 6, - // MUISC & SOUND events - kEventPlay = 1, - kEventStop = 2, + // MUSIC and SOUND events + // Reused: kEventPlay, kEventStop // SCENE events kEventDraw = 1, kEventEnd = 2, // TEXT events - kEventHide = 2, kEventRemove = 3, + // Reused: kEventHide // PALANIM events kEventCycleStart = 1, kEventCycleStep = 2, @@ -93,6 +92,7 @@ enum EventOps { kEventSetStatus = 3, kEventClearStatus = 4, kEventSetFadeMode = 5, + kEventRestoreMode = 6, // ACTOR events kEventMove = 1, // SCRIPT events @@ -101,23 +101,24 @@ enum EventOps { kEventThreadWake = 3, // CURSOR events kEventShow = 1, - // kEventHide = 2, // reused + kEventHide = 2, // used in text events too kEventSetNormalCursor = 3, kEventSetBusyCursor = 4, // GRAPHICS events kEventFillRect = 1, - // kEventSetFlag = 4, // reused - // kEventClearFlag = 5, // reused - + // Reused: kEventSetFlag, kEventClearFlag // CONTINUOUS events + // // PALETTE events kEventPalToBlack = 1, kEventBlackToPal = 2, + kEventPalFade = 3, // TRANSITION events kEventDissolve = 1, kEventDissolveBGMask = 2, // CUTAWAY events - kEventClear = 1 + kEventClear = 1, + kEventShowCutawayBg = 2 }; enum EventParams { diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp index 71cd6b0eef..06e51a78e4 100644 --- a/engines/saga/font.cpp +++ b/engines/saga/font.cpp @@ -49,6 +49,7 @@ Font::Font(SagaEngine *vm) : _vm(vm), _initialized(false) { } _initialized = true; + _fontMapping = 0; } Font::~Font(void) { @@ -325,14 +326,29 @@ void Font::outFont(const FontStyle &drawFont, Surface *ds, const char *text, siz c_code = *textPointer & 0xFFU; // Translate character - if (!(flags & kFontDontmap)) + if (_fontMapping == 0) { // Check font mapping debug flag + // Default game behavior + + // It seems that this font mapping causes problems with non-english + // versions of IHNM, so it has been changed to apply for ITE only. + // It doesn't make any difference for the English version of IHNM. + // Fixes bug #1796045: "IHNM: Spanish font wrong". + if (!(flags & kFontDontmap) && _vm->getGameType() == GType_ITE) + c_code = _charMap[c_code]; + } else if (_fontMapping == 1) { + // Force font mapping c_code = _charMap[c_code]; + } else { + // In all other cases, ignore font mapping + } assert(c_code < FONT_CHARCOUNT); // Check if character is defined if ((drawFont.fontCharEntry[c_code].index == 0) && (c_code != FONT_FIRSTCHAR)) { #if FONT_SHOWUNDEFINED - if (c_code == FONT_CH_SPACE || c_code == 9) { + // A tab character appears in the IHNM demo instructions screen, so filter + // it out here + if (c_code == FONT_CH_SPACE || c_code == FONT_CH_TAB) { textPoint.x += drawFont.fontCharEntry[c_code].tracking; continue; } @@ -632,8 +648,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) { // The demo version of IHNM has 3 font types (like ITE), not 6 (like the full version of IHNM) if (_vm->getGameType() == GType_ITE || _vm->getGameId() == GID_IHNM_DEMO) { - switch (font) - { + switch (font) { case (kKnownFontSmall): fontId = kSmallFont; break; @@ -655,8 +670,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) { break; } } else if (_vm->getGameType() == GType_IHNM && _vm->getGameId() != GID_IHNM_DEMO) { - switch (font) - { + switch (font) { case (kKnownFontSmall): fontId = kSmallFont; break; diff --git a/engines/saga/font.h b/engines/saga/font.h index 5823513e0f..16fdfc22b9 100644 --- a/engines/saga/font.h +++ b/engines/saga/font.h @@ -39,6 +39,7 @@ namespace Saga { // have a valid offset of '0' #define FONT_FIRSTCHAR 33 +#define FONT_CH_TAB 9 #define FONT_CH_SPACE 32 #define FONT_CH_QMARK 63 @@ -140,8 +141,11 @@ class Font { } void textDrawRect(KnownFont font, Surface *ds, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags) { textDrawRect(knownFont2FontIdx(font), ds, text, rect, color, effectColor, flags); + } + void setFontMapping(int mapping) { + _fontMapping = mapping; } - + private: enum FontId { kSmallFont, @@ -196,6 +200,7 @@ class Font { SagaEngine *_vm; bool _initialized; + int _fontMapping; int _loadedFonts; FontData **_fonts; diff --git a/engines/saga/gfx.cpp b/engines/saga/gfx.cpp index 56ffe04c96..8509da62ed 100644 --- a/engines/saga/gfx.cpp +++ b/engines/saga/gfx.cpp @@ -356,8 +356,6 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) { // Exponential fade fpercent = percent * percent; - fpercent = 1.0 - fpercent; - // Use the correct percentage change per frame for each palette entry for (i = 0, ppal = _currentPal; i < PAL_ENTRIES; i++, ppal += 4) { if (i < from || i >= from + numcolors) @@ -365,7 +363,7 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) { else palE = &srcPal[i]; - new_entry = (int)(palE->red - palE->red * fpercent); + new_entry = (int)(palE->red * fpercent); if (new_entry < 0) { ppal[0] = 0; @@ -373,7 +371,7 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) { ppal[0] = (byte)new_entry; } - new_entry = (int)(palE->green - palE->green * fpercent); + new_entry = (int)(palE->green * fpercent); if (new_entry < 0) { ppal[1] = 0; @@ -381,7 +379,7 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) { ppal[1] = (byte) new_entry; } - new_entry = (int)(palE->blue - palE->blue * fpercent); + new_entry = (int)(palE->blue * fpercent); if (new_entry < 0) { ppal[2] = 0; @@ -402,7 +400,79 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) { _system->setPalette(_currentPal, 0, PAL_ENTRIES); } +// Used in IHNM only +void Gfx::palFade(PalEntry *srcPal, int16 from, int16 to, int16 start, int16 numColors, double percent) { + int i; + int new_entry; + byte *ppal; + PalEntry *palE; + double fpercent; + + from = from > 256 ? 256 : from; + from = from < 0 ? 0 : from; + to = to > 256 ? 256 : to; + to = to < 0 ? 0 : to; + + if (from == 0 || to == 0) { + // This case works like palToBlack or blackToPal, so no changes are needed + } else { + double x = from > to ? from / to : to / from; + percent /= x; + if (from < to) + percent += 1 / x; + } + + // Exponential fade + percent = percent > 1.0 ? 1.0 : percent; + fpercent = percent * percent; + + if (from > to) + fpercent = 1.0 - fpercent; + + // Use the correct percentage change per frame for each palette entry + for (i = 0, ppal = _currentPal; i < PAL_ENTRIES; i++, ppal += 4) { + if (i < start || i >= start + numColors) + palE = &_globalPalette[i]; + else + palE = &srcPal[i]; + + new_entry = (int)(palE->red * fpercent); + + if (new_entry < 0) { + ppal[0] = 0; + } else { + ppal[0] = (byte) new_entry; + } + + new_entry = (int)(palE->green * fpercent); + + if (new_entry < 0) { + ppal[1] = 0; + } else { + ppal[1] = (byte) new_entry; + } + + new_entry = (int)(palE->blue * fpercent); + + if (new_entry < 0) { + ppal[2] = 0; + } else { + ppal[2] = (byte) new_entry; + } + ppal[3] = 0; + } + + // Color 0 should always be black in IHNM + memset(&_currentPal[0 * 4], 0, 4); + + _system->setPalette(_currentPal, 0, PAL_ENTRIES); +} + void Gfx::showCursor(bool state) { + // Don't show the mouse cursor in the non-interactive part of the IHNM demo + if (_vm->_scene->isNonInteractiveIHNMDemoPart()) + state = false; + CursorMan.showMouse(state); } diff --git a/engines/saga/gfx.h b/engines/saga/gfx.h index 0fa7aab742..ea1370c79d 100644 --- a/engines/saga/gfx.h +++ b/engines/saga/gfx.h @@ -150,6 +150,7 @@ public: void restorePalette() { setPalette(_savedPalette, true); } void palToBlack(PalEntry *src_pal, double percent); void blackToPal(PalEntry *src_pal, double percent); + void palFade(PalEntry *srcPal, int16 from, int16 to, int16 start, int16 numColors, double percent); void showCursor(bool state); void setCursor(CursorType cursorType = kCursorNormal); diff --git a/engines/saga/ihnm_introproc.cpp b/engines/saga/ihnm_introproc.cpp index 631da37e82..fcf69d1bd1 100644 --- a/engines/saga/ihnm_introproc.cpp +++ b/engines/saga/ihnm_introproc.cpp @@ -31,154 +31,52 @@ #include "saga/animation.h" #include "saga/events.h" #include "saga/interface.h" +#include "saga/render.h" #include "saga/rscfile.h" #include "saga/sndres.h" #include "saga/music.h" #include "saga/scene.h" -namespace Saga { +#include "common/events.h" -SceneResourceData IHNM_IntroMovie1RL[] = { - {30, 2, 0, 0, false}, - {31, 14, 0, 0, false} -}; - -SceneDescription IHNM_IntroMovie1Desc = { - 0, 0, 0, 0, 0, 0, 0, 0, - IHNM_IntroMovie1RL, - ARRAYSIZE(IHNM_IntroMovie1RL) -}; - -SceneResourceData IHNM_IntroMovie2RL[] = { - {32, 2, 0, 0, false}, - {33, 14, 0, 0, false} -}; - -SceneDescription IHNM_IntroMovie2Desc = { - 0, 0, 0, 0, 0, 0, 0, 0, - IHNM_IntroMovie2RL, - ARRAYSIZE(IHNM_IntroMovie2RL) -}; - -SceneResourceData IHNM_IntroMovie3RL[] = { - {34, 2, 0, 0, false}, - {35, 14, 0, 0, false} -}; - -SceneDescription IHNM_IntroMovie3Desc = { - 0, 0, 0, 0, 0, 0, 0, 0, - IHNM_IntroMovie3RL, - ARRAYSIZE(IHNM_IntroMovie3RL) -}; - -SceneResourceData IHNM_IntroMovie4RL[] = { - {1227, 2, 0, 0, false}, - {1226, 14, 0, 0, false} -}; - -SceneDescription IHNM_IntroMovie4Desc = { - 0, 0, 0, 0, 0, 0, 0, 0, - IHNM_IntroMovie4RL, - ARRAYSIZE(IHNM_IntroMovie4RL) -}; - -// Demo -SceneResourceData IHNMDEMO_IntroMovie1RL[] = { - {19, 2, 0, 0, false} // this scene doesn't have an animation -}; - -SceneDescription IHNMDEMO_IntroMovie1Desc = { - 0, 0, 0, 0, 0, 0, 0, 0, - IHNMDEMO_IntroMovie1RL, - ARRAYSIZE(IHNMDEMO_IntroMovie1RL) -}; - -SceneResourceData IHNMDEMO_IntroMovie2RL[] = { - {22, 2, 0, 0, false}, - {23, 14, 0, 0, false} -}; - -SceneDescription IHNMDEMO_IntroMovie2Desc = { - 0, 0, 0, 0, 0, 0, 0, 0, - IHNMDEMO_IntroMovie2RL, - ARRAYSIZE(IHNMDEMO_IntroMovie2RL) -}; - -LoadSceneParams IHNM_IntroList[] = { - {0, kLoadByDescription, &IHNM_IntroMovie1Desc, Scene::SC_IHNMIntroMovieProc1, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, - {0, kLoadByDescription, &IHNM_IntroMovie2Desc, Scene::SC_IHNMIntroMovieProc2, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, - {0, kLoadByDescription, &IHNM_IntroMovie3Desc, Scene::SC_IHNMIntroMovieProc3, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, -}; - -LoadSceneParams IHNMDEMO_IntroList[] = { - {0, kLoadByDescription, &IHNMDEMO_IntroMovie1Desc, Scene::SC_IHNMIntroMovieProc1, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, - {0, kLoadByDescription, &IHNMDEMO_IntroMovie2Desc, Scene::SC_IHNMIntroMovieProc3, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, -}; +namespace Saga { // IHNM cutaway intro resource IDs #define RID_IHNM_INTRO_CUTAWAYS 39 #define RID_IHNMDEMO_INTRO_CUTAWAYS 25 int Scene::IHNMStartProc() { - size_t n_introscenes; - size_t i; - LoadSceneParams firstScene; - /* - // Test code - uses loadCutawayList to load the intro cutaways, like the original + IHNMLoadCutaways(); - ResourceContext *resourceContext; - //ResourceContext *soundContext; - byte *resourcePointer; - size_t resourceLength; - - resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE); - if (resourceContext == NULL) { - error("Scene::IHNMStartProc() resource context not found"); - } - - if (_vm->getGameId() != GID_IHNM_DEMO) - _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourcePointer, resourceLength); - else - _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourcePointer, resourceLength); - - if (resourceLength == 0) { - error("Scene::IHNMStartProc() Can't load cutaway list"); - } - - // Load the cutaways for the title screens - _vm->_anim->loadCutawayList(resourcePointer, resourceLength); - - // Note that the resource ID needed is the returned ID minus one - printf("%i\n", _vm->_anim->cutawayResourceID(0)); - printf("%i\n", _vm->_anim->cutawayResourceID(1)); - printf("%i\n", _vm->_anim->cutawayResourceID(2)); - */ - - // The original used the "play video" mechanism for the first part of - // the intro. We just use that panel mode. - - _vm->_anim->setCutAwayMode(kPanelVideo); - _vm->_interface->setMode(kPanelVideo); - - if (_vm->getGameId() != GID_IHNM_DEMO) - n_introscenes = ARRAYSIZE(IHNM_IntroList); - else - n_introscenes = ARRAYSIZE(IHNMDEMO_IntroList); - - // Queue the company and title videos if (_vm->getGameId() != GID_IHNM_DEMO) { - for (i = 0; i < n_introscenes; i++) { - _vm->_scene->queueScene(&IHNM_IntroList[i]); + int logoLength = -168; + + if (_vm->getLanguage() == Common::DE_DEU || _vm->getLanguage() == Common::ES_ESP) + logoLength = -128; + + // Play Cyberdreams logo for 168 frames + if (!playTitle(0, logoLength, true)) { + // Play Dreamers Guild logo for 10 seconds + if (!playLoopingTitle(1, 10)) { + // Play the title music + _vm->_music->play(1, MUSIC_NORMAL); + // Play title screen + playTitle(2, 17); + } } } else { - for (i = 0; i < n_introscenes; i++) { - _vm->_scene->queueScene(&IHNMDEMO_IntroList[i]); - } + _vm->_music->play(1, MUSIC_NORMAL); + playTitle(0, 10); + playTitle(2, 12); } + _vm->_music->setVolume(0, 1000); + _vm->_anim->freeCutawayList(); + + // Queue first scene firstScene.loadFlag = kLoadBySceneNumber; firstScene.sceneDescriptor = -1; firstScene.sceneDescription = NULL; @@ -193,241 +91,189 @@ int Scene::IHNMStartProc() { return SUCCESS; } -int Scene::SC_IHNMIntroMovieProc1(int param, void *refCon) { - return ((Scene *)refCon)->IHNMIntroMovieProc1(param); -} +int Scene::IHNMCreditsProc() { + IHNMLoadCutaways(); -int Scene::IHNMIntroMovieProc1(int param) { - Event event; - Event *q_event; - - switch (param) { - case SCENE_BEGIN: - // Background for intro scene is the first frame of the - // intro animation; display it and set the palette - event.type = kEvTOneshot; - event.code = kBgEvent; - event.op = kEventDisplay; - event.param = kEvPSetPalette; - event.time = 0; - - q_event = _vm->_events->queue(&event); - - if (_vm->getGameId() != GID_IHNM_DEMO) { - _vm->_anim->setFrameTime(0, IHNM_INTRO_FRAMETIME); - _vm->_anim->setFlag(0, ANIM_FLAG_ENDSCENE); - - event.type = kEvTOneshot; - event.code = kAnimEvent; - event.op = kEventPlay; - event.param = 0; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - } else { - // Start playing the intro music for the demo version - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = 1; - event.param2 = MUSIC_NORMAL; - event.op = kEventPlay; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - - // The IHNM demo doesn't have an animation at the - // Cyberdreans logo screen - - // Queue end of scene after a while - event.type = kEvTOneshot; - event.code = kSceneEvent; - event.op = kEventEnd; - event.time = 8000; - - q_event = _vm->_events->chain(q_event, &event); - } + _vm->_music->play(0, MUSIC_NORMAL); - break; - default: - break; + if (_vm->getGameId() != GID_IHNM_DEMO) { + // Display the credits for 400 frames + playTitle(4, -400, true); + } else { + // Display sales info for 60 seconds + playTitle(3, 60, true); } - return 0; -} + _vm->_music->setVolume(0, 1000); + _vm->_anim->freeCutawayList(); -int Scene::SC_IHNMIntroMovieProc2(int param, void *refCon) { - return ((Scene *)refCon)->IHNMIntroMovieProc2(param); + return SUCCESS; } -int Scene::IHNMIntroMovieProc2(int param) { - Event event; - Event *q_event; - PalEntry *pal; - - static PalEntry current_pal[PAL_ENTRIES]; - - switch (param) { - case SCENE_BEGIN: - // Fade to black out of the intro CyberDreams logo anim - _vm->_gfx->getCurrentPal(current_pal); - - event.type = kEvTContinuous; - event.code = kPalEvent; - event.op = kEventPalToBlack; - event.time = 0; - event.duration = IHNM_PALFADE_TIME; - event.data = current_pal; - - q_event = _vm->_events->queue(&event); - - // Background for intro scene is the first frame of the - // intro animation; display it but don't set palette - event.type = kEvTOneshot; - event.code = kBgEvent; - event.op = kEventDisplay; - event.param = kEvPNoSetPalette; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - - _vm->_anim->setCycles(0, -1); - - // Unlike the original, we keep the logo spinning during the - // palette fades. We don't have to, but I think it looks better - // that way. - - event.type = kEvTOneshot; - event.code = kAnimEvent; - event.op = kEventPlay; - event.param = 0; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - - // Fade in from black to the scene background palette - _vm->_scene->getBGPal(pal); - - event.type = kEvTContinuous; - event.code = kPalEvent; - event.op = kEventBlackToPal; - event.time = 0; - event.duration = IHNM_PALFADE_TIME; - event.data = pal; - - q_event = _vm->_events->chain(q_event, &event); - - // Fade to black after looping animation for a while - event.type = kEvTContinuous; - event.code = kPalEvent; - event.op = kEventPalToBlack; - event.time = IHNM_DGLOGO_TIME; - event.duration = IHNM_PALFADE_TIME; - event.data = pal; - - q_event = _vm->_events->chain(q_event, &event); - - // Queue end of scene - event.type = kEvTOneshot; - event.code = kSceneEvent; - event.op = kEventEnd; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - break; - default: - break; +void Scene::IHNMLoadCutaways() { + ResourceContext *resourceContext; + //ResourceContext *soundContext; + byte *resourcePointer; + size_t resourceLength; + + resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE); + if (resourceContext == NULL) { + error("Scene::IHNMStartProc() resource context not found"); } - return 0; -} + if (_vm->getGameId() != GID_IHNM_DEMO) + _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourcePointer, resourceLength); + else + _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourcePointer, resourceLength); -int Scene::SC_IHNMIntroMovieProc3(int param, void *refCon) { - return ((Scene *)refCon)->IHNMIntroMovieProc3(param); -} + if (resourceLength == 0) { + error("Scene::IHNMStartProc() Can't load cutaway list"); + } -int Scene::IHNMIntroMovieProc3(int param) { - Event event; - Event *q_event; - PalEntry *pal; - static PalEntry current_pal[PAL_ENTRIES]; + // Load the cutaways for the title screens + _vm->_anim->loadCutawayList(resourcePointer, resourceLength); +} - switch (param) { - case SCENE_BEGIN: - // Fade to black out of the intro DG logo anim - _vm->_gfx->getCurrentPal(current_pal); +bool Scene::checkKey() { + Common::Event event; + bool res = false; + + while (_vm->_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + _vm->shutDown(); + // fallthrough + case Common::EVENT_KEYDOWN: + res = true; + break; + default: + break; + } + } - event.type = kEvTContinuous; - event.code = kPalEvent; - event.op = kEventPalToBlack; - event.time = 0; - event.duration = IHNM_PALFADE_TIME; - event.data = current_pal; + return res; +} - q_event = _vm->_events->queue(&event); +bool Scene::playTitle(int title, int time, int mode) { + bool interrupted = false; + Surface *backBufferSurface; + int startTime = _vm->_system->getMillis(); + int frameTime = 0; + int curTime; + int assignedId; + int phase = 0; + bool done = false; + bool playParameter = true; + static PalEntry cur_pal[PAL_ENTRIES]; + static PalEntry pal_cut[PAL_ENTRIES]; + + backBufferSurface = _vm->_render->getBackGroundSurface(); + + // Load the cutaway + + _vm->_anim->setCutAwayMode(mode); + _vm->_frameCount = 0; + + _vm->_gfx->getCurrentPal(cur_pal); + + assignedId = _vm->_anim->playCutaway(title, false); + + _vm->_gfx->getCurrentPal(pal_cut); + + while (!done) { + curTime = _vm->_system->getMillis(); + + switch (phase) { + case 0: // fadeout + case 1: // fadeout 100% + case 7: // fadeout + case 8: // fadeout 100% + _vm->_gfx->palToBlack(cur_pal, (double)(curTime - startTime) / kNormalFadeDuration); + // fall through + + case 3: // fadein + case 4: // fadein 100% + if (phase == 3 || phase == 4) + _vm->_gfx->blackToPal(pal_cut, (double)(curTime - startTime) / kNormalFadeDuration); + + if (curTime - startTime > kNormalFadeDuration) { + phase++; + if (phase == 2 || phase == 5 || phase == 9) + startTime = curTime; + break; + } + break; + + case 2: // display background + _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0, + backBufferSurface->w, backBufferSurface->h); + phase++; + startTime = curTime; + break; + + case 5: // playback + if (time < 0) { + if (_vm->_frameCount >= -time) { + phase++; + break; + } + } else { + if (curTime - startTime >= time * 1000) { + phase++; + break; + } + } + + if (checkKey()) { + interrupted = true; + done = true; + break; + } + + if (_vm->_anim->getCycles(assignedId)) { // IHNM demo has 0 frames logo + if (curTime - frameTime > _vm->_anim->getFrameTime(assignedId)) { + _vm->_anim->play(assignedId, 0, playParameter); + + if (playParameter == true) // Do not loop animations + playParameter = false; + + frameTime = curTime; + + _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0, + backBufferSurface->w, backBufferSurface->h); + } + + } + break; + + case 6: // playback end + startTime = curTime; + _vm->_gfx->getCurrentPal(cur_pal); + phase++; + break; + + case 9: // end + done = true; + break; + } - // Music, maestro + _vm->_system->updateScreen(); + _vm->_system->delayMillis(10); + } - // In the GM file, this music also appears as tracks 7, 13, 19, - // 25 and 31, but only track 1 sounds right with the FM music. + // Clean up - if (_vm->getGameId() != GID_IHNM_DEMO) { - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = 1; - event.param2 = MUSIC_NORMAL; - event.op = kEventPlay; - event.time = 0; + _vm->_anim->endVideo(); - q_event = _vm->_events->chain(q_event, &event); - } + memset((byte *)backBufferSurface->pixels, 0, backBufferSurface->w * backBufferSurface->h); + _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0, + backBufferSurface->w, backBufferSurface->h); - // Background for intro scene is the first frame of the intro - // animation; display it but don't set palette - event.type = kEvTOneshot; - event.code = kBgEvent; - event.op = kEventDisplay; - event.param = kEvPNoSetPalette; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - - // Fade in from black to the scene background palette - _vm->_scene->getBGPal(pal); - - event.type = kEvTContinuous; - event.code = kPalEvent; - event.op = kEventBlackToPal; - event.time = 0; - event.duration = IHNM_PALFADE_TIME; - event.data = pal; - - q_event = _vm->_events->chain(q_event, &event); - - event.type = kEvTOneshot; - event.code = kAnimEvent; - event.op = kEventPlay; - event.param = 0; - event.time = 0; - - q_event = _vm->_events->chain(q_event, &event); - - // Queue end of scene after a while - // The delay has been increased so the speech won't start until the music has ended - event.type = kEvTOneshot; - event.code = kSceneEvent; - event.op = kEventEnd; - if (_vm->getGameId() != GID_IHNM_DEMO) - event.time = _vm->_music->hasAdlib() ? IHNM_TITLE_TIME_FM : IHNM_TITLE_TIME_GM; - else - event.time = 12000; - - q_event = _vm->_events->chain(q_event, &event); - break; - default: - break; - } + return interrupted; +} - return 0; +bool Scene::playLoopingTitle(int title, int seconds) { + return playTitle(title, seconds, kPanelCutaway); } } // End of namespace Saga diff --git a/engines/saga/input.cpp b/engines/saga/input.cpp index 358a225efa..5082ec7aca 100644 --- a/engines/saga/input.cpp +++ b/engines/saga/input.cpp @@ -49,7 +49,7 @@ int SagaEngine::processInput() { _console->attach(); } if (_interface->_textInput || _interface->_statusTextInput) { - _interface->processAscii(event.kbd.ascii); + _interface->processAscii(event.kbd); return SUCCESS; } @@ -115,7 +115,7 @@ int SagaEngine::processInput() { _render->toggleFlag(RF_RENDERPAUSE); break; default: - _interface->processAscii(event.kbd.ascii); + _interface->processAscii(event.kbd); break; } break; diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 8cfd993391..e6854b1c05 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -229,6 +229,12 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) { _vm->_sprite->loadList(_vm->getResourceDescription()->mainPanelSpritesResourceId, _mainPanel.sprites); // Option panel sprites _vm->_sprite->loadList(_vm->getResourceDescription()->optionPanelSpritesResourceId, _optionPanel.sprites); + // Save panel sprites + _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _savePanel.sprites); + // Load panel sprites + _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _loadPanel.sprites); + // Quit panel sprites + _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _quitPanel.sprites); if (_vm->getGameType() == GType_ITE) { _vm->_sprite->loadList(_vm->getResourceDescription()->defaultPortraitsResourceId, _defPortraits); @@ -342,18 +348,10 @@ int Interface::activate() { } else if (_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO) { _saveReminderState = 1; } + _vm->_gfx->showCursor(true); draw(); } - if (_vm->getGameId() != GID_IHNM_DEMO) { - _vm->_gfx->showCursor(true); - } else { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) { - // Don't show the mouse cursor in the non-interactive part of the IHNM demo - } else { - _vm->_gfx->showCursor(true); - } - } return SUCCESS; } @@ -369,7 +367,7 @@ int Interface::deactivate() { } void Interface::rememberMode() { - debug(1, "rememberMode(%d)", _savedMode); + debug(1, "rememberMode(%d)", _panelMode); _savedMode = _panelMode; } @@ -400,9 +398,6 @@ void Interface::setMode(int mode) { if (_vm->getGameId() == GID_IHNM_DEMO) { _inMainMode = true; _saveReminderState = 1; - if ((_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) || - _vm->_scene->currentSceneNumber() == 0 || _vm->_scene->currentSceneNumber() == -1) - _vm->_gfx->showCursor(false); } } else if (mode == kPanelOption) { // Show the cursor in the IHNM demo @@ -420,8 +415,8 @@ void Interface::setMode(int mode) { switch (_panelMode) { case kPanelMain: - if (_vm->getGameType() == GType_IHNM) - warning("FIXME: Implement IHNM differences from ExecuteInventoryPanel"); + // FIXME: Implement IHNM differences from ExecuteInventoryPanel for IHNM (though I believe they're already + // implemented) _mainPanel.currentButton = NULL; break; @@ -481,22 +476,22 @@ void Interface::setMode(int mode) { draw(); } -bool Interface::processAscii(uint16 ascii) { +bool Interface::processAscii(Common::KeyState keystate) { // TODO: Checking for Esc and Enter below is a bit hackish, and // and probably only works with the English version. Maybe we should // add a flag to the button so it can indicate if it's the default or // cancel button? - + uint16 ascii = keystate.ascii; int i; PanelButton *panelButton; if (_statusTextInput) { - processStatusTextInput(ascii); + processStatusTextInput(keystate); return true; } switch (_panelMode) { case kPanelNull: - if (ascii == 27) { // Esc + if (keystate.keycode == Common::KEYCODE_ESCAPE) { if (_vm->_scene->isInIntro()) { _vm->_scene->skipScene(); } else { @@ -506,26 +501,22 @@ bool Interface::processAscii(uint16 ascii) { return true; } - if (_vm->getGameId() == GID_IHNM_DEMO) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) - _vm->_scene->showIHNMDemoSpecialScreen(); - } + if (_vm->_scene->isNonInteractiveIHNMDemoPart()) + _vm->_scene->showIHNMDemoSpecialScreen(); break; case kPanelCutaway: - if (ascii == 27) { // Esc + if (keystate.keycode == Common::KEYCODE_ESCAPE) { if (!_disableAbortSpeeches) _vm->_actor->abortAllSpeeches(); _vm->_scene->cutawaySkip(); return true; } - if (_vm->getGameId() == GID_IHNM_DEMO) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) - _vm->_scene->showIHNMDemoSpecialScreen(); - } + if (_vm->_scene->isNonInteractiveIHNMDemoPart()) + _vm->_scene->showIHNMDemoSpecialScreen(); break; case kPanelVideo: - if (ascii == 27) { // Esc + if (keystate.keycode == Common::KEYCODE_ESCAPE) { if (_vm->_scene->isInIntro()) { _vm->_scene->skipScene(); } else { @@ -536,14 +527,12 @@ bool Interface::processAscii(uint16 ascii) { return true; } - if (_vm->getGameId() == GID_IHNM_DEMO) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) - _vm->_scene->showIHNMDemoSpecialScreen(); - } + if (_vm->_scene->isNonInteractiveIHNMDemoPart()) + _vm->_scene->showIHNMDemoSpecialScreen(); break; case kPanelOption: // TODO: check input dialog keys - if (ascii == 27 || ascii == 13) { // Esc or Enter + if (keystate.keycode == Common::KEYCODE_ESCAPE || keystate.keycode == Common::KEYCODE_RETURN) { // Esc or Enter ascii = 'c'; //continue } @@ -558,13 +547,13 @@ bool Interface::processAscii(uint16 ascii) { } break; case kPanelSave: - if (_textInput && processTextInput(ascii)) { + if (_textInput && processTextInput(keystate)) { return true; } - if (ascii == 27) { // Esc + if (keystate.keycode == Common::KEYCODE_ESCAPE) { ascii = 'c'; // cancel - } else if (ascii == 13) { // Enter + } else if (keystate.keycode == Common::KEYCODE_RETURN) { // Enter ascii = 's'; // save } @@ -579,9 +568,9 @@ bool Interface::processAscii(uint16 ascii) { } break; case kPanelQuit: - if (ascii == 27) { // Esc + if (keystate.keycode == Common::KEYCODE_ESCAPE) { ascii = 'c'; // cancel - } else if (ascii == 13) { // Enter + } else if (keystate.keycode == Common::KEYCODE_RETURN) { // Enter ascii = 'q'; // quit } @@ -619,8 +608,7 @@ bool Interface::processAscii(uint16 ascii) { return true; } } - if (ascii == 15) // ctrl-o - { + if (keystate.keycode == Common::KEYCODE_o && keystate.flags == Common::KBD_CTRL) { // ctrl-o if (_saveReminderState > 0) { setMode(kPanelOption); return true; @@ -663,7 +651,7 @@ bool Interface::processAscii(uint16 ascii) { mapPanelClean(); break; case kPanelSceneSubstitute: - if (ascii == 13) { + if (keystate.keycode == Common::KEYCODE_RETURN) { _vm->_render->clearFlag(RF_DEMO_SUBST); _vm->_gfx->setPalette(_mapSavedPal); setMode(kPanelMain); @@ -678,11 +666,11 @@ bool Interface::processAscii(uint16 ascii) { break; case kPanelProtect: if (_vm->getGameType() == GType_ITE) { - if (_textInput && processTextInput(ascii)) { + if (_textInput && processTextInput(keystate)) { return true; } - if (ascii == 27 || ascii == 13) { // Esc or Enter + if (keystate.keycode == Common::KEYCODE_ESCAPE || keystate.keycode == Common::KEYCODE_RETURN) { _vm->_script->wakeUpThreads(kWaitTypeRequest); _vm->_interface->setMode(kPanelMain); @@ -725,7 +713,7 @@ void Interface::setStatusText(const char *text, int statusColor) { assert(text != NULL); assert(strlen(text) < STATUS_TEXT_LEN); - if (_vm->_render->getFlags() & (RF_PLACARD | RF_MAP)) + if (_vm->_render->getFlags() & RF_MAP || _vm->_interface->getMode() == kPanelPlacard) return; strncpy(_statusText, text, STATUS_TEXT_LEN); @@ -801,16 +789,6 @@ void Interface::draw() { converseDisplayTextLines(backBuffer); } - if (_vm->getGameType() == GType_IHNM) { - if (_vm->_spiritualBarometer > 255) - _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff); - else - _vm->_gfx->setPaletteColor(kIHNMColorPortrait, - _vm->_spiritualBarometer * _portraitBgColor.red / 256, - _vm->_spiritualBarometer * _portraitBgColor.green / 256, - _vm->_spiritualBarometer * _portraitBgColor.blue / 256); - } - if (_panelMode == kPanelMain || _panelMode == kPanelConverse || _lockedMode == kPanelMain || _lockedMode == kPanelConverse || (_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO)) { @@ -841,14 +819,19 @@ void Interface::calcOptionSaveSlider() { int totalFiles = _vm->getSaveFilesCount(); int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible; int height = _optionSaveFileSlider->height; - int sliderHeight; + int sliderHeight = 13; // IHNM's save file list slider has a fixed height int pos; if (totalFiles < visibleFiles) { totalFiles = visibleFiles; } - sliderHeight = visibleFiles * height / totalFiles; + if (_vm->getGameType() == GType_ITE) { + // ITE's save file list slider has a dynamically computed height, depending on + // the number of save games + sliderHeight = visibleFiles * height / totalFiles; + } + if (sliderHeight < 7) { sliderHeight = 7; } @@ -931,6 +914,7 @@ void Interface::drawOption() { PanelButton *panelButton; Point textPoint; Point point; + Point sliderPoint; int spritenum = 0; backBuffer = _vm->_gfx->getBackBuffer(); @@ -959,7 +943,15 @@ void Interface::drawOption() { backBuffer->drawRect(_optionSaveRectTop, kITEColorDarkGrey); } - drawButtonBox(backBuffer, _optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0); + if (_vm->getGameType() == GType_ITE) { + drawButtonBox(backBuffer, _optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0); + } else { + panelButton = &_optionPanel.buttons[0]; + sliderPoint.x = _optionPanel.x + panelButton->xOffset; + sliderPoint.y = _optionSaveRectSlider.top; + _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _optionPanel.sprites, 0 + _optionSaveFileSlider->state, sliderPoint, 256); + + } if (_optionSaveRectBottom.height() > 0) { backBuffer->drawRect(_optionSaveRectBottom, kITEColorDarkGrey); @@ -970,7 +962,10 @@ void Interface::drawOption() { rect2 = rect; fontHeight = _vm->_font->getHeight(kKnownFontSmall); for (j = 0; j < _vm->getDisplayInfo().optionSaveFileVisible; j++) { - bgColor = kITEColorDarkGrey0C; + if (_vm->getGameType() == GType_ITE) + bgColor = kITEColorDarkGrey0C; + else + bgColor = kIHNMColorBlack; fgColor = kITEColorBrightWhite; idx = j + _optionSaveFileTop; @@ -1052,7 +1047,10 @@ void Interface::setQuit(PanelButton *panelButton) { setMode(kPanelOption); break; case kTextQuit: - _vm->shutDown(); + if (_vm->getGameId() == GID_IHNM_DEMO) + _vm->_scene->creditsScene(); // display sales info for IHNM demo + else + _vm->shutDown(); break; } } @@ -1118,20 +1116,20 @@ void Interface::setLoad(PanelButton *panelButton) { } } -void Interface::processStatusTextInput(uint16 ascii) { +void Interface::processStatusTextInput(Common::KeyState keystate) { - switch (ascii) { - case 27: // esc + switch (keystate.keycode) { + case Common::KEYCODE_ESCAPE: _statusTextInputState = kStatusTextInputAborted; _statusTextInput = false; _vm->_script->wakeUpThreads(kWaitTypeStatusTextInput); break; - case 13: // return + case Common::KEYCODE_RETURN: _statusTextInputState = kStatusTextInputEntered; _statusTextInput = false; _vm->_script->wakeUpThreads(kWaitTypeStatusTextInput); break; - case 8: // backspace + case Common::KEYCODE_BACKSPACE: if (_statusTextInputPos == 0) { break; } @@ -1141,36 +1139,36 @@ void Interface::processStatusTextInput(uint16 ascii) { if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX) { break; } - if (((ascii >= 'a') && (ascii <='z')) || - ((ascii >= '0') && (ascii <='9')) || - ((ascii >= 'A') && (ascii <='Z')) || - (ascii == ' ')) { - _statusTextInputString[_statusTextInputPos++] = ascii; + if (isalnum(keystate.ascii) || (keystate.ascii == ' ')) { + _statusTextInputString[_statusTextInputPos++] = keystate.ascii; _statusTextInputString[_statusTextInputPos] = 0; } } setStatusText(_statusTextInputString); } -bool Interface::processTextInput(uint16 ascii) { +bool Interface::processTextInput(Common::KeyState keystate) { char ch[2]; char tempString[SAVE_TITLE_SIZE]; uint tempWidth; memset(tempString, 0, SAVE_TITLE_SIZE); ch[1] = 0; + // IHNM has a smaller save title size than ITE. We only limit the save title size during text input + // in IHNM, to preserve backwards compatibility with older save games + uint save_title_size = _vm->getGameType() == GType_ITE ? SAVE_TITLE_SIZE : IHNM_SAVE_TITLE_SIZE; - switch (ascii) { - case 13: + switch (keystate.keycode) { + case Common::KEYCODE_RETURN: return false; - case 27: // esc + case Common::KEYCODE_ESCAPE: _textInput = false; break; - case 8: // backspace + case Common::KEYCODE_BACKSPACE: if (_textInputPos <= 1) { break; } _textInputPos--; - case 127: // del + case Common::KEYCODE_DELETE: if (_textInputPos <= _textInputStringLength) { if (_textInputPos != 1) { strncpy(tempString, _textInputString, _textInputPos - 1); @@ -1182,27 +1180,25 @@ bool Interface::processTextInput(uint16 ascii) { _textInputStringLength = strlen(_textInputString); } break; - case 276: // left + case Common::KEYCODE_LEFT: if (_textInputPos > 1) { _textInputPos--; } break; - case 275: // right + case Common::KEYCODE_RIGHT: if (_textInputPos <= _textInputStringLength) { _textInputPos++; } break; default: - if (((ascii >= 'a') && (ascii <='z')) || - ((ascii >= '0') && (ascii <='9')) || - ((ascii >= 'A') && (ascii <='Z')) || - (ascii == ' ')) { - if (_textInputStringLength < SAVE_TITLE_SIZE - 1) { - ch[0] = ascii; + if (isalnum(keystate.ascii) || (keystate.ascii == ' ') || + (keystate.ascii == '-') || (keystate.ascii == '_')) { + if (_textInputStringLength < save_title_size - 1) { + ch[0] = keystate.ascii; tempWidth = _vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal); tempWidth += _vm->_font->getStringWidth(kKnownFontSmall, _textInputString, 0, kFontNormal); if (tempWidth > _textInputMaxWidth) { - break; + break; } if (_textInputPos != 1) { strncpy(tempString, _textInputString, _textInputPos - 1); @@ -1243,10 +1239,10 @@ void Interface::drawTextInput(Surface *ds, InterfacePanel *panel, PanelButton *p while ((ch[0] = _textInputString[i++]) != 0) { rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal)); if ((i == _textInputPos) && _textInput) { - fgColor = kITEColorBlack; - ds->fillRect(rect, kITEColorWhite); + fgColor = _vm->KnownColor2ColorId(kKnownColorBlack); + ds->fillRect(rect, _vm->KnownColor2ColorId(kKnownColorWhite)); } else { - fgColor = kITEColorWhite; + fgColor = _vm->KnownColor2ColorId(kKnownColorWhite); } textPoint.x = rect.left; textPoint.y = rect.top + 1; @@ -1257,7 +1253,7 @@ void Interface::drawTextInput(Surface *ds, InterfacePanel *panel, PanelButton *p if (_textInput && (_textInputPos >= i)) { ch[0] = ' '; rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal)); - ds->fillRect(rect, kITEColorWhite); + ds->fillRect(rect, _vm->KnownColor2ColorId(kKnownColorWhite)); } } @@ -1468,11 +1464,22 @@ void Interface::handleOptionClick(const Point& mousePoint) { void Interface::handleChapterSelectionUpdate(const Point& mousePoint) { uint16 objectId; + int hitZoneIndex; + const HitZone * hitZone; // FIXME: Original handled more object types here. objectId = _vm->_actor->hitTest(mousePoint, true); + if (objectId == ID_NOTHING) { + hitZoneIndex = _vm->_scene->_objectMap->hitTest(mousePoint); + + if ((hitZoneIndex != -1)) { + hitZone = _vm->_scene->_objectMap->getHitZone(hitZoneIndex); + objectId = hitZone->getHitZoneId(); + } + } + if (objectId != _vm->_script->_pointerObject) { _vm->_script->_pointerObject = objectId; } @@ -1492,12 +1499,12 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) { switch (objectTypeId(obj)) { case kGameObjectHitZone: - hitZone = _vm->_scene->_actionMap->getHitZone(objectIdToIndex(obj)); + hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(obj)); if (hitZone == NULL) return; - if (hitZone->getFlags() & kHitZoneExit) + if (hitZone->getFlags() & kHitZoneEnabled) script = hitZone->getScriptNumber(); break; @@ -1523,7 +1530,6 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) { event.param4 = obj; // Object event.param5 = 0; // With Object event.param6 = obj; // Actor - _vm->_events->queue(&event); } } @@ -1540,11 +1546,8 @@ void Interface::setOption(PanelButton *panelButton) { } else { if (_vm->_scene->currentChapterNumber() == 8) { setMode(kPanelChapterSelection); - } else if (_vm->getGameId() == GID_IHNM_DEMO) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) - setMode(kPanelNull); - else - setMode(kPanelMain); + } else if (_vm->_scene->isNonInteractiveIHNMDemoPart()) { + setMode(kPanelNull); } else { setMode(kPanelMain); } @@ -1564,11 +1567,9 @@ void Interface::setOption(PanelButton *panelButton) { } break; case kTextSave: - // Disallow saving in the non-interactive part of the IHNM demo - if (_vm->getGameId() == GID_IHNM_DEMO) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) - return; - } + // Disallow saving in the non-interactive part of the IHNM demo (original demo didn't support saving at all) + if (_vm->_scene->isNonInteractiveIHNMDemoPart()) + return; if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) { _textInputString[0] = 0; @@ -1787,10 +1788,8 @@ void Interface::update(const Point& mousePoint, int updateFlag) { break; case kPanelNull: - if (_vm->getGameId() == GID_IHNM_DEMO && (updateFlag & UPDATE_MOUSECLICK)) { - if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) - _vm->_scene->showIHNMDemoSpecialScreen(); - } + if (_vm->_scene->isNonInteractiveIHNMDemoPart() && (updateFlag & UPDATE_MOUSECLICK)) + _vm->_scene->showIHNMDemoSpecialScreen(); break; } @@ -1808,6 +1807,10 @@ void Interface::drawStatusBar() { if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8) return; + // Don't draw the status bar while fading out + if (_fadeMode == kFadeOut) + return; + backBuffer = _vm->_gfx->getBackBuffer(); // Erase background of status bar @@ -1921,7 +1924,6 @@ void Interface::handleMainUpdate(const Point& mousePoint) { if ((panelButton != NULL) && (panelButton->type == kPanelButtonArrow)) { if (panelButton->state == 1) { - //TODO: insert timeout catchup inventoryChangePos(panelButton->id); } changed = true; @@ -1938,11 +1940,14 @@ void Interface::handleMainUpdate(const Point& mousePoint) { //inventory stuff void Interface::inventoryChangePos(int chg) { - if ((chg < 0 && _inventoryStart + chg >= 0) || - (chg > 0 && _inventoryStart < _inventoryEnd)) { - _inventoryStart += chg; - draw(); + // Arrows will scroll the inventory up or down up to 4 items + for (int i = 1; i <= 4; i++) { + if ((chg < 0 && _inventoryStart + chg >= 0) || + (chg > 0 && _inventoryStart < _inventoryEnd)) { + _inventoryStart += chg; } + } + draw(); } void Interface::inventorySetPos(int key) { @@ -2087,18 +2092,19 @@ void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bo solidColor = down ? kITEColorLightBlue94 : kITEColorLightBlue96; break; case kEdit: - cornerColor = kITEColorLightBlue96; - frameColor = kITEColorLightBlue96; - fillColor = kITEColorLightBlue96; - our = kITEColorDarkBlue8a; - odl = kITEColorLightBlue94; - iur = 0x97; - idl = 0x95; - if (down) { - solidColor = kITEColorBlue; + if (_vm->getGameType() == GType_ITE) { + cornerColor = frameColor = fillColor = kITEColorLightBlue96; + our = kITEColorDarkBlue8a; + odl = kITEColorLightBlue94; + solidColor = down ? kITEColorBlue : kITEColorDarkGrey0C; } else { - solidColor = kITEColorDarkGrey0C; + cornerColor = frameColor = fillColor = kIHNMColorBlack; + our = kIHNMColorBlack; + odl = kIHNMColorBlack; + solidColor = kIHNMColorBlack; } + iur = 0x97; + idl = 0x95; break; default: cornerColor = 0x8b; @@ -2248,21 +2254,25 @@ void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelBut litButton = panelButton->state > 0; if (panel == &_optionPanel) { - texturePoint.x = _optionPanel.x + panelButton->xOffset; - texturePoint.y = _optionPanel.y + panelButton->yOffset; + texturePoint.x = _optionPanel.x + panelButton->xOffset - 1; + texturePoint.y = _optionPanel.y + panelButton->yOffset - 1; _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, spritenum + 2 + litButton, texturePoint, 256); } else if (panel == &_quitPanel) { - texturePoint.x = _quitPanel.x + panelButton->xOffset; - texturePoint.y = _quitPanel.y + panelButton->yOffset; - _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256); + texturePoint.x = _quitPanel.x + panelButton->xOffset - 3; + texturePoint.y = _quitPanel.y + panelButton->yOffset - 3; + _vm->_sprite->draw(ds, _vm->getDisplayClip(), _quitPanel.sprites, litButton, texturePoint, 256); } else if (panel == &_savePanel) { - texturePoint.x = _savePanel.x + panelButton->xOffset; - texturePoint.y = _savePanel.y + panelButton->yOffset; - _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256); + texturePoint.x = _savePanel.x + panelButton->xOffset - 3; + texturePoint.y = _savePanel.y + panelButton->yOffset - 3; + _vm->_sprite->draw(ds, _vm->getDisplayClip(), _savePanel.sprites, litButton, texturePoint, 256); + // Input text box sprite + texturePoint.x = _savePanel.x + _saveEdit->xOffset - 2; + texturePoint.y = _savePanel.y + _saveEdit->yOffset - 2; + _vm->_sprite->draw(ds, _vm->getDisplayClip(), _savePanel.sprites, 2, texturePoint, 256); } else if (panel == &_loadPanel) { - texturePoint.x = _loadPanel.x + panelButton->xOffset; - texturePoint.y = _loadPanel.y + panelButton->yOffset; - _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256); + texturePoint.x = _loadPanel.x + panelButton->xOffset - 3; + texturePoint.y = _loadPanel.y + panelButton->yOffset - 3; + _vm->_sprite->draw(ds, _vm->getDisplayClip(), _loadPanel.sprites, litButton, texturePoint, 256); } else { // revert to default behavior drawButtonBox(ds, rect, kButton, panelButton->state > 0); @@ -2523,11 +2533,14 @@ void Interface::converseDisplayTextLines(Surface *ds) { } void Interface::converseChangePos(int chg) { - if ((chg < 0 && _converseStartPos + chg >= 0) || - (chg > 0 && _converseStartPos < _converseEndPos)) { - _converseStartPos += chg; - draw(); + // Arrows will scroll the converse panel or down up to 4 conversation options + for (int i = 1; i <= 4; i++) { + if ((chg < 0 && _converseStartPos + chg >= 0) || + (chg > 0 && _converseStartPos < _converseEndPos)) { + _converseStartPos += chg; + } } + draw(); } void Interface::converseSetPos(int key) { @@ -2580,7 +2593,6 @@ void Interface::handleConverseUpdate(const Point& mousePoint) { if (_conversePanel.currentButton->type == kPanelButtonArrow) { if (_conversePanel.currentButton->state == 1) { - //TODO: insert timeout catchup converseChangePos(_conversePanel.currentButton->id); } draw(); diff --git a/engines/saga/interface.h b/engines/saga/interface.h index 7ae225219a..a8e2d5a647 100644 --- a/engines/saga/interface.h +++ b/engines/saga/interface.h @@ -28,6 +28,7 @@ #ifndef SAGA_INTERFACE_H #define SAGA_INTERFACE_H +#include "common/keyboard.h" #include "common/savefile.h" #include "saga/displayinfo.h" @@ -225,7 +226,7 @@ public: void drawStatusBar(); void setVerbState(int verb, int state); - bool processAscii(uint16 ascii); + bool processAscii(Common::KeyState keystate); void keyBoss(); void keyBossExit(); @@ -341,8 +342,8 @@ private: void drawVerbPanelText(Surface *ds, PanelButton *panelButton, KnownColor textKnownColor, KnownColor textShadowKnownColor); void drawVerbPanel(Surface *backBuffer, PanelButton* panelButton); void calcOptionSaveSlider(); - bool processTextInput(uint16 ascii); - void processStatusTextInput(uint16 ascii); + bool processTextInput(Common::KeyState keystate); + void processStatusTextInput(Common::KeyState keystate); public: void converseInit(void); @@ -379,6 +380,7 @@ private: public: SpriteList _defPortraits; + PalEntry _portraitBgColor; private: SagaEngine *_vm; @@ -416,7 +418,6 @@ private: int _statusOnceColor; int _leftPortrait; int _rightPortrait; - PalEntry _portraitBgColor; Point _lastMousePoint; diff --git a/engines/saga/ite_introproc.cpp b/engines/saga/ite_introproc.cpp index 1664969644..1b74d41cb7 100644 --- a/engines/saga/ite_introproc.cpp +++ b/engines/saga/ite_introproc.cpp @@ -115,7 +115,6 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo event.op = kEventDisplay; event.data = entry; event.time = (i == 0) ? 0 : VOICE_PAD; - q_event = _vm->_events->chain(q_event, &event); // Play voice @@ -124,7 +123,6 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo event.op = kEventPlay; event.param = dialogue[i].i_voice_rn; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn); @@ -138,7 +136,6 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo event.op = kEventRemove; event.data = entry; event.time = voice_len; - q_event = _vm->_events->chain(q_event, &event); } @@ -265,7 +262,6 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const event.op = kEventDisplay; event.data = entry; event.time = delta_time; - q_event = _vm->_events->queue(&event); // Remove text @@ -274,7 +270,6 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const event.op = kEventRemove; event.data = entry; event.time = duration; - q_event = _vm->_events->chain(q_event, &event); y += (_vm->_font->getHeight(font) + line_spacing); @@ -301,7 +296,6 @@ int Scene::ITEIntroAnimProc(int param) { event.op = kEventDisplay; event.param = kEvPSetPalette; event.time = 0; - q_event = _vm->_events->queue(&event); debug(3, "Intro animation procedure started."); @@ -340,7 +334,6 @@ int Scene::ITEIntroAnimProc(int param) { event.op = kEventPlay; event.param = 0; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); // Queue intro music playback @@ -350,7 +343,6 @@ int Scene::ITEIntroAnimProc(int param) { event.param2 = MUSIC_LOOP; event.op = kEventPlay; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); } break; @@ -427,7 +419,6 @@ int Scene::ITEIntroCave1Proc(int param) { event.code = kPalAnimEvent; event.op = kEventCycleStart; event.time = 0; - q_event = _vm->_events->queue(&event); // Queue narrator dialogue list @@ -438,8 +429,8 @@ int Scene::ITEIntroCave1Proc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = VOICE_PAD; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -504,7 +495,6 @@ int Scene::ITEIntroCave2Proc(int param) { event.op = kEventDissolve; event.time = 0; event.duration = DISSOLVE_DURATION; - q_event = _vm->_events->queue(&event); // Begin palette cycling animation for candles @@ -512,7 +502,6 @@ int Scene::ITEIntroCave2Proc(int param) { event.code = kPalAnimEvent; event.op = kEventCycleStart; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); // Queue narrator dialogue list @@ -523,8 +512,8 @@ int Scene::ITEIntroCave2Proc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = VOICE_PAD; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -588,7 +577,6 @@ int Scene::ITEIntroCave3Proc(int param) { event.op = kEventDissolve; event.time = 0; event.duration = DISSOLVE_DURATION; - q_event = _vm->_events->queue(&event); // Begin palette cycling animation for candles @@ -596,7 +584,6 @@ int Scene::ITEIntroCave3Proc(int param) { event.code = kPalAnimEvent; event.op = kEventCycleStart; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); // Queue narrator dialogue list @@ -607,8 +594,8 @@ int Scene::ITEIntroCave3Proc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = VOICE_PAD; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -681,7 +668,6 @@ int Scene::ITEIntroCave4Proc(int param) { event.op = kEventDissolve; event.time = 0; event.duration = DISSOLVE_DURATION; - q_event = _vm->_events->queue(&event); // Begin palette cycling animation for candles @@ -689,7 +675,6 @@ int Scene::ITEIntroCave4Proc(int param) { event.code = kPalAnimEvent; event.op = kEventCycleStart; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); // Queue narrator dialogue list @@ -700,8 +685,8 @@ int Scene::ITEIntroCave4Proc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = VOICE_PAD; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -747,7 +732,6 @@ int Scene::ITEIntroValleyProc(int param) { event.op = kEventPlay; event.param = 0; event.time = 0; - q_event = _vm->_events->queue(&event); // Begin ITE title theme music @@ -759,7 +743,6 @@ int Scene::ITEIntroValleyProc(int param) { event.param2 = MUSIC_NORMAL; event.op = kEventPlay; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); // Pause animation before logo @@ -768,7 +751,6 @@ int Scene::ITEIntroValleyProc(int param) { event.op = kEventStop; event.param = 0; event.time = 3000; - q_event = _vm->_events->chain(q_event, &event); // Display logo @@ -777,7 +759,6 @@ int Scene::ITEIntroValleyProc(int param) { event.op = kEventDissolveBGMask; event.time = 0; event.duration = LOGO_DISSOLVE_DURATION; - q_event = _vm->_events->chain(q_event, &event); // Remove logo @@ -786,7 +767,6 @@ int Scene::ITEIntroValleyProc(int param) { event.op = kEventDissolve; event.time = 3000; event.duration = LOGO_DISSOLVE_DURATION; - q_event = _vm->_events->chain(q_event, &event); // Unpause animation before logo @@ -795,7 +775,6 @@ int Scene::ITEIntroValleyProc(int param) { event.op = kEventPlay; event.time = 0; event.param = 0; - q_event = _vm->_events->chain(q_event, &event); // Queue game credits list @@ -806,8 +785,8 @@ int Scene::ITEIntroValleyProc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = 1000; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -870,7 +849,6 @@ int Scene::ITEIntroTreeHouseProc(int param) { event.op = kEventDissolve; event.time = 0; event.duration = DISSOLVE_DURATION; - q_event = _vm->_events->queue(&event); if (_vm->_anim->hasAnimation(0)) { @@ -882,7 +860,6 @@ int Scene::ITEIntroTreeHouseProc(int param) { event.op = kEventPlay; event.param = 0; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); } @@ -895,8 +872,8 @@ int Scene::ITEIntroTreeHouseProc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = 1000; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -950,7 +927,6 @@ int Scene::ITEIntroFairePathProc(int param) { event.op = kEventDissolve; event.time = 0; event.duration = DISSOLVE_DURATION; - q_event = _vm->_events->queue(&event); // Begin title screen background animation @@ -961,7 +937,6 @@ int Scene::ITEIntroFairePathProc(int param) { event.op = kEventPlay; event.param = 0; event.time = 0; - q_event = _vm->_events->chain(q_event, &event); // Queue game credits list @@ -973,8 +948,8 @@ int Scene::ITEIntroFairePathProc(int param) { event.code = kSceneEvent; event.op = kEventEnd; event.time = 1000; - q_event = _vm->_events->chain(q_event, &event); + break; case SCENE_END: break; @@ -1005,7 +980,6 @@ int Scene::ITEIntroFaireTentProc(int param) { event.op = kEventDissolve; event.time = 0; event.duration = DISSOLVE_DURATION; - q_event_start = _vm->_events->queue(&event); // End scene after momentary pause @@ -1014,6 +988,7 @@ int Scene::ITEIntroFaireTentProc(int param) { event.op = kEventEnd; event.time = 5000; q_event = _vm->_events->chain(q_event_start, &event); + break; case SCENE_END: break; diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h index d9bd59adc4..3c594b5fec 100644 --- a/engines/saga/itedata.h +++ b/engines/saga/itedata.h @@ -41,9 +41,6 @@ enum ActorFlags { kNoScale = 0x80 // (1<<7) Actor is not scaled }; -// TODO: This doesn't quite correspond to the original Actor struct, so I'm not -// sure if I got it right. - struct ActorTableData { byte flags; byte nameIndex; diff --git a/engines/saga/module.mk b/engines/saga/module.mk index 6c1812ad23..68cf91be32 100644 --- a/engines/saga/module.mk +++ b/engines/saga/module.mk @@ -2,6 +2,7 @@ MODULE := engines/saga MODULE_OBJS := \ actor.o \ + actor_walk.o \ animation.o \ console.o \ detection.o \ diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 04e79c174d..6b233e0256 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -92,7 +92,7 @@ DigitalMusicInputStream::DigitalMusicInputStream(SagaEngine *vm, ResourceContext _compressedStream = NULL; - if (Common::File::exists("music.cmp")) { + if (Common::File::exists("music.cmp") || Common::File::exists("musicd.cmp")) { // Read compressed header to determine compression type _file->seek((long)resourceData->offset, SEEK_SET); _file->read(compressedHeader, 9); @@ -320,6 +320,8 @@ void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) { void MusicPlayer::onTimer(void *refCon) { MusicPlayer *music = (MusicPlayer *)refCon; + Common::StackLock lock(music->_mutex); + if (music->_isPlaying) music->_parser->onTimer(); } @@ -329,6 +331,8 @@ void MusicPlayer::playMusic() { } void MusicPlayer::stopMusic() { + Common::StackLock lock(_mutex); + _isPlaying = false; if (_parser) { _parser->unloadMusic(); @@ -352,6 +356,7 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enable } Music::~Music() { + _vm->_timer->removeTimerProc(&musicVolumeGaugeCallback); _mixer->stopHandle(_musicHandle); delete _player; xmidiParser->setMidiDriver(NULL); @@ -561,7 +566,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) { parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); _player->_parser = parser; - _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); + setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); if (flags & MUSIC_LOOP) _player->setLoop(true); @@ -574,15 +579,17 @@ void Music::play(uint32 resourceId, MusicFlags flags) { } void Music::pause(void) { - //TODO: do it + _player->setVolume(-1); + _player->setPlaying(false); } void Music::resume(void) { - //TODO: do it} + _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); + _player->setPlaying(true); } void Music::stop(void) { - //TODO: do it + _player->stopMusic(); } } // End of namespace Saga diff --git a/engines/saga/music.h b/engines/saga/music.h index b038a25a11..1fbdda53f2 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -34,6 +34,7 @@ #include "sound/mp3.h" #include "sound/vorbis.h" #include "sound/flac.h" +#include "common/mutex.h" namespace Saga { @@ -49,6 +50,7 @@ public: ~MusicPlayer(); bool isPlaying() { return _isPlaying; } + void setPlaying(bool playing) { _isPlaying = playing; } void setVolume(int volume); int getVolume() { return _masterVolume; } @@ -77,6 +79,7 @@ public: MidiChannel *getPercussionChannel() { return 0; } MidiParser *_parser; + Common::Mutex _mutex; protected: diff --git a/engines/saga/palanim.cpp b/engines/saga/palanim.cpp index 19c2fc4d40..f318b815cc 100644 --- a/engines/saga/palanim.cpp +++ b/engines/saga/palanim.cpp @@ -131,7 +131,6 @@ int PalAnim::cycleStart() { event.code = kPalAnimEvent; event.op = kEventCycleStep; event.time = PALANIM_CYCLETIME; - _vm->_events->queue(&event); return SUCCESS; @@ -178,7 +177,6 @@ int PalAnim::cycleStep(int vectortime) { event.code = kPalAnimEvent; event.op = kEventCycleStep; event.time = vectortime + PALANIM_CYCLETIME; - _vm->_events->queue(&event); return SUCCESS; diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp index 930476b4e2..e006b4a627 100644 --- a/engines/saga/render.cpp +++ b/engines/saga/render.cpp @@ -85,11 +85,12 @@ void Render::drawScene() { // Get mouse coordinates mousePoint = _vm->mousePos(); - if (!(_flags & (RF_DEMO_SUBST | RF_PLACARD | RF_MAP))) { - // Display scene background - _vm->_scene->draw(); - + if (!(_flags & (RF_DEMO_SUBST | RF_MAP) || _vm->_interface->getMode() == kPanelPlacard)) { if (_vm->_interface->getFadeMode() != kFadeOut) { + // Display scene background + if (!(_flags & RF_DISABLE_ACTORS)) + _vm->_scene->draw(); + if (_vm->_puzzle->isActive()) { _vm->_puzzle->movePiece(mousePoint); _vm->_actor->drawSpeech(); diff --git a/engines/saga/render.h b/engines/saga/render.h index 4c6e3ee5b1..95abc2e4df 100644 --- a/engines/saga/render.h +++ b/engines/saga/render.h @@ -39,11 +39,10 @@ enum RENDER_FLAGS { RF_OBJECTMAP_TEST = (1 << 3), RF_RENDERPAUSE = (1 << 4), RF_GAMEPAUSE = (1 << 5), - RF_PLACARD = (1 << 6), - RF_ACTOR_PATH_TEST = (1 << 7), - RF_MAP = (1 << 8), - RF_DISABLE_ACTORS = (1 << 9), - RF_DEMO_SUBST = (1 << 10) + RF_ACTOR_PATH_TEST = (1 << 6), + RF_MAP = (1 << 7), + RF_DISABLE_ACTORS = (1 << 8), + RF_DEMO_SUBST = (1 << 9) }; class Render { diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp index 4d3ff1e47c..ba56e838b7 100644 --- a/engines/saga/rscfile.cpp +++ b/engines/saga/rscfile.cpp @@ -330,7 +330,11 @@ bool Resource::loadContext(ResourceContext *context) { if (resourceData->patchData->_patchFile->open(patchDescription->fileName)) { resourceData->offset = 0; resourceData->size = resourceData->patchData->_patchFile->size(); - resourceData->patchData->_patchFile->close(); + // ITE uses several patch files which are loaded and then not needed + // anymore (as they're in memory), so close them here. IHNM uses only + // 1 patch file, which is reused, so don't close it + if (_vm->getGameType() == GType_ITE) + resourceData->patchData->_patchFile->close(); } else { delete resourceData->patchData; resourceData->patchData = NULL; @@ -606,7 +610,11 @@ void Resource::loadResource(ResourceContext *context, uint32 resourceId, byte*&r if (file->read(resourceBuffer, resourceSize) != resourceSize) { error("Resource::loadResource() failed to read"); } - if (resourceData->patchData != NULL) + + // ITE uses several patch files which are loaded and then not needed + // anymore (as they're in memory), so close them here. IHNM uses only + // 1 patch file, which is reused, so don't close it + if (resourceData->patchData != NULL && _vm->getGameType() == GType_ITE) file->close(); } @@ -742,6 +750,12 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { if (_metaResource.songTableID > 0) { _vm->_resource->loadResource(resourceContext, _metaResource.songTableID, resourcePointer, resourceLength); + if (chapter == 6) { + int32 id = READ_LE_UINT32(&resourcePointer[actorsEntrance * 4]); + free(resourcePointer); + _vm->_resource->loadResource(resourceContext, id, resourcePointer, resourceLength); + } + if (resourceLength == 0) { error("Resource::loadGlobalResources Can't load songs list for current track"); } @@ -758,6 +772,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { free(resourcePointer); } else { // The IHNM demo has a fixed music track and doesn't load a song table + _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); _vm->_music->play(3, MUSIC_LOOP); } diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 76731c201a..01a75f4af1 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -259,10 +259,10 @@ int SagaEngine::go() { _scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade); _events->handleEvents(0); // Process immediate events + _interface->setMode(kPanelMain); char *fileName; fileName = calcSaveFileName(ConfMan.getInt("save_slot")); load(fileName); - _interface->setMode(kPanelMain); } else { _framesEsc = 0; _scene->startScene(); @@ -428,6 +428,9 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) { case (kKnownColorBrightWhite): colorId = kITEColorBrightWhite; break; + case (kKnownColorWhite): + colorId = kITEColorWhite; + break; case (kKnownColorBlack): colorId = kITEColorBlack; break; @@ -449,8 +452,7 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) { error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor); } } else if (getGameType() == GType_IHNM) { - switch (knownColor) - { + switch (knownColor) { case(kKnownColorTransparent): colorId = kITEColorTransBlack; break; @@ -458,6 +460,9 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) { case (kKnownColorBrightWhite): colorId = kITEColorBrightWhite; break; + case (kKnownColorWhite): + colorId = kITEColorBrightWhite; + break; case (kKnownColorBlack): colorId = kIHNMColorBlack; break; diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 43952fe564..8016fb9e65 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -69,7 +69,12 @@ struct StringList; #define MAXPATH 512 //TODO: remove +// Note that IHNM has a smaller save title size than ITE +// We allocate the ITE save title size in savegames, to +// preserve savegame backwards compatibility. We only check +// for IHNM's save title during text input #define SAVE_TITLE_SIZE 28 +#define IHNM_SAVE_TITLE_SIZE 22 #define MAX_SAVES 96 #define MAX_FILE_NAME 256 @@ -153,7 +158,8 @@ enum GameFeatures { GF_WYRMKEEP = 1 << 1, GF_CD_FX = 1 << 2, GF_SCENE_SUBSTITUTES = 1 << 3, - GF_COMPRESSED_SOUNDS = 1 << 4 + GF_COMPRESSED_SOUNDS = 1 << 4, + GF_NON_INTERACTIVE = 1 << 5 }; enum VerbTypeIds { @@ -297,6 +303,7 @@ struct GameResourceDescription { uint32 conversePanelResourceId; uint32 optionPanelResourceId; uint32 warningPanelResourceId; + uint32 warningPanelSpritesResourceId; uint32 mainSpritesResourceId; uint32 mainPanelSpritesResourceId; uint32 optionPanelSpritesResourceId; @@ -441,6 +448,7 @@ enum ColorId { enum KnownColor { kKnownColorTransparent, kKnownColorBrightWhite, + kKnownColorWhite, kKnownColorBlack, kKnownColorSubtitleTextColor, diff --git a/engines/saga/sagaresnames.h b/engines/saga/sagaresnames.h index 761ac1ab68..b416d85fd8 100644 --- a/engines/saga/sagaresnames.h +++ b/engines/saga/sagaresnames.h @@ -108,6 +108,7 @@ namespace Saga { #define RID_IHNM_OPTION_PANEL 15 #define RID_IHNM_OPTION_PANEL_SPRITES 16 #define RID_IHNM_WARNING_PANEL 17 +#define RID_IHNM_WARNING_PANEL_SPRITES 18 #define RID_IHNM_BOSS_SCREEN 19 #define RID_IHNM_PROFILE_BG 20 #define RID_IHNM_MAIN_STRINGS 21 @@ -122,7 +123,8 @@ namespace Saga { #define RID_IHNMDEMO_OPTION_PANEL 10 #define RID_IHNMDEMO_OPTION_PANEL_SPRITES 11 #define RID_IHNMDEMO_WARNING_PANEL 12 -#define RID_IHNMDEMO_BOSS_SCREEN 13 // Does not exist in the demo +#define RID_IHNMDEMO_WARNING_PANEL_SPRITES 13 +#define RID_IHNMDEMO_BOSS_SCREEN 14 // Does not exist in the demo #define RID_IHNMDEMO_PROFILE_BG 15 #define RID_IHNMDEMO_MAIN_STRINGS 16 diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp index 77d7816963..6e731de44e 100644 --- a/engines/saga/saveload.cpp +++ b/engines/saga/saveload.cpp @@ -187,6 +187,9 @@ void SagaEngine::save(const char *fileName, const char *saveName) { _saveHeader.type = MKID_BE('SAGA'); _saveHeader.size = 0; _saveHeader.version = CURRENT_SAGA_VER; + // Note that IHNM has a smaller save title size than ITE + // We allocate the ITE save title size here, to preserve + // savegame backwards compatibility strncpy(_saveHeader.name, saveName, SAVE_TITLE_SIZE); out->writeUint32BE(_saveHeader.type); @@ -255,8 +258,8 @@ void SagaEngine::load(const char *fileName) { // Some older saves were not written in an endian safe fashion. // We try to detect this here by checking for extremly high version values. // If found, we retry with the data swapped. - // FIXME: Maybe display a warning/error message instead? if (_saveHeader.version > 0xFFFFFF) { + warning("This savegame is not endian safe, retrying with the data swapped"); _saveHeader.version = SWAP_BYTES_32(_saveHeader.version); } @@ -276,7 +279,6 @@ void SagaEngine::load(const char *fileName) { // Surrounding scene sceneNumber = in->readSint32LE(); - // Protagonist if (getGameType() != GType_ITE) { int currentChapter = _scene->currentChapterNumber(); _scene->setChapterNumber(in->readSint32LE()); @@ -286,10 +288,13 @@ void SagaEngine::load(const char *fileName) { _scene->setCurrentMusicTrack(in->readSint32LE()); _scene->setCurrentMusicRepeat(in->readSint32LE()); _music->stop(); - if (getGameId() != GID_IHNM_DEMO) + if (_scene->currentChapterNumber() == 8) + _interface->setMode(kPanelChapterSelection); + if (getGameId() != GID_IHNM_DEMO) { _music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL); - else + } else { _music->play(3, MUSIC_LOOP); + } } // Inset scene @@ -323,11 +328,14 @@ void SagaEngine::load(const char *fileName) { if (getGameType() != GType_ITE) { if (_scene->currentProtag() != 0 && _scene->currentChapterNumber() != 6) { ActorData *actor1 = _actor->getFirstActor(); - // Original stores the current protagonist ID from sfSwapActors: - //ActorData *actor2 = _actor->getActor(_scene->currentProtag()); - // However, we already store the protagonist, so merely getting the saved - // protagonist is easier and safer, and works without glitches - ActorData *actor2 = _actor->_protagonist; + ActorData *actor2; + // The original gets actor2 from the current protagonist ID, but this is sometimes wrong + // If the current protagonist ID is not correct, use the stored protagonist + if (!_actor->validActorId(_scene->currentProtag())) { + actor2 = _actor->_protagonist; + } else { + actor2 = _actor->getActor(_scene->currentProtag()); + } SWAP(actor1->_location, actor2->_location); @@ -345,6 +353,7 @@ void SagaEngine::load(const char *fileName) { if (insetSceneNumber != sceneNumber) { _render->setFlag(RF_DISABLE_ACTORS); + _scene->draw(); _render->drawScene(); _render->clearFlag(RF_DISABLE_ACTORS); _scene->changeScene(insetSceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade); diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index c49fe546ee..a80b482e47 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -205,6 +205,7 @@ Scene::Scene(SagaEngine *vm) : _vm(vm) { _sceneLoaded = false; _sceneNumber = 0; + _chapterNumber = 0; _sceneResourceId = 0; _inGame = false; _loadDescription = false; @@ -281,6 +282,9 @@ void Scene::startScene() { break; } + // Stop the intro music + _vm->_music->stop(); + // Load the head in scene queue queueIterator = _sceneQueue.begin(); if (queueIterator == _sceneQueue.end()) { @@ -292,6 +296,31 @@ void Scene::startScene() { loadScene(sceneQueue); } +void Scene::creditsScene() { + // End the last game ending scene + _vm->_scene->endScene(); + // We're not in the game anymore + _inGame = false; + + // Hide cursor during credits + _vm->_gfx->showCursor(false); + + switch (_vm->getGameType()) { + case GType_ITE: + // Not called by ITE + break; + case GType_IHNM: + IHNMCreditsProc(); + break; + default: + error("Scene::creditsScene(): Error: Can't start credits scene... gametype not supported"); + break; + } + + _vm->shutDown(); + return; +} + void Scene::nextScene() { SceneQueueList::iterator queueIterator; LoadSceneParams *sceneQueue; @@ -561,6 +590,9 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { Event *q_event; static PalEntry current_pal[PAL_ENTRIES]; + if (loadSceneParams->transitionType == kTransitionFade) + _vm->_interface->setFadeMode(kFadeOut); + // Change the cursor to an hourglass in IHNM event.type = kEvTOneshot; event.code = kCursorEvent; @@ -575,19 +607,11 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { error("loadScene wrong usage"); } - if (loadSceneParams->chapter == 6) + if (loadSceneParams->chapter == 6 || loadSceneParams->chapter == 8) _vm->_interface->setLeftPortrait(0); _vm->_anim->freeCutawayList(); - // FIXME: Freed script modules are not reloaded correctly when changing chapters. - // This is apparent when returning back to the character selection screen, - // where the scene script module is loaded incorrectly - // Don't free them for now, but free them on game exit, like ITE. - // This has no impact on the game itself (other than increased memory usage), - // as each chapter uses a different module slot - // TODO: Find out why the script modules are not loaded correctly when - // changing chapters and uncomment this again - //_vm->_script->freeModules(); + _vm->_script->freeModules(); // deleteAllScenes(); @@ -612,6 +636,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _vm->_script->setVerb(_vm->_script->getVerbType(kVerbWalkTo)); if (loadSceneParams->sceneDescriptor == -2) { + _vm->_interface->setFadeMode(kNoFade); return; } } @@ -651,11 +676,11 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { debug(3, "Loading scene number %d:", _sceneNumber); - if (_vm->getGameId() == GID_IHNM_DEMO && _sceneNumber == 144) { + if (isNonInteractiveIHNMDemoPart()) { // WORKAROUND for the non-interactive part of the IHNM demo: When restarting the - // non-interactive demo, opcode sfMainMode is incorrectly called. Therefore, if the - // starting scene of the non-interactive demo is loaded (scene 144), set panel to null - // and lock the user interface + // non-interactive demo, opcode sfMainMode is incorrectly called. Therefore, if any + // of the scenes of the non-interactive demo are loaded (scenes 144-149), set panel + // to null and lock the user interface _vm->_interface->deactivate(); _vm->_interface->setMode(kPanelNull); } @@ -709,15 +734,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { q_event = NULL; - //fix placard bug - //i guess we should remove RF_PLACARD flag - and use _interface->getMode() - event.type = kEvTOneshot; - event.code = kGraphicsEvent; - event.op = kEventClearFlag; - event.param = RF_PLACARD; - - q_event = _vm->_events->chain(q_event, &event); - if (loadSceneParams->transitionType == kTransitionFade) { _vm->_interface->setFadeMode(kFadeOut); @@ -764,7 +780,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { event.param4 = _sceneNumber; // Object event.param5 = loadSceneParams->actorsEntrance; // With Object event.param6 = 0; // Actor - q_event = _vm->_events->chain(q_event, &event); } @@ -786,7 +801,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { event.time = 0; event.duration = kNormalFadeDuration; event.data = _bg.pal; - q_event = _vm->_events->chain(q_event, &event); // set fade mode @@ -807,11 +821,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _vm->_sound->stopAll(); - // FIXME: Does IHNM use scene background music, or is all the - // music scripted? At the very least, it shouldn't try - // to start song 0 at the beginning of the game, since - // it's the end credits music. - if (_vm->getGameType() == GType_ITE) { if (_sceneDescription.musicResourceId >= 0) { event.type = kEvTOneshot; @@ -820,14 +829,12 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { event.param2 = MUSIC_DEFAULT; event.op = kEventPlay; event.time = 0; - _vm->_events->queue(&event); } else { event.type = kEvTOneshot; event.code = kMusicEvent; event.op = kEventStop; event.time = 0; - _vm->_events->queue(&event); } } @@ -838,7 +845,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { event.op = kEventDisplay; event.param = kEvPSetPalette; event.time = 0; - _vm->_events->queue(&event); // Begin palette cycle animation if present @@ -846,7 +852,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { event.code = kPalAnimEvent; event.op = kEventCycleStart; event.time = 0; - q_event = _vm->_events->queue(&event); // Start the scene main script @@ -861,7 +866,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { event.param4 = _sceneNumber; // Object event.param5 = loadSceneParams->actorsEntrance; // With Object event.param6 = 0; // Actor - _vm->_events->queue(&event); } @@ -1178,7 +1182,9 @@ void Scene::endScene() { _sceneProc(SCENE_END, this); } - // + // Stop showing actors till the next scene's background is drawn from loadScene + _vm->_render->setFlag(RF_DISABLE_ACTORS); + _vm->_script->abortAllThreads(); _vm->_script->_skipSpeeches = false; @@ -1308,31 +1314,38 @@ void Scene::clearPlacard() { Event event; Event *q_event; - _vm->_interface->restoreMode(); + _vm->_interface->setFadeMode(kFadeOut); + // Fade to black out _vm->_gfx->getCurrentPal(cur_pal); - event.type = kEvTImmediate; event.code = kPalEvent; event.op = kEventPalToBlack; event.time = 0; event.duration = kNormalFadeDuration; event.data = cur_pal; - q_event = _vm->_events->queue(&event); - event.type = kEvTOneshot; - event.code = kGraphicsEvent; - event.op = kEventClearFlag; - event.param = RF_PLACARD; - + // set fade mode + event.type = kEvTImmediate; + event.code = kInterfaceEvent; + event.op = kEventSetFadeMode; + event.param = kNoFade; + event.time = 0; + event.duration = 0; q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; event.code = kTextEvent; event.op = kEventRemove; event.data = _vm->_script->getPlacardTextEntry(); + q_event = _vm->_events->chain(q_event, &event); + event.type = kEvTImmediate; + event.code = kInterfaceEvent; + event.op = kEventRestoreMode; + event.time = 0; + event.duration = 0; q_event = _vm->_events->chain(q_event, &event); _vm->_scene->getBGPal(pal); @@ -1343,20 +1356,17 @@ void Scene::clearPlacard() { event.time = 0; event.duration = kNormalFadeDuration; event.data = pal; - q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; event.code = kCursorEvent; event.op = kEventShow; - q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; event.code = kScriptEvent; event.op = kEventThreadWake; event.param = kWaitTypePlacard; - q_event = _vm->_events->chain(q_event, &event); } @@ -1378,37 +1388,37 @@ void Scene::showPsychicProfile(const char *text) { event.type = kEvTOneshot; event.code = kCursorEvent; event.op = kEventHide; - q_event = _vm->_events->queue(&event); - _vm->_gfx->getCurrentPal(cur_pal); + _vm->_interface->setFadeMode(kFadeOut); + // Fade to black out + _vm->_gfx->getCurrentPal(cur_pal); event.type = kEvTImmediate; event.code = kPalEvent; event.op = kEventPalToBlack; event.time = 0; event.duration = kNormalFadeDuration; event.data = cur_pal; - q_event = _vm->_events->chain(q_event, &event); - event.type = kEvTOneshot; + // set fade mode + event.type = kEvTImmediate; event.code = kInterfaceEvent; - event.op = kEventClearStatus; - + event.op = kEventSetFadeMode; + event.param = kNoFade; + event.time = 0; + event.duration = 0; q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; - event.code = kGraphicsEvent; - event.op = kEventSetFlag; - event.param = RF_PLACARD; - + event.code = kInterfaceEvent; + event.op = kEventClearStatus; q_event = _vm->_events->chain(q_event, &event); // Set the background and palette for the psychic profile event.type = kEvTOneshot; event.code = kPsychicProfileBgEvent; - q_event = _vm->_events->chain(q_event, &event); _vm->_scene->_textList.clear(); @@ -1432,7 +1442,6 @@ void Scene::showPsychicProfile(const char *text) { event.code = kTextEvent; event.op = kEventDisplay; event.data = _psychicProfileTextEntry; - q_event = _vm->_events->chain(q_event, &event); } @@ -1444,22 +1453,21 @@ void Scene::showPsychicProfile(const char *text) { event.time = 0; event.duration = kNormalFadeDuration; event.data = pal; - q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; event.code = kScriptEvent; event.op = kEventThreadWake; event.param = kWaitTypePlacard; - q_event = _vm->_events->chain(q_event, &event); } void Scene::clearPsychicProfile() { if (_vm->_interface->getMode() == kPanelPlacard || _vm->getGameId() == GID_IHNM_DEMO) { + _vm->_interface->restoreMode(); _vm->_scene->clearPlacard(); _vm->_scene->_textList.clear(); - _vm->_actor->showActors(false); + _vm->_render->setFlag(RF_DISABLE_ACTORS); _vm->_gfx->restorePalette(); _vm->_scene->restoreScene(); _vm->_interface->activate(); diff --git a/engines/saga/scene.h b/engines/saga/scene.h index da97bddff5..aca3f910e0 100644 --- a/engines/saga/scene.h +++ b/engines/saga/scene.h @@ -221,6 +221,7 @@ class Scene { void cmdSceneChange(int argc, const char **argv); void startScene(); + void creditsScene(); void nextScene(); void skipScene(); void endScene(); @@ -345,6 +346,10 @@ class Scene { void clearPsychicProfile(); void showIHNMDemoSpecialScreen(); + bool isNonInteractiveIHNMDemoPart() { + return _vm->getGameId() == GID_IHNM_DEMO && (_sceneNumber >= 144 && _sceneNumber <= 149); + } + private: void loadScene(LoadSceneParams *loadSceneParams); void loadSceneDescriptor(uint32 resourceId); @@ -391,17 +396,26 @@ class Scene { private: int IHNMStartProc(); + int IHNMCreditsProc(); int ITEStartProc(); + void IHNMLoadCutaways(); + bool checkKey(); + + bool playTitle(int title, int time, int mode = kPanelVideo); + bool playLoopingTitle(int title, int seconds); + public: static int SC_IHNMIntroMovieProc1(int param, void *refCon); static int SC_IHNMIntroMovieProc2(int param, void *refCon); static int SC_IHNMIntroMovieProc3(int param, void *refCon); + static int SC_IHNMCreditsMovieProc(int param, void *refCon); private: int IHNMIntroMovieProc1(int param); int IHNMIntroMovieProc2(int param); int IHNMIntroMovieProc3(int param); + int IHNMCreditsMovieProc(int param); public: static int SC_ITEIntroAnimProc(int param, void *refCon); diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp index 82fcb352c0..611975f471 100644 --- a/engines/saga/script.cpp +++ b/engines/saga/script.cpp @@ -204,6 +204,7 @@ void Script::freeModules() { for (i = 0; i < _modulesCount; i++) { if (_modules[i].loaded) { _modules[i].freeMem(); + _modules[i].loaded = false; } } _staticSize = 0; @@ -359,8 +360,6 @@ int Script::getVerbType(VerbTypes verbType) { } } else { - // TODO: This is ugly and needs rewriting, but - // it works for now switch (verbType) { case kVerbNone: return kVerbIHNMNone; @@ -507,7 +506,6 @@ void Script::doVerb() { event.param4 = _pendingObject[0]; // Object event.param5 = _pendingObject[1]; // With Object event.param6 = (objectType == kGameObjectActor) ? _pendingObject[0] : ID_PROTAG; // Actor - _vm->_events->queue(&event); } else { @@ -773,7 +771,13 @@ void Script::whichObject(const Point& mousePoint) { objectId = newObjectId; if (_vm->getGameType() == GType_ITE) objectFlags = kObjUseWith; + // Note: for IHNM, the default right button action is "Look at" for actors, + // but "Talk to" makes much more sense newRightButtonVerb = getVerbType(kVerbTalkTo); + // Slight hack because of the above change: the jukebox in Gorrister's chapter + // is an actor, so change the right button action to "Look at" + if (_vm->getGameType() == GType_IHNM && objectId == 8199) + newRightButtonVerb = getVerbType(kVerbLookAt); if ((_currentVerb == getVerbType(kVerbPickUp)) || (_currentVerb == getVerbType(kVerbOpen)) || @@ -827,6 +831,10 @@ void Script::whichObject(const Point& mousePoint) { if (newRightButtonVerb >= getVerbType(kVerbOptions)) { newRightButtonVerb = getVerbType(kVerbNone); } + } else { + if (newRightButtonVerb >= getVerbType(kVerbOptions)) { + newRightButtonVerb = getVerbType(kVerbWalkTo); + } } if ((_currentVerb == getVerbType(kVerbTalkTo)) || ((_currentVerb == getVerbType(kVerbGive)) && _firstObjectSet)) { diff --git a/engines/saga/script.h b/engines/saga/script.h index 5e5e702132..37e35cf241 100644 --- a/engines/saga/script.h +++ b/engines/saga/script.h @@ -237,7 +237,6 @@ struct ModuleData { voiceLUT.freeMem(); free(moduleBase); free(entryPoints); - memset(this, 0x0, sizeof(*this)); } }; @@ -597,7 +596,7 @@ private: void sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS); void sfGetPoints(SCRIPTFUNC_PARAMS); void sfSetGlobalFlag(SCRIPTFUNC_PARAMS); - void sf92(SCRIPTFUNC_PARAMS); + void sfDemoSetInteractive(SCRIPTFUNC_PARAMS); void sfClearGlobalFlag(SCRIPTFUNC_PARAMS); void sfTestGlobalFlag(SCRIPTFUNC_PARAMS); void sfSetPoints(SCRIPTFUNC_PARAMS); diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index c0e44584df..74f192c7f7 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -230,7 +230,7 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT OPCODE(sfShowIHNMDemoHelpPage), OPCODE(sfVstopFX), OPCODE(sfVstopLoopedFX), - OPCODE(sf92), // only used in the demo version of IHNM + OPCODE(sfDemoSetInteractive), // only used in the demo version of IHNM OPCODE(sfDemoIsInteractive), OPCODE(sfVsetTrack), OPCODE(sfGetPoints), @@ -253,8 +253,7 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT // Script function #0 (0x00) // Print a debugging message void Script::sfPutString(SCRIPTFUNC_PARAMS) { - const char *str; - str = thread->_strings->getString(thread->pop()); + const char *str = thread->_strings->getString(thread->pop()); _vm->_console->DebugPrintf("sfPutString: %s\n",str); debug(0, "sfPutString: %s", str); @@ -263,8 +262,7 @@ void Script::sfPutString(SCRIPTFUNC_PARAMS) { // Script function #1 (0x01) blocking // Param1: time in ticks void Script::sfWait(SCRIPTFUNC_PARAMS) { - int16 time; - time = thread->pop(); + int16 time = thread->pop(); if (!_skipSpeeches) { thread->waitDelay(_vm->ticksToMSec(time)); // put thread to sleep @@ -274,17 +272,17 @@ void Script::sfWait(SCRIPTFUNC_PARAMS) { // Script function #2 (0x02) void Script::sfTakeObject(SCRIPTFUNC_PARAMS) { uint16 objectId = thread->pop(); - ObjectData *obj; - obj = _vm->_actor->getObj(objectId); + ObjectData *obj = _vm->_actor->getObj(objectId); + if (obj->_sceneNumber != ITE_SCENE_INV) { obj->_sceneNumber = ITE_SCENE_INV; // 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 (obj->_spriteListResourceId == 4 && objectId == 16408) + if (objectId == 16408) obj->_spriteListResourceId = 24; - if (obj->_spriteListResourceId == 3 && objectId == 16409) + if (objectId == 16409) obj->_spriteListResourceId = 25; } @@ -297,23 +295,20 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) { void Script::sfIsCarried(SCRIPTFUNC_PARAMS) { uint16 objectId = thread->pop(); CommonObjectData *object; + if (_vm->_actor->validObjId(objectId)) { object = _vm->_actor->getObj(objectId); thread->_returnValue = (object->_sceneNumber == ITE_SCENE_INV) ? 1 : 0; } else { thread->_returnValue = 0; } - - } // Script function #4 (0x04) nonblocking // Set the command display to the specified text string // Param1: dialogue index of string void Script::sfStatusBar(SCRIPTFUNC_PARAMS) { - int16 stringIndex = thread->pop(); - - _vm->_interface->setStatusText(thread->_strings->getString(stringIndex)); + _vm->_interface->setStatusText(thread->_strings->getString(thread->pop())); } // Script function #5 (0x05) @@ -323,9 +318,29 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) { showVerb(); _vm->_interface->activate(); _vm->_interface->setMode(kPanelMain); + // Sometimes, the active cutaway is cleared after this opcode is called, + // resulting in an incorrect mode being set. An example is Ellen's chapter + // in IHNM, when using the computer with the chaos trebler CD. Make sure + // that the saved mode is kPanelMain, so that it won't get overwritten + // by an incorrect stored mode + _vm->_interface->rememberMode(); if (_vm->getGameType() == GType_ITE) setPointerVerb(); + + // The early Windows and Mac demos of ITE were non-interactive. In those demos, + // the intro is shown and then when the first scene is shown, there's a dialog + // thanking the user for playing the demo and asking him to buy the full game, + // without allowing him to continue any further. The game data itself for these + // demos does not contain any scripts for the first scene (i.e. there's no text + // in the game data to look at Rif's silver medallion). Also, there are no more + // scenes apart from the Grand Tournament scene. This opcode is called in those + // demos, and I assume that its use there is to just show the popup window and + // exit the game. Therefore, once this opcode is called in the older ITE demos, + // exit the game. Known non-interactive demos are GID_ITE_MACDEMO1 and + // GID_ITE_WINDEMO1 + if (_vm->getFeatures() & GF_NON_INTERACTIVE) + _vm->shutDown(); } // Script function #6 (0x06) blocking @@ -333,15 +348,11 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) { // Param2: actor x // Param3: actor y void Script::sfScriptWalkTo(SCRIPTFUNC_PARAMS) { - uint16 actorId; + uint16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); Location actorLocation; - ActorData *actor; - - actorId = thread->pop(); actorLocation.x = thread->pop(); actorLocation.y = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actorLocation.z = actor->_location.z; actor->_flags &= ~kFollower; @@ -357,10 +368,10 @@ void Script::sfScriptWalkTo(SCRIPTFUNC_PARAMS) { // Param3: theObject // Param4: withObject void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) { - uint16 objectId; - uint16 action; - uint16 theObject; - uint16 withObject; + uint16 objectId = thread->pop(); + uint16 action = thread->pop(); + uint16 theObject = thread->pop(); + uint16 withObject = thread->pop(); int16 scriptEntryPointNumber; int16 moduleNumber; ActorData *actor; @@ -368,11 +379,6 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) { const HitZone *hitZone; Event event; - objectId = thread->pop(); - action = thread->pop(); - theObject = thread->pop(); - withObject = thread->pop(); - switch (objectTypeId(objectId)) { case kGameObjectObject: obj = _vm->_actor->getObj(objectId); @@ -381,6 +387,8 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) { return; } moduleNumber = 0; + if (_vm->getGameType() == GType_IHNM) + moduleNumber = _vm->_scene->getScriptModuleNumber(); break; case kGameObjectActor: actor = _vm->_actor->getActor(objectId); @@ -393,6 +401,8 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) { } else { moduleNumber = _vm->_scene->getScriptModuleNumber(); } + if (_vm->getGameType() == GType_IHNM) + moduleNumber = _vm->_scene->getScriptModuleNumber(); break; case kGameObjectHitZone: case kGameObjectStepZone: @@ -421,7 +431,6 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) { event.param4 = theObject; // Object event.param5 = withObject; // With Object event.param6 = objectId; - _vm->_events->queue(&event); } @@ -429,14 +438,9 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) { // Param1: actor id // Param2: actor orientation void Script::sfSetActorFacing(SCRIPTFUNC_PARAMS) { - int16 actorId; - int actorDirection; - ActorData *actor; + ActorData *actor = _vm->_actor->getActor(thread->pop()); + int actorDirection = thread->pop(); - actorId = thread->pop(); - actorDirection = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actor->_facingDirection = actor->_actionDirection = actorDirection; actor->_targetObject = ID_NOTHING; } @@ -448,7 +452,9 @@ void Script::sfStartBgdAnim(SCRIPTFUNC_PARAMS) { _vm->_anim->setCycles(animId, cycles); _vm->_anim->setFrameTime(animId, _vm->ticksToMSec(kRepeatSpeedTicks)); - _vm->_anim->play(animId, 0); + + if (!_vm->_anim->isPlaying(animId)) + _vm->_anim->play(animId, 0); debug(1, "sfStartBgdAnim(%d, %d)", animId, cycles); } @@ -468,11 +474,7 @@ void Script::sfStopBgdAnim(SCRIPTFUNC_PARAMS) { // reenabled. // Param1: boolean void Script::sfLockUser(SCRIPTFUNC_PARAMS) { - int16 lock; - - lock = thread->pop(); - - if (lock) { + if (thread->pop()) { _vm->_interface->deactivate(); } else { _vm->_interface->activate(); @@ -485,6 +487,7 @@ void Script::sfLockUser(SCRIPTFUNC_PARAMS) { void Script::sfPreDialog(SCRIPTFUNC_PARAMS) { _vm->_interface->deactivate(); _vm->_interface->converseClear(); + if (_vm->_interface->isInMainMode()) _vm->_interface->setMode(kPanelConverse); else @@ -497,10 +500,7 @@ void Script::sfPreDialog(SCRIPTFUNC_PARAMS) { void Script::sfKillActorThreads(SCRIPTFUNC_PARAMS) { ScriptThread *anotherThread; ScriptThreadList::iterator threadIterator; - int16 actorId; - - actorId = thread->pop(); - + int16 actorId = thread->pop(); for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) { anotherThread = threadIterator.operator->(); @@ -515,34 +515,21 @@ void Script::sfKillActorThreads(SCRIPTFUNC_PARAMS) { // Param1: actor id // Param2: object id void Script::sfFaceTowards(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 targetObject; - ActorData *actor; - - actorId = thread->pop(); - targetObject = thread->pop(); - - actor = _vm->_actor->getActor(actorId); - actor->_targetObject = targetObject; + ActorData *actor = _vm->_actor->getActor(thread->pop()); + actor->_targetObject = thread->pop(); } // Script function #15 (0x0F) // Param1: actor id // Param2: target object void Script::sfSetFollower(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 targetObject; - - ActorData *actor; + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); + actor->_targetObject = thread->pop(); - actorId = thread->pop(); - targetObject = thread->pop(); + debug(1, "sfSetFollower(%d, %d) [%d]", actorId, actor->_targetObject, _vm->_actor->actorIdToIndex(actorId)); - debug(1, "sfSetFollower(%d, %d) [%d]", actorId, targetObject, _vm->_actor->actorIdToIndex(actorId)); - - actor = _vm->_actor->getActor(actorId); - actor->_targetObject = targetObject; - if (targetObject != ID_NOTHING) { + if (actor->_targetObject != ID_NOTHING) { actor->_flags |= kFollower; actor->_actorFlags &= ~kActorNoFollow; } else { @@ -552,53 +539,33 @@ void Script::sfSetFollower(SCRIPTFUNC_PARAMS) { // Script function #16 (0x10) void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { - int16 sceneNumber; - int16 entrance; - int16 transition = 0; // IHNM + int16 sceneNumber = thread->pop(); + int16 entrance = thread->pop(); - sceneNumber = thread->pop(); - entrance = thread->pop(); if (_vm->getGameType() == GType_IHNM) { - transition = thread->pop(); - _vm->_gfx->setCursor(kCursorBusy); } - if ((_vm->getGameType() == GType_ITE && sceneNumber < 0) || - (_vm->getGameType() == GType_IHNM && sceneNumber == 0)) { - // TODO: set creditsFlag to true for IHNM + if (_vm->getGameType() == GType_ITE && sceneNumber < 0) { _vm->shutDown(); return; } - if (_vm->getGameType() == GType_IHNM) { - // WORKAROUND for the briefly appearing actors at the beginning of each chapter - // This will stop the actors being drawn in those specific scenes until the scene background has been drawn - if ((_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 6) || - (_vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 31) || - (_vm->_scene->currentChapterNumber() == 3 && _vm->_scene->currentSceneNumber() == 58) || - (_vm->_scene->currentChapterNumber() == 4 && _vm->_scene->currentSceneNumber() == 68) || - (_vm->_scene->currentChapterNumber() == 5 && _vm->_scene->currentSceneNumber() == 91) || - (_vm->_scene->currentChapterNumber() == 7 && _vm->_scene->currentSceneNumber() == 145)) - _vm->_actor->showActors(false); // Stop showing actors before the background is drawn - - // Since it doesn't look like the IHNM scripts remove the - // cutaway after the intro, this is probably the best place to do it - _vm->_anim->clearCutaway(); + if (_vm->getGameType() == GType_IHNM && sceneNumber == 0) { + _vm->_scene->creditsScene(); + return; } // It is possible to leave scene when converse panel is on, // particulalrly it may happen at Moneychanger tent. This - // prevent this from happening. + // prevents this from happening. if (_vm->_interface->getMode() == kPanelConverse) { _vm->_interface->setMode(kPanelMain); } // changeScene calls loadScene which calls setVerb. setVerb resets all pending objects and object flags if (sceneNumber == -1 && _vm->getGameType() == GType_IHNM) { - // TODO: This is used to return back to the character selection screen in IHNM. - // However, it seems more than this is needed, AM's speech is wrong and no actors - // are shown + // Return back to the character selection screen in IHNM _vm->_scene->changeScene(154, entrance, kTransitionFade, 8); } else { _vm->_scene->changeScene(sceneNumber, entrance, (sceneNumber == ITE_SCENE_ENDCREDIT1) ? kTransitionFade : kTransitionNoFade); @@ -615,23 +582,27 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { _currentObject[0] = _currentObject[1] = ID_NOTHING; showVerb(); // calls setStatusText("") - if (_vm->getGameType() == GType_IHNM) + if (_vm->getGameType() == GType_IHNM) { + // There are some cutaways which are not removed by game scripts, like the cutaway + // after the intro of IHNM or the cutaway at the end of Ellen's part in the IHNM demo. + // Clear any remaining cutaways here + _vm->_anim->clearCutaway(); _vm->_gfx->setCursor(kCursorNormal); + } } // Script function #17 (0x11) // Param1: object id // Param2: sprite index void Script::sfSetObjImage(SCRIPTFUNC_PARAMS) { - uint16 objectId; - uint16 spriteId; - ObjectData *obj; - - objectId = thread->pop(); - spriteId = thread->pop(); + uint16 objectId = thread->pop(); + uint16 spriteId = thread->pop(); + ObjectData *obj = _vm->_actor->getObj(objectId); - obj = _vm->_actor->getObj(objectId); - obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId; + if (_vm->getGameType() == GType_IHNM) + obj->_spriteListResourceId = spriteId; + else + obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId; _vm->_interface->refreshInventory(); } @@ -639,26 +610,18 @@ void Script::sfSetObjImage(SCRIPTFUNC_PARAMS) { // Param1: object id // Param2: name index void Script::sfSetObjName(SCRIPTFUNC_PARAMS) { - uint16 objectId; - uint16 nameIdx; - ObjectData *obj; - - objectId = thread->pop(); - nameIdx = thread->pop(); + uint16 objectId = thread->pop(); + uint16 nameIdx = thread->pop(); + ObjectData *obj = _vm->_actor->getObj(objectId); - obj = _vm->_actor->getObj(objectId); obj->_nameIndex = nameIdx; } // Script function #19 (0x13) // Param1: object id void Script::sfGetObjImage(SCRIPTFUNC_PARAMS) { - uint16 objectId; - ObjectData *obj; - - objectId = thread->pop(); - - obj = _vm->_actor->getObj(objectId); + uint16 objectId = thread->pop(); + ObjectData *obj = _vm->_actor->getObj(objectId); if (_vm->getGameType() == GType_IHNM) thread->_returnValue = obj->_spriteListResourceId; @@ -686,8 +649,7 @@ void Script::sfGetNumber(SCRIPTFUNC_PARAMS) { // Script function #21 (0x15) // Param1: door # void Script::sfScriptOpenDoor(SCRIPTFUNC_PARAMS) { - int16 doorNumber; - doorNumber = thread->pop(); + int16 doorNumber = thread->pop(); if (_vm->_scene->getFlags() & kSceneFlagISO) { _vm->_isoMap->setTileDoorState(doorNumber, 1); @@ -699,8 +661,7 @@ void Script::sfScriptOpenDoor(SCRIPTFUNC_PARAMS) { // Script function #22 (0x16) // Param1: door # void Script::sfScriptCloseDoor(SCRIPTFUNC_PARAMS) { - int16 doorNumber; - doorNumber = thread->pop(); + int16 doorNumber = thread->pop(); if (_vm->_scene->getFlags() & kSceneFlagISO) { _vm->_isoMap->setTileDoorState(doorNumber, 0); @@ -728,10 +689,7 @@ void Script::SF_cycleColors(SCRIPTFUNC_PARAMS) { // Script function #25 (0x19) // Param1: actor id void Script::sfDoCenterActor(SCRIPTFUNC_PARAMS) { - int16 actorId; - actorId = thread->pop(); - - _vm->_actor->_centerActor = _vm->_actor->getActor(actorId); + _vm->_actor->_centerActor = _vm->_actor->getActor(thread->pop()); } // Script function #26 (0x1A) nonblocking @@ -743,7 +701,9 @@ void Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) { _vm->_anim->setCycles(animId, cycles); _vm->_anim->setFrameTime(animId, _vm->ticksToMSec(speed)); - _vm->_anim->play(animId, 0); + + if (!_vm->_anim->isPlaying(animId)) + _vm->_anim->play(animId, 0); debug(1, "sfStartBgdAnimSpeed(%d, %d, %d)", animId, cycles, speed); } @@ -753,19 +713,14 @@ void Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) { // Param2: actor x // Param3: actor y void Script::sfScriptWalkToAsync(SCRIPTFUNC_PARAMS) { - int16 actorId; + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); Location actorLocation; - ActorData *actor; - - actorId = thread->pop(); actorLocation.x = thread->pop(); actorLocation.y = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actorLocation.z = actor->_location.z; actor->_flags &= ~kFollower; - _vm->_actor->actorWalkTo(actorId, actorLocation); } @@ -797,14 +752,8 @@ void Script::sfEnableZone(SCRIPTFUNC_PARAMS) { // Param1: actor id // Param2: current action void Script::sfSetActorState(SCRIPTFUNC_PARAMS) { - int16 actorId; - int currentAction; - ActorData *actor; - - actorId = thread->pop(); - currentAction = thread->pop(); - - actor = _vm->_actor->getActor(actorId); + ActorData *actor = _vm->_actor->getActor(thread->pop()); + int currentAction = thread->pop(); if ((currentAction >= kActionWalkToPoint) && (currentAction <= kActionWalkToPoint)) { wakeUpActorThread(kWaitTypeWalk, actor); @@ -818,14 +767,12 @@ void Script::sfSetActorState(SCRIPTFUNC_PARAMS) { // Param2: actor pos x // Param3: actor pos y void Script::sfScriptMoveTo(SCRIPTFUNC_PARAMS) { - int16 objectId; + int16 objectId = thread->pop(); Location location; - ActorData *actor; - ObjectData *obj; - - objectId = thread->pop(); location.x = thread->pop(); location.y = thread->pop(); + ActorData *actor; + ObjectData *obj; if (_vm->_actor->validActorId(objectId)) { actor = _vm->_actor->getActor(objectId); @@ -854,18 +801,11 @@ void Script::sfSceneEq(SCRIPTFUNC_PARAMS) { // Script function #32 (0x20) void Script::sfDropObject(SCRIPTFUNC_PARAMS) { - uint16 objectId; - uint16 spriteId; - int16 x; - int16 y; - ObjectData *obj; - - objectId = thread->pop(); - spriteId = thread->pop(); - x = thread->pop(); - y = thread->pop(); - - obj = _vm->_actor->getObj(objectId); + uint16 objectId = thread->pop(); + ObjectData *obj = _vm->_actor->getObj(objectId); + uint16 spriteId = thread->pop(); + obj->_location.x = thread->pop(); + obj->_location.y = thread->pop(); if (obj->_sceneNumber == ITE_SCENE_INV) { _vm->_interface->removeFromInventory(objectId); @@ -873,10 +813,10 @@ void Script::sfDropObject(SCRIPTFUNC_PARAMS) { obj->_sceneNumber = _vm->_scene->currentSceneNumber(); - // WORKAROUND for the compact disk in Ellen's chapter + // HACK for the compact disk in Ellen's chapter // Change the scene number of the compact disk so that it's not shown. It will be shown // once Ellen says that there's something different (i.e. after speaking with AM) - // See Actor::actorSpeech for the other part of this workaround + // See Actor::actorSpeech for the other part of this hack if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 3 && _vm->_scene->currentSceneNumber() == 59 && obj->_id == 16385) obj->_sceneNumber = -1; @@ -891,9 +831,6 @@ void Script::sfDropObject(SCRIPTFUNC_PARAMS) { } else { obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId; } - - obj->_location.x = x; - obj->_location.y = y; } // Script function #33 (0x21) @@ -909,16 +846,10 @@ void Script::sfFinishBgdAnim(SCRIPTFUNC_PARAMS) { // Param1: actor id 1 // Param2: actor id 2 void Script::sfSwapActors(SCRIPTFUNC_PARAMS) { - int16 actorId1; - int16 actorId2; - ActorData *actor1; - ActorData *actor2; - - actorId1 = thread->pop(); - actorId2 = thread->pop(); - - actor1 = _vm->_actor->getActor(actorId1); - actor2 = _vm->_actor->getActor(actorId2); + int16 actorId1 = thread->pop(); + int16 actorId2 = thread->pop(); + ActorData *actor1 = _vm->_actor->getActor(actorId1); + ActorData *actor2 = _vm->_actor->getActor(actorId2); SWAP(actor1->_location, actor2->_location); @@ -944,24 +875,19 @@ void Script::sfSwapActors(SCRIPTFUNC_PARAMS) { ///.... // Param3: actor idN void Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) { - int16 stringId; - int16 actorsCount; + int16 stringId = thread->pop(); + int16 actorsCount = thread->pop(); int i; uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX]; - const char *string; + const char *string = thread->_strings->getString(stringId); int16 sampleResourceId = -1; - stringId = thread->pop(); - actorsCount = thread->pop(); - if (actorsCount > ACTOR_SPEECH_ACTORS_MAX) error("sfSimulSpeech actorsCount=0x%X exceed ACTOR_SPEECH_ACTORS_MAX", actorsCount); for (i = 0; i < actorsCount; i++) actorsIds[i] = thread->pop(); - string = thread->_strings->getString(stringId); - if (thread->_voiceLUT->voices) { if (_vm->getGameType() == GType_IHNM && stringId >= 338) { sampleResourceId = -1; @@ -982,22 +908,16 @@ void Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) { // Param3: actor y // Param4: actor walk flag void Script::sfScriptWalk(SCRIPTFUNC_PARAMS) { - int16 actorId; + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); Location actorLocation; - ActorData *actor; - uint16 walkFlags; - - actorId = thread->pop(); actorLocation.x = thread->pop(); actorLocation.y = thread->pop(); - walkFlags = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actorLocation.z = actor->_location.z; - - _vm->_actor->realLocation(actorLocation, ID_NOTHING, walkFlags); + uint16 walkFlags = thread->pop(); actor->_flags &= ~kFollower; + _vm->_actor->realLocation(actorLocation, ID_NOTHING, walkFlags); if (_vm->_actor->actorWalkTo(actorId, actorLocation) && !(walkFlags & kWalkAsync)) { thread->waitWalk(actor); @@ -1016,18 +936,10 @@ void Script::sfScriptWalk(SCRIPTFUNC_PARAMS) { // Param3: cycle frame number // Param4: cycle delay void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 flags; - int cycleFrameSequence; - int cycleDelay; - ActorData *actor; - - actorId = thread->pop(); - flags = thread->pop(); - cycleFrameSequence = thread->pop(); - cycleDelay = thread->pop(); - - actor = _vm->_actor->getActor(actorId); + ActorData *actor = _vm->_actor->getActor(thread->pop()); + int16 flags = thread->pop(); + int cycleFrameSequence = thread->pop(); + int cycleDelay = thread->pop(); if (flags & kCyclePong) { actor->_currentAction = kActionPongFrames; @@ -1046,8 +958,8 @@ void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) { if (flags & kCycleReverse) { if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 41) { - // Prevent Benny from walking backwards after talking to the child via the monitor. This occurs in the - // original as well, and is fixed by not setting the kActorBackwards flag at this point + // WORKAROUND: Prevent Benny from walking backwards after talking to the child via the monitor. This + // occurs in the original as well, and is fixed by not setting the kActorBackwards flag at this point } else { actor->_actorFlags |= kActorBackwards; } @@ -1064,19 +976,11 @@ void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) { // Param2: frame type // Param3: frame offset void Script::sfSetFrame(SCRIPTFUNC_PARAMS) { - int16 actorId; - int frameType; - int frameOffset; - ActorData *actor; - ActorFrameRange *frameRange; - - actorId = thread->pop(); - frameType = thread->pop(); - frameOffset = thread->pop(); - - actor = _vm->_actor->getActor(actorId); - - frameRange = _vm->_actor->getActorFrameRange(actorId, frameType); + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); + int frameType = thread->pop(); + int frameOffset = thread->pop(); + ActorFrameRange *frameRange = _vm->_actor->getActorFrameRange(actorId, frameType); actor->_frameNumber = frameRange->frameIndex + frameOffset; @@ -1088,17 +992,13 @@ void Script::sfSetFrame(SCRIPTFUNC_PARAMS) { // Script function #39 (0x27) // Sets the right-hand portrait void Script::sfSetPortrait(SCRIPTFUNC_PARAMS) { - int16 param = thread->pop(); - - _vm->_interface->setRightPortrait(param); + _vm->_interface->setRightPortrait(thread->pop()); } // Script function #40 (0x28) // Sets the left-hand portrait void Script::sfSetProtagPortrait(SCRIPTFUNC_PARAMS) { - int16 param = thread->pop(); - - _vm->_interface->setLeftPortrait(param); + _vm->_interface->setLeftPortrait(thread->pop()); } // Script function #41 (0x29) nonblocking @@ -1130,21 +1030,15 @@ void Script::sfChainBgdAnim(SCRIPTFUNC_PARAMS) { // Param3: actor y // Param4: frame seq void Script::sfScriptSpecialWalk(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 walkFrameSequence; + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); Location actorLocation; - ActorData *actor; - - actorId = thread->pop(); actorLocation.x = thread->pop(); actorLocation.y = thread->pop(); - walkFrameSequence = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actorLocation.z = actor->_location.z; + int16 walkFrameSequence = thread->pop(); _vm->_actor->actorWalkTo(actorId, actorLocation); - actor->_walkFrameSequence = walkFrameSequence; } @@ -1156,39 +1050,20 @@ void Script::sfScriptSpecialWalk(SCRIPTFUNC_PARAMS) { // Param5: actor action // Param6: actor frame number void Script::sfPlaceActor(SCRIPTFUNC_PARAMS) { - int16 actorId; - Location actorLocation; - int actorDirection; - int frameType; - int frameOffset; - ActorData *actor; + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); + actor->_location.x = thread->pop(); + actor->_location.y = thread->pop(); + actor->_facingDirection = actor->_actionDirection = thread->pop(); + int frameType = thread->pop(); + int frameOffset = thread->pop(); ActorFrameRange *frameRange; - actorId = thread->pop(); - actorLocation.x = thread->pop(); - actorLocation.y = thread->pop(); - actorDirection = thread->pop(); - frameType = thread->pop(); - frameOffset = thread->pop(); - - debug(1, "sfPlaceActor(id = 0x%x, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actorLocation.x, - actorLocation.y, actorDirection, frameType, frameOffset); - - actor = _vm->_actor->getActor(actorId); - actor->_location.x = actorLocation.x; - actor->_location.y = actorLocation.y; - actor->_facingDirection = actor->_actionDirection = actorDirection; - - if (!actor->_frames) - _vm->_actor->loadActorResources(actor); //? is not it already loaded ? + debug(1, "sfPlaceActor(id = 0x%x, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actor->_location.x, + actor->_location.y, actor->_facingDirection, frameType, frameOffset); if (frameType >= 0) { frameRange = _vm->_actor->getActorFrameRange(actorId, frameType); - - if (frameRange->frameCount <= frameOffset) { - warning("Wrong frameOffset 0x%X", frameOffset); - } - actor->_frameNumber = frameRange->frameIndex + frameOffset; actor->_currentAction = kActionFreeze; } else { @@ -1213,24 +1088,17 @@ void Script::sfCheckUserInterrupt(SCRIPTFUNC_PARAMS) { // Param4: actor y // Param5: actor walk flag void Script::sfScriptWalkRelative(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 objectId; - uint16 walkFlags; + int16 actorId = thread->pop(); + ActorData *actor = _vm->_actor->getActor(actorId); + int16 objectId = thread->pop(); Location actorLocation; - ActorData *actor; - - actorId = thread->pop(); - objectId = thread->pop(); actorLocation.x = thread->pop(); actorLocation.y = thread->pop(); - walkFlags = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actorLocation.z = actor->_location.z; - - _vm->_actor->realLocation(actorLocation, objectId, walkFlags); + uint16 walkFlags = thread->pop(); actor->_flags &= ~kFollower; + _vm->_actor->realLocation(actorLocation, objectId, walkFlags); if (_vm->_actor->actorWalkTo(actorId, actorLocation) && !(walkFlags & kWalkAsync)) { thread->waitWalk(actor); @@ -1250,50 +1118,36 @@ void Script::sfScriptWalkRelative(SCRIPTFUNC_PARAMS) { // Param4: actor y // Param5: actor walk flag void Script::sfScriptMoveRelative(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 objectId; - uint16 walkFlags; + ActorData *actor = _vm->_actor->getActor(thread->pop()); + int16 objectId = thread->pop(); Location actorLocation; - ActorData *actor; - - actorId = thread->pop(); - objectId = thread->pop(); actorLocation.x = thread->pop(); actorLocation.y = thread->pop(); - walkFlags = thread->pop(); - - actor = _vm->_actor->getActor(actorId); actorLocation.z = actor->_location.z; + uint16 walkFlags = thread->pop(); _vm->_actor->realLocation(actorLocation, objectId, walkFlags); - actor->_location = actorLocation; actor->_actorFlags = (actor->_actorFlags & ~kActorFacingMask) | (walkFlags & kActorFacingMask); } // Script function #47 (0x2F) void Script::sfSimulSpeech2(SCRIPTFUNC_PARAMS) { - int16 stringId; - int16 actorsCount; - int16 speechFlags; + int16 stringId = thread->pop(); + const char *string = thread->_strings->getString(stringId); + int16 actorsCount = thread->pop(); + int16 speechFlags = thread->pop(); int i; uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX]; - const char *string; int16 sampleResourceId = -1; - stringId = thread->pop(); - actorsCount = thread->pop(); - speechFlags = thread->pop(); - if (actorsCount > ACTOR_SPEECH_ACTORS_MAX) error("sfSimulSpeech2 actorsCount=0x%X exceed ACTOR_SPEECH_ACTORS_MAX", actorsCount); for (i = 0; i < actorsCount; i++) actorsIds[i] = thread->pop(); - string = thread->_strings->getString(stringId); - if (thread->_voiceLUT->voices) { sampleResourceId = thread->_voiceLUT->voices[stringId]; if (sampleResourceId <= 0 || sampleResourceId > 4000) @@ -1308,7 +1162,7 @@ void Script::sfSimulSpeech2(SCRIPTFUNC_PARAMS) { // Script function #48 (0x30) // Param1: string rid void Script::sfPlacard(SCRIPTFUNC_PARAMS) { - int stringId; + int stringId = thread->pop(); Surface *backBuffer = _vm->_gfx->getBackBuffer(); static PalEntry cur_pal[PAL_ENTRIES]; PalEntry *pal; @@ -1320,36 +1174,35 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) { _vm->_interface->rememberMode(); _vm->_interface->setMode(kPanelPlacard); - stringId = thread->pop(); - event.type = kEvTOneshot; event.code = kCursorEvent; event.op = kEventHide; - q_event = _vm->_events->queue(&event); - _vm->_gfx->getCurrentPal(cur_pal); + _vm->_interface->setFadeMode(kFadeOut); + // Fade to black out + _vm->_gfx->getCurrentPal(cur_pal); event.type = kEvTImmediate; event.code = kPalEvent; event.op = kEventPalToBlack; event.time = 0; event.duration = kNormalFadeDuration; event.data = cur_pal; - q_event = _vm->_events->chain(q_event, &event); - event.type = kEvTOneshot; + // set fade mode + event.type = kEvTImmediate; event.code = kInterfaceEvent; - event.op = kEventClearStatus; - + event.op = kEventSetFadeMode; + event.param = kNoFade; + event.time = 0; + event.duration = 0; q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; - event.code = kGraphicsEvent; - event.op = kEventSetFlag; - event.param = RF_PLACARD; - + event.code = kInterfaceEvent; + event.op = kEventClearStatus; q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; @@ -1361,7 +1214,6 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) { event.param3 = _vm->_scene->getHeight(); event.param4 = 0; event.param5 = _vm->getDisplayWidth(); - q_event = _vm->_events->chain(q_event, &event); // Put the text in the center of the viewport, assuming it will fit on @@ -1386,25 +1238,21 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) { event.code = kTextEvent; event.op = kEventDisplay; event.data = _placardTextEntry; - q_event = _vm->_events->chain(q_event, &event); _vm->_scene->getBGPal(pal); - event.type = kEvTImmediate; event.code = kPalEvent; event.op = kEventBlackToPal; event.time = 0; event.duration = kNormalFadeDuration; event.data = pal; - q_event = _vm->_events->chain(q_event, &event); event.type = kEvTOneshot; event.code = kScriptEvent; event.op = kEventThreadWake; event.param = kWaitTypePlacard; - q_event = _vm->_events->chain(q_event, &event); } @@ -1419,8 +1267,7 @@ void Script::sfPlacardOff(SCRIPTFUNC_PARAMS) { void Script::sfPsychicProfile(SCRIPTFUNC_PARAMS) { thread->wait(kWaitTypePlacard); - int stringId = thread->pop(); - _vm->_scene->showPsychicProfile(thread->_strings->getString(stringId)); + _vm->_scene->showPsychicProfile(thread->_strings->getString(thread->pop())); } void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) { @@ -1433,9 +1280,7 @@ void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) { // Script function #50 (0x32) void Script::sfSetProtagState(SCRIPTFUNC_PARAMS) { - int protagState = thread->pop(); - - _vm->_actor->setProtagState(protagState); + _vm->_actor->setProtagState(thread->pop()); } // Script function #51 (0x33) @@ -1456,28 +1301,20 @@ void Script::sfResumeBgdAnim(SCRIPTFUNC_PARAMS) { // Param5: actionCycle // Param6: flags void Script::sfThrowActor(SCRIPTFUNC_PARAMS) { - int16 actorId; - ActorData *actor; - int16 flags; - int32 actionCycle; - Location location; + ActorData *actor = _vm->_actor->getActor(thread->pop()); + actor->_finalTarget.x = thread->pop(); + actor->_finalTarget.y = thread->pop(); + actor->_finalTarget.z = actor->_location.z; + thread->pop(); // not used + int32 actionCycle = thread->pop(); + int16 flags = thread->pop(); - actorId = thread->pop(); - location.x = thread->pop(); - location.y = thread->pop(); - thread->pop(); - actionCycle = thread->pop(); - flags = thread->pop(); - - actor = _vm->_actor->getActor(actorId); - location.z = actor->_location.z; actor->_currentAction = kActionFall; actor->_actionCycle = actionCycle; actor->_fallAcceleration = -20; actor->_fallVelocity = - (actor->_fallAcceleration * actor->_actionCycle) / 2; - actor->_fallPosition = actor->_location.z << 4; + actor->_fallPosition = actor->_location.z << 4; - actor->_finalTarget = location; actor->_actionCycle--; if (!(flags & kWalkAsync)) { thread->waitWalk(actor); @@ -1488,11 +1325,7 @@ void Script::sfThrowActor(SCRIPTFUNC_PARAMS) { // Param1: actor id // Param2: target object void Script::sfWaitWalk(SCRIPTFUNC_PARAMS) { - int16 actorId; - ActorData *actor; - - actorId = thread->pop(); - actor = _vm->_actor->getActor(actorId); + ActorData *actor = _vm->_actor->getActor(thread->pop()); if ((actor->_currentAction == kActionWalkToPoint) || (actor->_currentAction == kActionWalkToLink) || @@ -1510,14 +1343,8 @@ void Script::sfScriptSceneID(SCRIPTFUNC_PARAMS) { // Param1: actor id // Param2: scene number void Script::sfChangeActorScene(SCRIPTFUNC_PARAMS) { - int16 actorId; - int32 sceneNumber; - ActorData *actor; - - actorId = thread->pop(); - sceneNumber = thread->pop(); - actor = _vm->_actor->getActor(actorId); - actor->_sceneNumber = sceneNumber; + ActorData *actor = _vm->_actor->getActor(thread->pop()); + actor->_sceneNumber = thread->pop(); } // Script function #56 (0x38) @@ -1526,19 +1353,11 @@ void Script::sfChangeActorScene(SCRIPTFUNC_PARAMS) { // Param3: frame seq // Param4: flags void Script::sfScriptClimb(SCRIPTFUNC_PARAMS) { - int16 actorId; - int16 z; - ActorData *actor; - uint16 flags; - int cycleFrameSequence; - - actorId = thread->pop(); - z = thread->pop(); - cycleFrameSequence = thread->pop(); - flags = thread->pop(); + ActorData *actor = _vm->_actor->getActor(thread->pop()); + actor->_finalTarget.z = thread->pop(); + int cycleFrameSequence = thread->pop(); + uint16 flags = thread->pop(); - actor = _vm->_actor->getActor(actorId); - actor->_finalTarget.z = z; actor->_flags &= ~kFollower; actor->_actionCycle = 1; actor->_cycleFrameSequence = cycleFrameSequence; @@ -1552,10 +1371,8 @@ void Script::sfScriptClimb(SCRIPTFUNC_PARAMS) { // Param1: door # // Param2: door state void Script::sfSetDoorState(SCRIPTFUNC_PARAMS) { - int16 doorNumber; - int16 doorState; - doorNumber = thread->pop(); - doorState = thread->pop(); + int16 doorNumber = thread->pop(); + int16 doorState = thread->pop(); if (_vm->_scene->getFlags() & kSceneFlagISO) { _vm->_isoMap->setTileDoorState(doorNumber, doorState); @@ -1568,14 +1385,10 @@ void Script::sfSetDoorState(SCRIPTFUNC_PARAMS) { // Param1: actor id // Param2: z void Script::sfSetActorZ(SCRIPTFUNC_PARAMS) { - int16 objectId; + int16 objectId = thread->pop(); + int16 z = thread->pop(); ActorData *actor; ObjectData *obj; - int16 z; - - objectId = thread->pop(); - z = thread->pop(); - if (_vm->_actor->validActorId(objectId)) { actor = _vm->_actor->getActor(objectId); @@ -1595,22 +1408,15 @@ void Script::sfSetActorZ(SCRIPTFUNC_PARAMS) { // Param4: x // Param5: y void Script::sfScriptText(SCRIPTFUNC_PARAMS) { - int16 stringId; - int16 flags; - Rect rect; - int color; + const char *text = thread->_strings->getString(thread->pop()); + int16 flags = thread->pop(); + int color = thread->pop(); Point point; - int width; - const char*text; - stringId = thread->pop(); - flags = thread->pop(); - color = thread->pop(); point.x = thread->pop(); point.y = thread->pop(); + Rect rect; + int width = _vm->_font->getStringWidth(kKnownFontScript, text, 0, kFontOutline); - text = thread->_strings->getString(stringId); - - width = _vm->_font->getStringWidth(kKnownFontScript, text, 0, kFontOutline); rect.top = point.y - 6; rect.setHeight(12); rect.left = point.x - width / 2; @@ -1623,11 +1429,7 @@ void Script::sfScriptText(SCRIPTFUNC_PARAMS) { // Script function #60 (0x3C) // Param1: actor id void Script::sfGetActorX(SCRIPTFUNC_PARAMS) { - int16 actorId; - ActorData *actor; - - actorId = thread->pop(); - actor = _vm->_actor->getActor(actorId); + ActorData *actor = _vm->_actor->getActor(thread->pop()); thread->_returnValue = actor->_location.x >> 2; } @@ -1635,23 +1437,17 @@ void Script::sfGetActorX(SCRIPTFUNC_PARAMS) { // Script function #61 (0x3D) // Param1: actor id void Script::sfGetActorY(SCRIPTFUNC_PARAMS) { - int16 actorId; - ActorData *actor; - - actorId = thread->pop(); - actor = _vm->_actor->getActor(actorId); + ActorData *actor = _vm->_actor->getActor(thread->pop()); thread->_returnValue = actor->_location.y >> 2; } // Script function #62 (0x3E) void Script::sfEraseDelta(SCRIPTFUNC_PARAMS) { - Surface *backGroundSurface; + Surface *backGroundSurface = _vm->_render->getBackGroundSurface(); BGInfo backGroundInfo; - backGroundSurface = _vm->_render->getBackGroundSurface(); _vm->_scene->getBGInfo(backGroundInfo); - backGroundSurface->blit(backGroundInfo.bounds, backGroundInfo.buffer); } @@ -1712,12 +1508,11 @@ void Script::sfPickClimbOutPos(SCRIPTFUNC_PARAMS) { // Script function #65 (0x41) void Script::sfTossRif(SCRIPTFUNC_PARAMS) { - int16 uc , vc; uint16 direction; ActorData *protagonist = _vm->_actor->_protagonist; + int16 uc = protagonist->_location.u() >> 4; + int16 vc = protagonist->_location.v() >> 4; - uc = protagonist->_location.u() >> 4; - vc = protagonist->_location.v() >> 4; if (_vm->_isoMap->findNearestChasm(uc, vc, direction)) { uc <<= 4; vc <<= 4; @@ -1793,10 +1588,9 @@ void Script::sfPlayLoopedSound(SCRIPTFUNC_PARAMS) { } // Script function #72 (0x48) +// Param1: animation id void Script::sfGetDeltaFrame(SCRIPTFUNC_PARAMS) { - uint16 animId = (uint16)thread->pop(); - - thread->_returnValue = _vm->_anim->getCurrentFrame(animId); + thread->_returnValue = _vm->_anim->getCurrentFrame((uint16)thread->pop()); } // Script function #73 (0x49) @@ -1813,10 +1607,8 @@ void Script::sfProtectResult(SCRIPTFUNC_PARAMS) { if (_vm->_copyProtection) { thread->_returnValue = _vm->_interface->getProtectHash(); } else { - int protectHash; - //cheating - protectHash = thread->pop(); + int protectHash = thread->pop(); thread->push(protectHash); thread->_returnValue = protectHash; } @@ -1824,10 +1616,7 @@ void Script::sfProtectResult(SCRIPTFUNC_PARAMS) { // Script function #75 (0x4b) void Script::sfRand(SCRIPTFUNC_PARAMS) { - int16 param; - - param = thread->pop(); - thread->_returnValue = _vm->_rnd.getRandomNumber(param - 1); + thread->_returnValue = _vm->_rnd.getRandomNumber(thread->pop() - 1); } // Script function #76 (0x4c) @@ -1839,7 +1628,6 @@ void Script::sfFadeMusic(SCRIPTFUNC_PARAMS) { void Script::sfPlayVoice(SCRIPTFUNC_PARAMS) { int16 param = thread->pop(); - warning("sfPlayVoice(%d)", param); if (param > 0) { _vm->_sndRes->playVoice(param + 3712); } else { @@ -1881,13 +1669,24 @@ void Script::finishDialog(int strID, int replyID, int flags, int bitOffset) { } void Script::sfSetChapterPoints(SCRIPTFUNC_PARAMS) { - int16 ethics = thread->pop(); - int16 barometer = thread->pop(); int chapter = _vm->_scene->currentChapterNumber(); + _vm->_ethicsPoints[chapter] = thread->pop(); + int16 barometer = thread->pop(); + static PalEntry cur_pal[PAL_ENTRIES]; - _vm->_ethicsPoints[chapter] = ethics; - _vm->_spiritualBarometer = ethics * 256 / barometer; + _vm->_spiritualBarometer = _vm->_ethicsPoints[chapter] * 256 / barometer; _vm->_scene->setChapterPointsChanged(true); // don't save this music when saving in IHNM + + if (_vm->_spiritualBarometer > 255) + _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff); + else + _vm->_gfx->setPaletteColor(kIHNMColorPortrait, + _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.red / 256, + _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.green / 256, + _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.blue / 256); + + _vm->_gfx->getCurrentPal(cur_pal); + _vm->_gfx->setPalette(cur_pal); } void Script::sfSetPortraitBgColor(SCRIPTFUNC_PARAMS) { @@ -1899,12 +1698,9 @@ void Script::sfSetPortraitBgColor(SCRIPTFUNC_PARAMS) { } void Script::sfScriptStartCutAway(SCRIPTFUNC_PARAMS) { - int16 cut; - int16 fade; - - cut = thread->pop(); + int16 cut = thread->pop(); thread->pop(); // Not used - fade = thread->pop(); + int16 fade = thread->pop(); _vm->_anim->setCutAwayMode(kPanelCutaway); _vm->_anim->playCutaway(cut, fade != 0); @@ -1930,61 +1726,37 @@ void Script::sfResetMouseClicks(SCRIPTFUNC_PARAMS) { // Used in IHNM only // Param1: frames void Script::sfWaitFrames(SCRIPTFUNC_PARAMS) { - int16 frames; - frames = thread->pop(); - - // HACK for the nightfall scene in Benny's chapter - // sfWaitFrames is supposed to wait for fadein and fadeout during that cutaway, but we - // don't support it yet (function sfScriptFade). This is a temporary hack to avoid - // having ScummVM wait for ever in that cutaway - // FIXME: Remove this hack once the palette fading is properly handled - if (_vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 41 && _vm->_anim->hasCutaway()) - return; + int16 frames = thread->pop(); if (!_skipSpeeches) thread->waitFrames(_vm->_frameCount + frames); } void Script::sfScriptFade(SCRIPTFUNC_PARAMS) { - thread->pop(); // first pal entry, ignored (already handled by Gfx::palToBlack) - thread->pop(); // last pal entry, ignored (already handled by Gfx::palToBlack) + int16 firstPalEntry = thread->pop(); + int16 lastPalEntry = thread->pop(); int16 startingBrightness = thread->pop(); int16 endingBrightness = thread->pop(); - // delay between pal changes is always 10 (not used) - static PalEntry cur_pal[PAL_ENTRIES]; Event event; - short delta = (startingBrightness < endingBrightness) ? +1 : -1; + static PalEntry cur_pal[PAL_ENTRIES]; _vm->_gfx->getCurrentPal(cur_pal); - - // TODO: This is still wrong, probably a new event type needs to be added (kEventPalFade) - warning("TODO: sfScriptFade"); - return; - - if (startingBrightness > 255) - startingBrightness = 255; - if (startingBrightness < 0 ) - startingBrightness = 0; - if (endingBrightness > 255) - endingBrightness = 255; - if (endingBrightness < 0) - endingBrightness = 0; - event.type = kEvTImmediate; event.code = kPalEvent; - event.op = kEventPalToBlack; + event.op = kEventPalFade; event.time = 0; - event.duration = kNormalFadeDuration - ((endingBrightness - startingBrightness) * delta); + event.duration = kNormalFadeDuration; event.data = cur_pal; - - _vm->_events->queue(&event); + event.param = startingBrightness; + event.param2 = endingBrightness; + event.param3 = firstPalEntry; + event.param4 = lastPalEntry - firstPalEntry + 1; + _vm->_events->queue(&event); } void Script::sfScriptStartVideo(SCRIPTFUNC_PARAMS) { - int16 vid; - int16 fade; - vid = thread->pop(); - fade = thread->pop(); + int16 vid = thread->pop(); + int16 fade = thread->pop(); _vm->_anim->setCutAwayMode(kPanelVideo); _vm->_anim->startVideo(vid, fade != 0); @@ -2006,14 +1778,10 @@ void Script::sfShowIHNMDemoHelpBg(SCRIPTFUNC_PARAMS) { } void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) { - int stringId, textHeight; + int stringId = thread->pop(); TextListEntry textEntry; Event event; - stringId = thread->pop(); - - textHeight = _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered); - textEntry.knownColor = kKnownColorBlack; textEntry.useRect = true; textEntry.rect.left = 245; @@ -2030,10 +1798,9 @@ void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) { event.code = kTextEvent; event.op = kEventDisplay; event.data = _psychicProfileTextEntry; - _vm->_events->queue(&event); - _ihnmDemoCurrentY += 10; + _ihnmDemoCurrentY += _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered); } void Script::sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS) { @@ -2051,9 +1818,14 @@ void Script::sfVstopLoopedFX(SCRIPTFUNC_PARAMS) { _vm->_sound->stopSound(); } -void Script::sf92(SCRIPTFUNC_PARAMS) { - SF_stub("sf92", thread, nArgs); - // This opcode is empty in the full version of IHNM, but it's not empty in the demo +void Script::sfDemoSetInteractive(SCRIPTFUNC_PARAMS) { + if (thread->pop() == 0) { + _vm->_interface->deactivate(); + _vm->_interface->setMode(kPanelNull); + } + + // Note: the original also sets an appropriate flag here, but we don't, + // as we don't use it } void Script::sfDemoIsInteractive(SCRIPTFUNC_PARAMS) { @@ -2159,7 +1931,6 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) { // change // FIXME: If this is too short for other cases apart from chapter // point change, set it back to 1000 - _vm->_events->queue(&event); if (!_vm->_scene->haveChapterPointsChanged()) { @@ -2173,9 +1944,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) { } void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) { - int value = thread->pop(); - - _vm->_interface->disableAbortSpeeches(value != 0); + _vm->_interface->disableAbortSpeeches(thread->pop() != 0); } void Script::sfNull(SCRIPTFUNC_PARAMS) { diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index edbdebabab..ac21656dfa 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -101,8 +101,7 @@ SndRes::~SndRes() { } } -void SndRes::setVoiceBank(int serial) -{ +void SndRes::setVoiceBank(int serial) { if (_voiceSerial == serial) return; _voiceSerial = serial; @@ -183,9 +182,9 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } bool uncompressedSound = false; - // If a patch file exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed - if (_vm->getGameType() == GType_ITE && resourceId == 4 && - (Common::File::exists("sound/p2_a.iaf") || Common::File::exists("sound/p2_a.voc"))) + // If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed + // Patch data for this resource is in file p2_a.iaf or p2_a.voc + if (_vm->getGameType() == GType_ITE && resourceId == 4 && context->table[resourceId].patchData != NULL) uncompressedSound = true; // FIXME: Currently, the SFX.RES file in IHNM cannot be compressed diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 187a45b836..38517c1d69 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -523,7 +523,7 @@ void Actor_v2::walkActor() { if (_moving & MF_TURN) { new_dir = updateActorDirection(false); - // FIXME -- is this correct? + // FIXME: is this correct? if (_facing != new_dir) setDirection(new_dir); else @@ -670,7 +670,7 @@ int Actor::remapDirection(int dir, bool is_walking) { bool flipX; bool flipY; - // FIXME - It seems that at least in The Dig the original code does + // FIXME: It seems that at least in The Dig the original code does // check _ignoreBoxes here. However, it breaks some animations in Loom, // causing Bobbin to face towards the camera instead of away from it // in some places: After the tree has been destroyed by lightning, and @@ -1446,7 +1446,7 @@ void Actor::drawActorCostume(bool hitTestMode) { bcr->_actorX *= V12_X_MULTIPLIER; bcr->_actorY *= V12_Y_MULTIPLIER; } - bcr->_actorX -= _vm->virtscr[0].xstart; + bcr->_actorX -= _vm->_virtscr[kMainVirtScreen].xstart; if (_vm->_game.platform == Common::kPlatformNES) { // In the NES version, when the actor is facing right, @@ -1532,7 +1532,7 @@ void Actor::drawActorCostume(bool hitTestMode) { _heNoTalkAnimation = 0; // If the actor is partially hidden, redraw it next frame. - if (bcr->drawCostume(_vm->virtscr[0], _vm->_gdi->_numStrips, this, _drawToBackBuf) & 1) { + if (bcr->drawCostume(_vm->_virtscr[kMainVirtScreen], _vm->_gdi->_numStrips, this, _drawToBackBuf) & 1) { _needRedraw = (_vm->_game.version <= 6); } @@ -1902,7 +1902,7 @@ void ScummEngine::actorTalk(const byte *msg) { convertMessageToString(msg, _charsetBuffer, sizeof(_charsetBuffer)); - // FIXME: Workaround for bugs #770039 and #770049 + // WORKAROUND for bugs #770039 and #770049 if (_game.id == GID_LOOM) { if (!*_charsetBuffer) return; @@ -2325,7 +2325,7 @@ void ScummEngine_v71he::postProcessAuxQueue() { int y = (int16)READ_LE_UINT16(axfd + 4) + dy; int w = (int16)READ_LE_UINT16(axfd + 6); int h = (int16)READ_LE_UINT16(axfd + 8); - VirtScreen *pvs = &virtscr[kMainVirtScreen]; + VirtScreen *pvs = &_virtscr[kMainVirtScreen]; uint8 *dst1 = pvs->getPixels(0, pvs->topline); uint8 *dst2 = pvs->getBackPixels(0, pvs->topline); switch (comp) { diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp index c8667d7ab2..86a19540d6 100644 --- a/engines/scumm/akos.cpp +++ b/engines/scumm/akos.cpp @@ -546,7 +546,7 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { scaleytab = &v1.scaletable[v1.scaleYindex]; maskbit = revBitMask(v1.x & 7); - mask = _vm->getMaskBuffer(v1.x - (_vm->virtscr[0].xstart & 7), v1.y, _zbuf); + mask = _vm->getMaskBuffer(v1.x - (_vm->_virtscr[kMainVirtScreen].xstart & 7), v1.y, _zbuf); if (len) goto StartPos; @@ -610,17 +610,13 @@ void AkosRenderer::codec1_genericDecode(Codec1 &v1) { skip_column = true; v1.scaleXindex += v1.scaleXstep; dst = v1.destptr; - mask = _vm->getMaskBuffer(v1.x - (_vm->virtscr[0].xstart & 7), v1.y, _zbuf); + mask = _vm->getMaskBuffer(v1.x - (_vm->_virtscr[kMainVirtScreen].xstart & 7), v1.y, _zbuf); } StartPos:; } while (--len); } while (1); } -#ifdef PALMOS_68K -const byte *bigCostumeScaleTable; -const byte *smallCostumeScaleTableAKOS; -#else // This is exact duplicate of smallCostumeScaleTable[] in costume.cpp // See FIXME below for explanation const byte smallCostumeScaleTableAKOS[256] = { @@ -757,7 +753,6 @@ const byte bigCostumeScaleTable[768] = { 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF, }; -#endif byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) { int num_colors; @@ -987,8 +982,8 @@ byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) { } void AkosRenderer::markRectAsDirty(Common::Rect rect) { - rect.left -= _vm->virtscr[0].xstart & 7; - rect.right -= _vm->virtscr[0].xstart & 7; + rect.left -= _vm->_virtscr[kMainVirtScreen].xstart & 7; + rect.right -= _vm->_virtscr[kMainVirtScreen].xstart & 7; _vm->markRectAsDirty(kMainVirtScreen, rect, _actorID); } @@ -1862,18 +1857,3 @@ void ScummEngine_v7::akos_processQueue() { #endif } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Akos) -_GSETPTR(Scumm::bigCostumeScaleTable, GBVARS_BIGSCALETABLE_INDEX, byte, GBVARS_SCUMM) -//_GSETPTR(Scumm::smallCostumeScaleTableAKOS, GBVARS_SMALLSCALETABLEAKOS_INDEX, byte, GBVARS_SCUMM) -_GEND - -_GRELEASE(Akos) -_GRELEASEPTR(GBVARS_BIGSCALETABLE_INDEX, GBVARS_SCUMM) -//_GRELEASEPTR(GBVARS_SMALLSCALETABLEAKOS_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/base-costume.cpp b/engines/scumm/base-costume.cpp index 8886dbfcd4..fe87dc65ec 100644 --- a/engines/scumm/base-costume.cpp +++ b/engines/scumm/base-costume.cpp @@ -39,9 +39,9 @@ byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, int numStrips, const else _out.pixels = vs.getPixels(0, 0); - _actorX += _vm->virtscr[0].xstart & 7; + _actorX += _vm->_virtscr[kMainVirtScreen].xstart & 7; _out.w = _out.pitch; - _out.pixels = (byte *)_out.pixels - (_vm->virtscr[0].xstart & 7); + _out.pixels = (byte *)_out.pixels - (_vm->_virtscr[kMainVirtScreen].xstart & 7); _numStrips = numStrips; diff --git a/engines/scumm/base-costume.h b/engines/scumm/base-costume.h index 155bbff97f..7acaff2679 100644 --- a/engines/scumm/base-costume.h +++ b/engines/scumm/base-costume.h @@ -42,15 +42,8 @@ struct CostumeInfo { #include "common/pack-end.h" // END STRUCT PACKING - -#ifdef PALMOS_68K -extern const byte *smallCostumeScaleTable; -extern const byte *bigCostumeScaleTable; -#else extern const byte smallCostumeScaleTable[256]; extern const byte bigCostumeScaleTable[768]; -#endif - class Actor; diff --git a/engines/scumm/camera.cpp b/engines/scumm/camera.cpp index d6ecc715ea..ea6ac9b528 100644 --- a/engines/scumm/camera.cpp +++ b/engines/scumm/camera.cpp @@ -199,7 +199,7 @@ void ScummEngine::cameraMoved() { screenLeft = _screenStartStrip * 8; } - virtscr[0].xstart = screenLeft; + _virtscr[kMainVirtScreen].xstart = screenLeft; } void ScummEngine::panCameraTo(int x, int y) { diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 2271bf53a1..6eb6cfd7c6 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -50,10 +50,7 @@ void ScummEngine::loadCJKFont() { _useCJKMode = false; _textSurfaceMultiplier = 1; - if (_game.platform == Common::kPlatformSegaCD) - return; - - if (_language == Common::JA_JPN && _game.version <= 5) { // FM-TOWNS v3 / v5 Kanji + if (_game.version <= 5 && _game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN) { // FM-TOWNS v3 / v5 Kanji int numChar = 256 * 32; _2byteWidth = 16; _2byteHeight = 16; @@ -66,7 +63,7 @@ void ScummEngine::loadCJKFont() { fp.close(); } _textSurfaceMultiplier = 2; - } else if (_language == Common::KO_KOR || _language == Common::JA_JPN || _language == Common::ZH_TWN) { + } else if (_game.version >= 7 && (_language == Common::KO_KOR || _language == Common::JA_JPN || _language == Common::ZH_TWN)) { int numChar = 0; const char *fontFile = NULL; @@ -77,7 +74,7 @@ void ScummEngine::loadCJKFont() { break; case Common::JA_JPN: fontFile = (_game.id == GID_DIG) ? "kanji16.fnt" : "japanese.fnt"; - numChar = 1024; //FIXME + numChar = 1024; //FIXME: sev needs japanese font files to clarify font size break; case Common::ZH_TWN: if (_game.id == GID_CMI) { @@ -501,13 +498,6 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) { setCurID(oldID); } -#ifdef PALMOS_68K -static const byte *englishCharsetDataV2; -static const byte *germanCharsetDataV2; -static const byte *frenchCharsetDataV2; -static const byte *italianCharsetDataV2; -static const byte *spanishCharsetDataV2; -#else // English Zak font static const byte englishCharsetDataV2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1168,7 +1158,6 @@ static const byte spanishCharsetDataV2[] = { 0x1c, 0x36, 0x36, 0x7c, 0x66, 0x66, 0x7c, 0x40, 0x08, 0x0c, 0x0e, 0xff, 0xff, 0x0e, 0x0c, 0x08, }; -#endif CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language) : CharsetRendererV3(vm) { @@ -1237,8 +1226,7 @@ int CharsetRendererV3::getCharWidth(byte chr) { return spacing; } -void CharsetRendererV3::setColor(byte color) -{ +void CharsetRendererV3::setColor(byte color) { bool useShadow = false; _color = color; @@ -1769,7 +1757,7 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) { int drawTop = _top; if (ignoreCharsetMask) { - VirtScreen *vs = &_vm->virtscr[kMainVirtScreen]; + VirtScreen *vs = &_vm->_virtscr[kMainVirtScreen]; s = *vs; s.pixels = vs->getPixels(0, 0); } else { @@ -1893,24 +1881,3 @@ void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const } } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Charset) -_GSETPTR(Scumm::germanCharsetDataV2, GBVARS_GERMANCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM) -_GSETPTR(Scumm::frenchCharsetDataV2, GBVARS_FRENCHCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM) -_GSETPTR(Scumm::englishCharsetDataV2, GBVARS_ENGLISHCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM) -_GSETPTR(Scumm::italianCharsetDataV2, GBVARS_ITALIANCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM) -_GSETPTR(Scumm::spanishCharsetDataV2, GBVARS_SPANISHCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM) -_GEND - -_GRELEASE(Charset) -_GRELEASEPTR(GBVARS_GERMANCHARSETDATAV2_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FRENCHCHARSETDATAV2_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_ENGLISHCHARSETDATAV2_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_ITALIANCHARSETDATAV2_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_SPANISHCHARSETDATAV2_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 2c5be5bf21..ac61d39d25 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -32,9 +32,6 @@ namespace Scumm { -#ifdef PALMOS_68K -const byte *smallCostumeScaleTable; -#else const byte smallCostumeScaleTable[256] = { 0xFF, 0xFD, 0x7D, 0xBD, 0x3D, 0xDD, 0x5D, 0x9D, 0x1D, 0xED, 0x6D, 0xAD, 0x2D, 0xCD, 0x4D, 0x8D, @@ -69,7 +66,6 @@ const byte smallCostumeScaleTable[256] = { 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE }; -#endif static const int v1MMNESLookup[25] = { 0x00, 0x03, 0x01, 0x06, 0x08, @@ -1165,16 +1161,3 @@ byte C64CostumeLoader::increaseAnim(Actor *a, int slot) { } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Costume) -_GSETPTR(Scumm::smallCostumeScaleTable, GBVARS_SMALLSCALETABLE_INDEX, byte, GBVARS_SCUMM) -_GEND - -_GRELEASE(Costume) -_GRELEASEPTR(GBVARS_SMALLSCALETABLE_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 23657946c6..b8b2cbcb6d 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -236,7 +236,7 @@ void ScummEngine_v6::setCursorFromImg(uint img, uint room, uint imgindex) { } void ScummEngine_v6::useIm01Cursor(const byte *im, int w, int h) { - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; byte *buf, *dst; const byte *src; int i; diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp index 83ba9e24c1..68a001c983 100644 --- a/engines/scumm/debugger.cpp +++ b/engines/scumm/debugger.cpp @@ -652,7 +652,7 @@ static int gfxPrimitivesCompareInt(const void *a, const void *b); static void hlineColor(ScummEngine *scumm, int x1, int x2, int y, byte color) { - VirtScreen *vs = &scumm->virtscr[0]; + VirtScreen *vs = &scumm->_virtscr[kMainVirtScreen]; byte *ptr; // Clip y diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index be830cab64..90c6e40aa7 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/scumm/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -56,11 +56,7 @@ static int compareMD5Table(const void *a, const void *b) { } static const MD5Table *findInMD5Table(const char *md5) { -#ifdef PALMOS_68K - uint32 arraySize = MemPtrSize((void *)md5table) / sizeof(MD5Table) - 1; -#else uint32 arraySize = ARRAYSIZE(md5table) - 1; -#endif return (const MD5Table *)bsearch(md5, md5table, arraySize, sizeof(MD5Table), compareMD5Table); } @@ -886,11 +882,9 @@ PluginError Engine_SCUMM_create(OSystem *syst, Engine **engine) { *engine = new ScummEngine_v70he(syst, res); break; #endif -#ifndef PALMOS_68K case 61: *engine = new ScummEngine_v60he(syst, res); break; -#endif default: *engine = new ScummEngine_v6(syst, res); } @@ -913,16 +907,3 @@ PluginError Engine_SCUMM_create(OSystem *syst, Engine **engine) { REGISTER_PLUGIN(SCUMM, "Scumm Engine", "LucasArts SCUMM Games (C) LucasArts\n" "Humongous SCUMM Games (C) Humongous" ); - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Scumm_md5table) -_GSETPTR(md5table, GBVARS_MD5TABLE_INDEX, MD5Table, GBVARS_SCUMM) -_GEND - -_GRELEASE(Scumm_md5table) -_GRELEASEPTR(GBVARS_MD5TABLE_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h index d0fefe3a29..bc67aafb7e 100644 --- a/engines/scumm/detection.h +++ b/engines/scumm/detection.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/scumm/detection.h $ - * $Id:detection.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index acde4e5ad0..70118b9baf 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/scumm/detection_tables.h $ - * $Id:detection_tables.h 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ @@ -37,11 +37,7 @@ //#include "scumm/intern.h" //#include "scumm/he/intern_he.h" -#ifdef PALMOS_68K -#include "extras/palm-scumm-md5.h" -#else #include "scumm/scumm-md5.h" -#endif namespace Scumm { @@ -399,6 +395,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "maniac", "Maniac Mansion (SW).prg", kGenUnchanged, Common::SE_SWE, Common::kPlatformNES, "NES" }, { "maniac", "Maniac Mansion (U).prg", kGenUnchanged, Common::EN_USA, Common::kPlatformNES, "NES" }, { "maniac", "Maniac Mansion (G).prg", kGenUnchanged, Common::DE_DEU, Common::kPlatformNES, "NES" }, + { "maniac", "Maniac Mansion (Sp).prg", kGenUnchanged, Common::ES_ESP, Common::kPlatformNES, "NES" }, { "zak", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, { "zak", "zak1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, 0 }, // ... and zak2.d64 diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 85a72cb090..1666578c4c 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -81,11 +81,6 @@ struct ResString { char string[80]; }; -#ifdef PALMOS_68K -static const ResString *string_map_table_v7; -static const ResString *string_map_table_v6; -static const ResString *string_map_table_v5; -#else static const ResString string_map_table_v8[] = { {0, "/BT_100/Please insert disk %d. Press ENTER"}, {0, "/BT__003/Unable to Find %s, (%s %d) Press Button."}, @@ -216,7 +211,6 @@ static const ResString string_map_table_v345[] = { {20, "Select a game to LOAD"}, {28, "Game title"} }; -#endif #pragma mark - @@ -967,20 +961,3 @@ void Indy3IQPointsDialog::handleKeyDown(Common::KeyState state) { } } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Dialogs) -_GSETPTR(Scumm::string_map_table_v7, GBVARS_STRINGMAPTABLEV7_INDEX, Scumm::ResString, GBVARS_SCUMM) -_GSETPTR(Scumm::string_map_table_v6, GBVARS_STRINGMAPTABLEV6_INDEX, Scumm::ResString, GBVARS_SCUMM) -_GSETPTR(Scumm::string_map_table_v5, GBVARS_STRINGMAPTABLEV5_INDEX, Scumm::ResString, GBVARS_SCUMM) -_GEND - -_GRELEASE(Dialogs) -_GRELEASEPTR(GBVARS_STRINGMAPTABLEV7_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_STRINGMAPTABLEV6_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_STRINGMAPTABLEV5_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index 2c7f9ead5b..b80be63d32 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -24,9 +24,6 @@ */ #include "scumm/file.h" -#include "common/endian.h" -#include "common/util.h" -#include "common/md5.h" #include "scumm/scumm.h" @@ -196,1275 +193,6 @@ uint32 ScummFile::write(const void *, uint32) { } #pragma mark - -#pragma mark --- ScummNESFile --- -#pragma mark - - -enum ResType { - NES_UNKNOWN, - NES_GLOBDATA, - NES_ROOM, - NES_SCRIPT, - NES_SOUND, - NES_COSTUME, - NES_ROOMGFX, - NES_COSTUMEGFX, - NES_SPRPALS, - NES_SPRDESC, - NES_SPRLENS, - NES_SPROFFS, - NES_SPRDATA, - NES_CHARSET, - NES_PREPLIST -}; - -struct ScummNESFile::Resource { - uint32 offset; - uint16 length; - ResType type; -}; - -ScummNESFile::ScummNESFile() : _stream(0), _buf(0), _ROMset(kROMsetNum) { -} - -uint32 ScummNESFile::write(const void *, uint32) { - error("ScummNESFile does not support writing!"); - return 0; -} - -void ScummNESFile::setEnc(byte enc) { - _stream->setEnc(enc); -} - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_roomgfx_usa; -static const ScummNESFile::Resource *res_roomgfx_eur; -static const ScummNESFile::Resource *res_roomgfx_swe; -static const ScummNESFile::Resource *res_roomgfx_fra; -static const ScummNESFile::Resource *res_roomgfx_ger; -#else -static const ScummNESFile::Resource res_roomgfx_usa[40] = { - { 0x04001, 0x03C9, NES_ROOMGFX }, { 0x043CA, 0x069E, NES_ROOMGFX }, { 0x04A68, 0x0327, NES_ROOMGFX }, { 0x04D8F, 0x053B, NES_ROOMGFX }, { 0x052CA, 0x06BE, NES_ROOMGFX }, - { 0x05988, 0x0682, NES_ROOMGFX }, { 0x0600A, 0x0778, NES_ROOMGFX }, { 0x06782, 0x0517, NES_ROOMGFX }, { 0x06C99, 0x07FB, NES_ROOMGFX }, { 0x07494, 0x07BE, NES_ROOMGFX }, - { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x0846, NES_ROOMGFX }, { 0x09BB3, 0x08C8, NES_ROOMGFX }, - { 0x0A47B, 0x0844, NES_ROOMGFX }, { 0x0ACBF, 0x0515, NES_ROOMGFX }, { 0x0B1D4, 0x0799, NES_ROOMGFX }, { 0x0B96D, 0x04BB, NES_ROOMGFX }, { 0x07C52, 0x0319, NES_ROOMGFX }, - { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x076D, NES_ROOMGFX }, { 0x0CBD2, 0x0827, NES_ROOMGFX }, { 0x0D3F9, 0x0515, NES_ROOMGFX }, { 0x0D90E, 0x064E, NES_ROOMGFX }, - { 0x0DF5C, 0x0775, NES_ROOMGFX }, { 0x0E6D1, 0x06DD, NES_ROOMGFX }, { 0x0EDAE, 0x0376, NES_ROOMGFX }, { 0x0F124, 0x05F7, NES_ROOMGFX }, { 0x0F71B, 0x0787, NES_ROOMGFX }, - { 0x10001, 0x02D6, NES_ROOMGFX }, { 0x102D7, 0x06A3, NES_ROOMGFX }, { 0x1097A, 0x099F, NES_ROOMGFX }, { 0x11319, 0x0361, NES_ROOMGFX }, { 0x1167A, 0x0489, NES_ROOMGFX }, - { 0x11B03, 0x0437, NES_ROOMGFX }, { 0x11F3A, 0x084D, NES_ROOMGFX }, { 0x0BE28, 0x0199, NES_ROOMGFX }, { 0x12787, 0x09A7, NES_ROOMGFX }, { 0x1312E, 0x037A, NES_ROOMGFX } -}; -static const ScummNESFile::Resource res_roomgfx_eur[40] = { - { 0x04001, 0x03B9, NES_ROOMGFX }, { 0x043BA, 0x069E, NES_ROOMGFX }, { 0x04A58, 0x0327, NES_ROOMGFX }, { 0x04D7F, 0x053B, NES_ROOMGFX }, { 0x052BA, 0x06BE, NES_ROOMGFX }, - { 0x05978, 0x0682, NES_ROOMGFX }, { 0x05FFA, 0x0778, NES_ROOMGFX }, { 0x06772, 0x0517, NES_ROOMGFX }, { 0x06C89, 0x07FB, NES_ROOMGFX }, { 0x07484, 0x07BE, NES_ROOMGFX }, - { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x0846, NES_ROOMGFX }, { 0x09BB3, 0x08C8, NES_ROOMGFX }, - { 0x0A47B, 0x0844, NES_ROOMGFX }, { 0x0ACBF, 0x0515, NES_ROOMGFX }, { 0x0B1D4, 0x0799, NES_ROOMGFX }, { 0x0B96D, 0x04BB, NES_ROOMGFX }, { 0x07C42, 0x0319, NES_ROOMGFX }, - { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x076D, NES_ROOMGFX }, { 0x0CBD2, 0x0827, NES_ROOMGFX }, { 0x0D3F9, 0x0515, NES_ROOMGFX }, { 0x0D90E, 0x064E, NES_ROOMGFX }, - { 0x0DF5C, 0x0775, NES_ROOMGFX }, { 0x0E6D1, 0x06DD, NES_ROOMGFX }, { 0x0EDAE, 0x0376, NES_ROOMGFX }, { 0x0F124, 0x05F7, NES_ROOMGFX }, { 0x0F71B, 0x0787, NES_ROOMGFX }, - { 0x10001, 0x02D6, NES_ROOMGFX }, { 0x102D7, 0x06A3, NES_ROOMGFX }, { 0x1097A, 0x099F, NES_ROOMGFX }, { 0x11319, 0x0361, NES_ROOMGFX }, { 0x1167A, 0x0489, NES_ROOMGFX }, - { 0x11B03, 0x0437, NES_ROOMGFX }, { 0x11F3A, 0x084D, NES_ROOMGFX }, { 0x12787, 0x0199, NES_ROOMGFX }, { 0x12920, 0x09A7, NES_ROOMGFX }, { 0x132C7, 0x037A, NES_ROOMGFX } -}; -static const ScummNESFile::Resource res_roomgfx_swe[40] = { - { 0x04001, 0x03F0, NES_ROOMGFX }, { 0x043F1, 0x069E, NES_ROOMGFX }, { 0x04A8F, 0x0327, NES_ROOMGFX }, { 0x04DB6, 0x053B, NES_ROOMGFX }, { 0x052F1, 0x06BE, NES_ROOMGFX }, - { 0x059AF, 0x0682, NES_ROOMGFX }, { 0x06031, 0x0778, NES_ROOMGFX }, { 0x067A9, 0x0517, NES_ROOMGFX }, { 0x06CC0, 0x07FB, NES_ROOMGFX }, { 0x074BB, 0x07BE, NES_ROOMGFX }, - { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, - { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04BF, NES_ROOMGFX }, { 0x0BC02, 0x0319, NES_ROOMGFX }, - { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, - { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x0791, NES_ROOMGFX }, - { 0x07C79, 0x02D6, NES_ROOMGFX }, { 0x10001, 0x06A3, NES_ROOMGFX }, { 0x106A4, 0x0921, NES_ROOMGFX }, { 0x10FC5, 0x0361, NES_ROOMGFX }, { 0x11326, 0x0489, NES_ROOMGFX }, - { 0x117AF, 0x0437, NES_ROOMGFX }, { 0x11BE6, 0x084F, NES_ROOMGFX }, { 0x12435, 0x0199, NES_ROOMGFX }, { 0x125CE, 0x0947, NES_ROOMGFX }, { 0x12F15, 0x037A, NES_ROOMGFX } -}; -static const ScummNESFile::Resource res_roomgfx_fra[40] = { - { 0x04001, 0x0426, NES_ROOMGFX }, { 0x04427, 0x069E, NES_ROOMGFX }, { 0x04AC5, 0x0327, NES_ROOMGFX }, { 0x04DEC, 0x053B, NES_ROOMGFX }, { 0x05327, 0x06BE, NES_ROOMGFX }, - { 0x059E5, 0x0682, NES_ROOMGFX }, { 0x06067, 0x0778, NES_ROOMGFX }, { 0x067DF, 0x0517, NES_ROOMGFX }, { 0x06CF6, 0x07FB, NES_ROOMGFX }, { 0x074F1, 0x07BE, NES_ROOMGFX }, - { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, - { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04BB, NES_ROOMGFX }, { 0x0BBFE, 0x0319, NES_ROOMGFX }, - { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, - { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x0787, NES_ROOMGFX }, - { 0x10001, 0x02D6, NES_ROOMGFX }, { 0x102D7, 0x06A3, NES_ROOMGFX }, { 0x1097A, 0x0921, NES_ROOMGFX }, { 0x1129B, 0x0361, NES_ROOMGFX }, { 0x115FC, 0x0489, NES_ROOMGFX }, - { 0x11A85, 0x0437, NES_ROOMGFX }, { 0x11EBC, 0x070D, NES_ROOMGFX }, { 0x07CAF, 0x0199, NES_ROOMGFX }, { 0x125C9, 0x0947, NES_ROOMGFX }, { 0x12F10, 0x037A, NES_ROOMGFX } -}; -static const ScummNESFile::Resource res_roomgfx_ger[40] = { - { 0x04001, 0x0406, NES_ROOMGFX }, { 0x04407, 0x069E, NES_ROOMGFX }, { 0x04AA5, 0x0327, NES_ROOMGFX }, { 0x04DCC, 0x053B, NES_ROOMGFX }, { 0x05307, 0x06BE, NES_ROOMGFX }, - { 0x059C5, 0x0682, NES_ROOMGFX }, { 0x06047, 0x0778, NES_ROOMGFX }, { 0x067BF, 0x0517, NES_ROOMGFX }, { 0x06CD6, 0x07FB, NES_ROOMGFX }, { 0x074D1, 0x07BE, NES_ROOMGFX }, - { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, - { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04BB, NES_ROOMGFX }, { 0x0BBFE, 0x0319, NES_ROOMGFX }, - { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, - { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x0787, NES_ROOMGFX }, - { 0x07C8F, 0x02D6, NES_ROOMGFX }, { 0x10001, 0x06A3, NES_ROOMGFX }, { 0x106A4, 0x0921, NES_ROOMGFX }, { 0x10FC5, 0x0361, NES_ROOMGFX }, { 0x11326, 0x0489, NES_ROOMGFX }, - { 0x117AF, 0x0437, NES_ROOMGFX }, { 0x11BE6, 0x07A0, NES_ROOMGFX }, { 0x12386, 0x0199, NES_ROOMGFX }, { 0x1251F, 0x0947, NES_ROOMGFX }, { 0x12E66, 0x037A, NES_ROOMGFX } -}; -#endif -static const ScummNESFile::Resource *res_roomgfx[ScummNESFile::kROMsetNum] = { - res_roomgfx_usa, - res_roomgfx_eur, - res_roomgfx_swe, - res_roomgfx_fra, - res_roomgfx_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_costumegfx_usa; -static const ScummNESFile::Resource *res_costumegfx_eur; -static const ScummNESFile::Resource *res_costumegfx_swe; -static const ScummNESFile::Resource *res_costumegfx_fra; -static const ScummNESFile::Resource *res_costumegfx_ger; -#else -static const ScummNESFile::Resource res_costumegfx_usa[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F9F1, 0x0340, NES_COSTUMEGFX } }; -static const ScummNESFile::Resource res_costumegfx_eur[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F9F1, 0x0340, NES_COSTUMEGFX } }; -static const ScummNESFile::Resource res_costumegfx_swe[2] = { { 0x2EFE1, 0x0EB8, NES_COSTUMEGFX }, { 0x30001, 0x0340, NES_COSTUMEGFX } }; -static const ScummNESFile::Resource res_costumegfx_fra[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F608, 0x0340, NES_COSTUMEGFX } }; -static const ScummNESFile::Resource res_costumegfx_ger[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F4CE, 0x0340, NES_COSTUMEGFX } }; -#endif -static const ScummNESFile::Resource *res_costumegfx[ScummNESFile::kROMsetNum] = { - res_costumegfx_usa, - res_costumegfx_eur, - res_costumegfx_swe, - res_costumegfx_fra, - res_costumegfx_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_rooms_usa; -static const ScummNESFile::Resource *res_rooms_eur; -static const ScummNESFile::Resource *res_rooms_swe; -static const ScummNESFile::Resource *res_rooms_fra; -static const ScummNESFile::Resource *res_rooms_ger; -#else -static const ScummNESFile::Resource res_rooms_usa[55] = { - { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D0C, NES_ROOM }, { 0x134A8, 0x04B3, NES_ROOM }, { 0x15397, 0x0849, NES_ROOM }, { 0x15C68, 0x0685, NES_ROOM }, - { 0x16381, 0x0715, NES_ROOM }, { 0x1395B, 0x04E7, NES_ROOM }, { 0x16CE8, 0x0AC0, NES_ROOM }, { 0x18001, 0x06BA, NES_ROOM }, { 0x17AED, 0x03CB, NES_ROOM }, - { 0x18BE7, 0x0663, NES_ROOM }, { 0x192A6, 0x0580, NES_ROOM }, { 0x19A44, 0x0443, NES_ROOM }, { 0x1A106, 0x0563, NES_ROOM }, { 0x1A669, 0x0446, NES_ROOM }, - { 0x1AAAF, 0x03A7, NES_ROOM }, { 0x1AE56, 0x07E3, NES_ROOM }, { 0x1B699, 0x0692, NES_ROOM }, { 0x1C001, 0x0B49, NES_ROOM }, { 0x1CD09, 0x04C6, NES_ROOM }, - { 0x1D4C2, 0x0568, NES_ROOM }, { 0x1DF6C, 0x0514, NES_ROOM }, { 0x1E8FA, 0x05CC, NES_ROOM }, { 0x1EF83, 0x0389, NES_ROOM }, { 0x1F5E4, 0x0723, NES_ROOM }, - { 0x20001, 0x049A, NES_ROOM }, { 0x20511, 0x04F8, NES_ROOM }, { 0x21666, 0x05CB, NES_ROOM }, { 0x21DD6, 0x046B, NES_ROOM }, { 0x222F0, 0x0460, NES_ROOM }, - { 0x227B6, 0x0909, NES_ROOM }, { 0x24001, 0x0366, NES_ROOM }, { 0x23BDF, 0x03CA, NES_ROOM }, { 0x247DB, 0x050D, NES_ROOM }, { 0x25ACF, 0x0346, NES_ROOM }, - { 0x1BDBD, 0x01CA, NES_ROOM }, { 0x25E15, 0x0457, NES_ROOM }, { 0x2626C, 0x0547, NES_ROOM }, { 0x267B3, 0x064A, NES_ROOM }, { 0x1FD72, 0x024B, NES_ROOM }, - { 0x2739A, 0x01FA, NES_ROOM }, { 0x2766D, 0x0219, NES_ROOM }, { 0x28001, 0x02F4, NES_ROOM }, { 0x284D6, 0x045C, NES_ROOM }, { 0x289A3, 0x09CF, NES_ROOM }, - { 0x293C6, 0x05A0, NES_ROOM }, { 0x27B65, 0x0201, NES_ROOM }, { 0x2ADD1, 0x0325, NES_ROOM }, { 0x2B339, 0x01FC, NES_ROOM }, { 0x2B535, 0x02A9, NES_ROOM }, - { 0x2B7DE, 0x02DE, NES_ROOM }, { 0x2C001, 0x03CE, NES_ROOM }, { 0x2BBC0, 0x0205, NES_ROOM }, { 0x2C53A, 0x0170, NES_ROOM }, { 0x13E42, 0x0169, NES_ROOM } -}; -static const ScummNESFile::Resource res_rooms_eur[55] = { - { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D0C, NES_ROOM }, { 0x13641, 0x04B3, NES_ROOM }, { 0x15397, 0x0849, NES_ROOM }, { 0x15C68, 0x0685, NES_ROOM }, - { 0x16381, 0x0715, NES_ROOM }, { 0x16CE8, 0x04E7, NES_ROOM }, { 0x18001, 0x0ABF, NES_ROOM }, { 0x171CF, 0x06BA, NES_ROOM }, { 0x13AF4, 0x03D2, NES_ROOM }, - { 0x18E1A, 0x0663, NES_ROOM }, { 0x194D9, 0x04A9, NES_ROOM }, { 0x19BA0, 0x0443, NES_ROOM }, { 0x1A262, 0x047C, NES_ROOM }, { 0x1A6DE, 0x0446, NES_ROOM }, - { 0x1AB24, 0x03A7, NES_ROOM }, { 0x1AECB, 0x07E3, NES_ROOM }, { 0x1B70E, 0x0692, NES_ROOM }, { 0x1C001, 0x0ACA, NES_ROOM }, { 0x1CC8A, 0x04C6, NES_ROOM }, - { 0x1D443, 0x0568, NES_ROOM }, { 0x1DEED, 0x0514, NES_ROOM }, { 0x1E87B, 0x05CC, NES_ROOM }, { 0x1EF04, 0x0389, NES_ROOM }, { 0x1F565, 0x0723, NES_ROOM }, - { 0x20001, 0x049A, NES_ROOM }, { 0x20511, 0x04F8, NES_ROOM }, { 0x21666, 0x05D5, NES_ROOM }, { 0x21DE0, 0x046B, NES_ROOM }, { 0x222FA, 0x0460, NES_ROOM }, - { 0x227C0, 0x0909, NES_ROOM }, { 0x24001, 0x0366, NES_ROOM }, { 0x247DB, 0x03CA, NES_ROOM }, { 0x24BA5, 0x050D, NES_ROOM }, { 0x23BE9, 0x0346, NES_ROOM }, - { 0x17DB5, 0x01CA, NES_ROOM }, { 0x25E99, 0x0457, NES_ROOM }, { 0x262F0, 0x0547, NES_ROOM }, { 0x26837, 0x064A, NES_ROOM }, { 0x1FCF3, 0x024B, NES_ROOM }, - { 0x2741E, 0x01FA, NES_ROOM }, { 0x276F1, 0x0219, NES_ROOM }, { 0x28001, 0x02F4, NES_ROOM }, { 0x284D6, 0x045C, NES_ROOM }, { 0x289A3, 0x09CF, NES_ROOM }, - { 0x293C6, 0x05A0, NES_ROOM }, { 0x27BE9, 0x0201, NES_ROOM }, { 0x2ADE3, 0x0325, NES_ROOM }, { 0x2B34B, 0x01FC, NES_ROOM }, { 0x2B547, 0x02A9, NES_ROOM }, - { 0x2B7F0, 0x02DE, NES_ROOM }, { 0x2C001, 0x03CE, NES_ROOM }, { 0x2BBD2, 0x0205, NES_ROOM }, { 0x2C53A, 0x0170, NES_ROOM }, { 0x2BDD7, 0x0169, NES_ROOM } -}; -static const ScummNESFile::Resource res_rooms_swe[55] = { - { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D12, NES_ROOM }, { 0x1328F, 0x04B3, NES_ROOM }, { 0x15367, 0x0859, NES_ROOM }, { 0x13742, 0x0694, NES_ROOM }, - { 0x15C45, 0x0707, NES_ROOM }, { 0x1658F, 0x04E0, NES_ROOM }, { 0x16A6F, 0x0AC8, NES_ROOM }, { 0x18001, 0x06C7, NES_ROOM }, { 0x1789C, 0x03EA, NES_ROOM }, - { 0x18C09, 0x0649, NES_ROOM }, { 0x192AE, 0x04AB, NES_ROOM }, { 0x19982, 0x0447, NES_ROOM }, { 0x1A04D, 0x047E, NES_ROOM }, { 0x1A4CB, 0x0444, NES_ROOM }, - { 0x1A90F, 0x03B9, NES_ROOM }, { 0x1ACC8, 0x07E9, NES_ROOM }, { 0x1B511, 0x06A4, NES_ROOM }, { 0x1C001, 0x0B1A, NES_ROOM }, { 0x1CCFD, 0x0486, NES_ROOM }, - { 0x1D482, 0x0579, NES_ROOM }, { 0x1DF61, 0x051E, NES_ROOM }, { 0x1E8EC, 0x05CF, NES_ROOM }, { 0x1EF73, 0x0398, NES_ROOM }, { 0x1F5F0, 0x071A, NES_ROOM }, - { 0x20001, 0x049C, NES_ROOM }, { 0x2051E, 0x051E, NES_ROOM }, { 0x21725, 0x05D5, NES_ROOM }, { 0x21EA5, 0x047F, NES_ROOM }, { 0x223D1, 0x0460, NES_ROOM }, - { 0x22897, 0x090D, NES_ROOM }, { 0x24001, 0x0378, NES_ROOM }, { 0x247C9, 0x03CA, NES_ROOM }, { 0x24B93, 0x050D, NES_ROOM }, { 0x25267, 0x0346, NES_ROOM }, - { 0x17CD0, 0x01CA, NES_ROOM }, { 0x255AD, 0x0453, NES_ROOM }, { 0x25A00, 0x053E, NES_ROOM }, { 0x25F3E, 0x0647, NES_ROOM }, { 0x1BC49, 0x024B, NES_ROOM }, - { 0x26B58, 0x01FA, NES_ROOM }, { 0x26E27, 0x0217, NES_ROOM }, { 0x27345, 0x02F4, NES_ROOM }, { 0x27829, 0x045C, NES_ROOM }, { 0x28001, 0x098A, NES_ROOM }, - { 0x289DF, 0x05A1, NES_ROOM }, { 0x2A442, 0x0201, NES_ROOM }, { 0x2A6E9, 0x0325, NES_ROOM }, { 0x1FD75, 0x01FC, NES_ROOM }, { 0x2AC64, 0x02A9, NES_ROOM }, - { 0x2AF0D, 0x02D1, NES_ROOM }, { 0x2B2E6, 0x03CC, NES_ROOM }, { 0x23D61, 0x0205, NES_ROOM }, { 0x2B818, 0x0168, NES_ROOM }, { 0x27CF6, 0x0169, NES_ROOM } -}; -static const ScummNESFile::Resource res_rooms_fra[55] = { - { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D76, NES_ROOM }, { 0x1328A, 0x04C6, NES_ROOM }, { 0x15451, 0x0885, NES_ROOM }, { 0x13750, 0x0693, NES_ROOM }, - { 0x15D68, 0x0709, NES_ROOM }, { 0x166D4, 0x0528, NES_ROOM }, { 0x16BFC, 0x0ACC, NES_ROOM }, { 0x18001, 0x06E2, NES_ROOM }, { 0x17A63, 0x03E5, NES_ROOM }, - { 0x18C3B, 0x066A, NES_ROOM }, { 0x19301, 0x049E, NES_ROOM }, { 0x199C8, 0x044B, NES_ROOM }, { 0x1A0B1, 0x0478, NES_ROOM }, { 0x1A529, 0x043F, NES_ROOM }, - { 0x1A968, 0x03C8, NES_ROOM }, { 0x1AD30, 0x086F, NES_ROOM }, { 0x1B5FF, 0x069B, NES_ROOM }, { 0x1C001, 0x0AA9, NES_ROOM }, { 0x1CC97, 0x049E, NES_ROOM }, - { 0x1D42C, 0x05A8, NES_ROOM }, { 0x1DF71, 0x054E, NES_ROOM }, { 0x1E9D1, 0x0606, NES_ROOM }, { 0x1F0A2, 0x039A, NES_ROOM }, { 0x1F74E, 0x071C, NES_ROOM }, - { 0x20001, 0x04B5, NES_ROOM }, { 0x2052E, 0x04FF, NES_ROOM }, { 0x2172E, 0x05DB, NES_ROOM }, { 0x21EAD, 0x0489, NES_ROOM }, { 0x223E1, 0x0465, NES_ROOM }, - { 0x228AC, 0x0957, NES_ROOM }, { 0x24001, 0x037E, NES_ROOM }, { 0x2481A, 0x03CA, NES_ROOM }, { 0x24BE4, 0x050D, NES_ROOM }, { 0x252C0, 0x0346, NES_ROOM }, - { 0x1BD30, 0x01CA, NES_ROOM }, { 0x25606, 0x046D, NES_ROOM }, { 0x25A73, 0x055A, NES_ROOM }, { 0x25FCD, 0x0654, NES_ROOM }, { 0x26C98, 0x024B, NES_ROOM }, - { 0x26EE3, 0x01FA, NES_ROOM }, { 0x271DD, 0x0217, NES_ROOM }, { 0x27713, 0x02F4, NES_ROOM }, { 0x28001, 0x045C, NES_ROOM }, { 0x284CE, 0x0975, NES_ROOM }, - { 0x28E97, 0x05E6, NES_ROOM }, { 0x27C3A, 0x0201, NES_ROOM }, { 0x2A9D6, 0x0325, NES_ROOM }, { 0x2AF88, 0x01FC, NES_ROOM }, { 0x2B184, 0x02A9, NES_ROOM }, - { 0x2B42D, 0x02DF, NES_ROOM }, { 0x2B818, 0x03EC, NES_ROOM }, { 0x2BD67, 0x0209, NES_ROOM }, { 0x2C001, 0x0168, NES_ROOM }, { 0x2C4BF, 0x0169, NES_ROOM } -}; -static const ScummNESFile::Resource res_rooms_ger[55] = { - { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D63, NES_ROOM }, { 0x131E0, 0x04A9, NES_ROOM }, { 0x13689, 0x086B, NES_ROOM }, { 0x15421, 0x06A8, NES_ROOM }, - { 0x15B5D, 0x0731, NES_ROOM }, { 0x16507, 0x0501, NES_ROOM }, { 0x16A08, 0x0AE9, NES_ROOM }, { 0x18001, 0x06DA, NES_ROOM }, { 0x17880, 0x03D0, NES_ROOM }, - { 0x18C7B, 0x0651, NES_ROOM }, { 0x19328, 0x04A7, NES_ROOM }, { 0x199FE, 0x0447, NES_ROOM }, { 0x1A0F1, 0x0486, NES_ROOM }, { 0x1A577, 0x045D, NES_ROOM }, - { 0x1A9D4, 0x03AE, NES_ROOM }, { 0x1AD82, 0x0840, NES_ROOM }, { 0x1B622, 0x06C3, NES_ROOM }, { 0x1C001, 0x0B07, NES_ROOM }, { 0x1CD05, 0x0494, NES_ROOM }, - { 0x1D4A5, 0x05AC, NES_ROOM }, { 0x1DFD6, 0x0524, NES_ROOM }, { 0x1E9C0, 0x05F7, NES_ROOM }, { 0x1F09A, 0x038E, NES_ROOM }, { 0x1F75F, 0x0733, NES_ROOM }, - { 0x20001, 0x04A9, NES_ROOM }, { 0x2052A, 0x052E, NES_ROOM }, { 0x2177C, 0x0621, NES_ROOM }, { 0x21F57, 0x0495, NES_ROOM }, { 0x2249A, 0x045E, NES_ROOM }, - { 0x2295E, 0x0951, NES_ROOM }, { 0x24001, 0x036E, NES_ROOM }, { 0x247F9, 0x03CA, NES_ROOM }, { 0x24BC3, 0x050D, NES_ROOM }, { 0x252A8, 0x0346, NES_ROOM }, - { 0x17CA2, 0x01CA, NES_ROOM }, { 0x255EE, 0x046F, NES_ROOM }, { 0x25A5D, 0x054D, NES_ROOM }, { 0x25FAA, 0x064B, NES_ROOM }, { 0x26BE2, 0x024B, NES_ROOM }, - { 0x26E2D, 0x01FA, NES_ROOM }, { 0x2710F, 0x0217, NES_ROOM }, { 0x27663, 0x02F4, NES_ROOM }, { 0x28001, 0x045C, NES_ROOM }, { 0x284CE, 0x0A8F, NES_ROOM }, - { 0x28FB1, 0x05FF, NES_ROOM }, { 0x27B69, 0x0201, NES_ROOM }, { 0x2AAA9, 0x0325, NES_ROOM }, { 0x1BD7C, 0x01FC, NES_ROOM }, { 0x2B031, 0x02A9, NES_ROOM }, - { 0x2B2DA, 0x02D8, NES_ROOM }, { 0x2B6D2, 0x03D2, NES_ROOM }, { 0x2BC0D, 0x020D, NES_ROOM }, { 0x2C001, 0x0168, NES_ROOM }, { 0x27E11, 0x0169, NES_ROOM } -}; -#endif -static const ScummNESFile::Resource *res_rooms[ScummNESFile::kROMsetNum] = { - res_rooms_usa, - res_rooms_eur, - res_rooms_swe, - res_rooms_fra, - res_rooms_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_scripts_usa; -static const ScummNESFile::Resource *res_scripts_eur; -static const ScummNESFile::Resource *res_scripts_swe; -static const ScummNESFile::Resource *res_scripts_fra; -static const ScummNESFile::Resource *res_scripts_ger; -#else -static const ScummNESFile::Resource res_scripts_usa[179] = { - { 0x00000, 0x0000, NES_SCRIPT }, { 0x29966, 0x044D, NES_SCRIPT }, { 0x29DB3, 0x0207, NES_SCRIPT }, { 0x29FBA, 0x009F, NES_SCRIPT }, { 0x2A059, 0x03F4, NES_SCRIPT }, - { 0x2A44D, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A5EE, 0x004A, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A638, 0x0005, NES_SCRIPT }, - { 0x2C6AA, 0x000D, NES_SCRIPT }, { 0x2C6B7, 0x000D, NES_SCRIPT }, { 0x186BB, 0x0040, NES_SCRIPT }, { 0x186FB, 0x0016, NES_SCRIPT }, { 0x1B639, 0x0046, NES_SCRIPT }, - { 0x1EEC6, 0x00BD, NES_SCRIPT }, { 0x21C31, 0x0055, NES_SCRIPT }, { 0x177A8, 0x0027, NES_SCRIPT }, { 0x1FD07, 0x0027, NES_SCRIPT }, { 0x1FD2E, 0x0027, NES_SCRIPT }, - { 0x1BD2B, 0x0022, NES_SCRIPT }, { 0x15BE0, 0x0088, NES_SCRIPT }, { 0x22241, 0x0020, NES_SCRIPT }, { 0x22261, 0x008F, NES_SCRIPT }, { 0x1924A, 0x002B, NES_SCRIPT }, - { 0x1CB4A, 0x0061, NES_SCRIPT }, { 0x1CBAB, 0x003C, NES_SCRIPT }, { 0x1CBE7, 0x0042, NES_SCRIPT }, { 0x1CC29, 0x004F, NES_SCRIPT }, { 0x2049B, 0x0076, NES_SCRIPT }, - { 0x16A96, 0x0035, NES_SCRIPT }, { 0x16ACB, 0x001C, NES_SCRIPT }, { 0x16AE7, 0x0014, NES_SCRIPT }, { 0x16AFB, 0x001C, NES_SCRIPT }, { 0x16B17, 0x0027, NES_SCRIPT }, - { 0x16B3E, 0x01AA, NES_SCRIPT }, { 0x1D1CF, 0x0096, NES_SCRIPT }, { 0x1D265, 0x010E, NES_SCRIPT }, { 0x1D373, 0x001C, NES_SCRIPT }, { 0x1D38F, 0x0056, NES_SCRIPT }, - { 0x1D3E5, 0x0072, NES_SCRIPT }, { 0x1E480, 0x0028, NES_SCRIPT }, { 0x1E4A8, 0x017D, NES_SCRIPT }, { 0x1E625, 0x0229, NES_SCRIPT }, { 0x28932, 0x0071, NES_SCRIPT }, - { 0x17EB8, 0x004D, NES_SCRIPT }, { 0x162ED, 0x0039, NES_SCRIPT }, { 0x18711, 0x028B, NES_SCRIPT }, { 0x1899C, 0x00BB, NES_SCRIPT }, { 0x18A57, 0x018B, NES_SCRIPT }, - { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E87, 0x00ED, NES_SCRIPT }, { 0x21C86, 0x00F6, NES_SCRIPT }, { 0x1E84E, 0x009B, NES_SCRIPT }, { 0x21D7C, 0x0047, NES_SCRIPT }, - { 0x2C6C4, 0x004D, NES_SCRIPT }, { 0x16326, 0x0024, NES_SCRIPT }, { 0x14D0D, 0x0014, NES_SCRIPT }, { 0x177CF, 0x0059, NES_SCRIPT }, { 0x17828, 0x0109, NES_SCRIPT }, - { 0x17931, 0x0009, NES_SCRIPT }, { 0x14D21, 0x01B6, NES_SCRIPT }, { 0x2B0F6, 0x0243, NES_SCRIPT }, { 0x230BF, 0x067F, NES_SCRIPT }, { 0x2C711, 0x001C, NES_SCRIPT }, - { 0x2C72D, 0x001A, NES_SCRIPT }, { 0x2C747, 0x0021, NES_SCRIPT }, { 0x2C768, 0x0024, NES_SCRIPT }, { 0x2C78C, 0x0017, NES_SCRIPT }, { 0x2C7A3, 0x0017, NES_SCRIPT }, - { 0x2C7BA, 0x0014, NES_SCRIPT }, { 0x2C7CE, 0x0024, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C7F2, 0x0011, NES_SCRIPT }, { 0x1793A, 0x009D, NES_SCRIPT }, - { 0x22750, 0x0066, NES_SCRIPT }, { 0x14ED7, 0x0075, NES_SCRIPT }, { 0x1F30C, 0x0120, NES_SCRIPT }, { 0x1FD55, 0x001D, NES_SCRIPT }, { 0x1F42C, 0x008F, NES_SCRIPT }, - { 0x1F4BB, 0x0097, NES_SCRIPT }, { 0x179D7, 0x006A, NES_SCRIPT }, { 0x17A41, 0x0030, NES_SCRIPT }, { 0x1F552, 0x0092, NES_SCRIPT }, { 0x2C803, 0x00CC, NES_SCRIPT }, - { 0x2C8CF, 0x00BA, NES_SCRIPT }, { 0x2C989, 0x0088, NES_SCRIPT }, { 0x20A09, 0x01B0, NES_SCRIPT }, { 0x20BB9, 0x0168, NES_SCRIPT }, { 0x20D21, 0x006C, NES_SCRIPT }, - { 0x20D8D, 0x0037, NES_SCRIPT }, { 0x20DC4, 0x00E4, NES_SCRIPT }, { 0x20EA8, 0x0045, NES_SCRIPT }, { 0x20EED, 0x00E1, NES_SCRIPT }, { 0x20FCE, 0x00F6, NES_SCRIPT }, - { 0x210C4, 0x0141, NES_SCRIPT }, { 0x21205, 0x0183, NES_SCRIPT }, { 0x21388, 0x0034, NES_SCRIPT }, { 0x213BC, 0x00A9, NES_SCRIPT }, { 0x24367, 0x011B, NES_SCRIPT }, - { 0x1BD4D, 0x0070, NES_SCRIPT }, { 0x1CC78, 0x0091, NES_SCRIPT }, { 0x29372, 0x0054, NES_SCRIPT }, { 0x19F74, 0x00CE, NES_SCRIPT }, { 0x1A042, 0x0077, NES_SCRIPT }, - { 0x14F4C, 0x0057, NES_SCRIPT }, { 0x27886, 0x02DF, NES_SCRIPT }, { 0x1DA2A, 0x0219, NES_SCRIPT }, { 0x1DC43, 0x00F9, NES_SCRIPT }, { 0x1DD3C, 0x0056, NES_SCRIPT }, - { 0x1DD92, 0x01C2, NES_SCRIPT }, { 0x14FA3, 0x004D, NES_SCRIPT }, { 0x27594, 0x00D9, NES_SCRIPT }, { 0x21DC3, 0x0013, NES_SCRIPT }, { 0x2A63D, 0x00F0, NES_SCRIPT }, - { 0x24482, 0x00E7, NES_SCRIPT }, { 0x21465, 0x00F2, NES_SCRIPT }, { 0x24569, 0x002B, NES_SCRIPT }, { 0x2C3CF, 0x010F, NES_SCRIPT }, { 0x24594, 0x00AA, NES_SCRIPT }, - { 0x24CE8, 0x0DAB, NES_SCRIPT }, { 0x1B67F, 0x000D, NES_SCRIPT }, { 0x1B68C, 0x000D, NES_SCRIPT }, { 0x2373E, 0x017C, NES_SCRIPT }, { 0x282F5, 0x01E1, NES_SCRIPT }, - { 0x238BA, 0x0153, NES_SCRIPT }, { 0x23A0D, 0x019C, NES_SCRIPT }, { 0x23BA9, 0x0016, NES_SCRIPT }, { 0x2C4DE, 0x005C, NES_SCRIPT }, { 0x23BBF, 0x0020, NES_SCRIPT }, - { 0x27D66, 0x00A5, NES_SCRIPT }, { 0x2A72D, 0x034D, NES_SCRIPT }, { 0x14FF0, 0x00E3, NES_SCRIPT }, { 0x2BABC, 0x005F, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, - { 0x25A93, 0x003C, NES_SCRIPT }, { 0x1E8E9, 0x0011, NES_SCRIPT }, { 0x1634A, 0x0018, NES_SCRIPT }, { 0x26DFD, 0x001F, NES_SCRIPT }, { 0x26E1C, 0x0054, NES_SCRIPT }, - { 0x26E70, 0x0149, NES_SCRIPT }, { 0x26FB9, 0x004B, NES_SCRIPT }, { 0x27004, 0x017D, NES_SCRIPT }, { 0x27181, 0x0027, NES_SCRIPT }, { 0x271A8, 0x0041, NES_SCRIPT }, - { 0x271E9, 0x01B1, NES_SCRIPT }, { 0x16362, 0x001F, NES_SCRIPT }, { 0x2463E, 0x002A, NES_SCRIPT }, { 0x150D3, 0x019E, NES_SCRIPT }, { 0x19275, 0x0031, NES_SCRIPT }, - { 0x17A71, 0x007C, NES_SCRIPT }, { 0x21557, 0x00DC, NES_SCRIPT }, { 0x1D457, 0x0018, NES_SCRIPT }, { 0x1D46F, 0x0053, NES_SCRIPT }, { 0x18BE2, 0x0005, NES_SCRIPT }, - { 0x15271, 0x011B, NES_SCRIPT }, { 0x1538C, 0x000B, NES_SCRIPT }, { 0x24668, 0x0138, NES_SCRIPT }, { 0x247A0, 0x0014, NES_SCRIPT }, { 0x1DF54, 0x0018, NES_SCRIPT }, - { 0x247B4, 0x0027, NES_SCRIPT }, { 0x1A0B9, 0x004D, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BB1B, 0x00A5, NES_SCRIPT }, { 0x2AA7A, 0x00C1, NES_SCRIPT }, - { 0x2AB3B, 0x0140, NES_SCRIPT }, { 0x19826, 0x00BF, NES_SCRIPT }, { 0x198E5, 0x014D, NES_SCRIPT }, { 0x19A32, 0x0012, NES_SCRIPT }, { 0x2AC7B, 0x0005, NES_SCRIPT }, - { 0x2AC80, 0x0005, NES_SCRIPT }, { 0x2AC85, 0x0005, NES_SCRIPT }, { 0x2AC8A, 0x0005, NES_SCRIPT }, { 0x2AC8F, 0x0005, NES_SCRIPT }, { 0x21633, 0x0033, NES_SCRIPT }, - { 0x2AC94, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2AC99, 0x009C, NES_SCRIPT }, { 0x2AD35, 0x009C, NES_SCRIPT } -}; -static const ScummNESFile::Resource res_scripts_eur[179] = { - { 0x00000, 0x0000, NES_SCRIPT }, { 0x29966, 0x044D, NES_SCRIPT }, { 0x29DB3, 0x0207, NES_SCRIPT }, { 0x29FBA, 0x009F, NES_SCRIPT }, { 0x2A059, 0x03F4, NES_SCRIPT }, - { 0x2A44D, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A5EE, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A64A, 0x0005, NES_SCRIPT }, - { 0x2C6AA, 0x000D, NES_SCRIPT }, { 0x2C6B7, 0x000D, NES_SCRIPT }, { 0x17889, 0x0040, NES_SCRIPT }, { 0x178C9, 0x0016, NES_SCRIPT }, { 0x1B6AE, 0x0046, NES_SCRIPT }, - { 0x1EE47, 0x00BD, NES_SCRIPT }, { 0x21C3B, 0x0055, NES_SCRIPT }, { 0x18AC0, 0x0027, NES_SCRIPT }, { 0x1FC88, 0x0027, NES_SCRIPT }, { 0x1FCAF, 0x0027, NES_SCRIPT }, - { 0x1BDA0, 0x0022, NES_SCRIPT }, { 0x15BE0, 0x0088, NES_SCRIPT }, { 0x2224B, 0x0020, NES_SCRIPT }, { 0x2226B, 0x008F, NES_SCRIPT }, { 0x1947D, 0x002B, NES_SCRIPT }, - { 0x1CACB, 0x0061, NES_SCRIPT }, { 0x1CB2C, 0x003C, NES_SCRIPT }, { 0x1CB68, 0x0042, NES_SCRIPT }, { 0x1CBAA, 0x004F, NES_SCRIPT }, { 0x2049B, 0x0076, NES_SCRIPT }, - { 0x16A96, 0x0035, NES_SCRIPT }, { 0x16ACB, 0x001C, NES_SCRIPT }, { 0x16AE7, 0x0014, NES_SCRIPT }, { 0x16AFB, 0x001C, NES_SCRIPT }, { 0x16B17, 0x0027, NES_SCRIPT }, - { 0x16B3E, 0x01AA, NES_SCRIPT }, { 0x1D150, 0x0096, NES_SCRIPT }, { 0x1D1E6, 0x010E, NES_SCRIPT }, { 0x1D2F4, 0x001C, NES_SCRIPT }, { 0x1D310, 0x0056, NES_SCRIPT }, - { 0x1D366, 0x0072, NES_SCRIPT }, { 0x1E401, 0x0028, NES_SCRIPT }, { 0x1E429, 0x017D, NES_SCRIPT }, { 0x1E5A6, 0x0229, NES_SCRIPT }, { 0x28932, 0x0071, NES_SCRIPT }, - { 0x13EC6, 0x004D, NES_SCRIPT }, { 0x162ED, 0x0039, NES_SCRIPT }, { 0x178DF, 0x028B, NES_SCRIPT }, { 0x17B6A, 0x00BB, NES_SCRIPT }, { 0x17C25, 0x018B, NES_SCRIPT }, - { 0x00000, 0x0000, NES_SCRIPT }, { 0x19FE3, 0x00ED, NES_SCRIPT }, { 0x21C90, 0x00F6, NES_SCRIPT }, { 0x1E7CF, 0x009B, NES_SCRIPT }, { 0x21D86, 0x0047, NES_SCRIPT }, - { 0x2C6C4, 0x004D, NES_SCRIPT }, { 0x16326, 0x0024, NES_SCRIPT }, { 0x14D0D, 0x0014, NES_SCRIPT }, { 0x18AE7, 0x0059, NES_SCRIPT }, { 0x18B40, 0x011E, NES_SCRIPT }, - { 0x18C5E, 0x0009, NES_SCRIPT }, { 0x14D21, 0x01B6, NES_SCRIPT }, { 0x2B108, 0x0243, NES_SCRIPT }, { 0x230C9, 0x067F, NES_SCRIPT }, { 0x2C711, 0x001C, NES_SCRIPT }, - { 0x2C72D, 0x001A, NES_SCRIPT }, { 0x2C747, 0x0021, NES_SCRIPT }, { 0x2C768, 0x0024, NES_SCRIPT }, { 0x2C78C, 0x0017, NES_SCRIPT }, { 0x2C7A3, 0x0017, NES_SCRIPT }, - { 0x2C7BA, 0x0014, NES_SCRIPT }, { 0x2C7CE, 0x0024, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C7F2, 0x0011, NES_SCRIPT }, { 0x18C67, 0x009D, NES_SCRIPT }, - { 0x2275A, 0x0066, NES_SCRIPT }, { 0x14ED7, 0x0075, NES_SCRIPT }, { 0x1F28D, 0x0120, NES_SCRIPT }, { 0x1FCD6, 0x001D, NES_SCRIPT }, { 0x1F3AD, 0x008F, NES_SCRIPT }, - { 0x1F43C, 0x0097, NES_SCRIPT }, { 0x18D04, 0x006A, NES_SCRIPT }, { 0x18D6E, 0x0030, NES_SCRIPT }, { 0x1F4D3, 0x0092, NES_SCRIPT }, { 0x2C803, 0x00CC, NES_SCRIPT }, - { 0x2C8CF, 0x00BA, NES_SCRIPT }, { 0x2C989, 0x0088, NES_SCRIPT }, { 0x20A09, 0x01B0, NES_SCRIPT }, { 0x20BB9, 0x0168, NES_SCRIPT }, { 0x20D21, 0x006C, NES_SCRIPT }, - { 0x20D8D, 0x0037, NES_SCRIPT }, { 0x20DC4, 0x00E4, NES_SCRIPT }, { 0x20EA8, 0x0045, NES_SCRIPT }, { 0x20EED, 0x00E1, NES_SCRIPT }, { 0x20FCE, 0x00F6, NES_SCRIPT }, - { 0x210C4, 0x0141, NES_SCRIPT }, { 0x21205, 0x0183, NES_SCRIPT }, { 0x21388, 0x0034, NES_SCRIPT }, { 0x213BC, 0x00A9, NES_SCRIPT }, { 0x24367, 0x011B, NES_SCRIPT }, - { 0x1BDC2, 0x0070, NES_SCRIPT }, { 0x1CBF9, 0x0091, NES_SCRIPT }, { 0x29372, 0x0054, NES_SCRIPT }, { 0x1A0D0, 0x00CE, NES_SCRIPT }, { 0x1A19E, 0x0077, NES_SCRIPT }, - { 0x14F4C, 0x0057, NES_SCRIPT }, { 0x2790A, 0x02DF, NES_SCRIPT }, { 0x1D9AB, 0x0219, NES_SCRIPT }, { 0x1DBC4, 0x00F9, NES_SCRIPT }, { 0x1DCBD, 0x0056, NES_SCRIPT }, - { 0x1DD13, 0x01C2, NES_SCRIPT }, { 0x14FA3, 0x004D, NES_SCRIPT }, { 0x27618, 0x00D9, NES_SCRIPT }, { 0x21DCD, 0x0013, NES_SCRIPT }, { 0x2A64F, 0x00F0, NES_SCRIPT }, - { 0x24482, 0x00E7, NES_SCRIPT }, { 0x21465, 0x00F2, NES_SCRIPT }, { 0x24569, 0x002B, NES_SCRIPT }, { 0x2C3CF, 0x010F, NES_SCRIPT }, { 0x24594, 0x00AA, NES_SCRIPT }, - { 0x250B2, 0x0DAB, NES_SCRIPT }, { 0x1B6F4, 0x000D, NES_SCRIPT }, { 0x1B701, 0x000D, NES_SCRIPT }, { 0x23748, 0x017C, NES_SCRIPT }, { 0x282F5, 0x01E1, NES_SCRIPT }, - { 0x238C4, 0x0153, NES_SCRIPT }, { 0x23A17, 0x019C, NES_SCRIPT }, { 0x23BB3, 0x0016, NES_SCRIPT }, { 0x2C4DE, 0x005C, NES_SCRIPT }, { 0x23BC9, 0x0020, NES_SCRIPT }, - { 0x27DEA, 0x00A5, NES_SCRIPT }, { 0x2A73F, 0x034D, NES_SCRIPT }, { 0x14FF0, 0x00E3, NES_SCRIPT }, { 0x2BACE, 0x005F, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, - { 0x25E5D, 0x003C, NES_SCRIPT }, { 0x1E86A, 0x0011, NES_SCRIPT }, { 0x1634A, 0x0018, NES_SCRIPT }, { 0x26E81, 0x001F, NES_SCRIPT }, { 0x26EA0, 0x0054, NES_SCRIPT }, - { 0x26EF4, 0x0149, NES_SCRIPT }, { 0x2703D, 0x004B, NES_SCRIPT }, { 0x27088, 0x017D, NES_SCRIPT }, { 0x27205, 0x0027, NES_SCRIPT }, { 0x2722C, 0x0041, NES_SCRIPT }, - { 0x2726D, 0x01B1, NES_SCRIPT }, { 0x16362, 0x001F, NES_SCRIPT }, { 0x2463E, 0x002A, NES_SCRIPT }, { 0x150D3, 0x019E, NES_SCRIPT }, { 0x194A8, 0x0031, NES_SCRIPT }, - { 0x18D9E, 0x007C, NES_SCRIPT }, { 0x21557, 0x00DC, NES_SCRIPT }, { 0x1D3D8, 0x0018, NES_SCRIPT }, { 0x1D3F0, 0x0053, NES_SCRIPT }, { 0x17DB0, 0x0005, NES_SCRIPT }, - { 0x15271, 0x011B, NES_SCRIPT }, { 0x1538C, 0x000B, NES_SCRIPT }, { 0x24668, 0x0138, NES_SCRIPT }, { 0x247A0, 0x0014, NES_SCRIPT }, { 0x1DED5, 0x0018, NES_SCRIPT }, - { 0x247B4, 0x0027, NES_SCRIPT }, { 0x1A215, 0x004D, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BB2D, 0x00A5, NES_SCRIPT }, { 0x2AA8C, 0x00C1, NES_SCRIPT }, - { 0x2AB4D, 0x0140, NES_SCRIPT }, { 0x19982, 0x00BF, NES_SCRIPT }, { 0x19A41, 0x014D, NES_SCRIPT }, { 0x19B8E, 0x0012, NES_SCRIPT }, { 0x2AC8D, 0x0005, NES_SCRIPT }, - { 0x2AC92, 0x0005, NES_SCRIPT }, { 0x2AC97, 0x0005, NES_SCRIPT }, { 0x2AC9C, 0x0005, NES_SCRIPT }, { 0x2ACA1, 0x0005, NES_SCRIPT }, { 0x21633, 0x0033, NES_SCRIPT }, - { 0x2ACA6, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2ACAB, 0x009C, NES_SCRIPT }, { 0x2AD47, 0x009C, NES_SCRIPT } -}; -static const ScummNESFile::Resource res_scripts_swe[179] = { - { 0x00000, 0x0000, NES_SCRIPT }, { 0x28F80, 0x043B, NES_SCRIPT }, { 0x293BB, 0x0209, NES_SCRIPT }, { 0x295C4, 0x00AB, NES_SCRIPT }, { 0x2966F, 0x03FD, NES_SCRIPT }, - { 0x29A6C, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x29C0D, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x29C69, 0x0005, NES_SCRIPT }, - { 0x2B980, 0x000D, NES_SCRIPT }, { 0x2B98D, 0x000D, NES_SCRIPT }, { 0x186C8, 0x0040, NES_SCRIPT }, { 0x18708, 0x0016, NES_SCRIPT }, { 0x1B4B1, 0x0046, NES_SCRIPT }, - { 0x1EEBB, 0x00B8, NES_SCRIPT }, { 0x21CFA, 0x005C, NES_SCRIPT }, { 0x17537, 0x0027, NES_SCRIPT }, { 0x1FD0A, 0x0027, NES_SCRIPT }, { 0x1FD31, 0x0027, NES_SCRIPT }, - { 0x1BBB5, 0x0022, NES_SCRIPT }, { 0x15BC0, 0x0085, NES_SCRIPT }, { 0x22324, 0x001E, NES_SCRIPT }, { 0x22342, 0x008F, NES_SCRIPT }, { 0x19252, 0x002B, NES_SCRIPT }, - { 0x1CB1B, 0x006D, NES_SCRIPT }, { 0x1CB88, 0x004C, NES_SCRIPT }, { 0x1CBD4, 0x0044, NES_SCRIPT }, { 0x1CC18, 0x0053, NES_SCRIPT }, { 0x2049D, 0x0081, NES_SCRIPT }, - { 0x1634C, 0x0035, NES_SCRIPT }, { 0x16381, 0x001C, NES_SCRIPT }, { 0x1639D, 0x0014, NES_SCRIPT }, { 0x163B1, 0x001C, NES_SCRIPT }, { 0x163CD, 0x0027, NES_SCRIPT }, - { 0x163F4, 0x019B, NES_SCRIPT }, { 0x1D183, 0x0094, NES_SCRIPT }, { 0x1D217, 0x0117, NES_SCRIPT }, { 0x1D32E, 0x001C, NES_SCRIPT }, { 0x1D34A, 0x0056, NES_SCRIPT }, - { 0x1D3A0, 0x0072, NES_SCRIPT }, { 0x1E47F, 0x0028, NES_SCRIPT }, { 0x1E4A7, 0x0175, NES_SCRIPT }, { 0x1E61C, 0x022B, NES_SCRIPT }, { 0x27C85, 0x0071, NES_SCRIPT }, - { 0x17C86, 0x004A, NES_SCRIPT }, { 0x13DD6, 0x0039, NES_SCRIPT }, { 0x1871E, 0x0270, NES_SCRIPT }, { 0x1898E, 0x00C0, NES_SCRIPT }, { 0x18A4E, 0x01B6, NES_SCRIPT }, - { 0x00000, 0x0000, NES_SCRIPT }, { 0x19DC9, 0x00EE, NES_SCRIPT }, { 0x21D56, 0x00F5, NES_SCRIPT }, { 0x1E847, 0x0094, NES_SCRIPT }, { 0x21E4B, 0x0047, NES_SCRIPT }, - { 0x2B99A, 0x004D, NES_SCRIPT }, { 0x13E0F, 0x0024, NES_SCRIPT }, { 0x14D13, 0x0014, NES_SCRIPT }, { 0x1755E, 0x0054, NES_SCRIPT }, { 0x175B2, 0x011A, NES_SCRIPT }, - { 0x176CC, 0x0009, NES_SCRIPT }, { 0x14D27, 0x01B9, NES_SCRIPT }, { 0x2AA0E, 0x0256, NES_SCRIPT }, { 0x231A4, 0x06D2, NES_SCRIPT }, { 0x2B9E7, 0x001D, NES_SCRIPT }, - { 0x2BA04, 0x0016, NES_SCRIPT }, { 0x2BA1A, 0x002D, NES_SCRIPT }, { 0x2BA47, 0x0027, NES_SCRIPT }, { 0x2BA6E, 0x0016, NES_SCRIPT }, { 0x2BA84, 0x0014, NES_SCRIPT }, - { 0x2BA98, 0x0015, NES_SCRIPT }, { 0x2BAAD, 0x0029, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BAD6, 0x0010, NES_SCRIPT }, { 0x176D5, 0x00A2, NES_SCRIPT }, - { 0x22831, 0x0066, NES_SCRIPT }, { 0x14EE0, 0x0077, NES_SCRIPT }, { 0x1F30B, 0x011A, NES_SCRIPT }, { 0x1FD58, 0x001D, NES_SCRIPT }, { 0x1F425, 0x0095, NES_SCRIPT }, - { 0x1F4BA, 0x009E, NES_SCRIPT }, { 0x17777, 0x006F, NES_SCRIPT }, { 0x177E6, 0x002F, NES_SCRIPT }, { 0x1F558, 0x0098, NES_SCRIPT }, { 0x2BAE6, 0x00C4, NES_SCRIPT }, - { 0x2BBAA, 0x00AE, NES_SCRIPT }, { 0x2BC58, 0x0088, NES_SCRIPT }, { 0x20A3C, 0x01BB, NES_SCRIPT }, { 0x20BF7, 0x0197, NES_SCRIPT }, { 0x20D8E, 0x006E, NES_SCRIPT }, - { 0x20DFC, 0x0028, NES_SCRIPT }, { 0x20E24, 0x00EA, NES_SCRIPT }, { 0x20F0E, 0x0049, NES_SCRIPT }, { 0x20F57, 0x00E7, NES_SCRIPT }, { 0x2103E, 0x010C, NES_SCRIPT }, - { 0x2114A, 0x0151, NES_SCRIPT }, { 0x2129B, 0x01B0, NES_SCRIPT }, { 0x2144B, 0x0034, NES_SCRIPT }, { 0x2147F, 0x00A9, NES_SCRIPT }, { 0x24379, 0x010E, NES_SCRIPT }, - { 0x1BBD7, 0x0072, NES_SCRIPT }, { 0x1CC6B, 0x0092, NES_SCRIPT }, { 0x2898B, 0x0054, NES_SCRIPT }, { 0x19EB7, 0x00D3, NES_SCRIPT }, { 0x19F8A, 0x0077, NES_SCRIPT }, - { 0x14F57, 0x0057, NES_SCRIPT }, { 0x2703E, 0x0307, NES_SCRIPT }, { 0x1D9FB, 0x024F, NES_SCRIPT }, { 0x1DC4A, 0x00E4, NES_SCRIPT }, { 0x1DD2E, 0x0059, NES_SCRIPT }, - { 0x1DD87, 0x01C2, NES_SCRIPT }, { 0x14FAE, 0x004D, NES_SCRIPT }, { 0x26D52, 0x00D5, NES_SCRIPT }, { 0x21E92, 0x0013, NES_SCRIPT }, { 0x29C6E, 0x00F0, NES_SCRIPT }, - { 0x24487, 0x00E0, NES_SCRIPT }, { 0x21528, 0x00F2, NES_SCRIPT }, { 0x24567, 0x0023, NES_SCRIPT }, { 0x2B6B2, 0x010B, NES_SCRIPT }, { 0x2458A, 0x00A1, NES_SCRIPT }, - { 0x250A0, 0x018B, NES_SCRIPT }, { 0x1B4F7, 0x000D, NES_SCRIPT }, { 0x1B504, 0x000D, NES_SCRIPT }, { 0x23876, 0x018E, NES_SCRIPT }, { 0x27639, 0x01F0, NES_SCRIPT }, - { 0x23A04, 0x017B, NES_SCRIPT }, { 0x23B7F, 0x01AC, NES_SCRIPT }, { 0x23D2B, 0x0016, NES_SCRIPT }, { 0x2B7BD, 0x005B, NES_SCRIPT }, { 0x23D41, 0x0020, NES_SCRIPT }, - { 0x2A643, 0x00A6, NES_SCRIPT }, { 0x29D5E, 0x0399, NES_SCRIPT }, { 0x14FFB, 0x00D2, NES_SCRIPT }, { 0x2B1DE, 0x0063, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, - { 0x2522B, 0x003C, NES_SCRIPT }, { 0x1E8DB, 0x0011, NES_SCRIPT }, { 0x13E33, 0x0018, NES_SCRIPT }, { 0x26585, 0x001F, NES_SCRIPT }, { 0x265A4, 0x0054, NES_SCRIPT }, - { 0x265F8, 0x017D, NES_SCRIPT }, { 0x26775, 0x004B, NES_SCRIPT }, { 0x267C0, 0x0165, NES_SCRIPT }, { 0x26925, 0x0027, NES_SCRIPT }, { 0x2694C, 0x0041, NES_SCRIPT }, - { 0x2698D, 0x01CB, NES_SCRIPT }, { 0x13E4B, 0x001F, NES_SCRIPT }, { 0x2462B, 0x002A, NES_SCRIPT }, { 0x150CD, 0x0187, NES_SCRIPT }, { 0x1927D, 0x0031, NES_SCRIPT }, - { 0x17815, 0x0087, NES_SCRIPT }, { 0x2161A, 0x00D8, NES_SCRIPT }, { 0x1D412, 0x0018, NES_SCRIPT }, { 0x1D42A, 0x0058, NES_SCRIPT }, { 0x18C04, 0x0005, NES_SCRIPT }, - { 0x15254, 0x0108, NES_SCRIPT }, { 0x1535C, 0x000B, NES_SCRIPT }, { 0x24655, 0x0139, NES_SCRIPT }, { 0x2478E, 0x0014, NES_SCRIPT }, { 0x1DF49, 0x0018, NES_SCRIPT }, - { 0x247A2, 0x0027, NES_SCRIPT }, { 0x1A001, 0x004C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B241, 0x00A5, NES_SCRIPT }, { 0x2A0F7, 0x00B5, NES_SCRIPT }, - { 0x2A1AC, 0x0140, NES_SCRIPT }, { 0x19759, 0x00CA, NES_SCRIPT }, { 0x19823, 0x014D, NES_SCRIPT }, { 0x19970, 0x0012, NES_SCRIPT }, { 0x2A2EC, 0x0005, NES_SCRIPT }, - { 0x2A2F1, 0x0005, NES_SCRIPT }, { 0x2A2F6, 0x0005, NES_SCRIPT }, { 0x2A2FB, 0x0005, NES_SCRIPT }, { 0x2A300, 0x0005, NES_SCRIPT }, { 0x216F2, 0x0033, NES_SCRIPT }, - { 0x2A305, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A30A, 0x009C, NES_SCRIPT }, { 0x2A3A6, 0x009C, NES_SCRIPT } -}; -static const ScummNESFile::Resource res_scripts_fra[179] = { - { 0x00000, 0x0000, NES_SCRIPT }, { 0x2947D, 0x0480, NES_SCRIPT }, { 0x298FD, 0x0226, NES_SCRIPT }, { 0x29B23, 0x0092, NES_SCRIPT }, { 0x29BB5, 0x040C, NES_SCRIPT }, - { 0x29FC1, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A162, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A1BE, 0x0005, NES_SCRIPT }, - { 0x2C169, 0x000D, NES_SCRIPT }, { 0x2C176, 0x000D, NES_SCRIPT }, { 0x186E3, 0x0040, NES_SCRIPT }, { 0x18723, 0x0016, NES_SCRIPT }, { 0x1B59F, 0x0046, NES_SCRIPT }, - { 0x1EFD7, 0x00CB, NES_SCRIPT }, { 0x21D09, 0x0054, NES_SCRIPT }, { 0x176C8, 0x0027, NES_SCRIPT }, { 0x1FE6A, 0x0027, NES_SCRIPT }, { 0x1FE91, 0x0027, NES_SCRIPT }, - { 0x1BC9A, 0x0022, NES_SCRIPT }, { 0x15CD6, 0x0092, NES_SCRIPT }, { 0x22336, 0x001C, NES_SCRIPT }, { 0x22352, 0x008F, NES_SCRIPT }, { 0x192A5, 0x002B, NES_SCRIPT }, - { 0x1CAAA, 0x0069, NES_SCRIPT }, { 0x1CB13, 0x0054, NES_SCRIPT }, { 0x1CB67, 0x0048, NES_SCRIPT }, { 0x1CBAF, 0x0058, NES_SCRIPT }, { 0x204B6, 0x0078, NES_SCRIPT }, - { 0x16471, 0x0035, NES_SCRIPT }, { 0x164A6, 0x001C, NES_SCRIPT }, { 0x164C2, 0x0014, NES_SCRIPT }, { 0x164D6, 0x001C, NES_SCRIPT }, { 0x164F2, 0x0027, NES_SCRIPT }, - { 0x16519, 0x01BB, NES_SCRIPT }, { 0x1D135, 0x008D, NES_SCRIPT }, { 0x1D1C2, 0x0119, NES_SCRIPT }, { 0x1D2DB, 0x001C, NES_SCRIPT }, { 0x1D2F7, 0x0056, NES_SCRIPT }, - { 0x1D34D, 0x0072, NES_SCRIPT }, { 0x1E4BF, 0x0028, NES_SCRIPT }, { 0x1E4E7, 0x01E0, NES_SCRIPT }, { 0x1E6C7, 0x0241, NES_SCRIPT }, { 0x2845D, 0x0071, NES_SCRIPT }, - { 0x17E48, 0x004C, NES_SCRIPT }, { 0x13DE3, 0x0039, NES_SCRIPT }, { 0x18739, 0x0296, NES_SCRIPT }, { 0x189CF, 0x00C2, NES_SCRIPT }, { 0x18A91, 0x01A5, NES_SCRIPT }, - { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E13, 0x00F3, NES_SCRIPT }, { 0x21D5D, 0x00F6, NES_SCRIPT }, { 0x1E908, 0x00B8, NES_SCRIPT }, { 0x21E53, 0x0047, NES_SCRIPT }, - { 0x2C183, 0x004D, NES_SCRIPT }, { 0x13E1C, 0x0024, NES_SCRIPT }, { 0x14D77, 0x0014, NES_SCRIPT }, { 0x176EF, 0x0059, NES_SCRIPT }, { 0x17748, 0x013F, NES_SCRIPT }, - { 0x17887, 0x0009, NES_SCRIPT }, { 0x14D8B, 0x01D4, NES_SCRIPT }, { 0x2ACFB, 0x028D, NES_SCRIPT }, { 0x23203, 0x0779, NES_SCRIPT }, { 0x2C1D0, 0x001B, NES_SCRIPT }, - { 0x2C1EB, 0x001F, NES_SCRIPT }, { 0x2C20A, 0x0024, NES_SCRIPT }, { 0x2C22E, 0x0019, NES_SCRIPT }, { 0x2C247, 0x0018, NES_SCRIPT }, { 0x2C25F, 0x001D, NES_SCRIPT }, - { 0x2C27C, 0x0016, NES_SCRIPT }, { 0x2C292, 0x0027, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C2B9, 0x0011, NES_SCRIPT }, { 0x17890, 0x00AA, NES_SCRIPT }, - { 0x22846, 0x0066, NES_SCRIPT }, { 0x14F5F, 0x0083, NES_SCRIPT }, { 0x1F43C, 0x013A, NES_SCRIPT }, { 0x1FEB8, 0x001D, NES_SCRIPT }, { 0x1F576, 0x0098, NES_SCRIPT }, - { 0x1F60E, 0x009B, NES_SCRIPT }, { 0x1793A, 0x006E, NES_SCRIPT }, { 0x179A8, 0x0033, NES_SCRIPT }, { 0x1F6A9, 0x00A5, NES_SCRIPT }, { 0x2C2CA, 0x00BA, NES_SCRIPT }, - { 0x2C384, 0x00AC, NES_SCRIPT }, { 0x2C430, 0x008F, NES_SCRIPT }, { 0x20A2D, 0x01BE, NES_SCRIPT }, { 0x20BEB, 0x0158, NES_SCRIPT }, { 0x20D43, 0x0079, NES_SCRIPT }, - { 0x20DBC, 0x002B, NES_SCRIPT }, { 0x20DE7, 0x00E8, NES_SCRIPT }, { 0x20ECF, 0x004A, NES_SCRIPT }, { 0x20F19, 0x0110, NES_SCRIPT }, { 0x21029, 0x0136, NES_SCRIPT }, - { 0x2115F, 0x0152, NES_SCRIPT }, { 0x212B1, 0x01B3, NES_SCRIPT }, { 0x21464, 0x0032, NES_SCRIPT }, { 0x21496, 0x00A9, NES_SCRIPT }, { 0x2437F, 0x0133, NES_SCRIPT }, - { 0x1BCBC, 0x0074, NES_SCRIPT }, { 0x1CC07, 0x0090, NES_SCRIPT }, { 0x28E43, 0x0054, NES_SCRIPT }, { 0x19F06, 0x00DB, NES_SCRIPT }, { 0x19FE1, 0x0080, NES_SCRIPT }, - { 0x14FE2, 0x0057, NES_SCRIPT }, { 0x273F4, 0x031F, NES_SCRIPT }, { 0x1D9D4, 0x0238, NES_SCRIPT }, { 0x1DC0C, 0x00FE, NES_SCRIPT }, { 0x1DD0A, 0x005A, NES_SCRIPT }, - { 0x1DD64, 0x01F5, NES_SCRIPT }, { 0x15039, 0x004D, NES_SCRIPT }, { 0x270DD, 0x0100, NES_SCRIPT }, { 0x21E9A, 0x0013, NES_SCRIPT }, { 0x2A1C3, 0x00F0, NES_SCRIPT }, - { 0x244B2, 0x00E4, NES_SCRIPT }, { 0x2153F, 0x00EC, NES_SCRIPT }, { 0x24596, 0x0033, NES_SCRIPT }, { 0x2BC04, 0x0108, NES_SCRIPT }, { 0x245C9, 0x009F, NES_SCRIPT }, - { 0x250F1, 0x0193, NES_SCRIPT }, { 0x1B5E5, 0x000D, NES_SCRIPT }, { 0x1B5F2, 0x000D, NES_SCRIPT }, { 0x2397C, 0x0199, NES_SCRIPT }, { 0x27A07, 0x0233, NES_SCRIPT }, - { 0x23B15, 0x0171, NES_SCRIPT }, { 0x23C86, 0x01BC, NES_SCRIPT }, { 0x23E42, 0x0016, NES_SCRIPT }, { 0x2BD0C, 0x005B, NES_SCRIPT }, { 0x23E58, 0x0020, NES_SCRIPT }, - { 0x27E3B, 0x00B9, NES_SCRIPT }, { 0x2A2B3, 0x03D3, NES_SCRIPT }, { 0x15086, 0x00E4, NES_SCRIPT }, { 0x2B70C, 0x0067, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, - { 0x25284, 0x003C, NES_SCRIPT }, { 0x1E9C0, 0x0011, NES_SCRIPT }, { 0x13E40, 0x0018, NES_SCRIPT }, { 0x26621, 0x001F, NES_SCRIPT }, { 0x26640, 0x0054, NES_SCRIPT }, - { 0x26694, 0x0173, NES_SCRIPT }, { 0x26807, 0x004B, NES_SCRIPT }, { 0x26852, 0x0190, NES_SCRIPT }, { 0x269E2, 0x0027, NES_SCRIPT }, { 0x26A09, 0x0041, NES_SCRIPT }, - { 0x26A4A, 0x024E, NES_SCRIPT }, { 0x13E58, 0x001F, NES_SCRIPT }, { 0x24668, 0x002A, NES_SCRIPT }, { 0x1516A, 0x01C9, NES_SCRIPT }, { 0x192D0, 0x0031, NES_SCRIPT }, - { 0x179DB, 0x0088, NES_SCRIPT }, { 0x2162B, 0x00D0, NES_SCRIPT }, { 0x1D3BF, 0x0018, NES_SCRIPT }, { 0x1D3D7, 0x0055, NES_SCRIPT }, { 0x18C36, 0x0005, NES_SCRIPT }, - { 0x15333, 0x0113, NES_SCRIPT }, { 0x15446, 0x000B, NES_SCRIPT }, { 0x24692, 0x014D, NES_SCRIPT }, { 0x247DF, 0x0014, NES_SCRIPT }, { 0x1DF59, 0x0018, NES_SCRIPT }, - { 0x247F3, 0x0027, NES_SCRIPT }, { 0x1A061, 0x0050, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B773, 0x00A5, NES_SCRIPT }, { 0x2A686, 0x00BA, NES_SCRIPT }, - { 0x2A740, 0x0140, NES_SCRIPT }, { 0x1979F, 0x00CA, NES_SCRIPT }, { 0x19869, 0x014D, NES_SCRIPT }, { 0x199B6, 0x0012, NES_SCRIPT }, { 0x2A880, 0x0005, NES_SCRIPT }, - { 0x2A885, 0x0005, NES_SCRIPT }, { 0x2A88A, 0x0005, NES_SCRIPT }, { 0x2A88F, 0x0005, NES_SCRIPT }, { 0x2A894, 0x0005, NES_SCRIPT }, { 0x216FB, 0x0033, NES_SCRIPT }, - { 0x2A899, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A89E, 0x009C, NES_SCRIPT }, { 0x2A93A, 0x009C, NES_SCRIPT } -}; -static const ScummNESFile::Resource res_scripts_ger[179] = { - { 0x00000, 0x0000, NES_SCRIPT }, { 0x295B0, 0x045A, NES_SCRIPT }, { 0x29A0A, 0x0218, NES_SCRIPT }, { 0x29C22, 0x00B1, NES_SCRIPT }, { 0x29CD3, 0x0408, NES_SCRIPT }, - { 0x2A0DB, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A27C, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A2D8, 0x0005, NES_SCRIPT }, - { 0x2C169, 0x000D, NES_SCRIPT }, { 0x2C176, 0x000D, NES_SCRIPT }, { 0x186DB, 0x0040, NES_SCRIPT }, { 0x1871B, 0x0016, NES_SCRIPT }, { 0x1B5C2, 0x0046, NES_SCRIPT }, - { 0x1EFB7, 0x00E3, NES_SCRIPT }, { 0x21D9D, 0x0069, NES_SCRIPT }, { 0x174F1, 0x0027, NES_SCRIPT }, { 0x1FE92, 0x0027, NES_SCRIPT }, { 0x1FEB9, 0x0027, NES_SCRIPT }, - { 0x1BCE5, 0x0022, NES_SCRIPT }, { 0x13EF4, 0x0087, NES_SCRIPT }, { 0x223EC, 0x001F, NES_SCRIPT }, { 0x2240B, 0x008F, NES_SCRIPT }, { 0x192CC, 0x002B, NES_SCRIPT }, - { 0x1CB08, 0x006E, NES_SCRIPT }, { 0x1CB76, 0x004E, NES_SCRIPT }, { 0x1CBC4, 0x004D, NES_SCRIPT }, { 0x1CC11, 0x0059, NES_SCRIPT }, { 0x204AA, 0x0080, NES_SCRIPT }, - { 0x1628E, 0x0035, NES_SCRIPT }, { 0x162C3, 0x001C, NES_SCRIPT }, { 0x162DF, 0x0014, NES_SCRIPT }, { 0x162F3, 0x001C, NES_SCRIPT }, { 0x1630F, 0x0027, NES_SCRIPT }, - { 0x16336, 0x01D1, NES_SCRIPT }, { 0x1D199, 0x00A0, NES_SCRIPT }, { 0x1D239, 0x011C, NES_SCRIPT }, { 0x1D355, 0x001C, NES_SCRIPT }, { 0x1D371, 0x0056, NES_SCRIPT }, - { 0x1D3C7, 0x0072, NES_SCRIPT }, { 0x1E4FA, 0x0028, NES_SCRIPT }, { 0x1E522, 0x019D, NES_SCRIPT }, { 0x1E6BF, 0x023B, NES_SCRIPT }, { 0x2845D, 0x0071, NES_SCRIPT }, - { 0x17C50, 0x0052, NES_SCRIPT }, { 0x15AC9, 0x0039, NES_SCRIPT }, { 0x18731, 0x02E7, NES_SCRIPT }, { 0x18A18, 0x00BC, NES_SCRIPT }, { 0x18AD4, 0x01A2, NES_SCRIPT }, - { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E45, 0x00F8, NES_SCRIPT }, { 0x21E06, 0x00F7, NES_SCRIPT }, { 0x1E8FA, 0x00B5, NES_SCRIPT }, { 0x21EFD, 0x0047, NES_SCRIPT }, - { 0x2C183, 0x004D, NES_SCRIPT }, { 0x15B02, 0x0024, NES_SCRIPT }, { 0x14D64, 0x0014, NES_SCRIPT }, { 0x17518, 0x005E, NES_SCRIPT }, { 0x17576, 0x0125, NES_SCRIPT }, - { 0x1769B, 0x0009, NES_SCRIPT }, { 0x14D78, 0x01C7, NES_SCRIPT }, { 0x2ADCE, 0x0263, NES_SCRIPT }, { 0x232AF, 0x077F, NES_SCRIPT }, { 0x2C1D0, 0x001E, NES_SCRIPT }, - { 0x2C1EE, 0x0024, NES_SCRIPT }, { 0x2C212, 0x002E, NES_SCRIPT }, { 0x2C240, 0x0022, NES_SCRIPT }, { 0x2C262, 0x0013, NES_SCRIPT }, { 0x2C275, 0x001E, NES_SCRIPT }, - { 0x2C293, 0x0016, NES_SCRIPT }, { 0x2C2A9, 0x0027, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C2D0, 0x0012, NES_SCRIPT }, { 0x176A4, 0x00A4, NES_SCRIPT }, - { 0x228F8, 0x0066, NES_SCRIPT }, { 0x14F3F, 0x007F, NES_SCRIPT }, { 0x1F428, 0x013A, NES_SCRIPT }, { 0x1FEE0, 0x001D, NES_SCRIPT }, { 0x1F562, 0x00A0, NES_SCRIPT }, - { 0x1F602, 0x00A4, NES_SCRIPT }, { 0x17748, 0x0076, NES_SCRIPT }, { 0x177BE, 0x0036, NES_SCRIPT }, { 0x1F6A6, 0x00B9, NES_SCRIPT }, { 0x2C2E2, 0x00CB, NES_SCRIPT }, - { 0x2C3AD, 0x00B7, NES_SCRIPT }, { 0x2C464, 0x008A, NES_SCRIPT }, { 0x20A58, 0x01BD, NES_SCRIPT }, { 0x20C15, 0x0181, NES_SCRIPT }, { 0x20D96, 0x0078, NES_SCRIPT }, - { 0x20E0E, 0x003C, NES_SCRIPT }, { 0x20E4A, 0x00E9, NES_SCRIPT }, { 0x20F33, 0x0046, NES_SCRIPT }, { 0x20F79, 0x00F6, NES_SCRIPT }, { 0x2106F, 0x0118, NES_SCRIPT }, - { 0x21187, 0x015B, NES_SCRIPT }, { 0x212E2, 0x01AC, NES_SCRIPT }, { 0x2148E, 0x003F, NES_SCRIPT }, { 0x214CD, 0x00A9, NES_SCRIPT }, { 0x2436F, 0x0126, NES_SCRIPT }, - { 0x1BD07, 0x0075, NES_SCRIPT }, { 0x1CC6A, 0x009B, NES_SCRIPT }, { 0x28F5D, 0x0054, NES_SCRIPT }, { 0x19F3D, 0x00E1, NES_SCRIPT }, { 0x1A01E, 0x0086, NES_SCRIPT }, - { 0x14FBE, 0x0057, NES_SCRIPT }, { 0x27326, 0x033D, NES_SCRIPT }, { 0x1DA51, 0x023B, NES_SCRIPT }, { 0x1DC8C, 0x00FB, NES_SCRIPT }, { 0x1DD87, 0x0056, NES_SCRIPT }, - { 0x1DDDD, 0x01E1, NES_SCRIPT }, { 0x15015, 0x004D, NES_SCRIPT }, { 0x27027, 0x00E8, NES_SCRIPT }, { 0x21F44, 0x0013, NES_SCRIPT }, { 0x2A2DD, 0x00F0, NES_SCRIPT }, - { 0x24495, 0x00F8, NES_SCRIPT }, { 0x21576, 0x00F9, NES_SCRIPT }, { 0x2458D, 0x002B, NES_SCRIPT }, { 0x2BAA4, 0x010F, NES_SCRIPT }, { 0x245B8, 0x00A5, NES_SCRIPT }, - { 0x250D0, 0x019C, NES_SCRIPT }, { 0x1B608, 0x000D, NES_SCRIPT }, { 0x1B615, 0x000D, NES_SCRIPT }, { 0x23A2E, 0x0185, NES_SCRIPT }, { 0x27957, 0x0212, NES_SCRIPT }, - { 0x23BB3, 0x0158, NES_SCRIPT }, { 0x23D0B, 0x01C4, NES_SCRIPT }, { 0x23ECF, 0x0016, NES_SCRIPT }, { 0x2BBB3, 0x005A, NES_SCRIPT }, { 0x23EE5, 0x0020, NES_SCRIPT }, - { 0x27D6A, 0x00A7, NES_SCRIPT }, { 0x2A3CD, 0x038C, NES_SCRIPT }, { 0x15062, 0x00F6, NES_SCRIPT }, { 0x2B5B2, 0x007B, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, - { 0x2526C, 0x003C, NES_SCRIPT }, { 0x1E9AF, 0x0011, NES_SCRIPT }, { 0x15B26, 0x0018, NES_SCRIPT }, { 0x265F5, 0x001F, NES_SCRIPT }, { 0x26614, 0x0054, NES_SCRIPT }, - { 0x26668, 0x018E, NES_SCRIPT }, { 0x267F6, 0x004B, NES_SCRIPT }, { 0x26841, 0x0196, NES_SCRIPT }, { 0x269D7, 0x0027, NES_SCRIPT }, { 0x269FE, 0x0041, NES_SCRIPT }, - { 0x26A3F, 0x01A3, NES_SCRIPT }, { 0x15B3E, 0x001F, NES_SCRIPT }, { 0x2465D, 0x002A, NES_SCRIPT }, { 0x15158, 0x0198, NES_SCRIPT }, { 0x192F7, 0x0031, NES_SCRIPT }, - { 0x177F4, 0x008C, NES_SCRIPT }, { 0x2166F, 0x00DA, NES_SCRIPT }, { 0x1D439, 0x0018, NES_SCRIPT }, { 0x1D451, 0x0054, NES_SCRIPT }, { 0x18C76, 0x0005, NES_SCRIPT }, - { 0x152F0, 0x0126, NES_SCRIPT }, { 0x15416, 0x000B, NES_SCRIPT }, { 0x24687, 0x0137, NES_SCRIPT }, { 0x247BE, 0x0014, NES_SCRIPT }, { 0x1DFBE, 0x0018, NES_SCRIPT }, - { 0x247D2, 0x0027, NES_SCRIPT }, { 0x1A0A4, 0x004D, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B62D, 0x00A5, NES_SCRIPT }, { 0x2A759, 0x00BA, NES_SCRIPT }, - { 0x2A813, 0x0140, NES_SCRIPT }, { 0x197CF, 0x00D0, NES_SCRIPT }, { 0x1989F, 0x014D, NES_SCRIPT }, { 0x199EC, 0x0012, NES_SCRIPT }, { 0x2A953, 0x0005, NES_SCRIPT }, - { 0x2A958, 0x0005, NES_SCRIPT }, { 0x2A95D, 0x0005, NES_SCRIPT }, { 0x2A962, 0x0005, NES_SCRIPT }, { 0x2A967, 0x0005, NES_SCRIPT }, { 0x21749, 0x0033, NES_SCRIPT }, - { 0x2A96C, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A971, 0x009C, NES_SCRIPT }, { 0x2AA0D, 0x009C, NES_SCRIPT } -}; -#endif -static const ScummNESFile::Resource *res_scripts[ScummNESFile::kROMsetNum] = { - res_scripts_usa, - res_scripts_eur, - res_scripts_swe, - res_scripts_fra, - res_scripts_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_sounds_usa; -static const ScummNESFile::Resource *res_sounds_eur; -static const ScummNESFile::Resource *res_sounds_swe; -static const ScummNESFile::Resource *res_sounds_fra; -static const ScummNESFile::Resource *res_sounds_ger; -#else -static const ScummNESFile::Resource res_sounds_usa[82] = { - { 0x0FFE8, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, - { 0x30ECA, 0x0832, NES_SOUND }, { 0x17FCA, 0x0011, NES_SOUND }, { 0x27E0B, 0x0073, NES_SOUND }, { 0x17FDB, 0x0011, NES_SOUND }, { 0x17FEC, 0x0011, NES_SOUND }, - { 0x27E7E, 0x0056, NES_SOUND }, { 0x27ED4, 0x001F, NES_SOUND }, { 0x23FEE, 0x0011, NES_SOUND }, { 0x0FFF2, 0x000A, NES_SOUND }, { 0x27EF3, 0x000A, NES_SOUND }, - { 0x27EFD, 0x0019, NES_SOUND }, { 0x27F16, 0x004B, NES_SOUND }, { 0x27F61, 0x000A, NES_SOUND }, { 0x27F6B, 0x000F, NES_SOUND }, { 0x27F7A, 0x001D, NES_SOUND }, - { 0x27F97, 0x0045, NES_SOUND }, { 0x27FDC, 0x000F, NES_SOUND }, { 0x2FD42, 0x001B, NES_SOUND }, { 0x2FD5D, 0x0033, NES_SOUND }, { 0x27FEB, 0x0011, NES_SOUND }, - { 0x2BFEF, 0x000F, NES_SOUND }, { 0x2FD90, 0x0075, NES_SOUND }, { 0x2FE05, 0x0014, NES_SOUND }, { 0x0FFE8, 0x000A, NES_SOUND }, { 0x2FE19, 0x00FF, NES_SOUND }, - { 0x2FF18, 0x000F, NES_SOUND }, { 0x2FF27, 0x000F, NES_SOUND }, { 0x2FF36, 0x0092, NES_SOUND }, { 0x2FF36, 0x0092, NES_SOUND }, { 0x2FFC8, 0x002D, NES_SOUND }, - { 0x316FC, 0x00F8, NES_SOUND }, { 0x317F4, 0x0016, NES_SOUND }, { 0x3180A, 0x0011, NES_SOUND }, { 0x3181B, 0x004B, NES_SOUND }, { 0x31866, 0x0011, NES_SOUND }, - { 0x31877, 0x003B, NES_SOUND }, { 0x318B2, 0x008A, NES_SOUND }, { 0x3193C, 0x0011, NES_SOUND }, { 0x3194D, 0x000F, NES_SOUND }, { 0x3195C, 0x00A2, NES_SOUND }, - { 0x319FE, 0x00D3, NES_SOUND }, { 0x31AD1, 0x0097, NES_SOUND }, { 0x2BFEF, 0x000F, NES_SOUND }, { 0x3195C, 0x00A2, NES_SOUND }, { 0x31B68, 0x05D1, NES_SOUND }, - { 0x31B68, 0x05D1, NES_SOUND }, { 0x32139, 0x0011, NES_SOUND }, { 0x0FFE8, 0x000A, NES_SOUND }, { 0x2FD90, 0x0075, NES_SOUND }, { 0x27ED4, 0x001F, NES_SOUND }, - { 0x3214A, 0x098E, NES_SOUND }, { 0x3181B, 0x004B, NES_SOUND }, { 0x32AD8, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x32AE9, 0x000F, NES_SOUND }, - { 0x32AF8, 0x002F, NES_SOUND }, { 0x32B27, 0x001D, NES_SOUND }, { 0x32B44, 0x0018, NES_SOUND }, { 0x32B5C, 0x0016, NES_SOUND }, { 0x32B72, 0x001B, NES_SOUND }, - { 0x32B8D, 0x0088, NES_SOUND }, { 0x32C15, 0x0065, NES_SOUND }, { 0x32C7A, 0x0065, NES_SOUND }, { 0x32CDF, 0x0073, NES_SOUND }, { 0x32D52, 0x00F9, NES_SOUND }, - { 0x32E4B, 0x049E, NES_SOUND }, { 0x34001, 0x0EA8, NES_SOUND }, { 0x332E9, 0x0B18, NES_SOUND }, { 0x34EA9, 0x0B9C, NES_SOUND }, { 0x35A45, 0x0C6B, NES_SOUND }, - { 0x366B0, 0x0E56, NES_SOUND }, { 0x38001, 0x0C70, NES_SOUND }, { 0x38C71, 0x0DEC, NES_SOUND }, { 0x39A5D, 0x0B77, NES_SOUND }, { 0x37506, 0x042F, NES_SOUND }, - { 0x3A5D4, 0x0AC5, NES_SOUND }, { 0x3B099, 0x0BE4, NES_SOUND } -}; -static const ScummNESFile::Resource res_sounds_eur[82] = { - { 0x0BF54, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, - { 0x30ECA, 0x0832, NES_SOUND }, { 0x0BF5E, 0x0011, NES_SOUND }, { 0x27ECB, 0x0073, NES_SOUND }, { 0x0BF6F, 0x0011, NES_SOUND }, { 0x0FF5D, 0x0011, NES_SOUND }, - { 0x316FC, 0x0056, NES_SOUND }, { 0x13F4E, 0x001F, NES_SOUND }, { 0x0FF6E, 0x0011, NES_SOUND }, { 0x13F6D, 0x000A, NES_SOUND }, { 0x1BF47, 0x000A, NES_SOUND }, - { 0x1BF51, 0x0019, NES_SOUND }, { 0x31752, 0x004B, NES_SOUND }, { 0x1BF6A, 0x000A, NES_SOUND }, { 0x27F3E, 0x000F, NES_SOUND }, { 0x27F4D, 0x001D, NES_SOUND }, - { 0x3179D, 0x0045, NES_SOUND }, { 0x27F6A, 0x000F, NES_SOUND }, { 0x2BF40, 0x001B, NES_SOUND }, { 0x317E2, 0x0033, NES_SOUND }, { 0x2BF5B, 0x0011, NES_SOUND }, - { 0x2BF6C, 0x000F, NES_SOUND }, { 0x31815, 0x0075, NES_SOUND }, { 0x2FF6C, 0x0014, NES_SOUND }, { 0x0BF54, 0x000A, NES_SOUND }, { 0x3188A, 0x00FF, NES_SOUND }, - { 0x31989, 0x000F, NES_SOUND }, { 0x31998, 0x000F, NES_SOUND }, { 0x319A7, 0x0092, NES_SOUND }, { 0x319A7, 0x0092, NES_SOUND }, { 0x31A39, 0x002D, NES_SOUND }, - { 0x31A66, 0x00F8, NES_SOUND }, { 0x31B5E, 0x0016, NES_SOUND }, { 0x31B74, 0x0011, NES_SOUND }, { 0x31B85, 0x004B, NES_SOUND }, { 0x31BD0, 0x0011, NES_SOUND }, - { 0x31BE1, 0x003B, NES_SOUND }, { 0x31C1C, 0x008A, NES_SOUND }, { 0x31CA6, 0x0011, NES_SOUND }, { 0x31CB7, 0x000F, NES_SOUND }, { 0x31CC6, 0x00A2, NES_SOUND }, - { 0x31D68, 0x00D3, NES_SOUND }, { 0x31E3B, 0x0097, NES_SOUND }, { 0x2BF6C, 0x000F, NES_SOUND }, { 0x31CC6, 0x00A2, NES_SOUND }, { 0x31ED2, 0x05D1, NES_SOUND }, - { 0x31ED2, 0x05D1, NES_SOUND }, { 0x324A3, 0x0011, NES_SOUND }, { 0x0BF54, 0x000A, NES_SOUND }, { 0x31815, 0x0075, NES_SOUND }, { 0x13F4E, 0x001F, NES_SOUND }, - { 0x324B4, 0x098E, NES_SOUND }, { 0x31B85, 0x004B, NES_SOUND }, { 0x32E42, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x32E53, 0x000F, NES_SOUND }, - { 0x32E62, 0x002F, NES_SOUND }, { 0x32E91, 0x001D, NES_SOUND }, { 0x32EAE, 0x0018, NES_SOUND }, { 0x32EC6, 0x0016, NES_SOUND }, { 0x32EDC, 0x001B, NES_SOUND }, - { 0x32EF7, 0x0088, NES_SOUND }, { 0x32F7F, 0x0065, NES_SOUND }, { 0x32FE4, 0x0065, NES_SOUND }, { 0x33049, 0x0073, NES_SOUND }, { 0x330BC, 0x00F9, NES_SOUND }, - { 0x331B5, 0x049E, NES_SOUND }, { 0x34001, 0x0EA8, NES_SOUND }, { 0x34EA9, 0x0B18, NES_SOUND }, { 0x359C1, 0x0B9C, NES_SOUND }, { 0x3655D, 0x0C6B, NES_SOUND }, - { 0x38001, 0x0E56, NES_SOUND }, { 0x371C8, 0x0C70, NES_SOUND }, { 0x38E57, 0x0DEC, NES_SOUND }, { 0x39C43, 0x0B77, NES_SOUND }, { 0x33653, 0x042F, NES_SOUND }, - { 0x3A7BA, 0x0AC5, NES_SOUND }, { 0x3B27F, 0x0BE4, NES_SOUND } -}; -static const ScummNESFile::Resource res_sounds_swe[82] = { - { 0x0BF58, 0x000A, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, - { 0x30352, 0x0832, NES_SOUND }, { 0x0BF62, 0x0011, NES_SOUND }, { 0x27E5F, 0x0073, NES_SOUND }, { 0x17F5A, 0x0011, NES_SOUND }, { 0x17F6B, 0x0011, NES_SOUND }, - { 0x27ED2, 0x0056, NES_SOUND }, { 0x1BF55, 0x001F, NES_SOUND }, { 0x23F66, 0x0011, NES_SOUND }, { 0x0BF73, 0x000A, NES_SOUND }, { 0x1BF74, 0x000A, NES_SOUND }, - { 0x27F28, 0x0019, NES_SOUND }, { 0x2BF0A, 0x004B, NES_SOUND }, { 0x1FF71, 0x000A, NES_SOUND }, { 0x27F41, 0x000F, NES_SOUND }, { 0x27F50, 0x001D, NES_SOUND }, - { 0x2FEAA, 0x0045, NES_SOUND }, { 0x27F6D, 0x000F, NES_SOUND }, { 0x2BF55, 0x001B, NES_SOUND }, { 0x2FEEF, 0x0033, NES_SOUND }, { 0x2FF22, 0x0011, NES_SOUND }, - { 0x2BF70, 0x000F, NES_SOUND }, { 0x30B84, 0x0075, NES_SOUND }, { 0x2FF33, 0x0014, NES_SOUND }, { 0x0BF58, 0x000A, NES_SOUND }, { 0x30BF9, 0x00FF, NES_SOUND }, - { 0x2FF47, 0x000F, NES_SOUND }, { 0x2FF56, 0x000F, NES_SOUND }, { 0x30CF8, 0x0092, NES_SOUND }, { 0x30CF8, 0x0092, NES_SOUND }, { 0x30D8A, 0x002D, NES_SOUND }, - { 0x30DB7, 0x00F8, NES_SOUND }, { 0x2FF65, 0x0016, NES_SOUND }, { 0x30EAF, 0x0011, NES_SOUND }, { 0x30EC0, 0x004B, NES_SOUND }, { 0x30F0B, 0x0011, NES_SOUND }, - { 0x30F1C, 0x003B, NES_SOUND }, { 0x30F57, 0x008A, NES_SOUND }, { 0x30FE1, 0x0011, NES_SOUND }, { 0x30FF2, 0x000F, NES_SOUND }, { 0x31001, 0x00A2, NES_SOUND }, - { 0x310A3, 0x00D3, NES_SOUND }, { 0x31176, 0x0097, NES_SOUND }, { 0x2BF70, 0x000F, NES_SOUND }, { 0x31001, 0x00A2, NES_SOUND }, { 0x3120D, 0x05D1, NES_SOUND }, - { 0x3120D, 0x05D1, NES_SOUND }, { 0x317DE, 0x0011, NES_SOUND }, { 0x0BF58, 0x000A, NES_SOUND }, { 0x30B84, 0x0075, NES_SOUND }, { 0x1BF55, 0x001F, NES_SOUND }, - { 0x317EF, 0x098E, NES_SOUND }, { 0x30EC0, 0x004B, NES_SOUND }, { 0x3217D, 0x0011, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x3218E, 0x000F, NES_SOUND }, - { 0x3219D, 0x002F, NES_SOUND }, { 0x321CC, 0x001D, NES_SOUND }, { 0x321E9, 0x0018, NES_SOUND }, { 0x32201, 0x0016, NES_SOUND }, { 0x32217, 0x001B, NES_SOUND }, - { 0x32232, 0x0088, NES_SOUND }, { 0x322BA, 0x0065, NES_SOUND }, { 0x3231F, 0x0065, NES_SOUND }, { 0x32384, 0x0073, NES_SOUND }, { 0x323F7, 0x00F9, NES_SOUND }, - { 0x324F0, 0x049E, NES_SOUND }, { 0x3298E, 0x0EA8, NES_SOUND }, { 0x34001, 0x0B18, NES_SOUND }, { 0x34B19, 0x0B9C, NES_SOUND }, { 0x356B5, 0x0C6B, NES_SOUND }, - { 0x36320, 0x0E56, NES_SOUND }, { 0x37176, 0x0C70, NES_SOUND }, { 0x38001, 0x0DEC, NES_SOUND }, { 0x38DED, 0x0B77, NES_SOUND }, { 0x33836, 0x042F, NES_SOUND }, - { 0x39964, 0x0AC5, NES_SOUND }, { 0x3A429, 0x0BE4, NES_SOUND } -}; -static const ScummNESFile::Resource res_sounds_fra[82] = { - { 0x07F74, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, - { 0x30ECA, 0x0832, NES_SOUND }, { 0x0BF6C, 0x0011, NES_SOUND }, { 0x1BEFA, 0x0073, NES_SOUND }, { 0x17F10, 0x0011, NES_SOUND }, { 0x17F21, 0x0011, NES_SOUND }, - { 0x1FED5, 0x0056, NES_SOUND }, { 0x17F32, 0x001F, NES_SOUND }, { 0x17F51, 0x0011, NES_SOUND }, { 0x0FF76, 0x000A, NES_SOUND }, { 0x17F62, 0x000A, NES_SOUND }, - { 0x1FF2B, 0x0019, NES_SOUND }, { 0x23E78, 0x004B, NES_SOUND }, { 0x17F6C, 0x000A, NES_SOUND }, { 0x1BF6D, 0x000F, NES_SOUND }, { 0x1FF44, 0x001D, NES_SOUND }, - { 0x23EC3, 0x0045, NES_SOUND }, { 0x1FF61, 0x000F, NES_SOUND }, { 0x23F08, 0x001B, NES_SOUND }, { 0x23F23, 0x0033, NES_SOUND }, { 0x23F56, 0x0011, NES_SOUND }, - { 0x1FF70, 0x000F, NES_SOUND }, { 0x27EF4, 0x0075, NES_SOUND }, { 0x23F67, 0x0014, NES_SOUND }, { 0x07F74, 0x000A, NES_SOUND }, { 0x2FB83, 0x00FF, NES_SOUND }, - { 0x27F69, 0x000F, NES_SOUND }, { 0x2BF70, 0x000F, NES_SOUND }, { 0x2FC82, 0x0092, NES_SOUND }, { 0x2FC82, 0x0092, NES_SOUND }, { 0x2FD14, 0x002D, NES_SOUND }, - { 0x2FD41, 0x00F8, NES_SOUND }, { 0x2FE39, 0x0016, NES_SOUND }, { 0x2FE4F, 0x0011, NES_SOUND }, { 0x2FE60, 0x004B, NES_SOUND }, { 0x2FEAB, 0x0011, NES_SOUND }, - { 0x2FEBC, 0x003B, NES_SOUND }, { 0x316FC, 0x008A, NES_SOUND }, { 0x2FEF7, 0x0011, NES_SOUND }, { 0x2FF08, 0x000F, NES_SOUND }, { 0x31786, 0x00A2, NES_SOUND }, - { 0x31828, 0x00D3, NES_SOUND }, { 0x318FB, 0x0097, NES_SOUND }, { 0x1FF70, 0x000F, NES_SOUND }, { 0x31786, 0x00A2, NES_SOUND }, { 0x31992, 0x05D1, NES_SOUND }, - { 0x31992, 0x05D1, NES_SOUND }, { 0x2FF17, 0x0011, NES_SOUND }, { 0x07F74, 0x000A, NES_SOUND }, { 0x27EF4, 0x0075, NES_SOUND }, { 0x17F32, 0x001F, NES_SOUND }, - { 0x31F63, 0x098E, NES_SOUND }, { 0x2FE60, 0x004B, NES_SOUND }, { 0x2FF28, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x2FF39, 0x000F, NES_SOUND }, - { 0x2FF48, 0x002F, NES_SOUND }, { 0x328F1, 0x001D, NES_SOUND }, { 0x3290E, 0x0018, NES_SOUND }, { 0x32926, 0x0016, NES_SOUND }, { 0x3293C, 0x001B, NES_SOUND }, - { 0x32957, 0x0088, NES_SOUND }, { 0x329DF, 0x0065, NES_SOUND }, { 0x32A44, 0x0065, NES_SOUND }, { 0x32AA9, 0x0073, NES_SOUND }, { 0x32B1C, 0x00F9, NES_SOUND }, - { 0x32C15, 0x049E, NES_SOUND }, { 0x330B3, 0x0EA8, NES_SOUND }, { 0x34001, 0x0B18, NES_SOUND }, { 0x34B19, 0x0B9C, NES_SOUND }, { 0x356B5, 0x0C6B, NES_SOUND }, - { 0x36320, 0x0E56, NES_SOUND }, { 0x37176, 0x0C70, NES_SOUND }, { 0x38001, 0x0DEC, NES_SOUND }, { 0x38DED, 0x0B77, NES_SOUND }, { 0x39964, 0x042F, NES_SOUND }, - { 0x39D93, 0x0AC5, NES_SOUND }, { 0x3A858, 0x0BE4, NES_SOUND } -}; -static const ScummNESFile::Resource res_sounds_ger[82] = { - { 0x0BF6D, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, - { 0x30ECA, 0x0832, NES_SOUND }, { 0x23F05, 0x0011, NES_SOUND }, { 0x2FA49, 0x0073, NES_SOUND }, { 0x23F16, 0x0011, NES_SOUND }, { 0x23F27, 0x0011, NES_SOUND }, - { 0x2FABC, 0x0056, NES_SOUND }, { 0x23F38, 0x001F, NES_SOUND }, { 0x23F57, 0x0011, NES_SOUND }, { 0x0FF76, 0x000A, NES_SOUND }, { 0x17F71, 0x000A, NES_SOUND }, - { 0x2BF2F, 0x0019, NES_SOUND }, { 0x2FB12, 0x004B, NES_SOUND }, { 0x23F68, 0x000A, NES_SOUND }, { 0x2BF48, 0x000F, NES_SOUND }, { 0x2BF57, 0x001D, NES_SOUND }, - { 0x2FB5D, 0x0045, NES_SOUND }, { 0x2FBA2, 0x000F, NES_SOUND }, { 0x2FBB1, 0x001B, NES_SOUND }, { 0x2FBCC, 0x0033, NES_SOUND }, { 0x2FBFF, 0x0011, NES_SOUND }, - { 0x2FC10, 0x000F, NES_SOUND }, { 0x2FC1F, 0x0075, NES_SOUND }, { 0x2FC94, 0x0014, NES_SOUND }, { 0x0BF6D, 0x000A, NES_SOUND }, { 0x2FCA8, 0x00FF, NES_SOUND }, - { 0x2FDA7, 0x000F, NES_SOUND }, { 0x2FDB6, 0x000F, NES_SOUND }, { 0x2FDC5, 0x0092, NES_SOUND }, { 0x2FDC5, 0x0092, NES_SOUND }, { 0x2FE57, 0x002D, NES_SOUND }, - { 0x2FE84, 0x00F8, NES_SOUND }, { 0x316FC, 0x0016, NES_SOUND }, { 0x31712, 0x0011, NES_SOUND }, { 0x31723, 0x004B, NES_SOUND }, { 0x3176E, 0x0011, NES_SOUND }, - { 0x3177F, 0x003B, NES_SOUND }, { 0x317BA, 0x008A, NES_SOUND }, { 0x31844, 0x0011, NES_SOUND }, { 0x31855, 0x000F, NES_SOUND }, { 0x31864, 0x00A2, NES_SOUND }, - { 0x31906, 0x00D3, NES_SOUND }, { 0x319D9, 0x0097, NES_SOUND }, { 0x2FC10, 0x000F, NES_SOUND }, { 0x31864, 0x00A2, NES_SOUND }, { 0x31A70, 0x05D1, NES_SOUND }, - { 0x31A70, 0x05D1, NES_SOUND }, { 0x32041, 0x0011, NES_SOUND }, { 0x0BF6D, 0x000A, NES_SOUND }, { 0x2FC1F, 0x0075, NES_SOUND }, { 0x23F38, 0x001F, NES_SOUND }, - { 0x32052, 0x098E, NES_SOUND }, { 0x31723, 0x004B, NES_SOUND }, { 0x329E0, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x329F1, 0x000F, NES_SOUND }, - { 0x32A00, 0x002F, NES_SOUND }, { 0x32A2F, 0x001D, NES_SOUND }, { 0x32A4C, 0x0018, NES_SOUND }, { 0x32A64, 0x0016, NES_SOUND }, { 0x32A7A, 0x001B, NES_SOUND }, - { 0x32A95, 0x0088, NES_SOUND }, { 0x32B1D, 0x0065, NES_SOUND }, { 0x32B82, 0x0065, NES_SOUND }, { 0x32BE7, 0x0073, NES_SOUND }, { 0x32C5A, 0x00F9, NES_SOUND }, - { 0x32D53, 0x049E, NES_SOUND }, { 0x34001, 0x0EA8, NES_SOUND }, { 0x331F1, 0x0B18, NES_SOUND }, { 0x34EA9, 0x0B9C, NES_SOUND }, { 0x35A45, 0x0C6B, NES_SOUND }, - { 0x366B0, 0x0E56, NES_SOUND }, { 0x38001, 0x0C70, NES_SOUND }, { 0x38C71, 0x0DEC, NES_SOUND }, { 0x39A5D, 0x0B77, NES_SOUND }, { 0x37506, 0x042F, NES_SOUND }, - { 0x3A5D4, 0x0AC5, NES_SOUND }, { 0x3B099, 0x0BE4, NES_SOUND } -}; -#endif -static const ScummNESFile::Resource *res_sounds[ScummNESFile::kROMsetNum] = { - res_sounds_usa, - res_sounds_eur, - res_sounds_swe, - res_sounds_fra, - res_sounds_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_costumes_usa; -static const ScummNESFile::Resource *res_costumes_eur; -static const ScummNESFile::Resource *res_costumes_swe; -static const ScummNESFile::Resource *res_costumes_fra; -static const ScummNESFile::Resource *res_costumes_ger; -#else -static const ScummNESFile::Resource res_costumes_usa[25] = { - { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, - { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x13FAB, 0x004B, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, - { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F5A, 0x0036, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, - { 0x17F05, 0x0055, NES_COSTUME }, { 0x1BF87, 0x003B, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x23FA9, 0x0045, NES_COSTUME }, { 0x1FFBD, 0x0040, NES_COSTUME }, - { 0x1BFC2, 0x003C, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x13FAB, 0x004B, NES_COSTUME } -}; -static const ScummNESFile::Resource res_costumes_eur[25] = { - { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, - { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0FEA2, 0x004B, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, - { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0FEED, 0x0036, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, - { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x13F13, 0x003B, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x23F2F, 0x0045, NES_COSTUME }, { 0x1FF3E, 0x0040, NES_COSTUME }, - { 0x27E8F, 0x003C, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0FEA2, 0x004B, NES_COSTUME } -}; -static const ScummNESFile::Resource res_costumes_swe[25] = { - { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, - { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x17E9A, 0x004B, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, - { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FF4A, 0x0036, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, - { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x17F1F, 0x003B, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x1BE94, 0x0045, NES_COSTUME }, { 0x1BED9, 0x0040, NES_COSTUME }, - { 0x1BF19, 0x003C, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x17E9A, 0x004B, NES_COSTUME } -}; -static const ScummNESFile::Resource res_costumes_fra[25] = { - { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, - { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13E77, 0x004B, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, - { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x07F3E, 0x0036, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, - { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13EFC, 0x003B, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13F37, 0x0045, NES_COSTUME }, { 0x17E94, 0x0040, NES_COSTUME }, - { 0x17ED4, 0x003C, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13E77, 0x004B, NES_COSTUME } -}; -static const ScummNESFile::Resource res_costumes_ger[25] = { - { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, - { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17E6C, 0x004B, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, - { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FF40, 0x0036, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, - { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17EF1, 0x003B, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17F2C, 0x0045, NES_COSTUME }, { 0x1FEFD, 0x0040, NES_COSTUME }, - { 0x1FF3D, 0x003C, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17E6C, 0x004B, NES_COSTUME } -}; -#endif -static const ScummNESFile::Resource *res_costumes[ScummNESFile::kROMsetNum] = { - res_costumes_usa, - res_costumes_eur, - res_costumes_swe, - res_costumes_fra, - res_costumes_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_globdata_usa; -static const ScummNESFile::Resource *res_globdata_eur; -static const ScummNESFile::Resource *res_globdata_swe; -static const ScummNESFile::Resource *res_globdata_fra; -static const ScummNESFile::Resource *res_globdata_ger; -#else -static const ScummNESFile::Resource res_globdata_usa[1] = { { 0x2CA11, 0x0307, NES_GLOBDATA } }; -static const ScummNESFile::Resource res_globdata_eur[1] = { { 0x2CA11, 0x0307, NES_GLOBDATA } }; -static const ScummNESFile::Resource res_globdata_swe[1] = { { 0x2C001, 0x0307, NES_GLOBDATA } }; -static const ScummNESFile::Resource res_globdata_fra[1] = { { 0x2C628, 0x0307, NES_GLOBDATA } }; -static const ScummNESFile::Resource res_globdata_ger[1] = { { 0x2C4EE, 0x0307, NES_GLOBDATA } }; -#endif -static const ScummNESFile::Resource *res_globdata[ScummNESFile::kROMsetNum] = { - res_globdata_usa, - res_globdata_eur, - res_globdata_swe, - res_globdata_fra, - res_globdata_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_sprpals_usa; -static const ScummNESFile::Resource *res_sprpals_eur; -static const ScummNESFile::Resource *res_sprpals_swe; -static const ScummNESFile::Resource *res_sprpals_fra; -static const ScummNESFile::Resource *res_sprpals_ger; -#else -// sprite palette data -static const ScummNESFile::Resource res_sprpals_usa[2] = { { 0x0BFC1, 0x0010, NES_SPRPALS }, { 0x0BFD1, 0x0010, NES_SPRPALS } }; -static const ScummNESFile::Resource res_sprpals_eur[2] = { { 0x07F61, 0x0010, NES_SPRPALS }, { 0x0BEB2, 0x0010, NES_SPRPALS } }; -static const ScummNESFile::Resource res_sprpals_swe[2] = { { 0x07F55, 0x0010, NES_SPRPALS }, { 0x07F65, 0x0010, NES_SPRPALS } }; -static const ScummNESFile::Resource res_sprpals_fra[2] = { { 0x07ED8, 0x0010, NES_SPRPALS }, { 0x07EE8, 0x0010, NES_SPRPALS } }; -static const ScummNESFile::Resource res_sprpals_ger[2] = { { 0x07F6B, 0x0010, NES_SPRPALS }, { 0x0BF17, 0x0010, NES_SPRPALS } }; -#endif -static const ScummNESFile::Resource *res_sprpals[ScummNESFile::kROMsetNum] = { - res_sprpals_usa, - res_sprpals_eur, - res_sprpals_swe, - res_sprpals_fra, - res_sprpals_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_sprdesc_usa; -static const ScummNESFile::Resource *res_sprdesc_eur; -static const ScummNESFile::Resource *res_sprdesc_swe; -static const ScummNESFile::Resource *res_sprdesc_fra; -static const ScummNESFile::Resource *res_sprdesc_ger; -#else -// associates costume IDs with sprite sets (indexes into SPRLENS/SPROFFS) -static const ScummNESFile::Resource res_sprdesc_usa[2] = { { 0x0FFB7, 0x0031, NES_SPRDESC }, { 0x0BFE1, 0x0009, NES_SPRDESC } }; -static const ScummNESFile::Resource res_sprdesc_eur[2] = { { 0x0BEC2, 0x0031, NES_SPRDESC }, { 0x07F71, 0x0009, NES_SPRDESC } }; -static const ScummNESFile::Resource res_sprdesc_swe[2] = { { 0x0BF1B, 0x0031, NES_SPRDESC }, { 0x07F75, 0x0009, NES_SPRDESC } }; -static const ScummNESFile::Resource res_sprdesc_fra[2] = { { 0x07EF8, 0x0031, NES_SPRDESC }, { 0x07F29, 0x0009, NES_SPRDESC } }; -static const ScummNESFile::Resource res_sprdesc_ger[2] = { { 0x0BF27, 0x0031, NES_SPRDESC }, { 0x0BF58, 0x0009, NES_SPRDESC } }; -#endif -static const ScummNESFile::Resource *res_sprdesc[ScummNESFile::kROMsetNum] = { - res_sprdesc_usa, - res_sprdesc_eur, - res_sprdesc_swe, - res_sprdesc_fra, - res_sprdesc_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_sprlens_usa; -static const ScummNESFile::Resource *res_sprlens_eur; -static const ScummNESFile::Resource *res_sprlens_swe; -static const ScummNESFile::Resource *res_sprlens_fra; -static const ScummNESFile::Resource *res_sprlens_ger; -#else -// number of sprites in each set (indicates length within SPRDATA) -static const ScummNESFile::Resource res_sprlens_usa[2] = { { 0x0FEA2, 0x0115, NES_SPRLENS }, { 0x07FF5, 0x0006, NES_SPRLENS } }; -static const ScummNESFile::Resource res_sprlens_eur[2] = { { 0x1BE32, 0x0115, NES_SPRLENS }, { 0x07F5B, 0x0006, NES_SPRLENS } }; -static const ScummNESFile::Resource res_sprlens_swe[2] = { { 0x13E6A, 0x0115, NES_SPRLENS }, { 0x07F4F, 0x0006, NES_SPRLENS } }; -static const ScummNESFile::Resource res_sprlens_fra[2] = { { 0x0FE61, 0x0115, NES_SPRLENS }, { 0x07ED2, 0x0006, NES_SPRLENS } }; -static const ScummNESFile::Resource res_sprlens_ger[2] = { { 0x2BE1A, 0x0115, NES_SPRLENS }, { 0x07F65, 0x0006, NES_SPRLENS } }; -#endif -static const ScummNESFile::Resource *res_sprlens[ScummNESFile::kROMsetNum] = { - res_sprlens_usa, - res_sprlens_eur, - res_sprlens_swe, - res_sprlens_fra, - res_sprlens_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_sproffs_usa; -static const ScummNESFile::Resource *res_sproffs_eur; -static const ScummNESFile::Resource *res_sproffs_swe; -static const ScummNESFile::Resource *res_sproffs_fra; -static const ScummNESFile::Resource *res_sproffs_ger; -#else -// offset of each sprite set (indexes into SPRDATA) -static const ScummNESFile::Resource res_sproffs_usa[2] = { { 0x2BDC5, 0x022A, NES_SPROFFS }, { 0x0BFEA, 0x000C, NES_SPROFFS } }; -static const ScummNESFile::Resource res_sproffs_eur[2] = { { 0x2FD42, 0x022A, NES_SPROFFS }, { 0x0BEF3, 0x000C, NES_SPROFFS } }; -static const ScummNESFile::Resource res_sproffs_swe[2] = { { 0x2BCE0, 0x022A, NES_SPROFFS }, { 0x0BF4C, 0x000C, NES_SPROFFS } }; -static const ScummNESFile::Resource res_sproffs_fra[2] = { { 0x2F959, 0x022A, NES_SPROFFS }, { 0x07F32, 0x000C, NES_SPROFFS } }; -static const ScummNESFile::Resource res_sproffs_ger[2] = { { 0x2F81F, 0x022A, NES_SPROFFS }, { 0x0BF61, 0x000C, NES_SPROFFS } }; -#endif -static const ScummNESFile::Resource *res_sproffs[ScummNESFile::kROMsetNum] = { - res_sproffs_usa, - res_sproffs_eur, - res_sproffs_swe, - res_sproffs_fra, - res_sproffs_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_sprdata_usa; -static const ScummNESFile::Resource *res_sprdata_eur; -static const ScummNESFile::Resource *res_sprdata_swe; -static const ScummNESFile::Resource *res_sprdata_fra; -static const ScummNESFile::Resource *res_sprdata_ger; -#else -// sprite data sets (packed NES sprite data) -static const ScummNESFile::Resource res_sprdata_usa[2] = { { 0x2CE11, 0x2BE0, NES_SPRDATA }, { 0x07F6B, 0x008A, NES_SPRDATA } }; -static const ScummNESFile::Resource res_sprdata_eur[2] = { { 0x2CE11, 0x2BE0, NES_SPRDATA }, { 0x0BE28, 0x008A, NES_SPRDATA } }; -static const ScummNESFile::Resource res_sprdata_swe[2] = { { 0x2C401, 0x2BE0, NES_SPRDATA }, { 0x0FE6B, 0x008A, NES_SPRDATA } }; -static const ScummNESFile::Resource res_sprdata_fra[2] = { { 0x2CA28, 0x2BE0, NES_SPRDATA }, { 0x07E48, 0x008A, NES_SPRDATA } }; -static const ScummNESFile::Resource res_sprdata_ger[2] = { { 0x2C8EE, 0x2BE0, NES_SPRDATA }, { 0x0FE61, 0x008A, NES_SPRDATA } }; -static const ScummNESFile::Resource *res_sprdata[ScummNESFile::kROMsetNum] = { - res_sprdata_usa, - res_sprdata_eur, - res_sprdata_swe, - res_sprdata_fra, - res_sprdata_ger, -}; -#endif - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_charset_usa; -static const ScummNESFile::Resource *res_charset_eur; -static const ScummNESFile::Resource *res_charset_swe; -static const ScummNESFile::Resource *res_charset_fra; -static const ScummNESFile::Resource *res_charset_ger; -#else -static const ScummNESFile::Resource res_charset_usa[1] = { { 0x3F6EE, 0x0090, NES_CHARSET } }; -static const ScummNESFile::Resource res_charset_eur[1] = { { 0x3F724, 0x0090, NES_CHARSET } }; -static const ScummNESFile::Resource res_charset_swe[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; -static const ScummNESFile::Resource res_charset_fra[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; -static const ScummNESFile::Resource res_charset_ger[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; -#endif -static const ScummNESFile::Resource *res_charset[ScummNESFile::kROMsetNum] = { - res_charset_usa, - res_charset_eur, - res_charset_swe, - res_charset_fra, - res_charset_ger, -}; - -#ifdef PALMOS_68K -static const ScummNESFile::Resource *res_preplist_usa; -static const ScummNESFile::Resource *res_preplist_eur; -static const ScummNESFile::Resource *res_preplist_swe; -static const ScummNESFile::Resource *res_preplist_fra; -static const ScummNESFile::Resource *res_preplist_ger; -#else -static const ScummNESFile::Resource res_preplist_usa[1] = { { 0x3FB5A, 0x000E, NES_PREPLIST } }; -static const ScummNESFile::Resource res_preplist_eur[1] = { { 0x3FB90, 0x000E, NES_PREPLIST } }; -static const ScummNESFile::Resource res_preplist_swe[1] = { { 0x3FBA9, 0x000E, NES_PREPLIST } }; -static const ScummNESFile::Resource res_preplist_fra[1] = { { 0x3FBAF, 0x0010, NES_PREPLIST } }; -static const ScummNESFile::Resource res_preplist_ger[1] = { { 0x3FBAB, 0x000F, NES_PREPLIST } }; -#endif -static const ScummNESFile::Resource *res_preplist[ScummNESFile::kROMsetNum] = { - res_preplist_usa, - res_preplist_eur, - res_preplist_swe, - res_preplist_fra, - res_preplist_ger, -}; - -uint16 write_byte(Common::WriteStream *out, byte val) { - val ^= 0xFF; - if (out != 0) - out->writeByte(val); - return 1; -} - -uint16 write_word(Common::WriteStream *out, uint16 val) { - val ^= 0xFFFF; - if (out != 0) - out->writeUint16LE(val); - return 2; -} - -byte ScummNESFile::fileReadByte() { - byte b = 0; - File::read(&b, 1); - return b; -} - -uint16 ScummNESFile::fileReadUint16LE() { - uint16 a = fileReadByte(); - uint16 b = fileReadByte(); - return a | (b << 8); -} - -uint16 ScummNESFile::extractResource(Common::WriteStream *output, const Resource *res) { - uint16 len, i, j; - byte val; - byte cnt; - uint16 reslen = 0; - - if (res == NULL) - error("extract_resource - no resource specified"); - - if ((res->offset == 0) && (res->length == 0)) - return 0; /* there are 8 scripts that are zero bytes long, so we should skip them */ - - File::seek(res->offset,SEEK_SET); - - switch (res->type) { - case NES_GLOBDATA: - len = res->length; - - for (i = 0; i < len; i++) - reslen += write_byte(output, fileReadByte()); - - break; - - case NES_ROOMGFX: - case NES_COSTUMEGFX: - reslen += write_word(output, (uint16)(res->length + 2)); - len = fileReadByte(); - reslen += write_byte(output, (byte)len); - - if (!len) - len = 256; - len = len << 4; - - for (i = 0; i < len;) { - reslen += write_byte(output, cnt = fileReadByte()); - for (j = 0; j < (cnt & 0x7F); j++, i++) - if ((cnt & 0x80) || (j == 0)) - reslen += write_byte(output, fileReadByte()); - } - - if (File::pos() - res->offset != res->length) - error("extract_resource - length mismatch while extracting graphics resource (was %04X, should be %04X)", File::pos() - res->offset, res->length); - - break; - - case NES_ROOM: - case NES_SCRIPT: - len = fileReadUint16LE(); - - if (len != res->length) - error("extract_resource - length mismatch while extracting room/script resource (was %04X, should be %04X)", len, res->length); - - File::seek(-2, SEEK_CUR); - - for (i = 0; i < len; i++) - reslen += write_byte(output, fileReadByte()); - - break; - - case NES_SOUND: - len = res->length + 2; - val = fileReadByte(); - cnt = fileReadByte(); - - if ((val == 2) && (cnt == 100)) { - reslen += write_word(output, len); - reslen += write_byte(output, val); - reslen += write_byte(output, cnt); - - cnt = fileReadByte(); - reslen += write_byte(output, cnt); - for (i = 0; i < cnt; i++) - reslen += write_byte(output, fileReadByte()); - for (i = 0; i < cnt; i++) - reslen += write_byte(output, fileReadByte()); - - while (1) { - reslen += write_byte(output, val = fileReadByte()); - if (val >= 0xFE) - break; - } - } else if (((val == 0) || (val == 1) || (val == 4)) && (cnt == 10)) { - reslen += write_word(output, len); - reslen += write_byte(output, val); - reslen += write_byte(output, cnt); - while (1) { - reslen += write_byte(output, val = fileReadByte()); - - if (val >= 0xFE) - break; - - if (val >= 0x10) - reslen += write_byte(output, fileReadByte()); - else { - reslen += write_byte(output, fileReadByte()); - reslen += write_byte(output, fileReadByte()); - reslen += write_byte(output, fileReadByte()); - reslen += write_byte(output, fileReadByte()); - } - } - } else - error("extract_resource - unknown sound type %d/%d detected",val,cnt); - - if (File::pos() - res->offset != res->length) - error("extract_resource - length mismatch while extracting sound resource (was %04X, should be %04X)", File::pos() - res->offset, res->length); - - break; - - case NES_COSTUME: - case NES_SPRPALS: - case NES_SPRDESC: - case NES_SPRLENS: - case NES_SPROFFS: - case NES_SPRDATA: - case NES_CHARSET: - len = res->length; - reslen += write_word(output, (uint16)(len + 2)); - - for (i = 0; i < len; i++) - reslen += write_byte(output, fileReadByte()); - - break; - - case NES_PREPLIST: - len = res->length; - reslen += write_word(output, 0x002A); - - reslen += write_byte(output, ' '); - for (i = 1; i < 8; i++) - reslen += write_byte(output, 0); - - for (j = 0; j < 4; j++) - { - reslen += write_byte(output,' '); - for (i = 1; (val = fileReadByte()); i++) - reslen += write_byte(output, val); - for (; i < 8; i++) - reslen += write_byte(output, 0); - } - break; - - default: - error("extract_resource - unknown resource type %d specified!", res->type); - } - - return reslen; -} - -struct ScummNESFile::LFLEntry { - const Resource **type; - int index; -}; - -// based on structure of Classic PC Maniac Mansion LFL files -// (roomgfx resources are arranged in order, one per file, -// after the room blocks) -static const ScummNESFile::LFLEntry lfl_01[] = { {res_rooms, 1}, {res_roomgfx, 1}, {res_scripts, 57}, {res_scripts, 61}, {res_scripts, 76}, {res_scripts, 105}, {res_scripts, 111}, {res_sounds, 5}, {res_scripts, 132}, {res_scripts, 148}, {res_scripts, 155}, {res_scripts, 156}, {res_sounds, 39}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_02[] = { {res_rooms, 2}, {res_roomgfx, 2}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_03[] = { {res_rooms, 3}, {res_roomgfx, 3}, {res_scripts, 21}, {res_sounds, 26}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_04[] = { {res_rooms, 4}, {res_roomgfx, 4}, {res_scripts, 46}, {res_scripts, 56}, {res_scripts, 137}, {res_scripts, 146}, {res_sounds, 12}, {res_sounds, 11}, {res_sounds, 13}, {res_sounds, 42}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_05[] = { {res_rooms, 5}, {res_roomgfx, 5}, {res_scripts, 30}, {res_scripts, 31}, {res_scripts, 32}, {res_scripts, 33}, {res_scripts, 34}, {res_scripts, 35}, {res_sounds, 22}, {res_sounds, 23}, {res_sounds, 24}, {res_sounds, 21}, {res_sounds, 46}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_06[] = { {res_rooms, 6}, {res_roomgfx, 6}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_07[] = { {res_rooms, 7}, {res_roomgfx, 7}, {res_scripts, 17}, {res_scripts, 58}, {res_scripts, 59}, {res_scripts, 60}, {res_scripts, 74}, {res_scripts, 81}, {res_scripts, 82}, {res_scripts, 150}, {res_sounds, 14}, {res_sounds, 15}, {res_sounds, 16}, {res_sounds, 17}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_08[] = { {res_rooms, 8}, {res_roomgfx, 8}, {res_scripts, 7}, {res_scripts, 12}, {res_scripts, 13}, {res_scripts, 47}, {res_scripts, 48}, {res_scripts, 49}, {res_scripts, 154}, {res_sounds, 32}, {res_sounds, 33}, {res_sounds, 36}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_09[] = { {res_rooms, 9}, {res_roomgfx, 9}, {res_scripts, 10}, {res_scripts, 11}, {res_scripts, 45}, {res_scripts, 55}, {res_scripts, 84}, {res_scripts, 85}, {res_scripts, 86}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_10[] = { {res_rooms, 10}, {res_roomgfx, 10}, {res_scripts, 24}, {res_scripts, 149}, {res_sounds, 28}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_11[] = { {res_rooms, 11}, {res_roomgfx, 11}, {res_scripts, 166}, {res_scripts, 167}, {res_scripts, 168}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_12[] = { {res_rooms, 12}, {res_roomgfx, 12}, {res_scripts, 51}, {res_scripts, 103}, {res_scripts, 104}, {res_scripts, 161}, {res_sounds, 63}, {res_costumes, 14}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_13[] = { {res_rooms, 13}, {res_roomgfx, 13}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_14[] = { {res_rooms, 14}, {res_roomgfx, 14}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_15[] = { {res_rooms, 15}, {res_roomgfx, 15}, {res_sounds, 27}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_16[] = { {res_rooms, 16}, {res_roomgfx, 16}, {res_scripts, 14}, {res_scripts, 121}, {res_scripts, 122}, {res_sounds, 40}, {res_sounds, 64}, {res_sounds, 68}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_17[] = { {res_rooms, 17}, {res_roomgfx, 17}, {res_scripts, 20}, {res_scripts, 100}, {res_sounds, 25}, {res_sounds, 44}, {res_sounds, 2}, {res_sounds, 50}, {res_sounds, 52}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_18[] = { {res_rooms, 18}, {res_roomgfx, 18}, {res_scripts, 25}, {res_scripts, 26}, {res_scripts, 27}, {res_scripts, 28}, {res_scripts, 64}, {res_scripts, 65}, {res_scripts, 66}, {res_scripts, 67}, {res_scripts, 68}, {res_scripts, 69}, {res_scripts, 70}, {res_scripts, 71}, {res_scripts, 73}, {res_scripts, 101}, {res_sounds, 35}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_19[] = { {res_rooms, 19}, {res_roomgfx, 19}, {res_scripts, 36}, {res_scripts, 37}, {res_scripts, 38}, {res_scripts, 39}, {res_scripts, 40}, {res_scripts, 152}, {res_scripts, 153}, {res_costumes, 10}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_20[] = { {res_rooms, 20}, {res_roomgfx, 20}, {res_scripts, 107}, {res_scripts, 108}, {res_scripts, 109}, {res_scripts, 110}, {res_scripts, 159}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_21[] = { {res_rooms, 21}, {res_roomgfx, 21}, {res_scripts, 41}, {res_scripts, 42}, {res_scripts, 43}, {res_scripts, 53}, {res_scripts, 136}, {res_sounds, 29}, {res_sounds, 20}, {res_sounds, 37}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_22[] = { {res_rooms, 22}, {res_roomgfx, 22}, {res_scripts, 15}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_23[] = { {res_rooms, 23}, {res_roomgfx, 23}, {res_scripts, 77}, {res_scripts, 79}, {res_scripts, 80}, {res_scripts, 83}, {res_sounds, 41}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_24[] = { {res_rooms, 24}, {res_roomgfx, 24}, {res_scripts, 18}, {res_scripts, 19}, {res_scripts, 78}, {res_sounds, 7}, {res_sounds, 3}, {res_sounds, 18}, {res_sounds, 34}, {res_costumes, 12}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_25[] = { {res_rooms, 25}, {res_roomgfx, 25}, {res_scripts, 29}, {res_sounds, 30}, {res_sounds, 31}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_26[] = { {res_rooms, 26}, {res_roomgfx, 26}, {res_scripts, 87}, {res_scripts, 88}, {res_scripts, 89}, {res_scripts, 90}, {res_scripts, 91}, {res_scripts, 92}, {res_scripts, 93}, {res_scripts, 94}, {res_scripts, 95}, {res_scripts, 96}, {res_scripts, 97}, {res_scripts, 98}, {res_scripts, 116}, {res_scripts, 151}, {res_scripts, 174}, {res_costumes, 11}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_27[] = { {res_rooms, 27}, {res_roomgfx, 27}, {res_scripts, 16}, {res_scripts, 52}, {res_scripts, 54}, {res_scripts, 113}, {res_sounds, 45}, {res_costumes, 19}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_28[] = { {res_rooms, 28}, {res_roomgfx, 28}, {res_scripts, 22}, {res_scripts, 23}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_29[] = { {res_rooms, 29}, {res_roomgfx, 29}, {res_scripts, 75}, {res_sounds, 43}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_30[] = { {res_rooms, 30}, {res_roomgfx, 30}, {res_scripts, 63}, {res_sounds, 0}, {res_scripts, 123}, {res_scripts, 125}, {res_scripts, 126}, {res_scripts, 127}, {res_scripts, 129}, {res_sounds, 55}, {res_sounds, 59}, {res_sounds, 60}, {res_costumes, 8}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_31[] = { {res_rooms, 31}, {res_roomgfx, 31}, {res_scripts, 99}, {res_scripts, 115}, {res_scripts, 117}, {res_scripts, 119}, {res_scripts, 147}, {res_scripts, 157}, {res_scripts, 158}, {res_scripts, 160}, {res_costumes, 13}, {res_costumes, 9}, {res_costumes, 23}, {res_costumes, 24}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_32[] = { {res_rooms, 32}, {res_roomgfx, 32}, {res_costumes, 15}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_33[] = { {res_rooms, 33}, {res_roomgfx, 33}, {res_scripts, 120}, {res_scripts, 135}, {res_sounds, 56}, {res_sounds, 57}, {res_sounds, 58}, {res_sounds, 1}, {res_costumes, 22}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_34[] = { {res_rooms, 34}, {res_roomgfx, 34}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_35[] = { {res_rooms, 35}, {res_roomgfx, 35}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_36[] = { {res_rooms, 36}, {res_roomgfx, 36}, {res_sounds, 10}, {res_sounds, 4}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_37[] = { {res_rooms, 37}, {res_roomgfx, 37}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_38[] = { {res_rooms, 38}, {res_roomgfx, 38}, {res_scripts, 138}, {res_scripts, 139}, {res_scripts, 140}, {res_scripts, 141}, {res_scripts, 142}, {res_scripts, 143}, {res_scripts, 144}, {res_scripts, 145}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_39[] = { {res_rooms, 39}, {res_roomgfx, 39}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_40[] = { {res_rooms, 40}, {res_roomgfx, 0}, {res_scripts, 112}, {res_costumes, 17}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_41[] = { {res_rooms, 41}, {res_scripts, 106}, {res_sounds, 47}, {res_sounds, 48}, {res_sounds, 53}, {res_sounds, 49}, {res_sounds, 51}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_42[] = { {res_rooms, 42}, {res_scripts, 124}, {res_costumes, 18}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_43[] = { {res_rooms, 43}, {res_scripts, 44}, {res_sounds, 19}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_44[] = { {res_rooms, 44}, {res_scripts, 102}, {res_sounds, 6}, {res_sounds, 38}, {res_sounds, 8}, {res_sounds, 9}, {res_costumes, 1}, {res_costumes, 2}, {res_costumes, 5}, {res_costumes, 6}, {res_costumes, 3}, {res_costumes, 4}, {res_costumes, 7}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_45[] = { {res_rooms, 45}, {res_scripts, 1}, {res_scripts, 2}, {res_scripts, 3}, {res_scripts, 4}, {res_scripts, 5}, {res_scripts, 9}, {res_scripts, 114}, {res_scripts, 131}, {res_scripts, 164}, {res_scripts, 165}, {res_scripts, 169}, {res_scripts, 170}, {res_scripts, 171}, {res_scripts, 172}, {res_scripts, 173}, {res_scripts, 175}, {res_sounds, 54}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_46[] = { {res_rooms, 46}, {res_scripts, 130}, {res_sounds, 65}, {res_costumes, 0}, {res_costumes, 21}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_47[] = { {res_rooms, 47}, {res_scripts, 62}, {res_sounds, 69}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_48[] = { {res_rooms, 48}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_49[] = { {res_rooms, 49}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_50[] = { {res_rooms, 50}, {res_scripts, 133}, {res_scripts, 163}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_51[] = { {res_rooms, 51}, {res_scripts, 118}, {res_scripts, 128}, {res_sounds, 61}, {res_sounds, 62}, {res_sounds, 67}, {res_sounds, 66}, {res_costumes, 16}, {res_costumes, 20}, {NULL, 0} }; -static const ScummNESFile::LFLEntry lfl_52[] = { {res_rooms, 52}, {NULL, 0} }; -// remaining 'standard' resources (not used by any of the original LFL files) -static const ScummNESFile::LFLEntry lfl_53[] = { {res_rooms, 53}, {res_scripts, 177}, {res_scripts, 178}, {res_sounds, 70}, {res_sounds, 71}, {res_sounds, 72}, {res_sounds, 73}, {res_sounds, 74}, {res_sounds, 75}, {res_sounds, 76}, {res_sounds, 77}, {res_sounds, 78}, {res_sounds, 79}, {res_sounds, 80}, {res_sounds, 81}, {NULL, 0} }; -// all 'non-standard' resources (the costume-related stuff) -static const ScummNESFile::LFLEntry lfl_54[] = { {res_rooms, 54}, {res_sprdesc, 0}, {res_sprdesc, 1}, {res_sprlens, 0}, {res_sprlens, 1}, {res_sproffs, 0}, {res_sproffs, 1}, {res_sprdata, 0}, {res_sprdata, 1}, {res_costumegfx, 0}, {res_costumegfx, 1}, {res_sprpals, 0}, {res_sprpals, 1}, {res_charset, 0}, {res_preplist, 0}, {NULL, 0} }; - -struct ScummNESFile::LFL { - int num; - const ScummNESFile::LFLEntry *entries; -}; - -static const ScummNESFile::LFL lfls[] = { - { 1, lfl_01 }, - { 2, lfl_02 }, - { 3, lfl_03 }, - { 4, lfl_04 }, - { 5, lfl_05 }, - { 6, lfl_06 }, - { 7, lfl_07 }, - { 8, lfl_08 }, - { 9, lfl_09 }, - { 10, lfl_10 }, - { 11, lfl_11 }, - { 12, lfl_12 }, - { 13, lfl_13 }, - { 14, lfl_14 }, - { 15, lfl_15 }, - { 16, lfl_16 }, - { 17, lfl_17 }, - { 18, lfl_18 }, - { 19, lfl_19 }, - { 20, lfl_20 }, - { 21, lfl_21 }, - { 22, lfl_22 }, - { 23, lfl_23 }, - { 24, lfl_24 }, - { 25, lfl_25 }, - { 26, lfl_26 }, - { 27, lfl_27 }, - { 28, lfl_28 }, - { 29, lfl_29 }, - { 30, lfl_30 }, - { 31, lfl_31 }, - { 32, lfl_32 }, - { 33, lfl_33 }, - { 34, lfl_34 }, - { 35, lfl_35 }, - { 36, lfl_36 }, - { 37, lfl_37 }, - { 38, lfl_38 }, - { 39, lfl_39 }, - { 40, lfl_40 }, - { 41, lfl_41 }, - { 42, lfl_42 }, - { 43, lfl_43 }, - { 44, lfl_44 }, - { 45, lfl_45 }, - { 46, lfl_46 }, - { 47, lfl_47 }, - { 48, lfl_48 }, - { 49, lfl_49 }, - { 50, lfl_50 }, - { 51, lfl_51 }, - { 52, lfl_52 }, - { 53, lfl_53 }, - { 54, lfl_54 }, - { -1, NULL } -}; - -#include "common/pack-start.h" // START STRUCT PACKING - -struct _lfl_index { - byte room_lfl[55]; - uint16 room_addr[55]; - byte costume_lfl[80]; - uint16 costume_addr[80]; - byte script_lfl[200]; - uint16 script_addr[200]; - byte sound_lfl[100]; - uint16 sound_addr[100]; -} PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING - -_lfl_index lfl_index; - -bool ScummNESFile::generateResource(int res) { - const LFL *lfl = &lfls[res - 1]; - int j; - int bufsize = 2; - - for (j = 0; lfl->entries[j].type != NULL; j++) - bufsize += extractResource(0, &lfl->entries[j].type[_ROMset][lfl->entries[j].index]); - - free(_buf); - _buf = (byte *)calloc(1, bufsize); - - Common::MemoryWriteStream out(_buf, bufsize); - - for (j = 0; lfl->entries[j].type != NULL; j++) { - const Resource *entry = &lfl->entries[j].type[_ROMset][lfl->entries[j].index]; - extractResource(&out, entry); - } - write_byte(&out, 0xD1); - write_byte(&out, 0xF5); - - if (_stream) - delete _stream; - - _stream = new Common::MemoryReadStream(_buf, bufsize); - - return true; -} - -bool ScummNESFile::generateIndex() { - int i, j; - - for (i = 0; lfls[i].num != -1; i++) { - const LFL *lfl = &lfls[i]; - uint16 respos = 0; - - for (j = 0; lfl->entries[j].type != NULL; j++) { - const LFLEntry *entry = &lfl->entries[j]; - - switch (entry->type[_ROMset][entry->index].type) { - case NES_ROOM: - lfl_index.room_lfl[entry->index] = lfl->num; - lfl_index.room_addr[entry->index] = TO_LE_16(respos); - break; - case NES_COSTUME: - lfl_index.costume_lfl[entry->index] = lfl->num; - lfl_index.costume_addr[entry->index] = TO_LE_16(respos); - break; - case NES_SPRDESC: - lfl_index.costume_lfl[entry->index + 25] = lfl->num; - lfl_index.costume_addr[entry->index + 25] = TO_LE_16(respos); - break; - case NES_SPRLENS: - lfl_index.costume_lfl[entry->index + 27] = lfl->num; - lfl_index.costume_addr[entry->index + 27] = TO_LE_16(respos); - break; - case NES_SPROFFS: - lfl_index.costume_lfl[entry->index + 29] = lfl->num; - lfl_index.costume_addr[entry->index + 29] = TO_LE_16(respos); - break; - case NES_SPRDATA: - lfl_index.costume_lfl[entry->index + 31] = lfl->num; - lfl_index.costume_addr[entry->index + 31] = TO_LE_16(respos); - break; - case NES_COSTUMEGFX: - lfl_index.costume_lfl[entry->index + 33] = lfl->num; - lfl_index.costume_addr[entry->index + 33] = TO_LE_16(respos); - break; - case NES_SPRPALS: - lfl_index.costume_lfl[entry->index + 35] = lfl->num; - lfl_index.costume_addr[entry->index + 35] = TO_LE_16(respos); - break; - case NES_ROOMGFX: - lfl_index.costume_lfl[entry->index + 37] = lfl->num; - lfl_index.costume_addr[entry->index + 37] = TO_LE_16(respos); - break; - case NES_SCRIPT: - lfl_index.script_lfl[entry->index] = lfl->num; - lfl_index.script_addr[entry->index] = TO_LE_16(respos); - break; - case NES_SOUND: - lfl_index.sound_lfl[entry->index] = lfl->num; - lfl_index.sound_addr[entry->index] = TO_LE_16(respos); - break; - case NES_CHARSET: - lfl_index.costume_lfl[77] = lfl->num; - lfl_index.costume_addr[77] = TO_LE_16(respos); - break; - case NES_PREPLIST: - lfl_index.costume_lfl[78] = lfl->num; - lfl_index.costume_addr[78] = TO_LE_16(respos); - break; - default: - error("Unindexed entry found!"); - break; - } - respos += extractResource(0, &entry->type[_ROMset][entry->index]); - } - } - - int bufsize = 2; - - bufsize += 775; - bufsize += sizeof(lfl_index); - - free(_buf); - _buf = (byte *)calloc(1, bufsize); - - Common::MemoryWriteStream out(_buf, bufsize); - - write_byte(&out, 0x43); - write_byte(&out, 0x46); - - extractResource(&out, &res_globdata[_ROMset][0]); - - for (i = 0; i < (int)sizeof(lfl_index); i++) - write_byte(&out, ((byte *)&lfl_index)[i]); - - if (_stream) - delete _stream; - - _stream = new Common::MemoryReadStream(_buf, bufsize); - - return true; -} - -bool ScummNESFile::open(const Common::String &filename, AccessMode mode) { - - if (_ROMset == kROMsetNum) { - char md5str[32+1]; - if (Common::md5_file_string(filename.c_str(), md5str)) { - - if (!strcmp(md5str, "3905799e081b80a61d4460b7b733c206")) { - _ROMset = kROMsetUSA; - debug(1, "ROM contents verified as Maniac Mansion (USA)"); - } else if (!strcmp(md5str, "d8d07efcb88f396bee0b402b10c3b1c9")) { - _ROMset = kROMsetEurope; - debug(1, "ROM contents verified as Maniac Mansion (Europe)"); - } else if (!strcmp(md5str, "22d07d6c386c9c25aca5dac2a0c0d94b")) { - _ROMset = kROMsetSweden; - debug(1, "ROM contents verified as Maniac Mansion (Sweden)"); - } else if (!strcmp(md5str, "81bbfa181184cb494e7a81dcfa94fbd9")) { - _ROMset = kROMsetFrance; - debug(2, "ROM contents verified as Maniac Mansion (France)"); - } else if (!strcmp(md5str, "257f8c14d8c584f7ddd601bcb00920c7")) { - _ROMset = kROMsetGermany; - debug(2, "ROM contents verified as Maniac Mansion (Germany)"); - } else { - error("Unsupported Maniac Mansion ROM, md5: %s", md5str); - return false; - } - } else { - return false; - } - } - - if (File::open(filename, mode)) { - if (_stream) - delete _stream; - _stream = 0; - - free(_buf); - _buf = 0; - - return true; - } else { - return false; - } -} - -void ScummNESFile::close() { - if (_stream) - delete _stream; - _stream = 0; - - free(_buf); - _buf = 0; - - File::close(); -} - -bool ScummNESFile::openSubFile(const Common::String &filename) { - assert(isOpen()); - - const char *ext = strrchr(filename.c_str(), '.'); - char resNum[3]; - int res; - - // We always have file name in form of XX.lfl - resNum[0] = ext[-2]; - resNum[1] = ext[-1]; - resNum[2] = 0; - - res = atoi(resNum); - - if (res == 0) { - return generateIndex(); - } else { - return generateResource(res); - } -} - -#pragma mark - #pragma mark --- ScummDiskImage --- #pragma mark - @@ -1487,6 +215,20 @@ static const int zakResourcesPerFile[59] = { }; +static uint16 write_byte(Common::WriteStream *out, byte val) { + val ^= 0xFF; + if (out != 0) + out->writeByte(val); + return 1; +} + +static uint16 write_word(Common::WriteStream *out, uint16 val) { + val ^= 0xFFFF; + if (out != 0) + out->writeUint16LE(val); + return 2; +} + ScummDiskImage::ScummDiskImage(const char *disk1, const char *disk2, GameSettings game) : _stream(0), _buf(0) { _disk1 = disk1; _disk2 = disk2; diff --git a/engines/scumm/file.h b/engines/scumm/file.h index 18b7b8fb18..10ab031c7e 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -70,50 +70,6 @@ public: uint32 write(const void *dataPtr, uint32 dataSize); }; -class ScummNESFile : public BaseScummFile { -public: - enum ROMset { - kROMsetUSA, - kROMsetEurope, - kROMsetSweden, - kROMsetFrance, - kROMsetGermany, - kROMsetNum - }; - - struct Resource; - struct LFLEntry; - struct LFL; - -private: - Common::MemoryReadStream *_stream; - ROMset _ROMset; - byte *_buf; - - bool generateIndex(); - bool generateResource(int res); - uint16 extractResource(Common::WriteStream *out, const Resource *res); - - byte fileReadByte(); - uint16 fileReadUint16LE(); - -public: - ScummNESFile(); - void setEnc(byte value); - - bool open(const Common::String &filename, AccessMode mode = kFileReadMode); - bool openSubFile(const Common::String &filename); - - void close(); - bool eof() { return _stream->eos(); } - uint32 pos() { return _stream->pos(); } - uint32 size() { return _stream->size(); } - void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); } - uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } - uint32 write(const void *dataPtr, uint32 dataSize); -}; - - class ScummDiskImage : public BaseScummFile { private: Common::MemoryReadStream *_stream; diff --git a/engines/scumm/file_nes.cpp b/engines/scumm/file_nes.cpp new file mode 100644 index 0000000000..88b4253a1d --- /dev/null +++ b/engines/scumm/file_nes.cpp @@ -0,0 +1,1317 @@ +/* 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 "scumm/file_nes.h" +#include "common/endian.h" +#include "common/md5.h" + +using Common::File; + +namespace Scumm { + +#pragma mark - +#pragma mark --- ScummNESFile --- +#pragma mark - + +enum ResType { + NES_UNKNOWN, + NES_GLOBDATA, + NES_ROOM, + NES_SCRIPT, + NES_SOUND, + NES_COSTUME, + NES_ROOMGFX, + NES_COSTUMEGFX, + NES_SPRPALS, + NES_SPRDESC, + NES_SPRLENS, + NES_SPROFFS, + NES_SPRDATA, + NES_CHARSET, + NES_PREPLIST +}; + +struct ScummNESFile::Resource { + uint32 offset; + uint16 length; + ResType type; +}; + +ScummNESFile::ScummNESFile() : _stream(0), _buf(0), _ROMset(kROMsetNum) { +} + +uint32 ScummNESFile::write(const void *, uint32) { + error("ScummNESFile does not support writing!"); + return 0; +} + +void ScummNESFile::setEnc(byte enc) { + _stream->setEnc(enc); +} + +static const ScummNESFile::Resource res_roomgfx_usa[40] = { + { 0x04001, 0x03C9, NES_ROOMGFX }, { 0x043CA, 0x069E, NES_ROOMGFX }, { 0x04A68, 0x0327, NES_ROOMGFX }, { 0x04D8F, 0x053B, NES_ROOMGFX }, { 0x052CA, 0x06BE, NES_ROOMGFX }, + { 0x05988, 0x0682, NES_ROOMGFX }, { 0x0600A, 0x0778, NES_ROOMGFX }, { 0x06782, 0x0517, NES_ROOMGFX }, { 0x06C99, 0x07FB, NES_ROOMGFX }, { 0x07494, 0x07BE, NES_ROOMGFX }, + { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x0846, NES_ROOMGFX }, { 0x09BB3, 0x08C8, NES_ROOMGFX }, + { 0x0A47B, 0x0844, NES_ROOMGFX }, { 0x0ACBF, 0x0515, NES_ROOMGFX }, { 0x0B1D4, 0x0799, NES_ROOMGFX }, { 0x0B96D, 0x04BB, NES_ROOMGFX }, { 0x07C52, 0x0319, NES_ROOMGFX }, + { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x076D, NES_ROOMGFX }, { 0x0CBD2, 0x0827, NES_ROOMGFX }, { 0x0D3F9, 0x0515, NES_ROOMGFX }, { 0x0D90E, 0x064E, NES_ROOMGFX }, + { 0x0DF5C, 0x0775, NES_ROOMGFX }, { 0x0E6D1, 0x06DD, NES_ROOMGFX }, { 0x0EDAE, 0x0376, NES_ROOMGFX }, { 0x0F124, 0x05F7, NES_ROOMGFX }, { 0x0F71B, 0x0787, NES_ROOMGFX }, + { 0x10001, 0x02D6, NES_ROOMGFX }, { 0x102D7, 0x06A3, NES_ROOMGFX }, { 0x1097A, 0x099F, NES_ROOMGFX }, { 0x11319, 0x0361, NES_ROOMGFX }, { 0x1167A, 0x0489, NES_ROOMGFX }, + { 0x11B03, 0x0437, NES_ROOMGFX }, { 0x11F3A, 0x084D, NES_ROOMGFX }, { 0x0BE28, 0x0199, NES_ROOMGFX }, { 0x12787, 0x09A7, NES_ROOMGFX }, { 0x1312E, 0x037A, NES_ROOMGFX } +}; +static const ScummNESFile::Resource res_roomgfx_eur[40] = { + { 0x04001, 0x03B9, NES_ROOMGFX }, { 0x043BA, 0x069E, NES_ROOMGFX }, { 0x04A58, 0x0327, NES_ROOMGFX }, { 0x04D7F, 0x053B, NES_ROOMGFX }, { 0x052BA, 0x06BE, NES_ROOMGFX }, + { 0x05978, 0x0682, NES_ROOMGFX }, { 0x05FFA, 0x0778, NES_ROOMGFX }, { 0x06772, 0x0517, NES_ROOMGFX }, { 0x06C89, 0x07FB, NES_ROOMGFX }, { 0x07484, 0x07BE, NES_ROOMGFX }, + { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x0846, NES_ROOMGFX }, { 0x09BB3, 0x08C8, NES_ROOMGFX }, + { 0x0A47B, 0x0844, NES_ROOMGFX }, { 0x0ACBF, 0x0515, NES_ROOMGFX }, { 0x0B1D4, 0x0799, NES_ROOMGFX }, { 0x0B96D, 0x04BB, NES_ROOMGFX }, { 0x07C42, 0x0319, NES_ROOMGFX }, + { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x076D, NES_ROOMGFX }, { 0x0CBD2, 0x0827, NES_ROOMGFX }, { 0x0D3F9, 0x0515, NES_ROOMGFX }, { 0x0D90E, 0x064E, NES_ROOMGFX }, + { 0x0DF5C, 0x0775, NES_ROOMGFX }, { 0x0E6D1, 0x06DD, NES_ROOMGFX }, { 0x0EDAE, 0x0376, NES_ROOMGFX }, { 0x0F124, 0x05F7, NES_ROOMGFX }, { 0x0F71B, 0x0787, NES_ROOMGFX }, + { 0x10001, 0x02D6, NES_ROOMGFX }, { 0x102D7, 0x06A3, NES_ROOMGFX }, { 0x1097A, 0x099F, NES_ROOMGFX }, { 0x11319, 0x0361, NES_ROOMGFX }, { 0x1167A, 0x0489, NES_ROOMGFX }, + { 0x11B03, 0x0437, NES_ROOMGFX }, { 0x11F3A, 0x084D, NES_ROOMGFX }, { 0x12787, 0x0199, NES_ROOMGFX }, { 0x12920, 0x09A7, NES_ROOMGFX }, { 0x132C7, 0x037A, NES_ROOMGFX } +}; +static const ScummNESFile::Resource res_roomgfx_swe[40] = { + { 0x04001, 0x03F0, NES_ROOMGFX }, { 0x043F1, 0x069E, NES_ROOMGFX }, { 0x04A8F, 0x0327, NES_ROOMGFX }, { 0x04DB6, 0x053B, NES_ROOMGFX }, { 0x052F1, 0x06BE, NES_ROOMGFX }, + { 0x059AF, 0x0682, NES_ROOMGFX }, { 0x06031, 0x0778, NES_ROOMGFX }, { 0x067A9, 0x0517, NES_ROOMGFX }, { 0x06CC0, 0x07FB, NES_ROOMGFX }, { 0x074BB, 0x07BE, NES_ROOMGFX }, + { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, + { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04BF, NES_ROOMGFX }, { 0x0BC02, 0x0319, NES_ROOMGFX }, + { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, + { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x0791, NES_ROOMGFX }, + { 0x07C79, 0x02D6, NES_ROOMGFX }, { 0x10001, 0x06A3, NES_ROOMGFX }, { 0x106A4, 0x0921, NES_ROOMGFX }, { 0x10FC5, 0x0361, NES_ROOMGFX }, { 0x11326, 0x0489, NES_ROOMGFX }, + { 0x117AF, 0x0437, NES_ROOMGFX }, { 0x11BE6, 0x084F, NES_ROOMGFX }, { 0x12435, 0x0199, NES_ROOMGFX }, { 0x125CE, 0x0947, NES_ROOMGFX }, { 0x12F15, 0x037A, NES_ROOMGFX } +}; +static const ScummNESFile::Resource res_roomgfx_fra[40] = { + { 0x04001, 0x0426, NES_ROOMGFX }, { 0x04427, 0x069E, NES_ROOMGFX }, { 0x04AC5, 0x0327, NES_ROOMGFX }, { 0x04DEC, 0x053B, NES_ROOMGFX }, { 0x05327, 0x06BE, NES_ROOMGFX }, + { 0x059E5, 0x0682, NES_ROOMGFX }, { 0x06067, 0x0778, NES_ROOMGFX }, { 0x067DF, 0x0517, NES_ROOMGFX }, { 0x06CF6, 0x07FB, NES_ROOMGFX }, { 0x074F1, 0x07BE, NES_ROOMGFX }, + { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, + { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04BB, NES_ROOMGFX }, { 0x0BBFE, 0x0319, NES_ROOMGFX }, + { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, + { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x0787, NES_ROOMGFX }, + { 0x10001, 0x02D6, NES_ROOMGFX }, { 0x102D7, 0x06A3, NES_ROOMGFX }, { 0x1097A, 0x0921, NES_ROOMGFX }, { 0x1129B, 0x0361, NES_ROOMGFX }, { 0x115FC, 0x0489, NES_ROOMGFX }, + { 0x11A85, 0x0437, NES_ROOMGFX }, { 0x11EBC, 0x070D, NES_ROOMGFX }, { 0x07CAF, 0x0199, NES_ROOMGFX }, { 0x125C9, 0x0947, NES_ROOMGFX }, { 0x12F10, 0x037A, NES_ROOMGFX } +}; +static const ScummNESFile::Resource res_roomgfx_ger[40] = { + { 0x04001, 0x0406, NES_ROOMGFX }, { 0x04407, 0x069E, NES_ROOMGFX }, { 0x04AA5, 0x0327, NES_ROOMGFX }, { 0x04DCC, 0x053B, NES_ROOMGFX }, { 0x05307, 0x06BE, NES_ROOMGFX }, + { 0x059C5, 0x0682, NES_ROOMGFX }, { 0x06047, 0x0778, NES_ROOMGFX }, { 0x067BF, 0x0517, NES_ROOMGFX }, { 0x06CD6, 0x07FB, NES_ROOMGFX }, { 0x074D1, 0x07BE, NES_ROOMGFX }, + { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, + { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04BB, NES_ROOMGFX }, { 0x0BBFE, 0x0319, NES_ROOMGFX }, + { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, + { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x0787, NES_ROOMGFX }, + { 0x07C8F, 0x02D6, NES_ROOMGFX }, { 0x10001, 0x06A3, NES_ROOMGFX }, { 0x106A4, 0x0921, NES_ROOMGFX }, { 0x10FC5, 0x0361, NES_ROOMGFX }, { 0x11326, 0x0489, NES_ROOMGFX }, + { 0x117AF, 0x0437, NES_ROOMGFX }, { 0x11BE6, 0x07A0, NES_ROOMGFX }, { 0x12386, 0x0199, NES_ROOMGFX }, { 0x1251F, 0x0947, NES_ROOMGFX }, { 0x12E66, 0x037A, NES_ROOMGFX } +}; +static const ScummNESFile::Resource res_roomgfx_esp[40] = { + { 0x04001, 0x041B, NES_ROOMGFX }, { 0x0441C, 0x069E, NES_ROOMGFX }, { 0x04ABA, 0x0327, NES_ROOMGFX }, { 0x04DE1, 0x053B, NES_ROOMGFX }, { 0x0531C, 0x06BE, NES_ROOMGFX }, + { 0x059DA, 0x0682, NES_ROOMGFX }, { 0x0605C, 0x0778, NES_ROOMGFX }, { 0x067D4, 0x0517, NES_ROOMGFX }, { 0x06CEB, 0x07FB, NES_ROOMGFX }, { 0x074E6, 0x07BE, NES_ROOMGFX }, + { 0x08001, 0x07A5, NES_ROOMGFX }, { 0x087A6, 0x06DD, NES_ROOMGFX }, { 0x08E83, 0x04EA, NES_ROOMGFX }, { 0x0936D, 0x07E2, NES_ROOMGFX }, { 0x09B4F, 0x0791, NES_ROOMGFX }, + { 0x0A2E0, 0x07B5, NES_ROOMGFX }, { 0x0AA95, 0x0515, NES_ROOMGFX }, { 0x0AFAA, 0x0799, NES_ROOMGFX }, { 0x0B743, 0x04B9, NES_ROOMGFX }, { 0x0BBFC, 0x0319, NES_ROOMGFX }, + { 0x0C001, 0x0464, NES_ROOMGFX }, { 0x0C465, 0x072C, NES_ROOMGFX }, { 0x0CB91, 0x0827, NES_ROOMGFX }, { 0x0D3B8, 0x0515, NES_ROOMGFX }, { 0x0D8CD, 0x064E, NES_ROOMGFX }, + { 0x0DF1B, 0x0775, NES_ROOMGFX }, { 0x0E690, 0x06DD, NES_ROOMGFX }, { 0x0ED6D, 0x0376, NES_ROOMGFX }, { 0x0F0E3, 0x05F7, NES_ROOMGFX }, { 0x0F6DA, 0x078D, NES_ROOMGFX }, + { 0x07CA4, 0x02D6, NES_ROOMGFX }, { 0x10001, 0x06A3, NES_ROOMGFX }, { 0x106A4, 0x091F, NES_ROOMGFX }, { 0x10FC3, 0x0361, NES_ROOMGFX }, { 0x11324, 0x0489, NES_ROOMGFX }, + { 0x117AD, 0x0437, NES_ROOMGFX }, { 0x11BE4, 0x086E, NES_ROOMGFX }, { 0x12452, 0x0199, NES_ROOMGFX }, { 0x125EB, 0x0947, NES_ROOMGFX }, { 0x12F32, 0x037A, NES_ROOMGFX } +}; + +static const ScummNESFile::Resource *res_roomgfx[ScummNESFile::kROMsetNum] = { + res_roomgfx_usa, + res_roomgfx_eur, + res_roomgfx_swe, + res_roomgfx_fra, + res_roomgfx_ger, + res_roomgfx_esp, +}; + +static const ScummNESFile::Resource res_costumegfx_usa[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F9F1, 0x0340, NES_COSTUMEGFX } }; +static const ScummNESFile::Resource res_costumegfx_eur[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F9F1, 0x0340, NES_COSTUMEGFX } }; +static const ScummNESFile::Resource res_costumegfx_swe[2] = { { 0x2EFE1, 0x0EB8, NES_COSTUMEGFX }, { 0x30001, 0x0340, NES_COSTUMEGFX } }; +static const ScummNESFile::Resource res_costumegfx_fra[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F608, 0x0340, NES_COSTUMEGFX } }; +static const ScummNESFile::Resource res_costumegfx_ger[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F4CE, 0x0340, NES_COSTUMEGFX } }; +static const ScummNESFile::Resource res_costumegfx_esp[2] = { { 0x30001, 0x0EB8, NES_COSTUMEGFX }, { 0x2F0F6, 0x0340, NES_COSTUMEGFX } }; + +static const ScummNESFile::Resource *res_costumegfx[ScummNESFile::kROMsetNum] = { + res_costumegfx_usa, + res_costumegfx_eur, + res_costumegfx_swe, + res_costumegfx_fra, + res_costumegfx_ger, + res_costumegfx_esp, +}; + +static const ScummNESFile::Resource res_rooms_usa[55] = { + { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D0C, NES_ROOM }, { 0x134A8, 0x04B3, NES_ROOM }, { 0x15397, 0x0849, NES_ROOM }, { 0x15C68, 0x0685, NES_ROOM }, + { 0x16381, 0x0715, NES_ROOM }, { 0x1395B, 0x04E7, NES_ROOM }, { 0x16CE8, 0x0AC0, NES_ROOM }, { 0x18001, 0x06BA, NES_ROOM }, { 0x17AED, 0x03CB, NES_ROOM }, + { 0x18BE7, 0x0663, NES_ROOM }, { 0x192A6, 0x0580, NES_ROOM }, { 0x19A44, 0x0443, NES_ROOM }, { 0x1A106, 0x0563, NES_ROOM }, { 0x1A669, 0x0446, NES_ROOM }, + { 0x1AAAF, 0x03A7, NES_ROOM }, { 0x1AE56, 0x07E3, NES_ROOM }, { 0x1B699, 0x0692, NES_ROOM }, { 0x1C001, 0x0B49, NES_ROOM }, { 0x1CD09, 0x04C6, NES_ROOM }, + { 0x1D4C2, 0x0568, NES_ROOM }, { 0x1DF6C, 0x0514, NES_ROOM }, { 0x1E8FA, 0x05CC, NES_ROOM }, { 0x1EF83, 0x0389, NES_ROOM }, { 0x1F5E4, 0x0723, NES_ROOM }, + { 0x20001, 0x049A, NES_ROOM }, { 0x20511, 0x04F8, NES_ROOM }, { 0x21666, 0x05CB, NES_ROOM }, { 0x21DD6, 0x046B, NES_ROOM }, { 0x222F0, 0x0460, NES_ROOM }, + { 0x227B6, 0x0909, NES_ROOM }, { 0x24001, 0x0366, NES_ROOM }, { 0x23BDF, 0x03CA, NES_ROOM }, { 0x247DB, 0x050D, NES_ROOM }, { 0x25ACF, 0x0346, NES_ROOM }, + { 0x1BDBD, 0x01CA, NES_ROOM }, { 0x25E15, 0x0457, NES_ROOM }, { 0x2626C, 0x0547, NES_ROOM }, { 0x267B3, 0x064A, NES_ROOM }, { 0x1FD72, 0x024B, NES_ROOM }, + { 0x2739A, 0x01FA, NES_ROOM }, { 0x2766D, 0x0219, NES_ROOM }, { 0x28001, 0x02F4, NES_ROOM }, { 0x284D6, 0x045C, NES_ROOM }, { 0x289A3, 0x09CF, NES_ROOM }, + { 0x293C6, 0x05A0, NES_ROOM }, { 0x27B65, 0x0201, NES_ROOM }, { 0x2ADD1, 0x0325, NES_ROOM }, { 0x2B339, 0x01FC, NES_ROOM }, { 0x2B535, 0x02A9, NES_ROOM }, + { 0x2B7DE, 0x02DE, NES_ROOM }, { 0x2C001, 0x03CE, NES_ROOM }, { 0x2BBC0, 0x0205, NES_ROOM }, { 0x2C53A, 0x0170, NES_ROOM }, { 0x13E42, 0x0169, NES_ROOM } +}; +static const ScummNESFile::Resource res_rooms_eur[55] = { + { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D0C, NES_ROOM }, { 0x13641, 0x04B3, NES_ROOM }, { 0x15397, 0x0849, NES_ROOM }, { 0x15C68, 0x0685, NES_ROOM }, + { 0x16381, 0x0715, NES_ROOM }, { 0x16CE8, 0x04E7, NES_ROOM }, { 0x18001, 0x0ABF, NES_ROOM }, { 0x171CF, 0x06BA, NES_ROOM }, { 0x13AF4, 0x03D2, NES_ROOM }, + { 0x18E1A, 0x0663, NES_ROOM }, { 0x194D9, 0x04A9, NES_ROOM }, { 0x19BA0, 0x0443, NES_ROOM }, { 0x1A262, 0x047C, NES_ROOM }, { 0x1A6DE, 0x0446, NES_ROOM }, + { 0x1AB24, 0x03A7, NES_ROOM }, { 0x1AECB, 0x07E3, NES_ROOM }, { 0x1B70E, 0x0692, NES_ROOM }, { 0x1C001, 0x0ACA, NES_ROOM }, { 0x1CC8A, 0x04C6, NES_ROOM }, + { 0x1D443, 0x0568, NES_ROOM }, { 0x1DEED, 0x0514, NES_ROOM }, { 0x1E87B, 0x05CC, NES_ROOM }, { 0x1EF04, 0x0389, NES_ROOM }, { 0x1F565, 0x0723, NES_ROOM }, + { 0x20001, 0x049A, NES_ROOM }, { 0x20511, 0x04F8, NES_ROOM }, { 0x21666, 0x05D5, NES_ROOM }, { 0x21DE0, 0x046B, NES_ROOM }, { 0x222FA, 0x0460, NES_ROOM }, + { 0x227C0, 0x0909, NES_ROOM }, { 0x24001, 0x0366, NES_ROOM }, { 0x247DB, 0x03CA, NES_ROOM }, { 0x24BA5, 0x050D, NES_ROOM }, { 0x23BE9, 0x0346, NES_ROOM }, + { 0x17DB5, 0x01CA, NES_ROOM }, { 0x25E99, 0x0457, NES_ROOM }, { 0x262F0, 0x0547, NES_ROOM }, { 0x26837, 0x064A, NES_ROOM }, { 0x1FCF3, 0x024B, NES_ROOM }, + { 0x2741E, 0x01FA, NES_ROOM }, { 0x276F1, 0x0219, NES_ROOM }, { 0x28001, 0x02F4, NES_ROOM }, { 0x284D6, 0x045C, NES_ROOM }, { 0x289A3, 0x09CF, NES_ROOM }, + { 0x293C6, 0x05A0, NES_ROOM }, { 0x27BE9, 0x0201, NES_ROOM }, { 0x2ADE3, 0x0325, NES_ROOM }, { 0x2B34B, 0x01FC, NES_ROOM }, { 0x2B547, 0x02A9, NES_ROOM }, + { 0x2B7F0, 0x02DE, NES_ROOM }, { 0x2C001, 0x03CE, NES_ROOM }, { 0x2BBD2, 0x0205, NES_ROOM }, { 0x2C53A, 0x0170, NES_ROOM }, { 0x2BDD7, 0x0169, NES_ROOM } +}; +static const ScummNESFile::Resource res_rooms_swe[55] = { + { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D12, NES_ROOM }, { 0x1328F, 0x04B3, NES_ROOM }, { 0x15367, 0x0859, NES_ROOM }, { 0x13742, 0x0694, NES_ROOM }, + { 0x15C45, 0x0707, NES_ROOM }, { 0x1658F, 0x04E0, NES_ROOM }, { 0x16A6F, 0x0AC8, NES_ROOM }, { 0x18001, 0x06C7, NES_ROOM }, { 0x1789C, 0x03EA, NES_ROOM }, + { 0x18C09, 0x0649, NES_ROOM }, { 0x192AE, 0x04AB, NES_ROOM }, { 0x19982, 0x0447, NES_ROOM }, { 0x1A04D, 0x047E, NES_ROOM }, { 0x1A4CB, 0x0444, NES_ROOM }, + { 0x1A90F, 0x03B9, NES_ROOM }, { 0x1ACC8, 0x07E9, NES_ROOM }, { 0x1B511, 0x06A4, NES_ROOM }, { 0x1C001, 0x0B1A, NES_ROOM }, { 0x1CCFD, 0x0486, NES_ROOM }, + { 0x1D482, 0x0579, NES_ROOM }, { 0x1DF61, 0x051E, NES_ROOM }, { 0x1E8EC, 0x05CF, NES_ROOM }, { 0x1EF73, 0x0398, NES_ROOM }, { 0x1F5F0, 0x071A, NES_ROOM }, + { 0x20001, 0x049C, NES_ROOM }, { 0x2051E, 0x051E, NES_ROOM }, { 0x21725, 0x05D5, NES_ROOM }, { 0x21EA5, 0x047F, NES_ROOM }, { 0x223D1, 0x0460, NES_ROOM }, + { 0x22897, 0x090D, NES_ROOM }, { 0x24001, 0x0378, NES_ROOM }, { 0x247C9, 0x03CA, NES_ROOM }, { 0x24B93, 0x050D, NES_ROOM }, { 0x25267, 0x0346, NES_ROOM }, + { 0x17CD0, 0x01CA, NES_ROOM }, { 0x255AD, 0x0453, NES_ROOM }, { 0x25A00, 0x053E, NES_ROOM }, { 0x25F3E, 0x0647, NES_ROOM }, { 0x1BC49, 0x024B, NES_ROOM }, + { 0x26B58, 0x01FA, NES_ROOM }, { 0x26E27, 0x0217, NES_ROOM }, { 0x27345, 0x02F4, NES_ROOM }, { 0x27829, 0x045C, NES_ROOM }, { 0x28001, 0x098A, NES_ROOM }, + { 0x289DF, 0x05A1, NES_ROOM }, { 0x2A442, 0x0201, NES_ROOM }, { 0x2A6E9, 0x0325, NES_ROOM }, { 0x1FD75, 0x01FC, NES_ROOM }, { 0x2AC64, 0x02A9, NES_ROOM }, + { 0x2AF0D, 0x02D1, NES_ROOM }, { 0x2B2E6, 0x03CC, NES_ROOM }, { 0x23D61, 0x0205, NES_ROOM }, { 0x2B818, 0x0168, NES_ROOM }, { 0x27CF6, 0x0169, NES_ROOM } +}; +static const ScummNESFile::Resource res_rooms_fra[55] = { + { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D76, NES_ROOM }, { 0x1328A, 0x04C6, NES_ROOM }, { 0x15451, 0x0885, NES_ROOM }, { 0x13750, 0x0693, NES_ROOM }, + { 0x15D68, 0x0709, NES_ROOM }, { 0x166D4, 0x0528, NES_ROOM }, { 0x16BFC, 0x0ACC, NES_ROOM }, { 0x18001, 0x06E2, NES_ROOM }, { 0x17A63, 0x03E5, NES_ROOM }, + { 0x18C3B, 0x066A, NES_ROOM }, { 0x19301, 0x049E, NES_ROOM }, { 0x199C8, 0x044B, NES_ROOM }, { 0x1A0B1, 0x0478, NES_ROOM }, { 0x1A529, 0x043F, NES_ROOM }, + { 0x1A968, 0x03C8, NES_ROOM }, { 0x1AD30, 0x086F, NES_ROOM }, { 0x1B5FF, 0x069B, NES_ROOM }, { 0x1C001, 0x0AA9, NES_ROOM }, { 0x1CC97, 0x049E, NES_ROOM }, + { 0x1D42C, 0x05A8, NES_ROOM }, { 0x1DF71, 0x054E, NES_ROOM }, { 0x1E9D1, 0x0606, NES_ROOM }, { 0x1F0A2, 0x039A, NES_ROOM }, { 0x1F74E, 0x071C, NES_ROOM }, + { 0x20001, 0x04B5, NES_ROOM }, { 0x2052E, 0x04FF, NES_ROOM }, { 0x2172E, 0x05DB, NES_ROOM }, { 0x21EAD, 0x0489, NES_ROOM }, { 0x223E1, 0x0465, NES_ROOM }, + { 0x228AC, 0x0957, NES_ROOM }, { 0x24001, 0x037E, NES_ROOM }, { 0x2481A, 0x03CA, NES_ROOM }, { 0x24BE4, 0x050D, NES_ROOM }, { 0x252C0, 0x0346, NES_ROOM }, + { 0x1BD30, 0x01CA, NES_ROOM }, { 0x25606, 0x046D, NES_ROOM }, { 0x25A73, 0x055A, NES_ROOM }, { 0x25FCD, 0x0654, NES_ROOM }, { 0x26C98, 0x024B, NES_ROOM }, + { 0x26EE3, 0x01FA, NES_ROOM }, { 0x271DD, 0x0217, NES_ROOM }, { 0x27713, 0x02F4, NES_ROOM }, { 0x28001, 0x045C, NES_ROOM }, { 0x284CE, 0x0975, NES_ROOM }, + { 0x28E97, 0x05E6, NES_ROOM }, { 0x27C3A, 0x0201, NES_ROOM }, { 0x2A9D6, 0x0325, NES_ROOM }, { 0x2AF88, 0x01FC, NES_ROOM }, { 0x2B184, 0x02A9, NES_ROOM }, + { 0x2B42D, 0x02DF, NES_ROOM }, { 0x2B818, 0x03EC, NES_ROOM }, { 0x2BD67, 0x0209, NES_ROOM }, { 0x2C001, 0x0168, NES_ROOM }, { 0x2C4BF, 0x0169, NES_ROOM } +}; +static const ScummNESFile::Resource res_rooms_ger[55] = { + { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D63, NES_ROOM }, { 0x131E0, 0x04A9, NES_ROOM }, { 0x13689, 0x086B, NES_ROOM }, { 0x15421, 0x06A8, NES_ROOM }, + { 0x15B5D, 0x0731, NES_ROOM }, { 0x16507, 0x0501, NES_ROOM }, { 0x16A08, 0x0AE9, NES_ROOM }, { 0x18001, 0x06DA, NES_ROOM }, { 0x17880, 0x03D0, NES_ROOM }, + { 0x18C7B, 0x0651, NES_ROOM }, { 0x19328, 0x04A7, NES_ROOM }, { 0x199FE, 0x0447, NES_ROOM }, { 0x1A0F1, 0x0486, NES_ROOM }, { 0x1A577, 0x045D, NES_ROOM }, + { 0x1A9D4, 0x03AE, NES_ROOM }, { 0x1AD82, 0x0840, NES_ROOM }, { 0x1B622, 0x06C3, NES_ROOM }, { 0x1C001, 0x0B07, NES_ROOM }, { 0x1CD05, 0x0494, NES_ROOM }, + { 0x1D4A5, 0x05AC, NES_ROOM }, { 0x1DFD6, 0x0524, NES_ROOM }, { 0x1E9C0, 0x05F7, NES_ROOM }, { 0x1F09A, 0x038E, NES_ROOM }, { 0x1F75F, 0x0733, NES_ROOM }, + { 0x20001, 0x04A9, NES_ROOM }, { 0x2052A, 0x052E, NES_ROOM }, { 0x2177C, 0x0621, NES_ROOM }, { 0x21F57, 0x0495, NES_ROOM }, { 0x2249A, 0x045E, NES_ROOM }, + { 0x2295E, 0x0951, NES_ROOM }, { 0x24001, 0x036E, NES_ROOM }, { 0x247F9, 0x03CA, NES_ROOM }, { 0x24BC3, 0x050D, NES_ROOM }, { 0x252A8, 0x0346, NES_ROOM }, + { 0x17CA2, 0x01CA, NES_ROOM }, { 0x255EE, 0x046F, NES_ROOM }, { 0x25A5D, 0x054D, NES_ROOM }, { 0x25FAA, 0x064B, NES_ROOM }, { 0x26BE2, 0x024B, NES_ROOM }, + { 0x26E2D, 0x01FA, NES_ROOM }, { 0x2710F, 0x0217, NES_ROOM }, { 0x27663, 0x02F4, NES_ROOM }, { 0x28001, 0x045C, NES_ROOM }, { 0x284CE, 0x0A8F, NES_ROOM }, + { 0x28FB1, 0x05FF, NES_ROOM }, { 0x27B69, 0x0201, NES_ROOM }, { 0x2AAA9, 0x0325, NES_ROOM }, { 0x1BD7C, 0x01FC, NES_ROOM }, { 0x2B031, 0x02A9, NES_ROOM }, + { 0x2B2DA, 0x02D8, NES_ROOM }, { 0x2B6D2, 0x03D2, NES_ROOM }, { 0x2BC0D, 0x020D, NES_ROOM }, { 0x2C001, 0x0168, NES_ROOM }, { 0x27E11, 0x0169, NES_ROOM } +}; +static const ScummNESFile::Resource res_rooms_esp[55] = { + { 0x00000, 0x0000, NES_ROOM }, { 0x14001, 0x0D05, NES_ROOM }, { 0x132AC, 0x04B0, NES_ROOM }, { 0x153AB, 0x087B, NES_ROOM }, { 0x1375C, 0x06B3, NES_ROOM }, + { 0x15CB1, 0x0729, NES_ROOM }, { 0x16625, 0x04F0, NES_ROOM }, { 0x16B15, 0x0AD4, NES_ROOM }, { 0x18001, 0x06ED, NES_ROOM }, { 0x17936, 0x03DE, NES_ROOM }, + { 0x18C3E, 0x0671, NES_ROOM }, { 0x1930B, 0x04C4, NES_ROOM }, { 0x199EC, 0x0452, NES_ROOM }, { 0x1A0DA, 0x048F, NES_ROOM }, { 0x1A569, 0x0449, NES_ROOM }, + { 0x1A9B2, 0x03A8, NES_ROOM }, { 0x1AD5A, 0x0846, NES_ROOM }, { 0x1B600, 0x0686, NES_ROOM }, { 0x1C001, 0x0B58, NES_ROOM }, { 0x1CD42, 0x049C, NES_ROOM }, + { 0x1D4ED, 0x0586, NES_ROOM }, { 0x1DFE9, 0x0526, NES_ROOM }, { 0x1E9C9, 0x05CE, NES_ROOM }, { 0x1F04B, 0x0390, NES_ROOM }, { 0x1F6CA, 0x073C, NES_ROOM }, + { 0x20001, 0x04CB, NES_ROOM }, { 0x20543, 0x0530, NES_ROOM }, { 0x2171B, 0x05FC, NES_ROOM }, { 0x21EBE, 0x0470, NES_ROOM }, { 0x223DC, 0x045C, NES_ROOM }, + { 0x2289E, 0x0928, NES_ROOM }, { 0x24001, 0x036C, NES_ROOM }, { 0x247EC, 0x03CA, NES_ROOM }, { 0x24BB6, 0x050D, NES_ROOM }, { 0x25283, 0x0346, NES_ROOM }, + { 0x17D60, 0x01CA, NES_ROOM }, { 0x255C9, 0x0462, NES_ROOM }, { 0x25A2B, 0x055C, NES_ROOM }, { 0x25F87, 0x0659, NES_ROOM }, { 0x1BD19, 0x024B, NES_ROOM }, + { 0x26B8A, 0x01F7, NES_ROOM }, { 0x26E5D, 0x0217, NES_ROOM }, { 0x2736A, 0x02F4, NES_ROOM }, { 0x27845, 0x045C, NES_ROOM }, { 0x28001, 0x0969, NES_ROOM }, + { 0x289BE, 0x058E, NES_ROOM }, { 0x2A418, 0x0201, NES_ROOM }, { 0x2A6BE, 0x0325, NES_ROOM }, { 0x23D84, 0x01FC, NES_ROOM }, { 0x2AC46, 0x02A9, NES_ROOM }, + { 0x2AEEF, 0x02C9, NES_ROOM }, { 0x2B2C0, 0x03D2, NES_ROOM }, { 0x27D12, 0x0207, NES_ROOM }, { 0x2B7FC, 0x0168, NES_ROOM }, { 0x2BD06, 0x0169, NES_ROOM } +}; + +static const ScummNESFile::Resource *res_rooms[ScummNESFile::kROMsetNum] = { + res_rooms_usa, + res_rooms_eur, + res_rooms_swe, + res_rooms_fra, + res_rooms_ger, + res_rooms_esp, +}; + +static const ScummNESFile::Resource res_scripts_usa[179] = { + { 0x00000, 0x0000, NES_SCRIPT }, { 0x29966, 0x044D, NES_SCRIPT }, { 0x29DB3, 0x0207, NES_SCRIPT }, { 0x29FBA, 0x009F, NES_SCRIPT }, { 0x2A059, 0x03F4, NES_SCRIPT }, + { 0x2A44D, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A5EE, 0x004A, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A638, 0x0005, NES_SCRIPT }, + { 0x2C6AA, 0x000D, NES_SCRIPT }, { 0x2C6B7, 0x000D, NES_SCRIPT }, { 0x186BB, 0x0040, NES_SCRIPT }, { 0x186FB, 0x0016, NES_SCRIPT }, { 0x1B639, 0x0046, NES_SCRIPT }, + { 0x1EEC6, 0x00BD, NES_SCRIPT }, { 0x21C31, 0x0055, NES_SCRIPT }, { 0x177A8, 0x0027, NES_SCRIPT }, { 0x1FD07, 0x0027, NES_SCRIPT }, { 0x1FD2E, 0x0027, NES_SCRIPT }, + { 0x1BD2B, 0x0022, NES_SCRIPT }, { 0x15BE0, 0x0088, NES_SCRIPT }, { 0x22241, 0x0020, NES_SCRIPT }, { 0x22261, 0x008F, NES_SCRIPT }, { 0x1924A, 0x002B, NES_SCRIPT }, + { 0x1CB4A, 0x0061, NES_SCRIPT }, { 0x1CBAB, 0x003C, NES_SCRIPT }, { 0x1CBE7, 0x0042, NES_SCRIPT }, { 0x1CC29, 0x004F, NES_SCRIPT }, { 0x2049B, 0x0076, NES_SCRIPT }, + { 0x16A96, 0x0035, NES_SCRIPT }, { 0x16ACB, 0x001C, NES_SCRIPT }, { 0x16AE7, 0x0014, NES_SCRIPT }, { 0x16AFB, 0x001C, NES_SCRIPT }, { 0x16B17, 0x0027, NES_SCRIPT }, + { 0x16B3E, 0x01AA, NES_SCRIPT }, { 0x1D1CF, 0x0096, NES_SCRIPT }, { 0x1D265, 0x010E, NES_SCRIPT }, { 0x1D373, 0x001C, NES_SCRIPT }, { 0x1D38F, 0x0056, NES_SCRIPT }, + { 0x1D3E5, 0x0072, NES_SCRIPT }, { 0x1E480, 0x0028, NES_SCRIPT }, { 0x1E4A8, 0x017D, NES_SCRIPT }, { 0x1E625, 0x0229, NES_SCRIPT }, { 0x28932, 0x0071, NES_SCRIPT }, + { 0x17EB8, 0x004D, NES_SCRIPT }, { 0x162ED, 0x0039, NES_SCRIPT }, { 0x18711, 0x028B, NES_SCRIPT }, { 0x1899C, 0x00BB, NES_SCRIPT }, { 0x18A57, 0x018B, NES_SCRIPT }, + { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E87, 0x00ED, NES_SCRIPT }, { 0x21C86, 0x00F6, NES_SCRIPT }, { 0x1E84E, 0x009B, NES_SCRIPT }, { 0x21D7C, 0x0047, NES_SCRIPT }, + { 0x2C6C4, 0x004D, NES_SCRIPT }, { 0x16326, 0x0024, NES_SCRIPT }, { 0x14D0D, 0x0014, NES_SCRIPT }, { 0x177CF, 0x0059, NES_SCRIPT }, { 0x17828, 0x0109, NES_SCRIPT }, + { 0x17931, 0x0009, NES_SCRIPT }, { 0x14D21, 0x01B6, NES_SCRIPT }, { 0x2B0F6, 0x0243, NES_SCRIPT }, { 0x230BF, 0x067F, NES_SCRIPT }, { 0x2C711, 0x001C, NES_SCRIPT }, + { 0x2C72D, 0x001A, NES_SCRIPT }, { 0x2C747, 0x0021, NES_SCRIPT }, { 0x2C768, 0x0024, NES_SCRIPT }, { 0x2C78C, 0x0017, NES_SCRIPT }, { 0x2C7A3, 0x0017, NES_SCRIPT }, + { 0x2C7BA, 0x0014, NES_SCRIPT }, { 0x2C7CE, 0x0024, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C7F2, 0x0011, NES_SCRIPT }, { 0x1793A, 0x009D, NES_SCRIPT }, + { 0x22750, 0x0066, NES_SCRIPT }, { 0x14ED7, 0x0075, NES_SCRIPT }, { 0x1F30C, 0x0120, NES_SCRIPT }, { 0x1FD55, 0x001D, NES_SCRIPT }, { 0x1F42C, 0x008F, NES_SCRIPT }, + { 0x1F4BB, 0x0097, NES_SCRIPT }, { 0x179D7, 0x006A, NES_SCRIPT }, { 0x17A41, 0x0030, NES_SCRIPT }, { 0x1F552, 0x0092, NES_SCRIPT }, { 0x2C803, 0x00CC, NES_SCRIPT }, + { 0x2C8CF, 0x00BA, NES_SCRIPT }, { 0x2C989, 0x0088, NES_SCRIPT }, { 0x20A09, 0x01B0, NES_SCRIPT }, { 0x20BB9, 0x0168, NES_SCRIPT }, { 0x20D21, 0x006C, NES_SCRIPT }, + { 0x20D8D, 0x0037, NES_SCRIPT }, { 0x20DC4, 0x00E4, NES_SCRIPT }, { 0x20EA8, 0x0045, NES_SCRIPT }, { 0x20EED, 0x00E1, NES_SCRIPT }, { 0x20FCE, 0x00F6, NES_SCRIPT }, + { 0x210C4, 0x0141, NES_SCRIPT }, { 0x21205, 0x0183, NES_SCRIPT }, { 0x21388, 0x0034, NES_SCRIPT }, { 0x213BC, 0x00A9, NES_SCRIPT }, { 0x24367, 0x011B, NES_SCRIPT }, + { 0x1BD4D, 0x0070, NES_SCRIPT }, { 0x1CC78, 0x0091, NES_SCRIPT }, { 0x29372, 0x0054, NES_SCRIPT }, { 0x19F74, 0x00CE, NES_SCRIPT }, { 0x1A042, 0x0077, NES_SCRIPT }, + { 0x14F4C, 0x0057, NES_SCRIPT }, { 0x27886, 0x02DF, NES_SCRIPT }, { 0x1DA2A, 0x0219, NES_SCRIPT }, { 0x1DC43, 0x00F9, NES_SCRIPT }, { 0x1DD3C, 0x0056, NES_SCRIPT }, + { 0x1DD92, 0x01C2, NES_SCRIPT }, { 0x14FA3, 0x004D, NES_SCRIPT }, { 0x27594, 0x00D9, NES_SCRIPT }, { 0x21DC3, 0x0013, NES_SCRIPT }, { 0x2A63D, 0x00F0, NES_SCRIPT }, + { 0x24482, 0x00E7, NES_SCRIPT }, { 0x21465, 0x00F2, NES_SCRIPT }, { 0x24569, 0x002B, NES_SCRIPT }, { 0x2C3CF, 0x010F, NES_SCRIPT }, { 0x24594, 0x00AA, NES_SCRIPT }, + { 0x24CE8, 0x0DAB, NES_SCRIPT }, { 0x1B67F, 0x000D, NES_SCRIPT }, { 0x1B68C, 0x000D, NES_SCRIPT }, { 0x2373E, 0x017C, NES_SCRIPT }, { 0x282F5, 0x01E1, NES_SCRIPT }, + { 0x238BA, 0x0153, NES_SCRIPT }, { 0x23A0D, 0x019C, NES_SCRIPT }, { 0x23BA9, 0x0016, NES_SCRIPT }, { 0x2C4DE, 0x005C, NES_SCRIPT }, { 0x23BBF, 0x0020, NES_SCRIPT }, + { 0x27D66, 0x00A5, NES_SCRIPT }, { 0x2A72D, 0x034D, NES_SCRIPT }, { 0x14FF0, 0x00E3, NES_SCRIPT }, { 0x2BABC, 0x005F, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, + { 0x25A93, 0x003C, NES_SCRIPT }, { 0x1E8E9, 0x0011, NES_SCRIPT }, { 0x1634A, 0x0018, NES_SCRIPT }, { 0x26DFD, 0x001F, NES_SCRIPT }, { 0x26E1C, 0x0054, NES_SCRIPT }, + { 0x26E70, 0x0149, NES_SCRIPT }, { 0x26FB9, 0x004B, NES_SCRIPT }, { 0x27004, 0x017D, NES_SCRIPT }, { 0x27181, 0x0027, NES_SCRIPT }, { 0x271A8, 0x0041, NES_SCRIPT }, + { 0x271E9, 0x01B1, NES_SCRIPT }, { 0x16362, 0x001F, NES_SCRIPT }, { 0x2463E, 0x002A, NES_SCRIPT }, { 0x150D3, 0x019E, NES_SCRIPT }, { 0x19275, 0x0031, NES_SCRIPT }, + { 0x17A71, 0x007C, NES_SCRIPT }, { 0x21557, 0x00DC, NES_SCRIPT }, { 0x1D457, 0x0018, NES_SCRIPT }, { 0x1D46F, 0x0053, NES_SCRIPT }, { 0x18BE2, 0x0005, NES_SCRIPT }, + { 0x15271, 0x011B, NES_SCRIPT }, { 0x1538C, 0x000B, NES_SCRIPT }, { 0x24668, 0x0138, NES_SCRIPT }, { 0x247A0, 0x0014, NES_SCRIPT }, { 0x1DF54, 0x0018, NES_SCRIPT }, + { 0x247B4, 0x0027, NES_SCRIPT }, { 0x1A0B9, 0x004D, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BB1B, 0x00A5, NES_SCRIPT }, { 0x2AA7A, 0x00C1, NES_SCRIPT }, + { 0x2AB3B, 0x0140, NES_SCRIPT }, { 0x19826, 0x00BF, NES_SCRIPT }, { 0x198E5, 0x014D, NES_SCRIPT }, { 0x19A32, 0x0012, NES_SCRIPT }, { 0x2AC7B, 0x0005, NES_SCRIPT }, + { 0x2AC80, 0x0005, NES_SCRIPT }, { 0x2AC85, 0x0005, NES_SCRIPT }, { 0x2AC8A, 0x0005, NES_SCRIPT }, { 0x2AC8F, 0x0005, NES_SCRIPT }, { 0x21633, 0x0033, NES_SCRIPT }, + { 0x2AC94, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2AC99, 0x009C, NES_SCRIPT }, { 0x2AD35, 0x009C, NES_SCRIPT } +}; +static const ScummNESFile::Resource res_scripts_eur[179] = { + { 0x00000, 0x0000, NES_SCRIPT }, { 0x29966, 0x044D, NES_SCRIPT }, { 0x29DB3, 0x0207, NES_SCRIPT }, { 0x29FBA, 0x009F, NES_SCRIPT }, { 0x2A059, 0x03F4, NES_SCRIPT }, + { 0x2A44D, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A5EE, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A64A, 0x0005, NES_SCRIPT }, + { 0x2C6AA, 0x000D, NES_SCRIPT }, { 0x2C6B7, 0x000D, NES_SCRIPT }, { 0x17889, 0x0040, NES_SCRIPT }, { 0x178C9, 0x0016, NES_SCRIPT }, { 0x1B6AE, 0x0046, NES_SCRIPT }, + { 0x1EE47, 0x00BD, NES_SCRIPT }, { 0x21C3B, 0x0055, NES_SCRIPT }, { 0x18AC0, 0x0027, NES_SCRIPT }, { 0x1FC88, 0x0027, NES_SCRIPT }, { 0x1FCAF, 0x0027, NES_SCRIPT }, + { 0x1BDA0, 0x0022, NES_SCRIPT }, { 0x15BE0, 0x0088, NES_SCRIPT }, { 0x2224B, 0x0020, NES_SCRIPT }, { 0x2226B, 0x008F, NES_SCRIPT }, { 0x1947D, 0x002B, NES_SCRIPT }, + { 0x1CACB, 0x0061, NES_SCRIPT }, { 0x1CB2C, 0x003C, NES_SCRIPT }, { 0x1CB68, 0x0042, NES_SCRIPT }, { 0x1CBAA, 0x004F, NES_SCRIPT }, { 0x2049B, 0x0076, NES_SCRIPT }, + { 0x16A96, 0x0035, NES_SCRIPT }, { 0x16ACB, 0x001C, NES_SCRIPT }, { 0x16AE7, 0x0014, NES_SCRIPT }, { 0x16AFB, 0x001C, NES_SCRIPT }, { 0x16B17, 0x0027, NES_SCRIPT }, + { 0x16B3E, 0x01AA, NES_SCRIPT }, { 0x1D150, 0x0096, NES_SCRIPT }, { 0x1D1E6, 0x010E, NES_SCRIPT }, { 0x1D2F4, 0x001C, NES_SCRIPT }, { 0x1D310, 0x0056, NES_SCRIPT }, + { 0x1D366, 0x0072, NES_SCRIPT }, { 0x1E401, 0x0028, NES_SCRIPT }, { 0x1E429, 0x017D, NES_SCRIPT }, { 0x1E5A6, 0x0229, NES_SCRIPT }, { 0x28932, 0x0071, NES_SCRIPT }, + { 0x13EC6, 0x004D, NES_SCRIPT }, { 0x162ED, 0x0039, NES_SCRIPT }, { 0x178DF, 0x028B, NES_SCRIPT }, { 0x17B6A, 0x00BB, NES_SCRIPT }, { 0x17C25, 0x018B, NES_SCRIPT }, + { 0x00000, 0x0000, NES_SCRIPT }, { 0x19FE3, 0x00ED, NES_SCRIPT }, { 0x21C90, 0x00F6, NES_SCRIPT }, { 0x1E7CF, 0x009B, NES_SCRIPT }, { 0x21D86, 0x0047, NES_SCRIPT }, + { 0x2C6C4, 0x004D, NES_SCRIPT }, { 0x16326, 0x0024, NES_SCRIPT }, { 0x14D0D, 0x0014, NES_SCRIPT }, { 0x18AE7, 0x0059, NES_SCRIPT }, { 0x18B40, 0x011E, NES_SCRIPT }, + { 0x18C5E, 0x0009, NES_SCRIPT }, { 0x14D21, 0x01B6, NES_SCRIPT }, { 0x2B108, 0x0243, NES_SCRIPT }, { 0x230C9, 0x067F, NES_SCRIPT }, { 0x2C711, 0x001C, NES_SCRIPT }, + { 0x2C72D, 0x001A, NES_SCRIPT }, { 0x2C747, 0x0021, NES_SCRIPT }, { 0x2C768, 0x0024, NES_SCRIPT }, { 0x2C78C, 0x0017, NES_SCRIPT }, { 0x2C7A3, 0x0017, NES_SCRIPT }, + { 0x2C7BA, 0x0014, NES_SCRIPT }, { 0x2C7CE, 0x0024, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C7F2, 0x0011, NES_SCRIPT }, { 0x18C67, 0x009D, NES_SCRIPT }, + { 0x2275A, 0x0066, NES_SCRIPT }, { 0x14ED7, 0x0075, NES_SCRIPT }, { 0x1F28D, 0x0120, NES_SCRIPT }, { 0x1FCD6, 0x001D, NES_SCRIPT }, { 0x1F3AD, 0x008F, NES_SCRIPT }, + { 0x1F43C, 0x0097, NES_SCRIPT }, { 0x18D04, 0x006A, NES_SCRIPT }, { 0x18D6E, 0x0030, NES_SCRIPT }, { 0x1F4D3, 0x0092, NES_SCRIPT }, { 0x2C803, 0x00CC, NES_SCRIPT }, + { 0x2C8CF, 0x00BA, NES_SCRIPT }, { 0x2C989, 0x0088, NES_SCRIPT }, { 0x20A09, 0x01B0, NES_SCRIPT }, { 0x20BB9, 0x0168, NES_SCRIPT }, { 0x20D21, 0x006C, NES_SCRIPT }, + { 0x20D8D, 0x0037, NES_SCRIPT }, { 0x20DC4, 0x00E4, NES_SCRIPT }, { 0x20EA8, 0x0045, NES_SCRIPT }, { 0x20EED, 0x00E1, NES_SCRIPT }, { 0x20FCE, 0x00F6, NES_SCRIPT }, + { 0x210C4, 0x0141, NES_SCRIPT }, { 0x21205, 0x0183, NES_SCRIPT }, { 0x21388, 0x0034, NES_SCRIPT }, { 0x213BC, 0x00A9, NES_SCRIPT }, { 0x24367, 0x011B, NES_SCRIPT }, + { 0x1BDC2, 0x0070, NES_SCRIPT }, { 0x1CBF9, 0x0091, NES_SCRIPT }, { 0x29372, 0x0054, NES_SCRIPT }, { 0x1A0D0, 0x00CE, NES_SCRIPT }, { 0x1A19E, 0x0077, NES_SCRIPT }, + { 0x14F4C, 0x0057, NES_SCRIPT }, { 0x2790A, 0x02DF, NES_SCRIPT }, { 0x1D9AB, 0x0219, NES_SCRIPT }, { 0x1DBC4, 0x00F9, NES_SCRIPT }, { 0x1DCBD, 0x0056, NES_SCRIPT }, + { 0x1DD13, 0x01C2, NES_SCRIPT }, { 0x14FA3, 0x004D, NES_SCRIPT }, { 0x27618, 0x00D9, NES_SCRIPT }, { 0x21DCD, 0x0013, NES_SCRIPT }, { 0x2A64F, 0x00F0, NES_SCRIPT }, + { 0x24482, 0x00E7, NES_SCRIPT }, { 0x21465, 0x00F2, NES_SCRIPT }, { 0x24569, 0x002B, NES_SCRIPT }, { 0x2C3CF, 0x010F, NES_SCRIPT }, { 0x24594, 0x00AA, NES_SCRIPT }, + { 0x250B2, 0x0DAB, NES_SCRIPT }, { 0x1B6F4, 0x000D, NES_SCRIPT }, { 0x1B701, 0x000D, NES_SCRIPT }, { 0x23748, 0x017C, NES_SCRIPT }, { 0x282F5, 0x01E1, NES_SCRIPT }, + { 0x238C4, 0x0153, NES_SCRIPT }, { 0x23A17, 0x019C, NES_SCRIPT }, { 0x23BB3, 0x0016, NES_SCRIPT }, { 0x2C4DE, 0x005C, NES_SCRIPT }, { 0x23BC9, 0x0020, NES_SCRIPT }, + { 0x27DEA, 0x00A5, NES_SCRIPT }, { 0x2A73F, 0x034D, NES_SCRIPT }, { 0x14FF0, 0x00E3, NES_SCRIPT }, { 0x2BACE, 0x005F, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, + { 0x25E5D, 0x003C, NES_SCRIPT }, { 0x1E86A, 0x0011, NES_SCRIPT }, { 0x1634A, 0x0018, NES_SCRIPT }, { 0x26E81, 0x001F, NES_SCRIPT }, { 0x26EA0, 0x0054, NES_SCRIPT }, + { 0x26EF4, 0x0149, NES_SCRIPT }, { 0x2703D, 0x004B, NES_SCRIPT }, { 0x27088, 0x017D, NES_SCRIPT }, { 0x27205, 0x0027, NES_SCRIPT }, { 0x2722C, 0x0041, NES_SCRIPT }, + { 0x2726D, 0x01B1, NES_SCRIPT }, { 0x16362, 0x001F, NES_SCRIPT }, { 0x2463E, 0x002A, NES_SCRIPT }, { 0x150D3, 0x019E, NES_SCRIPT }, { 0x194A8, 0x0031, NES_SCRIPT }, + { 0x18D9E, 0x007C, NES_SCRIPT }, { 0x21557, 0x00DC, NES_SCRIPT }, { 0x1D3D8, 0x0018, NES_SCRIPT }, { 0x1D3F0, 0x0053, NES_SCRIPT }, { 0x17DB0, 0x0005, NES_SCRIPT }, + { 0x15271, 0x011B, NES_SCRIPT }, { 0x1538C, 0x000B, NES_SCRIPT }, { 0x24668, 0x0138, NES_SCRIPT }, { 0x247A0, 0x0014, NES_SCRIPT }, { 0x1DED5, 0x0018, NES_SCRIPT }, + { 0x247B4, 0x0027, NES_SCRIPT }, { 0x1A215, 0x004D, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BB2D, 0x00A5, NES_SCRIPT }, { 0x2AA8C, 0x00C1, NES_SCRIPT }, + { 0x2AB4D, 0x0140, NES_SCRIPT }, { 0x19982, 0x00BF, NES_SCRIPT }, { 0x19A41, 0x014D, NES_SCRIPT }, { 0x19B8E, 0x0012, NES_SCRIPT }, { 0x2AC8D, 0x0005, NES_SCRIPT }, + { 0x2AC92, 0x0005, NES_SCRIPT }, { 0x2AC97, 0x0005, NES_SCRIPT }, { 0x2AC9C, 0x0005, NES_SCRIPT }, { 0x2ACA1, 0x0005, NES_SCRIPT }, { 0x21633, 0x0033, NES_SCRIPT }, + { 0x2ACA6, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2ACAB, 0x009C, NES_SCRIPT }, { 0x2AD47, 0x009C, NES_SCRIPT } +}; +static const ScummNESFile::Resource res_scripts_swe[179] = { + { 0x00000, 0x0000, NES_SCRIPT }, { 0x28F80, 0x043B, NES_SCRIPT }, { 0x293BB, 0x0209, NES_SCRIPT }, { 0x295C4, 0x00AB, NES_SCRIPT }, { 0x2966F, 0x03FD, NES_SCRIPT }, + { 0x29A6C, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x29C0D, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x29C69, 0x0005, NES_SCRIPT }, + { 0x2B980, 0x000D, NES_SCRIPT }, { 0x2B98D, 0x000D, NES_SCRIPT }, { 0x186C8, 0x0040, NES_SCRIPT }, { 0x18708, 0x0016, NES_SCRIPT }, { 0x1B4B1, 0x0046, NES_SCRIPT }, + { 0x1EEBB, 0x00B8, NES_SCRIPT }, { 0x21CFA, 0x005C, NES_SCRIPT }, { 0x17537, 0x0027, NES_SCRIPT }, { 0x1FD0A, 0x0027, NES_SCRIPT }, { 0x1FD31, 0x0027, NES_SCRIPT }, + { 0x1BBB5, 0x0022, NES_SCRIPT }, { 0x15BC0, 0x0085, NES_SCRIPT }, { 0x22324, 0x001E, NES_SCRIPT }, { 0x22342, 0x008F, NES_SCRIPT }, { 0x19252, 0x002B, NES_SCRIPT }, + { 0x1CB1B, 0x006D, NES_SCRIPT }, { 0x1CB88, 0x004C, NES_SCRIPT }, { 0x1CBD4, 0x0044, NES_SCRIPT }, { 0x1CC18, 0x0053, NES_SCRIPT }, { 0x2049D, 0x0081, NES_SCRIPT }, + { 0x1634C, 0x0035, NES_SCRIPT }, { 0x16381, 0x001C, NES_SCRIPT }, { 0x1639D, 0x0014, NES_SCRIPT }, { 0x163B1, 0x001C, NES_SCRIPT }, { 0x163CD, 0x0027, NES_SCRIPT }, + { 0x163F4, 0x019B, NES_SCRIPT }, { 0x1D183, 0x0094, NES_SCRIPT }, { 0x1D217, 0x0117, NES_SCRIPT }, { 0x1D32E, 0x001C, NES_SCRIPT }, { 0x1D34A, 0x0056, NES_SCRIPT }, + { 0x1D3A0, 0x0072, NES_SCRIPT }, { 0x1E47F, 0x0028, NES_SCRIPT }, { 0x1E4A7, 0x0175, NES_SCRIPT }, { 0x1E61C, 0x022B, NES_SCRIPT }, { 0x27C85, 0x0071, NES_SCRIPT }, + { 0x17C86, 0x004A, NES_SCRIPT }, { 0x13DD6, 0x0039, NES_SCRIPT }, { 0x1871E, 0x0270, NES_SCRIPT }, { 0x1898E, 0x00C0, NES_SCRIPT }, { 0x18A4E, 0x01B6, NES_SCRIPT }, + { 0x00000, 0x0000, NES_SCRIPT }, { 0x19DC9, 0x00EE, NES_SCRIPT }, { 0x21D56, 0x00F5, NES_SCRIPT }, { 0x1E847, 0x0094, NES_SCRIPT }, { 0x21E4B, 0x0047, NES_SCRIPT }, + { 0x2B99A, 0x004D, NES_SCRIPT }, { 0x13E0F, 0x0024, NES_SCRIPT }, { 0x14D13, 0x0014, NES_SCRIPT }, { 0x1755E, 0x0054, NES_SCRIPT }, { 0x175B2, 0x011A, NES_SCRIPT }, + { 0x176CC, 0x0009, NES_SCRIPT }, { 0x14D27, 0x01B9, NES_SCRIPT }, { 0x2AA0E, 0x0256, NES_SCRIPT }, { 0x231A4, 0x06D2, NES_SCRIPT }, { 0x2B9E7, 0x001D, NES_SCRIPT }, + { 0x2BA04, 0x0016, NES_SCRIPT }, { 0x2BA1A, 0x002D, NES_SCRIPT }, { 0x2BA47, 0x0027, NES_SCRIPT }, { 0x2BA6E, 0x0016, NES_SCRIPT }, { 0x2BA84, 0x0014, NES_SCRIPT }, + { 0x2BA98, 0x0015, NES_SCRIPT }, { 0x2BAAD, 0x0029, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BAD6, 0x0010, NES_SCRIPT }, { 0x176D5, 0x00A2, NES_SCRIPT }, + { 0x22831, 0x0066, NES_SCRIPT }, { 0x14EE0, 0x0077, NES_SCRIPT }, { 0x1F30B, 0x011A, NES_SCRIPT }, { 0x1FD58, 0x001D, NES_SCRIPT }, { 0x1F425, 0x0095, NES_SCRIPT }, + { 0x1F4BA, 0x009E, NES_SCRIPT }, { 0x17777, 0x006F, NES_SCRIPT }, { 0x177E6, 0x002F, NES_SCRIPT }, { 0x1F558, 0x0098, NES_SCRIPT }, { 0x2BAE6, 0x00C4, NES_SCRIPT }, + { 0x2BBAA, 0x00AE, NES_SCRIPT }, { 0x2BC58, 0x0088, NES_SCRIPT }, { 0x20A3C, 0x01BB, NES_SCRIPT }, { 0x20BF7, 0x0197, NES_SCRIPT }, { 0x20D8E, 0x006E, NES_SCRIPT }, + { 0x20DFC, 0x0028, NES_SCRIPT }, { 0x20E24, 0x00EA, NES_SCRIPT }, { 0x20F0E, 0x0049, NES_SCRIPT }, { 0x20F57, 0x00E7, NES_SCRIPT }, { 0x2103E, 0x010C, NES_SCRIPT }, + { 0x2114A, 0x0151, NES_SCRIPT }, { 0x2129B, 0x01B0, NES_SCRIPT }, { 0x2144B, 0x0034, NES_SCRIPT }, { 0x2147F, 0x00A9, NES_SCRIPT }, { 0x24379, 0x010E, NES_SCRIPT }, + { 0x1BBD7, 0x0072, NES_SCRIPT }, { 0x1CC6B, 0x0092, NES_SCRIPT }, { 0x2898B, 0x0054, NES_SCRIPT }, { 0x19EB7, 0x00D3, NES_SCRIPT }, { 0x19F8A, 0x0077, NES_SCRIPT }, + { 0x14F57, 0x0057, NES_SCRIPT }, { 0x2703E, 0x0307, NES_SCRIPT }, { 0x1D9FB, 0x024F, NES_SCRIPT }, { 0x1DC4A, 0x00E4, NES_SCRIPT }, { 0x1DD2E, 0x0059, NES_SCRIPT }, + { 0x1DD87, 0x01C2, NES_SCRIPT }, { 0x14FAE, 0x004D, NES_SCRIPT }, { 0x26D52, 0x00D5, NES_SCRIPT }, { 0x21E92, 0x0013, NES_SCRIPT }, { 0x29C6E, 0x00F0, NES_SCRIPT }, + { 0x24487, 0x00E0, NES_SCRIPT }, { 0x21528, 0x00F2, NES_SCRIPT }, { 0x24567, 0x0023, NES_SCRIPT }, { 0x2B6B2, 0x010B, NES_SCRIPT }, { 0x2458A, 0x00A1, NES_SCRIPT }, + { 0x250A0, 0x018B, NES_SCRIPT }, { 0x1B4F7, 0x000D, NES_SCRIPT }, { 0x1B504, 0x000D, NES_SCRIPT }, { 0x23876, 0x018E, NES_SCRIPT }, { 0x27639, 0x01F0, NES_SCRIPT }, + { 0x23A04, 0x017B, NES_SCRIPT }, { 0x23B7F, 0x01AC, NES_SCRIPT }, { 0x23D2B, 0x0016, NES_SCRIPT }, { 0x2B7BD, 0x005B, NES_SCRIPT }, { 0x23D41, 0x0020, NES_SCRIPT }, + { 0x2A643, 0x00A6, NES_SCRIPT }, { 0x29D5E, 0x0399, NES_SCRIPT }, { 0x14FFB, 0x00D2, NES_SCRIPT }, { 0x2B1DE, 0x0063, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, + { 0x2522B, 0x003C, NES_SCRIPT }, { 0x1E8DB, 0x0011, NES_SCRIPT }, { 0x13E33, 0x0018, NES_SCRIPT }, { 0x26585, 0x001F, NES_SCRIPT }, { 0x265A4, 0x0054, NES_SCRIPT }, + { 0x265F8, 0x017D, NES_SCRIPT }, { 0x26775, 0x004B, NES_SCRIPT }, { 0x267C0, 0x0165, NES_SCRIPT }, { 0x26925, 0x0027, NES_SCRIPT }, { 0x2694C, 0x0041, NES_SCRIPT }, + { 0x2698D, 0x01CB, NES_SCRIPT }, { 0x13E4B, 0x001F, NES_SCRIPT }, { 0x2462B, 0x002A, NES_SCRIPT }, { 0x150CD, 0x0187, NES_SCRIPT }, { 0x1927D, 0x0031, NES_SCRIPT }, + { 0x17815, 0x0087, NES_SCRIPT }, { 0x2161A, 0x00D8, NES_SCRIPT }, { 0x1D412, 0x0018, NES_SCRIPT }, { 0x1D42A, 0x0058, NES_SCRIPT }, { 0x18C04, 0x0005, NES_SCRIPT }, + { 0x15254, 0x0108, NES_SCRIPT }, { 0x1535C, 0x000B, NES_SCRIPT }, { 0x24655, 0x0139, NES_SCRIPT }, { 0x2478E, 0x0014, NES_SCRIPT }, { 0x1DF49, 0x0018, NES_SCRIPT }, + { 0x247A2, 0x0027, NES_SCRIPT }, { 0x1A001, 0x004C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B241, 0x00A5, NES_SCRIPT }, { 0x2A0F7, 0x00B5, NES_SCRIPT }, + { 0x2A1AC, 0x0140, NES_SCRIPT }, { 0x19759, 0x00CA, NES_SCRIPT }, { 0x19823, 0x014D, NES_SCRIPT }, { 0x19970, 0x0012, NES_SCRIPT }, { 0x2A2EC, 0x0005, NES_SCRIPT }, + { 0x2A2F1, 0x0005, NES_SCRIPT }, { 0x2A2F6, 0x0005, NES_SCRIPT }, { 0x2A2FB, 0x0005, NES_SCRIPT }, { 0x2A300, 0x0005, NES_SCRIPT }, { 0x216F2, 0x0033, NES_SCRIPT }, + { 0x2A305, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A30A, 0x009C, NES_SCRIPT }, { 0x2A3A6, 0x009C, NES_SCRIPT } +}; +static const ScummNESFile::Resource res_scripts_fra[179] = { + { 0x00000, 0x0000, NES_SCRIPT }, { 0x2947D, 0x0480, NES_SCRIPT }, { 0x298FD, 0x0226, NES_SCRIPT }, { 0x29B23, 0x0092, NES_SCRIPT }, { 0x29BB5, 0x040C, NES_SCRIPT }, + { 0x29FC1, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A162, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A1BE, 0x0005, NES_SCRIPT }, + { 0x2C169, 0x000D, NES_SCRIPT }, { 0x2C176, 0x000D, NES_SCRIPT }, { 0x186E3, 0x0040, NES_SCRIPT }, { 0x18723, 0x0016, NES_SCRIPT }, { 0x1B59F, 0x0046, NES_SCRIPT }, + { 0x1EFD7, 0x00CB, NES_SCRIPT }, { 0x21D09, 0x0054, NES_SCRIPT }, { 0x176C8, 0x0027, NES_SCRIPT }, { 0x1FE6A, 0x0027, NES_SCRIPT }, { 0x1FE91, 0x0027, NES_SCRIPT }, + { 0x1BC9A, 0x0022, NES_SCRIPT }, { 0x15CD6, 0x0092, NES_SCRIPT }, { 0x22336, 0x001C, NES_SCRIPT }, { 0x22352, 0x008F, NES_SCRIPT }, { 0x192A5, 0x002B, NES_SCRIPT }, + { 0x1CAAA, 0x0069, NES_SCRIPT }, { 0x1CB13, 0x0054, NES_SCRIPT }, { 0x1CB67, 0x0048, NES_SCRIPT }, { 0x1CBAF, 0x0058, NES_SCRIPT }, { 0x204B6, 0x0078, NES_SCRIPT }, + { 0x16471, 0x0035, NES_SCRIPT }, { 0x164A6, 0x001C, NES_SCRIPT }, { 0x164C2, 0x0014, NES_SCRIPT }, { 0x164D6, 0x001C, NES_SCRIPT }, { 0x164F2, 0x0027, NES_SCRIPT }, + { 0x16519, 0x01BB, NES_SCRIPT }, { 0x1D135, 0x008D, NES_SCRIPT }, { 0x1D1C2, 0x0119, NES_SCRIPT }, { 0x1D2DB, 0x001C, NES_SCRIPT }, { 0x1D2F7, 0x0056, NES_SCRIPT }, + { 0x1D34D, 0x0072, NES_SCRIPT }, { 0x1E4BF, 0x0028, NES_SCRIPT }, { 0x1E4E7, 0x01E0, NES_SCRIPT }, { 0x1E6C7, 0x0241, NES_SCRIPT }, { 0x2845D, 0x0071, NES_SCRIPT }, + { 0x17E48, 0x004C, NES_SCRIPT }, { 0x13DE3, 0x0039, NES_SCRIPT }, { 0x18739, 0x0296, NES_SCRIPT }, { 0x189CF, 0x00C2, NES_SCRIPT }, { 0x18A91, 0x01A5, NES_SCRIPT }, + { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E13, 0x00F3, NES_SCRIPT }, { 0x21D5D, 0x00F6, NES_SCRIPT }, { 0x1E908, 0x00B8, NES_SCRIPT }, { 0x21E53, 0x0047, NES_SCRIPT }, + { 0x2C183, 0x004D, NES_SCRIPT }, { 0x13E1C, 0x0024, NES_SCRIPT }, { 0x14D77, 0x0014, NES_SCRIPT }, { 0x176EF, 0x0059, NES_SCRIPT }, { 0x17748, 0x013F, NES_SCRIPT }, + { 0x17887, 0x0009, NES_SCRIPT }, { 0x14D8B, 0x01D4, NES_SCRIPT }, { 0x2ACFB, 0x028D, NES_SCRIPT }, { 0x23203, 0x0779, NES_SCRIPT }, { 0x2C1D0, 0x001B, NES_SCRIPT }, + { 0x2C1EB, 0x001F, NES_SCRIPT }, { 0x2C20A, 0x0024, NES_SCRIPT }, { 0x2C22E, 0x0019, NES_SCRIPT }, { 0x2C247, 0x0018, NES_SCRIPT }, { 0x2C25F, 0x001D, NES_SCRIPT }, + { 0x2C27C, 0x0016, NES_SCRIPT }, { 0x2C292, 0x0027, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C2B9, 0x0011, NES_SCRIPT }, { 0x17890, 0x00AA, NES_SCRIPT }, + { 0x22846, 0x0066, NES_SCRIPT }, { 0x14F5F, 0x0083, NES_SCRIPT }, { 0x1F43C, 0x013A, NES_SCRIPT }, { 0x1FEB8, 0x001D, NES_SCRIPT }, { 0x1F576, 0x0098, NES_SCRIPT }, + { 0x1F60E, 0x009B, NES_SCRIPT }, { 0x1793A, 0x006E, NES_SCRIPT }, { 0x179A8, 0x0033, NES_SCRIPT }, { 0x1F6A9, 0x00A5, NES_SCRIPT }, { 0x2C2CA, 0x00BA, NES_SCRIPT }, + { 0x2C384, 0x00AC, NES_SCRIPT }, { 0x2C430, 0x008F, NES_SCRIPT }, { 0x20A2D, 0x01BE, NES_SCRIPT }, { 0x20BEB, 0x0158, NES_SCRIPT }, { 0x20D43, 0x0079, NES_SCRIPT }, + { 0x20DBC, 0x002B, NES_SCRIPT }, { 0x20DE7, 0x00E8, NES_SCRIPT }, { 0x20ECF, 0x004A, NES_SCRIPT }, { 0x20F19, 0x0110, NES_SCRIPT }, { 0x21029, 0x0136, NES_SCRIPT }, + { 0x2115F, 0x0152, NES_SCRIPT }, { 0x212B1, 0x01B3, NES_SCRIPT }, { 0x21464, 0x0032, NES_SCRIPT }, { 0x21496, 0x00A9, NES_SCRIPT }, { 0x2437F, 0x0133, NES_SCRIPT }, + { 0x1BCBC, 0x0074, NES_SCRIPT }, { 0x1CC07, 0x0090, NES_SCRIPT }, { 0x28E43, 0x0054, NES_SCRIPT }, { 0x19F06, 0x00DB, NES_SCRIPT }, { 0x19FE1, 0x0080, NES_SCRIPT }, + { 0x14FE2, 0x0057, NES_SCRIPT }, { 0x273F4, 0x031F, NES_SCRIPT }, { 0x1D9D4, 0x0238, NES_SCRIPT }, { 0x1DC0C, 0x00FE, NES_SCRIPT }, { 0x1DD0A, 0x005A, NES_SCRIPT }, + { 0x1DD64, 0x01F5, NES_SCRIPT }, { 0x15039, 0x004D, NES_SCRIPT }, { 0x270DD, 0x0100, NES_SCRIPT }, { 0x21E9A, 0x0013, NES_SCRIPT }, { 0x2A1C3, 0x00F0, NES_SCRIPT }, + { 0x244B2, 0x00E4, NES_SCRIPT }, { 0x2153F, 0x00EC, NES_SCRIPT }, { 0x24596, 0x0033, NES_SCRIPT }, { 0x2BC04, 0x0108, NES_SCRIPT }, { 0x245C9, 0x009F, NES_SCRIPT }, + { 0x250F1, 0x0193, NES_SCRIPT }, { 0x1B5E5, 0x000D, NES_SCRIPT }, { 0x1B5F2, 0x000D, NES_SCRIPT }, { 0x2397C, 0x0199, NES_SCRIPT }, { 0x27A07, 0x0233, NES_SCRIPT }, + { 0x23B15, 0x0171, NES_SCRIPT }, { 0x23C86, 0x01BC, NES_SCRIPT }, { 0x23E42, 0x0016, NES_SCRIPT }, { 0x2BD0C, 0x005B, NES_SCRIPT }, { 0x23E58, 0x0020, NES_SCRIPT }, + { 0x27E3B, 0x00B9, NES_SCRIPT }, { 0x2A2B3, 0x03D3, NES_SCRIPT }, { 0x15086, 0x00E4, NES_SCRIPT }, { 0x2B70C, 0x0067, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, + { 0x25284, 0x003C, NES_SCRIPT }, { 0x1E9C0, 0x0011, NES_SCRIPT }, { 0x13E40, 0x0018, NES_SCRIPT }, { 0x26621, 0x001F, NES_SCRIPT }, { 0x26640, 0x0054, NES_SCRIPT }, + { 0x26694, 0x0173, NES_SCRIPT }, { 0x26807, 0x004B, NES_SCRIPT }, { 0x26852, 0x0190, NES_SCRIPT }, { 0x269E2, 0x0027, NES_SCRIPT }, { 0x26A09, 0x0041, NES_SCRIPT }, + { 0x26A4A, 0x024E, NES_SCRIPT }, { 0x13E58, 0x001F, NES_SCRIPT }, { 0x24668, 0x002A, NES_SCRIPT }, { 0x1516A, 0x01C9, NES_SCRIPT }, { 0x192D0, 0x0031, NES_SCRIPT }, + { 0x179DB, 0x0088, NES_SCRIPT }, { 0x2162B, 0x00D0, NES_SCRIPT }, { 0x1D3BF, 0x0018, NES_SCRIPT }, { 0x1D3D7, 0x0055, NES_SCRIPT }, { 0x18C36, 0x0005, NES_SCRIPT }, + { 0x15333, 0x0113, NES_SCRIPT }, { 0x15446, 0x000B, NES_SCRIPT }, { 0x24692, 0x014D, NES_SCRIPT }, { 0x247DF, 0x0014, NES_SCRIPT }, { 0x1DF59, 0x0018, NES_SCRIPT }, + { 0x247F3, 0x0027, NES_SCRIPT }, { 0x1A061, 0x0050, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B773, 0x00A5, NES_SCRIPT }, { 0x2A686, 0x00BA, NES_SCRIPT }, + { 0x2A740, 0x0140, NES_SCRIPT }, { 0x1979F, 0x00CA, NES_SCRIPT }, { 0x19869, 0x014D, NES_SCRIPT }, { 0x199B6, 0x0012, NES_SCRIPT }, { 0x2A880, 0x0005, NES_SCRIPT }, + { 0x2A885, 0x0005, NES_SCRIPT }, { 0x2A88A, 0x0005, NES_SCRIPT }, { 0x2A88F, 0x0005, NES_SCRIPT }, { 0x2A894, 0x0005, NES_SCRIPT }, { 0x216FB, 0x0033, NES_SCRIPT }, + { 0x2A899, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A89E, 0x009C, NES_SCRIPT }, { 0x2A93A, 0x009C, NES_SCRIPT } +}; +static const ScummNESFile::Resource res_scripts_ger[179] = { + { 0x00000, 0x0000, NES_SCRIPT }, { 0x295B0, 0x045A, NES_SCRIPT }, { 0x29A0A, 0x0218, NES_SCRIPT }, { 0x29C22, 0x00B1, NES_SCRIPT }, { 0x29CD3, 0x0408, NES_SCRIPT }, + { 0x2A0DB, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A27C, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A2D8, 0x0005, NES_SCRIPT }, + { 0x2C169, 0x000D, NES_SCRIPT }, { 0x2C176, 0x000D, NES_SCRIPT }, { 0x186DB, 0x0040, NES_SCRIPT }, { 0x1871B, 0x0016, NES_SCRIPT }, { 0x1B5C2, 0x0046, NES_SCRIPT }, + { 0x1EFB7, 0x00E3, NES_SCRIPT }, { 0x21D9D, 0x0069, NES_SCRIPT }, { 0x174F1, 0x0027, NES_SCRIPT }, { 0x1FE92, 0x0027, NES_SCRIPT }, { 0x1FEB9, 0x0027, NES_SCRIPT }, + { 0x1BCE5, 0x0022, NES_SCRIPT }, { 0x13EF4, 0x0087, NES_SCRIPT }, { 0x223EC, 0x001F, NES_SCRIPT }, { 0x2240B, 0x008F, NES_SCRIPT }, { 0x192CC, 0x002B, NES_SCRIPT }, + { 0x1CB08, 0x006E, NES_SCRIPT }, { 0x1CB76, 0x004E, NES_SCRIPT }, { 0x1CBC4, 0x004D, NES_SCRIPT }, { 0x1CC11, 0x0059, NES_SCRIPT }, { 0x204AA, 0x0080, NES_SCRIPT }, + { 0x1628E, 0x0035, NES_SCRIPT }, { 0x162C3, 0x001C, NES_SCRIPT }, { 0x162DF, 0x0014, NES_SCRIPT }, { 0x162F3, 0x001C, NES_SCRIPT }, { 0x1630F, 0x0027, NES_SCRIPT }, + { 0x16336, 0x01D1, NES_SCRIPT }, { 0x1D199, 0x00A0, NES_SCRIPT }, { 0x1D239, 0x011C, NES_SCRIPT }, { 0x1D355, 0x001C, NES_SCRIPT }, { 0x1D371, 0x0056, NES_SCRIPT }, + { 0x1D3C7, 0x0072, NES_SCRIPT }, { 0x1E4FA, 0x0028, NES_SCRIPT }, { 0x1E522, 0x019D, NES_SCRIPT }, { 0x1E6BF, 0x023B, NES_SCRIPT }, { 0x2845D, 0x0071, NES_SCRIPT }, + { 0x17C50, 0x0052, NES_SCRIPT }, { 0x15AC9, 0x0039, NES_SCRIPT }, { 0x18731, 0x02E7, NES_SCRIPT }, { 0x18A18, 0x00BC, NES_SCRIPT }, { 0x18AD4, 0x01A2, NES_SCRIPT }, + { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E45, 0x00F8, NES_SCRIPT }, { 0x21E06, 0x00F7, NES_SCRIPT }, { 0x1E8FA, 0x00B5, NES_SCRIPT }, { 0x21EFD, 0x0047, NES_SCRIPT }, + { 0x2C183, 0x004D, NES_SCRIPT }, { 0x15B02, 0x0024, NES_SCRIPT }, { 0x14D64, 0x0014, NES_SCRIPT }, { 0x17518, 0x005E, NES_SCRIPT }, { 0x17576, 0x0125, NES_SCRIPT }, + { 0x1769B, 0x0009, NES_SCRIPT }, { 0x14D78, 0x01C7, NES_SCRIPT }, { 0x2ADCE, 0x0263, NES_SCRIPT }, { 0x232AF, 0x077F, NES_SCRIPT }, { 0x2C1D0, 0x001E, NES_SCRIPT }, + { 0x2C1EE, 0x0024, NES_SCRIPT }, { 0x2C212, 0x002E, NES_SCRIPT }, { 0x2C240, 0x0022, NES_SCRIPT }, { 0x2C262, 0x0013, NES_SCRIPT }, { 0x2C275, 0x001E, NES_SCRIPT }, + { 0x2C293, 0x0016, NES_SCRIPT }, { 0x2C2A9, 0x0027, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2C2D0, 0x0012, NES_SCRIPT }, { 0x176A4, 0x00A4, NES_SCRIPT }, + { 0x228F8, 0x0066, NES_SCRIPT }, { 0x14F3F, 0x007F, NES_SCRIPT }, { 0x1F428, 0x013A, NES_SCRIPT }, { 0x1FEE0, 0x001D, NES_SCRIPT }, { 0x1F562, 0x00A0, NES_SCRIPT }, + { 0x1F602, 0x00A4, NES_SCRIPT }, { 0x17748, 0x0076, NES_SCRIPT }, { 0x177BE, 0x0036, NES_SCRIPT }, { 0x1F6A6, 0x00B9, NES_SCRIPT }, { 0x2C2E2, 0x00CB, NES_SCRIPT }, + { 0x2C3AD, 0x00B7, NES_SCRIPT }, { 0x2C464, 0x008A, NES_SCRIPT }, { 0x20A58, 0x01BD, NES_SCRIPT }, { 0x20C15, 0x0181, NES_SCRIPT }, { 0x20D96, 0x0078, NES_SCRIPT }, + { 0x20E0E, 0x003C, NES_SCRIPT }, { 0x20E4A, 0x00E9, NES_SCRIPT }, { 0x20F33, 0x0046, NES_SCRIPT }, { 0x20F79, 0x00F6, NES_SCRIPT }, { 0x2106F, 0x0118, NES_SCRIPT }, + { 0x21187, 0x015B, NES_SCRIPT }, { 0x212E2, 0x01AC, NES_SCRIPT }, { 0x2148E, 0x003F, NES_SCRIPT }, { 0x214CD, 0x00A9, NES_SCRIPT }, { 0x2436F, 0x0126, NES_SCRIPT }, + { 0x1BD07, 0x0075, NES_SCRIPT }, { 0x1CC6A, 0x009B, NES_SCRIPT }, { 0x28F5D, 0x0054, NES_SCRIPT }, { 0x19F3D, 0x00E1, NES_SCRIPT }, { 0x1A01E, 0x0086, NES_SCRIPT }, + { 0x14FBE, 0x0057, NES_SCRIPT }, { 0x27326, 0x033D, NES_SCRIPT }, { 0x1DA51, 0x023B, NES_SCRIPT }, { 0x1DC8C, 0x00FB, NES_SCRIPT }, { 0x1DD87, 0x0056, NES_SCRIPT }, + { 0x1DDDD, 0x01E1, NES_SCRIPT }, { 0x15015, 0x004D, NES_SCRIPT }, { 0x27027, 0x00E8, NES_SCRIPT }, { 0x21F44, 0x0013, NES_SCRIPT }, { 0x2A2DD, 0x00F0, NES_SCRIPT }, + { 0x24495, 0x00F8, NES_SCRIPT }, { 0x21576, 0x00F9, NES_SCRIPT }, { 0x2458D, 0x002B, NES_SCRIPT }, { 0x2BAA4, 0x010F, NES_SCRIPT }, { 0x245B8, 0x00A5, NES_SCRIPT }, + { 0x250D0, 0x019C, NES_SCRIPT }, { 0x1B608, 0x000D, NES_SCRIPT }, { 0x1B615, 0x000D, NES_SCRIPT }, { 0x23A2E, 0x0185, NES_SCRIPT }, { 0x27957, 0x0212, NES_SCRIPT }, + { 0x23BB3, 0x0158, NES_SCRIPT }, { 0x23D0B, 0x01C4, NES_SCRIPT }, { 0x23ECF, 0x0016, NES_SCRIPT }, { 0x2BBB3, 0x005A, NES_SCRIPT }, { 0x23EE5, 0x0020, NES_SCRIPT }, + { 0x27D6A, 0x00A7, NES_SCRIPT }, { 0x2A3CD, 0x038C, NES_SCRIPT }, { 0x15062, 0x00F6, NES_SCRIPT }, { 0x2B5B2, 0x007B, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, + { 0x2526C, 0x003C, NES_SCRIPT }, { 0x1E9AF, 0x0011, NES_SCRIPT }, { 0x15B26, 0x0018, NES_SCRIPT }, { 0x265F5, 0x001F, NES_SCRIPT }, { 0x26614, 0x0054, NES_SCRIPT }, + { 0x26668, 0x018E, NES_SCRIPT }, { 0x267F6, 0x004B, NES_SCRIPT }, { 0x26841, 0x0196, NES_SCRIPT }, { 0x269D7, 0x0027, NES_SCRIPT }, { 0x269FE, 0x0041, NES_SCRIPT }, + { 0x26A3F, 0x01A3, NES_SCRIPT }, { 0x15B3E, 0x001F, NES_SCRIPT }, { 0x2465D, 0x002A, NES_SCRIPT }, { 0x15158, 0x0198, NES_SCRIPT }, { 0x192F7, 0x0031, NES_SCRIPT }, + { 0x177F4, 0x008C, NES_SCRIPT }, { 0x2166F, 0x00DA, NES_SCRIPT }, { 0x1D439, 0x0018, NES_SCRIPT }, { 0x1D451, 0x0054, NES_SCRIPT }, { 0x18C76, 0x0005, NES_SCRIPT }, + { 0x152F0, 0x0126, NES_SCRIPT }, { 0x15416, 0x000B, NES_SCRIPT }, { 0x24687, 0x0137, NES_SCRIPT }, { 0x247BE, 0x0014, NES_SCRIPT }, { 0x1DFBE, 0x0018, NES_SCRIPT }, + { 0x247D2, 0x0027, NES_SCRIPT }, { 0x1A0A4, 0x004D, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B62D, 0x00A5, NES_SCRIPT }, { 0x2A759, 0x00BA, NES_SCRIPT }, + { 0x2A813, 0x0140, NES_SCRIPT }, { 0x197CF, 0x00D0, NES_SCRIPT }, { 0x1989F, 0x014D, NES_SCRIPT }, { 0x199EC, 0x0012, NES_SCRIPT }, { 0x2A953, 0x0005, NES_SCRIPT }, + { 0x2A958, 0x0005, NES_SCRIPT }, { 0x2A95D, 0x0005, NES_SCRIPT }, { 0x2A962, 0x0005, NES_SCRIPT }, { 0x2A967, 0x0005, NES_SCRIPT }, { 0x21749, 0x0033, NES_SCRIPT }, + { 0x2A96C, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A971, 0x009C, NES_SCRIPT }, { 0x2AA0D, 0x009C, NES_SCRIPT } +}; +static const ScummNESFile::Resource res_scripts_esp[179] = { + { 0x00000, 0x0000, NES_SCRIPT }, { 0x28F4C, 0x0457, NES_SCRIPT }, { 0x293A3, 0x0213, NES_SCRIPT }, { 0x295B6, 0x009C, NES_SCRIPT }, { 0x29652, 0x03FE, NES_SCRIPT }, + { 0x29A50, 0x01A1, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x29BF1, 0x005C, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x29C4D, 0x0005, NES_SCRIPT }, + { 0x2B964, 0x000D, NES_SCRIPT }, { 0x2B971, 0x000D, NES_SCRIPT }, { 0x186EE, 0x0040, NES_SCRIPT }, { 0x1872E, 0x0016, NES_SCRIPT }, { 0x1B5A0, 0x0046, NES_SCRIPT }, + { 0x1EF97, 0x00B4, NES_SCRIPT }, { 0x21D17, 0x0056, NES_SCRIPT }, { 0x175E9, 0x0027, NES_SCRIPT }, { 0x1FE06, 0x0027, NES_SCRIPT }, { 0x1FE2D, 0x0027, NES_SCRIPT }, + { 0x1BC86, 0x0022, NES_SCRIPT }, { 0x15C26, 0x008B, NES_SCRIPT }, { 0x2232E, 0x001F, NES_SCRIPT }, { 0x2234D, 0x008F, NES_SCRIPT }, { 0x192AF, 0x002B, NES_SCRIPT }, + { 0x1CB59, 0x006B, NES_SCRIPT }, { 0x1CBC4, 0x0045, NES_SCRIPT }, { 0x1CC09, 0x0046, NES_SCRIPT }, { 0x1CC4F, 0x005D, NES_SCRIPT }, { 0x204CC, 0x0077, NES_SCRIPT }, + { 0x163DA, 0x0035, NES_SCRIPT }, { 0x1640F, 0x001C, NES_SCRIPT }, { 0x1642B, 0x0014, NES_SCRIPT }, { 0x1643F, 0x001C, NES_SCRIPT }, { 0x1645B, 0x0027, NES_SCRIPT }, + { 0x16482, 0x01A3, NES_SCRIPT }, { 0x1D1DE, 0x009E, NES_SCRIPT }, { 0x1D27C, 0x011A, NES_SCRIPT }, { 0x1D396, 0x001C, NES_SCRIPT }, { 0x1D3B2, 0x0056, NES_SCRIPT }, + { 0x1D408, 0x0072, NES_SCRIPT }, { 0x1E50F, 0x0028, NES_SCRIPT }, { 0x1E537, 0x0199, NES_SCRIPT }, { 0x1E6D0, 0x0240, NES_SCRIPT }, { 0x27CA1, 0x0071, NES_SCRIPT }, + { 0x17D14, 0x004C, NES_SCRIPT }, { 0x13E0F, 0x0039, NES_SCRIPT }, { 0x18744, 0x02B9, NES_SCRIPT }, { 0x189FD, 0x00B9, NES_SCRIPT }, { 0x18AB6, 0x0183, NES_SCRIPT }, + { 0x00000, 0x0000, NES_SCRIPT }, { 0x19E3E, 0x00F0, NES_SCRIPT }, { 0x21D6D, 0x00F7, NES_SCRIPT }, { 0x1E910, 0x00A8, NES_SCRIPT }, { 0x21E64, 0x0047, NES_SCRIPT }, + { 0x2B97E, 0x004D, NES_SCRIPT }, { 0x13E48, 0x0024, NES_SCRIPT }, { 0x14D06, 0x0014, NES_SCRIPT }, { 0x17610, 0x005B, NES_SCRIPT }, { 0x1766B, 0x0111, NES_SCRIPT }, + { 0x1777C, 0x0009, NES_SCRIPT }, { 0x14D1A, 0x01C9, NES_SCRIPT }, { 0x2A9E3, 0x0263, NES_SCRIPT }, { 0x231C6, 0x06D6, NES_SCRIPT }, { 0x2B9CB, 0x001C, NES_SCRIPT }, + { 0x2B9E7, 0x001C, NES_SCRIPT }, { 0x2BA03, 0x0025, NES_SCRIPT }, { 0x2BA28, 0x0023, NES_SCRIPT }, { 0x2BA4B, 0x002A, NES_SCRIPT }, { 0x2BA75, 0x0033, NES_SCRIPT }, + { 0x2BAA8, 0x0016, NES_SCRIPT }, { 0x2BABE, 0x0024, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2BAE2, 0x0011, NES_SCRIPT }, { 0x17785, 0x00A2, NES_SCRIPT }, + { 0x22838, 0x0066, NES_SCRIPT }, { 0x14EE3, 0x0079, NES_SCRIPT }, { 0x1F3DB, 0x010F, NES_SCRIPT }, { 0x1FE54, 0x001D, NES_SCRIPT }, { 0x1F4EA, 0x00A2, NES_SCRIPT }, + { 0x1F58C, 0x0097, NES_SCRIPT }, { 0x17827, 0x0061, NES_SCRIPT }, { 0x17888, 0x0032, NES_SCRIPT }, { 0x1F623, 0x00A7, NES_SCRIPT }, { 0x2BAF3, 0x00CD, NES_SCRIPT }, + { 0x2BBC0, 0x00BD, NES_SCRIPT }, { 0x2BC7D, 0x0089, NES_SCRIPT }, { 0x20A73, 0x01C2, NES_SCRIPT }, { 0x20C35, 0x016E, NES_SCRIPT }, { 0x20DA3, 0x006F, NES_SCRIPT }, + { 0x20E12, 0x0037, NES_SCRIPT }, { 0x20E49, 0x00EC, NES_SCRIPT }, { 0x20F35, 0x0047, NES_SCRIPT }, { 0x20F7C, 0x00F8, NES_SCRIPT }, { 0x21074, 0x0102, NES_SCRIPT }, + { 0x21176, 0x0133, NES_SCRIPT }, { 0x212A9, 0x0197, NES_SCRIPT }, { 0x21440, 0x002D, NES_SCRIPT }, { 0x2146D, 0x00A9, NES_SCRIPT }, { 0x2436D, 0x0125, NES_SCRIPT }, + { 0x1BCA8, 0x0071, NES_SCRIPT }, { 0x1CCAC, 0x0096, NES_SCRIPT }, { 0x2896A, 0x0054, NES_SCRIPT }, { 0x19F2E, 0x00DF, NES_SCRIPT }, { 0x1A00D, 0x007F, NES_SCRIPT }, + { 0x14F5C, 0x0057, NES_SCRIPT }, { 0x27074, 0x02F6, NES_SCRIPT }, { 0x1DA73, 0x023A, NES_SCRIPT }, { 0x1DCAD, 0x00E8, NES_SCRIPT }, { 0x1DD95, 0x0059, NES_SCRIPT }, + { 0x1DDEE, 0x01E3, NES_SCRIPT }, { 0x14FB3, 0x004D, NES_SCRIPT }, { 0x26D81, 0x00DC, NES_SCRIPT }, { 0x21EAB, 0x0013, NES_SCRIPT }, { 0x29C52, 0x00F0, NES_SCRIPT }, + { 0x24492, 0x00E4, NES_SCRIPT }, { 0x21516, 0x00EE, NES_SCRIPT }, { 0x24576, 0x002D, NES_SCRIPT }, { 0x2B692, 0x010D, NES_SCRIPT }, { 0x245A3, 0x00AC, NES_SCRIPT }, + { 0x250C3, 0x0184, NES_SCRIPT }, { 0x1B5E6, 0x000D, NES_SCRIPT }, { 0x1B5F3, 0x000D, NES_SCRIPT }, { 0x2389C, 0x0182, NES_SCRIPT }, { 0x2765E, 0x01E7, NES_SCRIPT }, + { 0x23A1E, 0x017A, NES_SCRIPT }, { 0x23B98, 0x01B6, NES_SCRIPT }, { 0x23D4E, 0x0016, NES_SCRIPT }, { 0x2B79F, 0x005D, NES_SCRIPT }, { 0x23D64, 0x0020, NES_SCRIPT }, + { 0x2A619, 0x00A5, NES_SCRIPT }, { 0x29D42, 0x038F, NES_SCRIPT }, { 0x15000, 0x00ED, NES_SCRIPT }, { 0x2B1B8, 0x0063, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, + { 0x25247, 0x003C, NES_SCRIPT }, { 0x1E9B8, 0x0011, NES_SCRIPT }, { 0x13E6C, 0x0018, NES_SCRIPT }, { 0x265E0, 0x001F, NES_SCRIPT }, { 0x265FF, 0x0054, NES_SCRIPT }, + { 0x26653, 0x0147, NES_SCRIPT }, { 0x2679A, 0x004B, NES_SCRIPT }, { 0x267E5, 0x0184, NES_SCRIPT }, { 0x26969, 0x0027, NES_SCRIPT }, { 0x26990, 0x0041, NES_SCRIPT }, + { 0x269D1, 0x01B9, NES_SCRIPT }, { 0x13E84, 0x001F, NES_SCRIPT }, { 0x2464F, 0x002A, NES_SCRIPT }, { 0x150ED, 0x01A4, NES_SCRIPT }, { 0x192DA, 0x0031, NES_SCRIPT }, + { 0x178BA, 0x007C, NES_SCRIPT }, { 0x21604, 0x00E4, NES_SCRIPT }, { 0x1D47A, 0x0018, NES_SCRIPT }, { 0x1D492, 0x005B, NES_SCRIPT }, { 0x18C39, 0x0005, NES_SCRIPT }, + { 0x15291, 0x010F, NES_SCRIPT }, { 0x153A0, 0x000B, NES_SCRIPT }, { 0x24679, 0x0138, NES_SCRIPT }, { 0x247B1, 0x0014, NES_SCRIPT }, { 0x1DFD1, 0x0018, NES_SCRIPT }, + { 0x247C5, 0x0027, NES_SCRIPT }, { 0x1A08C, 0x004E, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2B21B, 0x00A5, NES_SCRIPT }, { 0x2A0D1, 0x00B1, NES_SCRIPT }, + { 0x2A182, 0x0140, NES_SCRIPT }, { 0x197CF, 0x00BE, NES_SCRIPT }, { 0x1988D, 0x014D, NES_SCRIPT }, { 0x199DA, 0x0012, NES_SCRIPT }, { 0x2A2C2, 0x0005, NES_SCRIPT }, + { 0x2A2C7, 0x0005, NES_SCRIPT }, { 0x2A2CC, 0x0005, NES_SCRIPT }, { 0x2A2D1, 0x0005, NES_SCRIPT }, { 0x2A2D6, 0x0005, NES_SCRIPT }, { 0x216E8, 0x0033, NES_SCRIPT }, + { 0x2A2DB, 0x0005, NES_SCRIPT }, { 0x00000, 0x0000, NES_SCRIPT }, { 0x2A2E0, 0x009C, NES_SCRIPT }, { 0x2A37C, 0x009C, NES_SCRIPT } +}; + +static const ScummNESFile::Resource *res_scripts[ScummNESFile::kROMsetNum] = { + res_scripts_usa, + res_scripts_eur, + res_scripts_swe, + res_scripts_fra, + res_scripts_ger, + res_scripts_esp, +}; + +static const ScummNESFile::Resource res_sounds_usa[82] = { + { 0x0FFE8, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, + { 0x30ECA, 0x0832, NES_SOUND }, { 0x17FCA, 0x0011, NES_SOUND }, { 0x27E0B, 0x0073, NES_SOUND }, { 0x17FDB, 0x0011, NES_SOUND }, { 0x17FEC, 0x0011, NES_SOUND }, + { 0x27E7E, 0x0056, NES_SOUND }, { 0x27ED4, 0x001F, NES_SOUND }, { 0x23FEE, 0x0011, NES_SOUND }, { 0x0FFF2, 0x000A, NES_SOUND }, { 0x27EF3, 0x000A, NES_SOUND }, + { 0x27EFD, 0x0019, NES_SOUND }, { 0x27F16, 0x004B, NES_SOUND }, { 0x27F61, 0x000A, NES_SOUND }, { 0x27F6B, 0x000F, NES_SOUND }, { 0x27F7A, 0x001D, NES_SOUND }, + { 0x27F97, 0x0045, NES_SOUND }, { 0x27FDC, 0x000F, NES_SOUND }, { 0x2FD42, 0x001B, NES_SOUND }, { 0x2FD5D, 0x0033, NES_SOUND }, { 0x27FEB, 0x0011, NES_SOUND }, + { 0x2BFEF, 0x000F, NES_SOUND }, { 0x2FD90, 0x0075, NES_SOUND }, { 0x2FE05, 0x0014, NES_SOUND }, { 0x0FFE8, 0x000A, NES_SOUND }, { 0x2FE19, 0x00FF, NES_SOUND }, + { 0x2FF18, 0x000F, NES_SOUND }, { 0x2FF27, 0x000F, NES_SOUND }, { 0x2FF36, 0x0092, NES_SOUND }, { 0x2FF36, 0x0092, NES_SOUND }, { 0x2FFC8, 0x002D, NES_SOUND }, + { 0x316FC, 0x00F8, NES_SOUND }, { 0x317F4, 0x0016, NES_SOUND }, { 0x3180A, 0x0011, NES_SOUND }, { 0x3181B, 0x004B, NES_SOUND }, { 0x31866, 0x0011, NES_SOUND }, + { 0x31877, 0x003B, NES_SOUND }, { 0x318B2, 0x008A, NES_SOUND }, { 0x3193C, 0x0011, NES_SOUND }, { 0x3194D, 0x000F, NES_SOUND }, { 0x3195C, 0x00A2, NES_SOUND }, + { 0x319FE, 0x00D3, NES_SOUND }, { 0x31AD1, 0x0097, NES_SOUND }, { 0x2BFEF, 0x000F, NES_SOUND }, { 0x3195C, 0x00A2, NES_SOUND }, { 0x31B68, 0x05D1, NES_SOUND }, + { 0x31B68, 0x05D1, NES_SOUND }, { 0x32139, 0x0011, NES_SOUND }, { 0x0FFE8, 0x000A, NES_SOUND }, { 0x2FD90, 0x0075, NES_SOUND }, { 0x27ED4, 0x001F, NES_SOUND }, + { 0x3214A, 0x098E, NES_SOUND }, { 0x3181B, 0x004B, NES_SOUND }, { 0x32AD8, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x32AE9, 0x000F, NES_SOUND }, + { 0x32AF8, 0x002F, NES_SOUND }, { 0x32B27, 0x001D, NES_SOUND }, { 0x32B44, 0x0018, NES_SOUND }, { 0x32B5C, 0x0016, NES_SOUND }, { 0x32B72, 0x001B, NES_SOUND }, + { 0x32B8D, 0x0088, NES_SOUND }, { 0x32C15, 0x0065, NES_SOUND }, { 0x32C7A, 0x0065, NES_SOUND }, { 0x32CDF, 0x0073, NES_SOUND }, { 0x32D52, 0x00F9, NES_SOUND }, + { 0x32E4B, 0x049E, NES_SOUND }, { 0x34001, 0x0EA8, NES_SOUND }, { 0x332E9, 0x0B18, NES_SOUND }, { 0x34EA9, 0x0B9C, NES_SOUND }, { 0x35A45, 0x0C6B, NES_SOUND }, + { 0x366B0, 0x0E56, NES_SOUND }, { 0x38001, 0x0C70, NES_SOUND }, { 0x38C71, 0x0DEC, NES_SOUND }, { 0x39A5D, 0x0B77, NES_SOUND }, { 0x37506, 0x042F, NES_SOUND }, + { 0x3A5D4, 0x0AC5, NES_SOUND }, { 0x3B099, 0x0BE4, NES_SOUND } +}; +static const ScummNESFile::Resource res_sounds_eur[82] = { + { 0x0BF54, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, + { 0x30ECA, 0x0832, NES_SOUND }, { 0x0BF5E, 0x0011, NES_SOUND }, { 0x27ECB, 0x0073, NES_SOUND }, { 0x0BF6F, 0x0011, NES_SOUND }, { 0x0FF5D, 0x0011, NES_SOUND }, + { 0x316FC, 0x0056, NES_SOUND }, { 0x13F4E, 0x001F, NES_SOUND }, { 0x0FF6E, 0x0011, NES_SOUND }, { 0x13F6D, 0x000A, NES_SOUND }, { 0x1BF47, 0x000A, NES_SOUND }, + { 0x1BF51, 0x0019, NES_SOUND }, { 0x31752, 0x004B, NES_SOUND }, { 0x1BF6A, 0x000A, NES_SOUND }, { 0x27F3E, 0x000F, NES_SOUND }, { 0x27F4D, 0x001D, NES_SOUND }, + { 0x3179D, 0x0045, NES_SOUND }, { 0x27F6A, 0x000F, NES_SOUND }, { 0x2BF40, 0x001B, NES_SOUND }, { 0x317E2, 0x0033, NES_SOUND }, { 0x2BF5B, 0x0011, NES_SOUND }, + { 0x2BF6C, 0x000F, NES_SOUND }, { 0x31815, 0x0075, NES_SOUND }, { 0x2FF6C, 0x0014, NES_SOUND }, { 0x0BF54, 0x000A, NES_SOUND }, { 0x3188A, 0x00FF, NES_SOUND }, + { 0x31989, 0x000F, NES_SOUND }, { 0x31998, 0x000F, NES_SOUND }, { 0x319A7, 0x0092, NES_SOUND }, { 0x319A7, 0x0092, NES_SOUND }, { 0x31A39, 0x002D, NES_SOUND }, + { 0x31A66, 0x00F8, NES_SOUND }, { 0x31B5E, 0x0016, NES_SOUND }, { 0x31B74, 0x0011, NES_SOUND }, { 0x31B85, 0x004B, NES_SOUND }, { 0x31BD0, 0x0011, NES_SOUND }, + { 0x31BE1, 0x003B, NES_SOUND }, { 0x31C1C, 0x008A, NES_SOUND }, { 0x31CA6, 0x0011, NES_SOUND }, { 0x31CB7, 0x000F, NES_SOUND }, { 0x31CC6, 0x00A2, NES_SOUND }, + { 0x31D68, 0x00D3, NES_SOUND }, { 0x31E3B, 0x0097, NES_SOUND }, { 0x2BF6C, 0x000F, NES_SOUND }, { 0x31CC6, 0x00A2, NES_SOUND }, { 0x31ED2, 0x05D1, NES_SOUND }, + { 0x31ED2, 0x05D1, NES_SOUND }, { 0x324A3, 0x0011, NES_SOUND }, { 0x0BF54, 0x000A, NES_SOUND }, { 0x31815, 0x0075, NES_SOUND }, { 0x13F4E, 0x001F, NES_SOUND }, + { 0x324B4, 0x098E, NES_SOUND }, { 0x31B85, 0x004B, NES_SOUND }, { 0x32E42, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x32E53, 0x000F, NES_SOUND }, + { 0x32E62, 0x002F, NES_SOUND }, { 0x32E91, 0x001D, NES_SOUND }, { 0x32EAE, 0x0018, NES_SOUND }, { 0x32EC6, 0x0016, NES_SOUND }, { 0x32EDC, 0x001B, NES_SOUND }, + { 0x32EF7, 0x0088, NES_SOUND }, { 0x32F7F, 0x0065, NES_SOUND }, { 0x32FE4, 0x0065, NES_SOUND }, { 0x33049, 0x0073, NES_SOUND }, { 0x330BC, 0x00F9, NES_SOUND }, + { 0x331B5, 0x049E, NES_SOUND }, { 0x34001, 0x0EA8, NES_SOUND }, { 0x34EA9, 0x0B18, NES_SOUND }, { 0x359C1, 0x0B9C, NES_SOUND }, { 0x3655D, 0x0C6B, NES_SOUND }, + { 0x38001, 0x0E56, NES_SOUND }, { 0x371C8, 0x0C70, NES_SOUND }, { 0x38E57, 0x0DEC, NES_SOUND }, { 0x39C43, 0x0B77, NES_SOUND }, { 0x33653, 0x042F, NES_SOUND }, + { 0x3A7BA, 0x0AC5, NES_SOUND }, { 0x3B27F, 0x0BE4, NES_SOUND } +}; +static const ScummNESFile::Resource res_sounds_swe[82] = { + { 0x0BF58, 0x000A, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, + { 0x30352, 0x0832, NES_SOUND }, { 0x0BF62, 0x0011, NES_SOUND }, { 0x27E5F, 0x0073, NES_SOUND }, { 0x17F5A, 0x0011, NES_SOUND }, { 0x17F6B, 0x0011, NES_SOUND }, + { 0x27ED2, 0x0056, NES_SOUND }, { 0x1BF55, 0x001F, NES_SOUND }, { 0x23F66, 0x0011, NES_SOUND }, { 0x0BF73, 0x000A, NES_SOUND }, { 0x1BF74, 0x000A, NES_SOUND }, + { 0x27F28, 0x0019, NES_SOUND }, { 0x2BF0A, 0x004B, NES_SOUND }, { 0x1FF71, 0x000A, NES_SOUND }, { 0x27F41, 0x000F, NES_SOUND }, { 0x27F50, 0x001D, NES_SOUND }, + { 0x2FEAA, 0x0045, NES_SOUND }, { 0x27F6D, 0x000F, NES_SOUND }, { 0x2BF55, 0x001B, NES_SOUND }, { 0x2FEEF, 0x0033, NES_SOUND }, { 0x2FF22, 0x0011, NES_SOUND }, + { 0x2BF70, 0x000F, NES_SOUND }, { 0x30B84, 0x0075, NES_SOUND }, { 0x2FF33, 0x0014, NES_SOUND }, { 0x0BF58, 0x000A, NES_SOUND }, { 0x30BF9, 0x00FF, NES_SOUND }, + { 0x2FF47, 0x000F, NES_SOUND }, { 0x2FF56, 0x000F, NES_SOUND }, { 0x30CF8, 0x0092, NES_SOUND }, { 0x30CF8, 0x0092, NES_SOUND }, { 0x30D8A, 0x002D, NES_SOUND }, + { 0x30DB7, 0x00F8, NES_SOUND }, { 0x2FF65, 0x0016, NES_SOUND }, { 0x30EAF, 0x0011, NES_SOUND }, { 0x30EC0, 0x004B, NES_SOUND }, { 0x30F0B, 0x0011, NES_SOUND }, + { 0x30F1C, 0x003B, NES_SOUND }, { 0x30F57, 0x008A, NES_SOUND }, { 0x30FE1, 0x0011, NES_SOUND }, { 0x30FF2, 0x000F, NES_SOUND }, { 0x31001, 0x00A2, NES_SOUND }, + { 0x310A3, 0x00D3, NES_SOUND }, { 0x31176, 0x0097, NES_SOUND }, { 0x2BF70, 0x000F, NES_SOUND }, { 0x31001, 0x00A2, NES_SOUND }, { 0x3120D, 0x05D1, NES_SOUND }, + { 0x3120D, 0x05D1, NES_SOUND }, { 0x317DE, 0x0011, NES_SOUND }, { 0x0BF58, 0x000A, NES_SOUND }, { 0x30B84, 0x0075, NES_SOUND }, { 0x1BF55, 0x001F, NES_SOUND }, + { 0x317EF, 0x098E, NES_SOUND }, { 0x30EC0, 0x004B, NES_SOUND }, { 0x3217D, 0x0011, NES_SOUND }, { 0x30352, 0x0832, NES_SOUND }, { 0x3218E, 0x000F, NES_SOUND }, + { 0x3219D, 0x002F, NES_SOUND }, { 0x321CC, 0x001D, NES_SOUND }, { 0x321E9, 0x0018, NES_SOUND }, { 0x32201, 0x0016, NES_SOUND }, { 0x32217, 0x001B, NES_SOUND }, + { 0x32232, 0x0088, NES_SOUND }, { 0x322BA, 0x0065, NES_SOUND }, { 0x3231F, 0x0065, NES_SOUND }, { 0x32384, 0x0073, NES_SOUND }, { 0x323F7, 0x00F9, NES_SOUND }, + { 0x324F0, 0x049E, NES_SOUND }, { 0x3298E, 0x0EA8, NES_SOUND }, { 0x34001, 0x0B18, NES_SOUND }, { 0x34B19, 0x0B9C, NES_SOUND }, { 0x356B5, 0x0C6B, NES_SOUND }, + { 0x36320, 0x0E56, NES_SOUND }, { 0x37176, 0x0C70, NES_SOUND }, { 0x38001, 0x0DEC, NES_SOUND }, { 0x38DED, 0x0B77, NES_SOUND }, { 0x33836, 0x042F, NES_SOUND }, + { 0x39964, 0x0AC5, NES_SOUND }, { 0x3A429, 0x0BE4, NES_SOUND } +}; +static const ScummNESFile::Resource res_sounds_fra[82] = { + { 0x07F74, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, + { 0x30ECA, 0x0832, NES_SOUND }, { 0x0BF6C, 0x0011, NES_SOUND }, { 0x1BEFA, 0x0073, NES_SOUND }, { 0x17F10, 0x0011, NES_SOUND }, { 0x17F21, 0x0011, NES_SOUND }, + { 0x1FED5, 0x0056, NES_SOUND }, { 0x17F32, 0x001F, NES_SOUND }, { 0x17F51, 0x0011, NES_SOUND }, { 0x0FF76, 0x000A, NES_SOUND }, { 0x17F62, 0x000A, NES_SOUND }, + { 0x1FF2B, 0x0019, NES_SOUND }, { 0x23E78, 0x004B, NES_SOUND }, { 0x17F6C, 0x000A, NES_SOUND }, { 0x1BF6D, 0x000F, NES_SOUND }, { 0x1FF44, 0x001D, NES_SOUND }, + { 0x23EC3, 0x0045, NES_SOUND }, { 0x1FF61, 0x000F, NES_SOUND }, { 0x23F08, 0x001B, NES_SOUND }, { 0x23F23, 0x0033, NES_SOUND }, { 0x23F56, 0x0011, NES_SOUND }, + { 0x1FF70, 0x000F, NES_SOUND }, { 0x27EF4, 0x0075, NES_SOUND }, { 0x23F67, 0x0014, NES_SOUND }, { 0x07F74, 0x000A, NES_SOUND }, { 0x2FB83, 0x00FF, NES_SOUND }, + { 0x27F69, 0x000F, NES_SOUND }, { 0x2BF70, 0x000F, NES_SOUND }, { 0x2FC82, 0x0092, NES_SOUND }, { 0x2FC82, 0x0092, NES_SOUND }, { 0x2FD14, 0x002D, NES_SOUND }, + { 0x2FD41, 0x00F8, NES_SOUND }, { 0x2FE39, 0x0016, NES_SOUND }, { 0x2FE4F, 0x0011, NES_SOUND }, { 0x2FE60, 0x004B, NES_SOUND }, { 0x2FEAB, 0x0011, NES_SOUND }, + { 0x2FEBC, 0x003B, NES_SOUND }, { 0x316FC, 0x008A, NES_SOUND }, { 0x2FEF7, 0x0011, NES_SOUND }, { 0x2FF08, 0x000F, NES_SOUND }, { 0x31786, 0x00A2, NES_SOUND }, + { 0x31828, 0x00D3, NES_SOUND }, { 0x318FB, 0x0097, NES_SOUND }, { 0x1FF70, 0x000F, NES_SOUND }, { 0x31786, 0x00A2, NES_SOUND }, { 0x31992, 0x05D1, NES_SOUND }, + { 0x31992, 0x05D1, NES_SOUND }, { 0x2FF17, 0x0011, NES_SOUND }, { 0x07F74, 0x000A, NES_SOUND }, { 0x27EF4, 0x0075, NES_SOUND }, { 0x17F32, 0x001F, NES_SOUND }, + { 0x31F63, 0x098E, NES_SOUND }, { 0x2FE60, 0x004B, NES_SOUND }, { 0x2FF28, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x2FF39, 0x000F, NES_SOUND }, + { 0x2FF48, 0x002F, NES_SOUND }, { 0x328F1, 0x001D, NES_SOUND }, { 0x3290E, 0x0018, NES_SOUND }, { 0x32926, 0x0016, NES_SOUND }, { 0x3293C, 0x001B, NES_SOUND }, + { 0x32957, 0x0088, NES_SOUND }, { 0x329DF, 0x0065, NES_SOUND }, { 0x32A44, 0x0065, NES_SOUND }, { 0x32AA9, 0x0073, NES_SOUND }, { 0x32B1C, 0x00F9, NES_SOUND }, + { 0x32C15, 0x049E, NES_SOUND }, { 0x330B3, 0x0EA8, NES_SOUND }, { 0x34001, 0x0B18, NES_SOUND }, { 0x34B19, 0x0B9C, NES_SOUND }, { 0x356B5, 0x0C6B, NES_SOUND }, + { 0x36320, 0x0E56, NES_SOUND }, { 0x37176, 0x0C70, NES_SOUND }, { 0x38001, 0x0DEC, NES_SOUND }, { 0x38DED, 0x0B77, NES_SOUND }, { 0x39964, 0x042F, NES_SOUND }, + { 0x39D93, 0x0AC5, NES_SOUND }, { 0x3A858, 0x0BE4, NES_SOUND } +}; +static const ScummNESFile::Resource res_sounds_ger[82] = { + { 0x0BF6D, 0x000A, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, + { 0x30ECA, 0x0832, NES_SOUND }, { 0x23F05, 0x0011, NES_SOUND }, { 0x2FA49, 0x0073, NES_SOUND }, { 0x23F16, 0x0011, NES_SOUND }, { 0x23F27, 0x0011, NES_SOUND }, + { 0x2FABC, 0x0056, NES_SOUND }, { 0x23F38, 0x001F, NES_SOUND }, { 0x23F57, 0x0011, NES_SOUND }, { 0x0FF76, 0x000A, NES_SOUND }, { 0x17F71, 0x000A, NES_SOUND }, + { 0x2BF2F, 0x0019, NES_SOUND }, { 0x2FB12, 0x004B, NES_SOUND }, { 0x23F68, 0x000A, NES_SOUND }, { 0x2BF48, 0x000F, NES_SOUND }, { 0x2BF57, 0x001D, NES_SOUND }, + { 0x2FB5D, 0x0045, NES_SOUND }, { 0x2FBA2, 0x000F, NES_SOUND }, { 0x2FBB1, 0x001B, NES_SOUND }, { 0x2FBCC, 0x0033, NES_SOUND }, { 0x2FBFF, 0x0011, NES_SOUND }, + { 0x2FC10, 0x000F, NES_SOUND }, { 0x2FC1F, 0x0075, NES_SOUND }, { 0x2FC94, 0x0014, NES_SOUND }, { 0x0BF6D, 0x000A, NES_SOUND }, { 0x2FCA8, 0x00FF, NES_SOUND }, + { 0x2FDA7, 0x000F, NES_SOUND }, { 0x2FDB6, 0x000F, NES_SOUND }, { 0x2FDC5, 0x0092, NES_SOUND }, { 0x2FDC5, 0x0092, NES_SOUND }, { 0x2FE57, 0x002D, NES_SOUND }, + { 0x2FE84, 0x00F8, NES_SOUND }, { 0x316FC, 0x0016, NES_SOUND }, { 0x31712, 0x0011, NES_SOUND }, { 0x31723, 0x004B, NES_SOUND }, { 0x3176E, 0x0011, NES_SOUND }, + { 0x3177F, 0x003B, NES_SOUND }, { 0x317BA, 0x008A, NES_SOUND }, { 0x31844, 0x0011, NES_SOUND }, { 0x31855, 0x000F, NES_SOUND }, { 0x31864, 0x00A2, NES_SOUND }, + { 0x31906, 0x00D3, NES_SOUND }, { 0x319D9, 0x0097, NES_SOUND }, { 0x2FC10, 0x000F, NES_SOUND }, { 0x31864, 0x00A2, NES_SOUND }, { 0x31A70, 0x05D1, NES_SOUND }, + { 0x31A70, 0x05D1, NES_SOUND }, { 0x32041, 0x0011, NES_SOUND }, { 0x0BF6D, 0x000A, NES_SOUND }, { 0x2FC1F, 0x0075, NES_SOUND }, { 0x23F38, 0x001F, NES_SOUND }, + { 0x32052, 0x098E, NES_SOUND }, { 0x31723, 0x004B, NES_SOUND }, { 0x329E0, 0x0011, NES_SOUND }, { 0x30ECA, 0x0832, NES_SOUND }, { 0x329F1, 0x000F, NES_SOUND }, + { 0x32A00, 0x002F, NES_SOUND }, { 0x32A2F, 0x001D, NES_SOUND }, { 0x32A4C, 0x0018, NES_SOUND }, { 0x32A64, 0x0016, NES_SOUND }, { 0x32A7A, 0x001B, NES_SOUND }, + { 0x32A95, 0x0088, NES_SOUND }, { 0x32B1D, 0x0065, NES_SOUND }, { 0x32B82, 0x0065, NES_SOUND }, { 0x32BE7, 0x0073, NES_SOUND }, { 0x32C5A, 0x00F9, NES_SOUND }, + { 0x32D53, 0x049E, NES_SOUND }, { 0x34001, 0x0EA8, NES_SOUND }, { 0x331F1, 0x0B18, NES_SOUND }, { 0x34EA9, 0x0B9C, NES_SOUND }, { 0x35A45, 0x0C6B, NES_SOUND }, + { 0x366B0, 0x0E56, NES_SOUND }, { 0x38001, 0x0C70, NES_SOUND }, { 0x38C71, 0x0DEC, NES_SOUND }, { 0x39A5D, 0x0B77, NES_SOUND }, { 0x37506, 0x042F, NES_SOUND }, + { 0x3A5D4, 0x0AC5, NES_SOUND }, { 0x3B099, 0x0BE4, NES_SOUND } +}; +static const ScummNESFile::Resource res_sounds_esp[82] = { + { 0x13F63, 0x000A, NES_SOUND }, { 0x2F671, 0x0832, NES_SOUND }, { 0x2F671, 0x0832, NES_SOUND }, { 0x2F671, 0x0832, NES_SOUND }, { 0x2F671, 0x0832, NES_SOUND }, + { 0x2F671, 0x0832, NES_SOUND }, { 0x13F6D, 0x0011, NES_SOUND }, { 0x1FEED, 0x0073, NES_SOUND }, { 0x17F6F, 0x0011, NES_SOUND }, { 0x1BF64, 0x0011, NES_SOUND }, + { 0x27F19, 0x0056, NES_SOUND }, { 0x1FF60, 0x001F, NES_SOUND }, { 0x27F6F, 0x0011, NES_SOUND }, { 0x1BF75, 0x000A, NES_SOUND }, { 0x2BE6F, 0x000A, NES_SOUND }, + { 0x2BE79, 0x0019, NES_SOUND }, { 0x2BE92, 0x004B, NES_SOUND }, { 0x2BEDD, 0x000A, NES_SOUND }, { 0x2BEE7, 0x000F, NES_SOUND }, { 0x2BEF6, 0x001D, NES_SOUND }, + { 0x2BF13, 0x0045, NES_SOUND }, { 0x2BF58, 0x000F, NES_SOUND }, { 0x2FEA3, 0x001B, NES_SOUND }, { 0x2FEBE, 0x0033, NES_SOUND }, { 0x2BF67, 0x0011, NES_SOUND }, + { 0x2FEF1, 0x000F, NES_SOUND }, { 0x2FF00, 0x0075, NES_SOUND }, { 0x30ECA, 0x0014, NES_SOUND }, { 0x13F63, 0x000A, NES_SOUND }, { 0x30EDE, 0x00FF, NES_SOUND }, + { 0x30FDD, 0x000F, NES_SOUND }, { 0x30FEC, 0x000F, NES_SOUND }, { 0x30FFB, 0x0092, NES_SOUND }, { 0x30FFB, 0x0092, NES_SOUND }, { 0x3108D, 0x002D, NES_SOUND }, + { 0x310BA, 0x00F8, NES_SOUND }, { 0x311B2, 0x0016, NES_SOUND }, { 0x311C8, 0x0011, NES_SOUND }, { 0x311D9, 0x004B, NES_SOUND }, { 0x31224, 0x0011, NES_SOUND }, + { 0x31235, 0x003B, NES_SOUND }, { 0x31270, 0x008A, NES_SOUND }, { 0x312FA, 0x0011, NES_SOUND }, { 0x3130B, 0x000F, NES_SOUND }, { 0x3131A, 0x00A2, NES_SOUND }, + { 0x313BC, 0x00D3, NES_SOUND }, { 0x3148F, 0x0097, NES_SOUND }, { 0x2FEF1, 0x000F, NES_SOUND }, { 0x3131A, 0x00A2, NES_SOUND }, { 0x31526, 0x05D1, NES_SOUND }, + { 0x31526, 0x05D1, NES_SOUND }, { 0x31AF7, 0x0011, NES_SOUND }, { 0x13F63, 0x000A, NES_SOUND }, { 0x2FF00, 0x0075, NES_SOUND }, { 0x1FF60, 0x001F, NES_SOUND }, + { 0x31B08, 0x098E, NES_SOUND }, { 0x311D9, 0x004B, NES_SOUND }, { 0x32496, 0x0011, NES_SOUND }, { 0x2F671, 0x0832, NES_SOUND }, { 0x324A7, 0x000F, NES_SOUND }, + { 0x324B6, 0x002F, NES_SOUND }, { 0x324E5, 0x001D, NES_SOUND }, { 0x32502, 0x0018, NES_SOUND }, { 0x3251A, 0x0016, NES_SOUND }, { 0x32530, 0x001B, NES_SOUND }, + { 0x3254B, 0x0088, NES_SOUND }, { 0x325D3, 0x0065, NES_SOUND }, { 0x32638, 0x0065, NES_SOUND }, { 0x3269D, 0x0073, NES_SOUND }, { 0x32710, 0x00F9, NES_SOUND }, + { 0x32809, 0x049E, NES_SOUND }, { 0x32CA7, 0x0EA8, NES_SOUND }, { 0x34001, 0x0B18, NES_SOUND }, { 0x34B19, 0x0B9C, NES_SOUND }, { 0x356B5, 0x0C6B, NES_SOUND }, + { 0x36320, 0x0E56, NES_SOUND }, { 0x37176, 0x0C70, NES_SOUND }, { 0x38001, 0x0DEC, NES_SOUND }, { 0x38DED, 0x0B77, NES_SOUND }, { 0x33B4F, 0x042F, NES_SOUND }, + { 0x39964, 0x0AC5, NES_SOUND }, { 0x3A429, 0x0BE4, NES_SOUND } +}; + +static const ScummNESFile::Resource *res_sounds[ScummNESFile::kROMsetNum] = { + res_sounds_usa, + res_sounds_eur, + res_sounds_swe, + res_sounds_fra, + res_sounds_ger, + res_sounds_esp, +}; + +static const ScummNESFile::Resource res_costumes_usa[25] = { + { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, + { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x13FAB, 0x004B, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, + { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x17F5A, 0x0036, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, + { 0x17F05, 0x0055, NES_COSTUME }, { 0x1BF87, 0x003B, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x23FA9, 0x0045, NES_COSTUME }, { 0x1FFBD, 0x0040, NES_COSTUME }, + { 0x1BFC2, 0x003C, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, { 0x17F90, 0x003A, NES_COSTUME }, { 0x17F05, 0x0055, NES_COSTUME }, { 0x13FAB, 0x004B, NES_COSTUME } +}; +static const ScummNESFile::Resource res_costumes_eur[25] = { + { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, + { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0FEA2, 0x004B, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, + { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0FEED, 0x0036, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, + { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x13F13, 0x003B, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x23F2F, 0x0045, NES_COSTUME }, { 0x1FF3E, 0x0040, NES_COSTUME }, + { 0x27E8F, 0x003C, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, { 0x0FF23, 0x003A, NES_COSTUME }, { 0x0BEFF, 0x0055, NES_COSTUME }, { 0x0FEA2, 0x004B, NES_COSTUME } +}; +static const ScummNESFile::Resource res_costumes_swe[25] = { + { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, + { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x17E9A, 0x004B, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, + { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x0FF4A, 0x0036, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, + { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x17F1F, 0x003B, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x1BE94, 0x0045, NES_COSTUME }, { 0x1BED9, 0x0040, NES_COSTUME }, + { 0x1BF19, 0x003C, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, { 0x17EE5, 0x003A, NES_COSTUME }, { 0x0FEF5, 0x0055, NES_COSTUME }, { 0x17E9A, 0x004B, NES_COSTUME } +}; +static const ScummNESFile::Resource res_costumes_fra[25] = { + { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, + { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13E77, 0x004B, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, + { 0x0BF17, 0x0055, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x07F3E, 0x0036, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, + { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13EFC, 0x003B, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13F37, 0x0045, NES_COSTUME }, { 0x17E94, 0x0040, NES_COSTUME }, + { 0x17ED4, 0x003C, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, { 0x13EC2, 0x003A, NES_COSTUME }, { 0x0BF17, 0x0055, NES_COSTUME }, { 0x13E77, 0x004B, NES_COSTUME } +}; +static const ScummNESFile::Resource res_costumes_ger[25] = { + { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, + { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17E6C, 0x004B, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, + { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x0FF40, 0x0036, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, + { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17EF1, 0x003B, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17F2C, 0x0045, NES_COSTUME }, { 0x1FEFD, 0x0040, NES_COSTUME }, + { 0x1FF3D, 0x003C, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, { 0x17EB7, 0x003A, NES_COSTUME }, { 0x0FEEB, 0x0055, NES_COSTUME }, { 0x17E6C, 0x004B, NES_COSTUME } +}; +static const ScummNESFile::Resource res_costumes_esp[25] = { + { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, + { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x13EA3, 0x004B, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, + { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x0FF46, 0x0036, NES_COSTUME }, { 0x13EEE, 0x003A, NES_COSTUME }, { 0x13EEE, 0x003A, NES_COSTUME }, + { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x13F28, 0x003B, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x17F2A, 0x0045, NES_COSTUME }, { 0x1FE71, 0x0040, NES_COSTUME }, + { 0x1FEB1, 0x003C, NES_COSTUME }, { 0x13EEE, 0x003A, NES_COSTUME }, { 0x13EEE, 0x003A, NES_COSTUME }, { 0x0FEF1, 0x0055, NES_COSTUME }, { 0x13EA3, 0x004B, NES_COSTUME } +}; + +static const ScummNESFile::Resource *res_costumes[ScummNESFile::kROMsetNum] = { + res_costumes_usa, + res_costumes_eur, + res_costumes_swe, + res_costumes_fra, + res_costumes_ger, + res_costumes_esp, +}; + +static const ScummNESFile::Resource res_globdata_usa[1] = { { 0x2CA11, 0x0307, NES_GLOBDATA } }; +static const ScummNESFile::Resource res_globdata_eur[1] = { { 0x2CA11, 0x0307, NES_GLOBDATA } }; +static const ScummNESFile::Resource res_globdata_swe[1] = { { 0x2C001, 0x0307, NES_GLOBDATA } }; +static const ScummNESFile::Resource res_globdata_fra[1] = { { 0x2C628, 0x0307, NES_GLOBDATA } }; +static const ScummNESFile::Resource res_globdata_ger[1] = { { 0x2C4EE, 0x0307, NES_GLOBDATA } }; +static const ScummNESFile::Resource res_globdata_esp[1] = { { 0x2C001, 0x0307, NES_GLOBDATA } }; + +static const ScummNESFile::Resource *res_globdata[ScummNESFile::kROMsetNum] = { + res_globdata_usa, + res_globdata_eur, + res_globdata_swe, + res_globdata_fra, + res_globdata_ger, + res_globdata_esp, +}; + +// sprite palette data +static const ScummNESFile::Resource res_sprpals_usa[2] = { { 0x0BFC1, 0x0010, NES_SPRPALS }, { 0x0BFD1, 0x0010, NES_SPRPALS } }; +static const ScummNESFile::Resource res_sprpals_eur[2] = { { 0x07F61, 0x0010, NES_SPRPALS }, { 0x0BEB2, 0x0010, NES_SPRPALS } }; +static const ScummNESFile::Resource res_sprpals_swe[2] = { { 0x07F55, 0x0010, NES_SPRPALS }, { 0x07F65, 0x0010, NES_SPRPALS } }; +static const ScummNESFile::Resource res_sprpals_fra[2] = { { 0x07ED8, 0x0010, NES_SPRPALS }, { 0x07EE8, 0x0010, NES_SPRPALS } }; +static const ScummNESFile::Resource res_sprpals_ger[2] = { { 0x07F6B, 0x0010, NES_SPRPALS }, { 0x0BF17, 0x0010, NES_SPRPALS } }; +static const ScummNESFile::Resource res_sprpals_esp[2] = { { 0x0BF15, 0x0010, NES_SPRPALS }, { 0x0BF25, 0x0010, NES_SPRPALS } }; + +static const ScummNESFile::Resource *res_sprpals[ScummNESFile::kROMsetNum] = { + res_sprpals_usa, + res_sprpals_eur, + res_sprpals_swe, + res_sprpals_fra, + res_sprpals_ger, + res_sprpals_esp, +}; + +// associates costume IDs with sprite sets (indexes into SPRLENS/SPROFFS) +static const ScummNESFile::Resource res_sprdesc_usa[2] = { { 0x0FFB7, 0x0031, NES_SPRDESC }, { 0x0BFE1, 0x0009, NES_SPRDESC } }; +static const ScummNESFile::Resource res_sprdesc_eur[2] = { { 0x0BEC2, 0x0031, NES_SPRDESC }, { 0x07F71, 0x0009, NES_SPRDESC } }; +static const ScummNESFile::Resource res_sprdesc_swe[2] = { { 0x0BF1B, 0x0031, NES_SPRDESC }, { 0x07F75, 0x0009, NES_SPRDESC } }; +static const ScummNESFile::Resource res_sprdesc_fra[2] = { { 0x07EF8, 0x0031, NES_SPRDESC }, { 0x07F29, 0x0009, NES_SPRDESC } }; +static const ScummNESFile::Resource res_sprdesc_ger[2] = { { 0x0BF27, 0x0031, NES_SPRDESC }, { 0x0BF58, 0x0009, NES_SPRDESC } }; +static const ScummNESFile::Resource res_sprdesc_esp[2] = { { 0x0BF35, 0x0031, NES_SPRDESC }, { 0x0BF66, 0x0009, NES_SPRDESC } }; + +static const ScummNESFile::Resource *res_sprdesc[ScummNESFile::kROMsetNum] = { + res_sprdesc_usa, + res_sprdesc_eur, + res_sprdesc_swe, + res_sprdesc_fra, + res_sprdesc_ger, + res_sprdesc_esp, +}; + +// number of sprites in each set (indicates length within SPRDATA) +static const ScummNESFile::Resource res_sprlens_usa[2] = { { 0x0FEA2, 0x0115, NES_SPRLENS }, { 0x07FF5, 0x0006, NES_SPRLENS } }; +static const ScummNESFile::Resource res_sprlens_eur[2] = { { 0x1BE32, 0x0115, NES_SPRLENS }, { 0x07F5B, 0x0006, NES_SPRLENS } }; +static const ScummNESFile::Resource res_sprlens_swe[2] = { { 0x13E6A, 0x0115, NES_SPRLENS }, { 0x07F4F, 0x0006, NES_SPRLENS } }; +static const ScummNESFile::Resource res_sprlens_fra[2] = { { 0x0FE61, 0x0115, NES_SPRLENS }, { 0x07ED2, 0x0006, NES_SPRLENS } }; +static const ScummNESFile::Resource res_sprlens_ger[2] = { { 0x2BE1A, 0x0115, NES_SPRLENS }, { 0x07F65, 0x0006, NES_SPRLENS } }; +static const ScummNESFile::Resource res_sprlens_esp[2] = { { 0x2EFE1, 0x0115, NES_SPRLENS }, { 0x07F7A, 0x0006, NES_SPRLENS } }; + +static const ScummNESFile::Resource *res_sprlens[ScummNESFile::kROMsetNum] = { + res_sprlens_usa, + res_sprlens_eur, + res_sprlens_swe, + res_sprlens_fra, + res_sprlens_ger, + res_sprlens_esp, +}; + +// offset of each sprite set (indexes into SPRDATA) +static const ScummNESFile::Resource res_sproffs_usa[2] = { { 0x2BDC5, 0x022A, NES_SPROFFS }, { 0x0BFEA, 0x000C, NES_SPROFFS } }; +static const ScummNESFile::Resource res_sproffs_eur[2] = { { 0x2FD42, 0x022A, NES_SPROFFS }, { 0x0BEF3, 0x000C, NES_SPROFFS } }; +static const ScummNESFile::Resource res_sproffs_swe[2] = { { 0x2BCE0, 0x022A, NES_SPROFFS }, { 0x0BF4C, 0x000C, NES_SPROFFS } }; +static const ScummNESFile::Resource res_sproffs_fra[2] = { { 0x2F959, 0x022A, NES_SPROFFS }, { 0x07F32, 0x000C, NES_SPROFFS } }; +static const ScummNESFile::Resource res_sproffs_ger[2] = { { 0x2F81F, 0x022A, NES_SPROFFS }, { 0x0BF61, 0x000C, NES_SPROFFS } }; +static const ScummNESFile::Resource res_sproffs_esp[2] = { { 0x2F447, 0x022A, NES_SPROFFS }, { 0x0BF6F, 0x000C, NES_SPROFFS } }; + +static const ScummNESFile::Resource *res_sproffs[ScummNESFile::kROMsetNum] = { + res_sproffs_usa, + res_sproffs_eur, + res_sproffs_swe, + res_sproffs_fra, + res_sproffs_ger, + res_sproffs_esp, +}; + +// sprite data sets (packed NES sprite data) +static const ScummNESFile::Resource res_sprdata_usa[2] = { { 0x2CE11, 0x2BE0, NES_SPRDATA }, { 0x07F6B, 0x008A, NES_SPRDATA } }; +static const ScummNESFile::Resource res_sprdata_eur[2] = { { 0x2CE11, 0x2BE0, NES_SPRDATA }, { 0x0BE28, 0x008A, NES_SPRDATA } }; +static const ScummNESFile::Resource res_sprdata_swe[2] = { { 0x2C401, 0x2BE0, NES_SPRDATA }, { 0x0FE6B, 0x008A, NES_SPRDATA } }; +static const ScummNESFile::Resource res_sprdata_fra[2] = { { 0x2CA28, 0x2BE0, NES_SPRDATA }, { 0x07E48, 0x008A, NES_SPRDATA } }; +static const ScummNESFile::Resource res_sprdata_ger[2] = { { 0x2C8EE, 0x2BE0, NES_SPRDATA }, { 0x0FE61, 0x008A, NES_SPRDATA } }; +static const ScummNESFile::Resource res_sprdata_esp[2] = { { 0x2C401, 0x2BE0, NES_SPRDATA }, { 0x0FE67, 0x008A, NES_SPRDATA } }; +static const ScummNESFile::Resource *res_sprdata[ScummNESFile::kROMsetNum] = { + res_sprdata_usa, + res_sprdata_eur, + res_sprdata_swe, + res_sprdata_fra, + res_sprdata_ger, + res_sprdata_esp, +}; + +static const ScummNESFile::Resource res_charset_usa[1] = { { 0x3F6EE, 0x0090, NES_CHARSET } }; +static const ScummNESFile::Resource res_charset_eur[1] = { { 0x3F724, 0x0090, NES_CHARSET } }; +static const ScummNESFile::Resource res_charset_swe[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; +static const ScummNESFile::Resource res_charset_fra[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; +static const ScummNESFile::Resource res_charset_ger[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; +static const ScummNESFile::Resource res_charset_esp[1] = { { 0x3F739, 0x0090, NES_CHARSET } }; + +static const ScummNESFile::Resource *res_charset[ScummNESFile::kROMsetNum] = { + res_charset_usa, + res_charset_eur, + res_charset_swe, + res_charset_fra, + res_charset_ger, + res_charset_esp, +}; + +static const ScummNESFile::Resource res_preplist_usa[1] = { { 0x3FB5A, 0x000E, NES_PREPLIST } }; +static const ScummNESFile::Resource res_preplist_eur[1] = { { 0x3FB90, 0x000E, NES_PREPLIST } }; +static const ScummNESFile::Resource res_preplist_swe[1] = { { 0x3FBA9, 0x000E, NES_PREPLIST } }; +static const ScummNESFile::Resource res_preplist_fra[1] = { { 0x3FBAF, 0x0010, NES_PREPLIST } }; +static const ScummNESFile::Resource res_preplist_ger[1] = { { 0x3FBAB, 0x000F, NES_PREPLIST } }; +static const ScummNESFile::Resource res_preplist_esp[1] = { { 0x3FBAE, 0x000F, NES_PREPLIST } }; + +static const ScummNESFile::Resource *res_preplist[ScummNESFile::kROMsetNum] = { + res_preplist_usa, + res_preplist_eur, + res_preplist_swe, + res_preplist_fra, + res_preplist_ger, + res_preplist_esp, +}; + +static uint16 write_byte(Common::WriteStream *out, byte val) { + val ^= 0xFF; + if (out != 0) + out->writeByte(val); + return 1; +} + +static uint16 write_word(Common::WriteStream *out, uint16 val) { + val ^= 0xFFFF; + if (out != 0) + out->writeUint16LE(val); + return 2; +} + +byte ScummNESFile::fileReadByte() { + byte b = 0; + File::read(&b, 1); + return b; +} + +uint16 ScummNESFile::fileReadUint16LE() { + uint16 a = fileReadByte(); + uint16 b = fileReadByte(); + return a | (b << 8); +} + +uint16 ScummNESFile::extractResource(Common::WriteStream *output, const Resource *res) { + uint16 len, i, j; + byte val; + byte cnt; + uint16 reslen = 0; + + if (res == NULL) + error("extract_resource - no resource specified"); + + if ((res->offset == 0) && (res->length == 0)) + return 0; /* there are 8 scripts that are zero bytes long, so we should skip them */ + + File::seek(res->offset,SEEK_SET); + + switch (res->type) { + case NES_GLOBDATA: + len = res->length; + + for (i = 0; i < len; i++) + reslen += write_byte(output, fileReadByte()); + + break; + + case NES_ROOMGFX: + case NES_COSTUMEGFX: + reslen += write_word(output, (uint16)(res->length + 2)); + len = fileReadByte(); + reslen += write_byte(output, (byte)len); + + if (!len) + len = 256; + len = len << 4; + + for (i = 0; i < len;) { + reslen += write_byte(output, cnt = fileReadByte()); + for (j = 0; j < (cnt & 0x7F); j++, i++) + if ((cnt & 0x80) || (j == 0)) + reslen += write_byte(output, fileReadByte()); + } + + if (File::pos() - res->offset != res->length) + error("extract_resource - length mismatch while extracting graphics resource (was %04X, should be %04X)", File::pos() - res->offset, res->length); + + break; + + case NES_ROOM: + case NES_SCRIPT: + len = fileReadUint16LE(); + + if (len != res->length) + error("extract_resource - length mismatch while extracting room/script resource (was %04X, should be %04X)", len, res->length); + + File::seek(-2, SEEK_CUR); + + for (i = 0; i < len; i++) + reslen += write_byte(output, fileReadByte()); + + break; + + case NES_SOUND: + len = res->length + 2; + val = fileReadByte(); + cnt = fileReadByte(); + + if ((val == 2) && (cnt == 100)) { + reslen += write_word(output, len); + reslen += write_byte(output, val); + reslen += write_byte(output, cnt); + + cnt = fileReadByte(); + reslen += write_byte(output, cnt); + for (i = 0; i < cnt; i++) + reslen += write_byte(output, fileReadByte()); + for (i = 0; i < cnt; i++) + reslen += write_byte(output, fileReadByte()); + + while (1) { + reslen += write_byte(output, val = fileReadByte()); + if (val >= 0xFE) + break; + } + } else if (((val == 0) || (val == 1) || (val == 4)) && (cnt == 10)) { + reslen += write_word(output, len); + reslen += write_byte(output, val); + reslen += write_byte(output, cnt); + while (1) { + reslen += write_byte(output, val = fileReadByte()); + + if (val >= 0xFE) + break; + + if (val >= 0x10) + reslen += write_byte(output, fileReadByte()); + else { + reslen += write_byte(output, fileReadByte()); + reslen += write_byte(output, fileReadByte()); + reslen += write_byte(output, fileReadByte()); + reslen += write_byte(output, fileReadByte()); + } + } + } else + error("extract_resource - unknown sound type %d/%d detected",val,cnt); + + if (File::pos() - res->offset != res->length) + error("extract_resource - length mismatch while extracting sound resource (was %04X, should be %04X)", File::pos() - res->offset, res->length); + + break; + + case NES_COSTUME: + case NES_SPRPALS: + case NES_SPRDESC: + case NES_SPRLENS: + case NES_SPROFFS: + case NES_SPRDATA: + case NES_CHARSET: + len = res->length; + reslen += write_word(output, (uint16)(len + 2)); + + for (i = 0; i < len; i++) + reslen += write_byte(output, fileReadByte()); + + break; + + case NES_PREPLIST: + len = res->length; + reslen += write_word(output, 0x002A); + + reslen += write_byte(output, ' '); + for (i = 1; i < 8; i++) + reslen += write_byte(output, 0); + + for (j = 0; j < 4; j++) { + reslen += write_byte(output,' '); + for (i = 1; (val = fileReadByte()); i++) + reslen += write_byte(output, val); + for (; i < 8; i++) + reslen += write_byte(output, 0); + } + break; + + default: + error("extract_resource - unknown resource type %d specified!", res->type); + } + + return reslen; +} + +struct ScummNESFile::LFLEntry { + const Resource **type; + int index; +}; + +// based on structure of Classic PC Maniac Mansion LFL files +// (roomgfx resources are arranged in order, one per file, +// after the room blocks) +static const ScummNESFile::LFLEntry lfl_01[] = { {res_rooms, 1}, {res_roomgfx, 1}, {res_scripts, 57}, {res_scripts, 61}, {res_scripts, 76}, {res_scripts, 105}, {res_scripts, 111}, {res_sounds, 5}, {res_scripts, 132}, {res_scripts, 148}, {res_scripts, 155}, {res_scripts, 156}, {res_sounds, 39}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_02[] = { {res_rooms, 2}, {res_roomgfx, 2}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_03[] = { {res_rooms, 3}, {res_roomgfx, 3}, {res_scripts, 21}, {res_sounds, 26}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_04[] = { {res_rooms, 4}, {res_roomgfx, 4}, {res_scripts, 46}, {res_scripts, 56}, {res_scripts, 137}, {res_scripts, 146}, {res_sounds, 12}, {res_sounds, 11}, {res_sounds, 13}, {res_sounds, 42}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_05[] = { {res_rooms, 5}, {res_roomgfx, 5}, {res_scripts, 30}, {res_scripts, 31}, {res_scripts, 32}, {res_scripts, 33}, {res_scripts, 34}, {res_scripts, 35}, {res_sounds, 22}, {res_sounds, 23}, {res_sounds, 24}, {res_sounds, 21}, {res_sounds, 46}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_06[] = { {res_rooms, 6}, {res_roomgfx, 6}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_07[] = { {res_rooms, 7}, {res_roomgfx, 7}, {res_scripts, 17}, {res_scripts, 58}, {res_scripts, 59}, {res_scripts, 60}, {res_scripts, 74}, {res_scripts, 81}, {res_scripts, 82}, {res_scripts, 150}, {res_sounds, 14}, {res_sounds, 15}, {res_sounds, 16}, {res_sounds, 17}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_08[] = { {res_rooms, 8}, {res_roomgfx, 8}, {res_scripts, 7}, {res_scripts, 12}, {res_scripts, 13}, {res_scripts, 47}, {res_scripts, 48}, {res_scripts, 49}, {res_scripts, 154}, {res_sounds, 32}, {res_sounds, 33}, {res_sounds, 36}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_09[] = { {res_rooms, 9}, {res_roomgfx, 9}, {res_scripts, 10}, {res_scripts, 11}, {res_scripts, 45}, {res_scripts, 55}, {res_scripts, 84}, {res_scripts, 85}, {res_scripts, 86}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_10[] = { {res_rooms, 10}, {res_roomgfx, 10}, {res_scripts, 24}, {res_scripts, 149}, {res_sounds, 28}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_11[] = { {res_rooms, 11}, {res_roomgfx, 11}, {res_scripts, 166}, {res_scripts, 167}, {res_scripts, 168}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_12[] = { {res_rooms, 12}, {res_roomgfx, 12}, {res_scripts, 51}, {res_scripts, 103}, {res_scripts, 104}, {res_scripts, 161}, {res_sounds, 63}, {res_costumes, 14}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_13[] = { {res_rooms, 13}, {res_roomgfx, 13}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_14[] = { {res_rooms, 14}, {res_roomgfx, 14}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_15[] = { {res_rooms, 15}, {res_roomgfx, 15}, {res_sounds, 27}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_16[] = { {res_rooms, 16}, {res_roomgfx, 16}, {res_scripts, 14}, {res_scripts, 121}, {res_scripts, 122}, {res_sounds, 40}, {res_sounds, 64}, {res_sounds, 68}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_17[] = { {res_rooms, 17}, {res_roomgfx, 17}, {res_scripts, 20}, {res_scripts, 100}, {res_sounds, 25}, {res_sounds, 44}, {res_sounds, 2}, {res_sounds, 50}, {res_sounds, 52}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_18[] = { {res_rooms, 18}, {res_roomgfx, 18}, {res_scripts, 25}, {res_scripts, 26}, {res_scripts, 27}, {res_scripts, 28}, {res_scripts, 64}, {res_scripts, 65}, {res_scripts, 66}, {res_scripts, 67}, {res_scripts, 68}, {res_scripts, 69}, {res_scripts, 70}, {res_scripts, 71}, {res_scripts, 73}, {res_scripts, 101}, {res_sounds, 35}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_19[] = { {res_rooms, 19}, {res_roomgfx, 19}, {res_scripts, 36}, {res_scripts, 37}, {res_scripts, 38}, {res_scripts, 39}, {res_scripts, 40}, {res_scripts, 152}, {res_scripts, 153}, {res_costumes, 10}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_20[] = { {res_rooms, 20}, {res_roomgfx, 20}, {res_scripts, 107}, {res_scripts, 108}, {res_scripts, 109}, {res_scripts, 110}, {res_scripts, 159}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_21[] = { {res_rooms, 21}, {res_roomgfx, 21}, {res_scripts, 41}, {res_scripts, 42}, {res_scripts, 43}, {res_scripts, 53}, {res_scripts, 136}, {res_sounds, 29}, {res_sounds, 20}, {res_sounds, 37}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_22[] = { {res_rooms, 22}, {res_roomgfx, 22}, {res_scripts, 15}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_23[] = { {res_rooms, 23}, {res_roomgfx, 23}, {res_scripts, 77}, {res_scripts, 79}, {res_scripts, 80}, {res_scripts, 83}, {res_sounds, 41}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_24[] = { {res_rooms, 24}, {res_roomgfx, 24}, {res_scripts, 18}, {res_scripts, 19}, {res_scripts, 78}, {res_sounds, 7}, {res_sounds, 3}, {res_sounds, 18}, {res_sounds, 34}, {res_costumes, 12}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_25[] = { {res_rooms, 25}, {res_roomgfx, 25}, {res_scripts, 29}, {res_sounds, 30}, {res_sounds, 31}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_26[] = { {res_rooms, 26}, {res_roomgfx, 26}, {res_scripts, 87}, {res_scripts, 88}, {res_scripts, 89}, {res_scripts, 90}, {res_scripts, 91}, {res_scripts, 92}, {res_scripts, 93}, {res_scripts, 94}, {res_scripts, 95}, {res_scripts, 96}, {res_scripts, 97}, {res_scripts, 98}, {res_scripts, 116}, {res_scripts, 151}, {res_scripts, 174}, {res_costumes, 11}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_27[] = { {res_rooms, 27}, {res_roomgfx, 27}, {res_scripts, 16}, {res_scripts, 52}, {res_scripts, 54}, {res_scripts, 113}, {res_sounds, 45}, {res_costumes, 19}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_28[] = { {res_rooms, 28}, {res_roomgfx, 28}, {res_scripts, 22}, {res_scripts, 23}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_29[] = { {res_rooms, 29}, {res_roomgfx, 29}, {res_scripts, 75}, {res_sounds, 43}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_30[] = { {res_rooms, 30}, {res_roomgfx, 30}, {res_scripts, 63}, {res_sounds, 0}, {res_scripts, 123}, {res_scripts, 125}, {res_scripts, 126}, {res_scripts, 127}, {res_scripts, 129}, {res_sounds, 55}, {res_sounds, 59}, {res_sounds, 60}, {res_costumes, 8}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_31[] = { {res_rooms, 31}, {res_roomgfx, 31}, {res_scripts, 99}, {res_scripts, 115}, {res_scripts, 117}, {res_scripts, 119}, {res_scripts, 147}, {res_scripts, 157}, {res_scripts, 158}, {res_scripts, 160}, {res_costumes, 13}, {res_costumes, 9}, {res_costumes, 23}, {res_costumes, 24}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_32[] = { {res_rooms, 32}, {res_roomgfx, 32}, {res_costumes, 15}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_33[] = { {res_rooms, 33}, {res_roomgfx, 33}, {res_scripts, 120}, {res_scripts, 135}, {res_sounds, 56}, {res_sounds, 57}, {res_sounds, 58}, {res_sounds, 1}, {res_costumes, 22}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_34[] = { {res_rooms, 34}, {res_roomgfx, 34}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_35[] = { {res_rooms, 35}, {res_roomgfx, 35}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_36[] = { {res_rooms, 36}, {res_roomgfx, 36}, {res_sounds, 10}, {res_sounds, 4}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_37[] = { {res_rooms, 37}, {res_roomgfx, 37}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_38[] = { {res_rooms, 38}, {res_roomgfx, 38}, {res_scripts, 138}, {res_scripts, 139}, {res_scripts, 140}, {res_scripts, 141}, {res_scripts, 142}, {res_scripts, 143}, {res_scripts, 144}, {res_scripts, 145}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_39[] = { {res_rooms, 39}, {res_roomgfx, 39}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_40[] = { {res_rooms, 40}, {res_roomgfx, 0}, {res_scripts, 112}, {res_costumes, 17}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_41[] = { {res_rooms, 41}, {res_scripts, 106}, {res_sounds, 47}, {res_sounds, 48}, {res_sounds, 53}, {res_sounds, 49}, {res_sounds, 51}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_42[] = { {res_rooms, 42}, {res_scripts, 124}, {res_costumes, 18}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_43[] = { {res_rooms, 43}, {res_scripts, 44}, {res_sounds, 19}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_44[] = { {res_rooms, 44}, {res_scripts, 102}, {res_sounds, 6}, {res_sounds, 38}, {res_sounds, 8}, {res_sounds, 9}, {res_costumes, 1}, {res_costumes, 2}, {res_costumes, 5}, {res_costumes, 6}, {res_costumes, 3}, {res_costumes, 4}, {res_costumes, 7}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_45[] = { {res_rooms, 45}, {res_scripts, 1}, {res_scripts, 2}, {res_scripts, 3}, {res_scripts, 4}, {res_scripts, 5}, {res_scripts, 9}, {res_scripts, 114}, {res_scripts, 131}, {res_scripts, 164}, {res_scripts, 165}, {res_scripts, 169}, {res_scripts, 170}, {res_scripts, 171}, {res_scripts, 172}, {res_scripts, 173}, {res_scripts, 175}, {res_sounds, 54}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_46[] = { {res_rooms, 46}, {res_scripts, 130}, {res_sounds, 65}, {res_costumes, 0}, {res_costumes, 21}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_47[] = { {res_rooms, 47}, {res_scripts, 62}, {res_sounds, 69}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_48[] = { {res_rooms, 48}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_49[] = { {res_rooms, 49}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_50[] = { {res_rooms, 50}, {res_scripts, 133}, {res_scripts, 163}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_51[] = { {res_rooms, 51}, {res_scripts, 118}, {res_scripts, 128}, {res_sounds, 61}, {res_sounds, 62}, {res_sounds, 67}, {res_sounds, 66}, {res_costumes, 16}, {res_costumes, 20}, {NULL, 0} }; +static const ScummNESFile::LFLEntry lfl_52[] = { {res_rooms, 52}, {NULL, 0} }; +// remaining 'standard' resources (not used by any of the original LFL files) +static const ScummNESFile::LFLEntry lfl_53[] = { {res_rooms, 53}, {res_scripts, 177}, {res_scripts, 178}, {res_sounds, 70}, {res_sounds, 71}, {res_sounds, 72}, {res_sounds, 73}, {res_sounds, 74}, {res_sounds, 75}, {res_sounds, 76}, {res_sounds, 77}, {res_sounds, 78}, {res_sounds, 79}, {res_sounds, 80}, {res_sounds, 81}, {NULL, 0} }; +// all 'non-standard' resources (the costume-related stuff) +static const ScummNESFile::LFLEntry lfl_54[] = { {res_rooms, 54}, {res_sprdesc, 0}, {res_sprdesc, 1}, {res_sprlens, 0}, {res_sprlens, 1}, {res_sproffs, 0}, {res_sproffs, 1}, {res_sprdata, 0}, {res_sprdata, 1}, {res_costumegfx, 0}, {res_costumegfx, 1}, {res_sprpals, 0}, {res_sprpals, 1}, {res_charset, 0}, {res_preplist, 0}, {NULL, 0} }; + +struct ScummNESFile::LFL { + int num; + const ScummNESFile::LFLEntry *entries; +}; + +static const ScummNESFile::LFL lfls[] = { + { 1, lfl_01 }, + { 2, lfl_02 }, + { 3, lfl_03 }, + { 4, lfl_04 }, + { 5, lfl_05 }, + { 6, lfl_06 }, + { 7, lfl_07 }, + { 8, lfl_08 }, + { 9, lfl_09 }, + { 10, lfl_10 }, + { 11, lfl_11 }, + { 12, lfl_12 }, + { 13, lfl_13 }, + { 14, lfl_14 }, + { 15, lfl_15 }, + { 16, lfl_16 }, + { 17, lfl_17 }, + { 18, lfl_18 }, + { 19, lfl_19 }, + { 20, lfl_20 }, + { 21, lfl_21 }, + { 22, lfl_22 }, + { 23, lfl_23 }, + { 24, lfl_24 }, + { 25, lfl_25 }, + { 26, lfl_26 }, + { 27, lfl_27 }, + { 28, lfl_28 }, + { 29, lfl_29 }, + { 30, lfl_30 }, + { 31, lfl_31 }, + { 32, lfl_32 }, + { 33, lfl_33 }, + { 34, lfl_34 }, + { 35, lfl_35 }, + { 36, lfl_36 }, + { 37, lfl_37 }, + { 38, lfl_38 }, + { 39, lfl_39 }, + { 40, lfl_40 }, + { 41, lfl_41 }, + { 42, lfl_42 }, + { 43, lfl_43 }, + { 44, lfl_44 }, + { 45, lfl_45 }, + { 46, lfl_46 }, + { 47, lfl_47 }, + { 48, lfl_48 }, + { 49, lfl_49 }, + { 50, lfl_50 }, + { 51, lfl_51 }, + { 52, lfl_52 }, + { 53, lfl_53 }, + { 54, lfl_54 }, + { -1, NULL } +}; + +#include "common/pack-start.h" // START STRUCT PACKING + +struct _lfl_index { + byte room_lfl[55]; + uint16 room_addr[55]; + byte costume_lfl[80]; + uint16 costume_addr[80]; + byte script_lfl[200]; + uint16 script_addr[200]; + byte sound_lfl[100]; + uint16 sound_addr[100]; +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + +_lfl_index lfl_index; + +bool ScummNESFile::generateResource(int res) { + const LFL *lfl = &lfls[res - 1]; + int j; + int bufsize = 2; + + for (j = 0; lfl->entries[j].type != NULL; j++) + bufsize += extractResource(0, &lfl->entries[j].type[_ROMset][lfl->entries[j].index]); + + free(_buf); + _buf = (byte *)calloc(1, bufsize); + + Common::MemoryWriteStream out(_buf, bufsize); + + for (j = 0; lfl->entries[j].type != NULL; j++) { + const Resource *entry = &lfl->entries[j].type[_ROMset][lfl->entries[j].index]; + extractResource(&out, entry); + } + write_byte(&out, 0xD1); + write_byte(&out, 0xF5); + + if (_stream) + delete _stream; + + _stream = new Common::MemoryReadStream(_buf, bufsize); + + return true; +} + +bool ScummNESFile::generateIndex() { + int i, j; + + for (i = 0; lfls[i].num != -1; i++) { + const LFL *lfl = &lfls[i]; + uint16 respos = 0; + + for (j = 0; lfl->entries[j].type != NULL; j++) { + const LFLEntry *entry = &lfl->entries[j]; + + switch (entry->type[_ROMset][entry->index].type) { + case NES_ROOM: + lfl_index.room_lfl[entry->index] = lfl->num; + lfl_index.room_addr[entry->index] = TO_LE_16(respos); + break; + case NES_COSTUME: + lfl_index.costume_lfl[entry->index] = lfl->num; + lfl_index.costume_addr[entry->index] = TO_LE_16(respos); + break; + case NES_SPRDESC: + lfl_index.costume_lfl[entry->index + 25] = lfl->num; + lfl_index.costume_addr[entry->index + 25] = TO_LE_16(respos); + break; + case NES_SPRLENS: + lfl_index.costume_lfl[entry->index + 27] = lfl->num; + lfl_index.costume_addr[entry->index + 27] = TO_LE_16(respos); + break; + case NES_SPROFFS: + lfl_index.costume_lfl[entry->index + 29] = lfl->num; + lfl_index.costume_addr[entry->index + 29] = TO_LE_16(respos); + break; + case NES_SPRDATA: + lfl_index.costume_lfl[entry->index + 31] = lfl->num; + lfl_index.costume_addr[entry->index + 31] = TO_LE_16(respos); + break; + case NES_COSTUMEGFX: + lfl_index.costume_lfl[entry->index + 33] = lfl->num; + lfl_index.costume_addr[entry->index + 33] = TO_LE_16(respos); + break; + case NES_SPRPALS: + lfl_index.costume_lfl[entry->index + 35] = lfl->num; + lfl_index.costume_addr[entry->index + 35] = TO_LE_16(respos); + break; + case NES_ROOMGFX: + lfl_index.costume_lfl[entry->index + 37] = lfl->num; + lfl_index.costume_addr[entry->index + 37] = TO_LE_16(respos); + break; + case NES_SCRIPT: + lfl_index.script_lfl[entry->index] = lfl->num; + lfl_index.script_addr[entry->index] = TO_LE_16(respos); + break; + case NES_SOUND: + lfl_index.sound_lfl[entry->index] = lfl->num; + lfl_index.sound_addr[entry->index] = TO_LE_16(respos); + break; + case NES_CHARSET: + lfl_index.costume_lfl[77] = lfl->num; + lfl_index.costume_addr[77] = TO_LE_16(respos); + break; + case NES_PREPLIST: + lfl_index.costume_lfl[78] = lfl->num; + lfl_index.costume_addr[78] = TO_LE_16(respos); + break; + default: + error("Unindexed entry found!"); + break; + } + respos += extractResource(0, &entry->type[_ROMset][entry->index]); + } + } + + int bufsize = 2; + + bufsize += 775; + bufsize += sizeof(lfl_index); + + free(_buf); + _buf = (byte *)calloc(1, bufsize); + + Common::MemoryWriteStream out(_buf, bufsize); + + write_byte(&out, 0x43); + write_byte(&out, 0x46); + + extractResource(&out, &res_globdata[_ROMset][0]); + + for (i = 0; i < (int)sizeof(lfl_index); i++) + write_byte(&out, ((byte *)&lfl_index)[i]); + + if (_stream) + delete _stream; + + _stream = new Common::MemoryReadStream(_buf, bufsize); + + return true; +} + +bool ScummNESFile::open(const Common::String &filename, AccessMode mode) { + + if (_ROMset == kROMsetNum) { + char md5str[32+1]; + if (Common::md5_file_string(filename.c_str(), md5str)) { + + if (!strcmp(md5str, "3905799e081b80a61d4460b7b733c206")) { + _ROMset = kROMsetUSA; + debug(1, "ROM contents verified as Maniac Mansion (USA)"); + } else if (!strcmp(md5str, "d8d07efcb88f396bee0b402b10c3b1c9")) { + _ROMset = kROMsetEurope; + debug(1, "ROM contents verified as Maniac Mansion (Europe)"); + } else if (!strcmp(md5str, "22d07d6c386c9c25aca5dac2a0c0d94b")) { + _ROMset = kROMsetSweden; + debug(1, "ROM contents verified as Maniac Mansion (Sweden)"); + } else if (!strcmp(md5str, "81bbfa181184cb494e7a81dcfa94fbd9")) { + _ROMset = kROMsetFrance; + debug(2, "ROM contents verified as Maniac Mansion (France)"); + } else if (!strcmp(md5str, "257f8c14d8c584f7ddd601bcb00920c7")) { + _ROMset = kROMsetGermany; + debug(2, "ROM contents verified as Maniac Mansion (Germany)"); + } else if (!strcmp(md5str, "f163cf53f7850e43fb482471e5c52e1a")) { + _ROMset = kROMsetSpain; + debug(2, "ROM contents verified as Maniac Mansion (Spain)"); + } else { + error("Unsupported Maniac Mansion ROM, md5: %s", md5str); + return false; + } + } else { + return false; + } + } + + if (File::open(filename, mode)) { + if (_stream) + delete _stream; + _stream = 0; + + free(_buf); + _buf = 0; + + return true; + } else { + return false; + } +} + +void ScummNESFile::close() { + if (_stream) + delete _stream; + _stream = 0; + + free(_buf); + _buf = 0; + + File::close(); +} + +bool ScummNESFile::openSubFile(const Common::String &filename) { + assert(isOpen()); + + const char *ext = strrchr(filename.c_str(), '.'); + char resNum[3]; + int res; + + // We always have file name in form of XX.lfl + resNum[0] = ext[-2]; + resNum[1] = ext[-1]; + resNum[2] = 0; + + res = atoi(resNum); + + if (res == 0) { + return generateIndex(); + } else { + return generateResource(res); + } +} + + +} // End of namespace Scumm diff --git a/engines/scumm/file_nes.h b/engines/scumm/file_nes.h new file mode 100644 index 0000000000..d601c2c496 --- /dev/null +++ b/engines/scumm/file_nes.h @@ -0,0 +1,81 @@ +/* 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 SCUMM_FILE_NES_H +#define SCUMM_FILE_NES_H + +#include "common/file.h" + +#include "scumm/file.h" + +namespace Scumm { + +class ScummNESFile : public BaseScummFile { +public: + enum ROMset { + kROMsetUSA, + kROMsetEurope, + kROMsetSweden, + kROMsetFrance, + kROMsetGermany, + kROMsetSpain, + kROMsetNum + }; + + struct Resource; + struct LFLEntry; + struct LFL; + +private: + Common::MemoryReadStream *_stream; + ROMset _ROMset; + byte *_buf; + + bool generateIndex(); + bool generateResource(int res); + uint16 extractResource(Common::WriteStream *out, const Resource *res); + + byte fileReadByte(); + uint16 fileReadUint16LE(); + +public: + ScummNESFile(); + void setEnc(byte value); + + bool open(const Common::String &filename, AccessMode mode = kFileReadMode); + bool openSubFile(const Common::String &filename); + + void close(); + bool eof() { return _stream->eos(); } + uint32 pos() { return _stream->pos(); } + uint32 size() { return _stream->size(); } + void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); } + uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } + uint32 write(const void *dataPtr, uint32 dataSize); +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index c1e06609b9..8d111492a2 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -51,6 +51,7 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height); static void clear8Col(byte *dst, int dstPitch, int height); static void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height); +static void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); struct StripTable { int offsets[160]; @@ -90,9 +91,6 @@ struct TransitionEffect { byte stripTable[16]; // ditto }; -#ifdef PALMOS_68K -static const TransitionEffect *transitionEffects; -#else static const TransitionEffect transitionEffects[6] = { // Iris effect (looks like an opening/closing camera iris) { @@ -197,7 +195,6 @@ static const TransitionEffect transitionEffects[6] = { } }; -#endif Gdi::Gdi(ScummEngine *vm) : _vm(vm) { @@ -322,7 +319,7 @@ void ScummEngine::initScreens(int b, int h) { void ScummEngine::initVirtScreen(VirtScreenNumber slot, int top, int width, int height, bool twobufs, bool scrollable) { - VirtScreen *vs = &virtscr[slot]; + VirtScreen *vs = &_virtscr[slot]; int size; assert(height >= 0); @@ -378,7 +375,7 @@ void ScummEngine::initVirtScreen(VirtScreenNumber slot, int top, int width, int } VirtScreen *ScummEngine::findVirtScreen(int y) { - VirtScreen *vs = virtscr; + VirtScreen *vs = _virtscr; int i; for (i = 0; i < 3; i++, vs++) { @@ -390,7 +387,7 @@ VirtScreen *ScummEngine::findVirtScreen(int y) { } void ScummEngine::markRectAsDirty(VirtScreenNumber virt, int left, int right, int top, int bottom, int dirtybit) { - VirtScreen *vs = &virtscr[virt]; + VirtScreen *vs = &_virtscr[virt]; int lp, rp; if (left > right || top > bottom) @@ -456,7 +453,7 @@ void ScummEngine::drawDirtyScreenParts() { // Update game area ("stage") if (camera._last.x != camera._cur.x || (_game.version >= 7 && (camera._cur.y != camera._last.y))) { // Camera moved: redraw everything - VirtScreen *vs = &virtscr[kMainVirtScreen]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; drawStripToScreen(vs, 0, vs->w, 0, vs->h); vs->setDirtyRange(vs->h, 0); } else { @@ -501,7 +498,7 @@ void ScummEngine_v6::drawDirtyScreenParts() { * a full blit is done, otherwise only the visible dirty areas are updated. */ void ScummEngine::updateDirtyScreen(VirtScreenNumber slot) { - VirtScreen *vs = &virtscr[slot]; + VirtScreen *vs = &_virtscr[slot]; // Do nothing for unused virtual screens if (vs->h == 0) @@ -745,7 +742,7 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid *height = dsty - *y; } -void ScummEngine::scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { +void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h) { byte *dstL1 = dst; byte *dstL2 = dst + dstPitch; @@ -779,7 +776,7 @@ void ScummEngine::initBGBuffers(int height) { // Resize main virtual screen in V7 games. This is necessary // because in V7, rooms may be higher than one screen, so we have // to accomodate for that. - initVirtScreen(kMainVirtScreen, virtscr[0].topline, _screenWidth, height, true, true); + initVirtScreen(kMainVirtScreen, _virtscr[kMainVirtScreen].topline, _screenWidth, height, true, true); } if (_game.heversion >= 70) @@ -903,7 +900,7 @@ void ScummEngine_v71he::redrawBGAreas() { byte *room = getResourceAddress(rtRoomImage, _roomResource) + _IM00_offs; if (_fullRedraw) { _bgNeedsRedraw = false; - _gdi->drawBMAPBg(room, &virtscr[0]); + _gdi->drawBMAPBg(room, &_virtscr[kMainVirtScreen]); } drawRoomObjects(0); @@ -929,7 +926,7 @@ void ScummEngine::redrawBGStrip(int start, int num) { else room = getResourceAddress(rtRoom, _roomResource); - _gdi->drawBitmap(room + _IM00_offs, &virtscr[0], s, 0, _roomWidth, virtscr[0].h, s, num, 0); + _gdi->drawBitmap(room + _IM00_offs, &_virtscr[kMainVirtScreen], s, 0, _roomWidth, _virtscr[kMainVirtScreen].h, s, num, 0); } void ScummEngine::restoreBackground(Common::Rect rect, byte backColor) { @@ -987,7 +984,7 @@ void ScummEngine::restoreCharsetBg() { // restoreBackground(), but was changed to only restore those parts which are // currently covered by the charset mask. - VirtScreen *vs = &virtscr[_charset->_textScreenID]; + VirtScreen *vs = &_virtscr[_charset->_textScreenID]; if (!vs->h) return; @@ -1022,7 +1019,7 @@ void ScummEngine::clearTextSurface() { } byte *ScummEngine::getMaskBuffer(int x, int y, int z) { - return _gdi->getMaskBuffer((x + virtscr[0].xstart) / 8, y, z); + return _gdi->getMaskBuffer((x + _virtscr[kMainVirtScreen].xstart) / 8, y, z); } byte *Gdi::getMaskBuffer(int x, int y, int z) { @@ -1223,7 +1220,7 @@ void ScummEngine_v5::clearFlashlight() { void ScummEngine_v5::drawFlashlight() { int i, j, x, y; - VirtScreen *vs = &virtscr[kMainVirtScreen]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; // Remove the flash light first if it was previously drawn if (_flashlight.isDrawn) { @@ -1923,7 +1920,7 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, if (code == 8 || code == 9) { Common::Rect rScreen(0, 0, vs->w, vs->h); - byte *dst = (byte *)_vm->virtscr[0].backBuf + scrX; + byte *dst = (byte *)_vm->_virtscr[kMainVirtScreen].backBuf + scrX; Wiz::copyWizImage(dst, bmap_ptr, vs->w, vs->h, x - scrX, y, w, h, &rScreen); } @@ -1943,7 +1940,7 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, void ScummEngine_v70he::restoreBackgroundHE(Common::Rect rect, int dirtybit) { byte *src, *dst; - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; if (rect.top > vs->h || rect.bottom < 0) return; @@ -1969,12 +1966,12 @@ void ScummEngine_v70he::restoreBackgroundHE(Common::Rect rect, int dirtybit) { if (rw == 0 || rh == 0) return; - src = virtscr[0].getBackPixels(rect.left, rect.top); - dst = virtscr[0].getPixels(rect.left, rect.top); + src = _virtscr[kMainVirtScreen].getBackPixels(rect.left, rect.top); + dst = _virtscr[kMainVirtScreen].getPixels(rect.left, rect.top); assert(rw <= _screenWidth && rw > 0); assert(rh <= _screenHeight && rh > 0); - blit(dst, virtscr[0].pitch, src, virtscr[0].pitch, rw, rh); + blit(dst, _virtscr[kMainVirtScreen].pitch, src, _virtscr[kMainVirtScreen].pitch, rw, rh); markRectAsDirty(kMainVirtScreen, rect, dirtybit); } #endif @@ -1983,7 +1980,7 @@ void ScummEngine_v70he::restoreBackgroundHE(Common::Rect rect, int dirtybit) { * Reset the background behind an actor or blast object. */ void Gdi::resetBackground(int top, int bottom, int strip) { - VirtScreen *vs = &_vm->virtscr[0]; + VirtScreen *vs = &_vm->_virtscr[kMainVirtScreen]; byte *backbuff_ptr, *bgbak_ptr; int numLinesToProcess; @@ -3162,7 +3159,7 @@ void ScummEngine::fadeIn(int effect) { // that broke the FOA intro. Probably other things as well. // // Hopefully it's safe to do it at this point, at least. - virtscr[0].setDirtyRange(0, 0); + _virtscr[kMainVirtScreen].setDirtyRange(0, 0); transitionEffect(effect - 1); break; case 128: @@ -3180,7 +3177,7 @@ void ScummEngine::fadeIn(int effect) { dissolveEffect(1, 1); break; case 135: - dissolveEffect(1, virtscr[0].h); + dissolveEffect(1, _virtscr[kMainVirtScreen].h); break; default: error("Unknown screen effect, %d", effect); @@ -3189,7 +3186,7 @@ void ScummEngine::fadeIn(int effect) { } void ScummEngine::fadeOut(int effect) { - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; vs->setDirtyRange(0, 0); if (_game.version < 7) @@ -3226,7 +3223,7 @@ void ScummEngine::fadeOut(int effect) { dissolveEffect(1, 1); break; case 135: - dissolveEffect(1, virtscr[0].h); + dissolveEffect(1, _virtscr[kMainVirtScreen].h); break; default: error("fadeOut: default case %d", effect); @@ -3256,7 +3253,7 @@ void ScummEngine::transitionEffect(int a) { int i, j; int bottom; int l, t, r, b; - const int height = MIN((int)virtscr[0].h, _screenHeight); + const int height = MIN((int)_virtscr[kMainVirtScreen].h, _screenHeight); const int delay = (VAR_FADE_DELAY != 0xFF) ? VAR(VAR_FADE_DELAY) * kFadeDelay : kPictureDelay; for (i = 0; i < 16; i++) { @@ -3278,8 +3275,8 @@ void ScummEngine::transitionEffect(int a) { if (t == b) { while (l <= r) { if (l >= 0 && l < _gdi->_numStrips && t < bottom) { - virtscr[0].tdirty[l] = _screenTop + t * 8; - virtscr[0].bdirty[l] = _screenTop + (b + 1) * 8; + _virtscr[kMainVirtScreen].tdirty[l] = _screenTop + t * 8; + _virtscr[kMainVirtScreen].bdirty[l] = _screenTop + (b + 1) * 8; } l++; } @@ -3290,8 +3287,8 @@ void ScummEngine::transitionEffect(int a) { b = bottom; if (t < 0) t = 0; - virtscr[0].tdirty[l] = _screenTop + t * 8; - virtscr[0].bdirty[l] = _screenTop + (b + 1) * 8; + _virtscr[kMainVirtScreen].tdirty[l] = _screenTop + t * 8; + _virtscr[kMainVirtScreen].bdirty[l] = _screenTop + (b + 1) * 8; } updateDirtyScreen(kMainVirtScreen); } @@ -3314,16 +3311,7 @@ void ScummEngine::transitionEffect(int a) { * dissolveEffect(virtsrc[0].width, 1) produces a line-by-line dissolve */ void ScummEngine::dissolveEffect(int width, int height) { -#ifdef PALMOS_68K - // Remove this dissolve effect for now on PalmOS since it is a bit - // too slow using 68k emulation - if (width == 1 && height == 1) { - waitForTimer(30); - return; - } -#endif - - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; int *offsets; int blits_before_refresh, blits; int x, y; @@ -3432,7 +3420,7 @@ void ScummEngine::dissolveEffect(int width, int height) { } void ScummEngine::scrollEffect(int dir) { - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; int x, y; int step; @@ -3557,15 +3545,3 @@ void ScummEngine::unkScreenEffect6() { } // End of namespace Scumm -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Gfx) -_GSETPTR(Scumm::transitionEffects, GBVARS_TRANSITIONEFFECTS_INDEX, Scumm::TransitionEffect, GBVARS_SCUMM) -_GEND - -_GRELEASE(Gfx) -_GRELEASEPTR(GBVARS_TRANSITIONEFFECTS_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index fb8da562c8..4e92fad0fd 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -84,7 +84,7 @@ enum VirtScreenNumber { struct VirtScreen : Graphics::Surface { /** * The unique id of this screen (corresponds to its position in the - * ScummEngine:virtscr array). + * ScummEngine:_virtscr array). */ VirtScreenNumber number; diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 3bc2f3e5d7..3c7d742ba2 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -89,7 +89,7 @@ void MoviePlayer::handleNextFrame() { return; } - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; decodeNextFrame(); diff --git a/engines/scumm/he/floodfill_he.cpp b/engines/scumm/he/floodfill_he.cpp index 1fdd11fce8..ea2043d69f 100644 --- a/engines/scumm/he/floodfill_he.cpp +++ b/engines/scumm/he/floodfill_he.cpp @@ -179,7 +179,7 @@ skip: void floodFill(FloodFillParameters *ffp, ScummEngine_v90he *vm) { uint8 *dst; - VirtScreen *vs = &vm->virtscr[kMainVirtScreen]; + VirtScreen *vs = &vm->_virtscr[kMainVirtScreen]; if (ffp->flags & 0x8000) { dst = vs->getBackPixels(0, vs->topline); } else { diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index baee2f3e49..0b9c94fe18 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -801,7 +801,7 @@ void ScummEngine_v60he::o60_kernelSetFunctions() { void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) { vsUnpackCtx ctx; memset(&ctx, 0, sizeof(ctx)); - VirtScreen &vs = virtscr[kMainVirtScreen]; + VirtScreen &vs = _virtscr[kMainVirtScreen]; ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx); virtScreenLoadUnpack(&ctx, ah->data); @@ -875,7 +875,7 @@ void ScummEngine_v60he::o60_kernelGetFunctions() { int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) { int packedSize = 0; - VirtScreen &vs = virtscr[kMainVirtScreen]; + VirtScreen &vs = _virtscr[kMainVirtScreen]; for (int j = y1; j <= y2; ++j) { uint8 *p = vs.getBackPixels(x1, j - vs.topline); diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp index 8e6f3ce4c2..15698dedba 100644 --- a/engines/scumm/he/sprite_he.cpp +++ b/engines/scumm/he/sprite_he.cpp @@ -1120,7 +1120,7 @@ void Sprite::resetBackground() { } void Sprite::setRedrawFlags(bool checkZOrder) { - VirtScreen *vs = &_vm->virtscr[kMainVirtScreen]; + VirtScreen *vs = &_vm->_virtscr[kMainVirtScreen]; for (int i = 0; i < _numSpritesToProcess; ++i) { SpriteInfo *spi = _activeSpritesTable[i]; if (!(spi->flags & kSFNeedRedraw)) { diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index 549e4480f6..a99f3b1ad5 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -1009,7 +1009,7 @@ static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, int compType) { debug(5, "ScummEngine_v72he::captureWizImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); uint8 *src = NULL; - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; if (backBuffer) { src = pvs->getBackPixels(0, 0); } else { @@ -1182,7 +1182,7 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int assert(dst); getWizImageDim(dstResNum, 0, cw, ch); } else { - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; if (flags & kWIFMarkBufferDirty) { dst = pvs->getPixels(0, pvs->topline); } else { @@ -1377,7 +1377,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int if (srcWizBuf) { uint8 *dst; int32 dstw, dsth, dstpitch, wizW, wizH; - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen]; int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; if (dstResNum) { diff --git a/engines/scumm/imuse_digi/dimuse.h b/engines/scumm/imuse_digi/dimuse.h index dca9baac60..caff9958f3 100644 --- a/engines/scumm/imuse_digi/dimuse.h +++ b/engines/scumm/imuse_digi/dimuse.h @@ -237,16 +237,6 @@ struct imuseFtSeqTable { byte volume; }; -#ifdef PALMOS_68K -extern const imuseRoomMap *_digStateMusicMap; -extern const imuseDigTable *_digStateMusicTable; -extern const imuseDigTable *_digSeqMusicTable; -extern const imuseComiTable *_comiStateMusicTable; -extern const imuseComiTable *_comiSeqMusicTable; -extern const imuseFtStateTable *_ftStateMusicTable; -extern const imuseFtSeqTable *_ftSeqMusicTable; -extern const imuseFtNames *_ftSeqNames; -#else extern const imuseRoomMap _digStateMusicMap[]; extern const imuseDigTable _digStateMusicTable[]; extern const imuseDigTable _digSeqMusicTable[]; @@ -255,7 +245,6 @@ extern const imuseComiTable _comiSeqMusicTable[]; extern const imuseFtStateTable _ftStateMusicTable[]; extern const imuseFtSeqTable _ftSeqMusicTable[]; extern const imuseFtNames _ftSeqNames[]; -#endif } // End of namespace Scumm diff --git a/engines/scumm/imuse_digi/dimuse_codecs.cpp b/engines/scumm/imuse_digi/dimuse_codecs.cpp index 17082f5256..b79c7111f9 100644 --- a/engines/scumm/imuse_digi/dimuse_codecs.cpp +++ b/engines/scumm/imuse_digi/dimuse_codecs.cpp @@ -62,9 +62,6 @@ uint32 decode12BitsSample(const byte *src, byte **dst, uint32 size) { static byte _imcTableEntryBitCount[89]; -#ifdef PALMOS_68K -static const int16 *imcTable; -#else static const int16 imcTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, @@ -79,7 +76,6 @@ static const int16 imcTable[89] = { 15289,16818,18500,20350,22385,24623,27086,29794, 32767 }; -#endif static const byte imxOtherTable[6][64] = { { @@ -651,16 +647,3 @@ int32 decompressCodec(int32 codec, byte *compInput, byte *compOutput, int32 inpu } // End of namespace BundleCodecs } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(DimuseCodecs) -_GSETPTR(Scumm::BundleCodecs::imcTable, GBVARS_IMCTABLE_INDEX, int16, GBVARS_SCUMM) -_GEND - -_GRELEASE(DimuseCodecs) -_GRELEASEPTR(GBVARS_IMCTABLE_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/imuse_digi/dimuse_tables.cpp b/engines/scumm/imuse_digi/dimuse_tables.cpp index 0b014b5f5e..9c56063557 100644 --- a/engines/scumm/imuse_digi/dimuse_tables.cpp +++ b/engines/scumm/imuse_digi/dimuse_tables.cpp @@ -27,16 +27,6 @@ namespace Scumm { -#ifdef PALMOS_68K -const imuseRoomMap *_digStateMusicMap; -const imuseDigTable *_digStateMusicTable; -const imuseDigTable *_digSeqMusicTable; -const imuseComiTable *_comiStateMusicTable; -const imuseComiTable *_comiSeqMusicTable; -const imuseFtStateTable *_ftStateMusicTable; -const imuseFtSeqTable *_ftSeqMusicTable; -const imuseFtNames *_ftSeqNames; -#else const imuseRoomMap _digStateMusicMap[] = { {0, 0, 0, 0, 0, 0 }, {1, 0, 0, 0, 0, 0 }, @@ -852,33 +842,5 @@ const imuseFtSeqTable _ftSeqMusicTable[] = { {"legavox", 2, 127}, {"chances", 2, 90 }, }; -#endif } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(DimuseTables) -_GSETPTR(Scumm::_digStateMusicMap, GBVARS_DIGSTATEMUSICMAP_INDEX, Scumm::imuseRoomMap , GBVARS_SCUMM) -_GSETPTR(Scumm::_digStateMusicTable, GBVARS_DIGSTATEMUSICTABLE_INDEX, Scumm::imuseDigTable , GBVARS_SCUMM) -_GSETPTR(Scumm::_digSeqMusicTable, GBVARS_DIGSEQMUSICTABLE_INDEX, Scumm::imuseDigTable , GBVARS_SCUMM) -_GSETPTR(Scumm::_comiStateMusicTable, GBVARS_COMISTATEMUSICTABLE_INDEX, Scumm::imuseComiTable , GBVARS_SCUMM) -_GSETPTR(Scumm::_comiSeqMusicTable, GBVARS_COMISEQMUSICTABLE_INDEX, Scumm::imuseComiTable , GBVARS_SCUMM) -_GSETPTR(Scumm::_ftStateMusicTable, GBVARS_FTSTATEMUSICTABLE_INDEX, Scumm::imuseFtStateTable, GBVARS_SCUMM) -_GSETPTR(Scumm::_ftSeqMusicTable, GBVARS_FTSEQMUSICTABLE_INDEX, Scumm::imuseFtSeqTable , GBVARS_SCUMM) -_GSETPTR(Scumm::_ftSeqNames, GBVARS_FTSEQNAMES_INDEX, Scumm::imuseFtNames , GBVARS_SCUMM) -_GEND - -_GRELEASE(DimuseTables) -_GRELEASEPTR(GBVARS_DIGSTATEMUSICMAP_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_DIGSTATEMUSICTABLE_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_DIGSEQMUSICTABLE_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_COMISTATEMUSICTABLE_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_COMISEQMUSICTABLE_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FTSTATEMUSICTABLE_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FTSEQMUSICTABLE_INDEX , GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FTSEQNAMES_INDEX , GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 6647e9fe8d..94fafc78de 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -249,14 +249,15 @@ void ScummEngine::processInput() { if (_mouse.y > _screenHeight-1) _mouse.y = _screenHeight-1; - _virtualMouse.x = _mouse.x + virtscr[0].xstart; - _virtualMouse.y = _mouse.y - virtscr[0].topline; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; + _virtualMouse.x = _mouse.x + vs->xstart; + _virtualMouse.y = _mouse.y - vs->topline; if (_game.version >= 7) _virtualMouse.y += _screenTop; if (_virtualMouse.y < 0) _virtualMouse.y = -1; - if (_virtualMouse.y >= virtscr[0].h) + if (_virtualMouse.y >= vs->h) _virtualMouse.y = -1; // diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp index 252407913e..af09daff96 100644 --- a/engines/scumm/insane/insane.cpp +++ b/engines/scumm/insane/insane.cpp @@ -1169,8 +1169,6 @@ int Insane::smlayer_loadCostume(int id, int phase) { _vm->ensureResourceLoaded(rtCostume, resid); _vm->_res->setResourceCounter(rtCostume, resid, 1); - // smlayer_lock(rtCostume, resid); // FIXME - if (phase == 1) { _objArray1Idx2++; _objArray1[_objArray1Idx2] = id; diff --git a/engines/scumm/insane/insane_scenes.cpp b/engines/scumm/insane/insane_scenes.cpp index 5843e85f0f..0cf6623664 100644 --- a/engines/scumm/insane/insane_scenes.cpp +++ b/engines/scumm/insane/insane_scenes.cpp @@ -171,7 +171,7 @@ void Insane::runScene(int arraynum) { writeArray(339, _enemy[EN_VULTF2].isEmpty); writeArray(340, _enemy[EN_VULTM2].isEmpty); } - // insane_unlock(); // FIXME + _vm->_sound->stopAllSounds(); // IMUSE_StopAllSounds(); } @@ -328,8 +328,7 @@ int Insane::loadSceneData(int scene, int flag, int phase) { int retvalue = 1; debugC(DEBUG_INSANE, "Insane::loadSceneData(%d, %d, %d)", scene, flag, phase); - //if (phase == 1) /// FIXME - // insane_unlock(); + switch (scene) { case 1: smlayer_loadSound(88, flag, phase); diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index a340f564b3..2d70b167ea 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -14,6 +14,7 @@ MODULE_OBJS := \ detection.o \ dialogs.o \ file.o \ + file_nes.o \ gfx.o \ he/script_v60he.o \ he/sound_he.o \ diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index a88c56bc5a..128270538d 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -156,11 +156,14 @@ void ScummEngine::setOwnerOf(int obj, int owner) { } void ScummEngine::clearOwnerOf(int obj) { - int i, j; + int i; uint16 *a; + // Stop the associated object script code (else crashes might occurs) stopObjectScript(obj); + // If the object is "owned" by a the current room, we scan the + // object list and (only if it's a floating object) nuke it. if (getOwner(obj) == OF_OWNER_ROOM) { for (i = 0; i < _numLocalObjects; i++) { if (_objs[i].obj_nr == obj && _objs[i].fl_object_index) { @@ -170,26 +173,28 @@ void ScummEngine::clearOwnerOf(int obj) { _objs[i].fl_object_index = 0; } } - return; - } - - for (i = 0; i < _numInventory; i++) { - if (_inventory[i] == obj) { - j = whereIsObject(obj); - if (j == WIO_INVENTORY) { + } else { + + // Alternatively, scan the inventory to see if the object is in there... + for (i = 0; i < _numInventory; i++) { + if (_inventory[i] == obj) { + assert(WIO_INVENTORY == whereIsObject(obj)); + // Found the object! Nuke it from the inventory. _res->nukeResource(rtInventory, i); _inventory[i] = 0; - } - a = _inventory; - for (i = 0; i < _numInventory - 1; i++, a++) { - if (!a[0] && a[1]) { - a[0] = a[1]; - a[1] = 0; - _res->address[rtInventory][i] = _res->address[rtInventory][i + 1]; - _res->address[rtInventory][i + 1] = NULL; + + // Now fill up the gap removing the object from the inventory created. + a = _inventory; + for (i = 0; i < _numInventory - 1; i++, a++) { + if (!_inventory[i] && _inventory[i+1]) { + _inventory[i] = _inventory[i+1]; + _inventory[i+1] = 0; + _res->address[rtInventory][i] = _res->address[rtInventory][i + 1]; + _res->address[rtInventory][i + 1] = NULL; + } } + break; } - return; } } } @@ -583,11 +588,7 @@ void ScummEngine::drawObject(int obj, int arg) { return; ptr = getOBIMFromObjectData(od); - - if (_game.features & GF_OLD_BUNDLE) - ptr += 0; - else - ptr = getObjectImage(ptr, getState(od.obj_nr)); + ptr = getObjectImage(ptr, getState(od.obj_nr)); if (!ptr) return; @@ -619,10 +620,10 @@ void ScummEngine::drawObject(int obj, int arg) { #ifndef DISABLE_HE if (_game.heversion >= 70 && findResource(MKID_BE('SMAP'), ptr) == NULL) - _gdi->drawBMAPObject(ptr, &virtscr[0], obj, od.x_pos, od.y_pos, od.width, od.height); + _gdi->drawBMAPObject(ptr, &_virtscr[kMainVirtScreen], obj, od.x_pos, od.y_pos, od.width, od.height); else #endif - _gdi->drawBitmap(ptr, &virtscr[0], x, ypos, width * 8, height, x - xpos, numstrip, flags); + _gdi->drawBitmap(ptr, &_virtscr[kMainVirtScreen], x, ypos, width * 8, height, x - xpos, numstrip, flags); } } @@ -1394,7 +1395,9 @@ void ScummEngine::findObjectInRoom(FindObjectInRoom *fo, byte findWhat, uint id, if (id2 == (uint16)id) { if (findWhat & foCodeHeader) { fo->obcd = obcdptr; - fo->cdhd = (const CodeHeader *)(obcdptr + 10); // TODO - FIXME + // We assume that the code header starts at a fixed offset. + // A bit hackish, but works reasonably well. + fo->cdhd = (const CodeHeader *)(obcdptr + 10); } if (findWhat & foImageHeader) { fo->obim = obimptr; @@ -1626,7 +1629,7 @@ void ScummEngine_v6::drawBlastObject(BlastObject *eo) { int objnum; BompDrawData bdd; - vs = &virtscr[0]; + vs = &_virtscr[kMainVirtScreen]; assertRange(30, eo->number, _numGlobalObjects - 1, "blast object"); @@ -1704,7 +1707,7 @@ void ScummEngine_v6::removeBlastObjects() { } void ScummEngine_v6::removeBlastObject(BlastObject *eo) { - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; Common::Rect r; int left_strip, right_strip; diff --git a/engines/scumm/player_v2.cpp b/engines/scumm/player_v2.cpp index ae7985011b..82bb2cb4ec 100644 --- a/engines/scumm/player_v2.cpp +++ b/engines/scumm/player_v2.cpp @@ -44,16 +44,6 @@ namespace Scumm { #define FB_WNOISE 0x12000 /* feedback for white noise */ #define FB_PNOISE 0x08000 /* feedback for periodic noise */ -#ifdef PALMOS_68K -const uint8 *note_lengths; -static const uint16 *hull_offsets; -static const int16 *hulls; -static const uint16 *freqmod_lengths; -static const uint16 *freqmod_offsets; -static const int8 *freqmod_table; -static const uint16 *spk_freq_table; -static const uint16 *pcjr_freq_table; -#else const uint8 note_lengths[] = { 0, 0, 0, 2, @@ -341,7 +331,6 @@ static const uint16 pcjr_freq_table[12] = { 65472, 61760, 58304, 55040, 52032, 49024, 46272, 43648, 41216, 38912, 36736, 34624 }; -#endif Player_V2::Player_V2(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr) { @@ -977,30 +966,3 @@ void Player_V2::mutex_down() { } } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(PlayerV2) -_GSETPTR(Scumm::note_lengths, GBVARS_NOTELENGTHS_INDEX, uint8, GBVARS_SCUMM) -_GSETPTR(Scumm::hull_offsets, GBVARS_HULLOFFSETS_INDEX, uint16, GBVARS_SCUMM) -_GSETPTR(Scumm::hulls, GBVARS_HULLS_INDEX, int16, GBVARS_SCUMM) -_GSETPTR(Scumm::freqmod_lengths, GBVARS_FREQMODLENGTHS_INDEX, uint16, GBVARS_SCUMM) -_GSETPTR(Scumm::freqmod_offsets, GBVARS_FREQMODOFFSETS_INDEX, uint16, GBVARS_SCUMM) -_GSETPTR(Scumm::freqmod_table, GBVARS_FREQMODTABLE_INDEX, int8, GBVARS_SCUMM) -_GSETPTR(Scumm::spk_freq_table, GBVARS_SPKFREQTABLE_INDEX, uint16, GBVARS_SCUMM) -_GSETPTR(Scumm::pcjr_freq_table, GBVARS_PCJRFREQTABLE_INDEX, uint16, GBVARS_SCUMM) -_GEND - -_GRELEASE(PlayerV2) -_GRELEASEPTR(GBVARS_NOTELENGTHS_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_HULLOFFSETS_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_HULLS_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FREQMODLENGTHS_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FREQMODOFFSETS_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_FREQMODTABLE_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_SPKFREQTABLE_INDEX, GBVARS_SCUMM) -_GRELEASEPTR(GBVARS_PCJRFREQTABLE_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/player_v2a.cpp b/engines/scumm/player_v2a.cpp index 7096021be9..ceabbc7d95 100644 --- a/engines/scumm/player_v2a.cpp +++ b/engines/scumm/player_v2a.cpp @@ -32,20 +32,15 @@ namespace Scumm { #define BASE_FREQUENCY 3579545 -#ifdef PALMOS_68K -static uint32 *CRCtable = NULL; -#else static uint32 CRCtable[256]; -#endif -static void InitCRC (void) -{ + +static void InitCRC (void) { const uint32 poly = 0xEDB88320; int i, j; uint32 n; - for (i = 0; i < 256; i++) - { + for (i = 0; i < 256; i++) { n = i; for (j = 0; j < 8; j++) n = (n & 1) ? ((n >> 1) ^ poly) : (n >> 1); @@ -53,8 +48,7 @@ static void InitCRC (void) } } -static uint32 GetCRC (byte *data, int len) -{ +static uint32 GetCRC (byte *data, int len) { uint32 CRC = 0xFFFFFFFF; int i; for (i = 0; i < len; i++) @@ -1116,8 +1110,7 @@ public: } virtual bool update() { assert(_id); - if (_curfreq >= _freq2) - { + if (_curfreq >= _freq2) { _mod->setChannelFreq(_id, BASE_FREQUENCY / _curfreq); _curfreq -= _bendrate; if (--_bendctr) @@ -1125,9 +1118,7 @@ public: _bendrate--; if (_bendrate < 2) _bendrate = 2; - } - else - { + } else { if (!--_holdctr) return false; } @@ -1163,15 +1154,12 @@ public: } virtual bool update() { assert(_id); - if (!_loop) - { + if (!_loop) { _vol--; if (_vol) _mod->setChannelVol(_id, _vol); else return false; - } - else if (!--_loop) - { + } else if (!--_loop) { _mod->stopChannel(_id); char *tmp_data = (char *)malloc(_size2); memcpy(tmp_data, _data + _offset2, _size2); @@ -1309,9 +1297,6 @@ Player_V2A::Player_V2A(ScummEngine *scumm, Audio::Mixer *mixer) { int i; _vm = scumm; -#ifdef PALMOS_68K - if (!CRCtable) CRCtable = (uint32 *)calloc(256, sizeof(uint32)); -#endif InitCRC(); for (i = 0; i < V2A_MAXSLOTS; i++) { @@ -1325,9 +1310,6 @@ Player_V2A::Player_V2A(ScummEngine *scumm, Audio::Mixer *mixer) { Player_V2A::~Player_V2A() { delete _mod; -#ifdef PALMOS_68K - free(CRCtable); -#endif } void Player_V2A::setMusicVolume (int vol) { diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 88df9da6c7..d96ecc58f6 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -597,7 +597,7 @@ void ScummEngine::ensureResourceLoaded(int type, int i) { i = _resourceMapper[i & 0x7F]; } - // FIXME - TODO: This check used to be "i==0". However, that causes + // FIXME: This check used to be "i==0". However, that causes // problems when using this function to ensure charset 0 is loaded. // This is done for many games, e.g. Zak256 or Indy3 (EGA and VGA). // For now we restrict the check to anything which is not a charset. diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 3f638946c4..0e485e226a 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -344,7 +344,7 @@ bool ScummEngine::loadState(int slot, bool compat) { // Restore the virtual screens and force a fade to black. initScreens(0, _screenHeight); - VirtScreen *vs = &virtscr[kMainVirtScreen]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; memset(vs->getPixels(0, 0), 0, vs->pitch * vs->h); vs->setDirtyRange(0, vs->h); updateDirtyScreen(kMainVirtScreen); diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp index 62e5cee03b..143e926604 100644 --- a/engines/scumm/script_v0.cpp +++ b/engines/scumm/script_v0.cpp @@ -527,9 +527,9 @@ void ScummEngine_v0::drawSentence() { } _string[2].charset = 1; - _string[2].ypos = virtscr[kVerbVirtScreen].topline; + _string[2].ypos = _virtscr[kVerbVirtScreen].topline; _string[2].xpos = 0; - _string[2].right = virtscr[kVerbVirtScreen].w - 1; + _string[2].right = _virtscr[kVerbVirtScreen].w - 1; _string[2].color = 16; byte string[80]; @@ -550,10 +550,10 @@ void ScummEngine_v0::drawSentence() { } string[i] = 0; - sentenceline.top = virtscr[kVerbVirtScreen].topline; - sentenceline.bottom = virtscr[kVerbVirtScreen].topline + 8; + sentenceline.top = _virtscr[kVerbVirtScreen].topline; + sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 8; sentenceline.left = 0; - sentenceline.right = virtscr[kVerbVirtScreen].w - 1; + sentenceline.right = _virtscr[kVerbVirtScreen].w - 1; restoreBackground(sentenceline); drawString(2, (byte*)string); diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp index 767d9495cc..532acc98a3 100644 --- a/engines/scumm/script_v2.cpp +++ b/engines/scumm/script_v2.cpp @@ -1053,9 +1053,9 @@ void ScummEngine_v2::o2_drawSentence() { } _string[2].charset = 1; - _string[2].ypos = virtscr[kVerbVirtScreen].topline; + _string[2].ypos = _virtscr[kVerbVirtScreen].topline; _string[2].xpos = 0; - _string[2].right = virtscr[kVerbVirtScreen].w - 1; + _string[2].right = _virtscr[kVerbVirtScreen].w - 1; if (_game.platform == Common::kPlatformNES) { _string[2].xpos = 16; _string[2].color = 0; @@ -1087,15 +1087,15 @@ void ScummEngine_v2::o2_drawSentence() { string[i] = 0; if (_game.platform == Common::kPlatformNES) { - sentenceline.top = virtscr[kVerbVirtScreen].topline; - sentenceline.bottom = virtscr[kVerbVirtScreen].topline + 16; + sentenceline.top = _virtscr[kVerbVirtScreen].topline; + sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 16; sentenceline.left = 16; - sentenceline.right = virtscr[kVerbVirtScreen].w - 1; + sentenceline.right = _virtscr[kVerbVirtScreen].w - 1; } else { - sentenceline.top = virtscr[kVerbVirtScreen].topline; - sentenceline.bottom = virtscr[kVerbVirtScreen].topline + 8; + sentenceline.top = _virtscr[kVerbVirtScreen].topline; + sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 8; sentenceline.left = 0; - sentenceline.right = virtscr[kVerbVirtScreen].w - 1; + sentenceline.right = _virtscr[kVerbVirtScreen].w - 1; } restoreBackground(sentenceline); @@ -1590,9 +1590,9 @@ void ScummEngine_v2::setUserState(byte state) { // Hide all verbs and inventory Common::Rect rect; - rect.top = virtscr[kVerbVirtScreen].topline; - rect.bottom = virtscr[kVerbVirtScreen].topline + 8 * 88; - rect.right = virtscr[kVerbVirtScreen].w - 1; + rect.top = _virtscr[kVerbVirtScreen].topline; + rect.bottom = _virtscr[kVerbVirtScreen].topline + 8 * 88; + rect.right = _virtscr[kVerbVirtScreen].w - 1; if (_game.platform == Common::kPlatformNES) { rect.left = 16; } else { diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index c4f7937aa4..3cd71bac08 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -2929,8 +2929,8 @@ void ScummEngine_v5::o5_oldRoomEffect() { // For now, we force a redraw of the screen background. This // way the Zak end credits seem to work mostly correct. - VirtScreen *vs = &virtscr[0]; - restoreBackground(Common::Rect(0,vs->topline, vs->w, vs->topline + vs->h)); + VirtScreen *vs = &_virtscr[kMainVirtScreen]; + restoreBackground(Common::Rect(0, vs->topline, vs->w, vs->topline + vs->h)); vs->setDirtyRange(0, vs->h); updateDirtyScreen(kMainVirtScreen); diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index 7e0d705377..e436489f25 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -2715,7 +2715,7 @@ void ScummEngine_v6::o6_kernelGetFunctions() { int i; int slot; Actor *a; - VirtScreen *vs = &virtscr[0]; + VirtScreen *vs = &_virtscr[kMainVirtScreen]; getStackList(args, ARRAYSIZE(args)); diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 4f6b2477c6..69d2bea3e0 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 Fri Jul 20 21:25:14 2007 + This file was generated by the md5table tool on Mon Aug 13 12:40:13 2007 DO NOT EDIT MANUALLY! */ @@ -104,9 +104,9 @@ static const MD5Table md5table[] = { { "2232b0b9411575b1f9961713ebc9de61", "balloon", "HE 80", "", -1, Common::ES_ESP, Common::kPlatformWindows }, { "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "22d07d6c386c9c25aca5dac2a0c0d94b", "maniac", "NES", "", -1, Common::SE_SWE, Common::kPlatformNES }, + { "22d07d6c386c9c25aca5dac2a0c0d94b", "maniac", "NES", "", 262144, Common::SE_SWE, Common::kPlatformNES }, { "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, - { "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", -1, Common::DE_DEU, Common::kPlatformNES }, + { "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", 262144, Common::DE_DEU, Common::kPlatformNES }, { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "", "Floppy", 7932, Common::EN_ANY, Common::kPlatformPC }, { "27b3a4224ad63d5b04627595c1c1a025", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "28d24a33448fab6795850bc9f159a4a2", "atlantis", "", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns }, @@ -147,7 +147,7 @@ static const MD5Table md5table[] = { { "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows }, { "3824e60cdf639d22f6df92a03dc4b131", "fbear", "HE 61", "", 7732, Common::EN_ANY, Common::kPlatformPC }, { "387a544b8b10b26912d8413bab63a853", "monkey2", "", "Demo", -1, Common::EN_ANY, Common::kPlatformPC }, - { "3905799e081b80a61d4460b7b733c206", "maniac", "NES", "", -1, Common::EN_GRB, Common::kPlatformNES }, + { "3905799e081b80a61d4460b7b733c206", "maniac", "NES", "", 262144, Common::EN_GRB, Common::kPlatformNES }, { "3938ee1aa4433fca9d9308c9891172b1", "zak", "FM-TOWNS", "Demo", -1, Common::EN_ANY, Common::kPlatformFMTowns }, { "399b217b0c8d65d0398076da486363a9", "indy3", "VGA", "VGA", 6295, Common::DE_DEU, Common::kPlatformPC }, { "39cb9dec16fa16f38d79acd80effb059", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformAmiga }, @@ -312,7 +312,7 @@ static const MD5Table md5table[] = { { "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "810a9da887aefa597b0cf3c77d262897", "BluesABCTime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "81bbfa181184cb494e7a81dcfa94fbd9", "maniac", "NES", "", -1, Common::FR_FRA, Common::kPlatformNES }, + { "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 }, { "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, @@ -414,6 +414,7 @@ static const MD5Table md5table[] = { { "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", 5361, Common::EN_ANY, Common::kPlatformPC }, { "b628506f7def772e40de0aa5440fb8e1", "activity", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "b7d37d6b786b5a22deea3b038eca96ca", "maniac", "NES", "extracted", 2082, Common::ES_ESP, Common::kPlatformNES }, { "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 }, @@ -426,6 +427,7 @@ static const MD5Table md5table[] = { { "bf8b52fdd9a69c67f34e8e9fec72661c", "farm", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "bfdf584b01503f0762baded581f6a0a2", "SoccerMLS", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", -1, Common::NL_NLD, Common::kPlatformWindows }, + { "c0d5c89550381ac433624fedad5e1100", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine }, { "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD }, { "c24c490373aeb48fbd54caa8e7ae376d", "loom", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "c25755b08a8d0d47695e05f1e2111bfc", "freddi4", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -488,7 +490,7 @@ static const MD5Table md5table[] = { { "d7b247c26bf1f01f8f7daf142be84de3", "balloon", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "d831f7c048574dd9d5d85db2a1468099", "maniac", "C64", "", -1, Common::EN_ANY, Common::kPlatformC64 }, { "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", 16304, Common::UNK_LANG, Common::kPlatformUnknown }, - { "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", -1, Common::EN_USA, Common::kPlatformNES }, + { "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", 262144, Common::EN_USA, Common::kPlatformNES }, { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformPC }, { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns }, @@ -537,6 +539,7 @@ static const MD5Table md5table[] = { { "f049e38c1f8302b5db6170f1872af89a", "monkey", "CD", "CD", 8955, Common::ES_ESP, Common::kPlatformPC }, { "f06e66fd45b2f8b0f4a2833ff4476050", "fbpack", "", "", -1, Common::HB_ISR, Common::kPlatformPC }, { "f08145577e4f13584cc90b3d6e9caa55", "pajama3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, + { "f163cf53f7850e43fb482471e5c52e1a", "maniac", "NES", "", 262144, Common::ES_ESP, Common::kPlatformNES }, { "f1b0e0d587b85052de5534a3847e68fe", "water", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown }, { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index e54060c9e1..60911a97dd 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -41,6 +41,7 @@ #include "scumm/debugger.h" #include "scumm/dialogs.h" #include "scumm/file.h" +#include "scumm/file_nes.h" #include "scumm/imuse/imuse.h" #include "scumm/imuse_digi/dimuse.h" #include "scumm/smush/smush_mixer.h" @@ -227,7 +228,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _roomWidth = 0; _screenHeight = 0; _screenWidth = 0; - memset(virtscr, 0, sizeof(virtscr)); + memset(_virtscr, 0, sizeof(_virtscr)); memset(&camera, 0, sizeof(CameraData)); memset(_colorCycle, 0, sizeof(_colorCycle)); memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle)); @@ -1196,12 +1197,7 @@ void ScummEngine::setupScumm() { } int maxHeapThreshold = -1; -#ifdef PALMOS_68K - if (_game.features & GF_NEW_COSTUMES) - maxHeapThreshold = gVars->memory[kMemScummNewCostGames]; - else - maxHeapThreshold = gVars->memory[kMemScummOldCostGames]; -#else + if (_game.features & GF_NEW_COSTUMES) { // Since the new costumes are very big, we increase the heap limit, to avoid having // to constantly reload stuff from the data files. @@ -1209,7 +1205,7 @@ void ScummEngine::setupScumm() { } else { maxHeapThreshold = 550000; } -#endif + _res->setHeapThreshold(400000, maxHeapThreshold); #if (defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__)) @@ -1381,7 +1377,7 @@ void ScummEngine::resetScumm() { } camera._follows = 0; - virtscr[0].xstart = 0; + _virtscr[0].xstart = 0; _mouse.x = 104; _mouse.y = 56; diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 18c2275029..2a155c7e02 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -917,7 +917,7 @@ protected: public: int _roomHeight, _roomWidth; int _screenHeight, _screenWidth; - VirtScreen virtscr[4]; // Virtual screen areas + VirtScreen _virtscr[4]; // Virtual screen areas CameraData camera; // 'Camera' - viewport int _screenStartStrip, _screenEndStrip; @@ -1031,7 +1031,6 @@ protected: void updateDirtyScreen(VirtScreenNumber slot); void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b); void ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const; - void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); public: VirtScreen *findVirtScreen(int y); diff --git a/engines/scumm/smush/codec47.cpp b/engines/scumm/smush/codec47.cpp index 6904e96c11..739c7308d3 100644 --- a/engines/scumm/smush/codec47.cpp +++ b/engines/scumm/smush/codec47.cpp @@ -88,9 +88,6 @@ static const int8 codec47_table_big2[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1, }; -#ifdef PALMOS_68K -static const int8 *codec47_table; -#else static const int8 codec47_table[] = { 0, 0, -1, -43, 6, -43, -9, -42, 13, -41, -16, -40, 19, -39, -23, -36, 26, -34, -2, -33, @@ -144,7 +141,6 @@ static const int8 codec47_table[] = { 23, 36, -19, 39, 16, 40, -13, 41, 9, 42, -6, 43, 1, 43, 0, 0, 0, 0, 0, 0 }; -#endif void Codec47Decoder::makeTablesInterpolation(int param) { int32 variable1, variable2; @@ -617,16 +613,3 @@ bool Codec47Decoder::decode(byte *dst, const byte *src) { } } // End of namespace Scumm - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Codec47) -_GSETPTR(Scumm::codec47_table, GBVARS_CODEC47TABLE_INDEX, int8, GBVARS_SCUMM) -_GEND - -_GRELEASE(Codec47) -_GRELEASEPTR(GBVARS_CODEC47TABLE_INDEX, GBVARS_SCUMM) -_GEND - -#endif diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp index ce39302e25..612f2771db 100644 --- a/engines/scumm/smush/smush_player.cpp +++ b/engines/scumm/smush/smush_player.cpp @@ -265,6 +265,8 @@ SmushPlayer::~SmushPlayer() { } void SmushPlayer::init(int32 speed) { + VirtScreen *vs = &_vm->_virtscr[kMainVirtScreen]; + _frame = 0; _speed = speed; _endOfFile = false; @@ -273,7 +275,7 @@ void SmushPlayer::init(int32 speed) { _vm->_smushActive = true; _vm->setDirtyColors(0, 255); - _dst = _vm->virtscr[0].getPixels(0, 0); + _dst = vs->getPixels(0, 0); // HACK HACK HACK: This is an *evil* trick, beware! // We do this to fix bug #1037052. A proper solution would change all the @@ -281,10 +283,10 @@ void SmushPlayer::init(int32 speed) { // However, since a lot of the SMUSH code currently assumes the screen // width and pitch to be equal, this will require lots of changes. So // we resort to this hackish solution for now. - _origPitch = _vm->virtscr[0].pitch; + _origPitch = vs->pitch; _origNumStrips = _vm->_gdi->_numStrips; - _vm->virtscr[0].pitch = _vm->virtscr[0].w; - _vm->_gdi->_numStrips = _vm->virtscr[0].w / 8; + vs->pitch = vs->w; + _vm->_gdi->_numStrips = vs->w / 8; _vm->_mixer->stopHandle(_compressedFileSoundHandle); _vm->_mixer->stopHandle(_IACTchannel); @@ -319,7 +321,7 @@ void SmushPlayer::release() { // HACK HACK HACK: This is an *evil* trick, beware! See above for // some explanation. - _vm->virtscr[0].pitch = _origPitch; + _vm->_virtscr[kMainVirtScreen].pitch = _origPitch; _vm->_gdi->_numStrips = _origNumStrips; delete _codec37; diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp index 32fdf0e04e..83b4e90cf6 100644 --- a/engines/scumm/string.cpp +++ b/engines/scumm/string.cpp @@ -456,7 +456,7 @@ void ScummEngine::CHARSET_1() { if (a && _string[0].overhead) { int s; - _string[0].xpos = a->getPos().x - virtscr[0].xstart; + _string[0].xpos = a->getPos().x - _virtscr[kMainVirtScreen].xstart; _string[0].ypos = a->getPos().y - a->getElevation() - _screenTop; if (_game.version <= 5) { @@ -586,7 +586,7 @@ void ScummEngine::CHARSET_1() { _nextTop += _charset->getFontHeight(); } if (_game.version > 3) { - // FIXME - is this really needed? + // FIXME: is this really needed? _charset->_disableOffsX = true; } continue; @@ -678,7 +678,7 @@ void ScummEngine_v8::CHARSET_1() { if (a && _string[0].overhead) { int s; - _string[0].xpos = a->getPos().x - virtscr[0].xstart; + _string[0].xpos = a->getPos().x - _virtscr[kMainVirtScreen].xstart; s = a->_scalex * a->_talkPosX / 255; _string[0].xpos += (a->_talkPosX - s) / 2 + s; diff --git a/engines/scumm/thumbnail.cpp b/engines/scumm/thumbnail.cpp index 01255f1c1d..360d0de932 100644 --- a/engines/scumm/thumbnail.cpp +++ b/engines/scumm/thumbnail.cpp @@ -99,7 +99,7 @@ Graphics::Surface *ScummEngine::loadThumbnail(Common::InSaveFile *file) { void ScummEngine::saveThumbnail(Common::OutSaveFile *file) { Graphics::Surface thumb; -#if !defined(PALMOS_68K) || !defined(__DS__) +#if !defined(__DS__) if (!createThumbnailFromScreen(&thumb)) #endif thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16)); diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp index 56ee454240..3c5713d241 100644 --- a/engines/scumm/verbs.cpp +++ b/engines/scumm/verbs.cpp @@ -86,7 +86,7 @@ static const VerbSettings v0VerbTable_German[] = { }; void ScummEngine_v0::resetVerbs() { - VirtScreen *virt = &virtscr[kVerbVirtScreen]; + VirtScreen *virt = &_virtscr[kVerbVirtScreen]; VerbSlot *vs; int i; @@ -121,7 +121,7 @@ void ScummEngine_v0::resetVerbs() { } void ScummEngine_v0::setNewKidVerbs() { - VirtScreen *virt = &virtscr[kVerbVirtScreen]; + VirtScreen *virt = &_virtscr[kVerbVirtScreen]; VerbSlot *vs; int i; @@ -283,7 +283,7 @@ void ScummEngine_v2::initNESMouseOver() { } void ScummEngine_v2::checkV2MouseOver(Common::Point pos) { - VirtScreen *vs = &virtscr[kVerbVirtScreen]; + VirtScreen *vs = &_virtscr[kVerbVirtScreen]; Common::Rect rect; byte *ptr, *dst; int i, x, y, new_box = -1; @@ -346,7 +346,7 @@ void ScummEngine_v2::checkV2Inventory(int x, int y) { int inventoryArea = (_game.platform == Common::kPlatformNES) ? 48: 32; int object = 0; - y -= virtscr[kVerbVirtScreen].topline; + y -= _virtscr[kVerbVirtScreen].topline; if ((y < inventoryArea) || !(_mouseAndKeyboardStat & MBS_LEFT_CLICK)) return; @@ -391,7 +391,7 @@ void ScummEngine_v2::checkV2Inventory(int x, int y) { } void ScummEngine_v2::redrawV2Inventory() { - VirtScreen *vs = &virtscr[kVerbVirtScreen]; + VirtScreen *vs = &_virtscr[kVerbVirtScreen]; int i; int max_inv; Common::Rect inventoryBox; @@ -405,7 +405,7 @@ void ScummEngine_v2::redrawV2Inventory() { // Clear on all invocations inventoryBox.top = vs->topline + inventoryArea; - inventoryBox.bottom = vs->topline + virtscr[kVerbVirtScreen].h; + inventoryBox.bottom = vs->topline + vs->h; inventoryBox.left = 0; inventoryBox.right = vs->w; restoreBackground(inventoryBox); @@ -1014,8 +1014,8 @@ void ScummEngine::setVerbObject(uint room, uint object, uint verb) { } else if (_game.features & GF_SMALL_HEADER) { for (i = (_numLocalObjects-1); i > 0; i--) { if (_objs[i].obj_nr == object) { - // FIXME - the only thing we need from the OBCD is the image size! - // So we could use almost the same code (save for offsets) + // FIXME: the only thing we need from the OBCD is the image size! + // So we could use almost the same code (except for offsets) // as in the GF_OLD_BUNDLE code. But of course that would break save games // unless we insert special conversion code... <sigh> findObjectInRoom(&foir, foImageHeader, object, room); diff --git a/engines/sky/hufftext.cpp b/engines/sky/hufftext.cpp index b3e299d00c..677ea4817e 100644 --- a/engines/sky/hufftext.cpp +++ b/engines/sky/hufftext.cpp @@ -27,17 +27,6 @@ namespace Sky { -#ifdef PALMOS_68K -const HuffTree *Text::_huffTree_00109; -const HuffTree *Text::_huffTree_00267; -const HuffTree *Text::_huffTree_00288; -const HuffTree *Text::_huffTree_00303; -const HuffTree *Text::_huffTree_00331; -const HuffTree *Text::_huffTree_00348; -const HuffTree *Text::_huffTree_00365; -const HuffTree *Text::_huffTree_00368; -const HuffTree *Text::_huffTree_00372; -#else const HuffTree Text::_huffTree_00109[] = { { 1, 22, 0 }, { 2, 9, 0 }, @@ -2015,35 +2004,5 @@ const HuffTree Text::_huffTree_00372[] = { { 0, 0, 148 }, { 0, 0, '!' }, }; -#endif } // End of namespace Sky - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Sky_Hufftext) -_GSETPTR(Sky::Text::_huffTree_00109, GBVARS_HUFFTREE_00109_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00267, GBVARS_HUFFTREE_00267_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00288, GBVARS_HUFFTREE_00288_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00303, GBVARS_HUFFTREE_00303_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00331, GBVARS_HUFFTREE_00331_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00348, GBVARS_HUFFTREE_00348_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00365, GBVARS_HUFFTREE_00365_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00368, GBVARS_HUFFTREE_00368_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GSETPTR(Sky::Text::_huffTree_00372, GBVARS_HUFFTREE_00372_INDEX, const Sky::HuffTree, GBVARS_QUEEN) -_GEND - -_GRELEASE(Sky_Hufftext) -_GRELEASEPTR(GBVARS_HUFFTREE_00109_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00267_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00288_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00303_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00331_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00348_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00365_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00368_INDEX, GBVARS_QUEEN) -_GRELEASEPTR(GBVARS_HUFFTREE_00372_INDEX, GBVARS_QUEEN) -_GEND - -#endif diff --git a/engines/sky/text.h b/engines/sky/text.h index be09f5a437..dd73b51db4 100644 --- a/engines/sky/text.h +++ b/engines/sky/text.h @@ -96,7 +96,6 @@ private: static const uint16 _patchLangIdx[8]; static const uint16 _patchLangNum[8]; -#ifndef PALMOS_68K static const HuffTree _huffTree_00109[]; // trees moved to hufftext.cpp static const HuffTree _huffTree_00267[]; static const HuffTree _huffTree_00288[]; @@ -106,18 +105,6 @@ private: static const HuffTree _huffTree_00365[]; static const HuffTree _huffTree_00368[]; static const HuffTree _huffTree_00372[]; -#else -public: - static const HuffTree *_huffTree_00109; // trees moved to hufftext.cpp - static const HuffTree *_huffTree_00267; - static const HuffTree *_huffTree_00288; - static const HuffTree *_huffTree_00303; - static const HuffTree *_huffTree_00331; - static const HuffTree *_huffTree_00348; - static const HuffTree *_huffTree_00365; - static const HuffTree *_huffTree_00368; - static const HuffTree *_huffTree_00372; -#endif }; } // End of namespace Sky diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 7c15d66a46..60103ba5f9 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -317,8 +317,7 @@ int Logic::logicArAnimate(Object *compact, uint32 id) { } compact->o_walk_pc++; - if (route[compact->o_walk_pc].frame == 512) //end of sequence - { + if (route[compact->o_walk_pc].frame == 512) { //end of sequence compact->o_logic = LOGIC_script; if (((_scriptVars[GEORGE_WALKING] == 2) || (_scriptVars[GEORGE_WALKING] == 1)) && (id == PLAYER)) { diff --git a/engines/sword1/router.cpp b/engines/sword1/router.cpp index 685e11fd32..6478674eb2 100644 --- a/engines/sword1/router.cpp +++ b/engines/sword1/router.cpp @@ -130,8 +130,7 @@ int32 Router::routeFinder(int32 id, Object *megaObject, int32 x, int32 y, int32 slowInFrames = 0; slowOutFrames = 0; - if (megaId == GEORGE) - { + if (megaId == GEORGE) { turnFramesLeft = 3 * _framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT; turnFramesRight = 3 * _framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT + NO_DIRECTIONS; walkFramesLeft = _framesPerChar + NO_DIRECTIONS; @@ -703,8 +702,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // TURN TO START THE WALK //**************************************************************************** // rotate if we need to - if (lastDir != currentDir) - { + if (lastDir != currentDir) { // get the direction to turn turnDir = currentDir - lastDir; if ( turnDir < 0) @@ -717,10 +715,8 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // rotate to new walk direction // for george and nico put in a head turn at the start - if ((megaId == GEORGE) || (megaId == NICO)) - { - if ( turnDir < 0) // new frames for turn frames 29oct95jps - { + if ((megaId == GEORGE) || (megaId == NICO)) { + if ( turnDir < 0) { // new frames for turn frames 29oct95jps module = turnFramesLeft + lastDir; } else { module = turnFramesRight + lastDir; @@ -734,11 +730,9 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { } // rotate till were facing new dir then go back 45 degrees - while (lastDir != currentDir) - { + while (lastDir != currentDir) { lastDir += turnDir; - if ( turnDir < 0) // new frames for turn frames 29oct95jps - { + if ( turnDir < 0) { // new frames for turn frames 29oct95jps if ( lastDir < 0) lastDir += NO_DIRECTIONS; module = turnFramesLeft + lastDir; @@ -774,8 +768,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { lastDir = 99;// this ensures that we don't put in turn frames for the start currentDir = 99;// this ensures that we don't put in turn frames for the start do { - while (_modularPath[p].num == 0) - { + while (_modularPath[p].num == 0) { p = p + 1; if (currentDir != 99) lastRealDir = currentDir; @@ -784,8 +777,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { } //calculate average amount to lose in each step on the way to the next _node currentDir = _modularPath[p].dir; - if (currentDir < NO_DIRECTIONS) - { + if (currentDir < NO_DIRECTIONS) { module = currentDir * _framesPerStep * 2 + left; if (left == 0) left = _framesPerStep; @@ -814,22 +806,18 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { errorX = errorX * stepX; errorY = _modularPath[p].y - moduleY; errorY = errorY * stepY; - if ((errorX < 0) || (errorY < 0)) - { + if ((errorX < 0) || (errorY < 0)) { _modularPath[p].num = 0; // the end of the path // okay those last steps took us past our target but do we want to scoot or moonwalk frames = stepCount - lastCount; errorX = _modularPath[p].x - walkAnim[stepCount-1].x; errorY = _modularPath[p].y - walkAnim[stepCount-1].y; - if (frames > _framesPerStep) - { + if (frames > _framesPerStep) { lastErrorX = _modularPath[p].x - walkAnim[stepCount-7].x; lastErrorY = _modularPath[p].y - walkAnim[stepCount-7].y; - if (stepX==0) - { - if (3*ABS(lastErrorY) < ABS(errorY)) //the last stop was closest - { + if (stepX==0) { + if (3*ABS(lastErrorY) < ABS(errorY)) { //the last stop was closest stepCount -= _framesPerStep; if (left == 0) left = _framesPerStep; @@ -837,8 +825,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { left = 0; } } else { - if (3*ABS(lastErrorX) < ABS(errorX)) //the last stop was closest - { + if (3*ABS(lastErrorX) < ABS(errorX)) { //the last stop was closest stepCount -= _framesPerStep; if (left == 0) left = _framesPerStep; @@ -850,8 +837,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { errorX = _modularPath[p].x - walkAnim[stepCount-1].x; errorY = _modularPath[p].y - walkAnim[stepCount-1].y; // okay we've reached the end but we still have an error - if (errorX != 0) - { + if (errorX != 0) { frameCount = 0; frames = stepCount - lastCount; do { @@ -859,8 +845,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { walkAnim[lastCount + frameCount - 1].x += errorX*frameCount/frames; } while (frameCount<frames); } - if (errorY != 0) - { + if (errorY != 0) { frameCount = 0; frames = stepCount - lastCount; do { @@ -874,25 +859,20 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { if (currentDir != 99) lastRealDir = currentDir; // check each turn condition in turn - if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) // only for george - { + if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) { // only for george lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left - if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6))) - { + if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6))) { // turn at the end of the last walk frame = lastCount - _framesPerStep; - do - { + do { walkAnim[frame].frame += 104;//turning left frame += 1; } while (frame < lastCount ); } - if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6))) - { + if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6))) { // turn at the end of the current walk frame = lastCount - _framesPerStep; - do - { + do { walkAnim[frame].frame += 200; //was 60 now 116 frame += 1; } while (frame < lastCount ); @@ -912,8 +892,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { - if (lastRealDir == 99) - { + if (lastRealDir == 99) { error("SlidyWalkAnimatorlast direction error\n"); } //**************************************************************************** @@ -924,8 +903,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // We've done the walk now put in any turns at the end - if (_targetDir == NO_DIRECTIONS) // stand in the last direction - { + if (_targetDir == NO_DIRECTIONS) { // stand in the last direction module = standFrames + lastRealDir; _targetDir = lastRealDir; walkAnim[stepCount].frame = module; @@ -935,10 +913,8 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { walkAnim[stepCount].y = moduleY; stepCount += 1; } - if (_targetDir == 9) - { - if (stepCount == 0) - { + if (_targetDir == 9) { + if (stepCount == 0) { module = _framesPerChar + lastRealDir; walkAnim[stepCount].frame = module; walkAnim[stepCount].step = 0; @@ -947,8 +923,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { walkAnim[stepCount].y = moduleY; stepCount += 1; } - } else if (_targetDir != lastRealDir) // rotate to _targetDir - { + } else if (_targetDir != lastRealDir) { // rotate to _targetDir // rotate to target direction turnDir = _targetDir - lastRealDir; if ( turnDir < 0) @@ -961,10 +936,8 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // rotate to target direction // for george and nico put in a head turn at the start - if ((megaId == GEORGE) || (megaId == NICO)) - { - if ( turnDir < 0) // new frames for turn frames 29oct95jps - { + if ((megaId == GEORGE) || (megaId == NICO)) { + if ( turnDir < 0) { // new frames for turn frames 29oct95jps module = turnFramesLeft + lastDir; } else { module = turnFramesRight + lastDir; @@ -978,11 +951,9 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { } // rotate if we need to - while (lastRealDir != _targetDir) - { + while (lastRealDir != _targetDir) { lastRealDir += turnDir; - if ( turnDir < 0) // new frames for turn frames 29oct95jps - { + if ( turnDir < 0) { // new frames for turn frames 29oct95jps if ( lastRealDir < 0) lastRealDir += NO_DIRECTIONS; module = turnFramesLeft + lastRealDir; @@ -1000,8 +971,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { } module = standFrames + lastRealDir; walkAnim[stepCount-1].frame = module; - } else // just stand at the end - { + } else { // just stand at the end module = standFrames + lastRealDir; walkAnim[stepCount].frame = module; walkAnim[stepCount].step = 0; @@ -1150,8 +1120,7 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { // TURN TO START THE WALK //**************************************************************************** // rotate if we need to - if (lastDir != currentDir) - { + if (lastDir != currentDir) { // get the direction to turn turnDir = currentDir - lastDir; if ( turnDir < 0) @@ -1164,10 +1133,8 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { // rotate to new walk direction // for george and nico put in a head turn at the start - if ((megaId == GEORGE) || (megaId == NICO)) - { - if ( turnDir < 0) // new frames for turn frames 29oct95jps - { + if ((megaId == GEORGE) || (megaId == NICO)) { + if ( turnDir < 0) { // new frames for turn frames 29oct95jps module = turnFramesLeft + lastDir; } else { module = turnFramesRight + lastDir; @@ -1181,11 +1148,9 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { } // rotate till were facing new dir then go back 45 degrees - while (lastDir != currentDir) - { + while (lastDir != currentDir) { lastDir += turnDir; - if ( turnDir < 0) // new frames for turn frames 29oct95jps - { + if ( turnDir < 0) { // new frames for turn frames 29oct95jps if ( lastDir < 0) lastDir += NO_DIRECTIONS; module = turnFramesLeft + lastDir; @@ -1882,8 +1847,7 @@ int32 Router::checkTarget(int32 x, int32 y) { // * THE SETUP ROUTINES // **************************************************************************** -int32 Router::LoadWalkResources(Object *megaObject, int32 x, int32 y, int32 dir) -{ +int32 Router::LoadWalkResources(Object *megaObject, int32 x, int32 y, int32 dir) { WalkGridHeader floorHeader; int32 i; uint8 *fPolygrid; @@ -1915,8 +1879,7 @@ int32 Router::LoadWalkResources(Object *megaObject, int32 x, int32 y, int32 dir) fPolygrid += sizeof(WalkGridHeader); _nBars = _resMan->getUint32(floorHeader.numBars); - if (_nBars >= O_GRID_SIZE) - { + if (_nBars >= O_GRID_SIZE) { #ifdef DEBUG //check for id > number in file, error("RouteFinder Error too many _bars %d", _nBars); #endif @@ -1925,8 +1888,7 @@ int32 Router::LoadWalkResources(Object *megaObject, int32 x, int32 y, int32 dir) _nNodes = _resMan->getUint32(floorHeader.numNodes)+1; //array starts at 0 begins at a start _node has nnodes nodes and a target _node - if (_nNodes >= O_GRID_SIZE) - { + if (_nNodes >= O_GRID_SIZE) { #ifdef DEBUG //check for id > number in file, error("RouteFinder Error too many nodes %d", _nNodes); #endif diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h index fafc9c2d06..da793bc45a 100644 --- a/engines/sword1/sound.h +++ b/engines/sword1/sound.h @@ -118,12 +118,8 @@ private: char _filePath[100]; static const char _musicList[270]; static const uint16 _roomsFixedFx[TOTAL_ROOMS][TOTAL_FX_PER_ROOM]; -#ifdef PALMOS_68K -public: - static const FxDef *_fxList; -#else static const FxDef _fxList[312]; -#endif + }; } // End of namespace Sword1 diff --git a/engines/sword1/staticres.cpp b/engines/sword1/staticres.cpp index 08e6a108c4..63a1ce35ef 100644 --- a/engines/sword1/staticres.cpp +++ b/engines/sword1/staticres.cpp @@ -2894,9 +2894,6 @@ const char Music::_tuneList[TOTAL_TUNES][8] = { "rm3d", // DONE 269 ONe the scene change after the Grand Master says, "George, we have watched you..." This one might need a bit of fiddling to get it to match to the fisticuffs. }; -#ifdef PALMOS_68K -const FxDef *Sound::_fxList; -#else const FxDef Sound::_fxList[312] = { // 0 { @@ -6445,7 +6442,7 @@ const FxDef Sound::_fxList[312] = { }, //------------------------ }; -#endif + //-------------------------------------------------------------------------------------- // Continuous & random background sound effects for each location @@ -7156,16 +7153,3 @@ const uint8 *Logic::_helperData[] = { }; } // End of namespace Sword1 - -#ifdef PALMOS_68K -#include "scumm_globals.h" - -_GINIT(Sword1_fxList) -_GSETPTR(Sword1::Sound::_fxList, GBVARS_FXLIST_INDEX, Sword1::FxDef, GBVARS_SWORD1) -_GEND - -_GRELEASE(Sword1_fxList) -_GRELEASEPTR(GBVARS_FXLIST_INDEX, GBVARS_SWORD1) -_GEND - -#endif diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp index 2860d832dd..8e8de71e9c 100644 --- a/engines/touche/detection.cpp +++ b/engines/touche/detection.cpp @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/touche/detection.cpp $ - * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $ + * $URL$ + * $Id$ * */ diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index c67b1e9be3..f3d1f33dfd 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -148,10 +148,7 @@ void ToucheEngine::restart() { _waitingSetKeyCharNum3 = -1; _currentEpisodeNum = 0; - _newEpisodeNum = ConfMan.getInt("boot_param"); - if (_newEpisodeNum == 0) { - _newEpisodeNum = kStartupEpisode; - } + _newEpisodeNum = kStartupEpisode; _newMusicNum = 0; _currentMusicNum = 0; @@ -252,15 +249,22 @@ void ToucheEngine::mainLoop() { readConfigurationSettings(); + _inp_leftMouseButtonPressed = false; + _inp_rightMouseButtonPressed = false; + if (ConfMan.hasKey("save_slot")) { loadGameState(ConfMan.getInt("save_slot")); - _newEpisodeNum = _currentEpisodeNum; + _newEpisodeNum = 0; + resetSortedKeyCharsTable(); + showCursor(true); + } else { + _newEpisodeNum = ConfMan.getInt("boot_param"); + if (_newEpisodeNum == 0) { + _newEpisodeNum = kStartupEpisode; + } + showCursor(_newEpisodeNum != kStartupEpisode); } - _inp_leftMouseButtonPressed = false; - _inp_rightMouseButtonPressed = false; - showCursor(_newEpisodeNum != kStartupEpisode); - uint32 frameTimeStamp = _system->getMillis(); for (uint32 cycleCounter = 0; _flagsTable[611] == 0; ++cycleCounter) { if ((cycleCounter % 3) == 0) { |