From 84a5b4e1e32b8d6f48121d1a63401fb0be0be474 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Tue, 13 May 2008 16:09:57 +0000 Subject: used memmove() instead of memcpy() to fix memory overlap error svn-id: r32088 --- engines/agos/draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp index 737f5317af..d38a5ad33b 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -473,7 +473,7 @@ void AGOSEngine::restoreBackGround() { animTable = animTableTmp = _screenAnim1; while (animTable->srcPtr) { if (!(animTable->windowNum & 0x8000)) { - memcpy(animTableTmp, animTable, sizeof(AnimTable)); + memmove(animTableTmp, animTable, sizeof(AnimTable)); animTableTmp++; } animTable++; -- cgit v1.2.3 From 7d98ed714be064b75308db21ce6d5191fd040c94 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Tue, 13 May 2008 22:59:19 +0000 Subject: Fixed memory leak by deallocating memory used by window->iconPtr svn-id: r32094 --- engines/agos/icons.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'engines') diff --git a/engines/agos/icons.cpp b/engines/agos/icons.cpp index 7875347d4a..0a1877cd9b 100644 --- a/engines/agos/icons.cpp +++ b/engines/agos/icons.cpp @@ -534,6 +534,8 @@ void AGOSEngine::drawIconArray(uint num, Item *itemRef, int line, int classMask) window->iconPtr->upArrow = _scrollUpHitArea; window->iconPtr->downArrow = _scrollDownHitArea; } + + free (window->iconPtr); } uint AGOSEngine_Feeble::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *item_ptr) { -- cgit v1.2.3 From 5e592d4e4aa7eb9929a9bbf1283a0382d890de84 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Wed, 14 May 2008 23:26:32 +0000 Subject: Fixed memory leak when returning to launcher in AGOS engine by properly creating and deleting midi driver pointer svn-id: r32129 --- engines/agos/agos.cpp | 11 ++++++++--- engines/agos/agos.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index a79b84843c..b1586bfecc 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -558,14 +558,17 @@ int AGOSEngine::init() { // Setup midi driver int midiDriver = MidiDriver::detectMusicDriver(MDT_ADLIB | MDT_MIDI); _nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); - MidiDriver *driver = MidiDriver::createMidi(midiDriver); + + _driver = MidiDriver::createMidi(midiDriver); + if (_nativeMT32) { - driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); } _midi.mapMT32toGM (getGameType() != GType_SIMON2 && !_nativeMT32); - _midi.setDriver(driver); + _midi.setDriver(_driver); + int ret = _midi.open(); if (ret) warning("MIDI Player init failed: \"%s\"", _midi.getErrorName (ret)); @@ -877,6 +880,7 @@ AGOSEngine::~AGOSEngine() { delete _gameFile; _midi.close(); + delete _driver; for (uint i = 0; i < _itemHeap.size(); i++) { delete[] _itemHeap[i]; @@ -1015,6 +1019,7 @@ void AGOSEngine::shutdown() { delete _gameFile; _midi.close(); + delete _driver; for (uint i = 0; i < _itemHeap.size(); i++) { delete[] _itemHeap[i]; diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 1d5eda8392..50dbf7d6db 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -523,6 +523,7 @@ protected: byte _lettersToPrintBuf[80]; MidiPlayer _midi; + MidiDriver *_driver; bool _midiEnabled; bool _nativeMT32; -- cgit v1.2.3 From ca76ef4e1fa2fc9ebe0daaa2b3b6e61bed87ea14 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Tue, 20 May 2008 21:40:53 +0000 Subject: AGOS Engine: Began implementation for a new quit event which will cleanly return to the launcher. This replaces the old shutdown() method within delay() svn-id: r32203 --- engines/agos/agos.cpp | 12 +++++++++--- engines/agos/agos.h | 1 + engines/agos/event.cpp | 6 +++--- engines/agos/gfx.cpp | 2 +- engines/agos/input.cpp | 4 ++-- engines/agos/script.cpp | 9 ++++++--- engines/agos/script_e1.cpp | 4 ++-- engines/agos/script_s1.cpp | 4 ++-- engines/agos/subroutine.cpp | 4 ++++ 9 files changed, 30 insertions(+), 16 deletions(-) (limited to 'engines') diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index b1586bfecc..ec7244c068 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -98,6 +98,8 @@ AGOSEngine::AGOSEngine(OSystem *syst) _vc_get_out_of_code = 0; _gameOffsetsPtr = 0; + _quit = false; + _debugger = 0; _gameFile = 0; @@ -933,7 +935,7 @@ void AGOSEngine::pause() { _mixer->pauseAll(true); _sound->ambientPause(true); - while (_pause) { + while (_pause && !_quit) { delay(1); if (_keyPressed.keycode == Common::KEYCODE_p) _pause = false; @@ -974,7 +976,7 @@ int AGOSEngine::go() { (getFeatures() & GF_DEMO)) { int i; - while (1) { + while (!_quit) { for (i = 0; i < 4; i++) { setWindowImage(3, 9902 + i); debug(0, "Displaying image %d", 9902 + i); @@ -1003,7 +1005,7 @@ int AGOSEngine::go() { runSubroutine101(); permitInput(); - while (1) { + while (!_quit) { waitForInput(); handleVerbClicked(_verbHitArea); delay(100); @@ -1012,6 +1014,9 @@ int AGOSEngine::go() { return 0; } + +/* I do not think that this will be used + * void AGOSEngine::shutdown() { // Sync with AGOSEngine::~AGOSEngine() // In Simon 2, this gets deleted along with _sound further down @@ -1059,6 +1064,7 @@ void AGOSEngine::shutdown() { _system->quit(); } +*/ uint32 AGOSEngine::getTime() const { // FIXME: calling time() is not portable, use OSystem::getMillis instead diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 50dbf7d6db..bd8ff9d63c 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -269,6 +269,7 @@ protected: uint16 _marks; + bool _quit; bool _scriptVar2; bool _runScriptReturn1; bool _runScriptCondition[40]; diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index 250ff2fcfd..010b331cf8 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -142,7 +142,7 @@ bool AGOSEngine::kickoffTimeEvents() { cur_time = getTime() - _gameStoppedClock; - while ((te = _firstTimeStruct) != NULL && te->time <= cur_time) { + while ((te = _firstTimeStruct) != NULL && te->time <= cur_time && !_quit) { result = true; _pendingDeleteTimeEvent = te; invokeTimeEvent(te); @@ -521,7 +521,7 @@ void AGOSEngine::delay(uint amount) { _rightButtonDown++; break; case Common::EVENT_QUIT: - shutdown(); + _quit = true; return; default: break; @@ -544,7 +544,7 @@ void AGOSEngine::delay(uint amount) { _system->delayMillis(this_delay); cur = _system->getMillis(); - } while (cur < start + amount); + } while (cur < start + amount && !_quit); } void AGOSEngine::timer_callback() { diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 193b7347d6..c014413bdc 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -1263,7 +1263,7 @@ void AGOSEngine::setWindowImageEx(uint16 mode, uint16 vga_res) { if (getGameType() == GType_WW && (mode == 6 || mode == 8 || mode == 9)) { setWindowImage(mode, vga_res); } else { - while (_copyScnFlag) + while (_copyScnFlag && !_quit) delay(1); setWindowImage(mode, vga_res); diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index add7eb96f0..d36549f187 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -189,12 +189,12 @@ void AGOSEngine::waitForInput() { resetVerbs(); } - for (;;) { + while (!_quit) { _lastHitArea = NULL; _lastHitArea3 = NULL; _dragAccept = 1; - for (;;) { + while (!_quit) { if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && _keyPressed.keycode == Common::KEYCODE_F10) displayBoxStars(); diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp index 44fbb4e9e0..6758aec511 100644 --- a/engines/agos/script.cpp +++ b/engines/agos/script.cpp @@ -410,7 +410,7 @@ void AGOSEngine::o_msg() { void AGOSEngine::o_end() { // 68: exit interpreter - shutdown(); + _quit = true; } void AGOSEngine::o_done() { @@ -965,6 +965,9 @@ void AGOSEngine::writeVariable(uint16 variable, uint16 contents) { int AGOSEngine::runScript() { bool flag; + if (_quit) + return 1; + do { if (_continousMainScript) dumpOpcode(_codePtr); @@ -1007,7 +1010,7 @@ int AGOSEngine::runScript() { error("Invalid opcode '%d' encountered", _opcode); executeOpcode(_opcode); - } while (getScriptCondition() != flag && !getScriptReturn()); + } while (getScriptCondition() != flag && !getScriptReturn() && !_quit); return getScriptReturn(); } @@ -1063,7 +1066,7 @@ void AGOSEngine::waitForSync(uint a) { _exitCutscene = false; _rightButtonDown = false; - while (_vgaWaitFor != 0) { + while (_vgaWaitFor != 0 && !_quit) { if (_rightButtonDown) { if (_vgaWaitFor == 200 && (getGameType() == GType_FF || !getBitFlag(14))) { skipSpeech(); diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp index 94df21979c..c7e1d6736e 100644 --- a/engines/agos/script_e1.cpp +++ b/engines/agos/script_e1.cpp @@ -565,7 +565,7 @@ void AGOSEngine_Elvira1::oe1_look() { lobjFunc(l, "You can see "); /* Show objects */ } if (r && (r->flags & 4) && levelOf(i) < 10000) { - shutdown(); + _quit = true; } } @@ -944,7 +944,7 @@ restart: windowPutChar(window, *message2); if (confirmYesOrNo(120, 62) == 0x7FFF) { - shutdown(); + _quit = true; } else { goto restart; } diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp index a1308b951d..51918b9515 100644 --- a/engines/agos/script_s1.cpp +++ b/engines/agos/script_s1.cpp @@ -345,14 +345,14 @@ void AGOSEngine_Simon1::os1_pauseGame() { if (isSmartphone()) { if (_keyPressed.keycode) { if (_keyPressed.keycode == Common::KEYCODE_RETURN) - shutdown(); + _quit = true; else break; } } #endif if (_keyPressed.keycode == keyYes) - shutdown(); + _quit = true; else if (_keyPressed.keycode == keyNo) break; } diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp index 44ada82585..cb71ed7efa 100644 --- a/engines/agos/subroutine.cpp +++ b/engines/agos/subroutine.cpp @@ -554,6 +554,10 @@ int AGOSEngine::startSubroutine(Subroutine *sub) { _currentTable = sub; restart: + + if (_quit) + return result; + while ((byte *)sl != (byte *)sub) { _currentLine = sl; if (checkIfToRunSubroutineLine(sl, sub)) { -- cgit v1.2.3 From 799fb932f421c7833e2afbfd897b6f0c6c90c6e5 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Wed, 21 May 2008 18:52:27 +0000 Subject: AGOS: Fixed two memory leaks when returning to the launcher (_mouseData and _zoneBuffers) svn-id: r32208 --- engines/agos/agos.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'engines') diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index ec7244c068..80fbe28c0c 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -891,6 +891,8 @@ AGOSEngine::~AGOSEngine() { free(_tablesHeapPtr - _tablesHeapCurPos); + free(_mouseData); + free(_gameOffsetsPtr); free(_iconFilePtr); free(_itemArrayPtr); @@ -902,6 +904,7 @@ AGOSEngine::~AGOSEngine() { free(_backGroundBuf); free(_backBuf); free(_scaleBuf); + free(_zoneBuffers); free(_window4BackScn); free(_window6BackScn); -- cgit v1.2.3 From 9e4115a3bf5c2d2004f5876a5c9b6b62c2706630 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Thu, 22 May 2008 23:40:36 +0000 Subject: AGOS: Fixed a memory leak from earlier in a better way svn-id: r32219 --- engines/agos/icons.cpp | 2 -- engines/agos/intern.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/agos/icons.cpp b/engines/agos/icons.cpp index 0a1877cd9b..7875347d4a 100644 --- a/engines/agos/icons.cpp +++ b/engines/agos/icons.cpp @@ -534,8 +534,6 @@ void AGOSEngine::drawIconArray(uint num, Item *itemRef, int line, int classMask) window->iconPtr->upArrow = _scrollUpHitArea; window->iconPtr->downArrow = _scrollDownHitArea; } - - free (window->iconPtr); } uint AGOSEngine_Feeble::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *item_ptr) { diff --git a/engines/agos/intern.h b/engines/agos/intern.h index 54cf4dba16..4479e2851e 100644 --- a/engines/agos/intern.h +++ b/engines/agos/intern.h @@ -161,6 +161,7 @@ struct WindowBlock { uint8 fill_color, text_color; IconBlock *iconPtr; WindowBlock() { memset(this, 0, sizeof(*this)); } + ~WindowBlock() { free (iconPtr); } }; // note on text offset: // the actual x-coordinate is: textColumn * 8 + textColumnOffset -- cgit v1.2.3 From e41bd1eae8a15ea28237b090a833b94ca68c39ad Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Sat, 24 May 2008 00:08:13 +0000 Subject: AGI: Fixed two memory leaks when returning to launcher from AGI Engine svn-id: r32236 --- engines/agi/agi.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'engines') diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 81aec3e351..3e0987bc18 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -766,12 +766,15 @@ AgiEngine::~AgiEngine() { } agiDeinit(); + delete _loader; _sound->deinitSound(); delete _sound; _gfx->deinitVideo(); delete _sprites; + delete _picture; free(_game.sbufOrig); _gfx->deinitMachine(); + delete _gfx; delete _rnd; delete _console; -- cgit v1.2.3 From 369f7b0d083cf78a8d00310f2e35013717ff09fc Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Tue, 27 May 2008 20:15:36 +0000 Subject: AGI: Modified AGI Engine to shutdown without using system->quit svn-id: r32329 --- engines/agi/agi.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 3e0987bc18..9d88dd73ef 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -62,9 +62,7 @@ void AgiEngine::processEvents() { while (_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_QUIT: - _gfx->deinitVideo(); - _gfx->deinitMachine(); - _system->quit(); + _game.quitProgNow = true; break; case Common::EVENT_PREDICTIVE_DIALOG: if (_predictiveDialogRunning) -- cgit v1.2.3 From 17b0144402a9e74c51ba6d2c6e223f67adf03e59 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Tue, 27 May 2008 23:26:48 +0000 Subject: CINE: Fixed two memory leaks when shutting down the CINE engine svn-id: r32332 --- engines/cine/cine.cpp | 4 +++- engines/cine/sound.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 41dd9be16f..52474d13a9 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -42,7 +42,6 @@ #include "cine/sound.h" #include "cine/various.h" - namespace Cine { Sound *g_sound; @@ -70,6 +69,9 @@ CineEngine::~CineEngine() { freeErrmessDat(); } Common::clearAllSpecialDebugLevels(); + + free(partBuffer); + free(textDataPtr); } int CineEngine::init() { diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index e808de6922..f26032fe98 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -249,6 +249,7 @@ AdlibSoundDriver::AdlibSoundDriver(Audio::Mixer *mixer) AdlibSoundDriver::~AdlibSoundDriver() { _mixer->stopHandle(_soundHandle); + OPLDestroy(_opl); } void AdlibSoundDriver::setupChannel(int channel, const byte *data, int instrument, int volume) { -- cgit v1.2.3 From 3c0e72bb25f83120f0320782793af64213cbd1c2 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Wed, 28 May 2008 00:52:45 +0000 Subject: CINE: Initialize exitEngine to 0 in mainLoop() to allow replay after returning to the launcher svn-id: r32333 --- engines/cine/main_loop.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 6042849f59..098ce84ae5 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -187,6 +187,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { uint16 mouseButton; quitFlag = 0; + exitEngine = 0; if (_preLoad == false) { resetSeqList(); -- cgit v1.2.3 From 203f62ad7cfc3f931c98c8fc3ecdbb01924b896f Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Wed, 28 May 2008 23:28:11 +0000 Subject: LURE: Fixed some memory leaks when returning to the launcher from the LURE engine svn-id: r32357 --- engines/lure/lure.cpp | 4 ++++ engines/lure/lure.h | 2 +- engines/lure/menu.cpp | 5 +++++ engines/lure/menu.h | 1 + engines/lure/palette.cpp | 6 ++++++ engines/lure/palette.h | 1 + engines/lure/res.cpp | 1 + 7 files changed, 19 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/lure/lure.cpp b/engines/lure/lure.cpp index 06d3b1984e..fa6323af07 100644 --- a/engines/lure/lure.cpp +++ b/engines/lure/lure.cpp @@ -164,10 +164,14 @@ void LureEngine::pauseEngineIntern(bool pause) { } } +/* This is not being used + void LureEngine::quitGame() { _system->quit(); } +*/ + const char *LureEngine::generateSaveName(int slotNumber) { static char buffer[15]; diff --git a/engines/lure/lure.h b/engines/lure/lure.h index d66f446247..b4cec38ef3 100644 --- a/engines/lure/lure.h +++ b/engines/lure/lure.h @@ -70,7 +70,7 @@ public: virtual int init(); virtual int go(); virtual void pauseEngineIntern(bool pause); - void quitGame(); + //void quitGame(); This is not being used Disk &disk() { return *_disk; } diff --git a/engines/lure/menu.cpp b/engines/lure/menu.cpp index cecc415499..0b4ef06081 100644 --- a/engines/lure/menu.cpp +++ b/engines/lure/menu.cpp @@ -57,6 +57,11 @@ MenuRecord::MenuRecord(const MenuRecordBounds *bounds, int numParams, ...) { _width = (bounds->contentsWidth + 3) << 3; } +MenuRecord::~MenuRecord() { + free(_entries); + _entries = NULL; +} + const char *MenuRecord::getEntry(uint8 index) { if (index >= _numEntries) error("Invalid menuitem index specified: %d", index); return _entries[index]; diff --git a/engines/lure/menu.h b/engines/lure/menu.h index b5b7769e34..fcc6308375 100644 --- a/engines/lure/menu.h +++ b/engines/lure/menu.h @@ -56,6 +56,7 @@ private: uint8 _numEntries; public: MenuRecord(const MenuRecordBounds *bounds, int numParams, ...); + ~MenuRecord(); uint16 xstart() { return _xstart; } uint16 width() { return _width; } diff --git a/engines/lure/palette.cpp b/engines/lure/palette.cpp index 03161032c0..badc3c96b0 100644 --- a/engines/lure/palette.cpp +++ b/engines/lure/palette.cpp @@ -106,6 +106,12 @@ Palette::Palette(uint16 resourceId, PaletteSource paletteSource) { delete srcData; } +// Destructor + +Palette::~Palette() { + delete _palette; +} + void Palette::convertRgb64Palette(const byte *srcPalette, uint16 srcNumEntries) { byte *pDest = _palette->data(); const byte *pSrc = srcPalette; diff --git a/engines/lure/palette.h b/engines/lure/palette.h index 1481e22775..9420079346 100644 --- a/engines/lure/palette.h +++ b/engines/lure/palette.h @@ -46,6 +46,7 @@ public: Palette(uint16 srcNumEntries, const byte *srcData, PaletteSource paletteSource); Palette(Palette &src); Palette(uint16 resourceId, PaletteSource paletteSource = DEFAULT); + ~Palette(); uint8 *data() { return _palette->data(); } MemoryBlock *palette() { return _palette; } diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp index f2997d5d17..68de260061 100644 --- a/engines/lure/res.cpp +++ b/engines/lure/res.cpp @@ -349,6 +349,7 @@ void Resources::reloadData() { _indexedRoomExitHospots.push_back(RoomExitIndexedHotspotList::value_type(new RoomExitIndexedHotspotData(indexedRec))); indexedRec++; } + delete mb; // Initialise delay list _delayList.clear(true); -- cgit v1.2.3 From a338d5fdb2715a7b29ae789c632a0cfa05803079 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Mon, 2 Jun 2008 21:08:49 +0000 Subject: PARA: Got rid of calls to system->quit() so that the Parallaction engine can return to the launcher. Also fixed a couple of memory leaks. svn-id: r32504 --- engines/parallaction/dialogue.cpp | 14 ++++++++++---- engines/parallaction/exec_ns.cpp | 2 ++ engines/parallaction/graphics.h | 1 + engines/parallaction/input.cpp | 5 +---- engines/parallaction/parallaction.cpp | 13 ++++++++++++- engines/parallaction/parallaction_br.cpp | 3 +++ engines/parallaction/parallaction_ns.cpp | 8 +++++++- engines/parallaction/parser.cpp | 13 +++++++++++++ engines/parallaction/parser.h | 5 +++++ 9 files changed, 54 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 70db637699..b9dea60dc0 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -105,10 +105,8 @@ uint16 DialogueManager::askPassword() { if (g_system->getEventManager()->pollEvent(e)) { if (e.type == Common::EVENT_QUIT) { - // TODO: don't quit() here, just have caller routines to check - // on kEngineQuit and exit gracefully to allow the engine to shut down _engineFlags |= kEngineQuit; - g_system->quit(); + break; } if ((e.type == Common::EVENT_KEYDOWN) && isdigit(e.kbd.ascii)) { @@ -231,11 +229,19 @@ void DialogueManager::run() { answer = 0; displayQuestion(); + + if (_engineFlags & kEngineQuit) + return; + if (_q->_answers[0] == NULL) break; if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) { if (!displayAnswers()) break; answer = getAnswer(); + + if (_engineFlags & kEngineQuit) + return; + cmdlist = &_q->_answers[answer]->_commands; } @@ -266,7 +272,7 @@ int16 DialogueManager::selectAnswer() { uint32 event; Common::Point p; - while (true) { + while (_engineFlags & kEngineQuit == 0) { _vm->_input->readInput(); _vm->_input->getCursorPos(p); diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 68ae91c73e..f7c3b895c2 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -518,6 +518,8 @@ uint16 Parallaction::runZone(ZonePtr z) { case kZoneSpeak: runDialogue(z->u.speak); + if (_engineFlags & kEngineQuit) + return 0; break; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 8f1c14aef0..7528a20c67 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -95,6 +95,7 @@ public: } ~SurfaceToFrames() { + _surf->free(); delete _surf; } diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 28d0ad888d..e758bbd41c 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -80,11 +80,8 @@ uint16 Input::readInput() { break; case Common::EVENT_QUIT: - // TODO: don't quit() here, just have caller routines to check - // on kEngineQuit and exit gracefully to allow the engine to shut down _engineFlags |= kEngineQuit; - _vm->_system->quit(); - break; + return KeyDown; default: break; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index d66b1af1f1..cd723181d9 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -89,16 +89,18 @@ Parallaction::~Parallaction() { delete _globalTable; delete _callableNames; - delete _localFlagNames; + //delete _localFlagNames; freeLocation(); freeCharacter(); destroyInventory(); + delete _localFlagNames; delete _gfx; delete _soundMan; delete _disk; + delete _input; } @@ -354,12 +356,20 @@ void Parallaction::runGame() { processInput(data); } + if (_engineFlags & kEngineQuit) + return; + runPendingZones(); + if (_engineFlags & kEngineQuit) + return; + if (_engineFlags & kEngineChangeLocation) { changeLocation(_location._name); } + if (_engineFlags & kEngineQuit) + return; _gfx->beginFrame(); @@ -522,6 +532,7 @@ void Character::free() { delete _talk; delete _head; delete _objs; + delete _ani->gfxobj; _ani->gfxobj = NULL; _talk = NULL; diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index f07d201ae9..06f728f603 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -107,6 +107,9 @@ int Parallaction_br::go() { guiStart(); + if (_engineFlags & kEngineQuit) + return 0; + // initCharacter(); _input->_inputMode = Input::kInputModeGame; diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 8e0f83d46d..8254a85a34 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -241,9 +241,15 @@ int Parallaction_ns::go() { _globalTable = _disk->loadTable("global"); guiStart(); - + + if (_engineFlags & kEngineQuit) + return 0; + changeLocation(_location._name); + if (_engineFlags & kEngineQuit) + return 0; + _input->_inputMode = Input::kInputModeGame; while ((_engineFlags & kEngineQuit) == 0) { runGame(); diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index f9de6eb4af..c166c8fe3a 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -31,6 +31,8 @@ namespace Parallaction { char _tokens[20][MAX_TOKEN_LEN]; Script::Script(Common::ReadStream *input, bool disposeSource) : _input(input), _disposeSource(disposeSource), _line(0) { + +// clearAllTokens(); } Script::~Script() { @@ -73,6 +75,17 @@ void Script::clearTokens() { } +/* +void Script::clearAllTokens() { + + for (uint16 i = 0; i < 20; i++) + for (uint16 j = 0; j < 50; j++) + _tokens[i][j] = '\0'; + + return; +} +*/ + void Script::skip(const char* endToken) { while (scumm_stricmp(_tokens[0], endToken)) { diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index d600f9eb9d..e8de07822e 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -44,6 +44,7 @@ class Script { uint _line; // for debug messages void clearTokens(); + //void clearAllTokens(); uint16 fillTokens(char* line); public: @@ -239,8 +240,12 @@ public: } virtual ~LocationParser_ns() { + delete _parser; + delete _script; delete _commandsNames; delete _locationStmt; + delete _locationZoneStmt; + delete _locationAnimStmt; delete _zoneTypeNames; delete _zoneFlagNames; } -- cgit v1.2.3 From fa75221e484d8649ab4506ec49b698328dd7649b Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Tue, 3 Jun 2008 18:24:54 +0000 Subject: PARA: Fixed some memory leaks svn-id: r32519 --- engines/parallaction/parallaction.cpp | 18 ++++++++++-------- engines/parallaction/parallaction.h | 4 ++++ engines/parallaction/parallaction_ns.cpp | 4 +++- engines/parallaction/parser.cpp | 16 +--------------- engines/parallaction/parser.h | 6 ++---- engines/parallaction/parser_ns.cpp | 2 +- 6 files changed, 21 insertions(+), 29 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index cd723181d9..25ebe4263d 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -84,18 +84,18 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam Parallaction::~Parallaction() { + clearSet(_commandOpcodes); + clearSet(_instructionOpcodes); + delete _debugger; - delete _globalTable; - delete _callableNames; - //delete _localFlagNames; freeLocation(); freeCharacter(); destroyInventory(); - + delete _localFlagNames; delete _gfx; delete _soundMan; @@ -138,9 +138,11 @@ int Parallaction::init() { } - - - +void Parallaction::clearSet(OpcodeSet &opcodes) { + for (Common::Array::iterator i = opcodes.begin(); i != opcodes.end(); ++i) + delete *i; + opcodes.clear(); +} void Parallaction::updateView() { @@ -534,10 +536,10 @@ void Character::free() { delete _objs; delete _ani->gfxobj; - _ani->gfxobj = NULL; _talk = NULL; _head = NULL; _objs = NULL; + _ani->gfxobj = NULL; return; } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 3117424373..b100342c2e 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -385,6 +385,9 @@ protected: // members int16 pickupItem(ZonePtr z); + void clearSet(OpcodeSet &opcodes); + + public: virtual void callFunction(uint index, void* parm) { } @@ -401,6 +404,7 @@ public: void beep(); + public: // const char **_zoneFlagNamesRes; // const char **_zoneTypeNamesRes; diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 74003ee78b..08599cb06b 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -154,7 +154,9 @@ int Parallaction_ns::init() { Parallaction_ns::~Parallaction_ns() { freeFonts(); - + + delete _locationParser; + delete _programParser; delete _mouseComposedArrow; _location._animations.remove(_char._ani); diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index c166c8fe3a..6de0a7d7f5 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -30,10 +30,7 @@ namespace Parallaction { char _tokens[20][MAX_TOKEN_LEN]; -Script::Script(Common::ReadStream *input, bool disposeSource) : _input(input), _disposeSource(disposeSource), _line(0) { - -// clearAllTokens(); -} +Script::Script(Common::ReadStream *input, bool disposeSource) : _input(input), _disposeSource(disposeSource), _line(0) {} Script::~Script() { if (_disposeSource) @@ -75,17 +72,6 @@ void Script::clearTokens() { } -/* -void Script::clearAllTokens() { - - for (uint16 i = 0; i < 20; i++) - for (uint16 j = 0; j < 50; j++) - _tokens[i][j] = '\0'; - - return; -} -*/ - void Script::skip(const char* endToken) { while (scumm_stricmp(_tokens[0], endToken)) { diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index 79e9cc7df0..b6858ab175 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -44,7 +44,6 @@ class Script { uint _line; // for debug messages void clearTokens(); - //void clearAllTokens(); uint16 fillTokens(char* line); public: @@ -222,7 +221,6 @@ public: virtual ~LocationParser_ns() { delete _parser; - delete _script; delete _commandsNames; delete _locationStmt; delete _locationZoneStmt; @@ -230,8 +228,6 @@ public: delete _zoneTypeNames; delete _zoneFlagNames; - delete _parser; - clearSet(_commandParsers); clearSet(_locationAnimParsers); clearSet(_locationZoneParsers); @@ -361,7 +357,9 @@ public: } virtual ~ProgramParser_ns() { + delete _parser; delete _instructionNames; + clearSet(_instructionParsers); } diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 96a4fced71..1b66394abf 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1396,7 +1396,7 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) { list.push_front(z); _parser->pushTables(&_locationZoneParsers, _locationZoneStmt); - + return; } -- cgit v1.2.3 From 18b892e534c9fedf60a57c71e0978965d353fd60 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Wed, 4 Jun 2008 05:21:47 +0000 Subject: QUEEN: Modified engine to use a quit flag instead of system->quit() in order to return to the launcher svn-id: r32525 --- engines/queen/input.cpp | 9 +++++---- engines/queen/input.h | 4 +++- engines/queen/journal.cpp | 4 ++-- engines/queen/queen.cpp | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/queen/input.cpp b/engines/queen/input.cpp index 146e95bcef..9f03c341c9 100644 --- a/engines/queen/input.cpp +++ b/engines/queen/input.cpp @@ -27,6 +27,7 @@ #include "common/events.h" #include "common/system.h" +#include "queen/queen.h" #include "queen/input.h" namespace Queen { @@ -51,12 +52,12 @@ const Verb Input::_verbKeys[] = { VERB_USE }; -Input::Input(Common::Language language, OSystem *system) : +Input::Input(Common::Language language, OSystem *system, QueenEngine *vm) : _system(system), _eventMan(system->getEventManager()), _fastMode(false), _keyVerb(VERB_NONE), _cutawayRunning(false), _canQuit(false), _cutawayQuit(false), _dialogueRunning(false), _talkQuit(false), _quickSave(false), _quickLoad(false), _debugger(false), _inKey(Common::KEYCODE_INVALID), - _mouseButton(0), _idleTime(0) { + _mouseButton(0), _idleTime(0) , _vm(vm) { switch (language) { case Common::EN_ANY: @@ -119,8 +120,8 @@ void Input::delay(uint amount) { break; case Common::EVENT_QUIT: - _system->quit(); - break; + _vm->quitGame(); + return; default: break; diff --git a/engines/queen/input.h b/engines/queen/input.h index 86092aeed6..43a57729c6 100644 --- a/engines/queen/input.h +++ b/engines/queen/input.h @@ -49,7 +49,7 @@ public: MOUSE_RBUTTON = 2 }; - Input(Common::Language language, OSystem *system); + Input(Common::Language language, OSystem *system, QueenEngine *vm); void delay(uint amount); @@ -99,6 +99,8 @@ private: Common::EventManager *_eventMan; + QueenEngine *_vm; + //! some cutaways require update() run faster bool _fastMode; diff --git a/engines/queen/journal.cpp b/engines/queen/journal.cpp index bfbcfa4e59..0327fb74b8 100644 --- a/engines/queen/journal.cpp +++ b/engines/queen/journal.cpp @@ -85,8 +85,8 @@ void Journal::use() { handleMouseWheel(1); break; case Common::EVENT_QUIT: - _system->quit(); - break; + _vm->quitGame(); + return; default: break; } diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp index d1a1247c46..c95e44b477 100644 --- a/engines/queen/queen.cpp +++ b/engines/queen/queen.cpp @@ -418,7 +418,7 @@ int QueenEngine::init() { _display = new Display(this, _system); _graphics = new Graphics(this); _grid = new Grid(this); - _input = new Input(_resource->getLanguage(), _system); + _input = new Input(_resource->getLanguage(), _system, this); if (_resource->isDemo()) { _logic = new LogicDemo(this); -- cgit v1.2.3 From a98a350d14ae8731469f9c551477138c02a37032 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Fri, 6 Jun 2008 00:34:47 +0000 Subject: TOUCHE: Fixed a memory leak svn-id: r32566 --- engines/touche/midi.cpp | 1 + engines/touche/touche.cpp | 3 +++ 2 files changed, 4 insertions(+) (limited to 'engines') diff --git a/engines/touche/midi.cpp b/engines/touche/midi.cpp index 14cb85912a..ce62849d2f 100644 --- a/engines/touche/midi.cpp +++ b/engines/touche/midi.cpp @@ -107,6 +107,7 @@ void MidiPlayer::close() { _mutex.lock(); _driver->setTimerCallback(NULL, NULL); _driver->close(); + delete _driver; _driver = 0; _parser->setMidiDriver(NULL); delete _parser; diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index 6520fb5e4a..1e0ca44354 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -79,6 +79,7 @@ ToucheEngine::ToucheEngine(OSystem *system, Common::Language language) ToucheEngine::~ToucheEngine() { Common::clearAllSpecialDebugLevels(); delete _midiPlayer; +// delete driver; } int ToucheEngine::init() { @@ -96,6 +97,8 @@ int ToucheEngine::init() { MidiDriver *driver = MidiDriver::createMidi(midiDriver); _midiPlayer = new MidiPlayer(driver, native_mt32); + +// delete driver; _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume); -- cgit v1.2.3 From 0f41f1ccf4cbadedc63576af55249b142b833145 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Fri, 6 Jun 2008 16:40:39 +0000 Subject: SKY: Fixed a memory leak in SKY engine svn-id: r32578 --- engines/sky/music/adlibmusic.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/sky/music/adlibmusic.cpp b/engines/sky/music/adlibmusic.cpp index 7c2b262d82..4434f4cd68 100644 --- a/engines/sky/music/adlibmusic.cpp +++ b/engines/sky/music/adlibmusic.cpp @@ -47,6 +47,7 @@ AdlibMusic::AdlibMusic(Audio::Mixer *pMixer, Disk *pDisk) AdlibMusic::~AdlibMusic(void) { + OPLDestroy(_opl); _mixer->stopHandle(_soundHandle); } -- cgit v1.2.3 From 4d7798825cc287695e70ad9669e72fe317c6a9e0 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Mon, 9 Jun 2008 22:26:05 +0000 Subject: TOUCHE: Reverted some comments that were used for testing purposes svn-id: r32641 --- engines/touche/touche.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'engines') diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index 1e0ca44354..06ee28dae8 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -79,7 +79,6 @@ ToucheEngine::ToucheEngine(OSystem *system, Common::Language language) ToucheEngine::~ToucheEngine() { Common::clearAllSpecialDebugLevels(); delete _midiPlayer; -// delete driver; } int ToucheEngine::init() { @@ -98,7 +97,6 @@ int ToucheEngine::init() { _midiPlayer = new MidiPlayer(driver, native_mt32); -// delete driver; _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume); -- cgit v1.2.3 From dd423f803b43a0e6c54c3d7441c40cb7737d7867 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Thu, 12 Jun 2008 16:58:02 +0000 Subject: SAGA: Fixed memory leaks in the SAGA engine svn-id: r32673 --- engines/saga/animation.cpp | 1 + engines/saga/font.cpp | 2 ++ engines/saga/interface.cpp | 14 ++++++++++++++ engines/saga/interface.h | 6 +++++- engines/saga/introproc_ihnm.cpp | 2 ++ engines/saga/rscfile.cpp | 2 ++ engines/saga/saga.cpp | 8 +++++--- engines/saga/saga.h | 2 ++ engines/saga/script.cpp | 1 + engines/saga/sprite.cpp | 3 +++ 10 files changed, 37 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp index 3a1e510529..9fffb0f8bf 100644 --- a/engines/saga/animation.cpp +++ b/engines/saga/animation.cpp @@ -55,6 +55,7 @@ Anim::Anim(SagaEngine *vm) : _vm(vm) { Anim::~Anim(void) { reset(); + freeCutawayList(); } void Anim::loadCutawayList(const byte *resourcePointer, size_t resourceLength) { diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp index e936117894..7789949393 100644 --- a/engines/saga/font.cpp +++ b/engines/saga/font.cpp @@ -63,6 +63,8 @@ Font::~Font(void) { free(_fonts[i]); } + + free(_fonts); } diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 7380570a99..1d048baaad 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -334,7 +334,21 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) { Interface::~Interface(void) { free(_inventory); + free(_mainPanel.image); + free(_conversePanel.image); + free(_optionPanel.image); + free(_quitPanel.image); + free(_loadPanel.image); + free(_savePanel.image); + _mainPanel.sprites.freeMem(); + _conversePanel.sprites.freeMem(); + _optionPanel.sprites.freeMem(); + _quitPanel.sprites.freeMem(); + _loadPanel.sprites.freeMem(); + _savePanel.sprites.freeMem(); + _protectPanel.sprites.freeMem(); + _defPortraits.freeMem(); _scenePortraits.freeMem(); } diff --git a/engines/saga/interface.h b/engines/saga/interface.h index 2091c9f071..2e124c2d10 100644 --- a/engines/saga/interface.h +++ b/engines/saga/interface.h @@ -112,7 +112,11 @@ struct InterfacePanel { buttonsCount = 0; buttons = NULL; } - +/* + ~InterfacePanel() { + sprites.freeMem(); + } +*/ PanelButton *getButton(int index) { if ((index >= 0) && (index < buttonsCount)) { return &buttons[index]; diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp index 5f1d0157d5..6614f4098f 100644 --- a/engines/saga/introproc_ihnm.cpp +++ b/engines/saga/introproc_ihnm.cpp @@ -132,6 +132,8 @@ void Scene::IHNMLoadCutaways() { // Load the cutaways for the title screens _vm->_anim->loadCutawayList(resourcePointer, resourceLength); + + free(resourcePointer); } bool Scene::checkKey() { diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp index b7d4f4f1bd..e150caeca5 100644 --- a/engines/saga/rscfile.cpp +++ b/engines/saga/rscfile.cpp @@ -769,6 +769,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { _vm->_sprite->_mainSprites.freeMem(); _vm->_sprite->loadList(_metaResource.mainSpritesID, _vm->_sprite->_mainSprites); + _vm->_actor->loadObjList(_metaResource.objectCount, _metaResource.objectsResourceID); _vm->_resource->loadResource(resourceContext, _metaResource.cutawayListResourceID, resourcePointer, resourceLength); @@ -806,6 +807,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { // 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); + free(resourcePointer); } int voiceLUTResourceID = 0; diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 40eb32b276..fafbd02cec 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -79,6 +79,7 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) _scene = NULL; _isoMap = NULL; _gfx = NULL; + _driver = NULL; _console = NULL; _render = NULL; _music = NULL; @@ -133,6 +134,7 @@ SagaEngine::~SagaEngine() { delete _render; delete _music; delete _sound; + delete _driver; delete _gfx; delete _console; @@ -188,11 +190,11 @@ int SagaEngine::init() { bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); bool adlib = (midiDriver == MD_ADLIB); - MidiDriver *driver = MidiDriver::createMidi(midiDriver); + _driver = MidiDriver::createMidi(midiDriver); if (native_mt32) - driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - _music = new Music(this, _mixer, driver, _musicVolume); + _music = new Music(this, _mixer, _driver, _musicVolume); _music->setNativeMT32(native_mt32); _music->setAdlib(adlib); diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 4a5fae7ddb..6b6eb6b3fb 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -29,6 +29,7 @@ #include "engines/engine.h" #include "common/stream.h" +#include "sound/mididrv.h" #include "saga/gfx.h" #include "saga/list.h" @@ -531,6 +532,7 @@ public: SndRes *_sndRes; Sound *_sound; Music *_music; + MidiDriver *_driver; Anim *_anim; Render *_render; IsoMap *_isoMap; diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp index 7664af314f..088be34c72 100644 --- a/engines/saga/script.cpp +++ b/engines/saga/script.cpp @@ -150,6 +150,7 @@ Script::~Script() { debug(8, "Shutting down scripting subsystem."); _mainStrings.freeMem(); + _globalVoiceLUT.freeMem(); freeModules(); free(_modules); diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp index e9d002819c..be4f2a423d 100644 --- a/engines/saga/sprite.cpp +++ b/engines/saga/sprite.cpp @@ -74,6 +74,9 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) { Sprite::~Sprite(void) { debug(8, "Shutting down sprite subsystem..."); _mainSprites.freeMem(); + _inventorySprites.freeMem(); + _arrowSprites.freeMem(); + _saveReminderSprites.freeMem(); free(_decodeBuf); } -- cgit v1.2.3 From a596879c8ead93bc3dd8e812103d78819dd2a81a Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Thu, 12 Jun 2008 18:11:09 +0000 Subject: LURE: Fixed memory leaks in the LURE engine svn-id: r32675 --- engines/lure/lure.cpp | 9 +-------- engines/lure/sound.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/lure/lure.cpp b/engines/lure/lure.cpp index fa6323af07..ea760ddb4f 100644 --- a/engines/lure/lure.cpp +++ b/engines/lure/lure.cpp @@ -103,6 +103,7 @@ LureEngine::~LureEngine() { if (_initialised) { // Delete and deinitialise subsystems Surface::deinitialise(); + Sound.destroy(); delete _fights; delete _room; delete _menu; @@ -164,14 +165,6 @@ void LureEngine::pauseEngineIntern(bool pause) { } } -/* This is not being used - -void LureEngine::quitGame() { - _system->quit(); -} - -*/ - const char *LureEngine::generateSaveName(int slotNumber) { static char buffer[15]; diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp index 839298d1c5..285f66e4e2 100644 --- a/engines/lure/sound.cpp +++ b/engines/lure/sound.cpp @@ -85,8 +85,10 @@ SoundManager::~SoundManager() { if (_soundData) delete _soundData; - if (_driver) + if (_driver) { _driver->close(); + delete _driver; + } _driver = NULL; g_system->deleteMutex(_soundMutex); @@ -143,7 +145,7 @@ void SoundManager::bellsBodge() { Room &room = Room::getReference(); RoomData *roomData = res.getRoom(room.roomNumber()); - if (roomData->areaFlag != res.fieldList().getField(AREA_FLAG)) { + if (roomData && roomData->areaFlag != res.fieldList().getField(AREA_FLAG)) { res.fieldList().setField(AREA_FLAG, roomData->areaFlag); switch (roomData->areaFlag) { -- cgit v1.2.3 From 101105315e2c036c6edc2c5f2932eac8837fe14a Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Thu, 12 Jun 2008 18:52:43 +0000 Subject: CINE: Fixed memory leaks in the CINE engine svn-id: r32677 --- engines/cine/cine.cpp | 1 + engines/cine/pal.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'engines') diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 6cf9e2fb26..f6778b6457 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -70,6 +70,7 @@ CineEngine::~CineEngine() { } Common::clearAllSpecialDebugLevels(); + free(palPtr); free(partBuffer); free(textDataPtr); } diff --git a/engines/cine/pal.h b/engines/cine/pal.h index 70fcc0d98a..768cf0d27d 100644 --- a/engines/cine/pal.h +++ b/engines/cine/pal.h @@ -34,6 +34,8 @@ struct PalEntry { byte pal2[16]; }; +extern PalEntry *palPtr; + void loadPal(const char *fileName); void loadRelatedPalette(const char *fileName); -- cgit v1.2.3 From ad99e9b24989719b0da35e4162ea57982fd89a0a Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Thu, 12 Jun 2008 19:34:32 +0000 Subject: AGOS: Fixed a memory leak in the AGOS engine svn-id: r32679 --- engines/agos/agos.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'engines') diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index 7880d407b8..365f9fcde7 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -37,6 +37,7 @@ #include "sound/mididrv.h" #include "sound/mods/protracker.h" +#include "sound/audiocd.h" using Common::File; @@ -882,6 +883,8 @@ AGOSEngine::~AGOSEngine() { _midi.close(); delete _driver; + AudioCD.destroy(); + for (uint i = 0; i < _itemHeap.size(); i++) { delete[] _itemHeap[i]; } -- cgit v1.2.3 From 45525e7d187572d876636a8f82c57d768912d000 Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Thu, 12 Jun 2008 19:43:54 +0000 Subject: SCUMM: Fixed a memory leak in the SCUMM engine svn-id: r32680 --- engines/scumm/sound.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index fdd0598378..7500b16c87 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -89,6 +89,7 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer) Sound::~Sound() { stopCDTimer(); + AudioCD.destroy(); delete _sfxFile; } -- cgit v1.2.3 From 23fc803dad8d1e223c1a43fab076056e62fe201b Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Mon, 16 Jun 2008 17:34:58 +0000 Subject: AGOS: Found a system->quit(), changed to _quit=true svn-id: r32718 --- engines/agos/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index fd78c65002..c92f834a3b 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -280,7 +280,7 @@ void MoviePlayer::handleNextFrame() { _rightButtonDown = false; break; case Common::EVENT_QUIT: - _vm->_system->quit(); + _vm->_quit = true; break; default: break; -- cgit v1.2.3 From 8cb11a808a95a88c0a1f3542804e26dbc17d076a Mon Sep 17 00:00:00 2001 From: Christopher Page Date: Mon, 16 Jun 2008 19:55:59 +0000 Subject: Cleaned up some unnecessary comments svn-id: r32721 --- engines/lure/lure.h | 1 - engines/saga/interface.h | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/lure/lure.h b/engines/lure/lure.h index b4cec38ef3..1c5b40e54b 100644 --- a/engines/lure/lure.h +++ b/engines/lure/lure.h @@ -70,7 +70,6 @@ public: virtual int init(); virtual int go(); virtual void pauseEngineIntern(bool pause); - //void quitGame(); This is not being used Disk &disk() { return *_disk; } diff --git a/engines/saga/interface.h b/engines/saga/interface.h index 2e124c2d10..2091c9f071 100644 --- a/engines/saga/interface.h +++ b/engines/saga/interface.h @@ -112,11 +112,7 @@ struct InterfacePanel { buttonsCount = 0; buttons = NULL; } -/* - ~InterfacePanel() { - sprites.freeMem(); - } -*/ + PanelButton *getButton(int index) { if ((index >= 0) && (index < buttonsCount)) { return &buttons[index]; -- cgit v1.2.3 From cca355acd73ca648309714ba2185876aea8eda23 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 17 Jun 2008 18:27:03 +0000 Subject: Removed duplicate code svn-id: r32727 --- engines/drascula/graphics.cpp | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) (limited to 'engines') diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 64591a856e..67993bfb6c 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -89,31 +89,21 @@ void DrasculaEngine::setCursorTable() { } void DrasculaEngine::loadPic(const char *NamePcc, byte *targetSurface, int colorCount) { - unsigned int con, x = 0; - unsigned int fExit = 0; - byte ch, rep; + uint dataSize = 0; + byte *pcxData; _arj.open(NamePcc); if (!_arj.isOpen()) error("missing game data %s %c", NamePcc, 7); - _arj.seek(128); - while (!fExit) { - ch = _arj.readByte(); - rep = 1; - if ((ch & 192) == 192) { - rep = (ch & 63); - ch = _arj.readByte(); - } - for (con = 0; con < rep; con++) { - x++; - if (x > 64000) { - fExit = 1; - break; - } - *targetSurface++ = ch; - } - } + dataSize = _arj.size() - 128 - (256 * 3); + pcxData = (byte *)malloc(dataSize); + + _arj.seek(128, SEEK_SET); + _arj.read(pcxData, dataSize); + + decodeRLE(pcxData, targetSurface); + free(pcxData); for (int i = 0; i < 256; i++) { cPal[i * 3 + 0] = _arj.readByte(); @@ -141,7 +131,6 @@ void DrasculaEngine::showFrame(bool firstFrame) { memcpy(prevFrame, VGA, 64000); decodeRLE(pcxData, VGA); - free(pcxData); if (!firstFrame) -- cgit v1.2.3 From 8541fb51480c6748f06f1647f38d98a2aa00b9b6 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 17 Jun 2008 21:52:58 +0000 Subject: Possible fix for bug #1979086 - "DRASCULA: Wrong language detection(?) and crash" svn-id: r32728 --- engines/drascula/animation.cpp | 2 +- engines/drascula/drascula.h | 4 ++-- engines/drascula/palette.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'engines') diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index feb6cb93ca..b0877a2e3e 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -1669,7 +1669,7 @@ void DrasculaEngine::animation_12_5() { 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}; int color, component; - char fade; + signed char fade; playMusic(26); updateRoom(); diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index ce67cc2c0e..567d894b75 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -245,7 +245,7 @@ public: void loadPic(const char *NamePcc, byte *targetSurface, int colorCount = 1); - typedef char DacPalette256[256][3]; + typedef signed char DacPalette256[256][3]; void setRGB(byte *pal, int plt); void assignDefaultPalette(); @@ -397,7 +397,7 @@ public: void playFLI(const char *filefli, int vel); void fadeFromBlack(int fadeSpeed); void fadeToBlack(int fadeSpeed); - char adjustToVGA(char value); + signed char adjustToVGA(signed char value); void color_abc(int cl); void centerText(const char *,int,int); void playSound(int soundNum); diff --git a/engines/drascula/palette.cpp b/engines/drascula/palette.cpp index ad57bce618..6a93f21e55 100644 --- a/engines/drascula/palette.cpp +++ b/engines/drascula/palette.cpp @@ -87,12 +87,12 @@ void DrasculaEngine::color_abc(int cl) { setPalette((byte *)&gamePalette); } -char DrasculaEngine::adjustToVGA(char value) { +signed char DrasculaEngine::adjustToVGA(signed char value) { return (value & 0x3F) * (value > 0); } void DrasculaEngine::fadeToBlack(int fadeSpeed) { - char fade; + signed char fade; unsigned int color, component; DacPalette256 palFade; @@ -110,7 +110,7 @@ void DrasculaEngine::fadeToBlack(int fadeSpeed) { } void DrasculaEngine::fadeFromBlack(int fadeSpeed) { - char fade; + signed char fade; unsigned int color, component; DacPalette256 palFade; @@ -186,7 +186,7 @@ void DrasculaEngine::setDarkPalette() { } void DrasculaEngine::setPaletteBase(int darkness) { - char fade; + signed char fade; unsigned int color, component; for (fade = darkness; fade >= 0; fade--) { -- cgit v1.2.3 From 9b910eedba4b7f01e9b0aa7c90831904409ba98a Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 18 Jun 2008 03:31:13 +0000 Subject: Fixed a small discrepancy in Delphine unpacker's command 00b's documentation (Parameter range is 1..8, not 1..9). svn-id: r32730 --- engines/cine/unpack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cine/unpack.cpp b/engines/cine/unpack.cpp index dcd3181242..5d85ff6cab 100644 --- a/engines/cine/unpack.cpp +++ b/engines/cine/unpack.cpp @@ -111,7 +111,7 @@ bool CineUnpacker::unpack(const byte *src, uint srcLen, byte *dst, uint dstLen) while (_dst >= _dstBegin && !_error) { /* Bits => Action: - 0 0 => unpackRawBytes(3 bits + 1) i.e. unpackRawBytes(1..9) + 0 0 => unpackRawBytes(3 bits + 1) i.e. unpackRawBytes(1..8) 1 1 1 => unpackRawBytes(8 bits + 9) i.e. unpackRawBytes(9..264) 0 1 => copyRelocatedBytes(8 bits, 2) i.e. copyRelocatedBytes(0..255, 2) 1 0 0 => copyRelocatedBytes(9 bits, 3) i.e. copyRelocatedBytes(0..511, 3) -- cgit v1.2.3 From 7bceafb3f2cff0f80b5b489d21e8bff90ddb5fbe Mon Sep 17 00:00:00 2001 From: Benjamin Haisch Date: Wed, 18 Jun 2008 11:01:51 +0000 Subject: - Fixed sprite drawing in Rodney's Funscreen - Handle mouse button up events and event number fixes in MadeEngine::handleEvents() - Use milliseconds -> game ticks calculation based on Windows version of the original engine - "Rodney's Fun Screen" -> "Rodney's Funscreen" svn-id: r32731 --- engines/made/database.cpp | 13 +++++-------- engines/made/detection.cpp | 4 ++-- engines/made/made.cpp | 26 +++++++++++++------------- engines/made/made.h | 1 + engines/made/scriptfuncs.cpp | 10 +++++----- 5 files changed, 26 insertions(+), 28 deletions(-) (limited to 'engines') diff --git a/engines/made/database.cpp b/engines/made/database.cpp index 55e0e90732..3497b5b46f 100644 --- a/engines/made/database.cpp +++ b/engines/made/database.cpp @@ -88,10 +88,7 @@ int16 Object::getVectorItem(int16 index) { if (getClass() == 0x7FFF) { byte *vector = (byte*)getData(); return vector[index]; - } else if (getClass() == 0x7FFE) { - int16 *vector = (int16*)getData(); - return READ_LE_UINT16(&vector[index]); - } else if (getClass() < 0x7FFE) { + } else if (getClass() <= 0x7FFE) { int16 *vector = (int16*)getData(); return READ_LE_UINT16(&vector[index]); } else { @@ -372,7 +369,7 @@ void GameDatabaseV2::load(Common::SeekableReadStream &sourceS) { debug(2, "textOffs = %08X; textSize = %08X; objectCount = %d; varObjectCount = %d; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d\n", textOffs, textSize, objectCount, varObjectCount, _gameStateSize, objectsOffs, objectsSize); _gameState = new byte[_gameStateSize + 2]; - memset(_gameState, 0, _gameStateSize); + memset(_gameState, 0, _gameStateSize + 2); setVar(1, objectCount); sourceS.seek(textOffs); @@ -441,7 +438,7 @@ int16 *GameDatabaseV2::findObjectProperty(int16 objectIndex, int16 propertyId, i int16 *propPtr2 = prop + count2; // First see if the property exists in the given object - while (count2-- > 0) { + while (count2--) { if ((READ_LE_UINT16(prop) & 0x7FFF) == propertyId) { propertyFlag = obj->getFlags() & 1; return propPtr1; @@ -467,8 +464,8 @@ int16 *GameDatabaseV2::findObjectProperty(int16 objectIndex, int16 propertyId, i propPtr1 = propPtr2 + count1 - count2; int16 *propertyPtr = prop + count1; - while (count2-- > 0) { - if (!(READ_LE_UINT16(prop) & 0x8000)) { + while (count2--) { + if ((READ_LE_UINT16(prop) & 0x8000) == 0) { if ((READ_LE_UINT16(prop) & 0x7FFF) == propertyId) { propertyFlag = obj->getFlags() & 1; return propPtr1; diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp index dc7dbdee87..e5870bfeec 100644 --- a/engines/made/detection.cpp +++ b/engines/made/detection.cpp @@ -65,7 +65,7 @@ static const PlainGameDescriptor madeGames[] = { {"manhole", "The Manhole"}, {"rtz", "Return to Zork"}, {"lgop2", "Leather Goddesses of Phobos 2"}, - {"rodney", "Rodney's Fun Screen"}, + {"rodney", "Rodney's Funscreen"}, {0, 0} }; @@ -278,7 +278,7 @@ static const MadeGameDescription gameDescriptions[] = { }, { - // Rodney's Fun Screen + // Rodney's Funscreen { "rodney", "", diff --git a/engines/made/made.cpp b/engines/made/made.cpp index 59ec487c37..dc45dc4d2f 100644 --- a/engines/made/made.cpp +++ b/engines/made/made.cpp @@ -148,27 +148,31 @@ int MadeEngine::init() { return 0; } +int16 MadeEngine::getTicks() { + return g_system->getMillis() * 30 / 1000; +} + int16 MadeEngine::getTimer(int16 timerNum) { if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers) && _timers[timerNum - 1] != -1) - return (_system->getMillis() - _timers[timerNum - 1]) / kTimerResolution; + return (getTicks() - _timers[timerNum - 1]); else return 32000; } void MadeEngine::setTimer(int16 timerNum, int16 value) { if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers)) - _timers[timerNum - 1] = value * kTimerResolution; + _timers[timerNum - 1] = value; } void MadeEngine::resetTimer(int16 timerNum) { if (timerNum > 0 && timerNum <= ARRAYSIZE(_timers)) - _timers[timerNum - 1] = _system->getMillis(); + _timers[timerNum - 1] = getTicks(); } int16 MadeEngine::allocTimer() { for (int i = 0; i < ARRAYSIZE(_timers); i++) { if (_timers[i] == -1) { - _timers[i] = _system->getMillis(); + _timers[i] = getTicks(); return i + 1; } } @@ -202,24 +206,20 @@ void MadeEngine::handleEvents() { break; case Common::EVENT_LBUTTONDOWN: - _eventNum = 1; + _eventNum = 2; break; - /* case Common::EVENT_LBUTTONUP: - _eventNum = 2; // TODO: Is this correct? + _eventNum = 1; break; - */ case Common::EVENT_RBUTTONDOWN: - _eventNum = 3; + _eventNum = 4; break; - /* case Common::EVENT_RBUTTONUP: - eventNum = 4; // TODO: Is this correct? + _eventNum = 3; break; - */ case Common::EVENT_KEYDOWN: _eventKey = event.kbd.ascii; @@ -239,7 +239,7 @@ void MadeEngine::handleEvents() { } } - + AudioCD.updateCD(); } diff --git a/engines/made/made.h b/engines/made/made.h index 461941e5cf..971961c867 100644 --- a/engines/made/made.h +++ b/engines/made/made.h @@ -120,6 +120,7 @@ public: int _engineVersion; int32 _timers[50]; + int16 getTicks(); int16 getTimer(int16 timerNum); void setTimer(int16 timerNum, int16 value); void resetTimer(int16 timerNum); diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp index 932447a1eb..d697e24b04 100644 --- a/engines/made/scriptfuncs.cpp +++ b/engines/made/scriptfuncs.cpp @@ -106,7 +106,7 @@ void ScriptFunctions::setupExternalsTable() { External(sfStopSound); External(sfPlayVoice); - if (_vm->getGameID() == GID_MANHOLE || _vm->getGameID() == GID_RTZ) { + if (_vm->getGameID() == GID_MANHOLE || _vm->getGameID() == GID_RTZ || _vm->getGameID() == GID_RODNEY) { External(sfPlayCd); External(sfStopCd); External(sfGetCdStatus); @@ -332,7 +332,7 @@ int16 ScriptFunctions::sfAddSprite(int16 argc, int16 *argv) { if (_vm->getGameID() == GID_RTZ) { // Unused in RTZ return 0; - } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) { + } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE || _vm->getGameID() == GID_RODNEY) { return _vm->_screen->addToSpriteList(argv[2], argv[1], argv[0]); } else { return 0; @@ -341,7 +341,7 @@ int16 ScriptFunctions::sfAddSprite(int16 argc, int16 *argv) { int16 ScriptFunctions::sfFreeAnim(int16 argc, int16 *argv) { _vm->_screen->clearChannels(); - if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) { + if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE || _vm->getGameID() == GID_RODNEY) { _vm->_screen->clearSpriteList(); } return 0; @@ -350,7 +350,7 @@ int16 ScriptFunctions::sfFreeAnim(int16 argc, int16 *argv) { int16 ScriptFunctions::sfDrawSprite(int16 argc, int16 *argv) { if (_vm->getGameID() == GID_RTZ) { return _vm->_screen->drawSprite(argv[2], argv[1], argv[0]); - } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) { + } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE || _vm->getGameID() == GID_RODNEY) { SpriteListItem item = _vm->_screen->getFromSpriteList(argv[2]); int16 channelIndex = _vm->_screen->drawSprite(item.index, argv[1] - item.xofs, argv[0] - item.yofs); _vm->_screen->setChannelUseMask(channelIndex); @@ -409,7 +409,7 @@ int16 ScriptFunctions::sfDrawText(int16 argc, int16 *argv) { if (_vm->getGameID() == GID_RTZ) { text = _vm->_dat->getObjectString(argv[argc - 1]); - } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE) { + } if (_vm->getGameID() == GID_LGOP2 || _vm->getGameID() == GID_MANHOLE || _vm->getGameID() == GID_RODNEY) { text = _vm->_dat->getString(argv[argc - 1]); } -- cgit v1.2.3 From 07bcb5179ccad90d18a9e5a8f3c86d9d7ee3f910 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 18 Jun 2008 21:02:52 +0000 Subject: Renamed M4Surface::empty() to clear() (two reason: empty is not a verb, and in class String it is used for a bool property) svn-id: r32733 --- engines/m4/converse.cpp | 2 +- engines/m4/graphics.cpp | 6 +++--- engines/m4/graphics.h | 2 +- engines/m4/m4_views.cpp | 2 +- engines/m4/mads_anim.cpp | 16 ++++++++-------- engines/m4/viewmgr.cpp | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) (limited to 'engines') diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index 729af6c40f..a07a175066 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -153,7 +153,7 @@ void ConversationView::setNode(int32 nodeIndex) { void ConversationView::onRefresh(RectList *rects, M4Surface *destSurface) { //if (!this->isVisible()) // return; - empty(); + clear(); if (_entriesShown) { // Write out the conversation options diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp index beda178344..1846f1c1e7 100644 --- a/engines/m4/graphics.cpp +++ b/engines/m4/graphics.cpp @@ -320,7 +320,7 @@ byte *M4Surface::getBasePtr(int x, int y) { void M4Surface::freeData() { } -void M4Surface::empty() { +void M4Surface::clear() { Common::set_to((byte *) pixels, (byte *) pixels + w * h, _vm->_palette->BLACK); } @@ -389,7 +389,7 @@ void M4Surface::loadBackgroundRiddle(const char *sceneName) { } void M4Surface::loadBackground(int sceneNumber, RGBList **palData) { - this->empty(); // clear previous scene + clear(); // clear previous scene if (_vm->isM4() || (_vm->getGameType() == GType_RexNebular)) { char resourceName[20]; @@ -502,7 +502,7 @@ void M4Surface::madsLoadBackground(int roomNumber, RGBList **palData) { //printf("Tile: %i, compressed size: %i\n", i, compressedTileDataSize); - newTile->empty(); + newTile->clear(); byte *compressedTileData = new byte[compressedTileDataSize]; diff --git a/engines/m4/graphics.h b/engines/m4/graphics.h index 60e608c148..84fc77656f 100644 --- a/engines/m4/graphics.h +++ b/engines/m4/graphics.h @@ -128,7 +128,7 @@ public: byte *getData(); byte *getBasePtr(int x, int y); void freeData(); - void empty(); + void clear(); void frameRect(const Common::Rect &r, uint8 color); void fillRect(const Common::Rect &r, uint8 color); void copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY, diff --git a/engines/m4/m4_views.cpp b/engines/m4/m4_views.cpp index 9bf964ee96..777356467b 100644 --- a/engines/m4/m4_views.cpp +++ b/engines/m4/m4_views.cpp @@ -331,7 +331,7 @@ bool GameInterfaceView::onEvent(M4EventType eventType, int param, int x, int y, } void GameInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) { - empty(); + clear(); _statusText.onRefresh(); _inventory.onRefresh(); diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp index 3e80d0f1e0..c51daa84c4 100644 --- a/engines/m4/mads_anim.cpp +++ b/engines/m4/mads_anim.cpp @@ -61,9 +61,9 @@ TextviewView::TextviewView(M4Engine *vm): _vm->_font->setColors(5, 6, 4); - empty(); - _bgSurface.empty(); - _textSurface.empty(); + clear(); + _bgSurface.clear(); + _textSurface.clear(); int y = (height() - MADS_SURFACE_HEIGHT) / 2; setColor(2); @@ -83,8 +83,8 @@ TextviewView::~TextviewView() { } void TextviewView::reset() { - _bgSurface.empty(); - _textSurface.empty(); + _bgSurface.clear(); + _textSurface.clear(); _animating = false; _panX = 0; _panY = 0; @@ -456,8 +456,8 @@ AnimviewView::AnimviewView(M4Engine *vm): // Set up system palette colors _vm->_palette->setMadsSystemPalette(); - empty(); - _bgSurface.empty(); + clear(); + _bgSurface.clear(); int y = (height() - MADS_SURFACE_HEIGHT) / 2; setColor(2); @@ -471,7 +471,7 @@ AnimviewView::~AnimviewView() { } void AnimviewView::reset() { - _bgSurface.empty(); + _bgSurface.clear(); _soundDriverLoaded = false; } diff --git a/engines/m4/viewmgr.cpp b/engines/m4/viewmgr.cpp index 3a8b5d24a8..b74e598c6c 100644 --- a/engines/m4/viewmgr.cpp +++ b/engines/m4/viewmgr.cpp @@ -380,7 +380,7 @@ void ViewManager::updateState() { } void ViewManager::refreshAll() { - _vm->_screen->empty(); + _vm->_screen->clear(); for (ListIterator i = _views.begin(); i != _views.end(); ++i) { View *v = *i; -- cgit v1.2.3 From f1b0e379d1977df831bfd3659d73fa57588a0279 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 19 Jun 2008 16:27:49 +0000 Subject: Only try playing object videos when the game version supports that (only Woodruff, for now) svn-id: r32737 --- engines/gob/scenery.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index 6b52cdbbd6..33e540ace4 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -595,7 +595,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, int16 destX; int16 destY; - if (animation < 0) { + if ((_vm->getGameType() == kGameTypeWoodruff) && (animation < 0)) { // Object video if (flags & 1) { // Do capture @@ -736,6 +736,8 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, return; } + if ((animation < 0) || (animation >= 10)) + return; if ((_animPictCount[animation] == 0) || (layer < 0)) return; if (layer >= _animations[animation].layersCount) -- cgit v1.2.3 From 0c6c7de3554a65a22324a0aa89b111aa7f2fa79f Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 19 Jun 2008 22:54:17 +0000 Subject: Fixed a palette issue in Lost in Time svn-id: r32738 --- engines/gob/videoplayer.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index 909d39a63b..aa47e6cf84 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -588,12 +588,14 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, } void VideoPlayer::copyPalette(CoktelVideo &video, int16 palStart, int16 palEnd) { - if ((palStart != -1) && (palEnd != -1)) - memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + palStart * 3, - video.getPalette() + palStart * 3, - (palEnd - palStart + 1) * 3); - else - memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, video.getPalette(), 768); + if (palStart < 0) + palStart = 0; + if (palEnd < 0) + palEnd = 255; + + memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + palStart * 3, + video.getPalette() + palStart * 3, + (palEnd - palStart + 1) * 3); } void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, -- cgit v1.2.3 From 446f66807f078b574cb31d87bebdcff2f55953fa Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 22 Jun 2008 05:42:22 +0000 Subject: Circular references between Zone/Animation and Command are now manually removed, to allow the objects - which are stored into SharedPtr's - to be deallocated. svn-id: r32744 --- engines/parallaction/parallaction.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 25ebe4263d..4f586961a6 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -86,7 +86,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam Parallaction::~Parallaction() { clearSet(_commandOpcodes); clearSet(_instructionOpcodes); - + delete _debugger; delete _globalTable; delete _callableNames; @@ -95,7 +95,7 @@ Parallaction::~Parallaction() { freeCharacter(); destroyInventory(); - + delete _localFlagNames; delete _gfx; delete _soundMan; @@ -193,6 +193,9 @@ AnimationPtr Parallaction::findAnimation(const char *name) { } void Parallaction::freeAnimations() { + for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { + (*it)->_commands.clear(); // See comment for freeZones(), about circular references. + } _location._animations.clear(); return; } @@ -479,6 +482,9 @@ void Parallaction::freeZones() { debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name); it++; } else { + (*it)->_commands.clear(); // Since commands may reference zones, and both commands and zones are kept stored into + // SharedPtr's, we need to kill commands explicitly to destroy any potential circular + // reference. it = _location._zones.erase(it); } } -- cgit v1.2.3 From 3be9449e6730ec296091e7caaf5dd8f277d95bc9 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 22 Jun 2008 12:31:05 +0000 Subject: this should fix bug #1997149: KYRA2: no text in spellbook svn-id: r32750 --- engines/kyra/gui_hof.cpp | 22 +++++++++++++++++++--- engines/kyra/kyra_hof.cpp | 3 +++ 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 555934cb7f..e94f88a1d2 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -455,13 +455,29 @@ void KyraEngine_HoF::showBookPage() { char filename[16]; sprintf(filename, "PAGE%.01X.", _bookCurPage); - strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); + strcat(filename, _languageExtension[_lang]); uint8 *leftPage = _res->fileData(filename, 0); + if (!leftPage) { + // some floppy version use a TXT extension + sprintf(filename, "PAGE%.01X.", _bookCurPage); + strcat(filename, "TXT"); + leftPage = _res->fileData(filename, 0); + } + int leftPageY = _bookPageYOffset[_bookCurPage]; sprintf(filename, "PAGE%.01X.", _bookCurPage+1); - strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); - uint8 *rightPage = (_bookCurPage != _bookMaxPage) ? _res->fileData(filename, 0) : 0; + strcat(filename, _languageExtension[_lang]); + uint8 *rightPage = 0; + if (_bookCurPage != _bookMaxPage) { + rightPage = _res->fileData(filename, 0); + if (!rightPage) { + sprintf(filename, "PAGE%.01X.", _bookCurPage); + strcat(filename, "TXT"); + rightPage = _res->fileData(filename, 0); + } + } + int rightPageY = _bookPageYOffset[_bookCurPage+1]; _screen->hideMouse(); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 57f0dcc24a..a8b8c0dced 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -296,6 +296,9 @@ int KyraEngine_HoF::go() { _res->loadFileList("FILEDATA.FDT"); else _res->loadFileList(_ingamePakList, _ingamePakListSize); + + if (_flags.platform == Common::kPlatformPC98) + _res->loadPakFile("AUDIO.PAK"); } _menuDirectlyToLoad = (_menuChoice == 3) ? true : false; -- cgit v1.2.3 From 12d7a5e679683f537d35075a5f67e57817621102 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 22 Jun 2008 12:36:38 +0000 Subject: Cleanup. svn-id: r32751 --- engines/kyra/gui_hof.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index e94f88a1d2..7d56743af5 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -454,26 +454,22 @@ void KyraEngine_HoF::loadBookBkgd() { void KyraEngine_HoF::showBookPage() { char filename[16]; - sprintf(filename, "PAGE%.01X.", _bookCurPage); - strcat(filename, _languageExtension[_lang]); + sprintf(filename, "PAGE%.01X.%s", _bookCurPage, _languageExtension[_lang]); uint8 *leftPage = _res->fileData(filename, 0); if (!leftPage) { // some floppy version use a TXT extension - sprintf(filename, "PAGE%.01X.", _bookCurPage); - strcat(filename, "TXT"); + sprintf(filename, "PAGE%.01X.TXT", _bookCurPage); leftPage = _res->fileData(filename, 0); } int leftPageY = _bookPageYOffset[_bookCurPage]; - sprintf(filename, "PAGE%.01X.", _bookCurPage+1); - strcat(filename, _languageExtension[_lang]); + sprintf(filename, "PAGE%.01X.%s", _bookCurPage+1, _languageExtension[_lang]); uint8 *rightPage = 0; if (_bookCurPage != _bookMaxPage) { rightPage = _res->fileData(filename, 0); if (!rightPage) { - sprintf(filename, "PAGE%.01X.", _bookCurPage); - strcat(filename, "TXT"); + sprintf(filename, "PAGE%.01X.TXT", _bookCurPage); rightPage = _res->fileData(filename, 0); } } -- cgit v1.2.3 From 6360c392f25d880f8905dedaee0f34889817acaf Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 22 Jun 2008 12:41:46 +0000 Subject: missed this in last commit (bug fix for #1997149) svn-id: r32753 --- engines/kyra/script_hof.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index 91fbfb3e49..11b97afbe6 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -800,9 +800,15 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) { _screen->fadeToBlack(0x14); sprintf(filename, "LETTER%.1d.", letter); - strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT"); - + strcat(filename, _languageExtension[_lang]); uint8 *letterBuffer = _res->fileData(filename, 0); + if (!letterBuffer) { + // some floppy versions use a TXT extension + sprintf(filename, "LETTER%.1d.", letter); + strcat(filename, "TXT"); + letterBuffer = _res->fileData(filename, 0); + } + if (letterBuffer) { bookDecodeText(letterBuffer); bookPrintText(2, letterBuffer, 0xC, 0xA, 0x20); -- cgit v1.2.3 From 51000de1626090ac61ace8fa9bbfe233117219cc Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 22 Jun 2008 12:43:32 +0000 Subject: Cleanup. svn-id: r32754 --- engines/kyra/script_hof.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index 11b97afbe6..94f160d11f 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -799,13 +799,11 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) { _screen->fadeToBlack(0x14); - sprintf(filename, "LETTER%.1d.", letter); - strcat(filename, _languageExtension[_lang]); + sprintf(filename, "LETTER%.1d.%s", letter, _languageExtension[_lang]); uint8 *letterBuffer = _res->fileData(filename, 0); if (!letterBuffer) { // some floppy versions use a TXT extension - sprintf(filename, "LETTER%.1d.", letter); - strcat(filename, "TXT"); + sprintf(filename, "LETTER%.1d.TXT", letter); letterBuffer = _res->fileData(filename, 0); } -- cgit v1.2.3 From 4e2e46f16cd6480edc3509edfe4b49bde0268756 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 22 Jun 2008 14:31:45 +0000 Subject: Fixed leak when loading sounds for Amiga version of Nippon Safes. svn-id: r32756 --- engines/parallaction/disk_ns.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index cdbe3458a7..8f4f6d8e20 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -1395,9 +1395,7 @@ Common::ReadStream* AmigaDisk_ns::loadSound(const char* name) { char path[PATH_LEN]; sprintf(path, "%s.snd", name); - openArchivedFile(path); - - return new DummyArchiveStream(_resArchive); + return openArchivedFile(path); } } // namespace Parallaction -- cgit v1.2.3 From d2609258ccaf536cc4178d1e9c690ad472ae877c Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 22 Jun 2008 14:46:08 +0000 Subject: Added constructor and destructor to Dialogue, thus fixing a long standing leak. svn-id: r32757 --- engines/parallaction/objects.cpp | 10 ++++++++++ engines/parallaction/objects.h | 3 +++ 2 files changed, 13 insertions(+) (limited to 'engines') diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index cac31911f4..5b5aa85584 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -207,6 +207,16 @@ uint16 Zone::height() const { return _bottom - _top; } +Dialogue::Dialogue() { + memset(_questions, 0, sizeof(_questions)); +} + +Dialogue::~Dialogue() { + for (int i = 0; i < NUM_QUESTIONS; i++) { + delete _questions[i]; + } +} + Answer::Answer() { _text = NULL; _mood = 0; diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index afa6cc5ed5..2bc9df0bbe 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -181,6 +181,9 @@ struct Question { struct Dialogue { Question *_questions[NUM_QUESTIONS]; + + Dialogue(); + ~Dialogue(); }; struct GetData { // size = 24 -- cgit v1.2.3 From 9194f391854466dd5c54341fcc6ba1d5f4ca6eaa Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 22 Jun 2008 17:36:14 +0000 Subject: Fixed 2 MSVC warnings (potentially undefined behavior and possibly uninitialized variable used) svn-id: r32758 --- engines/parallaction/dialogue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index b9dea60dc0..903c71907c 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -268,11 +268,11 @@ int16 DialogueManager::selectAnswer() { } int oldSelection = -1; - int selection; + int selection = 0; uint32 event; Common::Point p; - while (_engineFlags & kEngineQuit == 0) { + while ((_engineFlags & kEngineQuit) == 0) { _vm->_input->readInput(); _vm->_input->getCursorPos(p); -- cgit v1.2.3 From 28e32bb7cb6df6610e137500c0187d4ba36d8bdf Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 24 Jun 2008 13:21:22 +0000 Subject: Fix for bug #2001193. Character confirmation screen didn't appear and game crashed because too many strings were added to the draw list. svn-id: r32762 --- engines/parallaction/callables_ns.cpp | 5 +++++ engines/parallaction/gui_ns.cpp | 2 ++ engines/parallaction/parallaction.h | 3 +++ engines/parallaction/parallaction_ns.cpp | 8 +++++--- 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 68e6a70ffb..36f5b00c5b 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -417,6 +417,11 @@ void Parallaction_ns::_c_ridux(void *parm) { } void Parallaction_ns::_c_testResult(void *parm) { + if (_inTestResult) { + return; + } + _inTestResult = true; + _gfx->updateScreen(); _disk->selectArchive("disk1"); diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 1d4d44fa46..9c48586dbc 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -166,6 +166,8 @@ void Parallaction_ns::guiStart() { } void Parallaction_ns::selectStartLocation() { + _inTestResult = false; + int character = guiSelectCharacter(); if (character == -1) error("invalid character selected from menu screen"); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 5ae1386378..f9c2c86a1b 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -548,6 +548,9 @@ private: ZonePtr _moveSarcExaZones[5]; AnimationPtr _rightHandAnim; + bool _inTestResult; + + // common callables void _c_play_boogie(void*); void _c_startIntro(void*); diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index f346a278f7..59b9465d0a 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -147,6 +147,8 @@ int Parallaction_ns::init() { num_foglie = 0; + _inTestResult = false; + _location._animations.push_front(_char._ani); Parallaction::init(); @@ -156,7 +158,7 @@ int Parallaction_ns::init() { Parallaction_ns::~Parallaction_ns() { freeFonts(); - + delete _locationParser; delete _programParser; delete _mouseComposedArrow; @@ -235,10 +237,10 @@ int Parallaction_ns::go() { _globalTable = _disk->loadTable("global"); guiStart(); - + if (_engineFlags & kEngineQuit) return 0; - + changeLocation(_location._name); if (_engineFlags & kEngineQuit) -- cgit v1.2.3 From df1aa7809aad2a6b0404d57aeb9d0c5a423fd91b Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 24 Jun 2008 13:59:48 +0000 Subject: Added const to some static data. svn-id: r32763 --- engines/kyra/animator_lok.cpp | 4 ++-- engines/kyra/gui_lok.cpp | 10 +++++----- engines/kyra/gui_lok.h | 2 ++ engines/kyra/items_lok.cpp | 2 +- engines/kyra/scene_hof.cpp | 4 ++-- engines/kyra/scene_lok.cpp | 4 ++-- engines/kyra/script.cpp | 2 +- engines/kyra/script_tim.cpp | 2 +- engines/kyra/seqplayer.cpp | 4 ++-- engines/kyra/sound_towns.cpp | 2 +- 10 files changed, 19 insertions(+), 17 deletions(-) (limited to 'engines') diff --git a/engines/kyra/animator_lok.cpp b/engines/kyra/animator_lok.cpp index 1baa78b203..75d5537e4a 100644 --- a/engines/kyra/animator_lok.cpp +++ b/engines/kyra/animator_lok.cpp @@ -665,7 +665,7 @@ void Animator_LoK::animRefreshNPC(int character) { void Animator_LoK::setCharacterDefaultFrame(int character) { debugC(9, kDebugLevelAnimator, "Animator_LoK::setCharacterDefaultFrame()"); - static uint16 initFrameTable[] = { + static const uint16 initFrameTable[] = { 7, 41, 77, 0, 0 }; assert(character < ARRAYSIZE(initFrameTable)); @@ -678,7 +678,7 @@ void Animator_LoK::setCharacterDefaultFrame(int character) { void Animator_LoK::setCharactersHeight() { debugC(9, kDebugLevelAnimator, "Animator_LoK::setCharactersHeight()"); - static int8 initHeightTable[] = { + static const int8 initHeightTable[] = { 48, 40, 48, 47, 56, 44, 42, 47, 38, 35, 40 diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 6fa30c9e9a..35b343fc25 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -188,6 +188,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) { #pragma mark - GUI_LoK::GUI_LoK(KyraEngine_LoK *vm, Screen_LoK *screen) : GUI(vm), _vm(vm), _screen(screen) { + _lastScreenUpdate = 0; _menu = 0; initStaticResource(); _scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::scrollUp); @@ -479,7 +480,6 @@ int GUI_LoK::buttonMenuCallback(Button *caller) { void GUI_LoK::getInput() { Common::Event event; - static uint32 lastScreenUpdate = 0; uint32 now = _vm->_system->getMillis(); _mouseWheel = 0; @@ -496,7 +496,7 @@ void GUI_LoK::getInput() { break; case Common::EVENT_MOUSEMOVE: _vm->_system->updateScreen(); - lastScreenUpdate = now; + _lastScreenUpdate = now; break; case Common::EVENT_WHEELUP: _mouseWheel = -1; @@ -512,9 +512,9 @@ void GUI_LoK::getInput() { } } - if (now - lastScreenUpdate > 50) { + if (now - _lastScreenUpdate > 50) { _vm->_system->updateScreen(); - lastScreenUpdate = now; + _lastScreenUpdate = now; } _vm->_system->delayMillis(3); @@ -1056,7 +1056,7 @@ void GUI_LoK::fadePalette() { if (_vm->gameFlags().platform == Common::kPlatformAmiga) return; - static int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; + static const int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; int index = 0; memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 607ef0b605..49081c7ae2 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -157,6 +157,8 @@ private: KyraEngine_LoK *_vm; Screen_LoK *_screen; + uint32 _lastScreenUpdate; + bool _menuRestoreScreen; uint8 _toplevelMenu; int _savegameOffset; diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp index 8eb62c20c2..2c2903d0b3 100644 --- a/engines/kyra/items_lok.cpp +++ b/engines/kyra/items_lok.cpp @@ -39,7 +39,7 @@ namespace Kyra { int KyraEngine_LoK::findDuplicateItemShape(int shape) { - static uint8 dupTable[] = { + static const uint8 dupTable[] = { 0x48, 0x46, 0x49, 0x47, 0x4a, 0x46, 0x4b, 0x47, 0x4c, 0x46, 0x4d, 0x47, 0x5b, 0x5a, 0x5c, 0x5a, 0x5d, 0x5a, 0x5e, 0x5a, 0xFF, 0xFF diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp index 1882386b03..62df683ea2 100644 --- a/engines/kyra/scene_hof.cpp +++ b/engines/kyra/scene_hof.cpp @@ -723,7 +723,7 @@ void KyraEngine_HoF::fadeScenePal(int srcIndex, int delayTime) { bool KyraEngine_HoF::lineIsPassable(int x, int y) { debugC(9, kDebugLevelMain, "KyraEngine_HoF::lineIsPassable(%d, %d)", x, y); - static int unkTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 }; + static const int widthTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 }; if (_pathfinderFlag & 2) { if (x >= 320) @@ -743,7 +743,7 @@ bool KyraEngine_HoF::lineIsPassable(int x, int y) { if (y > 143) return false; - int unk1 = unkTable[getScale(x, y) >> 5]; + int unk1 = widthTable[getScale(x, y) >> 5]; if (y < 0) y = 0; diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp index e4ae67f751..53c269a926 100644 --- a/engines/kyra/scene_lok.cpp +++ b/engines/kyra/scene_lok.cpp @@ -1144,11 +1144,11 @@ void KyraEngine_LoK::setCharactersInDefaultScene() { } void KyraEngine_LoK::setCharactersPositions(int character) { - static uint16 initXPosTable[] = { + static const uint16 initXPosTable[] = { 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B, 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042 }; - static uint8 initYPosTable[] = { + static const uint8 initYPosTable[] = { 0x00, 0xA2, 0x00, 0x42, 0x00, 0x67, 0x67, 0x60, 0x5A, 0x71, 0x76 diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index ef3e259cfa..a29cdc8ca3 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -35,7 +35,7 @@ namespace Kyra { EMCInterpreter::EMCInterpreter(KyraEngine_v1 *vm) : _vm(vm) { #define COMMAND(x) { &EMCInterpreter::x, #x } - static CommandEntry commandProcs[] = { + static const CommandEntry commandProcs[] = { // 0x00 COMMAND(cmd_jmpTo), COMMAND(cmd_setRetValue), diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 4ad6464424..6b82ba06de 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -34,7 +34,7 @@ namespace Kyra { TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) { #define COMMAND(x) { &TIMInterpreter::x, #x } #define COMMAND_UNIMPL() { 0, 0 } - static CommandEntry commandProcs[] = { + static const CommandEntry commandProcs[] = { // 0x00 COMMAND(cmd_initFunc0), COMMAND(cmd_stopCurFunc), diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp index 73d69ef10c..dfda5bf859 100644 --- a/engines/kyra/seqplayer.cpp +++ b/engines/kyra/seqplayer.cpp @@ -500,7 +500,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { debugC(9, kDebugLevelSequence, "SeqPlayer::seq_playSequence(%p, %d)", (const void *)seqData, skipSeq); assert(seqData); - static SeqEntry floppySeqProcs[] = { + static const SeqEntry floppySeqProcs[] = { // 0x00 SEQOP(3, s1_wsaOpen), SEQOP(2, s1_wsaClose), @@ -541,7 +541,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { SEQOP(1, s1_endOfScript) }; - static SeqEntry cdromSeqProcs[] = { + static const SeqEntry cdromSeqProcs[] = { // 0x00 SEQOP(3, s1_wsaOpen), SEQOP(2, s1_wsaClose), diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 4265533507..c0e4dd70a9 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -878,7 +878,7 @@ void MidiParser_EuD::parseNextEvent(EventInfo &info) { pos += 6; } } else if (cmd == 0xF2) { - static uint16 tickTable [] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; + static const uint16 tickTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; _baseTick += tickTable[_nextBaseTickStep >> 4] * ((_nextBaseTickStep & 0x0f) + 1); _nextBaseTickStep = pos[1]; pos += 6; -- cgit v1.2.3 From f1cacafc466ac8689a286d1e712f0ada67e9a994 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 24 Jun 2008 20:44:37 +0000 Subject: Fixed opcodes: - 0xA0: o2_addGfxElementType20 (Was o2_addGfxElementA0) Implemented opcodes: - 0xA1: o2_removeGfxElementType20 (Was o2_removeGfxElementA0) - 0xA2: o2_addGfxElementType21 (Was o2_opA2) - 0xA3: o2_removeGfxElementType21 (Was o2_opA3) NOTE: Drawing of type 21 overlay elements isn't coded yet. svn-id: r32769 --- engines/cine/object.cpp | 14 ++++++-------- engines/cine/object.h | 4 ++-- engines/cine/script.h | 8 ++++---- engines/cine/script_os.cpp | 38 ++++++++++++++++---------------------- 4 files changed, 28 insertions(+), 36 deletions(-) (limited to 'engines') diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index 7666f05352..96048f5214 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -122,24 +122,22 @@ void addOverlay(uint16 objIdx, uint16 param) { * \param objIdx Associate the overlay with this object * \param param source background index */ -void addGfxElementA0(int16 objIdx, int16 param) { +void addGfxElement(int16 objIdx, int16 param, int16 type) { Common::List::iterator it; overlay tmp; for (it = overlayList.begin(); it != overlayList.end(); ++it) { - // wtf?! - if (objectTable[it->objIdx].mask == objectTable[objIdx].mask && - (it->type == 2 || it->type == 3)) { + if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask || it->type == 2 || it->type == 3) { break; } } - if (it != overlayList.end() && it->objIdx == objIdx && it->type == 20 && it->x == param) { + if (it != overlayList.end() && it->objIdx == objIdx && it->type == type && it->x == param) { return; } tmp.objIdx = objIdx; - tmp.type = 20; + tmp.type = type; tmp.x = param; tmp.y = 0; tmp.width = 0; @@ -153,11 +151,11 @@ void addGfxElementA0(int16 objIdx, int16 param) { * \param param Remove overlay using this background * \todo Check that it works */ -void removeGfxElementA0(int16 objIdx, int16 param) { +void removeGfxElement(int16 objIdx, int16 param, int16 type) { Common::List::iterator it; for (it = overlayList.begin(); it != overlayList.end(); ++it) { - if (it->objIdx == objIdx && it->type == 20 && it->x == param) { + if (it->objIdx == objIdx && it->type == type && it->x == param) { overlayList.erase(it); return; } diff --git a/engines/cine/object.h b/engines/cine/object.h index e7de39649d..6252a628cb 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -62,8 +62,8 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue); void addOverlay(uint16 objIdx, uint16 param); int removeOverlay(uint16 objIdx, uint16 param); -void addGfxElementA0(int16 objIdx, int16 param); -void removeGfxElementA0(int16 objIdx, int16 param); +void addGfxElement(int16 objIdx, int16 param, int16 type); +void removeGfxElement(int16 objIdx, int16 param, int16 type); int16 getObjectParam(uint16 objIdx, uint16 paramIdx); diff --git a/engines/cine/script.h b/engines/cine/script.h index eeac0e8809..2b6acbba9b 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -258,10 +258,10 @@ protected: int o2_useBgScroll(); int o2_setAdditionalBgVScroll(); int o2_op9F(); - int o2_addGfxElementA0(); - int o2_removeGfxElementA0(); - int o2_opA2(); - int o2_opA3(); + int o2_addGfxElementType20(); + int o2_removeGfxElementType20(); + int o2_addGfxElementType21(); + int o2_removeGfxElementType21(); int o2_loadMask22(); int o2_unloadMask22(); diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index 319fca5d3c..ffc0da5790 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -240,10 +240,10 @@ const Opcode OSScript::_opcodeTable[] = { { &FWScript::o2_setAdditionalBgVScroll, "c" }, { &FWScript::o2_op9F, "ww" }, /* TODO: Name this opcode properly. */ /* A0 */ - { &FWScript::o2_addGfxElementA0, "ww" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_removeGfxElementA0, "ww" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_opA2, "ww" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_opA3, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_addGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_removeGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_addGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_removeGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */ /* A4 */ { &FWScript::o2_loadMask22, "b" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_unloadMask22, "b" }, /* TODO: Name this opcode properly. */ @@ -721,42 +721,36 @@ int FWScript::o2_op9F() { return 0; } -int FWScript::o2_addGfxElementA0() { +int FWScript::o2_addGfxElementType20() { uint16 param1 = getNextWord(); uint16 param2 = getNextWord(); - debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2); - addGfxElementA0(param1, param2); + debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType20(%d,%d)", _line, param1, param2); + addGfxElement(param1, param2, 20); return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_removeGfxElementA0() { +int FWScript::o2_removeGfxElementType20() { uint16 idx = getNextWord(); uint16 param = getNextWord(); - warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param); - removeGfxElementA0(idx, param); + debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType20(%d,%d)", _line, idx, param); + removeGfxElement(idx, param, 20); return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_opA2() { +int FWScript::o2_addGfxElementType21() { uint16 a = getNextWord(); uint16 b = getNextWord(); - warning("STUB: o2_opA2(%x, %x)", a, b); - // addGfxElementA2(); + debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType21(%d,%d)", _line, a, b); + addGfxElement(a, b, 21); return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_opA3() { +int FWScript::o2_removeGfxElementType21() { uint16 a = getNextWord(); uint16 b = getNextWord(); - warning("STUB: o2_opA3(%x, %x)", a, b); - // removeGfxElementA2(); + debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType21(%d,%d)", _line, a, b); + removeGfxElement(a, b, 21); return 0; } -- cgit v1.2.3 From 9654ee4fa3e6ba5fab6fda321542e150a27193b8 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 25 Jun 2008 08:36:07 +0000 Subject: Possible fix for (for the drascula engine) for bug #2001583 - "WINCE: CRUISE and DRASCULA engines can not be compiled" svn-id: r32777 --- engines/drascula/drascula.h | 2 +- engines/drascula/rooms.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'engines') diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index 567d894b75..8bb73d8dd1 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -328,7 +328,7 @@ public: int curHeight, curWidth, feetHeight; int talkHeight, talkWidth; int floorX1, floorY1, floorX2, floorY2; - int near, far; + int lowerLimit, upperLimit; int trackFinal, walkToObject; int objExit; int timeDiff, startTime; diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 6fe28bdbdc..37dddf4b7e 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -1672,8 +1672,8 @@ void DrasculaEngine::enterRoom(int roomIndex) { getIntFromLine(buffer, size, &floorY2); if (currentChapter != 2) { - getIntFromLine(buffer, size, &far); - getIntFromLine(buffer, size, &near); + getIntFromLine(buffer, size, &upperLimit); + getIntFromLine(buffer, size, &lowerLimit); } _arj.close(); @@ -1732,27 +1732,27 @@ void DrasculaEngine::enterRoom(int roomIndex) { if (currentChapter != 2) { for (l = 0; l <= floorY1; l++) - factor_red[l] = far; + factor_red[l] = upperLimit; for (l = floorY1; l <= 201; l++) - factor_red[l] = near; + factor_red[l] = lowerLimit; - chiquez = (float)(near - far) / (float)(floorY2 - floorY1); + chiquez = (float)(lowerLimit - upperLimit) / (float)(floorY2 - floorY1); for (l = floorY1; l <= floorY2; l++) { - factor_red[l] = (int)(far + pequegnez); + factor_red[l] = (int)(upperLimit + pequegnez); pequegnez = pequegnez + chiquez; } } if (roomNumber == 24) { for (l = floorY1 - 1; l > 74; l--) { - factor_red[l] = (int)(far - pequegnez); + factor_red[l] = (int)(upperLimit - pequegnez); pequegnez = pequegnez + chiquez; } } if (currentChapter == 5 && roomNumber == 54) { for (l = floorY1 - 1; l > 84; l--) { - factor_red[l] = (int)(far - pequegnez); + factor_red[l] = (int)(upperLimit - pequegnez); pequegnez = pequegnez + chiquez; } } -- cgit v1.2.3 From ef07d7e8a770f9ecd85d0915782775481acfef92 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 25 Jun 2008 12:02:34 +0000 Subject: Added patch from bug report #2001189 - "DRASCULA: Wrong intro music in Spanish version" svn-id: r32783 --- engines/drascula/animation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index b0877a2e3e..06868494b5 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -372,7 +372,11 @@ void DrasculaEngine::animation_1_1() { break; clearRoom(); - playMusic(2); + if (_lang == kSpanish) + playMusic(31); + else + playMusic(2); + pause(5); playFLI("intro.bin", 12); term_int = 1; -- cgit v1.2.3 From a2e6f35310b7f4fc4f4a1aa6ca3d5e7ab618b85d Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 25 Jun 2008 15:09:24 +0000 Subject: Implemented opcode: - 0x8D: o2_op8D (Didn't come up with a descriptive name yet) Compares ranges of x, y and mask parameters between two objects. Possibly some kind of an intersection testing function? svn-id: r32785 --- engines/cine/object.cpp | 23 +++++++++++++++++++++++ engines/cine/object.h | 2 ++ engines/cine/script_os.cpp | 21 +++++++++++---------- 3 files changed, 36 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index 96048f5214..b00a636ae6 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -219,6 +219,29 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { } } +/** + * Check if at least one of the range B's endpoints is inside range A, + * not counting the starting and ending points of range A. + * Used at least by Operation Stealth's opcode 0x8D i.e. 141. + */ +bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd) { + return (bStart > aStart && bStart < aEnd) || (bEnd > aStart && bEnd < aEnd); +} + +uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2) { + assert(objIdx1 < NUM_MAX_OBJECT && objIdx2 < NUM_MAX_OBJECT); + const objectStruct &obj1 = objectTable[objIdx1]; + const objectStruct &obj2 = objectTable[objIdx2]; + + if (compareRanges(obj1.x, obj1.x + xAdd1, obj2.x, obj2.x + xAdd2) && + compareRanges(obj1.y, obj1.y + yAdd1, obj2.y, obj2.y + yAdd2) && + compareRanges(obj1.mask, obj1.mask + maskAdd1, obj2.mask, obj2.mask + maskAdd2)) { + return kCmpEQ; + } else { + return 0; + } +} + uint16 compareObjectParam(byte objIdx, byte type, int16 value) { uint16 compareResult = 0; int16 objectParam = getObjectParam(objIdx, type); diff --git a/engines/cine/object.h b/engines/cine/object.h index 6252a628cb..12e72927e1 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -69,6 +69,8 @@ int16 getObjectParam(uint16 objIdx, uint16 paramIdx); void addObjectParam(byte objIdx, byte paramIdx, int16 newValue); void subObjectParam(byte objIdx, byte paramIdx, int16 newValue); +bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd); +uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2); uint16 compareObjectParam(byte objIdx, byte param1, int16 param2); } // End of namespace Cine diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index ffc0da5790..09ab5188a0 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -596,16 +596,17 @@ int FWScript::o2_stopObjectScript() { /*! \todo Implement this instruction */ int FWScript::o2_op8D() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - uint16 c = getNextWord(); - uint16 d = getNextWord(); - uint16 e = getNextWord(); - uint16 f = getNextWord(); - uint16 g = getNextWord(); - uint16 h = getNextWord(); - warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h); - // _currentScriptElement->compareResult = ... + uint16 objIdx1 = getNextWord(); + uint16 xAdd1 = getNextWord(); + uint16 yAdd1 = getNextWord(); + uint16 maskAdd1 = getNextWord(); + uint16 objIdx2 = getNextWord(); + uint16 xAdd2 = getNextWord(); + uint16 yAdd2 = getNextWord(); + uint16 maskAdd2 = getNextWord(); + debugC(5, kCineDebugScript, "Line: %d: o2_op8D(%d, %d, %d, %d, %d, %d, %d, %d)", _line, objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2); + + _compare = compareObjectParamRanges(objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2); return 0; } -- cgit v1.2.3 From d5d09208b4a03eb55697d8831bf87ba8a43385ec Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 25 Jun 2008 17:14:44 +0000 Subject: Implemented opcode: - 0x82: o2_modifySeqListElement (Was o2_op82) Seeks a matching element from the seqList and modifies its values. svn-id: r32786 --- engines/cine/script.h | 2 +- engines/cine/script_os.cpp | 10 +++++----- engines/cine/various.cpp | 13 +++++++++++++ engines/cine/various.h | 1 + 4 files changed, 20 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/cine/script.h b/engines/cine/script.h index 2b6acbba9b..fcd21990fa 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -237,7 +237,7 @@ protected: int o2_playSample(); int o2_playSampleAlt(); int o2_op81(); - int o2_op82(); + int o2_modifySeqListElement(); int o2_isSeqRunning(); int o2_gotoIfSupNearest(); int o2_gotoIfSupEquNearest(); diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index 09ab5188a0..5c6be12ab0 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -202,7 +202,7 @@ const Opcode OSScript::_opcodeTable[] = { /* 80 */ { &FWScript::o2_removeSeq, "bb" }, { &FWScript::o2_op81, "" }, /* TODO: Name this opcode properly. */ - { &FWScript::o2_op82, "bbwwb" }, /* TODO: Name this opcode properly. */ + { &FWScript::o2_modifySeqListElement, "bbwwb" }, { &FWScript::o2_isSeqRunning, "bb" }, /* 84 */ { &FWScript::o2_gotoIfSupNearest, "b" }, @@ -449,15 +449,15 @@ int FWScript::o2_op81() { return 0; } -/*! \todo Implement this instruction - */ -int FWScript::o2_op82() { +int FWScript::o2_modifySeqListElement() { byte a = getNextByte(); byte b = getNextByte(); uint16 c = getNextWord(); uint16 d = getNextWord(); byte e = getNextByte(); - warning("STUB: o2_op82(%x, %x, %x, %x, %x)", a, b, c, d, e); + debugC(5, kCineDebugScript, "Line: %d: o2_modifySeqListElement(%d,%d,%d,%d,%d)", _line, a, b, c, d, e); + + modifySeqListElement(a, 0, b, c, d, e); return 0; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9b98ddb253..f39ae4fb35 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1618,6 +1618,19 @@ void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, i seqList.insert(it, tmp); } +void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4) { + // Find a suitable list element and modify it + for (Common::List::iterator it = seqList.begin(); it != seqList.end(); ++it) { + if (it->objIdx == objIdx && it->var4 == var4Test) { + it->varC = param1; + it->var18 = param2; + it->var1A = param3; + it->var10 = it->var12 = param4; + break; + } + } +} + void computeMove1(SeqListElement &element, int16 x, int16 y, int16 param1, int16 param2, int16 x2, int16 y2) { element.var16 = 0; diff --git a/engines/cine/various.h b/engines/cine/various.h index 91662c16ff..17b11bf72a 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -138,6 +138,7 @@ void removeMessages(); void removeSeq(uint16 param1, uint16 param2, uint16 param3); uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3); void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8); +void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4); void processSeqList(void); bool makeTextEntryMenu(const char *caption, char *string, int strLen, int y); -- cgit v1.2.3 From dee147eebfce779b834b98b81cdad4e76b3fd984 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 25 Jun 2008 18:51:44 +0000 Subject: Added FIXME about the broken implementation of opcode 0x9A (o2_wasZoneChecked). svn-id: r32789 --- engines/cine/script_os.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index 5c6be12ab0..c79da0e230 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -654,6 +654,7 @@ int FWScript::o2_loadBg() { */ int FWScript::o2_wasZoneChecked() { byte param = getNextByte(); + // FIXME: Using a wrong table here, it's not zoneData we want, but something else (zoneQuery) _compare = (param < 16 && zoneData[param]); debugC(5, kCineDebugScript, "Line: %d: o2_wasZoneChecked(%d)", _line, param); return 0; -- cgit v1.2.3 From 1339a55389efa97e484457a8963b69364a98452d Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 25 Jun 2008 21:57:08 +0000 Subject: Implemented support for zoneQuery (Operation Stealth specific). Fixed opcodes (related to zoneQuery): - 0x08: o1_checkCollision - 0x9A: o2_wasZoneChecked NOTE: Savegame support for the zoneQuery data is broken svn-id: r32790 --- engines/cine/main_loop.cpp | 7 +++++++ engines/cine/script_fw.cpp | 20 +++++++++++++++++--- engines/cine/script_os.cpp | 3 +-- engines/cine/various.cpp | 4 ++++ engines/cine/various.h | 1 + 5 files changed, 30 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 0c5096c0d6..6aa1ec1737 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -235,6 +235,13 @@ void CineEngine::mainLoop(int bootScriptIdx) { do { stopMusicAfterFadeOut(); di = executePlayerInput(); + + // Clear the zoneQuery table (Operation Stealth specific) + if (g_cine->getGameType() == Cine::GType_OS) { + for (uint i = 0; i < NUM_MAX_ZONE; i++) { + zoneQuery[i] = 0; + } + } processSeqList(); executeList1(); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 845120c99e..b9dcad9877 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1764,18 +1764,32 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI int16 lx = objectTable[objIdx].x + x; int16 ly = objectTable[objIdx].y + y; int16 idx; + int16 result = 0; for (int16 i = 0; i < numZones; i++) { idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320); - assert(idx >= 0 && idx <= NUM_MAX_ZONE); + assert(idx >= 0 && idx < NUM_MAX_ZONE); + + // The zoneQuery table is updated here only in Operation Stealth + if (g_cine->getGameType() == Cine::GType_OS) { + if (zoneData[idx] >= 0 && zoneData[idx] < NUM_MAX_ZONE) { + zoneQuery[zoneData[idx]]++; + } + } if (zoneData[idx] == zoneIdx) { - return 1; + result = 1; + // Future Wars breaks out early on the first match, but + // Operation Stealth doesn't because it needs to update + // the zoneQuery table for the whole loop's period. + if (g_cine->getGameType() == Cine::GType_FW) { + break; + } } } - return 0; + return result; } uint16 compareVars(int16 a, int16 b) { diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index c79da0e230..f958c66fad 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -654,8 +654,7 @@ int FWScript::o2_loadBg() { */ int FWScript::o2_wasZoneChecked() { byte param = getNextByte(); - // FIXME: Using a wrong table here, it's not zoneData we want, but something else (zoneQuery) - _compare = (param < 16 && zoneData[param]); + _compare = (param < NUM_MAX_ZONE && zoneQuery[param]) ? 1 : 0; debugC(5, kCineDebugScript, "Line: %d: o2_wasZoneChecked(%d)", _line, param); return 0; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index f39ae4fb35..640ca8a169 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -112,6 +112,7 @@ int16 objListTab[20]; uint16 exitEngine; uint16 zoneData[NUM_MAX_ZONE]; +uint16 zoneQuery[NUM_MAX_ZONE]; //!< Only exists in Operation Stealth void stopMusicAfterFadeOut(void) { @@ -391,6 +392,7 @@ bool brokenSave(Common::InSaveFile &fHandle) { } /*! \todo Implement Operation Stealth loading, this is obviously Future Wars only + * \todo Add support for loading the zoneQuery table (Operation Stealth specific) */ bool CineEngine::makeLoad(char *saveName) { int16 i; @@ -588,6 +590,8 @@ bool CineEngine::makeLoad(char *saveName) { return true; } +/*! \todo Add support for saving the zoneQuery table (Operation Stealth specific) + */ void makeSave(char *saveFileName) { int16 i; Common::OutSaveFile *fHandle; diff --git a/engines/cine/various.h b/engines/cine/various.h index 17b11bf72a..c17138e487 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -130,6 +130,7 @@ struct SelectedObjStruct { #define NUM_MAX_ZONE 16 extern uint16 zoneData[NUM_MAX_ZONE]; +extern uint16 zoneQuery[NUM_MAX_ZONE]; void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5); -- cgit v1.2.3 From 1d71ab7e1fcf8d1545a9e508c4e21dc10ced2270 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 25 Jun 2008 22:13:18 +0000 Subject: Fix for GCC warning (Warned about testing x >= 0 when x is unsigned and therefore the test is always true). svn-id: r32791 --- engines/cine/script_fw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index b9dcad9877..148e673095 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1773,7 +1773,7 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI // The zoneQuery table is updated here only in Operation Stealth if (g_cine->getGameType() == Cine::GType_OS) { - if (zoneData[idx] >= 0 && zoneData[idx] < NUM_MAX_ZONE) { + if (zoneData[idx] < NUM_MAX_ZONE) { zoneQuery[zoneData[idx]]++; } } -- cgit v1.2.3 From b6adcca897963aae66ea68eac043f845500e11b1 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Thu, 26 Jun 2008 10:12:12 +0000 Subject: moved midi driver object creation to MidiPlayer class (to match delete call) svn-id: r32798 --- engines/touche/midi.cpp | 9 ++++++--- engines/touche/midi.h | 2 +- engines/touche/saveload.cpp | 3 --- engines/touche/touche.cpp | 6 +----- 4 files changed, 8 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/touche/midi.cpp b/engines/touche/midi.cpp index ce62849d2f..d77dbf5bfa 100644 --- a/engines/touche/midi.cpp +++ b/engines/touche/midi.cpp @@ -23,6 +23,7 @@ * */ +#include "common/config-manager.h" #include "common/stream.h" #include "sound/midiparser.h" @@ -31,9 +32,8 @@ namespace Touche { -MidiPlayer::MidiPlayer(MidiDriver *driver, bool nativeMT32) - : _driver(driver), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0), _nativeMT32(nativeMT32) { - assert(_driver); +MidiPlayer::MidiPlayer() + : _driver(0), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0) { memset(_channelsTable, 0, sizeof(_channelsTable)); memset(_channelsVolume, 0, sizeof(_channelsVolume)); open(); @@ -92,6 +92,9 @@ void MidiPlayer::setVolume(int volume) { } int MidiPlayer::open() { + int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); + _nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); + _driver = MidiDriver::createMidi(midiDriver); int ret = _driver->open(); if (ret == 0) { _parser = MidiParser::createParser_SMF(); diff --git a/engines/touche/midi.h b/engines/touche/midi.h index 3b128593db..a518a4bb29 100644 --- a/engines/touche/midi.h +++ b/engines/touche/midi.h @@ -46,7 +46,7 @@ public: NUM_CHANNELS = 16 }; - MidiPlayer(MidiDriver *driver, bool nativeMT32); + MidiPlayer(); ~MidiPlayer(); void play(Common::ReadStream &stream, int size, bool loop = false); diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp index eb647a1b42..4fcf6e114d 100644 --- a/engines/touche/saveload.cpp +++ b/engines/touche/saveload.cpp @@ -200,9 +200,6 @@ static void saveOrLoad(S &s, ProgramPointData &data) { saveOrLoad(s, data.order); } -template -static void saveOrLoadCommonArray(S &s, A &array); - template static void saveOrLoadCommonArray(Common::WriteStream &stream, A &array) { uint count = array.size(); diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index 06ee28dae8..ac8e8a786a 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -91,11 +91,7 @@ int ToucheEngine::init() { setupOpcodes(); - int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); - bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); - MidiDriver *driver = MidiDriver::createMidi(midiDriver); - _midiPlayer = new MidiPlayer(driver, native_mt32); - + _midiPlayer = new MidiPlayer; _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); -- cgit v1.2.3 From 358d2ec44ab9a3d98afcf8419b1613c018688d0b Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Thu, 26 Jun 2008 10:12:47 +0000 Subject: fix possible oob access svn-id: r32799 --- engines/queen/resource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp index 5a8db74e3b..b3bd663baf 100644 --- a/engines/queen/resource.cpp +++ b/engines/queen/resource.cpp @@ -106,7 +106,7 @@ ResourceEntry *Resource::resourceEntry(const char *filename) const { re = &_resourceTable[cur]; break; } - } while (cur++ < _resourceEntries); + } while (++cur < _resourceEntries); #endif return re; } -- cgit v1.2.3 From 68c598a3f3ad904dab66a2219d97af9eb5a02ccd Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Thu, 26 Jun 2008 15:16:15 +0000 Subject: Comments update. svn-id: r32801 --- engines/cine/script_fw.cpp | 6 ++++++ engines/cine/script_os.cpp | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 148e673095..f84904ccc5 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1760,6 +1760,12 @@ int16 getZoneFromPositionRaw(byte *page, int16 x, int16 y, int16 width) { return zoneVar; } +/*! + * \todo Check whether updating the zoneQuery table is appropriate every time + * this function is called because this function is called also from elsewhere + * than simply o1_checkCollision (e.g. from addAni). In Operation Stealth's + * disassembly this probably isn't the case, so there may be weird side-effects. + */ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx) { int16 lx = objectTable[objIdx].x + x; int16 ly = objectTable[objIdx].y + y; diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index f958c66fad..62a5cc6aaa 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -650,8 +650,6 @@ int FWScript::o2_loadBg() { return 0; } -/*! \todo Check the current implementation for correctness - */ int FWScript::o2_wasZoneChecked() { byte param = getNextByte(); _compare = (param < NUM_MAX_ZONE && zoneQuery[param]) ? 1 : 0; -- cgit v1.2.3 From d7051a8ef7e9569bb0d13ef437c6605ce4dbe1cc Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Thu, 26 Jun 2008 15:44:26 +0000 Subject: Comments update. svn-id: r32802 --- engines/cine/script_os.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index 62a5cc6aaa..aeb5302c22 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -442,6 +442,7 @@ int FWScript::o2_removeSeq() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op81() { warning("STUB: o2_op81()"); @@ -593,8 +594,6 @@ int FWScript::o2_stopObjectScript() { return 0; } -/*! \todo Implement this instruction - */ int FWScript::o2_op8D() { uint16 objIdx1 = getNextWord(); uint16 xAdd1 = getNextWord(); @@ -658,6 +657,7 @@ int FWScript::o2_wasZoneChecked() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9B() { uint16 a = getNextWord(); @@ -673,6 +673,7 @@ int FWScript::o2_op9B() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9C() { uint16 a = getNextWord(); @@ -712,6 +713,7 @@ int FWScript::o2_setAdditionalBgVScroll() { } /*! \todo Implement this instruction + * \note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9F() { warning("o2_op9F()"); -- cgit v1.2.3 From fafda89d0c53a2ac9b0521c1e4549388f14ccea0 Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Thu, 26 Jun 2008 16:51:02 +0000 Subject: Fixed Symbian buildsystem for new defines. Fixed ARM asm syntax for Symbian build. svn-id: r32803 --- engines/scumm/gfxARM.s | 2 +- engines/scumm/smush/codec47ARM.s | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s index cd3e5c7dad..83aaa78927 100644 --- a/engines/scumm/gfxARM.s +++ b/engines/scumm/gfxARM.s @@ -59,7 +59,7 @@ asmDrawStripToScreen: CMP r1,#4 @ If width<4 BLT end @ return - @ Width &= ~4 ? What's that about then? Width &= ~3 I could have + @ Width &= ~4 ? What''s that about then? Width &= ~3 I could have @ understood... BIC r1,r1,#4 diff --git a/engines/scumm/smush/codec47ARM.s b/engines/scumm/smush/codec47ARM.s index 81bfdb2d22..73341c117f 100644 --- a/engines/scumm/smush/codec47ARM.s +++ b/engines/scumm/smush/codec47ARM.s @@ -80,7 +80,7 @@ level1codeFD: LDRB r9,[r8,#384] @ r9 = l = tmp_ptr[384] LDRB r6,[r1],#1 @ r6 = val = *_d_src++ ADD r12,r8,#384 @ r12= &tmp_ptr[384] - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 BEQ level1codeFD_over1 level1codeFD_loop1: @@ -94,7 +94,7 @@ level1codeFD_over1: LDRB r9,[r12,#1] @ r9 = l = tmp_ptr[385] LDRB r6,[r1],#1 @ r6 = val = *_d_src++ SUB r12,r12,#256 @ r12= &tmp_ptr[128] (256 = 384-128) - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 BEQ level1codeFD_over2 level1codeFD_loop2: @@ -219,7 +219,7 @@ level2codeFD: LDRB r9,[r8,#96] @ r9 = l = tmp_ptr[96] LDRB r6,[r1],#1 @ r6 = val = *_d_src++ ADD r12,r8,#32 @ r12 = tmp_ptr + 32 - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 BEQ level2codeFD_over1 level2codeFD_loop1: @@ -232,7 +232,7 @@ level2codeFD_loop1: level2codeFD_over1: LDRB r9,[r12,#65] @ r9 = l = tmp_ptr[97] (65 = 97-32) LDRB r6,[r1],#1 @ r6 = val = *_d_src++ - @ I don't really believe the next 2 lines are necessary, but... + @ I don''t really believe the next 2 lines are necessary, but... CMP r9,#0 MOVEQ PC,R14 level2codeFD_loop2: -- cgit v1.2.3 From 971f27beb27cd853df7f20dbd21dc92e88b3f697 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Thu, 26 Jun 2008 17:29:21 +0000 Subject: Fixed opcode: - 0x83: o2_isSeqRunning (Should it be named o2_isSeqNotRunning?) -- Added previously missing test part -- Negated the result (It was backwards before!) svn-id: r32804 --- engines/cine/script_os.cpp | 4 +++- engines/cine/various.cpp | 9 ++++++--- engines/cine/various.h | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index aeb5302c22..78b6c55564 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -462,11 +462,13 @@ int FWScript::o2_modifySeqListElement() { return 0; } +/*! \todo Check whether this opcode's name is backwards (i.e. should it be o2_isSeqNotRunning?) + */ int FWScript::o2_isSeqRunning() { byte a = getNextByte(); byte b = getNextByte(); - debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b); + debugC(5, kCineDebugScript, "Line: %d: o2_isSeqRunning(%d,%d)", _line, a, b); if (isSeqRunning(a, 0, b)) { _compare = 1; diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 640ca8a169..20d9edc5de 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1586,16 +1586,19 @@ void removeSeq(uint16 param1, uint16 param2, uint16 param3) { } } -uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { +bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { Common::List::iterator it; for (it = seqList.begin(); it != seqList.end(); ++it) { if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) { - return 1; + // Just to be on the safe side there's a restriction of the + // addition's result to 16-bit arithmetic here like in the + // original. It's possible that it's not strictly needed. + return ((it->var14 + it->var16) & 0xFFFF) == 0; } } - return 0; + return true; } void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) { diff --git a/engines/cine/various.h b/engines/cine/various.h index c17138e487..d05447fb40 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -137,7 +137,7 @@ void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 par void removeMessages(); void removeSeq(uint16 param1, uint16 param2, uint16 param3); -uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3); +bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3); void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8); void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4); void processSeqList(void); -- cgit v1.2.3 From 7b30081be292d793914e44939923a67c2745b914 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Thu, 26 Jun 2008 19:42:59 +0000 Subject: - improved hof music support for fm-towns (driver for *.twn tracks) (still needs quite some work) - some PC-98 music support since it uses a very similar driver, but this can't be considered working yet) - Kyra 1 PC-98 music doen't work at all since I haven't figured out yet how to turn track numbers into the corresponding music file names (might require a hard coded track map) svn-id: r32807 --- engines/kyra/detection.cpp | 59 +- engines/kyra/kyra_v1.cpp | 12 +- engines/kyra/screen.cpp | 16 +- engines/kyra/sound.h | 55 +- engines/kyra/sound_lok.cpp | 9 +- engines/kyra/sound_towns.cpp | 1725 +++++++++++++++++++++++++++++++++++++----- engines/kyra/staticres.cpp | 36 +- 7 files changed, 1709 insertions(+), 203 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 344121b503..1e174bdfcf 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -44,6 +44,7 @@ namespace { #define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } #define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA1) #define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) #define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, Kyra::GI_KYRA1) #define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, Kyra::GI_KYRA1) @@ -66,6 +67,28 @@ const KYRAGameDescription adGameDescs[] = { { "kyra1", 0, + AD_ENTRY1("DISK1.EXE", "c8641d0414d6c966d0a3dad79db07bf4"), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_CMP_FLAGS + }, + { + { + "kyra1", + 0, + AD_ENTRY1("DISK1.EXE", "5d5cee4c3d0b68d586788b74243d254a"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA1_FLOPPY_CMP_FLAGS + }, + { + { + "kyra1", + "Extracted", AD_ENTRY1("GEMCUT.EMC", "3c244298395520bb62b5edfe41688879"), Common::EN_ANY, Common::kPlatformPC, @@ -76,7 +99,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "796e44863dd22fa635b042df1bf16673"), Common::EN_ANY, Common::kPlatformPC, @@ -87,7 +110,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "abf8eb360e79a6c2a837751fbd4d3d24"), Common::FR_FRA, Common::kPlatformPC, @@ -98,7 +121,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "6018e1dfeaca7fe83f8d0b00eb0dd049"), Common::DE_DEU, Common::kPlatformPC, @@ -109,7 +132,7 @@ const KYRAGameDescription adGameDescs[] = { { // from Arne.F { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "f0b276781f47c130f423ec9679fe9ed9"), Common::DE_DEU, Common::kPlatformPC, @@ -120,7 +143,7 @@ const KYRAGameDescription adGameDescs[] = { { // from VooD { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "8909b41596913b3f5deaf3c9f1017b01"), Common::ES_ESP, Common::kPlatformPC, @@ -131,7 +154,7 @@ const KYRAGameDescription adGameDescs[] = { { // floppy 1.8 from clemmy { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "747861d2a9c643c59fdab570df5b9093"), Common::ES_ESP, Common::kPlatformPC, @@ -142,7 +165,7 @@ const KYRAGameDescription adGameDescs[] = { { // from gourry { "kyra1", - 0, + "Extracted", AD_ENTRY1("GEMCUT.EMC", "ef08c8c237ee1473fd52578303fc36df"), Common::IT_ITA, Common::kPlatformPC, @@ -463,6 +486,28 @@ const KYRAGameDescription adGameDescs[] = { }, KYRA2_TOWNS_SJIS_FLAGS }, + { // PC-9821 + { + "kyra2", + 0, + AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), + Common::EN_ANY, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + KYRA2_TOWNS_FLAGS + }, + { + { + "kyra2", + 0, + AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), + Common::JA_JPN, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + KYRA2_TOWNS_SJIS_FLAGS + }, // Kyra3 diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 1cc1d728bf..980c181c4e 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -107,14 +107,16 @@ int KyraEngine_v1::init() { // "KYRA1: Crash on exceeded polyphony" for more information). int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/); - if (_flags.platform == Common::kPlatformFMTowns || _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 + if (_flags.platform == Common::kPlatformFMTowns) { if (_flags.gameID == GI_KYRA1) _sound = new SoundTowns(this, _mixer); else - _sound = new SoundTowns_v2(this, _mixer); + _sound = new SoundTownsPC98_v2(this, _mixer); + } else if (_flags.platform == Common::kPlatformPC98) { + if (_flags.gameID == GI_KYRA1) + _sound = new SoundPC98(this, _mixer); + else + _sound = new SoundTownsPC98_v2(this, _mixer); } else if (midiDriver == MD_ADLIB) { _sound = new SoundAdlibPC(this, _mixer); assert(_sound); diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index f00c47ceea..6e7a88b1a3 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -92,9 +92,19 @@ bool Screen::init() { if (_useSJIS) { if (!_sjisFontData) { - _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0); - if (!_sjisFontData) - error("missing font rom ('FMT_FNT.ROM') required for this version"); + // we use the FM-Towns font rom for PC-98, too, until we feel + // like adding support for the PC-98 font + //if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + // FM-Towns + _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0); + if (!_sjisFontData) + error("missing font rom ('FMT_FNT.ROM') required for this version"); + /*} else { + // PC-98 + _sjisFontData = _vm->resource()->fileData("FONT.ROM", 0); + if (!_sjisFontData) + error("missing font rom ('FONT.ROM') required for this version"); + }*/ } if (!_sjisTempPage) { diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 1baeb3064a..c08c531ab9 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -73,7 +73,8 @@ public: kAdlib, kMidiMT32, kMidiGM, - kTowns + kTowns, + kPC98 }; virtual kType getMusicType() const = 0; @@ -382,7 +383,9 @@ private: Common::Mutex _mutex; }; -class SoundTowns_EuphonyDriver; +class Towns_EuphonyDriver; +class TownsPC98_OpnDriver; + class SoundTowns : public MidiDriver, public Sound { public: SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer); @@ -417,6 +420,7 @@ public: static float semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, uint32 sampleRate, uint32 outputRate, int32 pitchWheel); + private: bool loadInstruments(); void playEuphonyTrack(uint32 offset, int loop); @@ -430,7 +434,7 @@ private: uint _sfxFileIndex; uint8 *_sfxFileData; - SoundTowns_EuphonyDriver * _driver; + Towns_EuphonyDriver * _driver; MidiParser * _parser; Common::Mutex _mutex; @@ -439,13 +443,38 @@ private: const uint8 *_sfxWDTable; }; -//class SoundTowns_v2_TwnDriver; -class SoundTowns_v2 : public Sound { +class SoundPC98 : public Sound { public: - SoundTowns_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer); - ~SoundTowns_v2(); + SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer); + ~SoundPC98(); - kType getMusicType() const { return kTowns; } + virtual kType getMusicType() const { return kPC98; } + + bool init(); + + void process() {} + void loadSoundFile(uint file) {} + + void playTrack(uint8 track); + void haltTrack(); + void beginFadeOut(); + + int32 voicePlay(const char *file, bool isSfx = false) { return -1; } + void playSoundEffect(uint8); + +protected: + int _lastTrack; + uint8 *_musicTrackData; + uint8 *_sfxTrackData; + TownsPC98_OpnDriver *_driver; +}; + +class SoundTownsPC98_v2 : public Sound { +public: + SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer); + ~SoundTownsPC98_v2(); + + kType getMusicType() const { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; } bool init(); void process(); @@ -459,13 +488,11 @@ public: int32 voicePlay(const char *file, bool isSfx = false); void playSoundEffect(uint8) {} -private: - int _lastTrack; - +protected: Audio::AudioStream *_currentSFX; - - //SoundTowns_v2_TwnDriver *_driver; - uint8 *_twnTrackData; + int _lastTrack; + uint8 *_musicTrackData; + TownsPC98_OpnDriver *_driver; }; class MixedSoundDriver : public Sound { diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp index 8a1d16a6b1..d320536507 100644 --- a/engines/kyra/sound_lok.cpp +++ b/engines/kyra/sound_lok.cpp @@ -43,7 +43,7 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) { if (restart) _lastMusicCommand = -1; - if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { + if (_flags.platform == Common::kPlatformFMTowns) { if (command == 1) { _sound->beginFadeOut(); } else if (command >= 35 && command <= 38) { @@ -56,6 +56,13 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) { } else { _sound->haltTrack(); } + } else if (_flags.platform == Common::kPlatformPC98) { + + ////////////// + //// TODO //// + ////////////// + _sound->playTrack(command); + } else { KyraEngine_v1::snd_playWanderScoreViaMap(command, restart); } diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index c0e4dd70a9..a6457f509b 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -34,18 +34,21 @@ #include "common/util.h" +#ifdef _MSC_VER +#define _USE_MATH_DEFINES +#endif #include #define EUPHONY_FADEOUT_TICKS 600 namespace Kyra { -enum ChannelState { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing }; +enum EnvelopeState { s_ready, s_attacking, s_decaying, s_sustaining, s_releasing }; -class MidiChannel_EuD : public MidiChannel { +class Towns_EuphonyChannel : public MidiChannel { public: - MidiChannel_EuD() {} - ~MidiChannel_EuD() {} + Towns_EuphonyChannel() {} + ~Towns_EuphonyChannel() {} virtual void nextTick(int32 *outbuf, int buflen) = 0; virtual void rate(uint16 r) = 0; @@ -54,10 +57,10 @@ protected: uint16 _rate; }; -class MidiChannel_EuD_FM : public MidiChannel_EuD { +class Towns_EuphonyFmChannel : public Towns_EuphonyChannel { public: - MidiChannel_EuD_FM(); - virtual ~MidiChannel_EuD_FM(); + Towns_EuphonyFmChannel(); + virtual ~Towns_EuphonyFmChannel(); void nextTick(int32 *outbuf, int buflen); void rate(uint16 r); @@ -79,13 +82,13 @@ protected: Voice2612 *_voice; }; -class MidiChannel_EuD_WAVE : public MidiChannel_EuD { +class Towns_EuphonyPcmChannel : public Towns_EuphonyChannel { public: void nextTick(int32 *outbuf, int buflen); void rate(uint16 r); - MidiChannel_EuD_WAVE(); - virtual ~MidiChannel_EuD_WAVE(); + Towns_EuphonyPcmChannel(); + virtual ~Towns_EuphonyPcmChannel(); // MidiChannel interface MidiDriver *device() { return 0; } @@ -126,9 +129,9 @@ protected: int32 keyOffset; int32 keyNote; const int8 *_samples; - } * _snd[8]; + } *_snd[8]; struct Env { - ChannelState state; + EnvelopeState state; int32 currentLevel; int32 rate; int32 tickCount; @@ -141,40 +144,39 @@ protected: int32 releaseRate; int32 rootKeyOffset; int32 size; - } * _env[8]; - } * _voice; + } *_env[8]; + } *_voice; }; -class SoundTowns_EuphonyTrackQueue { +class Towns_EuphonyTrackQueue { public: - SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver *driver, SoundTowns_EuphonyTrackQueue *last); - ~SoundTowns_EuphonyTrackQueue() {} + Towns_EuphonyTrackQueue(Towns_EuphonyDriver *driver, Towns_EuphonyTrackQueue *last); + ~Towns_EuphonyTrackQueue() {} - void release(); + Towns_EuphonyTrackQueue *release(); void initDriver(); - void loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop = 0); - void loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop = 0); + void loadDataToCurrentPosition(uint8 *trackdata, uint32 size, bool loop = 0); + void loadDataToEndOfQueue(uint8 *trackdata, uint32 size, bool loop = 0); void setPlayBackStatus(bool playing); - SoundTowns_EuphonyTrackQueue * reset(); bool isPlaying() {return _playing; } - uint8 * trackData() {return _trackData; } + const uint8 * trackData() {return _trackData; } bool _loop; - SoundTowns_EuphonyTrackQueue * _next; + Towns_EuphonyTrackQueue *_next; private: - uint8 * _trackData; - uint8 * _used; - uint8 * _fchan; - uint8 * _wchan; + uint8 *_trackData; + uint8 *_used; + uint8 *_fchan; + uint8 *_wchan; bool _playing; - SoundTowns_EuphonyDriver * _driver; - SoundTowns_EuphonyTrackQueue * _last; + Towns_EuphonyDriver *_driver; + Towns_EuphonyTrackQueue *_last; }; -class MidiParser_EuD : public MidiParser { +class Towns_EuphonyParser : public MidiParser { public: - MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue); + Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue); bool loadMusic (byte *data, uint32 size); int32 calculateTempo(int16 val); @@ -183,11 +185,11 @@ protected: void resetTracking(); void setup(); - byte * _enable; - byte * _mode; - byte * _channel; - byte * _adjVelo; - int8 * _adjNote; + byte *_enable; + byte *_mode; + byte *_channel; + byte *_adjVelo; + int8 *_adjNote; uint8 _firstBaseTickStep; uint8 _nextBaseTickStep; @@ -195,13 +197,13 @@ protected: uint32 _baseTick; byte _tempo[3]; - SoundTowns_EuphonyTrackQueue * _queue; + Towns_EuphonyTrackQueue *_queue; }; -class SoundTowns_EuphonyDriver : public MidiDriver_Emulated { +class Towns_EuphonyDriver : public MidiDriver_Emulated { public: - SoundTowns_EuphonyDriver(Audio::Mixer *mixer); - virtual ~SoundTowns_EuphonyDriver(); + Towns_EuphonyDriver(Audio::Mixer *mixer); + virtual ~Towns_EuphonyDriver(); int open(); void close(); @@ -213,7 +215,7 @@ public: void loadFmInstruments(const byte *instr); void loadWaveInstruments(const byte *instr); - SoundTowns_EuphonyTrackQueue * queue() { return _queue; } + Towns_EuphonyTrackQueue *queue() { return _queue; } MidiChannel *allocateChannel() { return 0; } MidiChannel *getPercussionChannel() { return 0; } @@ -237,10 +239,10 @@ protected: void generateSamples(int16 *buf, int len); - MidiChannel_EuD_FM *_fChannel[6]; - MidiChannel_EuD_WAVE *_wChannel[8]; - MidiChannel_EuD * _channel[16]; - SoundTowns_EuphonyTrackQueue * _queue; + Towns_EuphonyFmChannel *_fChannel[6]; + Towns_EuphonyPcmChannel *_wChannel[8]; + Towns_EuphonyChannel *_channel[16]; + Towns_EuphonyTrackQueue *_queue; int _volume; bool _fading; @@ -251,23 +253,23 @@ protected: int8 * _waveSounds[10]; }; -MidiChannel_EuD_FM::MidiChannel_EuD_FM() { +Towns_EuphonyFmChannel::Towns_EuphonyFmChannel() { _voice = new Voice2612; } -MidiChannel_EuD_FM::~MidiChannel_EuD_FM() { +Towns_EuphonyFmChannel::~Towns_EuphonyFmChannel() { delete _voice; } -void MidiChannel_EuD_FM::noteOn(byte note, byte onVelo) { +void Towns_EuphonyFmChannel::noteOn(byte note, byte onVelo) { _voice->noteOn(note, onVelo); } -void MidiChannel_EuD_FM::noteOff(byte note) { +void Towns_EuphonyFmChannel::noteOff(byte note) { _voice->noteOff(note); } -void MidiChannel_EuD_FM::controlChange(byte control, byte value) { +void Towns_EuphonyFmChannel::controlChange(byte control, byte value) { if (control == 121) { // Reset controller delete _voice; @@ -279,25 +281,25 @@ void MidiChannel_EuD_FM::controlChange(byte control, byte value) { } } -void MidiChannel_EuD_FM::sysEx_customInstrument(uint32, const byte *fmInst) { +void Towns_EuphonyFmChannel::sysEx_customInstrument(uint32, const byte *fmInst) { _voice->_rate = _rate; _voice->setInstrument(fmInst); } -void MidiChannel_EuD_FM::pitchBend(int16 value) { +void Towns_EuphonyFmChannel::pitchBend(int16 value) { _voice->pitchBend(value); } -void MidiChannel_EuD_FM::nextTick(int32 *outbuf, int buflen) { +void Towns_EuphonyFmChannel::nextTick(int32 *outbuf, int buflen) { _voice->nextTick((int*) outbuf, buflen); } -void MidiChannel_EuD_FM::rate(uint16 r) { +void Towns_EuphonyFmChannel::rate(uint16 r) { _rate = r; _voice->_rate = r; } -MidiChannel_EuD_WAVE::MidiChannel_EuD_WAVE() { +Towns_EuphonyPcmChannel::Towns_EuphonyPcmChannel() { _voice = new Voice; for (uint8 i = 0; i < 8; i++) { _voice->_env[i] = new Voice::Env; @@ -310,7 +312,7 @@ MidiChannel_EuD_WAVE::MidiChannel_EuD_WAVE() { _current = -1; } -MidiChannel_EuD_WAVE::~MidiChannel_EuD_WAVE() { +Towns_EuphonyPcmChannel::~Towns_EuphonyPcmChannel() { for (uint8 i = 0; i < 8; i++) { if (_voice->_snd[i]) delete _voice->_snd[i]; @@ -319,7 +321,7 @@ MidiChannel_EuD_WAVE::~MidiChannel_EuD_WAVE() { delete _voice; } -void MidiChannel_EuD_WAVE::noteOn(byte note, byte onVelo) { +void Towns_EuphonyPcmChannel::noteOn(byte note, byte onVelo) { _note = note; velocity(onVelo); _phase = 0; @@ -329,24 +331,24 @@ void MidiChannel_EuD_WAVE::noteOn(byte note, byte onVelo) { break; } - _voice->_env[_current]->state = _s_attacking; + _voice->_env[_current]->state = s_attacking; _voice->_env[_current]->currentLevel = 0; _voice->_env[_current]->rate = _rate; _voice->_env[_current]->tickCount = 0; } -void MidiChannel_EuD_WAVE::noteOff(byte note) { +void Towns_EuphonyPcmChannel::noteOff(byte note) { if (_current == -1) return; - if (_voice->_env[_current]->state == _s_ready) + if (_voice->_env[_current]->state == s_ready) return; - _voice->_env[_current]->state = _s_releasing; + _voice->_env[_current]->state = s_releasing; _voice->_env[_current]->releaseLevel = _voice->_env[_current]->currentLevel; _voice->_env[_current]->tickCount = 0; } -void MidiChannel_EuD_WAVE::controlChange(byte control, byte value) { +void Towns_EuphonyPcmChannel::controlChange(byte control, byte value) { switch (control) { case 0x07: // volume @@ -377,7 +379,7 @@ void MidiChannel_EuD_WAVE::controlChange(byte control, byte value) { } } -void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmInst) { +void Towns_EuphonyPcmChannel::sysEx_customInstrument(uint32 type, const byte *fmInst) { if (type == 0x80) { for (uint8 i = 0; i < 8; i++) { const byte * const* pos = (const byte * const*) fmInst; @@ -406,7 +408,7 @@ void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmIns _voice->split[i] = READ_LE_UINT16(fmInst + 16 + 2 * i); _voice->id[i] = READ_LE_UINT32(fmInst + 32 + 4 * i); _voice->_snd[i] = 0; - _voice->_env[i]->state = _s_ready; + _voice->_env[i]->state = s_ready; _voice->_env[i]->currentLevel = 0; _voice->_env[i]->totalLevel = *(fmInst + 64 + 8 * i); _voice->_env[i]->attackRate = *(fmInst + 65 + 8 * i) * 10; @@ -419,11 +421,11 @@ void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmIns } } -void MidiChannel_EuD_WAVE::pitchBend(int16 value) { +void Towns_EuphonyPcmChannel::pitchBend(int16 value) { _frequencyOffs = value; } -void MidiChannel_EuD_WAVE::nextTick(int32 *outbuf, int buflen) { +void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) { if (_current == -1 || !_voice->_snd[_current] || !_voice->_env[_current]->state || !_velocity) { velocity(0); _current = -1; @@ -475,13 +477,13 @@ void MidiChannel_EuD_WAVE::nextTick(int32 *outbuf, int buflen) { } } -void MidiChannel_EuD_WAVE::evpNextTick() { +void Towns_EuphonyPcmChannel::evpNextTick() { switch (_voice->_env[_current]->state) { - case _s_ready: + case s_ready: _voice->_env[_current]->currentLevel = 0; return; - case _s_attacking: + case s_attacking: if (_voice->_env[_current]->attackRate == 0) _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; else if (_voice->_env[_current]->attackRate >= 1270) @@ -493,12 +495,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel >= _voice->_env[_current]->totalLevel) { _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; - _voice->_env[_current]->state = _s_decaying; + _voice->_env[_current]->state = s_decaying; _voice->_env[_current]->tickCount = 0; } break; - case _s_decaying: + case s_decaying: if (_voice->_env[_current]->decayRate == 0) _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; else if (_voice->_env[_current]->decayRate >= 1270) @@ -512,12 +514,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel <= _voice->_env[_current]->sustainLevel) { _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; - _voice->_env[_current]->state = _s_sustaining; + _voice->_env[_current]->state = s_sustaining; _voice->_env[_current]->tickCount = 0; } break; - case _s_sustaining: + case s_sustaining: if (_voice->_env[_current]->sustainRate == 0) _voice->_env[_current]->currentLevel = 0; else if (_voice->_env[_current]->sustainRate >= 2540) @@ -531,12 +533,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel <= 0) { _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->state = _s_ready; + _voice->_env[_current]->state = s_ready; _voice->_env[_current]->tickCount = 0; } break; - case _s_releasing: + case s_releasing: if (_voice->_env[_current]->releaseRate == 0) _voice->_env[_current]->currentLevel = 0; else if (_voice->_env[_current]->releaseRate >= 1270) @@ -550,7 +552,7 @@ void MidiChannel_EuD_WAVE::evpNextTick() { if (_voice->_env[_current]->currentLevel <= 0) { _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->state = _s_ready; + _voice->_env[_current]->state = s_ready; } break; @@ -559,15 +561,15 @@ void MidiChannel_EuD_WAVE::evpNextTick() { } } -void MidiChannel_EuD_WAVE::rate(uint16 r) { +void Towns_EuphonyPcmChannel::rate(uint16 r) { _rate = r; } -void MidiChannel_EuD_WAVE::velocity(int velo) { +void Towns_EuphonyPcmChannel::velocity(int velo) { _velocity = velo; } -SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer) +Towns_EuphonyDriver::Towns_EuphonyDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) { _volume = 255; _fadestate = EUPHONY_FADEOUT_TICKS; @@ -576,9 +578,9 @@ SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer) MidiDriver_YM2612::createLookupTables(); for (uint8 i = 0; i < 6; i++) - _channel[i] = _fChannel[i] = new MidiChannel_EuD_FM; + _channel[i] = _fChannel[i] = new Towns_EuphonyFmChannel; for (uint8 i = 0; i < 8; i++) - _channel[i + 6] = _wChannel[i] = new MidiChannel_EuD_WAVE; + _channel[i + 6] = _wChannel[i] = new Towns_EuphonyPcmChannel; _channel[14] = _channel[15] = 0; _fmInstruments = _waveInstruments = 0; @@ -587,10 +589,10 @@ SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer) rate(getRate()); fading(0); - _queue = new SoundTowns_EuphonyTrackQueue(this, 0); + _queue = new Towns_EuphonyTrackQueue(this, 0); } -SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() { +Towns_EuphonyDriver::~Towns_EuphonyDriver() { for (int i = 0; i < 6; i++) delete _fChannel[i]; for (int i = 0; i < 8; i++) @@ -622,7 +624,7 @@ SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() { } } -int SoundTowns_EuphonyDriver::open() { +int Towns_EuphonyDriver::open() { if (_isOpen) return MERR_ALREADY_OPEN; MidiDriver_Emulated::open(); @@ -633,18 +635,18 @@ int SoundTowns_EuphonyDriver::open() { return 0; } -void SoundTowns_EuphonyDriver::close() { +void Towns_EuphonyDriver::close() { if (!_isOpen) return; _isOpen = false; _mixer->stopHandle(_mixerSoundHandle); } -void SoundTowns_EuphonyDriver::send(uint32 b) { +void Towns_EuphonyDriver::send(uint32 b) { send(b & 0xF, b & 0xFFFFFFF0); } -void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) { +void Towns_EuphonyDriver::send(byte chan, uint32 b) { byte param2 = (byte) ((b >> 16) & 0xFF); byte param1 = (byte) ((b >> 8) & 0xFF); byte cmd = (byte) (b & 0xF0); @@ -703,18 +705,18 @@ void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) { _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000); break; default: - warning("SoundTowns_EuphonyDriver: Unknown send() command 0x%02X", cmd); + warning("Towns_EuphonyDriver: Unknown send() command 0x%02X", cmd); } } -void SoundTowns_EuphonyDriver::loadFmInstruments(const byte *instr) { +void Towns_EuphonyDriver::loadFmInstruments(const byte *instr) { if (_fmInstruments) delete[] _fmInstruments; _fmInstruments = new uint8[0x1800]; memcpy(_fmInstruments, instr, 0x1800); } -void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) { +void Towns_EuphonyDriver::loadWaveInstruments(const byte *instr) { if (_waveInstruments) delete[] _waveInstruments; _waveInstruments = new uint8[0x1000]; @@ -739,24 +741,24 @@ void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) { } -void SoundTowns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) { +void Towns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) { _channel[midiChannelNumber] = _fChannel[fmChannelNumber]; } -void SoundTowns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) { +void Towns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) { _channel[midiChannelNumber] = _wChannel[waveChannelNumber]; } -void SoundTowns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) { +void Towns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) { _channel[midiChannelNumber] = 0; } -void SoundTowns_EuphonyDriver::generateSamples(int16 *data, int len) { +void Towns_EuphonyDriver::generateSamples(int16 *data, int len) { memset(data, 0, 2 * sizeof(int16) * len); nextTick(data, len); } -void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { +void Towns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { int32 *buf0 = (int32 *)buf1; for (int i = 0; i < ARRAYSIZE(_channel); i++) { @@ -779,33 +781,33 @@ void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { } } -void SoundTowns_EuphonyDriver::rate(uint16 r) { +void Towns_EuphonyDriver::rate(uint16 r) { for (uint8 i = 0; i < 16; i++) { if (_channel[i]) _channel[i]->rate(r); } } -void SoundTowns_EuphonyDriver::fading(bool status) { +void Towns_EuphonyDriver::fading(bool status) { _fading = status; if (!_fading) _fadestate = EUPHONY_FADEOUT_TICKS; } -MidiParser_EuD::MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue) : MidiParser(), +Towns_EuphonyParser::Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue) : MidiParser(), _firstBaseTickStep(0x33), _nextBaseTickStep(0x33) { _initialTempo = calculateTempo(0x5a); _queue = queue; } -void MidiParser_EuD::parseNextEvent(EventInfo &info) { +void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { byte *pos = _position._play_pos; if (_queue->_next) { if (info.ext.type == 0x2F) { unloadMusic(); memset(&info, 0, sizeof(EventInfo)); - pos = _position._play_pos = _tracks[0] = _queue->trackData() + 0x806; + pos = _position._play_pos = _tracks[0] = (byte*) _queue->trackData() + 0x806; } else if (_active_track == 255) { _queue = _queue->_next; setup(); @@ -920,15 +922,14 @@ void MidiParser_EuD::parseNextEvent(EventInfo &info) { _position._play_pos = pos; } -bool MidiParser_EuD::loadMusic(byte *data, uint32 size) { +bool Towns_EuphonyParser::loadMusic(byte *data, uint32 size) { bool loop = _autoLoop; if (_queue->isPlaying() && !_queue->_loop) { _queue->loadDataToEndOfQueue(data, size, loop); } else { unloadMusic(); - _queue = _queue->reset(); - _queue->release(); + _queue = _queue->release(); _queue->loadDataToCurrentPosition(data, size, loop); setup(); setTrack(0); @@ -937,7 +938,7 @@ bool MidiParser_EuD::loadMusic(byte *data, uint32 size) { return true; } -int32 MidiParser_EuD::calculateTempo(int16 val) { +int32 Towns_EuphonyParser::calculateTempo(int16 val) { int32 tempo = val; if (tempo < 0) @@ -953,7 +954,7 @@ int32 MidiParser_EuD::calculateTempo(int16 val) { return tempo; } -void MidiParser_EuD::resetTracking() { +void Towns_EuphonyParser::resetTracking() { MidiParser::resetTracking(); _nextBaseTickStep = _firstBaseTickStep; @@ -962,8 +963,8 @@ void MidiParser_EuD::resetTracking() { _queue->setPlayBackStatus(false); } -void MidiParser_EuD::setup() { - uint8 *data = _queue->trackData(); +void Towns_EuphonyParser::setup() { + uint8 *data = (uint8 *) _queue->trackData(); if (!data) return; _queue->initDriver(); @@ -984,7 +985,7 @@ void MidiParser_EuD::setup() { _tracks[0] = data + 0x806; } -SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver * driver, SoundTowns_EuphonyTrackQueue * last) { +Towns_EuphonyTrackQueue::Towns_EuphonyTrackQueue(Towns_EuphonyDriver * driver, Towns_EuphonyTrackQueue * last) { _trackData = 0; _next = 0; _driver = driver; @@ -993,22 +994,15 @@ SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDri _playing = false; } -void SoundTowns_EuphonyTrackQueue::setPlayBackStatus(bool playing) { - SoundTowns_EuphonyTrackQueue * i = this; +void Towns_EuphonyTrackQueue::setPlayBackStatus(bool playing) { + Towns_EuphonyTrackQueue * i = this; do { i->_playing = playing; i = i->_next; } while (i); } -SoundTowns_EuphonyTrackQueue * SoundTowns_EuphonyTrackQueue::reset() { - SoundTowns_EuphonyTrackQueue * i = this; - while (i->_last) - i = i->_last; - return i; -} - -void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) { +void Towns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) { if (_trackData) delete[] _trackData; _trackData = new uint8[0xC58A]; @@ -1022,17 +1016,17 @@ void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, _playing = false; } -void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) { +void Towns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) { if (!_trackData) { loadDataToCurrentPosition(trackdata, size, loop); return; } - SoundTowns_EuphonyTrackQueue * i = this; + Towns_EuphonyTrackQueue * i = this; while (i->_next) i = i->_next; - i = i->_next = new SoundTowns_EuphonyTrackQueue(_driver, i); + i = i->_next = new Towns_EuphonyTrackQueue(_driver, i); i->_trackData = new uint8[0xC58A]; memset(i->_trackData, 0, 0xC58A); Screen::decodeFrame4(trackdata, i->_trackData, size); @@ -1044,29 +1038,39 @@ void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint3 i->_playing = _playing; } -void SoundTowns_EuphonyTrackQueue::release() { - SoundTowns_EuphonyTrackQueue * i = _next; - _next = 0; - _playing = false; - _used = _fchan = _wchan = 0; +Towns_EuphonyTrackQueue *Towns_EuphonyTrackQueue::release() { + Towns_EuphonyTrackQueue *i = this; + while (i->_next) + i = i->_next; - if (_trackData) { - delete[] _trackData; - _trackData = 0; - } + Towns_EuphonyTrackQueue *res = i; while (i) { + i->_playing = false; + i->_used = i->_fchan = i->_wchan = 0; if (i->_trackData) { delete[] i->_trackData; i->_trackData = 0; } - i = i->_next; - if (i) - delete i->_last; + i = i->_last; + if (i) { + res = i; + if (i->_next) { + delete i->_next; + i->_next = 0; + } + } } + + if (res->_trackData) { + delete[] res->_trackData; + res->_trackData = 0; + } + + return res; } -void SoundTowns_EuphonyTrackQueue::initDriver() { +void Towns_EuphonyTrackQueue::initDriver() { for (uint8 i = 0; i < 6; i++) { if (_used[_fchan[i]]) _driver->assignFmChannel(_fchan[i], i); @@ -1084,11 +1088,1339 @@ void SoundTowns_EuphonyTrackQueue::initDriver() { _driver->send(0x79B0); } +class TownsPC98_OpnOperator { +public: + TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, uint8 id, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); + TownsPC98_OpnOperator::~TownsPC98_OpnOperator() {} + + void keyOn(); + void keyOff(); + void frequency(int freq); + void updatePhaseIncrement(); + void recalculateRates(); + void generateOutput(int phasebuf, int *feedbuf, int &out); + + void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } + void detune(int value) { _detn = (int32*) &_detnTbl[value << 5]; } + void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } + void attackRate(uint32 value) { _specifiedAttackRate = value; } + bool scaleRate(uint8 value); + void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } + void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } + void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } + void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } + void totalLevel(uint32 value) { _totalLevel = value << 3; } + void reset(); + +protected: + EnvelopeState _state; + uint32 _feedbackLevel; + uint32 _multiple; + uint32 _totalLevel; + uint8 _keyScale1; + uint8 _keyScale2; + uint32 _specifiedAttackRate; + uint32 _specifiedDecayRate; + uint32 _specifiedSustainRate; + uint32 _specifiedReleaseRate; + uint32 _tickCount; + uint32 _sustainLevel; + + uint32 _frequency; + uint8 _kcode; + uint32 _phase; + uint32 _phaseIncrement; + int32 *_detn; + + const uint8 *_rateTbl; + const uint8 *_rshiftTbl; + const uint8 *_adTbl; + const uint32 *_fTbl; + const uint32 *_sinTbl; + const int32 *_tLvlTbl; + const int32 *_detnTbl; + + const double _tickLength; + double _tick; + int32 _currentLevel; + + struct EvpState { + uint8 rate; + uint8 shift; + } fs_a, fs_d, fs_s, fs_r; +}; + +TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, uint8 id, + const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, + const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : + _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), + _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0), + _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), + _phase(0), _state(s_ready) { + + reset(); +} + +void TownsPC98_OpnOperator::keyOn() { + _state = s_attacking; + _phase = 0; +} + +void TownsPC98_OpnOperator::keyOff() { + if (_state != s_ready) + _state = s_releasing; +} + +void TownsPC98_OpnOperator::frequency(int freq) { + uint8 block = (freq >> 11); + uint16 pos = (freq & 0x7ff); + uint8 c = pos >> 7; + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); + _frequency = _fTbl[pos << 1] >> (7 - block); +} + +void TownsPC98_OpnOperator::updatePhaseIncrement() { + _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1; + uint8 keyscale = _kcode >> _keyScale1; + if (_keyScale2 != keyscale) { + _keyScale2 = keyscale; + recalculateRates(); + } +} + +void TownsPC98_OpnOperator::recalculateRates() { + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + + r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0; + fs_d.rate = _rateTbl[r + k]; + fs_d.shift = _rshiftTbl[r + k]; + + r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0; + fs_s.rate = _rateTbl[r + k]; + fs_s.shift = _rshiftTbl[r + k]; + + r = (_specifiedReleaseRate << 2) + 0x22; + fs_r.rate = _rateTbl[r + k]; + fs_r.shift = _rshiftTbl[r + k]; +} + +void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out) { + if (_state == s_ready) + return; + + _tick += _tickLength; + while (_tick > 0x30000) { + _tick -= 0x30000; + ++_tickCount; + + int32 levelIncrement = 0; + uint32 targetTime = 0; + int32 targetLevel = 0; + EnvelopeState next_state = s_ready; + + switch (_state) { + case s_ready: + return; + case s_attacking: + next_state = s_decaying; + targetTime = (1 << fs_a.shift) - 1; + targetLevel = 0; + levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; + break; + case s_decaying: + targetTime = (1 << fs_d.shift) - 1; + next_state = s_sustaining; + targetLevel = _sustainLevel; + levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; + break; + case s_sustaining: + targetTime = (1 << fs_s.shift) - 1; + next_state = s_ready; + targetLevel = 1023; + levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; + break; + case s_releasing: + targetTime = (1 << fs_r.shift) - 1; + next_state = s_ready; + targetLevel = 1023; + levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; + break; + } + + if (!(_tickCount & targetTime)) { + _currentLevel += levelIncrement; + if ((!targetLevel && _currentLevel <= targetLevel) || (targetLevel && _currentLevel >= targetLevel)) { + if (_state != s_decaying) + _currentLevel = targetLevel; + if (_state != s_sustaining) + _state = next_state; + } + } + } + + uint32 lvlout = _totalLevel + (uint32) _currentLevel; + + int outp = 0; + int *i = &outp, *o = &outp; + int phaseShift = 0; + + if (feedbuf) { + o = &feedbuf[0]; + i = &feedbuf[1]; + phaseShift = _feedbackLevel ? ((feedbuf[0] + feedbuf[1]) << _feedbackLevel) : 0; + *o = *i; + } else { + phaseShift = phasebuf << 15; + } + + if (lvlout < 832) { + uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) + + phaseShift)) >> 16) & 0x3ff]; + *i = ((index < 6656) ? _tLvlTbl[index] : 0); + } else { + *i = 0; + } + + _phase += _phaseIncrement; + out += *o; + if (out > 32767) + out = 32767; + if (out < -32767) + out = -32767; +} + +void TownsPC98_OpnOperator::reset(){ + keyOff(); + _tick = 0; + _keyScale2 = -1; + _currentLevel = 1023; + + frequency(0); + detune(0); + scaleRate(0); + multiple(0); + updatePhaseIncrement(); + attackRate(0); + decayRate(0); + releaseRate(0); + sustainRate(0); + feedbackLevel(0); + totalLevel(127); +} + +bool TownsPC98_OpnOperator::scaleRate(uint8 value) { + value = 3 - value; + if (_keyScale1 != value) { + _keyScale1 = value; + return true; + } + + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + return false; +} + +class TownsPC98_OpnDriver : public Audio::AudioStream { +public: + enum OpnType { + OD_TOWNS, + OD_TYPE26, + OD_TYPE86 + }; + + TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type); + ~TownsPC98_OpnDriver(); + + bool init(); + void loadData(uint8 *data, bool loadPaused = false); + void reset(); + void fadeOut(); + + void pause() { _playing = false; } + void cont() { _playing = true; } + + void callback(); + void nextTick(int16 *buffer, uint32 bufferSize); + + bool looping() { return _looping == _updateChannelsFlag ? true : false; } + + // AudioStream interface + int inline readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return true; } + bool endOfData() const { return false; } + int getRate() const { return _mixer->getOutputRate(); } + +protected: + void generateTables(); + + typedef enum channelState { + CHS_RECALCFREQ = 0x01, + CHS_KEYOFF = 0x02, + CHS_PITCHWHEELOFF = 0x08, + CHS_ALL_BUT_EOT = 0x0f, + CHS_EOT = 0x80 + } ChannelState; + + struct TwnChannel { + uint8 ticksLeft; + uint8 unk1, unk2, unk3; + uint8 algorithm; + uint8 instrID; + uint8 totalLevel; + uint8 frqBlockMSB; + int8 frqLSB; + uint8 keyOffTime; + bool protect; + uint8 *dataPtr; + uint8 unk15, unk16; + uint8 ptchWhlInitDelayLo; + uint8 ptchWhlInitDelayHi; + int16 ptchWhlModInitVal; + uint8 ptchWhlDuration; + uint8 ptchWhlCurDelay; + int16 ptchWhlModCurVal; + uint8 ptchWhlDurLeft; + uint16 frequency; + uint8 unk28, unk29; + uint8 regOffset; + uint8 flags; + uint8 chanNum; + uint8 keyNum; + uint8 part; + uint8 idFlag; + + TownsPC98_OpnOperator *opr[4]; + uint16 frqTemp; + bool enableLeft; + bool enableRight; + bool updateEnvelopes; + int feedbuf[3]; + } **_channels; + + void processEvents(TwnChannel *chan); + void processFrequency(TwnChannel *chan); + bool processControlEvent(TwnChannel *chan, uint8 cmd); + + void setOutputLevel(TwnChannel *chan); + void setTempo(uint8 tempo); + + void keyOn(TwnChannel *chan); + void keyOff(TwnChannel *chan); + void writeReg(TwnChannel *chan, uint8 regAdress, uint8 value); + + void lock() { _mutex.lock(); } + void unlock() { _mutex.unlock(); } + + bool control_f0_setPatch(TwnChannel *chan, uint8 para); + bool control_f1_presetOutputLevel(TwnChannel *chan, uint8 para); + bool control_f2_setKeyOffTime(TwnChannel *chan, uint8 para); + bool control_f3_setFreqLSB(TwnChannel *chan, uint8 para); + bool control_f4_setOutputLevel(TwnChannel *chan, uint8 para); + bool control_f5_setTempo(TwnChannel *chan, uint8 para); + bool control_f6_repeatSection(TwnChannel *chan, uint8 para); + bool control_f7_setupPitchWheel(TwnChannel *chan, uint8 para); + bool control_f8_togglePitchWheel(TwnChannel *chan, uint8 para); + bool control_f9_unk(TwnChannel *chan, uint8 para); + bool control_fa_writeReg(TwnChannel *chan, uint8 para); + bool control_fb_incOutLevel(TwnChannel *chan, uint8 para); + bool control_fc_decOutLevel(TwnChannel *chan, uint8 para); + bool control_fd_jump(TwnChannel *chan, uint8 para); + bool control_fe_unk(TwnChannel *chan, uint8 para); + bool control_ff_endOfTrack(TwnChannel *chan, uint8 para); + + typedef bool (TownsPC98_OpnDriver::*ControlEventFunc)(TwnChannel * chan, uint8 para); + + Audio::Mixer *_mixer; + TownsPC98_OpnOperator **_operators; + Common::Mutex _mutex; + Audio::SoundHandle _soundHandle; + + const uint8 *_twnCarrier; + const uint8 *_twnFreqTable; + const uint8 *_twnFxCmdLen; + const uint8 *_twnLvlPresets; + + uint8 *_oprRates; + uint8 *_oprRateshift; + uint8 *_oprAttackDecay; + uint32 *_oprFrq; + uint32 *_oprSinTbl; + int32 *_oprLevelOut; + int32 *_oprDetune; + + const uint8 *_trackData; + const uint8 *_patches; + uint8 _cbCounter; + uint8 _updateChannelsFlag; + uint8 _finishedChannelsFlag; + uint16 _tempo; + bool _playing; + bool _fading; + uint8 _looping; + + bool _updateEnvelopes; + + int32 _samplesTillCallback; + int32 _samplesTillCallbackRemainder; + int32 _samplesPerCallback; + int32 _samplesPerCallbackRemainder; + + const int _numChan; + const int _numSSG; + const bool _hasADPCM; + const bool _hasStereo; + + double _baserate; + static const uint8 _drvTables[]; + static const uint32 _adtStat[]; +}; + +TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : + _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), + _operators(0), _looping(0), _twnCarrier(_drvTables + 76), _twnFreqTable(_drvTables + 84), + _twnFxCmdLen(_drvTables + 36), _twnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), + _oprDetune(0), _cbCounter(4), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), + _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), + _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), + _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { + setTempo(84); + _baserate = (3579545.0 / (double)getRate()) / 144.0; +} + +TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { + _mixer->stopHandle(_soundHandle); + + if (_operators) { + for (int i = 0; i < (_numChan << 2); i++) + delete _operators[i]; + delete [] _operators; + } + + if (_channels) { + for (int i = 0; i < _numChan; i++) + delete _channels[i]; + delete [] _channels; + } + + delete [] _oprRates; + delete [] _oprRateshift; + delete [] _oprFrq; + delete [] _oprAttackDecay; + delete [] _oprSinTbl; + delete [] _oprLevelOut; + delete [] _oprDetune; +} + +bool TownsPC98_OpnDriver::init() { + generateTables(); + + if (_operators) { + for (int i = 0; i < (_numChan << 2); i++) { + if (_operators[i]) { + delete _operators[i]; + } + } + delete [] _operators; + } + + _operators = new TownsPC98_OpnOperator*[(_numChan << 2)]; + for (int i = 0; i < (_numChan << 2); i++) + _operators[i] = new TownsPC98_OpnOperator(_baserate, i & 3, _oprRates, + _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); + + if (_channels) { + for (int i = 0; i < _numChan; i++) { + if (_channels[i]) + delete _channels[i]; + } + delete [] _channels; + } + _channels = new TwnChannel*[_numChan]; + for (int i = 0; i < _numChan; i++) { + _channels[i] = new TwnChannel; + for (int ii = 0; ii < 4; ii++) { + _channels[i]->opr[ii] = _operators[(i << 2) + ii]; + _channels[i]->updateEnvelopes = false; + } + } + + for (int i = 0; i < _numChan; i++) { + int ix = i * 6; + memset(_channels[i], 0, sizeof(TwnChannel)); + _channels[i]->regOffset = _drvTables[ix]; + _channels[i]->flags = _drvTables[ix + 1]; + _channels[i]->chanNum = _drvTables[ix + 2]; + _channels[i]->keyNum = _drvTables[ix + 3]; + _channels[i]->part = _drvTables[ix + 4]; + _channels[i]->idFlag = _drvTables[ix + 5]; + } + + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, + &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); + + return true; +} + +int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) { + memset(buffer, 0, sizeof(int16) * numSamples); + int32 samplesLeft = numSamples >> 1; + while (samplesLeft) { + if (!_samplesTillCallback) { + callback(); + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= _tempo) { + _samplesTillCallback++; + _samplesTillCallbackRemainder -= _tempo; + } + } + + int32 render = MIN(samplesLeft, _samplesTillCallback); + samplesLeft -= render; + _samplesTillCallback -= render; + + nextTick(buffer, render); + + for (int i = 0; i < render; ++i) { + buffer[i << 1] <<= 2; + buffer[(i << 1) + 1] <<= 2; + } + + buffer += (render << 1); + } + + return numSamples; +} + +void TownsPC98_OpnDriver::loadData(uint8 * data, bool loadPaused) { + + lock(); + _trackData = data; + + reset(); + + for (uint8 i = 0; i < _numChan; i++) { + uint8 tmp1 = _channels[i]->regOffset; + uint8 tmp2 = _channels[i]->flags; + uint8 tmp3 = _channels[i]->chanNum; + uint8 tmp4 = _channels[i]->keyNum; + uint8 tmp5 = _channels[i]->part; + uint8 tmp6 = _channels[i]->idFlag; + memset(_channels[i], 0, sizeof(TwnChannel)); + _channels[i]->regOffset = tmp1; + _channels[i]->flags = tmp2; + _channels[i]->chanNum = tmp3; + _channels[i]->keyNum = tmp4; + _channels[i]->part = tmp5; + _channels[i]->idFlag = tmp6; + _channels[i]->enableLeft = _channels[i]->enableRight = true; + for (int ii = 0; ii < 4; ii++) + _channels[i]->opr[ii] = _operators[(i << 2) + ii]; + } + + const uint8 *src_a = (const uint8*) data; + uint8 bl = 0; + + for (uint8 i = 0; i < _numChan; i++) { + _channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; + _channels[i]->ticksLeft = 1; + _channels[i]->dataPtr = data + READ_LE_UINT16(src_a); + src_a += 2; + _channels[i]->totalLevel = 0x7F; + if (bl > 2) + bl -= 3; + _channels[i]->regOffset = bl++; + + uint8 * src_b = _channels[i]->dataPtr; + int loop = 1; + uint8 cmd = 0; + while (loop) { + if (loop == 1) { + cmd = *src_b++; + if (cmd < 0xf0) { + src_b++; + loop = 1; + } else { + if (cmd == 0xff) { + loop = *src_b ? 2 : 0; + if (READ_LE_UINT16(src_b)) + _looping |= _channels[i]->idFlag; + } else if (cmd == 0xf6) { + loop = 3; + } else { + loop = 2; + } + } + } else if (loop == 2) { + src_b += _twnFxCmdLen[cmd - 240]; + loop = 1; + } else if (loop == 3) { + src_b[0] = src_b[1]; + src_b += 4; + loop = 1; + } + } + } + + for (int i = 0; i < _numSSG; i++) { + // TODO + //_channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; + //_channels[i]->ticksLeft = 1; + //_channels[i]->dataPtr = data + READ_LE_UINT16(src_a); + uint8 *tmp = data + READ_LE_UINT16(src_a); + src_a += 2; + } + + if (_hasADPCM) { + // TODO + src_a += 2; + } + + _patches = src_a + 4; + _cbCounter = 4; + _finishedChannelsFlag = 0; + + // AH 0x17 + unlock(); + _playing = (loadPaused ? false : true); +} + +void TownsPC98_OpnDriver::reset() { + for (int i = 0; i < (_numChan << 2); i++) + _operators[i]->reset(); + + _playing = false; + _looping = 0; +} + +void TownsPC98_OpnDriver::fadeOut() { + if (!_playing) + return; + + _fading = true; + + for (int i = 0; i < 20; i++) { + + /// TODO /// + // twnFade(); + //waitTicks(s); + + } + + _fading = false; + + //haltTrack(); +} + +void TownsPC98_OpnDriver::callback() { + if (!_playing || --_cbCounter) + return; + + _cbCounter = 4; + + lock(); + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->idFlag) { + processEvents(_channels[i]); + processFrequency(_channels[i]); + } + } + unlock(); + + if (_finishedChannelsFlag == _updateChannelsFlag) + reset(); +} + +void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { + if (!_playing) + return; + + for (int i = 0; i < _numChan ; i++) { + if (_channels[i]->updateEnvelopes) { + _channels[i]->updateEnvelopes = false; + for (int ii = 0; ii < 4 ; ii++) + _channels[i]->opr[ii]->updatePhaseIncrement(); + } + + int phbuf1, phbuf2, output; + int *feed = _channels[i]->feedbuf; + int *del = &feed[2]; + + for (int ii = 0; ii < bufferSize ; ii++) { + phbuf1 = phbuf2 = output = 0; + + switch (_channels[i]->algorithm) { + case 0: + _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); + _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2); + *del = 0; + _channels[i]->opr[1]->generateOutput(phbuf1, 0, *del); + _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); + break; + case 1: + _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); + _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2); + _channels[i]->opr[1]->generateOutput(0, 0, phbuf1); + _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 2: + _channels[i]->opr[0]->generateOutput(0, feed, phbuf2); + _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2); + _channels[i]->opr[1]->generateOutput(0, 0, phbuf1); + _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 3: + _channels[i]->opr[0]->generateOutput(0, feed, phbuf2); + _channels[i]->opr[2]->generateOutput(0, 0, *del); + _channels[i]->opr[1]->generateOutput(phbuf2, 0, phbuf1); + _channels[i]->opr[3]->generateOutput(*del, 0, output); + *del = phbuf1; + break; + case 4: + _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); + _channels[i]->opr[2]->generateOutput(0, 0, phbuf2); + _channels[i]->opr[1]->generateOutput(phbuf1, 0, output); + _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); + *del = 0; + break; + case 5: + *del = feed[1]; + _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); + _channels[i]->opr[2]->generateOutput(*del, 0, output); + _channels[i]->opr[1]->generateOutput(*del, 0, output); + _channels[i]->opr[3]->generateOutput(*del, 0, output); + break; + case 6: + _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); + _channels[i]->opr[2]->generateOutput(0, 0, output); + _channels[i]->opr[1]->generateOutput(phbuf1, 0, output); + _channels[i]->opr[3]->generateOutput(0, 0, output); + *del = 0; + break; + case 7: + _channels[i]->opr[0]->generateOutput(0, feed, output); + _channels[i]->opr[2]->generateOutput(0, 0, output); + _channels[i]->opr[1]->generateOutput(0, 0, output); + _channels[i]->opr[3]->generateOutput(0, 0, output); + *del = 0; + break; + }; + + if (_channels[i]->enableLeft) { + int l = output + buffer[ii * 2]; + if (l > 32767) + l = 32767; + if (l < -32767) + l = -32767; + buffer[ii * 2] = (int16) l; + } + + if (_channels[i]->enableRight) { + int r = output + buffer[ii * 2 + 1]; + if (r > 32767) + r = 32767; + if (r < -32767) + r = -32767; + buffer[ii * 2 + 1] = (int16) r; + } + } + } +} + +void TownsPC98_OpnDriver::generateTables() { + delete [] _oprRates; + _oprRates = new uint8[128]; + memset(_oprRates, 0x90, 32); + uint8 * dst = (uint8*) _oprRates + 32; + for (int i = 0; i < 48; i += 4) + WRITE_BE_UINT32(dst + i, 0x00081018); + dst += 48; + for (uint8 i = 0; i < 16; i ++) { + uint8 v = (i < 12) ? i : 12; + *dst++ = ((4 + v) << 3); + } + memset(dst, 0x80, 32); + + delete [] _oprRateshift; + _oprRateshift = new uint8[128]; + memset(_oprRateshift, 0, 128); + dst = (uint8*) _oprRateshift + 32; + for (int i = 11; i; i--) { + memset(dst, i, 4); + dst += 4; + } + + delete [] _oprFrq; + _oprFrq = new uint32[0x1000]; + for (uint32 i = 0; i < 0x1000; i++) + _oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); + + delete [] _oprAttackDecay; + _oprAttackDecay = new uint8[152]; + memset(_oprAttackDecay, 0, 152); + for (int i = 0; i < 36; i++) + WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); + + delete [] _oprSinTbl; + _oprSinTbl = new uint32[1024]; + for (int i = 0; i < 1024; i++) { + double val = sin((double) (((i << 1) + 1) * M_PI / 1024.0)); + double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; + int32 i_dcb = (int32)(2.0 * d_dcb); + i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); + _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); + } + + delete [] _oprLevelOut; + _oprLevelOut = new int32[0x1a00]; + for (int i = 0; i < 256; i++) { + double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); + int32 val_int = ((int32) val) >> 4; + _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; + _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; + for (int ii = 1; ii < 13; ii++) { + _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; + _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; + } + } + + uint8 * dtt = new uint8[128]; + memset(dtt, 0, 36); + memset(dtt + 36, 1, 8); + memcpy(dtt + 44, _drvTables + 144, 84); + + delete [] _oprDetune; + _oprDetune = new int32[256]; + for (int i = 0; i < 128; i++) { + double rate = ((double)dtt[i]) * 1024.0 * _baserate * (1<<16) / ((double)(1<<20)); + _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); + _oprDetune[i + 128] = -_oprDetune[i]; + } + + delete [] dtt; +} + +void TownsPC98_OpnDriver::processEvents(TwnChannel *chan) { + if (chan->flags & CHS_EOT) + return; + + if (chan->protect == false && chan->ticksLeft == chan->keyOffTime) + keyOff(chan); + + if (--chan->ticksLeft) + return; + + if (chan->protect == false) + keyOff(chan); + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *chan->dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(chan, cmd)) + return; + } + + uint8 para = *chan->dataPtr++; + + if (cmd == 0x80) { + keyOff(chan); + chan->protect = false; + } else { + keyOn(chan); + + if (chan->protect == false || cmd != chan->frqBlockMSB) + chan->flags |= CHS_RECALCFREQ; + + chan->protect = (para & 0x80) ? true : false; + chan->frqBlockMSB = cmd; + } + + chan->ticksLeft = para & 0x7f; +} + +void TownsPC98_OpnDriver::processFrequency(TwnChannel *chan) { + if (chan->flags & CHS_RECALCFREQ) { + uint8 block = (chan->frqBlockMSB & 0x70) >> 1; + uint16 bfreq = ((uint16*)_twnFreqTable)[chan->frqBlockMSB & 0x0f]; + chan->frequency = (bfreq + chan->frqLSB) | (block << 8); + + writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8)); + writeReg(chan, (chan->regOffset + 0xa0), (chan->frequency & 0xff)); + + chan->ptchWhlCurDelay = chan->ptchWhlInitDelayHi; + if (chan->flags & CHS_KEYOFF) { + chan->ptchWhlModCurVal = chan->ptchWhlModInitVal; + chan->ptchWhlCurDelay += chan->ptchWhlInitDelayLo; + } + + chan->ptchWhlDurLeft = (chan->ptchWhlDuration >> 1); + chan->flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + } + + if (!(chan->flags & CHS_PITCHWHEELOFF)) { + if (--chan->ptchWhlCurDelay) + return; + chan->ptchWhlCurDelay = chan->ptchWhlInitDelayHi; + chan->frequency += chan->ptchWhlModCurVal; + + writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8)); + writeReg(chan, (chan->regOffset + 0xa0), (chan->frequency & 0xff)); + + if(!--chan->ptchWhlDurLeft) { + chan->ptchWhlDurLeft = chan->ptchWhlDuration; + chan->ptchWhlModCurVal = -chan->ptchWhlModCurVal; + } + } +} + +bool TownsPC98_OpnDriver::processControlEvent(TwnChannel *chan, uint8 cmd) { + #define Control(x) &TownsPC98_OpnDriver::control_##x + static const ControlEventFunc twnFxCommands[] = { + Control(f0_setPatch), + Control(f1_presetOutputLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setOutputLevel), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupPitchWheel), + Control(f8_togglePitchWheel), + Control(f9_unk), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(fe_unk), + Control(ff_endOfTrack) + }; + #undef Control + + uint8 para = *chan->dataPtr++; + return (this->*twnFxCommands[cmd & 0x0f])(chan, para); +} + +void TownsPC98_OpnDriver::setOutputLevel(TwnChannel *chan) { + uint8 outopr = _twnCarrier[chan->algorithm]; + uint8 reg = 0x40 + chan->regOffset; + + for (int i = 0; i < 4; i++) { + if (outopr & 1) + writeReg(chan, reg, chan->totalLevel); + outopr >>= 1; + reg += 4; + } +} + +void TownsPC98_OpnDriver::setTempo(uint8 tempo) { + _tempo = tempo; + _samplesPerCallback = getRate() / _tempo; + _samplesPerCallbackRemainder = getRate() % _tempo; +} + +bool TownsPC98_OpnDriver::control_f0_setPatch(TwnChannel *chan, uint8 para) { + chan->instrID = para; + uint8 reg = chan->regOffset + 0x80; + + for (int i = 0; i < 4; i++) { + // set release rate for each operator + writeReg(chan, reg, 0x0f); + reg += 4; + } + + const uint8 *tptr = (uint8*) _patches + ((uint32)chan->instrID << 5); + reg = chan->regOffset + 0x30; + + // write registers 0x30 to 0x8f + for (int i = 0; i < 6; i++) { + writeReg(chan, reg, tptr[0]); + reg += 4; + writeReg(chan, reg, tptr[2]); + reg += 4; + writeReg(chan, reg, tptr[1]); + reg += 4; + writeReg(chan, reg, tptr[3]); + reg += 4; + tptr += 4; + } + + reg = chan->regOffset + 0xB0; + chan->algorithm = tptr[0] & 7; + // set feedback and algorithm + writeReg(chan, reg, tptr[0]); + + setOutputLevel(chan); + return true; +} + +bool TownsPC98_OpnDriver::control_f1_presetOutputLevel(TwnChannel *chan, uint8 para) { + if (_fading) + return true; + + chan->totalLevel = _twnLvlPresets[para]; + setOutputLevel(chan); + return true; +} + +bool TownsPC98_OpnDriver::control_f2_setKeyOffTime(TwnChannel *chan, uint8 para) { + chan->keyOffTime = para; + return true; +} + +bool TownsPC98_OpnDriver::control_f3_setFreqLSB(TwnChannel *chan, uint8 para) { + chan->frqLSB = (int8) para; + return true; +} + +bool TownsPC98_OpnDriver::control_f4_setOutputLevel(TwnChannel *chan, uint8 para) { + if (_fading) + return true; + + chan->totalLevel = para; + setOutputLevel(chan); + return true; +} + +bool TownsPC98_OpnDriver::control_f5_setTempo(TwnChannel *chan, uint8 para) { + setTempo(para); + return true; +} + +bool TownsPC98_OpnDriver::control_f6_repeatSection(TwnChannel *chan, uint8 para) { + chan->dataPtr--; + chan->dataPtr[0]--; + + if (*chan->dataPtr) { + // repeat section until counter has reached zero + chan->dataPtr = (uint8*) _trackData + READ_LE_UINT16(chan->dataPtr + 2); + } else { + // reset counter, advance to next section + chan->dataPtr[0] = chan->dataPtr[1]; + chan->dataPtr += 4; + } + return true; +} + +bool TownsPC98_OpnDriver::control_f7_setupPitchWheel(TwnChannel *chan, uint8 para) { + chan->ptchWhlInitDelayLo = chan->dataPtr[0]; + chan->ptchWhlInitDelayHi = para; + chan->ptchWhlModInitVal = (int16) READ_LE_UINT16(chan->dataPtr + 1); + chan->ptchWhlDuration = chan->dataPtr[3]; + chan->dataPtr += 4; + chan->flags = (chan->flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ; + return true; +} + +bool TownsPC98_OpnDriver::control_f8_togglePitchWheel(TwnChannel *chan, uint8 para) { + if (para == 0x10) { + if (*chan->dataPtr++) { + chan->flags = (chan->flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF; + } else { + chan->flags |= CHS_PITCHWHEELOFF; + } + } else { + uint8 skipChannels = para / 36; + uint8 entry = para % 36; + TownsPC98_OpnDriver::TwnChannel *t = &chan[skipChannels]; + ////// NOT IMPLEMENTED + //t->unnamedEntries[entry] = *chan->dataPtr++; + } + return true; +} + +bool TownsPC98_OpnDriver::control_f9_unk(TwnChannel *chan, uint8 para) { + //chan->dataPtr += 5; + return true; +} + +bool TownsPC98_OpnDriver::control_fa_writeReg(TwnChannel *chan, uint8 para) { + writeReg(chan, para, *chan->dataPtr++); + return true; +} + +bool TownsPC98_OpnDriver::control_fb_incOutLevel(TwnChannel *chan, uint8 para) { + chan->dataPtr--; + if (_fading) + return true; + + uint8 val = (chan->totalLevel + 3); + if (val > 0x7f) + val = 0x7f; + + chan->totalLevel = val; + setOutputLevel(chan); + return true; +} + +bool TownsPC98_OpnDriver::control_fc_decOutLevel(TwnChannel *chan, uint8 para) { + chan->dataPtr--; + if (_fading) + return true; + + int8 val = (int8) (chan->totalLevel - 3); + if (val < 0) + val = 0; + + chan->totalLevel = (uint8) val; + setOutputLevel(chan); + return true; +} + +bool TownsPC98_OpnDriver::control_fd_jump(TwnChannel *chan, uint8 para) { + uint8 *tmp = (uint8*) _trackData + READ_LE_UINT16(chan->dataPtr - 1); + chan->dataPtr = (tmp[1] == 1) ? tmp : ++chan->dataPtr; + return true; +} + +bool TownsPC98_OpnDriver::control_fe_unk(TwnChannel *chan, uint8 para) { + chan->dataPtr--; + return true; +} + +bool TownsPC98_OpnDriver::control_ff_endOfTrack(TwnChannel *chan, uint8 para) { + uint16 val = READ_LE_UINT16(--chan->dataPtr); + if (val) { + // loop + chan->dataPtr = (uint8 *) _trackData + val; + return true; + } else { + // quit parsing for active channel + --chan->dataPtr; + chan->flags |= CHS_EOT; + _finishedChannelsFlag |= chan->idFlag; + keyOff(chan); + return false; + } +} + +void TownsPC98_OpnDriver::keyOff(TwnChannel *chan) { + // all operators off + uint8 value = chan->keyNum & 0x0f; + uint8 regAdress = 0x28; + writeReg(chan, regAdress, value); + chan->flags |= CHS_KEYOFF; +} + +void TownsPC98_OpnDriver::keyOn(TwnChannel *chan) { + // all operators on + uint8 value = chan->keyNum | 0xf0; + uint8 regAdress = 0x28; + writeReg(chan, regAdress, value); +} + +void TownsPC98_OpnDriver::writeReg(TwnChannel *chan, uint8 regAdress, uint8 value) { + uint8 h = regAdress & 0xf0; + uint8 l = (regAdress & 0x0f); + static const uint8 opr[] = { 0, 2, 1, 3 }; + uint8 o = opr[(l - chan->regOffset) >> 2]; + + switch (h) { + case 0x00: + // ssg + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + case 0x10: + // adpcm + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + case 0x20: + if (l == 8) { + // Key on/off + for (int i = 0; i < 4; i++) { + if ((value >> (4 + i)) & 1) + chan->opr[i]->keyOn(); + else + chan->opr[i]->keyOff(); + } + } else if (l == 2) { + // LFO + warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); + } else if (l == 7) { + // Timers; Ch 3/6 special mode + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)"); + } else if (l == 4 || l == 5) { + // Timer A + warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)"); + } else if (l == 6) { + // Timer B + warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)"); + } else if (l == 10 || l == 11) { + // DAC + warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); + } + break; + + case 0x30: + // detune, multiple + chan->opr[o]->detune((value >> 4) & 7); + chan->opr[o]->multiple(value & 0x0f); + chan->updateEnvelopes = true; + break; + + case 0x40: + // total level + chan->opr[o]->totalLevel(value & 0x7f); + break; + + case 0x50: + // rate scaling, attack rate + chan->opr[o]->attackRate(value & 0x1f); + if (chan->opr[o]->scaleRate(value >> 6)) + chan->updateEnvelopes = true; + break; + + case 0x60: + // first decay rate, amplitude modulation + chan->opr[o]->decayRate(value & 0x1f); + if (value & 0x80) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); + + break; + + case 0x70: + // secondary decay rate + chan->opr[o]->sustainRate(value & 0x1f); + break; + + case 0x80: + // secondary amplitude, release rate; + chan->opr[o]->sustainLevel(value >> 4); + chan->opr[o]->releaseRate(value & 0x0f); + break; + + case 0x90: + // ssg + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + + case 0xa0: + // frequency + l -= chan->regOffset; + if (l == 0) { + chan->frqTemp = (chan->frqTemp & 0xff00) | value; + chan->updateEnvelopes = true; + for (int i = 0; i < 4; i++) + chan->opr[i]->frequency(chan->frqTemp); + } else if (l == 4) { + chan->frqTemp = (chan->frqTemp & 0xff) | (value << 8); + } else if (l == 8) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } else if (l == 12) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } + break; + + case 0xb0: + l -= chan->regOffset; + if (l == 0) { + // feedback, algorithm + chan->opr[0]->feedbackLevel((value >> 3) & 7); + chan->opr[1]->feedbackLevel(0); + chan->opr[2]->feedbackLevel(0); + chan->opr[3]->feedbackLevel(0); + } else if (l == 4) { + // stereo, LFO sensitivity + chan->enableLeft = value & 0x80 ? true : false; + chan->enableRight = value & 0x40 ? true : false; + uint8 ams = (value & 0x3F) >> 3; + if (ams) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); + uint8 fms = value & 3; + if (fms) + warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); + } + break; + + default: + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + } +} + +const uint8 TownsPC98_OpnDriver::_drvTables[] = { + // channel presets + 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, + 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, + 0x00, 0x80, 0x03, 0x04, 0x01, 0x08, + 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, + 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, + + // control event size + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, + 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, + + // fmt level presets + 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, + 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, + 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, + + // carriers + 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, + + // frequencies + 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, + 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, + 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, + 0x00, 0x00, 0x00, 0x00, + + // unused + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // detune + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x16, 0x16, 0x16, 0x16, + + // pc98 level presets + 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, + 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, + 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90 +}; + +const uint32 TownsPC98_OpnDriver::_adtStat[] = { + 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010101, 0x00010101, 0x00010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010102, 0x01010102, + 0x01020102, 0x01020102, 0x01020202, 0x01020202, + 0x02020202, 0x02020202, 0x02020204, 0x02020204, + 0x02040204, 0x02040204, 0x02040404, 0x02040404, + 0x04040404, 0x04040404, 0x04040408, 0x04040408, + 0x04080408, 0x04080408, 0x04080808, 0x04080808, + 0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; + SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0), _sfxFileIndex((uint)-1), _sfxWDTable(0), _sfxBTTable(0), _parser(0) { - _driver = new SoundTowns_EuphonyDriver(_mixer); + _driver = new Towns_EuphonyDriver(_mixer); int ret = open(); if (ret != MERR_ALREADY_OPEN && ret != 0) error("couldn't open midi driver"); @@ -1304,7 +2636,7 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { Common::StackLock lock(_mutex); if (!_parser) { - _parser = new MidiParser_EuD(_driver->queue()); + _parser = new Towns_EuphonyParser(_driver->queue()); _parser->setMidiDriver(this); _parser->setTimerRate(getBaseTempo()); } @@ -1356,22 +2688,73 @@ float SoundTowns::semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiTo return (float) sampleRate * 10.0f * rateshift / outputRate; } +SoundPC98::SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer) : + Sound(vm, mixer), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0) { +} + +SoundPC98::~SoundPC98() { + delete[] _musicTrackData; + delete[] _sfxTrackData; + delete _driver; +} + +bool SoundPC98::init() { + _driver = new TownsPC98_OpnDriver(_mixer, TownsPC98_OpnDriver::OD_TYPE26); + _sfxTrackData = _vm->resource()->fileData("se.dat", 0); + if (!_sfxTrackData) + return false; + return _driver->init(); +} + +void SoundPC98::playTrack(uint8 track) { + if (track == _lastTrack && _musicEnabled) + return; + + haltTrack(); + + char musicfile[13]; + sprintf(musicfile, fileListEntry(0), track); + delete[] _musicTrackData; + // This is just for testing purposes atm since we haven't found a way + // to determine the correct file yet + _musicTrackData = _vm->resource()->fileData("kyram40.dat"/*musicfile*/, 0); + if (_musicEnabled) + _driver->loadData(_musicTrackData); + + _lastTrack = track; +} + +void SoundPC98::haltTrack() { + _lastTrack = -1; + AudioCD.stop(); + AudioCD.updateCD(); + _driver->reset(); +} + +void SoundPC98::beginFadeOut() { + _driver->fadeOut(); + haltTrack(); +} + +void SoundPC98::playSoundEffect(uint8) { + /// TODO /// +} + + // KYRA 2 -SoundTowns_v2::SoundTowns_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) - : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), /*_driver(0),*/ - _twnTrackData(0) { +SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) : + Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0) { } -SoundTowns_v2::~SoundTowns_v2() { - /*if (_driver) - delete _driver;*/ - if (_twnTrackData) - delete[] _twnTrackData; +SoundTownsPC98_v2::~SoundTownsPC98_v2() { + delete[] _musicTrackData; + delete _driver; } -bool SoundTowns_v2::init() { - //_driver = new SoundTowns_v2_TwnDriver(_mixer); +bool SoundTownsPC98_v2::init() { + _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like // a good idea, we should definitely not be doing this @@ -1384,55 +2767,60 @@ bool SoundTowns_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; - return true;//_driver->init(); + return _driver->init(); } -void SoundTowns_v2::process() { +void SoundTownsPC98_v2::process() { AudioCD.updateCD(); } -void SoundTowns_v2::playTrack(uint8 track) { +void SoundTownsPC98_v2::playTrack(uint8 track) { if (track == _lastTrack && _musicEnabled) return; const uint16 * const cdaTracks = (const uint16 * const) cdaData(); int trackNum = -1; - for (int i = 0; i < cdaTrackNum(); i++) { - if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) { - trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1; - break; + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + for (int i = 0; i < cdaTrackNum(); i++) { + if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) { + trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1; + break; + } } } haltTrack(); - // TODO: figure out when to loop and when not for CD Audio - bool loop = false; + char musicfile[13]; + sprintf(musicfile, fileListEntry(0), track); + delete[] _musicTrackData; + _musicTrackData = _vm->resource()->fileData(musicfile, 0); + _driver->loadData(_musicTrackData, true); if (_musicEnabled == 2 && trackNum != -1) { - AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0); + AudioCD.play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0); AudioCD.updateCD(); } else if (_musicEnabled) { - char musicfile[13]; - sprintf(musicfile, fileListEntry(0), track); - if (_twnTrackData) - delete[] _twnTrackData; - _twnTrackData = _vm->resource()->fileData(musicfile, 0); - //_driver->loadData(_twnTrackData); + _driver->cont(); } _lastTrack = track; } -void SoundTowns_v2::haltTrack() { +void SoundTownsPC98_v2::haltTrack() { _lastTrack = -1; AudioCD.stop(); AudioCD.updateCD(); - //_driver->reset(); + _driver->reset(); } -int32 SoundTowns_v2::voicePlay(const char *file, bool) { +void SoundTownsPC98_v2::beginFadeOut() { + _driver->fadeOut(); + haltTrack(); +} + +int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 }; int h = 0; @@ -1443,7 +2831,7 @@ int32 SoundTowns_v2::voicePlay(const char *file, bool) { return 0; } - char filename [13]; + char filename[13]; sprintf(filename, "%s.PCM", file); uint8 * data = _vm->resource()->fileData(filename, 0); @@ -1500,11 +2888,6 @@ int32 SoundTowns_v2::voicePlay(const char *file, bool) { return 1; } -void SoundTowns_v2::beginFadeOut() { - //_driver->fadeOut(); - haltTrack(); -} - } // end of namespace Kyra #undef EUPHONY_FADEOUT_TICKS diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index abdf115c1e..5d094fa13f 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1034,6 +1034,9 @@ void KyraEngine_LoK::initStaticResource() { } // audio data tables + static const char *tIntro98[] = { "intro%d.dat" }; + static const char *tIngame98[] = { "kyram%d.dat" }; + static const AudioDataStruct soundData_PC[] = { { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, { _soundFiles, _soundFilesSize, 0, 0 }, @@ -1045,7 +1048,20 @@ void KyraEngine_LoK::initStaticResource() { { _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize }, { 0, 0, 0, 0} }; - _soundData = (_flags.platform == Common::kPlatformPC) ? soundData_PC : soundData_TOWNS; + + static const AudioDataStruct soundData_PC98[] = { + { tIntro98, 1, 0, 0 }, + { tIngame98, 1, 0, 0 }, + { 0, 0, 0, 0} + }; + + if (_flags.platform == Common::kPlatformPC) + _soundData = soundData_PC; + else if (_flags.platform == Common::kPlatformFMTowns) + _soundData = soundData_TOWNS; + else if (_flags.platform == Common::kPlatformPC98) + _soundData = soundData_PC98; + } void KyraEngine_LoK::loadMouseShapes() { @@ -1243,6 +1259,10 @@ void KyraEngine_HoF::initStaticResource() { static const char *fmtMusicFileListFinale[] = { "finale%d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; + static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; + static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; + static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; + static const AudioDataStruct soundData_PC[] = { { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, { _musicFileListIngame, _musicFileListIngameSize, 0, 0}, @@ -1254,7 +1274,19 @@ void KyraEngine_HoF::initStaticResource() { { fmtMusicFileListIngame, 1, _cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1 }, { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } }; - _soundData = (_flags.platform == Common::kPlatformPC) ? soundData_PC : soundData_TOWNS; + + static const AudioDataStruct soundData_PC98[] = { + { pc98MusicFileListIntro, 1, 0, 0 }, + { pc98MusicFileListIngame, 1, 0, 0 }, + { pc98MusicFileListFinale, 1, 0, 0 } + }; + + if (_flags.platform == Common::kPlatformPC) + _soundData = soundData_PC; + else if (_flags.platform == Common::kPlatformFMTowns) + _soundData = soundData_TOWNS; + else if (_flags.platform == Common::kPlatformPC98) + _soundData = soundData_PC98; // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); -- cgit v1.2.3 From 41dfebc5322a21192b29817662dff290410680b6 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 26 Jun 2008 19:56:18 +0000 Subject: Fixing compilation for me. There are still lots of "cast casts away constness" warnings, though svn-id: r32809 --- engines/kyra/sound_towns.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index a6457f509b..3aeec49fdc 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1090,10 +1090,10 @@ void Towns_EuphonyTrackQueue::initDriver() { class TownsPC98_OpnOperator { public: - TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, uint8 id, const uint8 *rateTable, + TownsPC98_OpnOperator(double rate, uint8 id, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); - TownsPC98_OpnOperator::~TownsPC98_OpnOperator() {} + ~TownsPC98_OpnOperator() {} void keyOn(); void keyOff(); -- cgit v1.2.3 From 6cdb04f9404b57d2ce92a227b18ec4bc32567bce Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Thu, 26 Jun 2008 20:13:04 +0000 Subject: cleanup svn-id: r32810 --- engines/kyra/sound_towns.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 3aeec49fdc..0fed93839c 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1455,8 +1455,9 @@ protected: int32 *_oprLevelOut; int32 *_oprDetune; - const uint8 *_trackData; - const uint8 *_patches; + uint8 *_trackData; + uint8 *_patches; + uint8 _cbCounter; uint8 _updateChannelsFlag; uint8 _finishedChannelsFlag; @@ -1626,7 +1627,7 @@ void TownsPC98_OpnDriver::loadData(uint8 * data, bool loadPaused) { _channels[i]->opr[ii] = _operators[(i << 2) + ii]; } - const uint8 *src_a = (const uint8*) data; + uint8 *src_a = data; uint8 bl = 0; for (uint8 i = 0; i < _numChan; i++) { @@ -1955,7 +1956,7 @@ void TownsPC98_OpnDriver::processEvents(TwnChannel *chan) { void TownsPC98_OpnDriver::processFrequency(TwnChannel *chan) { if (chan->flags & CHS_RECALCFREQ) { uint8 block = (chan->frqBlockMSB & 0x70) >> 1; - uint16 bfreq = ((uint16*)_twnFreqTable)[chan->frqBlockMSB & 0x0f]; + uint16 bfreq = ((const uint16*)_twnFreqTable)[chan->frqBlockMSB & 0x0f]; chan->frequency = (bfreq + chan->frqLSB) | (block << 8); writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8)); @@ -2041,7 +2042,7 @@ bool TownsPC98_OpnDriver::control_f0_setPatch(TwnChannel *chan, uint8 para) { reg += 4; } - const uint8 *tptr = (uint8*) _patches + ((uint32)chan->instrID << 5); + const uint8 *tptr = _patches + ((uint32)chan->instrID << 5); reg = chan->regOffset + 0x30; // write registers 0x30 to 0x8f @@ -2105,7 +2106,7 @@ bool TownsPC98_OpnDriver::control_f6_repeatSection(TwnChannel *chan, uint8 para) if (*chan->dataPtr) { // repeat section until counter has reached zero - chan->dataPtr = (uint8*) _trackData + READ_LE_UINT16(chan->dataPtr + 2); + chan->dataPtr = _trackData + READ_LE_UINT16(chan->dataPtr + 2); } else { // reset counter, advance to next section chan->dataPtr[0] = chan->dataPtr[1]; @@ -2180,7 +2181,7 @@ bool TownsPC98_OpnDriver::control_fc_decOutLevel(TwnChannel *chan, uint8 para) { } bool TownsPC98_OpnDriver::control_fd_jump(TwnChannel *chan, uint8 para) { - uint8 *tmp = (uint8*) _trackData + READ_LE_UINT16(chan->dataPtr - 1); + uint8 *tmp = _trackData + READ_LE_UINT16(chan->dataPtr - 1); chan->dataPtr = (tmp[1] == 1) ? tmp : ++chan->dataPtr; return true; } @@ -2194,7 +2195,7 @@ bool TownsPC98_OpnDriver::control_ff_endOfTrack(TwnChannel *chan, uint8 para) { uint16 val = READ_LE_UINT16(--chan->dataPtr); if (val) { // loop - chan->dataPtr = (uint8 *) _trackData + val; + chan->dataPtr = _trackData + val; return true; } else { // quit parsing for active channel -- cgit v1.2.3 From b695cb74ca3c4e3fe671e670f70d18d503df953c Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Thu, 26 Jun 2008 20:30:43 +0000 Subject: more cleanup svn-id: r32811 --- engines/kyra/sound_towns.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 0fed93839c..550908fd0f 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1103,7 +1103,7 @@ public: void generateOutput(int phasebuf, int *feedbuf, int &out); void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } - void detune(int value) { _detn = (int32*) &_detnTbl[value << 5]; } + void detune(int value) { _detn = &_detnTbl[value << 5]; } void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } void attackRate(uint32 value) { _specifiedAttackRate = value; } bool scaleRate(uint8 value); @@ -1132,7 +1132,7 @@ protected: uint8 _kcode; uint32 _phase; uint32 _phaseIncrement; - int32 *_detn; + const int32 *_detn; const uint8 *_rateTbl; const uint8 *_rshiftTbl; @@ -1297,7 +1297,7 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out) void TownsPC98_OpnOperator::reset(){ keyOff(); _tick = 0; - _keyScale2 = -1; + _keyScale2 = 0; _currentLevel = 1023; frequency(0); @@ -1676,7 +1676,7 @@ void TownsPC98_OpnDriver::loadData(uint8 * data, bool loadPaused) { //_channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; //_channels[i]->ticksLeft = 1; //_channels[i]->dataPtr = data + READ_LE_UINT16(src_a); - uint8 *tmp = data + READ_LE_UINT16(src_a); + //uint8 *tmp = data + READ_LE_UINT16(src_a); src_a += 2; } @@ -1755,7 +1755,7 @@ void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { int *feed = _channels[i]->feedbuf; int *del = &feed[2]; - for (int ii = 0; ii < bufferSize ; ii++) { + for (uint32 ii = 0; ii < bufferSize ; ii++) { phbuf1 = phbuf2 = output = 0; switch (_channels[i]->algorithm) { @@ -1903,7 +1903,6 @@ void TownsPC98_OpnDriver::generateTables() { delete [] _oprDetune; _oprDetune = new int32[256]; for (int i = 0; i < 128; i++) { - double rate = ((double)dtt[i]) * 1024.0 * _baserate * (1<<16) / ((double)(1<<20)); _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); _oprDetune[i + 128] = -_oprDetune[i]; } @@ -2133,9 +2132,9 @@ bool TownsPC98_OpnDriver::control_f8_togglePitchWheel(TwnChannel *chan, uint8 pa chan->flags |= CHS_PITCHWHEELOFF; } } else { - uint8 skipChannels = para / 36; - uint8 entry = para % 36; - TownsPC98_OpnDriver::TwnChannel *t = &chan[skipChannels]; + //uint8 skipChannels = para / 36; + //uint8 entry = para % 36; + //TownsPC98_OpnDriver::TwnChannel *t = &chan[skipChannels]; ////// NOT IMPLEMENTED //t->unnamedEntries[entry] = *chan->dataPtr++; } -- cgit v1.2.3 From 0bea51974e4173cd7432348c334a6bb49f4aca6f Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Thu, 26 Jun 2008 20:43:23 +0000 Subject: fix bad const casts svn-id: r32812 --- engines/kyra/sound_towns.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 550908fd0f..40a746f1de 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -159,7 +159,7 @@ public: void loadDataToEndOfQueue(uint8 *trackdata, uint32 size, bool loop = 0); void setPlayBackStatus(bool playing); bool isPlaying() {return _playing; } - const uint8 * trackData() {return _trackData; } + uint8 *trackData() {return _trackData; } bool _loop; Towns_EuphonyTrackQueue *_next; @@ -807,7 +807,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { if (info.ext.type == 0x2F) { unloadMusic(); memset(&info, 0, sizeof(EventInfo)); - pos = _position._play_pos = _tracks[0] = (byte*) _queue->trackData() + 0x806; + pos = _position._play_pos = _tracks[0] = _queue->trackData() + 0x806; } else if (_active_track == 255) { _queue = _queue->_next; setup(); @@ -964,7 +964,7 @@ void Towns_EuphonyParser::resetTracking() { } void Towns_EuphonyParser::setup() { - uint8 *data = (uint8 *) _queue->trackData(); + uint8 *data = _queue->trackData(); if (!data) return; _queue->initDriver(); -- cgit v1.2.3 From 8cd03780f68a8558fd6b816629b0c2e3c9517a41 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Thu, 26 Jun 2008 23:30:45 +0000 Subject: Implemented Operation Stealth's version of addOverlay(objectIndex, overlayType). svn-id: r32816 --- engines/cine/object.cpp | 17 ++++++++++++++--- engines/cine/object.h | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index b00a636ae6..57a328eef9 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -99,21 +99,32 @@ int removeOverlay(uint16 objIdx, uint16 param) { /*! \brief Add new overlay sprite to the list * \param objIdx Associate the overlay with this object - * \param param Type of new overlay + * \param type Type of new overlay * \todo Why are x, y, width and color left uninitialized? */ -void addOverlay(uint16 objIdx, uint16 param) { +void addOverlay(uint16 objIdx, uint16 type) { Common::List::iterator it; overlay tmp; for (it = overlayList.begin(); it != overlayList.end(); ++it) { + // This is done for both Future Wars and Operation Stealth if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask) { break; } + + // There are additional checks in Operation Stealth's implementation + if (g_cine->getGameType() == Cine::GType_OS && (it->type == 2 || it->type == 3)) { + break; + } + } + + // In Operation Stealth's implementation we might bail out early + if (g_cine->getGameType() == Cine::GType_OS && it != overlayList.end() && it->objIdx == objIdx && it->type == type) { + return; } tmp.objIdx = objIdx; - tmp.type = param; + tmp.type = type; overlayList.insert(it, tmp); } diff --git a/engines/cine/object.h b/engines/cine/object.h index 12e72927e1..103b2f50ba 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -60,7 +60,7 @@ void loadObject(char *pObjectName); void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4); void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue); -void addOverlay(uint16 objIdx, uint16 param); +void addOverlay(uint16 objIdx, uint16 type); int removeOverlay(uint16 objIdx, uint16 param); void addGfxElement(int16 objIdx, int16 param, int16 type); void removeGfxElement(int16 objIdx, int16 param, int16 type); -- cgit v1.2.3 From b6ad2b00350dffbc4051f3d5eb27b9ce5cb198c4 Mon Sep 17 00:00:00 2001 From: Benjamin Haisch Date: Fri, 27 Jun 2008 09:57:38 +0000 Subject: - Fixed umlauts in printText - Don't exit when a pmv video couldn't be found svn-id: r32817 --- engines/made/pmvplayer.cpp | 5 ++++- engines/made/screen.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp index 1a8ca9c50a..831f1fab8e 100644 --- a/engines/made/pmvplayer.cpp +++ b/engines/made/pmvplayer.cpp @@ -40,7 +40,10 @@ void PmvPlayer::play(const char *filename) { _surface = NULL; _fd = new Common::File(); - _fd->open(filename); + if (!_fd->open(filename)) { + delete _fd; + return; + } uint32 chunkType, chunkSize; diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index cecd0c8968..1d81793448 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -688,7 +688,7 @@ void Screen::printText(const char *text) { for (int textPos = 0; textPos < textLen; textPos++) { - uint c = text[textPos]; + uint c = ((byte*)text)[textPos]; int charWidth = _font->getCharWidth(c); if (c == 9) { -- cgit v1.2.3 From e97dff9f33697fac6741a74c02e1034fb126a304 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sat, 28 Jun 2008 13:13:37 +0000 Subject: - HOF: bug fix for music driver - KYRA1 PC98: fix music file selection svn-id: r32819 --- engines/kyra/sound_lok.cpp | 12 ++++++------ engines/kyra/sound_towns.cpp | 12 ++++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp index d320536507..7d6e1dd378 100644 --- a/engines/kyra/sound_lok.cpp +++ b/engines/kyra/sound_lok.cpp @@ -57,12 +57,12 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) { _sound->haltTrack(); } } else if (_flags.platform == Common::kPlatformPC98) { - - ////////////// - //// TODO //// - ////////////// - _sound->playTrack(command); - + if (command == 1) + _sound->beginFadeOut(); + else if (command >= 2) + _sound->playTrack(command); + else + _sound->haltTrack(); } else { KyraEngine_v1::snd_playWanderScoreViaMap(command, restart); } diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 40a746f1de..b487afe8f8 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1273,6 +1273,8 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out) o = &feedbuf[0]; i = &feedbuf[1]; phaseShift = _feedbackLevel ? ((feedbuf[0] + feedbuf[1]) << _feedbackLevel) : 0; + if (phasebuf == -1) + *i = 0; *o = *i; } else { phaseShift = phasebuf << 15; @@ -1796,7 +1798,7 @@ void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { break; case 5: *del = feed[1]; - _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); + _channels[i]->opr[0]->generateOutput(-1, feed, phbuf1); _channels[i]->opr[2]->generateOutput(*del, 0, output); _channels[i]->opr[1]->generateOutput(*del, 0, output); _channels[i]->opr[3]->generateOutput(*del, 0, output); @@ -2707,6 +2709,9 @@ bool SoundPC98::init() { } void SoundPC98::playTrack(uint8 track) { + if (--track >= 56) + track -= 55; + if (track == _lastTrack && _musicEnabled) return; @@ -2715,9 +2720,7 @@ void SoundPC98::playTrack(uint8 track) { char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); delete[] _musicTrackData; - // This is just for testing purposes atm since we haven't found a way - // to determine the correct file yet - _musicTrackData = _vm->resource()->fileData("kyram40.dat"/*musicfile*/, 0); + _musicTrackData = _vm->resource()->fileData(musicfile, 0); if (_musicEnabled) _driver->loadData(_musicTrackData); @@ -2767,6 +2770,7 @@ bool SoundTownsPC98_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; + _musicEnabled = 1; return _driver->init(); } -- cgit v1.2.3 From e6e56feb1c61e9d4edb6032e9b759f9875ef00af Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sat, 28 Jun 2008 13:31:58 +0000 Subject: Added comment for fix for bug #2001193. svn-id: r32820 --- engines/parallaction/callables_ns.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 36f5b00c5b..3ecc7a9534 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -417,7 +417,9 @@ void Parallaction_ns::_c_ridux(void *parm) { } void Parallaction_ns::_c_testResult(void *parm) { - if (_inTestResult) { + if (_inTestResult) { // NOTE: _inTestResult has been added because the scripts call _c_testResult multiple times to cope with + // the multiple buffering that was used in the original engine. _inTestResult now prevents the engine + // from crashing when the scripts are executed. return; } _inTestResult = true; -- cgit v1.2.3 From 09247e7e5a5a78d050b716365a22dc9ccb61b078 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sat, 28 Jun 2008 13:40:03 +0000 Subject: hof: remove debug code svn-id: r32821 --- engines/kyra/sound_towns.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index b487afe8f8..5c9e14e52d 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -2770,7 +2770,6 @@ bool SoundTownsPC98_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; - _musicEnabled = 1; return _driver->init(); } -- cgit v1.2.3 From 3f878008dacf420fe48615fd45ae732dc13b1a54 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sat, 28 Jun 2008 15:36:50 +0000 Subject: - implement music fading for Hof FM-Towns svn-id: r32829 --- engines/kyra/sound_towns.cpp | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 5c9e14e52d..4971d39178 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1090,7 +1090,7 @@ void Towns_EuphonyTrackQueue::initDriver() { class TownsPC98_OpnOperator { public: - TownsPC98_OpnOperator(double rate, uint8 id, const uint8 *rateTable, + TownsPC98_OpnOperator(double rate, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); ~TownsPC98_OpnOperator() {} @@ -1152,9 +1152,9 @@ protected: } fs_a, fs_d, fs_s, fs_r; }; -TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, uint8 id, - const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, - const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : +TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0), _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), @@ -1467,6 +1467,7 @@ protected: bool _playing; bool _fading; uint8 _looping; + uint32 _tickCounter; bool _updateEnvelopes; @@ -1490,7 +1491,7 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : _operators(0), _looping(0), _twnCarrier(_drvTables + 76), _twnFreqTable(_drvTables + 84), _twnFxCmdLen(_drvTables + 36), _twnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), - _oprDetune(0), _cbCounter(4), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), + _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { @@ -1536,7 +1537,7 @@ bool TownsPC98_OpnDriver::init() { _operators = new TownsPC98_OpnOperator*[(_numChan << 2)]; for (int i = 0; i < (_numChan << 2); i++) - _operators[i] = new TownsPC98_OpnOperator(_baserate, i & 3, _oprRates, + _operators[i] = new TownsPC98_OpnOperator(_baserate, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); if (_channels) { @@ -1702,6 +1703,7 @@ void TownsPC98_OpnDriver::reset() { _playing = false; _looping = 0; + _tickCounter = 0; } void TownsPC98_OpnDriver::fadeOut() { @@ -1711,16 +1713,29 @@ void TownsPC98_OpnDriver::fadeOut() { _fading = true; for (int i = 0; i < 20; i++) { - - /// TODO /// - // twnFade(); - //waitTicks(s); + lock(); + uint32 dTime = _tickCounter + 2; + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->idFlag) { + uint8 tmp = _channels[i]->totalLevel + 3; + if (tmp > 0x7f) + tmp = 0x7f; + _channels[i]->totalLevel = tmp; + setOutputLevel(_channels[i]); + } + } + unlock(); + + while (_playing) { + if (_tickCounter >= dTime) + break; + } } _fading = false; - //haltTrack(); + reset(); } void TownsPC98_OpnDriver::callback() { @@ -1728,6 +1743,7 @@ void TownsPC98_OpnDriver::callback() { return; _cbCounter = 4; + _tickCounter++; lock(); for (int i = 0; i < _numChan; i++) { @@ -2770,6 +2786,7 @@ bool SoundTownsPC98_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; + _musicEnabled = 1; return _driver->init(); } @@ -2793,7 +2810,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) { } } - haltTrack(); + beginFadeOut(); char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); -- cgit v1.2.3 From 0184a7b0f9a5bbe4946c2e854f5cbe3c92457474 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Sat, 28 Jun 2008 16:00:04 +0000 Subject: Fixed warning. (Hopefully without breaking anything.) svn-id: r32830 --- engines/kyra/sound_towns.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 4971d39178..92e39fc769 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1716,13 +1716,13 @@ void TownsPC98_OpnDriver::fadeOut() { lock(); uint32 dTime = _tickCounter + 2; - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->idFlag) { - uint8 tmp = _channels[i]->totalLevel + 3; + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->idFlag) { + uint8 tmp = _channels[j]->totalLevel + 3; if (tmp > 0x7f) tmp = 0x7f; - _channels[i]->totalLevel = tmp; - setOutputLevel(_channels[i]); + _channels[j]->totalLevel = tmp; + setOutputLevel(_channels[j]); } } unlock(); -- cgit v1.2.3 From d8645297cd174fbbd7059a317975c45adefaa5e5 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 29 Jun 2008 09:30:32 +0000 Subject: Changed all remaining code to use the GfxObj class to keep frames data. This allows for more uniform processing during rendering, and also fixes the display of dialogue faces for BRA. svn-id: r32833 --- engines/parallaction/dialogue.cpp | 6 ++--- engines/parallaction/disk.h | 46 ++++++++++++++++++------------------- engines/parallaction/disk_br.cpp | 28 +++++++++++----------- engines/parallaction/disk_ns.cpp | 42 ++++++++++++++++----------------- engines/parallaction/gfxbase.cpp | 12 +++++----- engines/parallaction/graphics.cpp | 20 ++++++++++++---- engines/parallaction/graphics.h | 10 ++++---- engines/parallaction/gui_br.cpp | 4 ++-- engines/parallaction/objects.h | 2 +- engines/parallaction/parallaction.h | 6 ++--- 10 files changed, 93 insertions(+), 83 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 903c71907c..3b6c35d3bb 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -51,8 +51,8 @@ class DialogueManager { bool _askPassword; bool isNpc; - Frames *_questioner; - Frames *_answerer; + GfxObj *_questioner; + GfxObj *_answerer; Question *_q; @@ -229,7 +229,7 @@ void DialogueManager::run() { answer = 0; displayQuestion(); - + if (_engineFlags & kEngineQuit) return; diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index b76c66aead..176f10aa10 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -55,13 +55,13 @@ public: virtual Script* loadLocation(const char *name) = 0; virtual Script* loadScript(const char* name) = 0; - virtual Frames* loadTalk(const char *name) = 0; - virtual Frames* loadObjects(const char *name) = 0; + virtual GfxObj* loadTalk(const char *name) = 0; + virtual GfxObj* loadObjects(const char *name) = 0; virtual Frames* loadPointer(const char *name) = 0; - virtual Frames* loadHead(const char* name) = 0; + virtual GfxObj* loadHead(const char* name) = 0; virtual Font* loadFont(const char* name) = 0; - virtual Frames* loadStatic(const char* name) = 0; - virtual Frames* loadFrames(const char* name) = 0; + virtual GfxObj* loadStatic(const char* name) = 0; + virtual GfxObj* 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; @@ -147,13 +147,13 @@ public: Script* loadLocation(const char *name); Script* loadScript(const char* name); - Frames* loadTalk(const char *name); - Frames* loadObjects(const char *name); + GfxObj* loadTalk(const char *name); + GfxObj* loadObjects(const char *name); Frames* loadPointer(const char *name); - Frames* loadHead(const char* name); + GfxObj* loadHead(const char* name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); - Frames* loadFrames(const char* name); + GfxObj* loadStatic(const char* name); + GfxObj* 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); @@ -181,13 +181,13 @@ public: Script* loadLocation(const char *name); Script* loadScript(const char* name); - Frames* loadTalk(const char *name); - Frames* loadObjects(const char *name); + GfxObj* loadTalk(const char *name); + GfxObj* loadObjects(const char *name); Frames* loadPointer(const char *name); - Frames* loadHead(const char* name); + GfxObj* loadHead(const char* name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); - Frames* loadFrames(const char* name); + GfxObj* loadStatic(const char* name); + GfxObj* 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); @@ -220,13 +220,13 @@ public: void setLanguage(uint16 language); Script* loadLocation(const char *name); Script* loadScript(const char* name); - Frames* loadTalk(const char *name); - Frames* loadObjects(const char *name); + GfxObj* loadTalk(const char *name); + GfxObj* loadObjects(const char *name); Frames* loadPointer(const char *name); - Frames* loadHead(const char* name); + GfxObj* loadHead(const char* name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); - Frames* loadFrames(const char* name); + GfxObj* loadStatic(const char* name); + GfxObj* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); Table* loadTable(const char* name); @@ -248,10 +248,10 @@ public: AmigaDisk_br(Parallaction *vm); virtual ~AmigaDisk_br(); - Frames* loadTalk(const char *name); + GfxObj* loadTalk(const char *name); Font* loadFont(const char* name); - Frames* loadStatic(const char* name); - Frames* loadFrames(const char* name); + GfxObj* loadStatic(const char* name); + GfxObj* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); }; diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 5e88327879..0159d9d406 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -138,7 +138,7 @@ DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) { DosDisk_br::~DosDisk_br() { } -Frames* DosDisk_br::loadTalk(const char *name) { +GfxObj* DosDisk_br::loadTalk(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name); Common::File stream; @@ -151,7 +151,7 @@ Frames* DosDisk_br::loadTalk(const char *name) { errorFileNotFound(path); } - return createSprites(stream); + return new GfxObj(0, createSprites(stream), name); } Script* DosDisk_br::loadLocation(const char *name) { @@ -184,7 +184,7 @@ Script* DosDisk_br::loadScript(const char* name) { } // there are no Head resources in Big Red Adventure -Frames* DosDisk_br::loadHead(const char* name) { +GfxObj* DosDisk_br::loadHead(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadHead"); return 0; } @@ -235,7 +235,7 @@ Font* DosDisk_br::loadFont(const char* name) { } -Frames* DosDisk_br::loadObjects(const char *name) { +GfxObj* DosDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); return 0; } @@ -244,7 +244,7 @@ void genSlidePath(char *path, const char* name) { sprintf(path, "%s.bmp", name); } -Frames* DosDisk_br::loadStatic(const char* name) { +GfxObj* DosDisk_br::loadStatic(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadStatic"); char path[PATH_LEN]; @@ -256,7 +256,7 @@ Frames* DosDisk_br::loadStatic(const char* name) { Graphics::Surface *surf = new Graphics::Surface; loadBitmap(stream, *surf, 0); - return new SurfaceToFrames(surf); + return new GfxObj(0, new SurfaceToFrames(surf), name); } Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) { @@ -280,7 +280,7 @@ Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) { return sprites; } -Frames* DosDisk_br::loadFrames(const char* name) { +GfxObj* DosDisk_br::loadFrames(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); char path[PATH_LEN]; @@ -291,7 +291,7 @@ Frames* DosDisk_br::loadFrames(const char* name) { errorFileNotFound(path); - return createSprites(stream); + return new GfxObj(0, createSprites(stream), name); } // Slides in Nippon Safes are basically screen-sized pictures with valid @@ -552,7 +552,7 @@ void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) { return; } -Frames* AmigaDisk_br::loadStatic(const char* name) { +GfxObj* AmigaDisk_br::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name); char path[PATH_LEN]; @@ -570,7 +570,7 @@ Frames* AmigaDisk_br::loadStatic(const char* name) { free(pal); - return new SurfaceToFrames(surf); + return new GfxObj(0, new SurfaceToFrames(surf)); } Sprites* AmigaDisk_br::createSprites(const char *path) { @@ -600,22 +600,22 @@ Sprites* AmigaDisk_br::createSprites(const char *path) { return sprites; } -Frames* AmigaDisk_br::loadFrames(const char* name) { +GfxObj* AmigaDisk_br::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name); char path[PATH_LEN]; sprintf(path, "%s/anims/%s", _partPath, name); - return createSprites(path); + return new GfxObj(0, createSprites(path)); } -Frames* AmigaDisk_br::loadTalk(const char *name) { +GfxObj* AmigaDisk_br::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name); char path[PATH_LEN]; sprintf(path, "%s/talks/%s.tal", _partPath, name); - return createSprites(path); + return new GfxObj(0, createSprites(path)); } Font* AmigaDisk_br::loadFont(const char* name) { diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 8f4f6d8e20..f45cf83f56 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -385,12 +385,12 @@ Cnv* DosDisk_ns::loadCnv(const char *filename) { return new Cnv(numFrames, width, height, data); } -Frames* DosDisk_ns::loadTalk(const char *name) { +GfxObj* DosDisk_ns::loadTalk(const char *name) { const char *ext = strstr(name, ".talk"); if (ext != NULL) { // npc talk - return loadCnv(name); + return new GfxObj(0, loadCnv(name), name); } @@ -401,7 +401,7 @@ Frames* DosDisk_ns::loadTalk(const char *name) { sprintf(v20, "%stal", name); } - return loadExternalCnv(v20); + return new GfxObj(0, loadExternalCnv(v20), name); } Script* DosDisk_ns::loadLocation(const char *name) { @@ -434,14 +434,14 @@ Script* DosDisk_ns::loadScript(const char* name) { return new Script(new DummyArchiveStream(_resArchive), true); } -Frames* DosDisk_ns::loadHead(const char* name) { +GfxObj* DosDisk_ns::loadHead(const char* name) { char path[PATH_LEN]; sprintf(path, "%shead", name); path[8] = '\0'; - return loadExternalStaticCnv(path); + return new GfxObj(0, loadExternalStaticCnv(path)); } @@ -457,15 +457,15 @@ Font* DosDisk_ns::loadFont(const char* name) { } -Frames* DosDisk_ns::loadObjects(const char *name) { +GfxObj* DosDisk_ns::loadObjects(const char *name) { char path[PATH_LEN]; sprintf(path, "%sobj", name); - return loadExternalCnv(path); + return new GfxObj(0, loadExternalCnv(path), name); } -Frames* DosDisk_ns::loadStatic(const char* name) { +GfxObj* DosDisk_ns::loadStatic(const char* name) { char path[PATH_LEN]; @@ -487,11 +487,11 @@ Frames* DosDisk_ns::loadStatic(const char* name) { Graphics::PackBitsReadStream decoder(_resArchive); decoder.read(cnv->pixels, w*h); - return new SurfaceToFrames(cnv); + return new GfxObj(0, new SurfaceToFrames(cnv), name); } -Frames* DosDisk_ns::loadFrames(const char* name) { - return loadCnv(name); +GfxObj* DosDisk_ns::loadFrames(const char* name) { + return new GfxObj(0, loadCnv(name), name); } // @@ -1025,7 +1025,7 @@ Frames* AmigaDisk_ns::loadPointer(const char* name) { return makeStaticCnv(stream); } -Frames* AmigaDisk_ns::loadStatic(const char* name) { +GfxObj* AmigaDisk_ns::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadStatic '%s'", name); Common::SeekableReadStream *s = openArchivedFile(name, true); @@ -1033,7 +1033,7 @@ Frames* AmigaDisk_ns::loadStatic(const char* name) { delete s; - return cnv; + return new GfxObj(0, cnv, name); } Common::SeekableReadStream *AmigaDisk_ns::openArchivedFile(const char* name, bool errorOnFileNotFound) { @@ -1258,7 +1258,7 @@ void AmigaDisk_ns::loadSlide(BackgroundInfo& info, const char *name) { return; } -Frames* AmigaDisk_ns::loadFrames(const char* name) { +GfxObj* AmigaDisk_ns::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadFrames '%s'", name); Common::SeekableReadStream *s; @@ -1273,10 +1273,10 @@ Frames* AmigaDisk_ns::loadFrames(const char* name) { Cnv *cnv = makeCnv(*s); delete s; - return cnv; + return new GfxObj(0, cnv, name); } -Frames* AmigaDisk_ns::loadHead(const char* name) { +GfxObj* AmigaDisk_ns::loadHead(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadHead '%s'", name); char path[PATH_LEN]; @@ -1287,11 +1287,11 @@ Frames* AmigaDisk_ns::loadHead(const char* name) { delete s; - return cnv; + return new GfxObj(0, cnv, name); } -Frames* AmigaDisk_ns::loadObjects(const char *name) { +GfxObj* AmigaDisk_ns::loadObjects(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadObjects"); char path[PATH_LEN]; @@ -1305,11 +1305,11 @@ Frames* AmigaDisk_ns::loadObjects(const char *name) { Cnv *cnv = makeCnv(*s); delete s; - return cnv; + return new GfxObj(0, cnv, name); } -Frames* AmigaDisk_ns::loadTalk(const char *name) { +GfxObj* AmigaDisk_ns::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadTalk '%s'", name); Common::SeekableReadStream *s; @@ -1328,7 +1328,7 @@ Frames* AmigaDisk_ns::loadTalk(const char *name) { Cnv *cnv = makeCnv(*s); delete s; - return cnv; + return new GfxObj(0, cnv, name); } Table* AmigaDisk_ns::loadTable(const char* name) { diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 6599a1f81c..dc28d9d425 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -86,27 +86,27 @@ void GfxObj::clearFlags(uint32 flags) { } GfxObj* Gfx::loadAnim(const char *name) { - Frames *frames = _disk->loadFrames(name); - GfxObj *obj = new GfxObj(kGfxObjTypeAnim, frames, name); + GfxObj *obj = _disk->loadFrames(name); assert(obj); + obj->type = kGfxObjTypeAnim; return obj; } GfxObj* Gfx::loadGet(const char *name) { - Frames *frames = _disk->loadStatic(name); - GfxObj *obj = new GfxObj(kGfxObjTypeGet, frames, name); + GfxObj *obj = _disk->loadStatic(name); assert(obj); + obj->type = kGfxObjTypeGet; return obj; } GfxObj* Gfx::loadDoor(const char *name) { - Frames *frames = _disk->loadFrames(name); - GfxObj *obj = new GfxObj(kGfxObjTypeDoor, frames, name); + GfxObj *obj = _disk->loadFrames(name); assert(obj); + obj->type = kGfxObjTypeDoor; return obj; } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 58fb02a750..64edd7babe 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -356,7 +356,17 @@ void Gfx::drawItems() { Graphics::Surface *surf = g_system->lockScreen(); for (uint i = 0; i < _numItems; i++) { - blt(_items[i].rect, _items[i].data->getData(_items[i].frame), surf, LAYER_FOREGROUND, _items[i].transparentColor); + GfxObj *obj = _items[i].data; + + Common::Rect rect; + obj->getRect(obj->frame, rect); + rect.translate(obj->x, obj->y); + + if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { + blt(rect, obj->getData(obj->frame), surf, LAYER_FOREGROUND, _items[i].transparentColor); + } else { + unpackBlt(rect, obj->getData(obj->frame), obj->getRawSize(obj->frame), surf, LAYER_FOREGROUND, _items[i].transparentColor); + } } g_system->unlockScreen(); } @@ -949,7 +959,7 @@ Gfx::~Gfx() { -int Gfx::setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor) { +int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) { int id = _numItems; _items[id].data = frames; @@ -965,9 +975,9 @@ int Gfx::setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor) { void Gfx::setItemFrame(uint item, uint16 f) { assert(item < _numItems); - _items[item].frame = f; - _items[item].data->getRect(f, _items[item].rect); - _items[item].rect.moveTo(_items[item].x, _items[item].y); + _items[item].data->frame = f; + _items[item].data->x = _items[item].x; + _items[item].data->y = _items[item].y; } Gfx::Balloon* Gfx::getBalloon(uint id) { diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index f03b8538b8..c4b0c7b321 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -157,11 +157,11 @@ struct SurfaceToMultiFrames : public Frames { r.setHeight(_height); } uint getRawSize(uint16 index) { - assert(index == 0); + assert(index < _num); return getSize(index); } uint getSize(uint16 index) { - assert(index == 0); + assert(index < _num); return _width * _height; } @@ -487,7 +487,7 @@ public: void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height); // other items - int setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor = 0); + int setItem(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0); void setItemFrame(uint item, uint16 f); void hideDialogueStuff(); void freeBalloons(); @@ -549,7 +549,7 @@ protected: Graphics::Surface _bitmapMask; int32 getRenderMode(const char *type); -protected: +public: static int16 _dialogueBalloonX[5]; struct Balloon { @@ -567,7 +567,7 @@ protected: uint16 x; uint16 y; uint16 frame; - Frames *data; + GfxObj *data; byte transparentColor; Common::Rect rect; diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index c515299a34..5551108693 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -122,7 +122,7 @@ int Parallaction_br::guiShowMenu() { // TODO: filter menu entries according to progress in game #define NUM_MENULINES 7 - Frames *_lines[NUM_MENULINES]; + GfxObj *_lines[NUM_MENULINES]; const char *menuStrings[NUM_MENULINES] = { "SEE INTRO", @@ -157,7 +157,7 @@ int Parallaction_br::guiShowMenu() { int i; for (i = 0; i < availItems; i++) { - _lines[i] = guiRenderMenuItem(menuStrings[i]); + _lines[i] = new GfxObj(0, guiRenderMenuItem(menuStrings[i]), "MenuItem"); uint id = _gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF); _gfx->setItemFrame(id, 0); } diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index 2bc9df0bbe..44ad35e0ab 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -209,7 +209,7 @@ struct SpeakData { // size = 36 } }; struct ExamineData { // size = 28 - Frames *_cnv; + GfxObj *_cnv; uint16 _opBase; // unused uint16 field_12; // unused char* _description; diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index f9c2c86a1b..b1a5995e28 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -202,9 +202,9 @@ struct Character { AnimationPtr _ani; - Frames *_head; - Frames *_talk; - Frames *_objs; + GfxObj *_head; + GfxObj *_talk; + GfxObj *_objs; PathBuilder _builder; WalkNodeList *_walkPath; -- cgit v1.2.3 From 206485ffc676c64134774b9873cd8d333deddfee Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 29 Jun 2008 09:56:44 +0000 Subject: Merged the three render lists (for animations, doors and objects) into a single one. svn-id: r32834 --- engines/parallaction/debug.cpp | 14 +++++------- engines/parallaction/gfxbase.cpp | 47 ++++++++++++++++++++-------------------- engines/parallaction/graphics.h | 12 ++++++++-- 3 files changed, 39 insertions(+), 34 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp index 3c90a76f61..6bd704a2f5 100644 --- a/engines/parallaction/debug.cpp +++ b/engines/parallaction/debug.cpp @@ -191,14 +191,12 @@ bool Debugger::Cmd_GfxObjects(int argc, const char **argv) { "| name | x | y | z | f | type | flag |\n" "+--------------------+-----+-----+-----+-----+--------+--------+\n"); - for (uint i = 0; i < 3; i++) { - GfxObjList::iterator b = _vm->_gfx->_gfxobjList[i].begin(); - GfxObjList::iterator e = _vm->_gfx->_gfxobjList[i].end(); - - for ( ; b != e; b++) { - GfxObj *obj = *b; - DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], 6 ); - } + GfxObjList::iterator b = _vm->_gfx->_gfxobjList.begin(); + GfxObjList::iterator e = _vm->_gfx->_gfxobjList.end(); + + for ( ; b != e; b++) { + GfxObj *obj = *b; + DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], 6 ); } DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n"); diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index dc28d9d425..66b1ceecf7 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -89,6 +89,8 @@ GfxObj* Gfx::loadAnim(const char *name) { GfxObj *obj = _disk->loadFrames(name); assert(obj); + // animation Z is not set here, but controlled by game scripts and user interaction. + // it is always >=0 and type = kGfxObjTypeAnim; return obj; } @@ -98,6 +100,7 @@ GfxObj* Gfx::loadGet(const char *name) { GfxObj *obj = _disk->loadStatic(name); assert(obj); + obj->z = kGfxObjGetZ; // this preset Z value ensures that get zones are drawn after doors but before animations obj->type = kGfxObjTypeGet; return obj; } @@ -106,14 +109,13 @@ GfxObj* Gfx::loadDoor(const char *name) { GfxObj *obj = _disk->loadFrames(name); assert(obj); + obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first obj->type = kGfxObjTypeDoor; return obj; } void Gfx::clearGfxObjects() { - _gfxobjList[0].clear(); - _gfxobjList[1].clear(); - _gfxobjList[2].clear(); + _gfxobjList.clear(); } void Gfx::showGfxObj(GfxObj* obj, bool visible) { @@ -123,25 +125,25 @@ void Gfx::showGfxObj(GfxObj* obj, bool visible) { if (visible) { obj->setFlags(kGfxObjVisible); - _gfxobjList[obj->type].push_back(obj); + _gfxobjList.push_back(obj); } else { obj->clearFlags(kGfxObjVisible); - _gfxobjList[obj->type].remove(obj); + _gfxobjList.remove(obj); } } -bool compareAnimationZ(const GfxObj* a1, const GfxObj* a2) { +bool compareZ(const GfxObj* a1, const GfxObj* a2) { return a1->z < a2->z; } void Gfx::sortAnimations() { - GfxObjList::iterator first = _gfxobjList[kGfxObjTypeAnim].begin(); - GfxObjList::iterator last = _gfxobjList[kGfxObjTypeAnim].end(); + GfxObjList::iterator first = _gfxobjList.begin(); + GfxObjList::iterator last = _gfxobjList.end(); - Common::sort(first, last, compareAnimationZ); + Common::sort(first, last, compareZ); } void Gfx::drawGfxObjects(Graphics::Surface &surf) { @@ -154,22 +156,19 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) { // TODO: Dr.Ki is not visible inside the club - for (uint i = 0; i < 3; i++) { + GfxObjList::iterator b = _gfxobjList.begin(); + GfxObjList::iterator e = _gfxobjList.end(); - GfxObjList::iterator b = _gfxobjList[i].begin(); - GfxObjList::iterator e = _gfxobjList[i].end(); - - for (; b != e; b++) { - GfxObj *obj = *b; - if (obj->isVisible()) { - obj->getRect(obj->frame, rect); - rect.translate(obj->x - _varScrollX, obj->y); - data = obj->getData(obj->frame); - if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { - blt(rect, data, &surf, obj->layer, 0); - } else { - unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, 0); - } + for (; b != e; b++) { + GfxObj *obj = *b; + if (obj->isVisible()) { + obj->getRect(obj->frame, rect); + rect.translate(obj->x - _varScrollX, obj->y); + data = obj->getData(obj->frame); + if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { + blt(rect, data, &surf, obj->layer, 0); + } else { + unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, 0); } } } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index c4b0c7b321..6439941cc5 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -360,6 +360,11 @@ enum { kGfxObjTypeAnim = 2 }; +enum { + kGfxObjDoorZ = -200, + kGfxObjGetZ = -100 +}; + class GfxObj { char *_name; Frames *_frames; @@ -369,7 +374,10 @@ class GfxObj { public: int16 x, y; - uint16 z; + + int32 z; + + uint type; uint frame; uint layer; @@ -461,7 +469,7 @@ public: Disk *_disk; VarMap _vars; - GfxObjList _gfxobjList[3]; + GfxObjList _gfxobjList; GfxObj* loadAnim(const char *name); GfxObj* loadGet(const char *name); GfxObj* loadDoor(const char *name); -- cgit v1.2.3 From b0e22db7a89a27a7f9c09870fded7a64042293c7 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 29 Jun 2008 15:25:45 +0000 Subject: - some more work on the Hof FM-Towns/PC98 music driver - move channels to a separate class svn-id: r32841 --- engines/kyra/detection.cpp | 2 +- engines/kyra/sound.h | 4 +- engines/kyra/sound_towns.cpp | 1951 ++++++++++++++++++++++++------------------ 3 files changed, 1137 insertions(+), 820 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 1e174bdfcf..3fb62b51bd 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -346,7 +346,7 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_FLOPPY_CMP_FLAGS }, - { // // Floppy version extracted + { // Floppy version extracted { "kyra2", "Extracted", diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index c08c531ab9..cebfdf491f 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -486,11 +486,13 @@ public: void beginFadeOut(); int32 voicePlay(const char *file, bool isSfx = false); - void playSoundEffect(uint8) {} + void playSoundEffect(uint8 track); protected: Audio::AudioStream *_currentSFX; int _lastTrack; + bool _useFmSfx; + uint8 *_musicTrackData; TownsPC98_OpnDriver *_driver; }; diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 92e39fc769..4a8e8a5b15 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1100,7 +1100,7 @@ public: void frequency(int freq); void updatePhaseIncrement(); void recalculateRates(); - void generateOutput(int phasebuf, int *feedbuf, int &out); + void generateOutput(int phasebuf, int *_feedbuf, int &out); void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } void detune(int value) { _detn = &_detnTbl[value << 5]; } @@ -1209,7 +1209,7 @@ void TownsPC98_OpnOperator::recalculateRates() { fs_r.shift = _rshiftTbl[r + k]; } -void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out) { +void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) { if (_state == s_ready) return; @@ -1269,10 +1269,10 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out) int *i = &outp, *o = &outp; int phaseShift = 0; - if (feedbuf) { - o = &feedbuf[0]; - i = &feedbuf[1]; - phaseShift = _feedbackLevel ? ((feedbuf[0] + feedbuf[1]) << _feedbackLevel) : 0; + if (_feedbuf) { + o = &_feedbuf[0]; + i = &_feedbuf[1]; + phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0; if (phasebuf == -1) *i = 0; *o = *i; @@ -1329,7 +1329,121 @@ bool TownsPC98_OpnOperator::scaleRate(uint8 value) { return false; } +class TownsPC98_OpnDriver; +class TownsPC98_OpnChannel { +public: + TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, + uint8 key, uint8 prt, uint8 id); + ~TownsPC98_OpnChannel(); + virtual void init(); + + typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); + + typedef enum channelState { + CHS_RECALCFREQ = 0x01, + CHS_KEYOFF = 0x02, + CHS_SSG = 0x04, + CHS_PITCHWHEELOFF = 0x08, + CHS_ALL_BUT_EOT = 0x0f, + CHS_EOT = 0x80 + } ChannelState; + + void loadData(uint8 *data); + virtual void processEvents(); + virtual void processFrequency(); + bool processControlEvent(uint8 cmd); + void writeReg(uint8 regAdress, uint8 value); + + virtual void keyOn(); + virtual void keyOff(); + + void setOutputLevel(); + void fadeStep(); + void reset(); + + void updateEnv(); + void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed); + + bool _enableLeft; + bool _enableRight; + bool _fading; + bool _updateEnvelopes; + const uint8 _idFlag; + int _feedbuf[3]; + +protected: + bool control_dummy(uint8 para); + bool control_f0_setPatch(uint8 para); + bool control_f1_presetOutputLevel(uint8 para); + bool control_f2_setKeyOffTime(uint8 para); + bool control_f3_setFreqLSB(uint8 para); + bool control_f4_setOutputLevel(uint8 para); + bool control_f5_setTempo(uint8 para); + bool control_f6_repeatSection(uint8 para); + bool control_f7_setupPitchWheel(uint8 para); + bool control_f8_togglePitchWheel(uint8 para); + bool control_fa_writeReg(uint8 para); + bool control_fb_incOutLevel(uint8 para); + bool control_fc_decOutLevel(uint8 para); + bool control_fd_jump(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + bool control_f0_setPatchSSG(uint8 para); + bool control_f1_setTotalLevel(uint8 para); + bool control_f4_setAlgorithm(uint8 para); + bool control_f9_unkSSG(uint8 para); + bool control_fb_incOutLevelSSG(uint8 para); + bool control_fc_decOutLevelSSG(uint8 para); + bool control_ff_endOfTrackSSG(uint8 para); + + uint8 _ticksLeft; + uint8 _algorithm; + uint8 _instrID; + uint8 _totalLevel; + uint8 _frqBlockMSB; + int8 _frqLSB; + uint8 _keyOffTime; + bool _protect; + uint8 *_dataPtr; + uint8 _unk15, _unk16; + uint8 _ptchWhlInitDelayLo; + uint8 _ptchWhlInitDelayHi; + int16 _ptchWhlModInitVal; + uint8 _ptchWhlDuration; + uint8 _ptchWhlCurDelay; + int16 _ptchWhlModCurVal; + uint8 _ptchWhlDurLeft; + uint16 frequency; + uint8 _unk28, _unk29; + uint8 _regOffset; + uint8 _flags; + const uint8 _chanNum; + const uint8 _keyNum; + const uint8 _part; + + TownsPC98_OpnDriver *_drv; + TownsPC98_OpnOperator **_opr; + uint16 _frqTemp; + + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel { +public: + TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + void init(); + + void processEvents(); + void processFrequency(); + + void keyOn(); + void keyOff(); +}; + class TownsPC98_OpnDriver : public Audio::AudioStream { +friend class TownsPC98_OpnChannel; +friend class TownsPC98_OpnChannelSSG; public: enum OpnType { OD_TOWNS, @@ -1362,92 +1476,23 @@ public: protected: void generateTables(); - typedef enum channelState { - CHS_RECALCFREQ = 0x01, - CHS_KEYOFF = 0x02, - CHS_PITCHWHEELOFF = 0x08, - CHS_ALL_BUT_EOT = 0x0f, - CHS_EOT = 0x80 - } ChannelState; + TownsPC98_OpnChannel **_channels; + TownsPC98_OpnChannelSSG **_ssgChannels; + //TownsPC98_OpnChannel *_adpcmChannel; - struct TwnChannel { - uint8 ticksLeft; - uint8 unk1, unk2, unk3; - uint8 algorithm; - uint8 instrID; - uint8 totalLevel; - uint8 frqBlockMSB; - int8 frqLSB; - uint8 keyOffTime; - bool protect; - uint8 *dataPtr; - uint8 unk15, unk16; - uint8 ptchWhlInitDelayLo; - uint8 ptchWhlInitDelayHi; - int16 ptchWhlModInitVal; - uint8 ptchWhlDuration; - uint8 ptchWhlCurDelay; - int16 ptchWhlModCurVal; - uint8 ptchWhlDurLeft; - uint16 frequency; - uint8 unk28, unk29; - uint8 regOffset; - uint8 flags; - uint8 chanNum; - uint8 keyNum; - uint8 part; - uint8 idFlag; - - TownsPC98_OpnOperator *opr[4]; - uint16 frqTemp; - bool enableLeft; - bool enableRight; - bool updateEnvelopes; - int feedbuf[3]; - } **_channels; - - void processEvents(TwnChannel *chan); - void processFrequency(TwnChannel *chan); - bool processControlEvent(TwnChannel *chan, uint8 cmd); - - void setOutputLevel(TwnChannel *chan); void setTempo(uint8 tempo); - void keyOn(TwnChannel *chan); - void keyOff(TwnChannel *chan); - void writeReg(TwnChannel *chan, uint8 regAdress, uint8 value); - void lock() { _mutex.lock(); } void unlock() { _mutex.unlock(); } - bool control_f0_setPatch(TwnChannel *chan, uint8 para); - bool control_f1_presetOutputLevel(TwnChannel *chan, uint8 para); - bool control_f2_setKeyOffTime(TwnChannel *chan, uint8 para); - bool control_f3_setFreqLSB(TwnChannel *chan, uint8 para); - bool control_f4_setOutputLevel(TwnChannel *chan, uint8 para); - bool control_f5_setTempo(TwnChannel *chan, uint8 para); - bool control_f6_repeatSection(TwnChannel *chan, uint8 para); - bool control_f7_setupPitchWheel(TwnChannel *chan, uint8 para); - bool control_f8_togglePitchWheel(TwnChannel *chan, uint8 para); - bool control_f9_unk(TwnChannel *chan, uint8 para); - bool control_fa_writeReg(TwnChannel *chan, uint8 para); - bool control_fb_incOutLevel(TwnChannel *chan, uint8 para); - bool control_fc_decOutLevel(TwnChannel *chan, uint8 para); - bool control_fd_jump(TwnChannel *chan, uint8 para); - bool control_fe_unk(TwnChannel *chan, uint8 para); - bool control_ff_endOfTrack(TwnChannel *chan, uint8 para); - - typedef bool (TownsPC98_OpnDriver::*ControlEventFunc)(TwnChannel * chan, uint8 para); - Audio::Mixer *_mixer; - TownsPC98_OpnOperator **_operators; Common::Mutex _mutex; Audio::SoundHandle _soundHandle; - const uint8 *_twnCarrier; - const uint8 *_twnFreqTable; - const uint8 *_twnFxCmdLen; - const uint8 *_twnLvlPresets; + const uint8 *_opnCarrier; + const uint8 *_opnFreqTable; + const uint8 *_opnFxCmdLen; + const uint8 *_opnLvlPresets; uint8 *_oprRates; uint8 *_oprRateshift; @@ -1465,11 +1510,10 @@ protected: uint8 _finishedChannelsFlag; uint16 _tempo; bool _playing; - bool _fading; uint8 _looping; uint32 _tickCounter; - bool _updateEnvelopes; + bool __updateEnvelopes; int32 _samplesTillCallback; int32 _samplesTillCallbackRemainder; @@ -1484,890 +1528,1148 @@ protected: double _baserate; static const uint8 _drvTables[]; static const uint32 _adtStat[]; + bool _ready; }; -TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : - _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), - _operators(0), _looping(0), _twnCarrier(_drvTables + 76), _twnFreqTable(_drvTables + 84), - _twnFxCmdLen(_drvTables + 36), _twnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , - _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), - _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), - _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), - _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), - _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { - setTempo(84); - _baserate = (3579545.0 / (double)getRate()) / 144.0; -} - -TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { - _mixer->stopHandle(_soundHandle); - - if (_operators) { - for (int i = 0; i < (_numChan << 2); i++) - delete _operators[i]; - delete [] _operators; - } - - if (_channels) { - for (int i = 0; i < _numChan; i++) - delete _channels[i]; - delete [] _channels; - } +TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, + uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), + _part(prt), _idFlag(id) { - delete [] _oprRates; - delete [] _oprRateshift; - delete [] _oprFrq; - delete [] _oprAttackDecay; - delete [] _oprSinTbl; - delete [] _oprLevelOut; - delete [] _oprDetune; + _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _unk15 = _unk16 = 0; + _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = _unk28 = _unk29 = 0; + _frqLSB = 0; + _protect = _updateEnvelopes = _fading = false; + _enableLeft = _enableRight = true; + _dataPtr = 0; + _ptchWhlModInitVal = _ptchWhlModCurVal = 0; + frequency = _frqTemp = 0; + memset(&_feedbuf, 0, sizeof(int) * 3); + _opr = 0; } -bool TownsPC98_OpnDriver::init() { - generateTables(); - - if (_operators) { - for (int i = 0; i < (_numChan << 2); i++) { - if (_operators[i]) { - delete _operators[i]; - } - } - delete [] _operators; +TownsPC98_OpnChannel::~TownsPC98_OpnChannel() { + if (_opr) { + for (int i = 0; i < 4; i++) + delete _opr[i]; + delete [] _opr; } +} - _operators = new TownsPC98_OpnOperator*[(_numChan << 2)]; - for (int i = 0; i < (_numChan << 2); i++) - _operators[i] = new TownsPC98_OpnOperator(_baserate, _oprRates, - _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); - - if (_channels) { - for (int i = 0; i < _numChan; i++) { - if (_channels[i]) - delete _channels[i]; - } - delete [] _channels; - } - _channels = new TwnChannel*[_numChan]; - for (int i = 0; i < _numChan; i++) { - _channels[i] = new TwnChannel; - for (int ii = 0; ii < 4; ii++) { - _channels[i]->opr[ii] = _operators[(i << 2) + ii]; - _channels[i]->updateEnvelopes = false; - } - } +void TownsPC98_OpnChannel::init() { + + _opr = new TownsPC98_OpnOperator*[4]; + for (int i = 0; i < 4; i++) + _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, + _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); - for (int i = 0; i < _numChan; i++) { - int ix = i * 6; - memset(_channels[i], 0, sizeof(TwnChannel)); - _channels[i]->regOffset = _drvTables[ix]; - _channels[i]->flags = _drvTables[ix + 1]; - _channels[i]->chanNum = _drvTables[ix + 2]; - _channels[i]->keyNum = _drvTables[ix + 3]; - _channels[i]->part = _drvTables[ix + 4]; - _channels[i]->idFlag = _drvTables[ix + 5]; - } + #define Control(x) &TownsPC98_OpnChannel::control_##x + static const ControlEventFunc ctrlEvents[] = { + Control(f0_setPatch), + Control(f1_presetOutputLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setOutputLevel), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupPitchWheel), + Control(f8_togglePitchWheel), + Control(dummy), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, - &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); + controlEvents = ctrlEvents; +} - return true; +void TownsPC98_OpnChannel::keyOff() { + // all operators off + uint8 value = _keyNum & 0x0f; + uint8 regAdress = 0x28; + writeReg(regAdress, value); + _flags |= CHS_KEYOFF; } -int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) { - memset(buffer, 0, sizeof(int16) * numSamples); - int32 samplesLeft = numSamples >> 1; - while (samplesLeft) { - if (!_samplesTillCallback) { - callback(); - _samplesTillCallback = _samplesPerCallback; - _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; - if (_samplesTillCallbackRemainder >= _tempo) { - _samplesTillCallback++; - _samplesTillCallbackRemainder -= _tempo; - } - } +void TownsPC98_OpnChannel::keyOn() { + // all operators on + uint8 value = _keyNum | 0xf0; + uint8 regAdress = 0x28; + writeReg(regAdress, value); +} - int32 render = MIN(samplesLeft, _samplesTillCallback); - samplesLeft -= render; - _samplesTillCallback -= render; - nextTick(buffer, render); +void TownsPC98_OpnChannel::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; - for (int i = 0; i < render; ++i) { - buffer[i << 1] <<= 2; - buffer[(i << 1) + 1] <<= 2; + uint8 *src_b = _dataPtr; + int loop = 1; + uint8 cmd = 0; + while (loop) { + if (loop == 1) { + cmd = *src_b++; + if (cmd < 0xf0) { + src_b++; + loop = 1; + } else { + if (cmd == 0xff) { + loop = *src_b ? 2 : 0; + if (READ_LE_UINT16(src_b)) + _drv->_looping |= _idFlag; + } else if (cmd == 0xf6) { + loop = 3; + } else { + loop = 2; + } + } + } else if (loop == 2) { + src_b += _drv->_opnFxCmdLen[cmd - 240]; + loop = 1; + } else if (loop == 3) { + src_b[0] = src_b[1]; + src_b += 4; + loop = 1; } - - buffer += (render << 1); } - - return numSamples; } -void TownsPC98_OpnDriver::loadData(uint8 * data, bool loadPaused) { - - lock(); - _trackData = data; - - reset(); +void TownsPC98_OpnChannel::processEvents() { + if (_flags & CHS_EOT) + return; - for (uint8 i = 0; i < _numChan; i++) { - uint8 tmp1 = _channels[i]->regOffset; - uint8 tmp2 = _channels[i]->flags; - uint8 tmp3 = _channels[i]->chanNum; - uint8 tmp4 = _channels[i]->keyNum; - uint8 tmp5 = _channels[i]->part; - uint8 tmp6 = _channels[i]->idFlag; - memset(_channels[i], 0, sizeof(TwnChannel)); - _channels[i]->regOffset = tmp1; - _channels[i]->flags = tmp2; - _channels[i]->chanNum = tmp3; - _channels[i]->keyNum = tmp4; - _channels[i]->part = tmp5; - _channels[i]->idFlag = tmp6; - _channels[i]->enableLeft = _channels[i]->enableRight = true; - for (int ii = 0; ii < 4; ii++) - _channels[i]->opr[ii] = _operators[(i << 2) + ii]; - } + if (_protect == false && _ticksLeft == _keyOffTime) + keyOff(); - uint8 *src_a = data; - uint8 bl = 0; + if (--_ticksLeft) + return; - for (uint8 i = 0; i < _numChan; i++) { - _channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; - _channels[i]->ticksLeft = 1; - _channels[i]->dataPtr = data + READ_LE_UINT16(src_a); - src_a += 2; - _channels[i]->totalLevel = 0x7F; - if (bl > 2) - bl -= 3; - _channels[i]->regOffset = bl++; - - uint8 * src_b = _channels[i]->dataPtr; - int loop = 1; - uint8 cmd = 0; - while (loop) { - if (loop == 1) { - cmd = *src_b++; - if (cmd < 0xf0) { - src_b++; - loop = 1; - } else { - if (cmd == 0xff) { - loop = *src_b ? 2 : 0; - if (READ_LE_UINT16(src_b)) - _looping |= _channels[i]->idFlag; - } else if (cmd == 0xf6) { - loop = 3; - } else { - loop = 2; - } - } - } else if (loop == 2) { - src_b += _twnFxCmdLen[cmd - 240]; - loop = 1; - } else if (loop == 3) { - src_b[0] = src_b[1]; - src_b += 4; - loop = 1; - } - } - } + if (_protect == false) + keyOff(); - for (int i = 0; i < _numSSG; i++) { - // TODO - //_channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; - //_channels[i]->ticksLeft = 1; - //_channels[i]->dataPtr = data + READ_LE_UINT16(src_a); - //uint8 *tmp = data + READ_LE_UINT16(src_a); - src_a += 2; - } + uint8 cmd = 0; + bool loop = true; - if (_hasADPCM) { - // TODO - src_a += 2; + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; } - _patches = src_a + 4; - _cbCounter = 4; - _finishedChannelsFlag = 0; + uint8 para = *_dataPtr++; - // AH 0x17 - unlock(); - _playing = (loadPaused ? false : true); -} + if (cmd == 0x80) { + keyOff(); + _protect = false; + } else { + keyOn(); -void TownsPC98_OpnDriver::reset() { - for (int i = 0; i < (_numChan << 2); i++) - _operators[i]->reset(); + if (_protect == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _protect = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } - _playing = false; - _looping = 0; - _tickCounter = 0; + _ticksLeft = para & 0x7f; } -void TownsPC98_OpnDriver::fadeOut() { - if (!_playing) - return; +void TownsPC98_OpnChannel::processFrequency() { + if (_flags & CHS_RECALCFREQ) { + uint8 block = (_frqBlockMSB & 0x70) >> 1; + uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; + frequency = (bfreq + _frqLSB) | (block << 8); - _fading = true; + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); - for (int i = 0; i < 20; i++) { - - lock(); - uint32 dTime = _tickCounter + 2; - for (int j = 0; j < _numChan; j++) { - if (_updateChannelsFlag & _channels[j]->idFlag) { - uint8 tmp = _channels[j]->totalLevel + 3; - if (tmp > 0x7f) - tmp = 0x7f; - _channels[j]->totalLevel = tmp; - setOutputLevel(_channels[j]); - } + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + if (_flags & CHS_KEYOFF) { + _ptchWhlModCurVal = _ptchWhlModInitVal; + _ptchWhlCurDelay += _ptchWhlInitDelayLo; } - unlock(); - while (_playing) { - if (_tickCounter >= dTime) - break; - } + _ptchWhlDurLeft = (_ptchWhlDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); } - _fading = false; + if (!(_flags & CHS_PITCHWHEELOFF)) { + if (--_ptchWhlCurDelay) + return; + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + frequency += _ptchWhlModCurVal; - reset(); + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); + + if(!--_ptchWhlDurLeft) { + _ptchWhlDurLeft = _ptchWhlDuration; + _ptchWhlModCurVal = -_ptchWhlModCurVal; + } + } } -void TownsPC98_OpnDriver::callback() { - if (!_playing || --_cbCounter) - return; +bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} - _cbCounter = 4; - _tickCounter++; +void TownsPC98_OpnChannel::setOutputLevel() { + uint8 outopr = _drv->_opnCarrier[_algorithm]; + uint8 reg = 0x40 + _regOffset; - lock(); - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->idFlag) { - processEvents(_channels[i]); - processFrequency(_channels[i]); - } + for (int i = 0; i < 4; i++) { + if (outopr & 1) + writeReg(reg, _totalLevel); + outopr >>= 1; + reg += 4; } - unlock(); +} - if (_finishedChannelsFlag == _updateChannelsFlag) - reset(); +void TownsPC98_OpnChannel::fadeStep() { + _totalLevel += 3; + if (_totalLevel > 0x7f) + _totalLevel = 0x7f; + setOutputLevel(); } -void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { - if (!_playing) - return; +void TownsPC98_OpnChannel::reset() { + for (int i = 0; i < 4; i++) + _opr[i]->reset(); - for (int i = 0; i < _numChan ; i++) { - if (_channels[i]->updateEnvelopes) { - _channels[i]->updateEnvelopes = false; - for (int ii = 0; ii < 4 ; ii++) - _channels[i]->opr[ii]->updatePhaseIncrement(); - } + _fading = _updateEnvelopes = false; + _enableLeft = _enableRight = true; + memset(&_feedbuf, 0, sizeof(int) * 3); +} - int phbuf1, phbuf2, output; - int *feed = _channels[i]->feedbuf; - int *del = &feed[2]; - - for (uint32 ii = 0; ii < bufferSize ; ii++) { - phbuf1 = phbuf2 = output = 0; - - switch (_channels[i]->algorithm) { - case 0: - _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); - _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2); - *del = 0; - _channels[i]->opr[1]->generateOutput(phbuf1, 0, *del); - _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); - break; - case 1: - _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); - _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2); - _channels[i]->opr[1]->generateOutput(0, 0, phbuf1); - _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); - *del = phbuf1; - break; - case 2: - _channels[i]->opr[0]->generateOutput(0, feed, phbuf2); - _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2); - _channels[i]->opr[1]->generateOutput(0, 0, phbuf1); - _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); - *del = phbuf1; - break; - case 3: - _channels[i]->opr[0]->generateOutput(0, feed, phbuf2); - _channels[i]->opr[2]->generateOutput(0, 0, *del); - _channels[i]->opr[1]->generateOutput(phbuf2, 0, phbuf1); - _channels[i]->opr[3]->generateOutput(*del, 0, output); - *del = phbuf1; - break; - case 4: - _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); - _channels[i]->opr[2]->generateOutput(0, 0, phbuf2); - _channels[i]->opr[1]->generateOutput(phbuf1, 0, output); - _channels[i]->opr[3]->generateOutput(phbuf2, 0, output); - *del = 0; - break; - case 5: - *del = feed[1]; - _channels[i]->opr[0]->generateOutput(-1, feed, phbuf1); - _channels[i]->opr[2]->generateOutput(*del, 0, output); - _channels[i]->opr[1]->generateOutput(*del, 0, output); - _channels[i]->opr[3]->generateOutput(*del, 0, output); - break; - case 6: - _channels[i]->opr[0]->generateOutput(0, feed, phbuf1); - _channels[i]->opr[2]->generateOutput(0, 0, output); - _channels[i]->opr[1]->generateOutput(phbuf1, 0, output); - _channels[i]->opr[3]->generateOutput(0, 0, output); - *del = 0; - break; - case 7: - _channels[i]->opr[0]->generateOutput(0, feed, output); - _channels[i]->opr[2]->generateOutput(0, 0, output); - _channels[i]->opr[1]->generateOutput(0, 0, output); - _channels[i]->opr[3]->generateOutput(0, 0, output); - *del = 0; - break; - }; - - if (_channels[i]->enableLeft) { - int l = output + buffer[ii * 2]; - if (l > 32767) - l = 32767; - if (l < -32767) - l = -32767; - buffer[ii * 2] = (int16) l; - } +void TownsPC98_OpnChannel::updateEnv() { + for (int i = 0; i < 4 ; i++) + _opr[i]->updatePhaseIncrement(); +} - if (_channels[i]->enableRight) { - int r = output + buffer[ii * 2 + 1]; - if (r > 32767) - r = 32767; - if (r < -32767) - r = -32767; - buffer[ii * 2 + 1] = (int16) r; - } - } +void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) { + int phbuf1, phbuf2, output; + phbuf1 = phbuf2 = output = 0; + + switch (_algorithm) { + case 0: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(*del, 0, phbuf2); + *del = 0; + _opr[1]->generateOutput(phbuf1, 0, *del); + _opr[3]->generateOutput(phbuf2, 0, output); + break; + case 1: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(*del, 0, phbuf2); + _opr[1]->generateOutput(0, 0, phbuf1); + _opr[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 2: + _opr[0]->generateOutput(0, feed, phbuf2); + _opr[2]->generateOutput(*del, 0, phbuf2); + _opr[1]->generateOutput(0, 0, phbuf1); + _opr[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 3: + _opr[0]->generateOutput(0, feed, phbuf2); + _opr[2]->generateOutput(0, 0, *del); + _opr[1]->generateOutput(phbuf2, 0, phbuf1); + _opr[3]->generateOutput(*del, 0, output); + *del = phbuf1; + break; + case 4: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(0, 0, phbuf2); + _opr[1]->generateOutput(phbuf1, 0, output); + _opr[3]->generateOutput(phbuf2, 0, output); + *del = 0; + break; + case 5: + *del = feed[1]; + _opr[0]->generateOutput(-1, feed, phbuf1); + _opr[2]->generateOutput(*del, 0, output); + _opr[1]->generateOutput(*del, 0, output); + _opr[3]->generateOutput(*del, 0, output); + break; + case 6: + _opr[0]->generateOutput(0, feed, phbuf1); + _opr[2]->generateOutput(0, 0, output); + _opr[1]->generateOutput(phbuf1, 0, output); + _opr[3]->generateOutput(0, 0, output); + *del = 0; + break; + case 7: + _opr[0]->generateOutput(0, feed, output); + _opr[2]->generateOutput(0, 0, output); + _opr[1]->generateOutput(0, 0, output); + _opr[3]->generateOutput(0, 0, output); + *del = 0; + break; + }; + + if (_enableLeft) { + int l = output + leftSample; + if (l > 32767) + l = 32767; + if (l < -32767) + l = -32767; + leftSample = (int16) l; } -} -void TownsPC98_OpnDriver::generateTables() { - delete [] _oprRates; - _oprRates = new uint8[128]; - memset(_oprRates, 0x90, 32); - uint8 * dst = (uint8*) _oprRates + 32; - for (int i = 0; i < 48; i += 4) - WRITE_BE_UINT32(dst + i, 0x00081018); - dst += 48; - for (uint8 i = 0; i < 16; i ++) { - uint8 v = (i < 12) ? i : 12; - *dst++ = ((4 + v) << 3); + if (_enableRight) { + int r = output + rightSample; + if (r > 32767) + r = 32767; + if (r < -32767) + r = -32767; + rightSample = (int16) r; } - memset(dst, 0x80, 32); +} - delete [] _oprRateshift; - _oprRateshift = new uint8[128]; - memset(_oprRateshift, 0, 128); - dst = (uint8*) _oprRateshift + 32; - for (int i = 11; i; i--) { - memset(dst, i, 4); - dst += 4; +void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { + uint8 h = regAdress & 0xf0; + uint8 l = (regAdress & 0x0f); + static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; + uint8 o = oprOrdr[(l - _regOffset) >> 2]; + + switch (h) { + case 0x00: + // ssg + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + case 0x10: + // adpcm + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + case 0x20: + if (l == 8) { + // Key on/off + for (int i = 0; i < 4; i++) { + if ((value >> (4 + i)) & 1) + _opr[i]->keyOn(); + else + _opr[i]->keyOff(); + } + } else if (l == 2) { + // LFO + warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); + } else if (l == 7) { + // Timers; Ch 3/6 special mode + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)"); + } else if (l == 4 || l == 5) { + // Timer A + warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)"); + } else if (l == 6) { + // Timer B + warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)"); + } else if (l == 10 || l == 11) { + // DAC + warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); + } + break; + + case 0x30: + // detune, multiple + _opr[o]->detune((value >> 4) & 7); + _opr[o]->multiple(value & 0x0f); + _updateEnvelopes = true; + break; + + case 0x40: + // total level + _opr[o]->totalLevel(value & 0x7f); + break; + + case 0x50: + // rate scaling, attack rate + _opr[o]->attackRate(value & 0x1f); + if (_opr[o]->scaleRate(value >> 6)) + _updateEnvelopes = true; + break; + + case 0x60: + // first decay rate, amplitude modulation + _opr[o]->decayRate(value & 0x1f); + if (value & 0x80) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); + + break; + + case 0x70: + // secondary decay rate + _opr[o]->sustainRate(value & 0x1f); + break; + + case 0x80: + // secondary amplitude, release rate; + _opr[o]->sustainLevel(value >> 4); + _opr[o]->releaseRate(value & 0x0f); + break; + + case 0x90: + // ssg + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; + + case 0xa0: + // frequency + l -= _regOffset; + if (l == 0) { + _frqTemp = (_frqTemp & 0xff00) | value; + _updateEnvelopes = true; + for (int i = 0; i < 4; i++) + _opr[i]->frequency(_frqTemp); + } else if (l == 4) { + _frqTemp = (_frqTemp & 0xff) | (value << 8); + } else if (l == 8) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } else if (l == 12) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } + break; + + case 0xb0: + l -= _regOffset; + if (l == 0) { + // feedback, _algorithm + _opr[0]->feedbackLevel((value >> 3) & 7); + _opr[1]->feedbackLevel(0); + _opr[2]->feedbackLevel(0); + _opr[3]->feedbackLevel(0); + } else if (l == 4) { + // stereo, LFO sensitivity + _enableLeft = value & 0x80 ? true : false; + _enableRight = value & 0x40 ? true : false; + uint8 ams = (value & 0x3F) >> 3; + if (ams) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); + uint8 fms = value & 3; + if (fms) + warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); + } + break; + + default: + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); + break; } +} - delete [] _oprFrq; - _oprFrq = new uint32[0x1000]; - for (uint32 i = 0; i < 0x1000; i++) - _oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); +bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { + _instrID = para; + uint8 reg = _regOffset + 0x80; - delete [] _oprAttackDecay; - _oprAttackDecay = new uint8[152]; - memset(_oprAttackDecay, 0, 152); - for (int i = 0; i < 36; i++) - WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); + for (int i = 0; i < 4; i++) { + // set release rate for each operator + writeReg(reg, 0x0f); + reg += 4; + } - delete [] _oprSinTbl; - _oprSinTbl = new uint32[1024]; - for (int i = 0; i < 1024; i++) { - double val = sin((double) (((i << 1) + 1) * M_PI / 1024.0)); - double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; - int32 i_dcb = (int32)(2.0 * d_dcb); - i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); - _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); + const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5); + reg = _regOffset + 0x30; + + // write registers 0x30 to 0x8f + for (int i = 0; i < 6; i++) { + writeReg(reg, tptr[0]); + reg += 4; + writeReg(reg, tptr[2]); + reg += 4; + writeReg(reg, tptr[1]); + reg += 4; + writeReg(reg, tptr[3]); + reg += 4; + tptr += 4; } - delete [] _oprLevelOut; - _oprLevelOut = new int32[0x1a00]; - for (int i = 0; i < 256; i++) { - double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); - int32 val_int = ((int32) val) >> 4; - _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; - _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; - for (int ii = 1; ii < 13; ii++) { - _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; - _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; + reg = _regOffset + 0xB0; + _algorithm = tptr[0] & 7; + // set feedback and algorithm + writeReg(reg, tptr[0]); + + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) { + if (_fading) + return true; + + _totalLevel = _drv->_opnLvlPresets[para]; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_f2_setKeyOffTime(uint8 para) { + _keyOffTime = para; + return true; +} + +bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) { + _frqLSB = (int8) para; + return true; +} + +bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) { + if (_fading) + return true; + + _totalLevel = para; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) { + _drv->setTempo(para); + return true; +} + +bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { + _dataPtr--; + _dataPtr[0]--; + + if (*_dataPtr) { + // repeat section until counter has reached zero + _dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2); + } else { + // reset counter, advance to next section + _dataPtr[0] = _dataPtr[1]; + _dataPtr += 4; + } + return true; +} + +bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) { + _ptchWhlInitDelayLo = _dataPtr[0]; + _ptchWhlInitDelayHi = para; + _ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); + _ptchWhlDuration = _dataPtr[3]; + _dataPtr += 4; + _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ; + return true; +} + +bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) { + if (para == 0x10) { + if (*_dataPtr++) { + _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF; + } else { + _flags |= CHS_PITCHWHEELOFF; } + } else { + //uint8 skipChannels = para / 36; + //uint8 entry = para % 36; + //TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; + ////// NOT IMPLEMENTED + //t->unnamedEntries[entry] = *_dataPtr++; } + return true; +} - uint8 * dtt = new uint8[128]; - memset(dtt, 0, 36); - memset(dtt + 36, 1, 8); - memcpy(dtt + 44, _drvTables + 144, 84); +bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) { + writeReg(para, *_dataPtr++); + return true; +} - delete [] _oprDetune; - _oprDetune = new int32[256]; - for (int i = 0; i < 128; i++) { - _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); - _oprDetune[i + 128] = -_oprDetune[i]; +bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) { + _dataPtr--; + if (_fading) + return true; + + uint8 val = (_totalLevel + 3); + if (val > 0x7f) + val = 0x7f; + + _totalLevel = val; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) { + _dataPtr--; + if (_fading) + return true; + + int8 val = (int8) (_totalLevel - 3); + if (val < 0) + val = 0; + + _totalLevel = (uint8) val; + setOutputLevel(); + return true; +} + +bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) { + uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1); + _dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr; + return true; +} + +bool TownsPC98_OpnChannel::control_dummy(uint8 para) { + _dataPtr--; + return true; +} + +bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackData + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedChannelsFlag |= _idFlag; + keyOff(); + return false; } +} - delete [] dtt; +bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) { + _instrID = para << 4; + para = (para >> 3) & 0x1e; + if (para) + return control_f4_setAlgorithm(para | 0x40); + return true; +} + +bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) { + if (!_fading) + _totalLevel = para; + return true; +} + +bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) { + _algorithm = para; + return true; +} + +bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) { + _dataPtr += 5; + return true; +} + +bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { + _dataPtr--; + if (_fading) + return true; + + _totalLevel--; + if ((int8)_totalLevel < 0); + _totalLevel = 0; + + return true; +} + +bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { + _dataPtr--; + if (_fading) + return true; + + if(_totalLevel + 1 < 0x10) + _totalLevel++; + + return true; +} + +bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackData + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + //_finishedChannelsFlag |= _idFlag; + keyOff(); + return false; + } +} + +TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { +} + +void TownsPC98_OpnChannelSSG::init() { + _algorithm = 0x80; + + _opr = new TownsPC98_OpnOperator*[4]; + for (int i = 0; i < 4; i++) + _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, + _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); + + #define Control(x) &TownsPC98_OpnChannelSSG::control_##x + static const ControlEventFunc ctrlEventsSSG[] = { + Control(f0_setPatchSSG), + Control(f1_setTotalLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setOutputLevel), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupPitchWheel), + Control(f8_togglePitchWheel), + Control(f9_unkSSG), + Control(fa_writeReg), + Control(fb_incOutLevelSSG), + Control(fc_decOutLevelSSG), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrackSSG) + }; + #undef Control + + controlEvents = ctrlEventsSSG; } -void TownsPC98_OpnDriver::processEvents(TwnChannel *chan) { - if (chan->flags & CHS_EOT) +void TownsPC98_OpnChannelSSG::processEvents() { + if (_flags & CHS_EOT) return; - if (chan->protect == false && chan->ticksLeft == chan->keyOffTime) - keyOff(chan); + int _ssgUnk = (_flags & CHS_SSG) ? -1 : 0; - if (--chan->ticksLeft) + if (_protect == false && _ticksLeft == _keyOffTime) + keyOff(); + + if (--_ticksLeft) return; - if (chan->protect == false) - keyOff(chan); + if (_protect == false) + keyOff(); uint8 cmd = 0; bool loop = true; while (loop) { - cmd = *chan->dataPtr++; + cmd = *_dataPtr++; if (cmd < 0xf0) loop = false; - else if (!processControlEvent(chan, cmd)) + else if (!processControlEvent(cmd)) return; } - uint8 para = *chan->dataPtr++; + uint8 para = *_dataPtr++; if (cmd == 0x80) { - keyOff(chan); - chan->protect = false; + keyOff(); + _protect = false; } else { - keyOn(chan); + keyOn(); - if (chan->protect == false || cmd != chan->frqBlockMSB) - chan->flags |= CHS_RECALCFREQ; + if (_protect == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; - chan->protect = (para & 0x80) ? true : false; - chan->frqBlockMSB = cmd; + _protect = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; } - chan->ticksLeft = para & 0x7f; + _ticksLeft = para & 0x7f; + + if (!(_flags & CHS_SSG)) { + + } } -void TownsPC98_OpnDriver::processFrequency(TwnChannel *chan) { - if (chan->flags & CHS_RECALCFREQ) { - uint8 block = (chan->frqBlockMSB & 0x70) >> 1; - uint16 bfreq = ((const uint16*)_twnFreqTable)[chan->frqBlockMSB & 0x0f]; - chan->frequency = (bfreq + chan->frqLSB) | (block << 8); +void TownsPC98_OpnChannelSSG::processFrequency() { + if (_flags & CHS_RECALCFREQ) { + uint8 block = (_frqBlockMSB & 0x70) >> 1; + uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; + frequency = (bfreq + _frqLSB) | (block << 8); - writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8)); - writeReg(chan, (chan->regOffset + 0xa0), (chan->frequency & 0xff)); + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); - chan->ptchWhlCurDelay = chan->ptchWhlInitDelayHi; - if (chan->flags & CHS_KEYOFF) { - chan->ptchWhlModCurVal = chan->ptchWhlModInitVal; - chan->ptchWhlCurDelay += chan->ptchWhlInitDelayLo; + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + if (_flags & CHS_KEYOFF) { + _ptchWhlModCurVal = _ptchWhlModInitVal; + _ptchWhlCurDelay += _ptchWhlInitDelayLo; } - chan->ptchWhlDurLeft = (chan->ptchWhlDuration >> 1); - chan->flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + _ptchWhlDurLeft = (_ptchWhlDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); } - if (!(chan->flags & CHS_PITCHWHEELOFF)) { - if (--chan->ptchWhlCurDelay) + if (!(_flags & CHS_PITCHWHEELOFF)) { + if (--_ptchWhlCurDelay) return; - chan->ptchWhlCurDelay = chan->ptchWhlInitDelayHi; - chan->frequency += chan->ptchWhlModCurVal; + _ptchWhlCurDelay = _ptchWhlInitDelayHi; + frequency += _ptchWhlModCurVal; - writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8)); - writeReg(chan, (chan->regOffset + 0xa0), (chan->frequency & 0xff)); + writeReg(_regOffset + 0xa4, (frequency >> 8)); + writeReg(_regOffset + 0xa0, (frequency & 0xff)); - if(!--chan->ptchWhlDurLeft) { - chan->ptchWhlDurLeft = chan->ptchWhlDuration; - chan->ptchWhlModCurVal = -chan->ptchWhlModCurVal; + if(!--_ptchWhlDurLeft) { + _ptchWhlDurLeft = _ptchWhlDuration; + _ptchWhlModCurVal = -_ptchWhlModCurVal; } } } -bool TownsPC98_OpnDriver::processControlEvent(TwnChannel *chan, uint8 cmd) { - #define Control(x) &TownsPC98_OpnDriver::control_##x - static const ControlEventFunc twnFxCommands[] = { - Control(f0_setPatch), - Control(f1_presetOutputLevel), - Control(f2_setKeyOffTime), - Control(f3_setFreqLSB), - Control(f4_setOutputLevel), - Control(f5_setTempo), - Control(f6_repeatSection), - Control(f7_setupPitchWheel), - Control(f8_togglePitchWheel), - Control(f9_unk), - Control(fa_writeReg), - Control(fb_incOutLevel), - Control(fc_decOutLevel), - Control(fd_jump), - Control(fe_unk), - Control(ff_endOfTrack) - }; - #undef Control +void TownsPC98_OpnChannelSSG::keyOff() { + // all operators off + uint8 value = _keyNum & 0x0f; + uint8 regAdress = 0x28; + writeReg(regAdress, value); + _flags |= CHS_KEYOFF; +} - uint8 para = *chan->dataPtr++; - return (this->*twnFxCommands[cmd & 0x0f])(chan, para); +void TownsPC98_OpnChannelSSG::keyOn() { + // all operators on + uint8 value = _keyNum | 0xf0; + uint8 regAdress = 0x28; + writeReg(regAdress, value); } -void TownsPC98_OpnDriver::setOutputLevel(TwnChannel *chan) { - uint8 outopr = _twnCarrier[chan->algorithm]; - uint8 reg = 0x40 + chan->regOffset; +TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : + _mixer(mixer), _trackData(0), _playing(false), _channels(0), _ssgChannels(0), + _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), + _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), + _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), + _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false), + _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), + _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { + setTempo(84); + _baserate = (3579545.0 / (double)getRate()) / 144.0; +} - for (int i = 0; i < 4; i++) { - if (outopr & 1) - writeReg(chan, reg, chan->totalLevel); - outopr >>= 1; - reg += 4; +TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { + _mixer->stopHandle(_soundHandle); + + if (_channels) { + for (int i = 0; i < _numChan; i++) + delete _channels[i]; + delete [] _channels; } -} -void TownsPC98_OpnDriver::setTempo(uint8 tempo) { - _tempo = tempo; - _samplesPerCallback = getRate() / _tempo; - _samplesPerCallbackRemainder = getRate() % _tempo; -} + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) + delete _ssgChannels[i]; + delete [] _ssgChannels; + } -bool TownsPC98_OpnDriver::control_f0_setPatch(TwnChannel *chan, uint8 para) { - chan->instrID = para; - uint8 reg = chan->regOffset + 0x80; + delete [] _oprRates; + delete [] _oprRateshift; + delete [] _oprFrq; + delete [] _oprAttackDecay; + delete [] _oprSinTbl; + delete [] _oprLevelOut; + delete [] _oprDetune; +} - for (int i = 0; i < 4; i++) { - // set release rate for each operator - writeReg(chan, reg, 0x0f); - reg += 4; +bool TownsPC98_OpnDriver::init() { + if (_ready) { + reset(); + return true; } - const uint8 *tptr = _patches + ((uint32)chan->instrID << 5); - reg = chan->regOffset + 0x30; + generateTables(); - // write registers 0x30 to 0x8f - for (int i = 0; i < 6; i++) { - writeReg(chan, reg, tptr[0]); - reg += 4; - writeReg(chan, reg, tptr[2]); - reg += 4; - writeReg(chan, reg, tptr[1]); - reg += 4; - writeReg(chan, reg, tptr[3]); - reg += 4; - tptr += 4; + if (_channels) { + for (int i = 0; i < _numChan; i++) { + if (_channels[i]) + delete _channels[i]; + } + delete [] _channels; + } + _channels = new TownsPC98_OpnChannel*[_numChan]; + for (int i = 0; i < _numChan; i++) { + int ii = i * 6; + _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _channels[i]->init(); } - reg = chan->regOffset + 0xB0; - chan->algorithm = tptr[0] & 7; - // set feedback and algorithm - writeReg(chan, reg, tptr[0]); + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) { + if (_ssgChannels[i]) + delete _ssgChannels[i]; + } + delete [] _ssgChannels; + } + if (_numSSG) { + _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG]; + for (int i = 0; i < _numSSG; i++) { + int ii = i * 6; + _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _ssgChannels[i]->init(); + } + } - setOutputLevel(chan); + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, + &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); + + _ready = true; return true; } -bool TownsPC98_OpnDriver::control_f1_presetOutputLevel(TwnChannel *chan, uint8 para) { - if (_fading) - return true; +int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) { + memset(buffer, 0, sizeof(int16) * numSamples); + int32 samplesLeft = numSamples >> 1; + while (samplesLeft) { + if (!_samplesTillCallback) { + callback(); + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= _tempo) { + _samplesTillCallback++; + _samplesTillCallbackRemainder -= _tempo; + } + } - chan->totalLevel = _twnLvlPresets[para]; - setOutputLevel(chan); - return true; -} + int32 render = MIN(samplesLeft, _samplesTillCallback); + samplesLeft -= render; + _samplesTillCallback -= render; -bool TownsPC98_OpnDriver::control_f2_setKeyOffTime(TwnChannel *chan, uint8 para) { - chan->keyOffTime = para; - return true; + nextTick(buffer, render); + + for (int i = 0; i < render; ++i) { + buffer[i << 1] <<= 2; + buffer[(i << 1) + 1] <<= 2; + } + + buffer += (render << 1); + } + + return numSamples; } -bool TownsPC98_OpnDriver::control_f3_setFreqLSB(TwnChannel *chan, uint8 para) { - chan->frqLSB = (int8) para; - return true; +void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { + if (!_ready) { + warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); + return; + } + + if (!data) { + warning("TownsPC98_OpnDriver: Invalid music file data"); + return; + } + + lock(); + _trackData = data; + + reset(); + + uint8 *src_a = data; + + for (uint8 i = 0; i < _numChan; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + if (_hasADPCM) { + // TODO + src_a += 2; + } + + _patches = src_a + 4; + _cbCounter = 4; + _finishedChannelsFlag = 0; + + // AH 0x17 + unlock(); + _playing = (loadPaused ? false : true); } -bool TownsPC98_OpnDriver::control_f4_setOutputLevel(TwnChannel *chan, uint8 para) { - if (_fading) - return true; +void TownsPC98_OpnDriver::reset() { + for (int i = 0; i < (_numChan); i++) + _channels[i]->reset(); + for (int i = 0; i < (_numSSG); i++) + _ssgChannels[i]->reset(); - chan->totalLevel = para; - setOutputLevel(chan); - return true; + _playing = false; + _looping = 0; + _tickCounter = 0; } -bool TownsPC98_OpnDriver::control_f5_setTempo(TwnChannel *chan, uint8 para) { - setTempo(para); - return true; -} +void TownsPC98_OpnDriver::fadeOut() { + if (!_playing) + return; -bool TownsPC98_OpnDriver::control_f6_repeatSection(TwnChannel *chan, uint8 para) { - chan->dataPtr--; - chan->dataPtr[0]--; + for (int j = 0; j < _numChan; j++) + _channels[j]->_fading = true; + for (int j = 0; j < _numSSG; j++) + _ssgChannels[j]->_fading = true; - if (*chan->dataPtr) { - // repeat section until counter has reached zero - chan->dataPtr = _trackData + READ_LE_UINT16(chan->dataPtr + 2); - } else { - // reset counter, advance to next section - chan->dataPtr[0] = chan->dataPtr[1]; - chan->dataPtr += 4; - } - return true; -} + for (int i = 0; i < 20; i++) { + lock(); + uint32 dTime = _tickCounter + 2; + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->_idFlag) + _channels[j]->fadeStep(); + } + for (int j = 0; j < _numSSG; j++) + _ssgChannels[j]->fadeStep(); -bool TownsPC98_OpnDriver::control_f7_setupPitchWheel(TwnChannel *chan, uint8 para) { - chan->ptchWhlInitDelayLo = chan->dataPtr[0]; - chan->ptchWhlInitDelayHi = para; - chan->ptchWhlModInitVal = (int16) READ_LE_UINT16(chan->dataPtr + 1); - chan->ptchWhlDuration = chan->dataPtr[3]; - chan->dataPtr += 4; - chan->flags = (chan->flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ; - return true; -} + unlock(); -bool TownsPC98_OpnDriver::control_f8_togglePitchWheel(TwnChannel *chan, uint8 para) { - if (para == 0x10) { - if (*chan->dataPtr++) { - chan->flags = (chan->flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF; - } else { - chan->flags |= CHS_PITCHWHEELOFF; + while (_playing) { + if (_tickCounter >= dTime) + break; } - } else { - //uint8 skipChannels = para / 36; - //uint8 entry = para % 36; - //TownsPC98_OpnDriver::TwnChannel *t = &chan[skipChannels]; - ////// NOT IMPLEMENTED - //t->unnamedEntries[entry] = *chan->dataPtr++; } - return true; -} -bool TownsPC98_OpnDriver::control_f9_unk(TwnChannel *chan, uint8 para) { - //chan->dataPtr += 5; - return true; -} + for (int j = 0; j < _numChan; j++) + _channels[j]->_fading = false; + for (int j = 0; j < _numSSG; j++) + _ssgChannels[j]->_fading = false; -bool TownsPC98_OpnDriver::control_fa_writeReg(TwnChannel *chan, uint8 para) { - writeReg(chan, para, *chan->dataPtr++); - return true; + reset(); } -bool TownsPC98_OpnDriver::control_fb_incOutLevel(TwnChannel *chan, uint8 para) { - chan->dataPtr--; - if (_fading) - return true; +void TownsPC98_OpnDriver::callback() { + if (!_playing || --_cbCounter) + return; - uint8 val = (chan->totalLevel + 3); - if (val > 0x7f) - val = 0x7f; + _cbCounter = 4; + _tickCounter++; - chan->totalLevel = val; - setOutputLevel(chan); - return true; -} + lock(); -bool TownsPC98_OpnDriver::control_fc_decOutLevel(TwnChannel *chan, uint8 para) { - chan->dataPtr--; - if (_fading) - return true; + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } - int8 val = (int8) (chan->totalLevel - 3); - if (val < 0) - val = 0; + if (_numSSG) { + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } - chan->totalLevel = (uint8) val; - setOutputLevel(chan); - return true; -} + unlock(); -bool TownsPC98_OpnDriver::control_fd_jump(TwnChannel *chan, uint8 para) { - uint8 *tmp = _trackData + READ_LE_UINT16(chan->dataPtr - 1); - chan->dataPtr = (tmp[1] == 1) ? tmp : ++chan->dataPtr; - return true; + if (_finishedChannelsFlag == _updateChannelsFlag) + reset(); } -bool TownsPC98_OpnDriver::control_fe_unk(TwnChannel *chan, uint8 para) { - chan->dataPtr--; - return true; -} +void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { + if (!_playing) + return; -bool TownsPC98_OpnDriver::control_ff_endOfTrack(TwnChannel *chan, uint8 para) { - uint16 val = READ_LE_UINT16(--chan->dataPtr); - if (val) { - // loop - chan->dataPtr = _trackData + val; - return true; - } else { - // quit parsing for active channel - --chan->dataPtr; - chan->flags |= CHS_EOT; - _finishedChannelsFlag |= chan->idFlag; - keyOff(chan); - return false; + for (int i = 0; i < _numChan ; i++) { + if (_channels[i]->_updateEnvelopes) { + _channels[i]->_updateEnvelopes = false; + _channels[i]->updateEnv(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) + _channels[i]->generateOutput(buffer[ii * 2], + buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf); } -} - -void TownsPC98_OpnDriver::keyOff(TwnChannel *chan) { - // all operators off - uint8 value = chan->keyNum & 0x0f; - uint8 regAdress = 0x28; - writeReg(chan, regAdress, value); - chan->flags |= CHS_KEYOFF; -} -void TownsPC98_OpnDriver::keyOn(TwnChannel *chan) { - // all operators on - uint8 value = chan->keyNum | 0xf0; - uint8 regAdress = 0x28; - writeReg(chan, regAdress, value); + for (int i = 0; i < _numSSG ; i++) { + if (_ssgChannels[i]->_updateEnvelopes) { + _ssgChannels[i]->_updateEnvelopes = false; + _ssgChannels[i]->updateEnv(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) + _ssgChannels[i]->generateOutput(buffer[ii * 2], + buffer[ii * 2 + 1], &_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf); + } } -void TownsPC98_OpnDriver::writeReg(TwnChannel *chan, uint8 regAdress, uint8 value) { - uint8 h = regAdress & 0xf0; - uint8 l = (regAdress & 0x0f); - static const uint8 opr[] = { 0, 2, 1, 3 }; - uint8 o = opr[(l - chan->regOffset) >> 2]; - - switch (h) { - case 0x00: - // ssg - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - case 0x10: - // adpcm - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - case 0x20: - if (l == 8) { - // Key on/off - for (int i = 0; i < 4; i++) { - if ((value >> (4 + i)) & 1) - chan->opr[i]->keyOn(); - else - chan->opr[i]->keyOff(); - } - } else if (l == 2) { - // LFO - warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); - } else if (l == 7) { - // Timers; Ch 3/6 special mode - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)"); - } else if (l == 4 || l == 5) { - // Timer A - warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)"); - } else if (l == 6) { - // Timer B - warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)"); - } else if (l == 10 || l == 11) { - // DAC - warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); - } - break; - - case 0x30: - // detune, multiple - chan->opr[o]->detune((value >> 4) & 7); - chan->opr[o]->multiple(value & 0x0f); - chan->updateEnvelopes = true; - break; - - case 0x40: - // total level - chan->opr[o]->totalLevel(value & 0x7f); - break; +void TownsPC98_OpnDriver::generateTables() { + delete [] _oprRates; + _oprRates = new uint8[128]; + memset(_oprRates, 0x90, 32); + uint8 *dst = (uint8*) _oprRates + 32; + for (int i = 0; i < 48; i += 4) + WRITE_BE_UINT32(dst + i, 0x00081018); + dst += 48; + for (uint8 i = 0; i < 16; i ++) { + uint8 v = (i < 12) ? i : 12; + *dst++ = ((4 + v) << 3); + } + memset(dst, 0x80, 32); - case 0x50: - // rate scaling, attack rate - chan->opr[o]->attackRate(value & 0x1f); - if (chan->opr[o]->scaleRate(value >> 6)) - chan->updateEnvelopes = true; - break; + delete [] _oprRateshift; + _oprRateshift = new uint8[128]; + memset(_oprRateshift, 0, 128); + dst = (uint8*) _oprRateshift + 32; + for (int i = 11; i; i--) { + memset(dst, i, 4); + dst += 4; + } - case 0x60: - // first decay rate, amplitude modulation - chan->opr[o]->decayRate(value & 0x1f); - if (value & 0x80) - warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); + delete [] _oprFrq; + _oprFrq = new uint32[0x1000]; + for (uint32 i = 0; i < 0x1000; i++) + _oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); - break; + delete [] _oprAttackDecay; + _oprAttackDecay = new uint8[152]; + memset(_oprAttackDecay, 0, 152); + for (int i = 0; i < 36; i++) + WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); - case 0x70: - // secondary decay rate - chan->opr[o]->sustainRate(value & 0x1f); - break; + delete [] _oprSinTbl; + _oprSinTbl = new uint32[1024]; + for (int i = 0; i < 1024; i++) { + double val = sin((double) (((i << 1) + 1) * M_PI / 1024.0)); + double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; + int32 i_dcb = (int32)(2.0 * d_dcb); + i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); + _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); + } - case 0x80: - // secondary amplitude, release rate; - chan->opr[o]->sustainLevel(value >> 4); - chan->opr[o]->releaseRate(value & 0x0f); - break; + delete [] _oprLevelOut; + _oprLevelOut = new int32[0x1a00]; + for (int i = 0; i < 256; i++) { + double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); + int32 val_int = ((int32) val) >> 4; + _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; + _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; + for (int ii = 1; ii < 13; ii++) { + _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; + _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; + } + } - case 0x90: - // ssg - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; + uint8 *dtt = new uint8[128]; + memset(dtt, 0, 36); + memset(dtt + 36, 1, 8); + memcpy(dtt + 44, _drvTables + 144, 84); - case 0xa0: - // frequency - l -= chan->regOffset; - if (l == 0) { - chan->frqTemp = (chan->frqTemp & 0xff00) | value; - chan->updateEnvelopes = true; - for (int i = 0; i < 4; i++) - chan->opr[i]->frequency(chan->frqTemp); - } else if (l == 4) { - chan->frqTemp = (chan->frqTemp & 0xff) | (value << 8); - } else if (l == 8) { - // Ch 3/6 special mode frq - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); - } else if (l == 12) { - // Ch 3/6 special mode frq - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); - } - break; + delete [] _oprDetune; + _oprDetune = new int32[256]; + for (int i = 0; i < 128; i++) { + _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); + _oprDetune[i + 128] = -_oprDetune[i]; + } - case 0xb0: - l -= chan->regOffset; - if (l == 0) { - // feedback, algorithm - chan->opr[0]->feedbackLevel((value >> 3) & 7); - chan->opr[1]->feedbackLevel(0); - chan->opr[2]->feedbackLevel(0); - chan->opr[3]->feedbackLevel(0); - } else if (l == 4) { - // stereo, LFO sensitivity - chan->enableLeft = value & 0x80 ? true : false; - chan->enableRight = value & 0x40 ? true : false; - uint8 ams = (value & 0x3F) >> 3; - if (ams) - warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); - uint8 fms = value & 3; - if (fms) - warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); - } - break; + delete [] dtt; +} - default: - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - } +void TownsPC98_OpnDriver::setTempo(uint8 tempo) { + _tempo = tempo; + _samplesPerCallback = getRate() / _tempo; + _samplesPerCallbackRemainder = getRate() % _tempo; } const uint8 TownsPC98_OpnDriver::_drvTables[] = { @@ -2474,7 +2776,7 @@ void SoundTowns::playTrack(uint8 track) { return; track -= 2; - const int32 * const tTable = (const int32 * const) cdaData(); + const int32 *const tTable = (const int32 *const) cdaData(); int tTableIndex = 3 * track; int trackNum = (int) READ_LE_UINT32(&tTable[tTableIndex + 2]); @@ -2545,12 +2847,12 @@ void SoundTowns::playSoundEffect(uint8 track) { } } - uint8 * fileBody = _sfxFileData + 0x01b8; + uint8 *fileBody = _sfxFileData + 0x01b8; int32 offset = (int32)READ_LE_UINT32(_sfxFileData + (track - 0x0b) * 4); if (offset == -1) return; - uint32 * sfxHeader = (uint32*)(fileBody + offset); + uint32 *sfxHeader = (uint32*)(fileBody + offset); uint32 sfxHeaderID = READ_LE_UINT32(sfxHeader); uint32 sfxHeaderInBufferSize = READ_LE_UINT32(&sfxHeader[1]); @@ -2570,7 +2872,7 @@ void SoundTowns::playSoundEffect(uint8 track) { } else if (sfxHeaderID == 1) { Screen::decodeFrame4(sfxBody, sfxPlaybackBuffer, playbackBufferSize); } else if (_sfxWDTable) { - uint8 * tgt = sfxPlaybackBuffer; + uint8 *tgt = sfxPlaybackBuffer; uint32 sfx_BtTable_Offset = 0; uint32 sfx_WdTable_Offset = 0; uint32 sfx_WdTable_Number = 5; @@ -2635,7 +2937,7 @@ uint32 SoundTowns::getBaseTempo(void) { } bool SoundTowns::loadInstruments() { - uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0); + uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); if (!twm) return false; _driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0); @@ -2650,7 +2952,7 @@ bool SoundTowns::loadInstruments() { } void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { - uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0); + uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); Common::StackLock lock(_mutex); if (!_parser) { @@ -2665,7 +2967,7 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { delete[] twm; } -void SoundTowns::onTimer(void * data) { +void SoundTowns::onTimer(void *data) { SoundTowns *music = (SoundTowns *)data; Common::StackLock lock(music->_mutex); if (music->_parser) @@ -2763,7 +3065,7 @@ void SoundPC98::playSoundEffect(uint8) { // KYRA 2 SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) : - Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0) { + Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { } SoundTownsPC98_v2::~SoundTownsPC98_v2() { @@ -2774,6 +3076,7 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() { bool SoundTownsPC98_v2::init() { _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); + _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like // a good idea, we should definitely not be doing this @@ -2786,7 +3089,6 @@ bool SoundTownsPC98_v2::init() { (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) _musicEnabled = 2; - _musicEnabled = 1; return _driver->init(); } @@ -2798,7 +3100,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) { if (track == _lastTrack && _musicEnabled) return; - const uint16 * const cdaTracks = (const uint16 * const) cdaData(); + const uint16 *const cdaTracks = (const uint16 *const) cdaData(); int trackNum = -1; if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { @@ -2815,6 +3117,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) { char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); delete[] _musicTrackData; + _musicTrackData = _vm->resource()->fileData(musicfile, 0); _driver->loadData(_musicTrackData, true); @@ -2854,8 +3157,8 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { char filename[13]; sprintf(filename, "%s.PCM", file); - uint8 * data = _vm->resource()->fileData(filename, 0); - uint8 * src = data; + uint8 *data = _vm->resource()->fileData(filename, 0); + uint8 *src = data; uint16 sfxRate = rates[READ_LE_UINT16(src)]; src += 2; @@ -2908,6 +3211,18 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { return 1; } +void SoundTownsPC98_v2::playSoundEffect(uint8 track) { + if (!_useFmSfx) + return; + + uint8 *sd = _vm->resource()->fileData("sound.dat", 0); + + + //TODO + + delete [] sd; +} + } // end of namespace Kyra #undef EUPHONY_FADEOUT_TICKS -- cgit v1.2.3 From f5f97f424569d45987b73414847bda5e009f1f00 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 29 Jun 2008 15:59:35 +0000 Subject: cleanup svn-id: r32842 --- engines/kyra/sound_towns.cpp | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 4a8e8a5b15..f06817a4c1 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1334,7 +1334,7 @@ class TownsPC98_OpnChannel { public: TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); - ~TownsPC98_OpnChannel(); + virtual ~TownsPC98_OpnChannel(); virtual void init(); typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); @@ -1366,7 +1366,6 @@ public: bool _enableLeft; bool _enableRight; - bool _fading; bool _updateEnvelopes; const uint8 _idFlag; int _feedbuf[3]; @@ -1432,6 +1431,7 @@ class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel { public: TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + ~TownsPC98_OpnChannelSSG() {} void init(); void processEvents(); @@ -1510,6 +1510,7 @@ protected: uint8 _finishedChannelsFlag; uint16 _tempo; bool _playing; + bool _fading; uint8 _looping; uint32 _tickCounter; @@ -1538,7 +1539,7 @@ TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 re _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _unk15 = _unk16 = 0; _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = _unk28 = _unk29 = 0; _frqLSB = 0; - _protect = _updateEnvelopes = _fading = false; + _protect = _updateEnvelopes = false; _enableLeft = _enableRight = true; _dataPtr = 0; _ptchWhlModInitVal = _ptchWhlModCurVal = 0; @@ -1744,7 +1745,7 @@ void TownsPC98_OpnChannel::reset() { for (int i = 0; i < 4; i++) _opr[i]->reset(); - _fading = _updateEnvelopes = false; + _updateEnvelopes = false; _enableLeft = _enableRight = true; memset(&_feedbuf, 0, sizeof(int) * 3); } @@ -2003,7 +2004,7 @@ bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { } bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) { - if (_fading) + if (_drv->_fading) return true; _totalLevel = _drv->_opnLvlPresets[para]; @@ -2022,7 +2023,7 @@ bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) { } bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) { - if (_fading) + if (_drv->_fading) return true; _totalLevel = para; @@ -2084,7 +2085,7 @@ bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) { bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) { _dataPtr--; - if (_fading) + if (_drv->_fading) return true; uint8 val = (_totalLevel + 3); @@ -2098,7 +2099,7 @@ bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) { bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) { _dataPtr--; - if (_fading) + if (_drv->_fading) return true; int8 val = (int8) (_totalLevel - 3); @@ -2146,7 +2147,7 @@ bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) { } bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) { - if (!_fading) + if (!_drv->_fading) _totalLevel = para; return true; } @@ -2163,7 +2164,7 @@ bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) { bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { _dataPtr--; - if (_fading) + if (_drv->_fading) return true; _totalLevel--; @@ -2175,7 +2176,7 @@ bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { _dataPtr--; - if (_fading) + if (_drv->_fading) return true; if(_totalLevel + 1 < 0x10) @@ -2241,7 +2242,7 @@ void TownsPC98_OpnChannelSSG::processEvents() { if (_flags & CHS_EOT) return; - int _ssgUnk = (_flags & CHS_SSG) ? -1 : 0; + //int _ssgUnk = (_flags & CHS_SSG) ? -1 : 0; if (_protect == false && _ticksLeft == _keyOffTime) keyOff(); @@ -2336,7 +2337,7 @@ void TownsPC98_OpnChannelSSG::keyOn() { } TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : - _mixer(mixer), _trackData(0), _playing(false), _channels(0), _ssgChannels(0), + _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0), _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), @@ -2498,7 +2499,7 @@ void TownsPC98_OpnDriver::reset() { for (int i = 0; i < (_numSSG); i++) _ssgChannels[i]->reset(); - _playing = false; + _playing = _fading = false; _looping = 0; _tickCounter = 0; } @@ -2507,10 +2508,7 @@ void TownsPC98_OpnDriver::fadeOut() { if (!_playing) return; - for (int j = 0; j < _numChan; j++) - _channels[j]->_fading = true; - for (int j = 0; j < _numSSG; j++) - _ssgChannels[j]->_fading = true; + _fading = true; for (int i = 0; i < 20; i++) { lock(); @@ -2530,10 +2528,7 @@ void TownsPC98_OpnDriver::fadeOut() { } } - for (int j = 0; j < _numChan; j++) - _channels[j]->_fading = false; - for (int j = 0; j < _numSSG; j++) - _ssgChannels[j]->_fading = false; + _fading = false; reset(); } -- cgit v1.2.3 From cbf00ff5654ba1719a35ac139035e55d62b2fea0 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 29 Jun 2008 16:07:29 +0000 Subject: fix warning svn-id: r32843 --- engines/kyra/sound_towns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index f06817a4c1..a4142603e9 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -2168,7 +2168,7 @@ bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { return true; _totalLevel--; - if ((int8)_totalLevel < 0); + if ((int8)_totalLevel < 0) _totalLevel = 0; return true; -- cgit v1.2.3 From f0df79bb88b61140999afd7af36bf25b34b35e46 Mon Sep 17 00:00:00 2001 From: Kostas Nakos Date: Sun, 29 Jun 2008 16:58:27 +0000 Subject: adding a fixme svn-id: r32844 --- engines/cruise/cruise_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cruise/cruise_main.h b/engines/cruise/cruise_main.h index 60afe5fa4c..c9c27ada49 100644 --- a/engines/cruise/cruise_main.h +++ b/engines/cruise/cruise_main.h @@ -28,7 +28,7 @@ #include #include -#include +#include // FIXME: WINCE: this is not needed/not portable (probably applies to all above includes) #include "common/scummsys.h" -- cgit v1.2.3 From 2779b851ab4328bce306b58e49df515bca58f1ab Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 30 Jun 2008 01:36:50 +0000 Subject: Small cleanup/shuffling of Gfx code. svn-id: r32847 --- engines/parallaction/debug.cpp | 4 +- engines/parallaction/gfxbase.cpp | 220 +++++++++++++++++++++++++++++++++++++- engines/parallaction/graphics.cpp | 208 +---------------------------------- engines/parallaction/graphics.h | 2 - 4 files changed, 219 insertions(+), 215 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp index 6bd704a2f5..f57976594e 100644 --- a/engines/parallaction/debug.cpp +++ b/engines/parallaction/debug.cpp @@ -188,7 +188,7 @@ bool Debugger::Cmd_GfxObjects(int argc, const char **argv) { const char *objType[] = { "DOOR", "GET", "ANIM" }; DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n" - "| name | x | y | z | f | type | flag |\n" + "| name | x | y | z | f | type | visi |\n" "+--------------------+-----+-----+-----+-----+--------+--------+\n"); GfxObjList::iterator b = _vm->_gfx->_gfxobjList.begin(); @@ -196,7 +196,7 @@ bool Debugger::Cmd_GfxObjects(int argc, const char **argv) { for ( ; b != e; b++) { GfxObj *obj = *b; - DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], 6 ); + DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], obj->isVisible() ); } DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n"); diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 66b1ceecf7..cdf4c9cdf6 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -92,6 +92,7 @@ GfxObj* Gfx::loadAnim(const char *name) { // animation Z is not set here, but controlled by game scripts and user interaction. // it is always >=0 and type = kGfxObjTypeAnim; + _gfxobjList.push_back(obj); return obj; } @@ -102,6 +103,7 @@ GfxObj* Gfx::loadGet(const char *name) { obj->z = kGfxObjGetZ; // this preset Z value ensures that get zones are drawn after doors but before animations obj->type = kGfxObjTypeGet; + _gfxobjList.push_back(obj); return obj; } @@ -111,6 +113,7 @@ GfxObj* Gfx::loadDoor(const char *name) { obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first obj->type = kGfxObjTypeDoor; + _gfxobjList.push_back(obj); return obj; } @@ -119,16 +122,17 @@ void Gfx::clearGfxObjects() { } void Gfx::showGfxObj(GfxObj* obj, bool visible) { - if (!obj || obj->isVisible() == visible) { - return; - } +// if (!obj || obj->isVisible() == visible) { +// return; +// } + + assert(obj); if (visible) { obj->setFlags(kGfxObjVisible); - _gfxobjList.push_back(obj); } else { obj->clearFlags(kGfxObjVisible); - _gfxobjList.remove(obj); +// _gfxobjList.remove(obj); } } @@ -174,4 +178,210 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) { } } + + +void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) { + byte *dst = (byte*)surf->getBasePtr(x, y); + font->setColor(color); + font->drawString(dst, surf->w, text); +} + +void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) { + + uint16 lines = 0; + uint16 linewidth = 0; + + uint16 rx = 10; + uint16 ry = 4; + + uint16 blankWidth = font->getStringWidth(" "); + uint16 tokenWidth = 0; + + char token[MAX_TOKEN_LEN]; + + if (wrapwidth == -1) + wrapwidth = _vm->_screenWidth; + + while (strlen(text) > 0) { + + text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); + + if (!scumm_stricmp(token, "%p")) { + lines++; + rx = 10; + ry = 4 + lines*10; // y + + strcpy(token, "> ......."); + strncpy(token+2, _password, strlen(_password)); + tokenWidth = font->getStringWidth(token); + } else { + tokenWidth = font->getStringWidth(token); + + linewidth += tokenWidth; + + if (linewidth > wrapwidth) { + // wrap line + lines++; + rx = 10; // x + ry = 4 + lines*10; // y + linewidth = tokenWidth; + } + + if (!scumm_stricmp(token, "%s")) { + sprintf(token, "%d", _score); + } + + } + + drawText(font, surf, rx, ry, token, color); + + rx += tokenWidth + blankWidth; + linewidth += blankWidth; + + text = Common::ltrim(text); + } + +} + + +// this is the maximum size of an unpacked frame in BRA +byte _unpackedBitmap[640*401]; + +#if 0 +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { + + byte *d = _unpackedBitmap; + + while (size > 0) { + + uint8 p = *data++; + size--; + uint8 color = p & 0xF; + uint8 repeat = (p & 0xF0) >> 4; + if (repeat == 0) { + repeat = *data++; + size--; + } + + memset(d, color, repeat); + d += repeat; + } + + blt(r, _unpackedBitmap, surf, z, transparentColor); +} +#endif +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { + + byte *d = _unpackedBitmap; + uint pixelsLeftInLine = r.width(); + + while (size > 0) { + uint8 p = *data++; + size--; + uint8 color = p & 0xF; + uint8 repeat = (p & 0xF0) >> 4; + if (repeat == 0) { + repeat = *data++; + size--; + } + if (repeat == 0) { + // end of line + repeat = pixelsLeftInLine; + pixelsLeftInLine = r.width(); + } else { + pixelsLeftInLine -= repeat; + } + + memset(d, color, repeat); + d += repeat; + } + + blt(r, _unpackedBitmap, surf, z, transparentColor); +} + + +void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { + + Common::Point dp; + Common::Rect q(r); + + Common::Rect clipper(surf->w, surf->h); + + q.clip(clipper); + if (!q.isValidRect()) return; + + dp.x = q.left; + dp.y = q.top; + + q.translate(-r.left, -r.top); + + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = surf->w - q.width(); + + + if (_varRenderMode == 2) { + + for (uint16 i = 0; i < q.height(); i++) { + + for (uint16 j = 0; j < q.width(); j++) { + if (*s != transparentColor) { + if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { + byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); + if (z >= v) *d = 5; + } else { + *d = 5; + } + } + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + + } else { + if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { + + for (uint16 i = 0; i < q.height(); i++) { + + for (uint16 j = 0; j < q.width(); j++) { + if (*s != transparentColor) { + byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); + if (z >= v) *d = *s; + } + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + + } else { + + for (uint16 i = q.top; i < q.bottom; i++) { + for (uint16 j = q.left; j < q.right; j++) { + if (*s != transparentColor) + *d = *s; + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + + } + } + +} + + } // namespace Parallaction diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 64edd7babe..5d8d81253b 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -531,145 +531,6 @@ void Gfx::invertBackground(const Common::Rect& r) { } -// this is the maximum size of an unpacked frame in BRA -byte _unpackedBitmap[640*401]; - -#if 0 -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { - - byte *d = _unpackedBitmap; - - while (size > 0) { - - uint8 p = *data++; - size--; - uint8 color = p & 0xF; - uint8 repeat = (p & 0xF0) >> 4; - if (repeat == 0) { - repeat = *data++; - size--; - } - - memset(d, color, repeat); - d += repeat; - } - - blt(r, _unpackedBitmap, surf, z, transparentColor); -} -#endif -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { - - byte *d = _unpackedBitmap; - uint pixelsLeftInLine = r.width(); - - while (size > 0) { - uint8 p = *data++; - size--; - uint8 color = p & 0xF; - uint8 repeat = (p & 0xF0) >> 4; - if (repeat == 0) { - repeat = *data++; - size--; - } - if (repeat == 0) { - // end of line - repeat = pixelsLeftInLine; - pixelsLeftInLine = r.width(); - } else { - pixelsLeftInLine -= repeat; - } - - memset(d, color, repeat); - d += repeat; - } - - blt(r, _unpackedBitmap, surf, z, transparentColor); -} - - -void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { - - Common::Point dp; - Common::Rect q(r); - - Common::Rect clipper(surf->w, surf->h); - - q.clip(clipper); - if (!q.isValidRect()) return; - - dp.x = q.left; - dp.y = q.top; - - q.translate(-r.left, -r.top); - - byte *s = data + q.left + q.top * r.width(); - byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); - - uint sPitch = r.width() - q.width(); - uint dPitch = surf->w - q.width(); - - - if (_varRenderMode == 2) { - - for (uint16 i = 0; i < q.height(); i++) { - - for (uint16 j = 0; j < q.width(); j++) { - if (*s != transparentColor) { - if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { - byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); - if (z >= v) *d = 5; - } else { - *d = 5; - } - } - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } else { - if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { - - for (uint16 i = 0; i < q.height(); i++) { - - for (uint16 j = 0; j < q.width(); j++) { - if (*s != transparentColor) { - byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); - if (z >= v) *d = *s; - } - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } else { - - for (uint16 i = q.top; i < q.bottom; i++) { - for (uint16 j = q.left; j < q.right; j++) { - if (*s != transparentColor) - *d = *s; - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } - } - -} - @@ -963,8 +824,8 @@ int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) { int id = _numItems; _items[id].data = frames; - _items[id].x = x; - _items[id].y = y; + _items[id].data->x = x; + _items[id].data->y = y; _items[id].transparentColor = transparentColor; @@ -976,8 +837,6 @@ int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) { void Gfx::setItemFrame(uint item, uint16 f) { assert(item < _numItems); _items[item].data->frame = f; - _items[item].data->x = _items[item].x; - _items[item].data->y = _items[item].y; } Gfx::Balloon* Gfx::getBalloon(uint id) { @@ -1112,69 +971,6 @@ void Gfx::hideDialogueStuff() { freeBalloons(); } -void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) { - byte *dst = (byte*)surf->getBasePtr(x, y); - font->setColor(color); - font->drawString(dst, surf->w, text); -} - -void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) { - - uint16 lines = 0; - uint16 linewidth = 0; - - uint16 rx = 10; - uint16 ry = 4; - - uint16 blankWidth = font->getStringWidth(" "); - uint16 tokenWidth = 0; - - char token[MAX_TOKEN_LEN]; - - if (wrapwidth == -1) - wrapwidth = _vm->_screenWidth; - - while (strlen(text) > 0) { - - text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); - - if (!scumm_stricmp(token, "%p")) { - lines++; - rx = 10; - ry = 4 + lines*10; // y - - strcpy(token, "> ......."); - strncpy(token+2, _password, strlen(_password)); - tokenWidth = font->getStringWidth(token); - } else { - tokenWidth = font->getStringWidth(token); - - linewidth += tokenWidth; - - if (linewidth > wrapwidth) { - // wrap line - lines++; - rx = 10; // x - ry = 4 + lines*10; // y - linewidth = tokenWidth; - } - - if (!scumm_stricmp(token, "%s")) { - sprintf(token, "%d", _score); - } - - } - - drawText(font, surf, rx, ry, token, color); - - rx += tokenWidth + blankWidth; - linewidth += blankWidth; - - text = Common::ltrim(text); - } - -} - void Gfx::freeBackground() { _backgroundInfo.free(); } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 6439941cc5..17869de432 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -572,8 +572,6 @@ public: uint _numBalloons; struct Item { - uint16 x; - uint16 y; uint16 frame; GfxObj *data; -- cgit v1.2.3 From ecbf8d54ad78dac70f7838e7546196b3bb232c5a Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 30 Jun 2008 03:33:08 +0000 Subject: Implemented resetGfxEntityEntry and made it used where appropriate (The function wasn't very easy to reverse engineer so it may have flaws still, but let's hope it doesn't ;-)). svn-id: r32848 --- engines/cine/object.cpp | 17 +++++-- engines/cine/various.cpp | 118 ++++++++++++++++++----------------------------- engines/cine/various.h | 2 + 3 files changed, 60 insertions(+), 77 deletions(-) (limited to 'engines') diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index 57a328eef9..61fecb55f8 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -179,8 +179,12 @@ void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint1 objectTable[objIdx].mask = param3; objectTable[objIdx].frame = param4; - if (removeOverlay(objIdx, 0)) { - addOverlay(objIdx, 0); + if (g_cine->getGameType() == Cine::GType_OS) { + resetGfxEntityEntry(objIdx); + } else { // Future Wars + if (removeOverlay(objIdx, 0)) { + addOverlay(objIdx, 0); + } } } @@ -208,9 +212,12 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { case 3: objectTable[objIdx].mask = newValue; - // TODO: Check this part against disassembly - if (removeOverlay(objIdx, 0)) { - addOverlay(objIdx, 0); + if (g_cine->getGameType() == Cine::GType_OS) { // Operation Stealth specific + resetGfxEntityEntry(objIdx); + } else { // Future Wars specific + if (removeOverlay(objIdx, 0)) { + addOverlay(objIdx, 0); + } } break; case 4: diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 20d9edc5de..6bbc907eb0 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1682,78 +1682,6 @@ uint16 computeMove2(SeqListElement &element) { return returnVar; } -// sort all the gfx stuff... - -void resetGfxEntityEntry(uint16 objIdx) { -#if 0 - overlayHeadElement* tempHead = &overlayHead; - byte* var_16 = NULL; - uint16 var_10 = 0; - uint16 var_12 = 0; - overlayHeadElement* currentHead = tempHead->next; - byte* var_1A = NULL; - overlayHeadElement* var1E = &overlayHead; - - while (currentHead) { - tempHead2 = currentHead->next; - - if (currentHead->objIdx == objIdx && currentHead->type!=2 && currentHead->type!=3 && currentHead->type!=0x14) { - tempHead->next = tempHead2; - - if (tempHead2) { - tempHead2->previous = currentHead->previous; - } else { - seqVar0 = currentHead->previous; - } - - var_22 = var_16; - - if (!var_22) { - // todo: goto? - } - - var_22->previous = currentHead; - } else { - } - - if (currentHead->type == 0x14) { - } else { - } - - if (currentHead->type == 0x2 || currentHead->type == 0x3) { - si = 10000; - } else { - si = objectTable[currentHead->objIdx]; - } - - if (objectTable[objIdx]>si) { - var1E = currentHead; - } - - tempHead = tempHead->next; - - } - - if (var_1A) { - currentHead = var_16; - var_22 = var_1E->next; - var_1E->next = currentHead; - var_1A->next = var_22; - - if (var_1E != &gfxEntityHead) { - currentHead->previous = var_1E; - } - - if (!var_22) { - seqVar0 = var_1A; - } else { - var_22->previous = var_1A; - } - - } -#endif -} - uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &element, uint16 param3, int16 *param4) { const byte *currentPtr = ptr; const byte *ptrData; @@ -1795,6 +1723,52 @@ uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &ele return 1; } +/*! + * Permutates the overlay list into a different order according to some logic. + * \todo Check this function for correctness (Wasn't very easy to reverse engineer so there may be errors) + */ +void resetGfxEntityEntry(uint16 objIdx) { + Common::List::iterator it, bObjsCutPoint; + Common::List aReverseObjs, bObjs; + bool foundCutPoint = false; + + // Go through the overlay list and partition the whole list into two categories (Type A and type B objects) + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + if (it->objIdx == objIdx && it->type != 2 && it->type != 3) { // Type A object + aReverseObjs.push_front(*it); + } else { // Type B object + bObjs.push_back(*it); + uint16 objectMask; + if (it->type == 2 || it->type == 3) { + objectMask = 10000; + } else { + objectMask = objectTable[it->objIdx].mask; + } + + if (objectTable[objIdx].mask > objectMask) { // Check for B objects' cut point + bObjsCutPoint = bObjs.reverse_begin(); + foundCutPoint = true; + } + } + } + + // Recreate the overlay list in a different order. + overlayList.clear(); + if (foundCutPoint) { + // If a cut point was found the order is: + // B objects before the cut point, the cut point, A objects in reverse order, B objects after cut point. + ++bObjsCutPoint; // Include the cut point in the first list insertion + overlayList.insert(overlayList.end(), bObjs.begin(), bObjsCutPoint); + overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); + overlayList.insert(overlayList.end(), bObjsCutPoint, bObjs.end()); + } else { + // If no cut point was found the order is: + // A objects in reverse order, B objects. + overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); + overlayList.insert(overlayList.end(), bObjs.begin(), bObjs.end()); + } +} + void processSeqListElement(SeqListElement &element) { int16 x = objectTable[element.objIdx].x; int16 y = objectTable[element.objIdx].y; diff --git a/engines/cine/various.h b/engines/cine/various.h index d05447fb40..840f1674a2 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -142,6 +142,8 @@ void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, i void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4); void processSeqList(void); +void resetGfxEntityEntry(uint16 objIdx); + bool makeTextEntryMenu(const char *caption, char *string, int strLen, int y); } // End of namespace Cine -- cgit v1.2.3 From 2ecf8fdbb5a0141ea43a7d2074a2a7356182f12c Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 30 Jun 2008 17:24:23 +0000 Subject: Fixed addAni (A test before using resetGfxEntityEntry was incorrect). Also added comments and checked that most 8-bit values used in this function are used as signed integers. svn-id: r32850 --- engines/cine/various.cpp | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 6bbc907eb0..ea5956be6b 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1682,33 +1682,49 @@ uint16 computeMove2(SeqListElement &element) { return returnVar; } -uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &element, uint16 param3, int16 *param4) { - const byte *currentPtr = ptr; - const byte *ptrData; - const byte *ptr2; +uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptrByte, SeqListElement &element, uint16 param3, int16 *param4) { + const int8 *ptr = (const int8 *)ptrByte; + const int8 *ptrData; + const int8 *ptr2; int16 di; + // In the original an error string is set and 0 is returned if the following doesn't hold assert(ptr); - assert(param4); - - dummyU16 = READ_BE_UINT16((currentPtr + param1 * 2) + 8); + // We probably could just use a local variable here instead of the dummyU16 but + // haven't checked if this has any side-effects so keeping it this way still. + dummyU16 = READ_BE_UINT16(ptr + param1 * 2 + 8); ptrData = ptr + dummyU16; + // In the original an error string is set and 0 is returned if the following doesn't hold assert(*ptrData); di = (objectTable[objIdx].costume + 1) % (*ptrData); - ptr2 = (ptrData + (di * 8)) + 1; - + ++ptrData; // Jump over the just read byte + // Here ptr2 seems to be indexing a table of structs (8 bytes per struct): + // struct { + // int8 x; // 0 (Used with checkCollision) + // int8 y; // 1 (Used with checkCollision) + // int8 numZones; // 2 (Used with checkCollision) + // int8 var3; // 3 (Not used in this function) + // int8 xAdd; // 4 (Used with an object) + // int8 yAdd; // 5 (Used with an object) + // int8 maskAdd; // 6 (Used with an object) + // int8 frameAdd; // 7 (Used with an object) + // }; + ptr2 = ptrData + di * 8; + + // We might probably safely discard the AND by 1 here because + // at least in the original checkCollision returns always 0 or 1. if ((checkCollision(objIdx, ptr2[0], ptr2[1], ptr2[2], ptr[0]) & 1)) { return 0; } - objectTable[objIdx].x += (int8)ptr2[4]; - objectTable[objIdx].y += (int8)ptr2[5]; - objectTable[objIdx].mask += (int8)ptr2[6]; + objectTable[objIdx].x += ptr2[4]; + objectTable[objIdx].y += ptr2[5]; + objectTable[objIdx].mask += ptr2[6]; - if (objectTable[objIdx].frame) { + if (ptr2[6]) { resetGfxEntityEntry(objIdx); } @@ -1717,6 +1733,7 @@ uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &ele if (param3 || !element.var14) { objectTable[objIdx].costume = di; } else { + assert(param4); *param4 = di; } -- cgit v1.2.3 From e415a97fe53a3eec537d7d67760af45730ec91fd Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 30 Jun 2008 18:15:34 +0000 Subject: Removed TODO from checkCollision: Updating zoneQuery each time checkCollision is called seems to be fine. svn-id: r32852 --- engines/cine/script_fw.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'engines') diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index f84904ccc5..148e673095 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1760,12 +1760,6 @@ int16 getZoneFromPositionRaw(byte *page, int16 x, int16 y, int16 width) { return zoneVar; } -/*! - * \todo Check whether updating the zoneQuery table is appropriate every time - * this function is called because this function is called also from elsewhere - * than simply o1_checkCollision (e.g. from addAni). In Operation Stealth's - * disassembly this probably isn't the case, so there may be weird side-effects. - */ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx) { int16 lx = objectTable[objIdx].x + x; int16 ly = objectTable[objIdx].y + y; -- cgit v1.2.3 From b07ff576233dec6e2138f19a5cf053e2ccf146df Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Mon, 30 Jun 2008 21:55:08 +0000 Subject: - this fixes Hof PC98 music initialization - music sounds exactly like FM-Towns for now svn-id: r32854 --- engines/kyra/kyra_hof.cpp | 2 +- engines/kyra/sound_towns.cpp | 51 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 11 deletions(-) (limited to 'engines') diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index a8b8c0dced..61a1570893 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -1564,7 +1564,7 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) { int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]); if (vocIndex != -1) _sound->voicePlay(_ingameSoundList[vocIndex], true); - else if (_flags.platform == Common::kPlatformPC) + else if (_flags.platform != Common::kPlatformFMTowns) // TODO ?? Maybe there is a way to let users select whether they want // voc, midi or adl sfx (even though it makes no sense to choose anything but voc). KyraEngine_v1::snd_playSoundEffect(track); diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index a4142603e9..6be2cae7a4 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1348,7 +1348,7 @@ public: CHS_EOT = 0x80 } ChannelState; - void loadData(uint8 *data); + virtual void loadData(uint8 *data); virtual void processEvents(); virtual void processFrequency(); bool processControlEvent(uint8 cmd); @@ -1404,7 +1404,6 @@ protected: uint8 _keyOffTime; bool _protect; uint8 *_dataPtr; - uint8 _unk15, _unk16; uint8 _ptchWhlInitDelayLo; uint8 _ptchWhlInitDelayHi; int16 _ptchWhlModInitVal; @@ -1413,9 +1412,11 @@ protected: int16 _ptchWhlModCurVal; uint8 _ptchWhlDurLeft; uint16 frequency; - uint8 _unk28, _unk29; uint8 _regOffset; uint8 _flags; + uint8 _ssg1; + uint8 _ssg2; + const uint8 _chanNum; const uint8 _keyNum; const uint8 _part; @@ -1439,8 +1440,13 @@ public: void keyOn(); void keyOff(); + void loadData(uint8 *data); + +private: + void opn_SSG_UNK(uint8 a); }; + class TownsPC98_OpnDriver : public Audio::AudioStream { friend class TownsPC98_OpnChannel; friend class TownsPC98_OpnChannelSSG; @@ -1514,7 +1520,8 @@ protected: uint8 _looping; uint32 _tickCounter; - bool __updateEnvelopes; + bool _updateEnvelopes; + int _ssgFlag; int32 _samplesTillCallback; int32 _samplesTillCallbackRemainder; @@ -1536,8 +1543,8 @@ TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 re uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), _part(prt), _idFlag(id) { - _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _unk15 = _unk16 = 0; - _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = _unk28 = _unk29 = 0; + _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _ssg1 = _ssg2 = 0; + _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0; _frqLSB = 0; _protect = _updateEnvelopes = false; _enableLeft = _enableRight = true; @@ -1602,7 +1609,6 @@ void TownsPC98_OpnChannel::keyOn() { writeReg(regAdress, value); } - void TownsPC98_OpnChannel::loadData(uint8 *data) { _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; _ticksLeft = 1; @@ -2242,7 +2248,7 @@ void TownsPC98_OpnChannelSSG::processEvents() { if (_flags & CHS_EOT) return; - //int _ssgUnk = (_flags & CHS_SSG) ? -1 : 0; + _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; if (_protect == false && _ticksLeft == _keyOffTime) keyOff(); @@ -2336,6 +2342,22 @@ void TownsPC98_OpnChannelSSG::keyOn() { writeReg(regAdress, value); } +void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { + _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; + opn_SSG_UNK(0); + TownsPC98_OpnChannel::loadData(data); + _algorithm = 0x80; +} + +void TownsPC98_OpnChannelSSG::opn_SSG_UNK(uint8 a) { + _ssg1 = a; + uint16 h = (_totalLevel + 1) * a; + if ((h >> 8) == _ssg2) + return; + _ssg2 = (h >> 8); + writeReg(8 + _regOffset, _ssg2); +} + TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0), _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), @@ -2469,7 +2491,7 @@ void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { uint8 *src_a = data; - for (uint8 i = 0; i < _numChan; i++) { + for (uint8 i = 0; i < 3; i++) { _channels[i]->loadData(data + READ_LE_UINT16(src_a)); src_a += 2; } @@ -2479,11 +2501,18 @@ void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { src_a += 2; } + for (uint8 i = 3; i < _numChan; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + if (_hasADPCM) { - // TODO + //_adpcmChannel->loadData(data + READ_LE_UINT16(src_a)); src_a += 2; } + _ssgFlag = 0; + _patches = src_a + 4; _cbCounter = 4; _finishedChannelsFlag = 0; @@ -2555,6 +2584,8 @@ void TownsPC98_OpnDriver::callback() { _ssgChannels[i]->processFrequency(); } } + + _ssgFlag = 0; unlock(); -- cgit v1.2.3 From cef7d68fc531dbaac68c2b83a340bfbb3dcf142e Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 30 Jun 2008 23:39:56 +0000 Subject: Added support for Spanish fan translation of kyra3 (See fr #1994040 "KYRA3: Add support for Spanish fan translation"). svn-id: r32858 --- engines/kyra/detection.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++- engines/kyra/kyra_hof.cpp | 3 +++ engines/kyra/kyra_mr.cpp | 3 +++ engines/kyra/kyra_v1.cpp | 32 ++--------------------------- engines/kyra/kyra_v1.h | 6 +++++- engines/kyra/kyra_v2.cpp | 32 +++++++++++++++++++++++++++++ engines/kyra/kyra_v2.h | 3 +++ 7 files changed, 98 insertions(+), 32 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 3fb62b51bd..33d0d2c070 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -41,7 +41,8 @@ struct KYRAGameDescription { namespace { -#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } +#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } +#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, id } #define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) #define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA1) @@ -61,6 +62,7 @@ namespace { #define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) #define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, true, Kyra::GI_KYRA3) const KYRAGameDescription adGameDescs[] = { { @@ -605,6 +607,53 @@ const KYRAGameDescription adGameDescs[] = { KYRA3_CD_FLAGS }, + // Spanish fan translation, see fr#1994040 "KYRA3: Add support for Spanish fan translation" + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::ES_ESP, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) + }, + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } }; diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 61a1570893..879efab86e 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -2024,6 +2024,9 @@ void KyraEngine_HoF::writeSettings() { break; } + if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG) + _flags.lang = _flags.fanLang; + ConfMan.set("language", Common::getLanguageCode(_flags.lang)); KyraEngine_v1::writeSettings(); diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 8a49b8e155..b425c0929f 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -1543,6 +1543,9 @@ void KyraEngine_MR::writeSettings() { break; } + if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG) + _flags.lang = _flags.fanLang; + ConfMan.set("language", Common::getLanguageCode(_flags.lang)); ConfMan.setBool("studio_audience", _configStudio); diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 980c181c4e..d2e0f37a60 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -173,36 +173,6 @@ int KyraEngine_v1::init() { _gameToLoad = -1; } - _lang = 0; - Common::Language lang = Common::parseLanguage(ConfMan.get("language")); - - if (_flags.gameID == GI_KYRA2 || _flags.gameID == GI_KYRA3) { - switch (lang) { - case Common::EN_ANY: - case Common::EN_USA: - case Common::EN_GRB: - _lang = 0; - break; - - case Common::FR_FRA: - _lang = 1; - break; - - case Common::DE_DEU: - _lang = 2; - break; - - case Common::JA_JPN: - _lang = 3; - break; - - default: - warning("unsupported language, switching back to English"); - _lang = 0; - break; - } - } - return 0; } @@ -277,6 +247,8 @@ void KyraEngine_v1::delayWithTicks(int ticks) { void KyraEngine_v1::registerDefaultSettings() { if (_flags.gameID != GI_KYRA3) ConfMan.registerDefault("cdaudio", (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)); + if (_flags.fanLang != Common::UNK_LANG) + ConfMan.registerDefault("subtitles", true); } void KyraEngine_v1::readSettings() { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 4f38ceca98..09efc8cc97 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -44,6 +44,11 @@ namespace Kyra { struct GameFlags { Common::Language lang; + + // language overwrites of fan translations (only needed for multilingual games) + Common::Language fanLang; + Common::Language replacedLang; + Common::Platform platform; bool isDemo : 1; @@ -212,7 +217,6 @@ protected: // detection GameFlags _flags; - int _lang; // opcode virtual void setupOpcodeTable() = 0; diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 12da338843..2e704f2aa2 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -23,6 +23,8 @@ * */ +#include "common/config-manager.h" + #include "kyra/kyra_v2.h" #include "kyra/screen_v2.h" #include "kyra/debugger.h" @@ -70,6 +72,36 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi memset(&_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory)); _pauseStart = 0; + + _lang = 0; + Common::Language lang = Common::parseLanguage(ConfMan.get("language")); + if (lang == _flags.fanLang && _flags.replacedLang != Common::UNK_LANG) + lang = _flags.replacedLang; + + switch (lang) { + case Common::EN_ANY: + case Common::EN_USA: + case Common::EN_GRB: + _lang = 0; + break; + + case Common::FR_FRA: + _lang = 1; + break; + + case Common::DE_DEU: + _lang = 2; + break; + + case Common::JA_JPN: + _lang = 3; + break; + + default: + warning("unsupported language, switching back to English"); + _lang = 0; + break; + } } KyraEngine_v2::~KyraEngine_v2() { diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 24f7aad614..6fdf30fff8 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -94,6 +94,9 @@ protected: virtual void update() = 0; virtual void updateWithText() = 0; + // detection + int _lang; + // MainMenu MainMenu *_menu; -- cgit v1.2.3 From 34a49d4a5acd1e5c71bf3f37b829e37390b3c5e1 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 30 Jun 2008 23:44:33 +0000 Subject: Fix game flags for detection entries of installed kyra3 versions. svn-id: r32859 --- engines/kyra/detection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 33d0d2c070..f55cd1ac5e 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -61,8 +61,8 @@ namespace { #define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_KYRA2) #define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) -#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) -#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3) +#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3) const KYRAGameDescription adGameDescs[] = { { -- cgit v1.2.3 From bd296a45fa2ad9c08b096c50cf53ecbcd94a36a5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 1 Jul 2008 10:33:25 +0000 Subject: Fixed unitialized variables svn-id: r32865 --- engines/cine/bg_list.cpp | 2 ++ engines/cine/object.cpp | 4 ++++ engines/cine/various.cpp | 1 + engines/drascula/talk.cpp | 2 +- engines/engines.mk | 5 +++++ engines/m4/assets.cpp | 1 + engines/m4/converse.cpp | 2 +- engines/made/screen.cpp | 2 ++ 8 files changed, 17 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index cf25f1d355..b10211282f 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -63,6 +63,7 @@ void addSpriteFilledToBGList(int16 objIdx) { void createBgIncrustListElement(int16 objIdx, int16 param) { BGIncrust tmp; + tmp.unkPtr = 0; tmp.objIdx = objIdx; tmp.param = param; tmp.x = objectTable[objIdx].x; @@ -90,6 +91,7 @@ void loadBgIncrustFromSave(Common::InSaveFile &fHandle) { fHandle.readUint32BE(); fHandle.readUint32BE(); + tmp.unkPtr = 0; tmp.objIdx = fHandle.readUint16BE(); tmp.param = fHandle.readUint16BE(); tmp.x = fHandle.readUint16BE(); diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index 61fecb55f8..c02e01c8ce 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -125,6 +125,10 @@ void addOverlay(uint16 objIdx, uint16 type) { tmp.objIdx = objIdx; tmp.type = type; + tmp.x = 0; + tmp.y = 0; + tmp.width = 0; + tmp.color = 0; overlayList.insert(it, tmp); } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index ea5956be6b..0439856e5c 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -133,6 +133,7 @@ void runObjectScript(int16 entryIdx) { */ void addPlayerCommandMessage(int16 cmd) { overlay tmp; + memset(&tmp, 0, sizeof(tmp)); tmp.objIdx = cmd; tmp.type = 3; diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index 4d3187a0fd..a89c5ff734 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -60,7 +60,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { int x_talk1[8] = { 56, 86, 116, 146, 176, 206, 236, 266 }; int x_talk3[4] = { 80, 102, 124, 146 }; int x_talk4[4] = { 119, 158, 197, 236 }; - int face; + int face = 0; int length = strlen(said); color_abc(kColorWhite); diff --git a/engines/engines.mk b/engines/engines.mk index cfb8e69f3e..4dba913173 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -97,6 +97,11 @@ DEFINES += -DENABLE_SWORD2=$(ENABLE_SWORD2) MODULES += engines/sword2 endif +ifdef ENABLE_TINSEL +DEFINES += -DENABLE_TINSEL=$(ENABLE_TINSEL) +MODULES += engines/tinsel +endif + ifdef ENABLE_TOUCHE DEFINES += -DENABLE_TOUCHE=$(ENABLE_TOUCHE) MODULES += engines/touche diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp index 80b21119ff..0488f17d8f 100644 --- a/engines/m4/assets.cpp +++ b/engines/m4/assets.cpp @@ -201,6 +201,7 @@ void SpriteAsset::loadMadsSpriteAsset(M4Engine *vm, Common::SeekableReadStream* Common::SeekableReadStream *spriteDataStream = sprite.getItemStream(3); SpriteAssetFrame frame; for (curFrame = 0; curFrame < _frameCount; curFrame++) { + frame.stream = 0; frame.comp = 0; frameOffset = spriteStream->readUint32LE(); _frameOffsets.push_back(frameOffset); diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index a07a175066..a85fdea02f 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -379,7 +379,7 @@ void Converse::loadConversation(const char *convName) { uint32 header = convS->readUint32LE(); uint32 size; uint32 chunk; - uint32 data; + uint32 data = 0; uint32 i; ConvEntry* curEntry = NULL; ConvEntry* replyEntry = NULL; diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index 1d81793448..0c22d40259 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -822,6 +822,8 @@ SpriteListItem Screen::getFromSpriteList(int16 index) { if (((uint) index) > _spriteList.size()) { SpriteListItem emptyItem; emptyItem.index = 0; + emptyItem.xofs = 0; + emptyItem.yofs = 0; return emptyItem; } else { return _spriteList[index - 1]; -- cgit v1.2.3 From 6dc312b9e1ffbfc92452ebdeee8f3f703f07f7fa Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 1 Jul 2008 14:51:44 +0000 Subject: Reverted accidental commit of Tinsel changes in engines.mk svn-id: r32868 --- engines/engines.mk | 5 ----- 1 file changed, 5 deletions(-) (limited to 'engines') diff --git a/engines/engines.mk b/engines/engines.mk index 4dba913173..cfb8e69f3e 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -97,11 +97,6 @@ DEFINES += -DENABLE_SWORD2=$(ENABLE_SWORD2) MODULES += engines/sword2 endif -ifdef ENABLE_TINSEL -DEFINES += -DENABLE_TINSEL=$(ENABLE_TINSEL) -MODULES += engines/tinsel -endif - ifdef ENABLE_TOUCHE DEFINES += -DENABLE_TOUCHE=$(ENABLE_TOUCHE) MODULES += engines/touche -- cgit v1.2.3 From 77a60673ef970ec32fc2e4db09aa5ac534481c8d Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 2 Jul 2008 01:41:08 +0000 Subject: - Changed labels to be GfxObj's, thus removing the Label object altogether. - Changed Item's to be almost GfxObj's, since ownership and destruction of underlying resource is an issue here (got to think some more about it). svn-id: r32873 --- engines/parallaction/exec_br.cpp | 4 +- engines/parallaction/gfxbase.cpp | 38 ++++-- engines/parallaction/graphics.cpp | 199 +++++++++++++++---------------- engines/parallaction/graphics.h | 41 +++---- engines/parallaction/input.h | 2 +- engines/parallaction/objects.cpp | 1 - engines/parallaction/objects.h | 2 +- engines/parallaction/parallaction.cpp | 6 +- engines/parallaction/parallaction_ns.cpp | 4 +- 9 files changed, 146 insertions(+), 151 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 3b67b4c370..348af2b731 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -100,8 +100,8 @@ void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { } void Parallaction_br::clearSubtitles() { - _gfx->freeLabels(); - _subtitle[0] = _subtitle[1] = -1; + _gfx->hideLabel(_subtitle[0]); + _gfx->hideLabel(_subtitle[1]); } diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index cdf4c9cdf6..383f5d549c 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -92,6 +92,7 @@ GfxObj* Gfx::loadAnim(const char *name) { // animation Z is not set here, but controlled by game scripts and user interaction. // it is always >=0 and type = kGfxObjTypeAnim; + obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; } @@ -103,6 +104,7 @@ GfxObj* Gfx::loadGet(const char *name) { obj->z = kGfxObjGetZ; // this preset Z value ensures that get zones are drawn after doors but before animations obj->type = kGfxObjTypeGet; + obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; } @@ -113,6 +115,7 @@ GfxObj* Gfx::loadDoor(const char *name) { obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first obj->type = kGfxObjTypeDoor; + obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; } @@ -150,11 +153,32 @@ void Gfx::sortAnimations() { Common::sort(first, last, compareZ); } -void Gfx::drawGfxObjects(Graphics::Surface &surf) { + +void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) { + if (!obj->isVisible()) { + return; + } Common::Rect rect; byte *data; + uint scrollX = (scene) ? -_varScrollX : 0; + + obj->getRect(obj->frame, rect); + rect.translate(obj->x + scrollX, obj->y); + data = obj->getData(obj->frame); + + if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { + blt(rect, data, &surf, obj->layer, obj->transparentKey); + } else { + unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey); + } + +} + + +void Gfx::drawGfxObjects(Graphics::Surface &surf) { + sortAnimations(); // TODO: some zones don't appear because of wrong masking (3 or 0?) // TODO: Dr.Ki is not visible inside the club @@ -164,17 +188,7 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) { GfxObjList::iterator e = _gfxobjList.end(); for (; b != e; b++) { - GfxObj *obj = *b; - if (obj->isVisible()) { - obj->getRect(obj->frame, rect); - rect.translate(obj->x - _varScrollX, obj->y); - data = obj->getData(obj->frame); - if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { - blt(rect, data, &surf, obj->layer, 0); - } else { - unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, 0); - } - } + drawGfxObject(*b, surf, true); } } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 5d8d81253b..838827b19f 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -356,17 +356,7 @@ void Gfx::drawItems() { Graphics::Surface *surf = g_system->lockScreen(); for (uint i = 0; i < _numItems; i++) { - GfxObj *obj = _items[i].data; - - Common::Rect rect; - obj->getRect(obj->frame, rect); - rect.translate(obj->x, obj->y); - - if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { - blt(rect, obj->getData(obj->frame), surf, LAYER_FOREGROUND, _items[i].transparentColor); - } else { - unpackBlt(rect, obj->getData(obj->frame), obj->getRawSize(obj->frame), surf, LAYER_FOREGROUND, _items[i].transparentColor); - } + drawGfxObject(_items[i].data, *surf, false); } g_system->unlockScreen(); } @@ -540,10 +530,9 @@ void setupLabelSurface(Graphics::Surface &surf, uint w, uint h) { surf.fillRect(Common::Rect(w,h), LABEL_TRANSPARENT_COLOR); } -Label *Gfx::renderFloatingLabel(Font *font, char *text) { +uint Gfx::renderFloatingLabel(Font *font, char *text) { - Label *label = new Label; - Graphics::Surface *cnv = &label->_cnv; + Graphics::Surface *cnv = new Graphics::Surface; uint w, h; @@ -569,14 +558,74 @@ Label *Gfx::renderFloatingLabel(Font *font, char *text) { drawText(font, cnv, 0, 0, text, 0); } - return label; + GfxObj *obj = new GfxObj(kGfxObjTypeLabel, new SurfaceToFrames(cnv), "floatingLabel"); + obj->transparentKey = LABEL_TRANSPARENT_COLOR; + obj->layer = LAYER_FOREGROUND; + + uint id = _labels.size(); + _labels.insert_at(id, obj); + + return id; +} + +void Gfx::showFloatingLabel(uint label) { + assert(label < _labels.size()); + + hideFloatingLabel(); + + _labels[label]->x = -1000; + _labels[label]->y = -1000; + _labels[label]->setFlags(kGfxObjVisible); + + _floatingLabel = label; +} + +void Gfx::hideFloatingLabel() { + if (_floatingLabel != NO_FLOATING_LABEL) { + _labels[_floatingLabel]->clearFlags(kGfxObjVisible); + } + _floatingLabel = NO_FLOATING_LABEL; +} + + +void Gfx::updateFloatingLabel() { + if (_floatingLabel == NO_FLOATING_LABEL) { + return; + } + + int16 _si, _di; + + Common::Point cursor; + _vm->_input->getCursorPos(cursor); + + Common::Rect r; + _labels[_floatingLabel]->getRect(0, r); + + if (_vm->_input->_activeItem._id != 0) { + _si = cursor.x + 16 - r.width()/2; + _di = cursor.y + 34; + } else { + _si = cursor.x + 8 - r.width()/2; + _di = cursor.y + 21; + } + + if (_si < 0) _si = 0; + if (_di > 190) _di = 190; + + if (r.width() + _si > _vm->_screenWidth) + _si = _vm->_screenWidth - r.width(); + + _labels[_floatingLabel]->x = _si; + _labels[_floatingLabel]->y = _di; } + + + uint Gfx::createLabel(Font *font, const char *text, byte color) { - assert(_numLabels < MAX_NUM_LABELS); + assert(_labels.size() < MAX_NUM_LABELS); - Label *label = new Label; - Graphics::Surface *cnv = &label->_cnv; + Graphics::Surface *cnv = new Graphics::Surface; uint w, h; @@ -597,122 +646,64 @@ uint Gfx::createLabel(Font *font, const char *text, byte color) { drawText(font, cnv, 0, 0, text, color); } - uint id = _numLabels; - _labels[id] = label; - _numLabels++; + GfxObj *obj = new GfxObj(kGfxObjTypeLabel, new SurfaceToFrames(cnv), "label"); + obj->transparentKey = LABEL_TRANSPARENT_COLOR; + obj->layer = LAYER_FOREGROUND; + + int id = _labels.size(); + + _labels.insert_at(id, obj); return id; } void Gfx::showLabel(uint id, int16 x, int16 y) { - assert(id < _numLabels); - _labels[id]->_visible = true; + assert(id < _labels.size()); + _labels[id]->setFlags(kGfxObjVisible); + + Common::Rect r; + _labels[id]->getRect(0, r); if (x == CENTER_LABEL_HORIZONTAL) { - x = CLIP((_vm->_screenWidth - _labels[id]->_cnv.w) / 2, 0, _vm->_screenWidth/2); + x = CLIP((_vm->_screenWidth - r.width()) / 2, 0, _vm->_screenWidth/2); } if (y == CENTER_LABEL_VERTICAL) { - y = CLIP((_vm->_screenHeight - _labels[id]->_cnv.h) / 2, 0, _vm->_screenHeight/2); + y = CLIP((_vm->_screenHeight - r.height()) / 2, 0, _vm->_screenHeight/2); } - _labels[id]->_pos.x = x; - _labels[id]->_pos.y = y; + _labels[id]->x = x; + _labels[id]->y = y; } void Gfx::hideLabel(uint id) { - assert(id < _numLabels); - _labels[id]->_visible = false; + assert(id < _labels.size()); + _labels[id]->clearFlags(kGfxObjVisible); } void Gfx::freeLabels() { - for (uint i = 0; i < _numLabels; i++) { + for (uint i = 0; i < _labels.size(); i++) { delete _labels[i]; } - _numLabels = 0; -} - - -void Gfx::setFloatingLabel(Label *label) { - _floatingLabel = label; - - if (_floatingLabel) { - _floatingLabel->resetPosition(); - } -} - -void Gfx::updateFloatingLabel() { - if (!_floatingLabel) { - return; - } - - int16 _si, _di; - - Common::Point cursor; - _vm->_input->getCursorPos(cursor); - - if (_vm->_input->_activeItem._id != 0) { - _si = cursor.x + 16 - _floatingLabel->_cnv.w/2; - _di = cursor.y + 34; - } else { - _si = cursor.x + 8 - _floatingLabel->_cnv.w/2; - _di = cursor.y + 21; - } - - if (_si < 0) _si = 0; - if (_di > 190) _di = 190; - - if (_floatingLabel->_cnv.w + _si > _vm->_screenWidth) - _si = _vm->_screenWidth - _floatingLabel->_cnv.w; - - _floatingLabel->_pos.x = _si; - _floatingLabel->_pos.y = _di; + _labels.clear(); } void Gfx::drawLabels() { - if ((!_floatingLabel) && (_numLabels == 0)) { + if (_labels.size() == 0) { return; } + updateFloatingLabel(); Graphics::Surface* surf = g_system->lockScreen(); - for (uint i = 0; i < _numLabels; i++) { - if (_labels[i]->_visible) { - Common::Rect r(_labels[i]->_cnv.w, _labels[i]->_cnv.h); - r.moveTo(_labels[i]->_pos); - blt(r, (byte*)_labels[i]->_cnv.getBasePtr(0, 0), surf, LAYER_FOREGROUND, LABEL_TRANSPARENT_COLOR); - } - } - - if (_floatingLabel) { - Common::Rect r(_floatingLabel->_cnv.w, _floatingLabel->_cnv.h); - r.moveTo(_floatingLabel->_pos); - blt(r, (byte*)_floatingLabel->_cnv.getBasePtr(0, 0), surf, LAYER_FOREGROUND, LABEL_TRANSPARENT_COLOR); + for (uint i = 0; i < _labels.size(); i++) { + drawGfxObject(_labels[i], *surf, false); } g_system->unlockScreen(); } -Label::Label() { - resetPosition(); - _visible = false; -} - -Label::~Label() { - free(); -} - -void Label::free() { - _cnv.free(); - resetPosition(); -} - -void Label::resetPosition() { - _pos.x = -1000; - _pos.y = -1000; -} - void Gfx::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) { @@ -790,8 +781,7 @@ Gfx::Gfx(Parallaction* vm) : _numBalloons = 0; _numItems = 0; - _numLabels = 0; - _floatingLabel = 0; + _floatingLabel = NO_FLOATING_LABEL; _screenX = 0; _screenY = 0; @@ -826,8 +816,8 @@ int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) { _items[id].data = frames; _items[id].data->x = x; _items[id].data->y = y; - - _items[id].transparentColor = transparentColor; + _items[id].data->layer = LAYER_FOREGROUND; + _items[id].data->transparentKey = transparentColor; _numItems++; @@ -837,6 +827,7 @@ int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) { void Gfx::setItemFrame(uint item, uint16 f) { assert(item < _numItems); _items[item].data->frame = f; + _items[item].data->setFlags(kGfxObjVisible); } Gfx::Balloon* Gfx::getBalloon(uint id) { diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 17869de432..df4cab4caf 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -326,20 +326,6 @@ public: #define CENTER_LABEL_HORIZONTAL -1 #define CENTER_LABEL_VERTICAL -1 -struct Label { - Graphics::Surface _cnv; - - Common::Point _pos; - bool _visible; - - Label(); - ~Label(); - - void free(); - void resetPosition(); -}; - - #define MAX_BALLOON_WIDTH 130 @@ -357,7 +343,8 @@ enum { kGfxObjTypeDoor = 0, kGfxObjTypeGet = 1, - kGfxObjTypeAnim = 2 + kGfxObjTypeAnim = 2, + kGfxObjTypeLabel = 3 }; enum { @@ -381,6 +368,7 @@ public: uint type; uint frame; uint layer; + uint transparentKey; GfxObj(uint type, Frames *frames, const char *name = NULL); virtual ~GfxObj(); @@ -478,9 +466,12 @@ public: void clearGfxObjects(); void sortAnimations(); + // labels - void setFloatingLabel(Label *label); - Label *renderFloatingLabel(Font *font, char *text); + void showFloatingLabel(uint label); + void hideFloatingLabel(); + + uint renderFloatingLabel(Font *font, char *text); uint createLabel(Font *font, const char *text, byte color); void showLabel(uint id, int16 x, int16 y); void hideLabel(uint id); @@ -572,19 +563,18 @@ public: uint _numBalloons; struct Item { - uint16 frame; GfxObj *data; - - byte transparentColor; - Common::Rect rect; } _items[14]; uint _numItems; - #define MAX_NUM_LABELS 5 - Label* _labels[MAX_NUM_LABELS]; - uint _numLabels; - Label *_floatingLabel; + #define MAX_NUM_LABELS 20 + #define NO_FLOATING_LABEL 1000 + + typedef Common::Array GfxObjArray; + GfxObjArray _labels; + + uint _floatingLabel; void drawInventory(); void updateFloatingLabel(); @@ -601,6 +591,7 @@ public: void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); + void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene); void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor); }; diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 46dbb08c4e..e06fe96705 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -44,7 +44,7 @@ struct InputData { Common::Point _mousePos; int16 _inventoryIndex; ZonePtr _zone; - Label* _label; + uint _label; }; class Input { diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index 5b5aa85584..54afabc318 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -182,7 +182,6 @@ Zone::~Zone() { break; } - delete _label; } void Zone::getRect(Common::Rect& r) const { diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index 44ad35e0ab..19835da9d0 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -287,7 +287,7 @@ struct Zone { int16 _bottom; uint32 _type; uint32 _flags; - Label *_label; + uint _label; uint16 field_2C; // unused uint16 field_2E; // unused TypeData u; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 4f586961a6..5f5cfdb820 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -290,12 +290,12 @@ void Parallaction::processInput(InputData *data) { switch (data->_event) { case kEvEnterZone: debugC(2, kDebugInput, "processInput: kEvEnterZone"); - _gfx->setFloatingLabel(data->_label); + _gfx->showFloatingLabel(data->_label); break; case kEvExitZone: debugC(2, kDebugInput, "processInput: kEvExitZone"); - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); break; case kEvAction: @@ -308,7 +308,7 @@ void Parallaction::processInput(InputData *data) { case kEvOpenInventory: _input->stopHovering(); - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { setArrowCursor(); } diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 59b9465d0a..af848aa6af 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -187,7 +187,7 @@ void Parallaction_ns::setArrowCursor() { debugC(1, kDebugInput, "setting mouse cursor to arrow"); // this stuff is needed to avoid artifacts with labels and selected items when switching cursors - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); _input->_activeItem._id = 0; _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); @@ -298,7 +298,7 @@ void Parallaction_ns::changeLocation(char *location) { _soundMan->playLocationMusic(location); - _gfx->setFloatingLabel(0); + _gfx->hideFloatingLabel(); _gfx->freeLabels(); _input->stopHovering(); -- cgit v1.2.3 From 18559708c620b82f05c490e0ff118a02611730dd Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 2 Jul 2008 04:31:50 +0000 Subject: Fully implemented processSeqListElement - Added parts that were missing and fixed a couple of errors -- One test was backwards and a global variable was written to when it shouldn't have been Added global variable inputVar0 that's used in processSeqListElement NOTE: inputVar0 isn't updated anywhere yet, so that's a TODO svn-id: r32874 --- engines/cine/various.cpp | 60 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 18 deletions(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 0439856e5c..4b5d4efe13 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -95,6 +95,9 @@ int16 saveVar2; byte isInPause = 0; +// TODO: Implement inputVar0's changes in the program +// Currently inputVar0 isn't updated anywhere even though it's used at least in processSeqListElement. +uint16 inputVar0 = 0; byte inputVar1 = 0; uint16 inputVar2 = 0, inputVar3 = 0; @@ -1683,8 +1686,7 @@ uint16 computeMove2(SeqListElement &element) { return returnVar; } -uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptrByte, SeqListElement &element, uint16 param3, int16 *param4) { - const int8 *ptr = (const int8 *)ptrByte; +uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &element, uint16 param3, int16 *param4) { const int8 *ptrData; const int8 *ptr2; int16 di; @@ -1790,7 +1792,7 @@ void resetGfxEntityEntry(uint16 objIdx) { void processSeqListElement(SeqListElement &element) { int16 x = objectTable[element.objIdx].x; int16 y = objectTable[element.objIdx].y; - const byte *ptr1 = animDataTable[element.frame].data(); + const int8 *ptr1 = (const int8 *) animDataTable[element.frame].data(); int16 var_10; int16 var_4; int16 var_2; @@ -1803,22 +1805,44 @@ void processSeqListElement(SeqListElement &element) { element.var12 = 0; if (ptr1) { - uint16 param1 = ptr1[1]; - uint16 param2 = ptr1[2]; + int16 param1 = ptr1[1]; + int16 param2 = ptr1[2]; if (element.varC != 255) { - // FIXME: Why is this here? Fingolfin gets lots of these - // in his copy of Operation Stealth (value 0 or 236) under - // Mac OS X. Maybe it's a endian issue? At least the graphics - // in the copy protection screen are partially messed up. - warning("processSeqListElement: varC = %d", element.varC); - } - - if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) { - computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]); + int16 x2 = element.var18; + int16 y2 = element.var1A; + if (element.varC) { + x2 += objectTable[element.varC].x; + y2 += objectTable[element.varC].y; + } + computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, x2, y2); } else { - element.var16 = 0; - element.var14 = 0; + if (inputVar0 && allowPlayerInput) { + int16 adder = param1 + 1; + if (inputVar0 != 1) { + adder = -adder; + } + // FIXME: In Operation Stealth's disassembly global variable 251 is used here + // but it's named as VAR_MOUSE_Y_MODE in ScummVM. Is it correct or a + // left over from Future Wars's reverse engineering? + globalVars[VAR_MOUSE_X_POS] = globalVars[251] = ptr1[4] + x + adder; + } + + if (inputVar1 && allowPlayerInput) { + int16 adder = param2 + 1; + if (inputVar1 != 1) { + adder = -adder; + } + // TODO: Name currently unnamed global variable 252 + globalVars[VAR_MOUSE_Y_POS] = globalVars[252] = ptr1[5] + y + adder; + } + + if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) { + computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]); + } else { + element.var16 = 0; + element.var14 = 0; + } } var_10 = computeMove2(element); @@ -1859,14 +1883,14 @@ void processSeqListElement(SeqListElement &element) { } } - if (element.var16 + element.var14) { + if (element.var16 + element.var14 == 0) { if (element.var1C) { if (element.var1E) { objectTable[element.objIdx].costume = 0; element.var1E = 0; } - addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, (int16 *) & var2); + addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, &var_2); } } -- cgit v1.2.3 From de09845319f43f6bad3582af5d570de43c7f9632 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Thu, 3 Jul 2008 08:44:29 +0000 Subject: Fix for bug #2008054: Parallaction engine doesn't compile under MSVC9 svn-id: r32879 --- engines/parallaction/parser_br.cpp | 2 +- engines/parallaction/parser_ns.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 51da7eb396..defc917a72 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -390,7 +390,7 @@ DECLARE_LOCATION_PARSER(flags) { if ((_vm->getLocationFlags() & kFlagsVisited) == 0) { // only for 1st visit - _vm->clearLocationFlags(kFlagsAll); + _vm->clearLocationFlags((uint32)kFlagsAll); int _si = 1; do { diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index c654e3008e..2f4d2df776 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1059,7 +1059,7 @@ DECLARE_LOCATION_PARSER(flags) { if ((_vm->getLocationFlags() & kFlagsVisited) == 0) { // only for 1st visit - _vm->clearLocationFlags(kFlagsAll); + _vm->clearLocationFlags((uint32)kFlagsAll); int _si = 1; do { -- cgit v1.2.3 From 59e672ef40e4c227c27022ec764f8b811b375220 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 3 Jul 2008 10:31:25 +0000 Subject: Changed balloons to use GfxObj as well. Next step is to integrate balloons for BRA. svn-id: r32883 --- engines/parallaction/disk.h | 10 ++--- engines/parallaction/disk_br.cpp | 8 ++-- engines/parallaction/disk_ns.cpp | 8 ++-- engines/parallaction/gfxbase.cpp | 12 ++++-- engines/parallaction/graphics.cpp | 85 +++++++++++++++++++++++++-------------- engines/parallaction/graphics.h | 13 +++--- 6 files changed, 82 insertions(+), 54 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 176f10aa10..694d4efa6d 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -61,7 +61,7 @@ public: virtual GfxObj* loadHead(const char* name) = 0; virtual Font* loadFont(const char* name) = 0; virtual GfxObj* loadStatic(const char* name) = 0; - virtual GfxObj* loadFrames(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; @@ -153,7 +153,7 @@ public: GfxObj* loadHead(const char* name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(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); @@ -187,7 +187,7 @@ public: GfxObj* loadHead(const char* name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(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); @@ -226,7 +226,7 @@ public: GfxObj* loadHead(const char* name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(const char* name); + Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); Table* loadTable(const char* name); @@ -251,7 +251,7 @@ public: GfxObj* loadTalk(const char *name); Font* loadFont(const char* name); GfxObj* loadStatic(const char* name); - GfxObj* loadFrames(const char* name); + Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); }; diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 0159d9d406..543ed14146 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -280,7 +280,7 @@ Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) { return sprites; } -GfxObj* DosDisk_br::loadFrames(const char* name) { +Frames* DosDisk_br::loadFrames(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); char path[PATH_LEN]; @@ -291,7 +291,7 @@ GfxObj* DosDisk_br::loadFrames(const char* name) { errorFileNotFound(path); - return new GfxObj(0, createSprites(stream), name); + return createSprites(stream); } // Slides in Nippon Safes are basically screen-sized pictures with valid @@ -600,13 +600,13 @@ Sprites* AmigaDisk_br::createSprites(const char *path) { return sprites; } -GfxObj* AmigaDisk_br::loadFrames(const char* name) { +Frames* AmigaDisk_br::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name); char path[PATH_LEN]; sprintf(path, "%s/anims/%s", _partPath, name); - return new GfxObj(0, createSprites(path)); + return createSprites(path); } GfxObj* AmigaDisk_br::loadTalk(const char *name) { diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index f45cf83f56..55e6fc5e77 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -490,8 +490,8 @@ GfxObj* DosDisk_ns::loadStatic(const char* name) { return new GfxObj(0, new SurfaceToFrames(cnv), name); } -GfxObj* DosDisk_ns::loadFrames(const char* name) { - return new GfxObj(0, loadCnv(name), name); +Frames* DosDisk_ns::loadFrames(const char* name) { + return loadCnv(name); } // @@ -1258,7 +1258,7 @@ void AmigaDisk_ns::loadSlide(BackgroundInfo& info, const char *name) { return; } -GfxObj* AmigaDisk_ns::loadFrames(const char* name) { +Frames* AmigaDisk_ns::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_ns::loadFrames '%s'", name); Common::SeekableReadStream *s; @@ -1273,7 +1273,7 @@ GfxObj* AmigaDisk_ns::loadFrames(const char* name) { Cnv *cnv = makeCnv(*s); delete s; - return new GfxObj(0, cnv, name); + return cnv; } GfxObj* AmigaDisk_ns::loadHead(const char* name) { diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 383f5d549c..8d7041305d 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -86,12 +86,14 @@ void GfxObj::clearFlags(uint32 flags) { } GfxObj* Gfx::loadAnim(const char *name) { - GfxObj *obj = _disk->loadFrames(name); + Frames* frames = _disk->loadFrames(name); + assert(frames); + + GfxObj *obj = new GfxObj(kGfxObjTypeAnim, frames, name); assert(obj); // animation Z is not set here, but controlled by game scripts and user interaction. // it is always >=0 and type = kGfxObjTypeAnim; obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; @@ -110,11 +112,13 @@ GfxObj* Gfx::loadGet(const char *name) { } GfxObj* Gfx::loadDoor(const char *name) { - GfxObj *obj = _disk->loadFrames(name); + Frames *frames = _disk->loadFrames(name); + assert(frames); + + GfxObj *obj = new GfxObj(kGfxObjTypeDoor, frames, name); assert(obj); obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first - obj->type = kGfxObjTypeDoor; obj->transparentKey = 0; _gfxobjList.push_back(obj); return obj; diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 838827b19f..24c78d1703 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -362,15 +362,13 @@ void Gfx::drawItems() { } void Gfx::drawBalloons() { - if (_numBalloons == 0) { + if (_balloons.size() == 0) { return; } Graphics::Surface *surf = g_system->lockScreen(); - for (uint i = 0; i < _numBalloons; i++) { - Common::Rect r(_balloons[i].surface.w, _balloons[i].surface.h); - r.moveTo(_balloons[i].x, _balloons[i].y); - blt(r, (byte*)_balloons[i].surface.getBasePtr(0, 0), surf, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR); + for (uint i = 0; i < _balloons.size(); i++) { + drawGfxObject(_balloons[i], *surf, false); } g_system->unlockScreen(); } @@ -832,7 +830,7 @@ void Gfx::setItemFrame(uint item, uint16 f) { Gfx::Balloon* Gfx::getBalloon(uint id) { assert(id < _numBalloons); - return &_balloons[id]; + return &_intBalloons[id]; } int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) { @@ -840,18 +838,19 @@ int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) int id = _numBalloons; - Gfx::Balloon *balloon = &_balloons[id]; + Gfx::Balloon *balloon = &_intBalloons[id]; int16 real_h = (winding == -1) ? h : h + 9; - balloon->surface.create(w, real_h, 1); - balloon->surface.fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR); + balloon->surface = new Graphics::Surface; + balloon->surface->create(w, real_h, 1); + balloon->surface->fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR); Common::Rect r(w, h); - balloon->surface.fillRect(r, 0); + balloon->surface->fillRect(r, 0); balloon->outerBox = r; r.grow(-borderThickness); - balloon->surface.fillRect(r, 1); + balloon->surface->fillRect(r, 1); balloon->innerBox = r; if (winding != -1) { @@ -860,7 +859,7 @@ int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) winding = (winding == 0 ? 1 : 0); Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); s.moveTo(r.width()/2 - 5, r.bottom - 1); - blt(s, _resBalloonTail[winding], &balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR); + blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR); } _numBalloons++; @@ -868,6 +867,20 @@ int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) return id; } +GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) { + + GfxObj *obj = new GfxObj(kGfxObjTypeBalloon, frames, text); + + obj->layer = LAYER_FOREGROUND; + obj->frame = 0; + obj->transparentKey = BALLOON_TRANSPARENT_COLOR; + obj->setFlags(kGfxObjVisible); + + _balloons.push_back(obj); + + return obj; +} + int Gfx::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { int16 w, h; @@ -875,12 +888,14 @@ int Gfx::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte t getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); int id = createBalloon(w+5, h, winding, 1); - Gfx::Balloon *balloon = &_balloons[id]; + Gfx::Balloon *balloon = &_intBalloons[id]; - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); - balloon->x = x; - balloon->y = y; + // TODO: extract some text to make a name for obj + balloon->obj = registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = x; + balloon->obj->y = y; return id; } @@ -892,15 +907,17 @@ int Gfx::setDialogueBalloon(char *text, uint16 winding, byte textColor) { getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); int id = createBalloon(w+5, h, winding, 1); - Gfx::Balloon *balloon = &_balloons[id]; + Gfx::Balloon *balloon = &_intBalloons[id]; - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); - balloon->x = _dialogueBalloonX[id]; - balloon->y = 10; + // TODO: extract some text to make a name for obj + balloon->obj = registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = _dialogueBalloonX[id]; + balloon->obj->y = 10; if (id > 0) { - balloon->y += _balloons[id - 1].y + _balloons[id - 1].outerBox.height(); + balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].outerBox.height(); } @@ -909,8 +926,8 @@ int Gfx::setDialogueBalloon(char *text, uint16 winding, byte textColor) { void Gfx::setBalloonText(uint id, char *text, byte textColor) { Gfx::Balloon *balloon = getBalloon(id); - balloon->surface.fillRect(balloon->innerBox, 1); - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + balloon->surface->fillRect(balloon->innerBox, 1); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); } @@ -921,11 +938,13 @@ int Gfx::setLocationBalloon(char *text, bool endGame) { getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); - Gfx::Balloon *balloon = &_balloons[id]; - drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, 0, MAX_BALLOON_WIDTH); + Gfx::Balloon *balloon = &_intBalloons[id]; + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); - balloon->x = 5; - balloon->y = 5; + // TODO: extract some text to make a name for obj + balloon->obj = registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 5; + balloon->obj->y = 5; return id; } @@ -935,10 +954,10 @@ int Gfx::hitTestDialogueBalloon(int x, int y) { Common::Point p; for (uint i = 0; i < _numBalloons; i++) { - p.x = x - _balloons[i].x; - p.y = y - _balloons[i].y; + p.x = x - _intBalloons[i].obj->x; + p.y = y - _intBalloons[i].obj->y; - if (_balloons[i].innerBox.contains(p)) + if (_intBalloons[i].innerBox.contains(p)) return i; } @@ -947,8 +966,12 @@ int Gfx::hitTestDialogueBalloon(int x, int y) { void Gfx::freeBalloons() { + _balloons.clear(); + for (uint i = 0; i < _numBalloons; i++) { - _balloons[i].surface.free(); + delete _intBalloons[i].obj; + _intBalloons[i].obj = 0; + _intBalloons[i].surface = 0; // no need to delete surface, since it is done by obj (GfxObj) } _numBalloons = 0; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index df4cab4caf..b15da432d9 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -344,7 +344,8 @@ enum { kGfxObjTypeDoor = 0, kGfxObjTypeGet = 1, kGfxObjTypeAnim = 2, - kGfxObjTypeLabel = 3 + kGfxObjTypeLabel = 3, + kGfxObjTypeBalloon = 4 }; enum { @@ -484,6 +485,7 @@ public: void setBalloonText(uint id, char *text, byte textColor); int hitTestDialogueBalloon(int x, int y); void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height); + GfxObj* registerBalloon(Frames *frames, const char *text); // other items int setItem(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0); @@ -552,13 +554,11 @@ public: static int16 _dialogueBalloonX[5]; struct Balloon { - uint16 x; - uint16 y; Common::Rect outerBox; Common::Rect innerBox; - uint16 winding; - Graphics::Surface surface; - } _balloons[5]; + Graphics::Surface *surface; + GfxObj *obj; + } _intBalloons[5]; uint _numBalloons; @@ -573,6 +573,7 @@ public: typedef Common::Array GfxObjArray; GfxObjArray _labels; + GfxObjArray _balloons; uint _floatingLabel; -- cgit v1.2.3 From 56c6840ff72ab38a508aa0f46662ef7c636e410f Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 3 Jul 2008 16:25:59 +0000 Subject: Fixing a crash when loading a save made within the cult/bargon building (bug #2005965) svn-id: r32895 --- engines/gob/goblin_v2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp index 9144e35070..d763aeb01c 100644 --- a/engines/gob/goblin_v2.cpp +++ b/engines/gob/goblin_v2.cpp @@ -88,7 +88,7 @@ void Goblin_v2::placeObject(Gob_Object *objDesc, char animated, (_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (y + 1) / 2; *obj->pPosX = x * _vm->_map->_tilesWidth; } else { - if (obj->goblinStates[state] != 0) { + if ((obj->goblinStates != 0) && (obj->goblinStates[state] != 0)) { layer = obj->goblinStates[state][0].layer; animation = obj->goblinStates[state][0].animation; objAnim->state = state; -- cgit v1.2.3 From d92085b5071b0bb62642d62857e5853006be3b2c Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Thu, 3 Jul 2008 21:09:07 +0000 Subject: minor fix for Towns/PC98 music svn-id: r32899 --- engines/kyra/sequences_lok.cpp | 2 +- engines/kyra/sound_lok.cpp | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index b30568c7e2..3a497a258f 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -1083,7 +1083,7 @@ void KyraEngine_LoK::seq_playCredits() { _screen->_charWidth = -1; // we only need this for the fm-towns version - if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) + if (_flags.platform == Common::kPlatformFMTowns && _configMusic == 1) snd_playWanderScoreViaMap(53, 1); uint8 *buffer = 0; diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp index 7d6e1dd378..b43d72ebce 100644 --- a/engines/kyra/sound_lok.cpp +++ b/engines/kyra/sound_lok.cpp @@ -49,20 +49,23 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) { } else if (command >= 35 && command <= 38) { snd_playSoundEffect(command-20); } else if (command >= 2) { - if (_lastMusicCommand != command) { + if (_lastMusicCommand != command) // the original does -2 here we handle this inside _sound->playTrack() _sound->playTrack(command); - } } else { _sound->haltTrack(); } + _lastMusicCommand = command; } else if (_flags.platform == Common::kPlatformPC98) { - if (command == 1) + if (command == 1) { _sound->beginFadeOut(); - else if (command >= 2) - _sound->playTrack(command); - else + } else if (command >= 2) { + if (_lastMusicCommand != command) + _sound->playTrack(command); + } else { _sound->haltTrack(); + } + _lastMusicCommand = command; } else { KyraEngine_v1::snd_playWanderScoreViaMap(command, restart); } -- cgit v1.2.3 From d387d1af0ec869700da199578f07e5a0c00968f3 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 4 Jul 2008 00:29:21 +0000 Subject: - Moved dialogue balloon management code from Gfx to its own class - Added a class to draw balloons in BRA (still without text and with wrong placement) svn-id: r32902 --- engines/parallaction/balloons.cpp | 456 +++++++++++++++++++++++++++++++ engines/parallaction/callables_ns.cpp | 2 +- engines/parallaction/dialogue.cpp | 24 +- engines/parallaction/exec_br.cpp | 9 +- engines/parallaction/exec_ns.cpp | 4 +- engines/parallaction/graphics.cpp | 174 +----------- engines/parallaction/graphics.h | 33 +-- engines/parallaction/gui_br.cpp | 2 +- engines/parallaction/input.cpp | 2 +- engines/parallaction/module.mk | 1 + engines/parallaction/parallaction.cpp | 6 +- engines/parallaction/parallaction.h | 9 + engines/parallaction/parallaction_br.cpp | 3 + 13 files changed, 515 insertions(+), 210 deletions(-) create mode 100644 engines/parallaction/balloons.cpp (limited to 'engines') diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp new file mode 100644 index 0000000000..fab92dada9 --- /dev/null +++ b/engines/parallaction/balloons.cpp @@ -0,0 +1,456 @@ +/* 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 "parallaction/graphics.h" +#include "parallaction/parallaction.h" + +namespace Parallaction { + + +#define BALLOON_TRANSPARENT_COLOR_NS 2 +#define BALLOON_TRANSPARENT_COLOR_BR 0 + +#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, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + }, + { + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02 + } +}; + +class BalloonManager_ns : public BalloonManager { + + static int16 _dialogueBalloonX[5]; + + struct Balloon { + Common::Rect outerBox; + Common::Rect innerBox; + Graphics::Surface *surface; + GfxObj *obj; + } _intBalloons[5]; + + uint _numBalloons; + + void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); + int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); + Balloon *getBalloon(uint id); + + Gfx *_gfx; + +public: + BalloonManager_ns(Gfx *gfx); + ~BalloonManager_ns(); + + void freeBalloons(); + int setLocationBalloon(char *text, bool endGame); + int setDialogueBalloon(char *text, uint16 winding, byte textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); + void setBalloonText(uint id, char *text, byte textColor); + int hitTestDialogueBalloon(int x, int y); +}; + +int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 }; + +BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) { + +} + +BalloonManager_ns::~BalloonManager_ns() { + +} + + +BalloonManager_ns::Balloon* BalloonManager_ns::getBalloon(uint id) { + assert(id < _numBalloons); + return &_intBalloons[id]; +} + +int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) { + assert(_numBalloons < 5); + + int id = _numBalloons; + + Balloon *balloon = &_intBalloons[id]; + + int16 real_h = (winding == -1) ? h : h + 9; + balloon->surface = new Graphics::Surface; + balloon->surface->create(w, real_h, 1); + balloon->surface->fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR_NS); + + Common::Rect r(w, h); + balloon->surface->fillRect(r, 0); + balloon->outerBox = r; + + r.grow(-borderThickness); + balloon->surface->fillRect(r, 1); + balloon->innerBox = r; + + if (winding != -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); + Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); + s.moveTo(r.width()/2 - 5, r.bottom - 1); + _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS); + } + + _numBalloons++; + + return id; +} + + +int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { + + int16 w, h; + + _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+5, h, winding, 1); + Balloon *balloon = &_intBalloons[id]; + + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = x; + balloon->obj->y = y; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS; + + return id; +} + +int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) { + + int16 w, h; + + _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+5, h, winding, 1); + Balloon *balloon = &_intBalloons[id]; + + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = _dialogueBalloonX[id]; + balloon->obj->y = 10; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS; + + if (id > 0) { + balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].outerBox.height(); + } + + + return id; +} + +void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) { + Balloon *balloon = getBalloon(id); + balloon->surface->fillRect(balloon->innerBox, 1); + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); +} + + +int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) { + + int16 w, h; + + _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS); + Balloon *balloon = &_intBalloons[id]; + _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 5; + balloon->obj->y = 5; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS; + + return id; +} + +int BalloonManager_ns::hitTestDialogueBalloon(int x, int y) { + + Common::Point p; + + for (uint i = 0; i < _numBalloons; i++) { + p.x = x - _intBalloons[i].obj->x; + p.y = y - _intBalloons[i].obj->y; + + if (_intBalloons[i].innerBox.contains(p)) + return i; + } + + return -1; +} + +void BalloonManager_ns::freeBalloons() { + _gfx->destroyBalloons(); + + for (uint i = 0; i < _numBalloons; i++) { + _intBalloons[i].obj = 0; + _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons + } + + _numBalloons = 0; +} + + + + + + + + +class BalloonManager_br : public BalloonManager { + + struct Balloon { + Common::Rect box; + Graphics::Surface *surface; + GfxObj *obj; + } _intBalloons[3]; + + uint _numBalloons; + + Frames *_leftBalloon; + Frames *_rightBalloon; + Disk *_disk; + Gfx *_gfx; + + void cacheAnims(); + void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); + int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); + Balloon *getBalloon(uint id); + Graphics::Surface *expandBalloon(Frames *data, int frameNum); + + +public: + BalloonManager_br(Disk *disk, Gfx *gfx); + ~BalloonManager_br(); + + void freeBalloons(); + int setLocationBalloon(char *text, bool endGame); + int setDialogueBalloon(char *text, uint16 winding, byte textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); + void setBalloonText(uint id, char *text, byte textColor); + int hitTestDialogueBalloon(int x, int y); +}; + + + +BalloonManager_br::Balloon* BalloonManager_br::getBalloon(uint id) { + assert(id < _numBalloons); + return &_intBalloons[id]; +} + +Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum) { + + Common::Rect rect; + data->getRect(frameNum, rect); + + rect.translate(-rect.left, -rect.top); + + Graphics::Surface *surf = new Graphics::Surface; + surf->create(rect.width(), rect.height(), 1); + + _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR); + + return surf; +} + +int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { + cacheAnims(); + + int id = _numBalloons; + Frames *src = 0; + int srcFrame = 0; + + Balloon *balloon = &_intBalloons[id]; + + if (winding == 0) { + src = _leftBalloon; + srcFrame = 0; + } else + if (winding == 1) { + src = _rightBalloon; + srcFrame = 0; + } + + assert(src); + + balloon->surface = expandBalloon(src, srcFrame); + src->getRect(srcFrame, balloon->box); + +// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = x; + balloon->obj->y = y; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; + + _numBalloons++; + + return id; +} + +int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) { + cacheAnims(); + + int id = _numBalloons; + Frames *src = 0; + int srcFrame = 0; + + Balloon *balloon = &_intBalloons[id]; + + if (winding == 0) { + src = _leftBalloon; + srcFrame = id; + } else + if (winding == 1) { + src = _rightBalloon; + srcFrame = 0; + } + + assert(src); + + balloon->surface = expandBalloon(src, srcFrame); + src->getRect(srcFrame, balloon->box); + +// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 0; + balloon->obj->y = 10; + balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; + + if (id > 0) { + balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height(); + } + + _numBalloons++; + + return id; +} + +void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { } + +int BalloonManager_br::setLocationBalloon(char *text, bool endGame) { +/* + int16 w, h; + + getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + + int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); + Balloon *balloon = &_intBalloons[id]; + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); + + // TODO: extract some text to make a name for obj + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); + balloon->obj->x = 5; + balloon->obj->y = 5; +*/ + return 0; +} + +int BalloonManager_br::hitTestDialogueBalloon(int x, int y) { + + Common::Point p; + + for (uint i = 0; i < _numBalloons; i++) { + p.x = x - _intBalloons[i].obj->x; + p.y = y - _intBalloons[i].obj->y; + + if (_intBalloons[i].box.contains(p)) + return i; + } + + return -1; +} + +void BalloonManager_br::freeBalloons() { + _gfx->destroyBalloons(); + + for (uint i = 0; i < _numBalloons; i++) { + _intBalloons[i].obj = 0; + _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons + } + + _numBalloons = 0; +} + +void BalloonManager_br::cacheAnims() { + if (!_leftBalloon) { + _leftBalloon = _disk->loadFrames("fumetto.ani"); + _rightBalloon = _disk->loadFrames("fumdx.ani"); + } +} + +BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) { +} + +BalloonManager_br::~BalloonManager_br() { + delete _leftBalloon; + delete _rightBalloon; +} + +void Parallaction::setupBalloonManager() { + if (_vm->getGameType() == GType_Nippon) { + _balloonMan = new BalloonManager_ns(_vm->_gfx); + } else + if (_vm->getGameType() == GType_BRA) { + _balloonMan = new BalloonManager_br(_vm->_disk, _vm->_gfx); + } else { + error("Unknown game type"); + } +} + +} // namespace Parallaction diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 3ecc7a9534..7c053715f6 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -341,7 +341,7 @@ void Parallaction_ns::_c_endComment(void *param) { } _input->waitUntilLeftClick(); - _gfx->freeBalloons(); + _balloonMan->freeBalloons(); return; } diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 3b6c35d3bb..1dc4fd5ab3 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -93,7 +93,7 @@ uint16 DialogueManager::askPassword() { uint16 passwordLen = 0; _password[0] = '\0'; - _vm->_gfx->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); + _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); _vm->_gfx->setItemFrame(id, 0); @@ -118,7 +118,7 @@ uint16 DialogueManager::askPassword() { } if (changed) { - _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 3); + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); _vm->_gfx->updateScreen(); changed = false; } @@ -143,7 +143,7 @@ uint16 DialogueManager::askPassword() { } - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return 0; @@ -162,7 +162,7 @@ bool DialogueManager::displayAnswer(uint16 i) { // display suitable answers if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) { - int id = _vm->_gfx->setDialogueBalloon(a->_text, 1, 3); + int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3); assert(id >= 0); _visAnswers[id] = i; @@ -190,13 +190,13 @@ void DialogueManager::displayQuestion() { if (!scumm_stricmp(_q->_text, "NULL")) return; - _vm->_gfx->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); + _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); _vm->_gfx->updateScreen(); _vm->_input->waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return; } @@ -261,9 +261,9 @@ int16 DialogueManager::selectAnswer() { _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); if (numAvailableAnswers == 1) { - _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 0); + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 0); _vm->_input->waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return 0; } @@ -277,15 +277,15 @@ int16 DialogueManager::selectAnswer() { _vm->_input->readInput(); _vm->_input->getCursorPos(p); event = _vm->_input->getLastButtonEvent(); - selection = _vm->_gfx->hitTestDialogueBalloon(p.x, p.y); + selection = _vm->_balloonMan->hitTestDialogueBalloon(p.x, p.y); if (selection != oldSelection) { if (oldSelection != -1) { - _vm->_gfx->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); + _vm->_balloonMan->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); } if (selection != -1) { - _vm->_gfx->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); + _vm->_balloonMan->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF); } } @@ -300,7 +300,7 @@ int16 DialogueManager::selectAnswer() { oldSelection = selection; } - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); return _visAnswers[selection]; } diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 348af2b731..734360167b 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -100,8 +100,13 @@ void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { } void Parallaction_br::clearSubtitles() { - _gfx->hideLabel(_subtitle[0]); - _gfx->hideLabel(_subtitle[1]); + if (_subtitle[0] != -1) { + _gfx->hideLabel(_subtitle[0]); + } + + if (_subtitle[1] != -1) { + _gfx->hideLabel(_subtitle[1]); + } } diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index bd2d54c0a0..abad9f273b 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -469,7 +469,7 @@ void Parallaction::displayComment(ExamineData *data) { } _gfx->setHalfbriteMode(true); - _gfx->setSingleBalloon(data->_description, 0, 90, 0, 0); + _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); Common::Rect r; data->_cnv->getRect(0, r); id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); @@ -477,7 +477,7 @@ void Parallaction::displayComment(ExamineData *data) { id = _gfx->setItem(_char._head, 100, 152); _gfx->setItemFrame(id, 0); } else { - _gfx->setSingleBalloon(data->_description, 140, 10, 0, 0); + _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); id = _gfx->setItem(_char._talk, 190, 80); _gfx->setItemFrame(id, 0); } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 24c78d1703..f839f88778 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -64,10 +64,6 @@ int32 Gfx::getVar(const Common::String &name) { #define LABEL_TRANSPARENT_COLOR 0xFF -#define BALLOON_TRANSPARENT_COLOR 2 - - -int16 Gfx::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 }; void halfbritePixel(int x, int y, int color, void *data) { byte *buffer = (byte*)data; @@ -238,37 +234,6 @@ void Palette::rotate(uint first, uint last, bool forward) { } -#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, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - }, - { - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02 - } -}; - void Gfx::setPalette(Palette pal) { byte sysPal[256*4]; @@ -777,7 +742,6 @@ Gfx::Gfx(Parallaction* vm) : setPalette(_palette); - _numBalloons = 0; _numItems = 0; _floatingLabel = NO_FLOATING_LABEL; @@ -828,44 +792,6 @@ void Gfx::setItemFrame(uint item, uint16 f) { _items[item].data->setFlags(kGfxObjVisible); } -Gfx::Balloon* Gfx::getBalloon(uint id) { - assert(id < _numBalloons); - return &_intBalloons[id]; -} - -int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) { - assert(_numBalloons < 5); - - int id = _numBalloons; - - Gfx::Balloon *balloon = &_intBalloons[id]; - - int16 real_h = (winding == -1) ? h : h + 9; - balloon->surface = new Graphics::Surface; - balloon->surface->create(w, real_h, 1); - balloon->surface->fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR); - - Common::Rect r(w, h); - balloon->surface->fillRect(r, 0); - balloon->outerBox = r; - - r.grow(-borderThickness); - balloon->surface->fillRect(r, 1); - balloon->innerBox = r; - - if (winding != -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); - Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); - s.moveTo(r.width()/2 - 5, r.bottom - 1); - blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR); - } - - _numBalloons++; - - return id; -} GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) { @@ -873,7 +799,6 @@ GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) { obj->layer = LAYER_FOREGROUND; obj->frame = 0; - obj->transparentKey = BALLOON_TRANSPARENT_COLOR; obj->setFlags(kGfxObjVisible); _balloons.push_back(obj); @@ -881,110 +806,17 @@ GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) { return obj; } -int Gfx::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { - - int16 w, h; - - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); - - int id = createBalloon(w+5, h, winding, 1); - Gfx::Balloon *balloon = &_intBalloons[id]; - - drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); - - // TODO: extract some text to make a name for obj - balloon->obj = registerBalloon(new SurfaceToFrames(balloon->surface), 0); - balloon->obj->x = x; - balloon->obj->y = y; - - return id; -} - -int Gfx::setDialogueBalloon(char *text, uint16 winding, byte textColor) { - - int16 w, h; - - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); - - int id = createBalloon(w+5, h, winding, 1); - Gfx::Balloon *balloon = &_intBalloons[id]; - - drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); - - // TODO: extract some text to make a name for obj - balloon->obj = registerBalloon(new SurfaceToFrames(balloon->surface), 0); - balloon->obj->x = _dialogueBalloonX[id]; - balloon->obj->y = 10; - - if (id > 0) { - balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].outerBox.height(); - } - - - return id; -} - -void Gfx::setBalloonText(uint id, char *text, byte textColor) { - Gfx::Balloon *balloon = getBalloon(id); - balloon->surface->fillRect(balloon->innerBox, 1); - drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); -} - - -int Gfx::setLocationBalloon(char *text, bool endGame) { - - int16 w, h; - - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); - - int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); - Gfx::Balloon *balloon = &_intBalloons[id]; - drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); - - // TODO: extract some text to make a name for obj - balloon->obj = registerBalloon(new SurfaceToFrames(balloon->surface), 0); - balloon->obj->x = 5; - balloon->obj->y = 5; - - return id; -} - -int Gfx::hitTestDialogueBalloon(int x, int y) { - - Common::Point p; - - for (uint i = 0; i < _numBalloons; i++) { - p.x = x - _intBalloons[i].obj->x; - p.y = y - _intBalloons[i].obj->y; - - if (_intBalloons[i].innerBox.contains(p)) - return i; +void Gfx::destroyBalloons() { + for (uint i = 0; i < _balloons.size(); i++) { + delete _balloons[i]; } - - return -1; -} - - -void Gfx::freeBalloons() { _balloons.clear(); - - for (uint i = 0; i < _numBalloons; i++) { - delete _intBalloons[i].obj; - _intBalloons[i].obj = 0; - _intBalloons[i].surface = 0; // no need to delete surface, since it is done by obj (GfxObj) - } - _numBalloons = 0; } void Gfx::freeItems() { _numItems = 0; } -void Gfx::hideDialogueStuff() { - freeItems(); - freeBalloons(); -} - void Gfx::freeBackground() { _backgroundInfo.free(); } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index b15da432d9..00718d8c26 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -450,6 +450,20 @@ enum { kBackgroundSlide = 2 }; + +class BalloonManager { +public: + virtual ~BalloonManager() { } + + virtual void freeBalloons() = 0; + virtual int setLocationBalloon(char *text, bool endGame) = 0; + virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0; + virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0; + virtual void setBalloonText(uint id, char *text, byte textColor) = 0; + virtual int hitTestDialogueBalloon(int x, int y) = 0; +}; + + typedef Common::HashMap VarMap; class Gfx { @@ -479,13 +493,9 @@ public: void freeLabels(); // dialogue balloons - int setLocationBalloon(char *text, bool endGame); - int setDialogueBalloon(char *text, uint16 winding, byte textColor); - int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); - void setBalloonText(uint id, char *text, byte textColor); - int hitTestDialogueBalloon(int x, int y); void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height); GfxObj* registerBalloon(Frames *frames, const char *text); + void destroyBalloons(); // other items int setItem(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0); @@ -551,16 +561,6 @@ protected: int32 getRenderMode(const char *type); public: - static int16 _dialogueBalloonX[5]; - - struct Balloon { - Common::Rect outerBox; - Common::Rect innerBox; - Graphics::Surface *surface; - GfxObj *obj; - } _intBalloons[5]; - - uint _numBalloons; struct Item { GfxObj *data; @@ -585,9 +585,6 @@ public: void copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst); - int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); - Balloon *getBalloon(uint id); - // low level text and patches void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 5551108693..0be070e345 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -195,7 +195,7 @@ int Parallaction_br::guiShowMenu() { } _system->showMouse(false); - _gfx->hideDialogueStuff(); + hideDialogueStuff(); for (i = 0; i < availItems; i++) { delete _lines[i]; diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index e758bbd41c..65acbcfe58 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -174,7 +174,7 @@ void Input::updateGameInput() { void Input::updateCommentInput() { waitUntilLeftClick(); - _vm->_gfx->hideDialogueStuff(); + _vm->hideDialogueStuff(); _vm->_gfx->setHalfbriteMode(false); _inputMode = kInputModeGame; diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index 2478b4b2e1..92c6ec5227 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -1,6 +1,7 @@ MODULE := engines/parallaction MODULE_OBJS := \ + balloons_o \ callables_br.o \ callables_ns.o \ debug.o \ diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 5f5cfdb820..3a52b28e06 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -134,6 +134,8 @@ int Parallaction::init() { _debugger = new Debugger(this); + setupBalloonManager(); + return 0; } @@ -281,7 +283,7 @@ void Parallaction::setBackground(const char* name, const char* mask, const char* } void Parallaction::showLocationComment(const char *text, bool end) { - _gfx->setLocationBalloon(const_cast(text), end); + _balloonMan->setLocationBalloon(const_cast(text), end); } @@ -422,7 +424,7 @@ void Parallaction::doLocationEnterTransition() { showLocationComment(_location._comment, false); _input->waitUntilLeftClick(); - _gfx->freeBalloons(); + _balloonMan->freeBalloons(); // fades maximum intensity palette towards approximation of main palette for (uint16 _si = 0; _si<6; _si++) { diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index b1a5995e28..c095cab667 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -429,6 +429,15 @@ public: Inventory *_inventory; InventoryRenderer *_inventoryRenderer; + BalloonManager *_balloonMan; + + void setupBalloonManager(); + + void hideDialogueStuff() { + _gfx->freeItems(); + _balloonMan->freeBalloons(); + } + }; diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index b22e1b0f2d..e7f08d0339 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -80,6 +80,9 @@ int Parallaction_br::init() { _part = -1; + _subtitle[0] = -1; + _subtitle[1] = -1; + Parallaction::init(); return 0; -- cgit v1.2.3 From 60db8cb8cf9b39b591fd5c9d0c754cbc3577b765 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Fri, 4 Jul 2008 00:35:39 +0000 Subject: Correct typo. svn-id: r32903 --- engines/parallaction/module.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index 92c6ec5227..fb867f5285 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -1,7 +1,7 @@ MODULE := engines/parallaction MODULE_OBJS := \ - balloons_o \ + balloons.o \ callables_br.o \ callables_ns.o \ debug.o \ -- cgit v1.2.3 From 357f0c4e3abc23e1a4c711191c1aeca0bfe47000 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 5 Jul 2008 07:47:27 +0000 Subject: Added spanish menu strings for spanish fan translation of Kyrandia 3. svn-id: r32911 --- engines/kyra/kyra_mr.cpp | 5 +++++ engines/kyra/kyra_mr.h | 4 +++- engines/kyra/staticres.cpp | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index b425c0929f..3d1b09561d 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -343,6 +343,11 @@ void KyraEngine_MR::initMainMenu() { 0x80, 0xFF }; + if (_flags.lang == Common::ES_ESP) { + for (int i = 0; i < 4; ++i) + data.strings[i] = _mainMenuSpanishFan[i]; + } + MainMenu::Animation anim; anim.anim = _menuAnim; anim.startFrame = 29; diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 5af138373c..aa103b167b 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -184,9 +184,11 @@ private: private: // main menu - const char *const *_mainMenuStrings; + const char * const *_mainMenuStrings; int _mainMenuStringsSize; + static const char * const _mainMenuSpanishFan[]; + // animator uint8 *_gamePlayBuffer; void restorePage3(); diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 5d094fa13f..a25fe4b295 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1980,6 +1980,13 @@ const char *KyraEngine_MR::_languageExtension[] = { "TRS"*/ }; +const char * const KyraEngine_MR::_mainMenuSpanishFan[] = { + "Nouvelle Partie", + "Ver Intro", + "Restaurar", + "Finalizar" +}; + const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension); const KyraEngine_MR::ShapeDesc KyraEngine_MR::_shapeDescs[] = { -- cgit v1.2.3 From 056288f87a2e5ad5251c81901320b2b14ca22443 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 5 Jul 2008 08:20:10 +0000 Subject: Added support for Italian fan translation of Kyrandia 3. (see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3") svn-id: r32912 --- engines/kyra/detection.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ engines/kyra/kyra_mr.cpp | 3 +++ engines/kyra/kyra_mr.h | 1 + engines/kyra/kyra_v1.cpp | 10 ++++++++-- engines/kyra/staticres.cpp | 7 +++++++ 5 files changed, 65 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index f55cd1ac5e..0c8acb59b7 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -654,6 +654,52 @@ const KYRAGameDescription adGameDescs[] = { KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY) }, + // Itlian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3" + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) + }, + { + { + "kyra3", + 0, + { + { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 }, + { "AUD.PAK", 0, 0, -1 }, + { 0, 0, 0, 0 } + }, + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) + }, { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } }; diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 3d1b09561d..a4e5b58364 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -346,6 +346,9 @@ void KyraEngine_MR::initMainMenu() { if (_flags.lang == Common::ES_ESP) { for (int i = 0; i < 4; ++i) data.strings[i] = _mainMenuSpanishFan[i]; + } else if (_flags.lang == Common::IT_ITA) { + for (int i = 0; i < 4; ++i) + data.strings[i] = _mainMenuItalianFan[i]; } MainMenu::Animation anim; diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index aa103b167b..5f9f6f91a3 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -188,6 +188,7 @@ private: int _mainMenuStringsSize; static const char * const _mainMenuSpanishFan[]; + static const char * const _mainMenuItalianFan[]; // animator uint8 *_gamePlayBuffer; diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index d2e0f37a60..117194aea2 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -247,8 +247,14 @@ void KyraEngine_v1::delayWithTicks(int ticks) { void KyraEngine_v1::registerDefaultSettings() { if (_flags.gameID != GI_KYRA3) ConfMan.registerDefault("cdaudio", (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)); - if (_flags.fanLang != Common::UNK_LANG) - ConfMan.registerDefault("subtitles", true); + if (_flags.fanLang != Common::UNK_LANG) { + // HACK/WORKAROUND: Since we can't use registerDefault here to overwrite + // the global subtitles settings, we're using this hack to enable subtitles + // for fan translations + const Common::ConfigManager::Domain *cur = ConfMan.getActiveDomain(); + if (!cur || (cur && cur->get("subtitles").empty())) + ConfMan.setBool("subtitles", true); + } } void KyraEngine_v1::readSettings() { diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index a25fe4b295..1997039c4a 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1987,6 +1987,13 @@ const char * const KyraEngine_MR::_mainMenuSpanishFan[] = { "Finalizar" }; +const char * const KyraEngine_MR::_mainMenuItalianFan[] = { + "Nuova Partita", + "Introduzione", + "Carica una partita", + "Esci dal gioco" +}; + const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension); const KyraEngine_MR::ShapeDesc KyraEngine_MR::_shapeDescs[] = { -- cgit v1.2.3 From 1cc9af6b1023d438193587171890bf2ca7d5adbf Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Sun, 6 Jul 2008 18:37:52 +0000 Subject: Implemented Good Enough(TM) XMIDI looping. This is used by Kyrandia 2 (the loop hack is no longer needed, and has been removed), and will be used by Discworld. svn-id: r32930 --- engines/kyra/sound.cpp | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index f56c43aabd..c768255272 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -249,21 +249,6 @@ void SoundMidiPC::close() { } void SoundMidiPC::send(uint32 b) { - // HACK: For Kyrandia, we make the simplifying assumption that a song - // either loops in its entirety, or not at all. So if we see a FOR_LOOP - // controller event, we turn on looping even if there isn't any - // corresponding NEXT_BREAK event. - // - // This is a gross over-simplification of how XMIDI handles loops. If - // anyone feels like doing a proper implementation, please refer to - // the Exult project, and do it in midiparser_xmidi.cpp - - if ((b & 0xFFF0) == 0x74B0 && _eventFromMusic) { - debugC(9, kDebugLevelMain | kDebugLevelSound, "SoundMidiPC: Looping song"); - _musicParser->property(MidiParser::mpAutoLoop, true); - return; - } - if (_passThrough) { if ((b & 0xFFF0) == 0x007BB0) return; -- cgit v1.2.3 From 0f8f3d51bba952632eb5ee5926cad8814cd19c74 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 7 Jul 2008 14:51:27 +0000 Subject: Fixed regression after label code refactoring. svn-id: r32940 --- engines/parallaction/graphics.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index f839f88778..93ebdd3a65 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -649,6 +649,7 @@ void Gfx::freeLabels() { delete _labels[i]; } _labels.clear(); + _floatingLabel = NO_FLOATING_LABEL; } void Gfx::drawLabels() { -- cgit v1.2.3 From 741214b6568abc10992701cc284569c318181e93 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 7 Jul 2008 19:40:43 +0000 Subject: Some fixes for warnings under GCC 2.95 svn-id: r32948 --- engines/m4/globals.cpp | 10 ++++++---- engines/m4/globals.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp index 12d9a24d37..58c68979d1 100644 --- a/engines/m4/globals.cpp +++ b/engines/m4/globals.cpp @@ -75,7 +75,7 @@ bool Kernel::sendTrigger(int32 triggerNum) { bool Kernel::handleTrigger(int32 triggerNum) { - printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, triggerNum); + printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, (uint)triggerNum); if (betweenRooms) return true; @@ -271,11 +271,13 @@ Globals::Globals(M4Engine *vm): _vm(vm) { } Globals::~Globals() { - for(uint32 i = 0; i < _madsVocab.size(); i++) + uint32 i; + + for(i = 0; i < _madsVocab.size(); i++) free(_madsVocab[i]); _madsVocab.clear(); - for(uint32 i = 0; i < _madsQuotes.size(); i++) + for(i = 0; i < _madsQuotes.size(); i++) free(_madsQuotes[i]); _madsQuotes.clear(); @@ -351,7 +353,7 @@ void Globals::loadMadsMessagesInfo() { _vm->res()->toss("messages.dat"); } -char* Globals::loadMessage(uint32 index) { +char* Globals::loadMessage(uint index) { if (index > _madsMessages.size() - 1) { warning("Invalid message index: %i", index); return NULL; diff --git a/engines/m4/globals.h b/engines/m4/globals.h index a0133db2d6..a80e8bf710 100644 --- a/engines/m4/globals.h +++ b/engines/m4/globals.h @@ -177,7 +177,7 @@ public: void loadMadsMessagesInfo(); uint32 getMessagesSize() { return _madsMessages.size(); } - char* loadMessage(uint32 index); + char* loadMessage(uint index); }; #define PLAYER_FIELD_LENGTH 40 -- cgit v1.2.3 From aee23f36a2b0ed26588c40d96ef0eee53c482d75 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 7 Jul 2008 20:40:35 +0000 Subject: Fix for bug #2012293 "KYRA: Bad Spanish String in menu". svn-id: r32949 --- engines/kyra/staticres.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 1997039c4a..4f577c1d1e 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1976,12 +1976,14 @@ const char *KyraEngine_MR::_languageExtension[] = { "TRE", "TRF", "TRG"/*, - "TRI", Italian and Spanish were never included - "TRS"*/ + "TRI", Italian and Spanish were never included, the supported fan translations are using + "TRS" English/French extensions thus overwriting these languages */ }; +const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension); + const char * const KyraEngine_MR::_mainMenuSpanishFan[] = { - "Nouvelle Partie", + "Nueva Partida", "Ver Intro", "Restaurar", "Finalizar" @@ -1994,8 +1996,6 @@ const char * const KyraEngine_MR::_mainMenuItalianFan[] = { "Esci dal gioco" }; -const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension); - const KyraEngine_MR::ShapeDesc KyraEngine_MR::_shapeDescs[] = { { 57, 91, -31, -82 }, { 57, 91, -31, -82 }, -- cgit v1.2.3 From e74d01a59a17894a85723db3b9af4dacac659336 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 7 Jul 2008 22:02:01 +0000 Subject: Fix for bathroom door opening crash in Operation Stealth's start. svn-id: r32951 --- engines/cine/gfx.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'engines') diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 47446f2410..2b7f3b8890 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -969,6 +969,7 @@ void OSRenderer::drawBackground() { /*! \brief Draw one overlay * \param it Overlay info + * \todo Add handling of type 22 overlays */ void OSRenderer::renderOverlay(const Common::List::iterator &it) { int len; @@ -979,6 +980,9 @@ void OSRenderer::renderOverlay(const Common::List::iterator &it) { switch (it->type) { // color sprite case 0: + if (objectTable[it->objIdx].frame < 0) { + break; + } sprite = animDataTable + objectTable[it->objIdx].frame; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; @@ -988,6 +992,13 @@ void OSRenderer::renderOverlay(const Common::List::iterator &it) { delete[] mask; break; + // bitmap + case 4: + if (objectTable[it->objIdx].frame >= 0) { + FWRenderer::renderOverlay(it); + } + break; + // masked background case 20: assert(it->objIdx < NUM_MAX_OBJECT); -- cgit v1.2.3 From dadb771cdcdba41c795053b5115f04109b8fd545 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 8 Jul 2008 10:29:35 +0000 Subject: Remove reference to kPlainSoundType svn-id: r32960 --- engines/scumm/imuse_digi/dimuse_track.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/scumm/imuse_digi/dimuse_track.h b/engines/scumm/imuse_digi/dimuse_track.h index 33147128cb..2d4c673cf6 100644 --- a/engines/scumm/imuse_digi/dimuse_track.h +++ b/engines/scumm/imuse_digi/dimuse_track.h @@ -85,13 +85,15 @@ struct Track { int getPan() const { return (pan != 64) ? 2 * pan - 127 : 0; } int getVol() const { return vol / 1000; } Audio::Mixer::SoundType getType() const { - Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType; + Audio::Mixer::SoundType type; if (volGroupId == 1) type = Audio::Mixer::kSpeechSoundType; else if (volGroupId == 2) type = Audio::Mixer::kSFXSoundType; else if (volGroupId == 3) type = Audio::Mixer::kMusicSoundType; + else + error("Track::getType(): invalid sound type"); return type; } }; -- cgit v1.2.3 From 03b36a3a544b7ae36e4528bc63039f7f3de475bb Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Tue, 8 Jul 2008 11:18:44 +0000 Subject: Shut couple of MSVC warnings svn-id: r32961 --- engines/m4/converse.cpp | 2 +- engines/m4/resource.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index a85fdea02f..5b8bdab9d6 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -380,7 +380,7 @@ void Converse::loadConversation(const char *convName) { uint32 size; uint32 chunk; uint32 data = 0; - uint32 i; + uint32 i = 0; ConvEntry* curEntry = NULL; ConvEntry* replyEntry = NULL; int32 currentWeightedEntry = -1; diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp index 57816b6600..074cab1095 100644 --- a/engines/m4/resource.cpp +++ b/engines/m4/resource.cpp @@ -310,7 +310,7 @@ const char *MADSResourceManager::getResourceFilename(const char *resourceName) { Common::SeekableReadStream *MADSResourceManager::loadResource(const char *resourceName, bool loadFlag) { Common::File hagFile; - uint32 offset, size; + uint32 offset, size = 0; // If the first character is a '@' then look for an external file -- cgit v1.2.3 From 4a1cc7801661425c0e2eee527e886cd0f6b57263 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Tue, 8 Jul 2008 11:35:09 +0000 Subject: Modified the EGA story image delay to work for the Mac versions as well svn-id: r32962 --- engines/gob/inter.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index 9c39653a1d..df9c1353a0 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -212,25 +212,35 @@ void Inter::funcBlock(int16 retFlag) { break; // WORKAROUND: - // The EGA version of gob1 doesn't add a delay after showing + // The EGA and Mac versions of gob1 doesn't add a delay after showing // images between levels. We manually add it here. - if ((_vm->getGameType() == kGameTypeGob1) && _vm->isEGA()) { + if ((_vm->getGameType() == kGameTypeGob1) && + (_vm->isEGA() || (_vm->getPlatform() == Common::kPlatformMacintosh))) { + int addr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData; - if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie + + if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie, EGA + !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || + (startaddr == 0x188D && addr == 0x1A58 && // Zombie, Mac !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || (startaddr == 0x1299 && addr == 0x139A && // Dungeon !strncmp(_vm->_game->_curTotFile, "avt006.tot", 10)) || - (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron + (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron, EGA + !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) || + (startaddr == 0x11C8 && addr == 0x1341 && // Cauldron, Mac !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) || (startaddr == 0x09F2 && addr == 0x0AF3 && // Statue !strncmp(_vm->_game->_curTotFile, "avt016.tot", 10)) || (startaddr == 0x0B92 && addr == 0x0C93 && // Castle !strncmp(_vm->_game->_curTotFile, "avt019.tot", 10)) || - (startaddr == 0x17D9 && addr == 0x18DA && // Finale + (startaddr == 0x17D9 && addr == 0x18DA && // Finale, EGA + !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10)) || + (startaddr == 0x17E9 && addr == 0x19A8 && // Finale, Mac !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10))) { _vm->_util->longDelay(5000); } + } // End of workaround cmd = *_vm->_global->_inter_execPtr; -- cgit v1.2.3 From da0495cd786b7e8a874024a657e062a49a665fba Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Tue, 8 Jul 2008 11:36:52 +0000 Subject: Added a Gob1 version supplied by raina in the forums. It does look like the Mac version with a DOS executable and stripped music to me, so let's hope the Mac level image workaround works there as well. svn-id: r32963 --- engines/gob/detection.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'engines') diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 8351f2ecfb..63a0f8f45b 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -277,6 +277,19 @@ static const GOBGameDescription gameDescriptions[] = { kFeaturesNone, "intro" }, + { // Supplied by raina in the forums + { + "gob1", + "", + AD_ENTRY1s("intro.stk", "6d837c6380d8f4d984c9f6cc0026df4f", 192712), + EN_ANY, + kPlatformMacintosh, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob1, + kFeaturesNone, + "intro" + }, { // Supplied by paul66 in bug report #1652352 { "gob1", -- cgit v1.2.3 From 8093dbaf49ae54aac783cdf996911c459aac5468 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Tue, 8 Jul 2008 11:48:16 +0000 Subject: One more MSVC warning svn-id: r32964 --- engines/m4/resource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp index 074cab1095..5070a2b79c 100644 --- a/engines/m4/resource.cpp +++ b/engines/m4/resource.cpp @@ -310,7 +310,7 @@ const char *MADSResourceManager::getResourceFilename(const char *resourceName) { Common::SeekableReadStream *MADSResourceManager::loadResource(const char *resourceName, bool loadFlag) { Common::File hagFile; - uint32 offset, size = 0; + uint32 offset = 0, size = 0; // If the first character is a '@' then look for an external file -- cgit v1.2.3 From a294d222136a72534871d2030f828891762146ed Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 9 Jul 2008 02:49:20 +0000 Subject: Added a couple of NULLity checks. svn-id: r32972 --- engines/parallaction/gfxbase.cpp | 4 +++- engines/parallaction/sound.cpp | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 8d7041305d..3e9bd79e5d 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -133,7 +133,9 @@ void Gfx::showGfxObj(GfxObj* obj, bool visible) { // return; // } - assert(obj); + if (!obj) { + return; + } if (visible) { obj->setFlags(kGfxObjVisible); diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp index dd74e8f7aa..d9e78f3a9e 100644 --- a/engines/parallaction/sound.cpp +++ b/engines/parallaction/sound.cpp @@ -249,6 +249,9 @@ void DosSoundMan::stopMusic() { } void DosSoundMan::playCharacterMusic(const char *character) { + if (character == NULL) { + return; + } if (!scumm_stricmp(_vm->_location._name, "night") || !scumm_stricmp(_vm->_location._name, "intsushi")) { -- cgit v1.2.3 From 18b48c74a9de417254badf23744d5c5f73c2966c Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 9 Jul 2008 10:52:46 +0000 Subject: Fixed regression introduced with GfxObj: the character sprite was sometimes removed from the rendering list. svn-id: r32974 --- engines/parallaction/gfxbase.cpp | 25 ++++++++++++++----------- engines/parallaction/graphics.h | 9 ++++++--- engines/parallaction/parallaction.cpp | 12 +++++++++--- engines/parallaction/parallaction_br.cpp | 2 +- engines/parallaction/parallaction_ns.cpp | 3 +++ 5 files changed, 33 insertions(+), 18 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 3e9bd79e5d..9e7eb12ed8 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -32,7 +32,7 @@ namespace Parallaction { -GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(0), _keep(true) { +GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(kGfxObjNormal), _keep(true) { if (name) { _name = strdup(name); } else { @@ -124,15 +124,22 @@ GfxObj* Gfx::loadDoor(const char *name) { return obj; } -void Gfx::clearGfxObjects() { - _gfxobjList.clear(); +void Gfx::clearGfxObjects(uint filter) { + + GfxObjList::iterator b = _gfxobjList.begin(); + GfxObjList::iterator e = _gfxobjList.end(); + + for ( ; b != e; ) { + if (((*b)->_flags & filter) != 0) { + b = _gfxobjList.erase(b); + } else { + b++; + } + } + } void Gfx::showGfxObj(GfxObj* obj, bool visible) { -// if (!obj || obj->isVisible() == visible) { -// return; -// } - if (!obj) { return; } @@ -141,9 +148,7 @@ void Gfx::showGfxObj(GfxObj* obj, bool visible) { obj->setFlags(kGfxObjVisible); } else { obj->clearFlags(kGfxObjVisible); -// _gfxobjList.remove(obj); } - } @@ -187,8 +192,6 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) { sortAnimations(); // TODO: some zones don't appear because of wrong masking (3 or 0?) - // TODO: Dr.Ki is not visible inside the club - GfxObjList::iterator b = _gfxobjList.begin(); GfxObjList::iterator e = _gfxobjList.end(); diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 00718d8c26..09f4b2f244 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -340,12 +340,15 @@ class Disk; enum { kGfxObjVisible = 1, + kGfxObjNormal = 2, + kGfxObjCharacter = 4, kGfxObjTypeDoor = 0, kGfxObjTypeGet = 1, kGfxObjTypeAnim = 2, kGfxObjTypeLabel = 3, - kGfxObjTypeBalloon = 4 + kGfxObjTypeBalloon = 4, + kGfxObjTypeCharacter = 8 }; enum { @@ -356,7 +359,6 @@ enum { class GfxObj { char *_name; Frames *_frames; - uint32 _flags; bool _keep; @@ -365,6 +367,7 @@ public: int32 z; + uint32 _flags; uint type; uint frame; @@ -478,7 +481,7 @@ public: GfxObj* loadDoor(const char *name); void drawGfxObjects(Graphics::Surface &surf); void showGfxObj(GfxObj* obj, bool visible); - void clearGfxObjects(); + void clearGfxObjects(uint filter); void sortAnimations(); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 3a52b28e06..ca99d2a789 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -91,6 +91,8 @@ Parallaction::~Parallaction() { delete _globalTable; delete _callableNames; + _gfx->clearGfxObjects(kGfxObjCharacter | kGfxObjNormal); + hideDialogueStuff(); freeLocation(); freeCharacter(); @@ -166,6 +168,8 @@ void Parallaction::freeCharacter() { delete _objectsNames; _objectsNames = 0; + _gfx->clearGfxObjects(kGfxObjCharacter); + _char.free(); return; @@ -248,7 +252,7 @@ void Parallaction::freeLocation() { _location._walkNodes.clear(); - _gfx->clearGfxObjects(); + _gfx->clearGfxObjects(kGfxObjNormal); freeBackground(); _location._programs.clear(); @@ -569,10 +573,14 @@ void Character::setName(const char *name) { const char *end = begin + strlen(name); _prefix = _empty; + _suffix = _empty; _dummy = IS_DUMMY_CHARACTER(name); if (!_dummy) { + if (!strstr(name, "donna")) { + _engineFlags &= ~kEngineTransformedDonna; + } else if (_engineFlags & kEngineTransformedDonna) { _suffix = _suffixTras; } else { @@ -581,8 +589,6 @@ void Character::setName(const char *name) { _engineFlags |= kEngineTransformedDonna; _suffix = _suffixTras; end = s; - } else { - _suffix = _empty; } } if (IS_MINI_CHARACTER(name)) { diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index e7f08d0339..c382f6a7f6 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -224,7 +224,7 @@ void Parallaction_br::changeLocation(char *location) { // free open location stuff clearSubtitles(); freeBackground(); - _gfx->clearGfxObjects(); + _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter); _location._programs.clear(); freeZones(); freeAnimations(); diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index af848aa6af..a2217e4a73 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -306,6 +306,7 @@ void Parallaction_ns::changeLocation(char *location) { setArrowCursor(); } + _gfx->showGfxObj(_char._ani->gfxobj, false); _location._animations.remove(_char._ani); freeLocation(); @@ -327,6 +328,7 @@ void Parallaction_ns::changeLocation(char *location) { } _location._animations.push_front(_char._ani); + _gfx->showGfxObj(_char._ani->gfxobj, true); strcpy(_saveData1, locname.location()); parseLocation(_saveData1); @@ -411,6 +413,7 @@ void Parallaction_ns::changeCharacter(const char *name) { Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); _char._ani->gfxobj = _gfx->loadAnim(_char.getFullName()); + _char._ani->gfxobj->setFlags(kGfxObjCharacter); if (!_char.dummy()) { if (getPlatform() == Common::kPlatformAmiga) { -- cgit v1.2.3 From 12cefc4132ddb06ce56efd813c88f50d5e8b19ed Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 9 Jul 2008 13:27:09 +0000 Subject: Fixed leaks in NS and BRA. svn-id: r32976 --- engines/parallaction/graphics.cpp | 1 + engines/parallaction/objects.cpp | 3 +++ engines/parallaction/parallaction.cpp | 1 + 3 files changed, 5 insertions(+) (limited to 'engines') diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 93ebdd3a65..32d0e303eb 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -767,6 +767,7 @@ Gfx::Gfx(Parallaction* vm) : Gfx::~Gfx() { freeBackground(); + freeLabels(); return; } diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index 54afabc318..66025cf0f7 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -54,6 +54,7 @@ Animation::Animation() { Animation::~Animation() { free(_scriptName); + gfxobj->release(); } uint16 Animation::width() const { @@ -182,6 +183,8 @@ Zone::~Zone() { break; } + + free(_linkedName); } void Zone::getRect(Common::Rect& r) const { diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index ca99d2a789..b2146bd292 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -93,6 +93,7 @@ Parallaction::~Parallaction() { _gfx->clearGfxObjects(kGfxObjCharacter | kGfxObjNormal); hideDialogueStuff(); + delete _balloonMan; freeLocation(); freeCharacter(); -- cgit v1.2.3 From 03cd937b13d5629f84f52b05c6374e5a3373be15 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 10 Jul 2008 02:00:54 +0000 Subject: Fixed destruction of sprites in BRA. svn-id: r32983 --- engines/parallaction/disk_br.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 543ed14146..4068cbc202 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -58,7 +58,7 @@ struct Sprites : public Frames { } ~Sprites() { - delete _sprites; + delete[] _sprites; } uint16 getNum() { -- cgit v1.2.3 From 092d9f38c5080da66b4edc2ec52a204448ab9a4f Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 10 Jul 2008 11:25:43 +0000 Subject: Workaround for gcc 2.95 compiler bug. svn-id: r32986 --- engines/kyra/script_tim.cpp | 10 ++++++---- engines/kyra/script_tim.h | 8 ++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 6b82ba06de..8725f6def9 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -34,6 +34,7 @@ namespace Kyra { TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) { #define COMMAND(x) { &TIMInterpreter::x, #x } #define COMMAND_UNIMPL() { 0, 0 } +#define cmd_return(n) cmd_return_##n static const CommandEntry commandProcs[] = { // 0x00 COMMAND(cmd_initFunc0), @@ -66,15 +67,16 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s COMMAND_UNIMPL(), COMMAND(cmd_resetAllRuntimes), // 0x18 - COMMAND(cmd_return<1>), + COMMAND(cmd_return(1)), COMMAND(cmd_execOpcode), COMMAND(cmd_initFuncNow), COMMAND(cmd_stopFuncNow), // 0x1C - COMMAND(cmd_return<1>), - COMMAND(cmd_return<1>), - COMMAND(cmd_return<-1>) + COMMAND(cmd_return(1)), + COMMAND(cmd_return(1)), + COMMAND(cmd_return(n1)) }; +#undef cmd_return _commands = commandProcs; _commandsSize = ARRAYSIZE(commandProcs); diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index cd715ff4ef..f171823444 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -102,8 +102,12 @@ private: int cmd_execOpcode(const uint16 *param); int cmd_initFuncNow(const uint16 *param); int cmd_stopFuncNow(const uint16 *param); - template - int cmd_return(const uint16 *) { return T; } +#define cmd_return(n, v) \ + int cmd_return_##n(const uint16 *) { return v; } + + cmd_return( 1, 1); + cmd_return(n1, -1); +#undef cmd_return }; } // end of namespace Kyra -- cgit v1.2.3 From 9a34ef702de478611718bc94b4d1bcfc6a922613 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 10 Jul 2008 11:28:51 +0000 Subject: Fixed mem leak in MIDI related code. svn-id: r32987 --- engines/kyra/sound.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index c768255272..5068268d99 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -243,8 +243,10 @@ int SoundMidiPC::open() { } void SoundMidiPC::close() { - if (_driver) + if (_driver) { _driver->close(); + delete _driver; + } _driver = 0; } -- cgit v1.2.3 From e1e95f0c0edf58553af5f31d33f46f5eb864d168 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 10 Jul 2008 12:05:38 +0000 Subject: Added filename to unknown opcode/command warnings of EMC scripts. svn-id: r32988 --- engines/kyra/script.cpp | 6 ++++-- engines/kyra/script.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index a29cdc8ca3..b10a4b32bf 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -132,6 +132,8 @@ bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Commo scriptData->opcodes = opcodes; + strncpy(scriptData->filename, filename, 13); + return true; } @@ -205,7 +207,7 @@ bool EMCInterpreter::run(EMCState *script) { } if (opcode > 18) { - error("Script unknown command: %d", opcode); + error("Script unknown command: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset); } else { debugC(5, kDebugLevelScript, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _commands[opcode].desc, _parameter, (uint)_parameter); (this->*(_commands[opcode].proc))(script); @@ -388,7 +390,7 @@ void EMCInterpreter::cmd_execOpcode(EMCState* script) { script->retValue = (*(*script->dataPtr->opcodes)[opcode])(script); } else { script->retValue = 0; - warning("calling unimplemented opcode(0x%.02X/%d)", opcode, opcode); + warning("Calling unimplemented opcode(0x%.02X/%d) from file '%s'", opcode, opcode, script->dataPtr->filename); } } diff --git a/engines/kyra/script.h b/engines/kyra/script.h index de52093f66..2b97a83289 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -36,6 +36,8 @@ struct EMCState; typedef Common::Functor1 Opcode; struct EMCData { + char filename[13]; + byte *text; uint16 *data; uint16 *ordr; -- cgit v1.2.3 From a117024d23c3d43ee0ced9046fdbf8e866ddc135 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 10 Jul 2008 12:12:42 +0000 Subject: Added filename to unkown command/opcode warnings for TIM scripts. svn-id: r32989 --- engines/kyra/script_tim.cpp | 8 +++++--- engines/kyra/script_tim.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 8725f6def9..8ea316f159 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -124,6 +124,8 @@ TIM *TIMInterpreter::load(const char *filename, const Common::Arrayfunc[i].avtl = tim->avtl + tim->avtl[i]; + strncpy(tim->filename, filename, 13); + return tim; } @@ -201,12 +203,12 @@ void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) { int TIMInterpreter::execCommand(int cmd, const uint16 *param) { if (cmd < 0 || cmd >= _commandsSize) { - warning("Calling unimplemented TIM command %d", cmd); + warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename); return 0; } if (_commands[cmd].proc == 0) { - warning("Calling unimplemented TIM command %d", cmd); + warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename); return 0; } @@ -261,7 +263,7 @@ int TIMInterpreter::cmd_execOpcode(const uint16 *param) { uint16 opcode = *param++; if (opcode > _currentTim->opcodes->size()) { - warning("Calling unimplemented TIM opcode(0x%.02X/%d)", opcode, opcode); + warning("Calling unimplemented TIM opcode(0x%.02X/%d) form file '%s'", opcode, opcode, _currentTim->filename); return 0; } diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index f171823444..39a1d90a44 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -37,6 +37,8 @@ struct TIM; typedef Common::Functor2 TIMOpcode; struct TIM { + char filename[13]; + int16 procFunc; uint16 procParam; -- cgit v1.2.3 From 985a032871e3296daa2c9cedb4cfabfa9036137d Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 10 Jul 2008 12:14:00 +0000 Subject: Typo. svn-id: r32990 --- engines/kyra/script_tim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 8ea316f159..4b82232049 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -263,7 +263,7 @@ int TIMInterpreter::cmd_execOpcode(const uint16 *param) { uint16 opcode = *param++; if (opcode > _currentTim->opcodes->size()) { - warning("Calling unimplemented TIM opcode(0x%.02X/%d) form file '%s'", opcode, opcode, _currentTim->filename); + warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename); return 0; } -- cgit v1.2.3 From c8488c060cea860d02fdf59221408f7974a80eab Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Thu, 10 Jul 2008 16:19:17 +0000 Subject: Fixed Kyra 3 detection regression. svn-id: r32992 --- engines/kyra/detection.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 0c8acb59b7..fce1e93bc2 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -527,7 +527,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, { { @@ -542,7 +542,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, { { @@ -557,7 +557,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_INS_FLAGS + KYRA3_CD_FLAGS }, // installed version @@ -574,7 +574,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -589,7 +589,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, { { @@ -604,7 +604,7 @@ const KYRAGameDescription adGameDescs[] = { Common::kPlatformPC, Common::ADGF_DROPLANGUAGE }, - KYRA3_CD_FLAGS + KYRA3_CD_INS_FLAGS }, // Spanish fan translation, see fr#1994040 "KYRA3: Add support for Spanish fan translation" -- cgit v1.2.3 From f41ab55021c98e2ae1aee77fa0c1dd45e0475023 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Thu, 10 Jul 2008 18:01:54 +0000 Subject: Fixed a few warnings svn-id: r32994 --- engines/scumm/detection.cpp | 2 +- engines/scumm/he/resource_he.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 9359c6610c..753ad45212 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -492,7 +492,7 @@ static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Com // Note that GF_OLD_BUNDLE is true if and only if GF_OLD256 is false. // Candidates: maniac enhanced, zak enhanced, indy3ega, loom - if (g->version != 2 && g->version != 3 || (g->features & GF_OLD256)) + if ((g->version != 2 && g->version != 3) || (g->features & GF_OLD256)) return false; /* We distinguish the games by the presence/absence of diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index 33e6748860..f8fb1efca2 100644 --- a/engines/scumm/he/resource_he.cpp +++ b/engines/scumm/he/resource_he.cpp @@ -522,12 +522,13 @@ int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base, /* get a list of all resources at this level */ wr = list_resources(fi, base, &rescnt); - if (wr == NULL) + if (wr == NULL) { if (size != 0) return size; else return 0; - + } + /* process each resource listed */ for (c = 0 ; c < rescnt ; c++) { /* (over)write the corresponding WinResource holder with the current */ -- cgit v1.2.3 From fe655836575214c33c82120e9dd714b95a96e475 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 11 Jul 2008 12:55:08 +0000 Subject: Fixed leak in sound code by explicitly deleting the midi driver. svn-id: r33002 --- engines/parallaction/sound.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp index d9e78f3a9e..df6867a90c 100644 --- a/engines/parallaction/sound.cpp +++ b/engines/parallaction/sound.cpp @@ -175,6 +175,7 @@ void MidiPlayer::close() { _mutex.lock(); _driver->setTimerCallback(NULL, NULL); _driver->close(); + delete _driver; _driver = 0; _parser->setMidiDriver(NULL); delete _parser; -- cgit v1.2.3 From 8ed023142a9ce0ee825eb3d6c33759281d68357b Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 11 Jul 2008 13:06:28 +0000 Subject: Moved program and command execution code out of the engine, into their own brand new classes. svn-id: r33003 --- engines/parallaction/dialogue.cpp | 2 +- engines/parallaction/disk_br.cpp | 9 +- engines/parallaction/exec.h | 237 +++++++++++++++++++++++++++++++ engines/parallaction/exec_br.cpp | 100 +++++++------ engines/parallaction/exec_ns.cpp | 125 +++++++++------- engines/parallaction/input.cpp | 2 +- engines/parallaction/parallaction.cpp | 13 +- engines/parallaction/parallaction.h | 137 ++---------------- engines/parallaction/parallaction_br.cpp | 20 ++- engines/parallaction/parallaction_ns.cpp | 10 +- engines/parallaction/walk.cpp | 6 +- 11 files changed, 419 insertions(+), 242 deletions(-) create mode 100644 engines/parallaction/exec.h (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 1dc4fd5ab3..6e91dd8a88 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -249,7 +249,7 @@ void DialogueManager::run() { } if (cmdlist) - _vm->runCommands(*cmdlist); + _vm->_cmdExec->run(*cmdlist); } diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 4068cbc202..ee1e111139 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -287,9 +287,12 @@ Frames* DosDisk_br::loadFrames(const char* name) { sprintf(path, "%s/ani/%s", _partPath, name); Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); - + if (!stream.open(path)) { + sprintf(path, "%s/ani/%s.ani", _partPath, name); + if (!stream.open(path)) { + errorFileNotFound(path); + } + } return createSprites(stream); } diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h new file mode 100644 index 0000000000..ca359c2a8e --- /dev/null +++ b/engines/parallaction/exec.h @@ -0,0 +1,237 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + + +#ifndef PARALLACTION_EXEC_H +#define PARALLACTION_EXEC_H + +#include "common/util.h" +#include "parallaction/objects.h" + + +namespace Parallaction { + +typedef Common::Functor0 Opcode; +typedef Common::Array OpcodeSet; + +#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op() +#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op() + +class Parallaction_ns; +class Parallaction_br; + +class CommandExec { +protected: + struct ParallactionStruct1 { + CommandPtr cmd; + ZonePtr z; + } _cmdRunCtxt; + + OpcodeSet _opcodes; + +public: + virtual void init() = 0; + virtual void run(CommandList &list, ZonePtr z = nullZonePtr); + CommandExec() { + } + virtual ~CommandExec() { + for (Common::Array::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i) + delete *i; + _opcodes.clear(); + } +}; + +class CommandExec_ns : public CommandExec { + + Parallaction_ns *_vm; + +protected: + 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); + +public: + void init(); + + CommandExec_ns(Parallaction_ns* vm); + ~CommandExec_ns(); +}; + +class CommandExec_br : public CommandExec_ns { + +protected: + Parallaction_br *_vm; + + 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); + +public: + void init(); + + CommandExec_br(Parallaction_br* vm); + ~CommandExec_br(); +}; + + + + + +class ProgramExec { +protected: + struct ParallactionStruct2 { + AnimationPtr anim; + ProgramPtr program; + InstructionList::iterator inst; + uint16 modCounter; + bool suspend; + } _instRunCtxt; + + OpcodeSet _opcodes; + +public: + virtual void init() = 0; + virtual void runScripts(ProgramList::iterator first, ProgramList::iterator last); + ProgramExec() { + } + virtual ~ProgramExec() { + for (Common::Array::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i) + delete *i; + _opcodes.clear(); + } +}; + +class ProgramExec_ns : public ProgramExec { + + Parallaction_ns *_vm; + +protected: + 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); + +public: + void init(); + + ProgramExec_ns(Parallaction_ns *vm); + ~ProgramExec_ns(); +}; + +class ProgramExec_br : public ProgramExec_ns { + + Parallaction_br *_vm; + +protected: + 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); + +public: + void init(); + ProgramExec_br(Parallaction_br *vm); + ~ProgramExec_br(); +}; + +} // namespace Parallaction + +#endif diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 734360167b..eca01ea06a 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -23,6 +23,7 @@ * */ +#include "parallaction/exec.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" @@ -64,12 +65,13 @@ namespace Parallaction { #define SetOpcodeTable(x) table = &x; -typedef Common::Functor0Mem OpcodeV2; -#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::cmdOp_##op)) -#define DECLARE_COMMAND_OPCODE(op) void Parallaction_br::cmdOp_##op() +typedef Common::Functor0Mem OpcodeV1; +#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_br::cmdOp_##op)) +#define DECLARE_COMMAND_OPCODE(op) void CommandExec_br::cmdOp_##op() -#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::instOp_##op)) -#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_br::instOp_##op() +typedef Common::Functor0Mem OpcodeV2; +#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_br::instOp_##op)) +#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_br::instOp_##op() void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y); @@ -114,7 +116,7 @@ DECLARE_COMMAND_OPCODE(location) { warning("Parallaction_br::cmdOp_location command not yet implemented"); // TODO: handle startPos and startPos2 - scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); + _vm->scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); } @@ -137,7 +139,7 @@ DECLARE_COMMAND_OPCODE(on) { z->_flags &= ~kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, true); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, true); } } } @@ -151,14 +153,14 @@ DECLARE_COMMAND_OPCODE(off) { z->_flags |= kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, false); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, false); } } } DECLARE_COMMAND_OPCODE(call) { - callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); + _vm->callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); } @@ -182,7 +184,7 @@ DECLARE_COMMAND_OPCODE(stop) { DECLARE_COMMAND_OPCODE(character) { debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _cmdRunCtxt.cmd->u._string); - changeCharacter(_cmdRunCtxt.cmd->u._string); + _vm->changeCharacter(_cmdRunCtxt.cmd->u._string); } @@ -192,12 +194,12 @@ DECLARE_COMMAND_OPCODE(followme) { DECLARE_COMMAND_OPCODE(onmouse) { - _input->showCursor(true); + _vm->_input->showCursor(true); } DECLARE_COMMAND_OPCODE(offmouse) { - _input->showCursor(false); + _vm->_input->showCursor(false); } @@ -212,42 +214,42 @@ DECLARE_COMMAND_OPCODE(leave) { DECLARE_COMMAND_OPCODE(inc) { - _counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue; } DECLARE_COMMAND_OPCODE(dec) { - _counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue; } DECLARE_COMMAND_OPCODE(ifeq) { - if (_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) { - setLocationFlags(kFlagsTestTrue); + if (_vm->_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) { + _vm->setLocationFlags(kFlagsTestTrue); } else { - clearLocationFlags(kFlagsTestTrue); + _vm->clearLocationFlags(kFlagsTestTrue); } } DECLARE_COMMAND_OPCODE(iflt) { - if (_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) { - setLocationFlags(kFlagsTestTrue); + if (_vm->_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) { + _vm->setLocationFlags(kFlagsTestTrue); } else { - clearLocationFlags(kFlagsTestTrue); + _vm->clearLocationFlags(kFlagsTestTrue); } } DECLARE_COMMAND_OPCODE(ifgt) { - if (_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) { - setLocationFlags(kFlagsTestTrue); + if (_vm->_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) { + _vm->setLocationFlags(kFlagsTestTrue); } else { - clearLocationFlags(kFlagsTestTrue); + _vm->clearLocationFlags(kFlagsTestTrue); } } DECLARE_COMMAND_OPCODE(let) { - _counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue; } @@ -267,15 +269,15 @@ DECLARE_COMMAND_OPCODE(unfix) { DECLARE_COMMAND_OPCODE(zeta) { - _location._zeta0 = _cmdRunCtxt.cmd->u._zeta0; - _location._zeta1 = _cmdRunCtxt.cmd->u._zeta1; - _location._zeta2 = _cmdRunCtxt.cmd->u._zeta2; + _vm->_location._zeta0 = _cmdRunCtxt.cmd->u._zeta0; + _vm->_location._zeta1 = _cmdRunCtxt.cmd->u._zeta1; + _vm->_location._zeta2 = _cmdRunCtxt.cmd->u._zeta2; } DECLARE_COMMAND_OPCODE(scroll) { warning("Parallaction_br::cmdOp_scroll not yet implemented"); - _gfx->setVar("scroll_x", _cmdRunCtxt.cmd->u._rvalue ); + _vm->_gfx->setVar("scroll_x", _cmdRunCtxt.cmd->u._rvalue ); } @@ -291,7 +293,7 @@ DECLARE_COMMAND_OPCODE(give) { DECLARE_COMMAND_OPCODE(text) { CommandData *data = &_cmdRunCtxt.cmd->u; - setupSubtitles(data->_string, data->_string2, data->_zeta0); + _vm->setupSubtitles(data->_string, data->_string2, data->_zeta0); } @@ -302,7 +304,7 @@ DECLARE_COMMAND_OPCODE(part) { DECLARE_COMMAND_OPCODE(testsfx) { warning("Parallaction_br::cmdOp_testsfx not completely implemented"); - clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled + _vm->clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled } @@ -332,7 +334,7 @@ DECLARE_INSTRUCTION_OPCODE(on) { z->_flags &= ~kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, true); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, true); } } } @@ -346,7 +348,7 @@ DECLARE_INSTRUCTION_OPCODE(off) { z->_flags |= kFlagsRemove; if ((z->_type & 0xFFFF) & kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, false); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, false); } } } @@ -430,7 +432,7 @@ DECLARE_INSTRUCTION_OPCODE(start) { DECLARE_INSTRUCTION_OPCODE(process) { - _activeZone2 = (*_instRunCtxt.inst)->_z; + _vm->_activeZone2 = (*_instRunCtxt.inst)->_z; } @@ -444,7 +446,7 @@ DECLARE_INSTRUCTION_OPCODE(color) { int16 entry = inst->_opB.getRValue(); - _gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]); + _vm->_gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]); } @@ -465,7 +467,7 @@ DECLARE_INSTRUCTION_OPCODE(print) { DECLARE_INSTRUCTION_OPCODE(text) { InstructionPtr inst = (*_instRunCtxt.inst); - setupSubtitles(inst->_text, inst->_text2, inst->_y); + _vm->setupSubtitles(inst->_text, inst->_text2, inst->_y); } @@ -496,7 +498,7 @@ DECLARE_INSTRUCTION_OPCODE(stop) { DECLARE_INSTRUCTION_OPCODE(endscript) { if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) { _instRunCtxt.anim->_flags &= ~kFlagsActing; - runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim); + _vm->_cmdExec->run(_instRunCtxt.anim->_commands, _instRunCtxt.anim); _instRunCtxt.program->_status = kProgramDone; } _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin(); @@ -504,11 +506,10 @@ DECLARE_INSTRUCTION_OPCODE(endscript) { _instRunCtxt.suspend = true; } -void Parallaction_br::initOpcodes() { - +void CommandExec_br::init() { Common::Array *table = 0; - SetOpcodeTable(_commandOpcodes); + SetOpcodeTable(_opcodes); COMMAND_OPCODE(invalid); COMMAND_OPCODE(set); COMMAND_OPCODE(clear); @@ -551,8 +552,21 @@ void Parallaction_br::initOpcodes() { COMMAND_OPCODE(ret); COMMAND_OPCODE(onsave); COMMAND_OPCODE(offsave); +} + +CommandExec_br::CommandExec_br(Parallaction_br* vm) : CommandExec_ns(vm), _vm(vm) { + +} + +CommandExec_br::~CommandExec_br() { + +} - SetOpcodeTable(_instructionOpcodes); +void ProgramExec_br::init() { + + Common::Array *table = 0; + + SetOpcodeTable(_opcodes); INSTRUCTION_OPCODE(invalid); INSTRUCTION_OPCODE(on); INSTRUCTION_OPCODE(off); @@ -587,6 +601,12 @@ void Parallaction_br::initOpcodes() { INSTRUCTION_OPCODE(endscript); } +ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm) { +} + +ProgramExec_br::~ProgramExec_br() { +} + #if 0 void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index abad9f273b..1250d276f6 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -23,6 +23,7 @@ * */ +#include "parallaction/exec.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" #include "parallaction/sound.h" @@ -52,12 +53,13 @@ namespace Parallaction { #define SetOpcodeTable(x) table = &x; -typedef Common::Functor0Mem OpcodeV2; -#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::cmdOp_##op)) -#define DECLARE_COMMAND_OPCODE(op) void Parallaction_ns::cmdOp_##op() +typedef Common::Functor0Mem OpcodeV1; +#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_ns::cmdOp_##op)) +#define DECLARE_COMMAND_OPCODE(op) void CommandExec_ns::cmdOp_##op() -#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::instOp_##op)) -#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_ns::instOp_##op() +typedef Common::Functor0Mem OpcodeV2; +#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_ns::instOp_##op)) +#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_ns::instOp_##op() @@ -137,7 +139,7 @@ DECLARE_INSTRUCTION_OPCODE(put) { int16 y = inst->_opB.getRValue(); bool mask = (inst->_flags & kInstMaskedPut) == kInstMaskedPut; - _gfx->patchBackground(v18, x, y, mask); + _vm->_gfx->patchBackground(v18, x, y, mask); } DECLARE_INSTRUCTION_OPCODE(null) { @@ -149,7 +151,7 @@ DECLARE_INSTRUCTION_OPCODE(invalid) { } DECLARE_INSTRUCTION_OPCODE(call) { - callFunction((*_instRunCtxt.inst)->_immediate, 0); + _vm->callFunction((*_instRunCtxt.inst)->_immediate, 0); } @@ -165,7 +167,7 @@ DECLARE_INSTRUCTION_OPCODE(start) { DECLARE_INSTRUCTION_OPCODE(sound) { - _activeZone = (*_instRunCtxt.inst)->_z; + _vm->_activeZone = (*_instRunCtxt.inst)->_z; } @@ -175,13 +177,13 @@ DECLARE_INSTRUCTION_OPCODE(move) { int16 x = inst->_opA.getRValue(); int16 y = inst->_opB.getRValue(); - _char.scheduleWalk(x, y); + _vm->_char.scheduleWalk(x, y); } DECLARE_INSTRUCTION_OPCODE(endscript) { if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) { _instRunCtxt.anim->_flags &= ~kFlagsActing; - runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim); + _vm->_cmdExec->run(_instRunCtxt.anim->_commands, _instRunCtxt.anim); _instRunCtxt.program->_status = kProgramDone; } _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin(); @@ -201,7 +203,7 @@ DECLARE_COMMAND_OPCODE(set) { _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; _commandFlags |= _cmdRunCtxt.cmd->u._flags; } else { - setLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->setLocationFlags(_cmdRunCtxt.cmd->u._flags); } } @@ -211,7 +213,7 @@ DECLARE_COMMAND_OPCODE(clear) { _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; _commandFlags &= ~_cmdRunCtxt.cmd->u._flags; } else { - clearLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->clearLocationFlags(_cmdRunCtxt.cmd->u._flags); } } @@ -222,25 +224,25 @@ DECLARE_COMMAND_OPCODE(start) { DECLARE_COMMAND_OPCODE(speak) { - _activeZone = _cmdRunCtxt.cmd->u._zone; + _vm->_activeZone = _cmdRunCtxt.cmd->u._zone; } DECLARE_COMMAND_OPCODE(get) { _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; - runZone(_cmdRunCtxt.cmd->u._zone); + _vm->runZone(_cmdRunCtxt.cmd->u._zone); } DECLARE_COMMAND_OPCODE(location) { - scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); + _vm->scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); } DECLARE_COMMAND_OPCODE(open) { _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed; if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) { - updateDoor(_cmdRunCtxt.cmd->u._zone); + _vm->updateDoor(_cmdRunCtxt.cmd->u._zone); } } @@ -248,7 +250,7 @@ DECLARE_COMMAND_OPCODE(open) { DECLARE_COMMAND_OPCODE(close) { _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed; if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) { - updateDoor(_cmdRunCtxt.cmd->u._zone); + _vm->updateDoor(_cmdRunCtxt.cmd->u._zone); } } @@ -265,7 +267,7 @@ DECLARE_COMMAND_OPCODE(on) { z->_flags &= ~kFlagsRemove; z->_flags |= kFlagsActive; if ((z->_type & 0xFFFF) == kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, true); + _vm->_gfx->showGfxObj(z->u.get->gfxobj, true); } } } @@ -277,7 +279,7 @@ DECLARE_COMMAND_OPCODE(off) { DECLARE_COMMAND_OPCODE(call) { - callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); + _vm->callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); } @@ -286,13 +288,13 @@ DECLARE_COMMAND_OPCODE(toggle) { _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; _commandFlags ^= _cmdRunCtxt.cmd->u._flags; } else { - toggleLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->toggleLocationFlags(_cmdRunCtxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(drop){ - dropItem( _cmdRunCtxt.cmd->u._object ); + _vm->dropItem( _cmdRunCtxt.cmd->u._object ); } @@ -302,7 +304,7 @@ DECLARE_COMMAND_OPCODE(quit) { DECLARE_COMMAND_OPCODE(move) { - _char.scheduleWalk(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y); + _vm->_char.scheduleWalk(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y); } @@ -356,7 +358,7 @@ void Parallaction_ns::drawAnimations() { } -void Parallaction_ns::runScripts() { +void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) { if (_engineFlags & kEnginePauseJobs) { return; } @@ -365,7 +367,7 @@ void Parallaction_ns::runScripts() { static uint16 modCounter = 0; - for (ProgramList::iterator it = _location._programs.begin(); it != _location._programs.end(); it++) { + for (ProgramList::iterator it = first; it != last; it++) { AnimationPtr a = (*it)->_anim; @@ -388,7 +390,7 @@ void Parallaction_ns::runScripts() { _instRunCtxt.modCounter = modCounter; _instRunCtxt.suspend = false; - (*_instructionOpcodes[(*inst)->_index])(); + (*_opcodes[(*inst)->_index])(); inst = _instRunCtxt.inst; // handles endloop correctly @@ -405,17 +407,13 @@ label1: a->_z = a->_top + a->height(); } - _char._ani->_z = _char._ani->height() + _char._ani->_top; - if (_char._ani->gfxobj) { - _char._ani->gfxobj->z = _char._ani->_z; - } modCounter++; return; } -void Parallaction::runCommands(CommandList& list, ZonePtr z) { +void CommandExec::run(CommandList& list, ZonePtr z) { if (list.size() == 0) return; @@ -425,7 +423,7 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) { for ( ; it != list.end(); it++) { CommandPtr cmd = *it; - uint32 v8 = getLocationFlags(); + uint32 v8 = _vm->getLocationFlags(); if (_engineFlags & kEngineQuit) break; @@ -434,15 +432,15 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) { v8 = _commandFlags | kFlagsGlobal; } + debugC(3, kDebugExec, "runCommands[%i] (on: %x, off: %x)", cmd->_id, cmd->_flagsOn, cmd->_flagsOff); + 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])(); + (*_opcodes[cmd->_id])(); } debugC(3, kDebugExec, "runCommands completed"); @@ -451,6 +449,13 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) { } +CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) { + +} + +CommandExec_ns::~CommandExec_ns() { + +} // // ZONE TYPE: EXAMINE @@ -527,7 +532,7 @@ uint16 Parallaction::runZone(ZonePtr z) { debugC(3, kDebugExec, "runZone completed"); - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); return 0; } @@ -654,11 +659,34 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { } -void Parallaction_ns::initOpcodes() { +void CommandExec_ns::init() { + Common::Array *table = 0; + + SetOpcodeTable(_opcodes); + 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); +} + +void ProgramExec_ns::init() { Common::Array *table = 0; - SetOpcodeTable(_instructionOpcodes); + SetOpcodeTable(_opcodes); INSTRUCTION_OPCODE(invalid); INSTRUCTION_OPCODE(on); INSTRUCTION_OPCODE(off); @@ -680,25 +708,12 @@ void Parallaction_ns::initOpcodes() { INSTRUCTION_OPCODE(move); INSTRUCTION_OPCODE(endscript); - SetOpcodeTable(_commandOpcodes); - 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); } +ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) { + } + +ProgramExec_ns::~ProgramExec_ns() { +} } // namespace Parallaction diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 65acbcfe58..3797158661 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -302,7 +302,7 @@ bool Input::translateInventoryInput() { _vm->dropItem(z->u.merge->_obj1); _vm->dropItem(z->u.merge->_obj2); _vm->addInventoryItem(z->u.merge->_obj3); - _vm->runCommands(z->_commands); + _vm->_cmdExec->run(z->_commands); } return true; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index b2146bd292..295f10820f 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -84,12 +84,11 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam Parallaction::~Parallaction() { - clearSet(_commandOpcodes); - clearSet(_instructionOpcodes); - delete _debugger; delete _globalTable; delete _callableNames; + delete _cmdExec; + delete _programExec; _gfx->clearGfxObjects(kGfxObjCharacter | kGfxObjNormal); hideDialogueStuff(); @@ -386,7 +385,11 @@ void Parallaction::runGame() { _gfx->beginFrame(); if (_input->_inputMode == Input::kInputModeGame) { - runScripts(); + _programExec->runScripts(_location._programs.begin(), _location._programs.end()); + _char._ani->_z = _char._ani->height() + _char._ani->_top; + if (_char._ani->gfxobj) { + _char._ani->gfxobj->z = _char._ani->_z; + } walk(); drawAnimations(); } @@ -422,7 +425,7 @@ void Parallaction::doLocationEnterTransition() { pal.makeGrayscale(); _gfx->setPalette(pal); - runScripts(); + _programExec->runScripts(_location._programs.begin(), _location._programs.end()); drawAnimations(); _gfx->updateScreen(); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index c095cab667..13c56cf57b 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -33,6 +33,7 @@ #include "engines/engine.h" +#include "parallaction/exec.h" #include "parallaction/input.h" #include "parallaction/inventory.h" #include "parallaction/parser.h" @@ -238,10 +239,6 @@ public: -#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 { @@ -259,23 +256,6 @@ public: Input *_input; - OpcodeSet _commandOpcodes; - - struct ParallactionStruct1 { - CommandPtr cmd; - ZonePtr z; - } _cmdRunCtxt; - - OpcodeSet _instructionOpcodes; - - struct ParallactionStruct2 { - AnimationPtr anim; - ProgramPtr program; - InstructionList::iterator inst; - uint16 modCounter; - bool suspend; - } _instRunCtxt; - void processInput(InputData* data); void pauseJobs(); @@ -292,8 +272,6 @@ public: void runDialogue(SpeakData*); - void runCommands(CommandList& list, ZonePtr z = nullZonePtr); - AnimationPtr findAnimation(const char *name); void freeAnimations(); @@ -327,6 +305,8 @@ public: Gfx* _gfx; Disk* _disk; + CommandExec* _cmdExec; + ProgramExec* _programExec; Character _char; void setLocationFlags(uint32 flags); @@ -367,10 +347,8 @@ protected: // members void runGame(); void updateView(); - void scheduleLocationSwitch(const char *location); void doLocationEnterTransition(); virtual void changeLocation(char *location) = 0; - virtual void changeCharacter(const char *name) = 0; virtual void runPendingZones() = 0; void allocateLocationSlot(const char *name); void finalizeLocationParsing(); @@ -389,6 +367,9 @@ protected: // members public: + void scheduleLocationSwitch(const char *location); + virtual void changeCharacter(const char *name) = 0; + virtual void callFunction(uint index, void* parm) { } virtual void setArrowCursor() = 0; @@ -398,7 +379,6 @@ public: void updateDoor(ZonePtr z); - virtual void runScripts() = 0; virtual void walk() = 0; virtual void drawAnimations() = 0; @@ -533,7 +513,6 @@ private: void initResources(); void initCursors(); - void initParsers(); static byte _resMouseArrow[256]; byte *_mouseArrow; @@ -596,49 +575,12 @@ private: const Callable *_callables; protected: - void runScripts(); void walk(); void drawAnimations(); void parseLocation(const char *filename); void loadProgram(AnimationPtr a, const char *filename); - void initOpcodes(); - - 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); - void selectStartLocation(); void guiStart(); @@ -671,6 +613,9 @@ public: typedef void (Parallaction_br::*Callable)(void*); virtual void callFunction(uint index, void* parm); void changeCharacter(const char *name); + void setupSubtitles(char *s, char *s2, int y); + void clearSubtitles(); + public: Table *_countersNames; @@ -698,8 +643,6 @@ private: void initResources(); void initFonts(); void freeFonts(); - void initOpcodes(); - void initParsers(); void setArrowCursor(); void setInventoryCursor(int pos); @@ -741,68 +684,6 @@ private: void parseLocation(const char* name); void loadProgram(AnimationPtr a, const char *filename); - 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_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); - - void setupSubtitles(char *s, char *s2, int y); - void clearSubtitles(); #if 0 void jobWaitRemoveLabelJob(void *parm, Job *job); void jobPauseSfx(void *parm, Job *job); diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index c382f6a7f6..6606550132 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -72,12 +72,16 @@ int Parallaction_br::init() { initResources(); initFonts(); initCursors(); - initOpcodes(); _locationParser = new LocationParser_br(this); _locationParser->init(); _programParser = new ProgramParser_br(this); _programParser->init(); + _cmdExec = new CommandExec_br(this); + _cmdExec->init(); + _programExec = new ProgramExec_br(this); + _programExec->init(); + _part = -1; _subtitle[0] = -1; @@ -226,8 +230,14 @@ void Parallaction_br::changeLocation(char *location) { freeBackground(); _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter); _location._programs.clear(); + + _location._animations.remove(_char._ani); + freeZones(); freeAnimations(); + + _location._animations.push_front(_char._ani); + // free(_location._comment); // _location._comment = 0; // _location._commands.clear(); @@ -236,9 +246,9 @@ void Parallaction_br::changeLocation(char *location) { // load new location parseLocation(location); - runCommands(_location._commands); + _cmdExec->run(_location._commands); // doLocationEnterTransition(); - runCommands(_location._aCommands); + _cmdExec->run(_location._aCommands); _engineFlags &= ~kEngineChangeLocation; } @@ -287,12 +297,16 @@ void Parallaction_br::loadProgram(AnimationPtr a, const char *filename) { void Parallaction_br::changeCharacter(const char *name) { + printf("changeCharacter(%s)\n", name); + const char *charName = _char.getName(); if (!scumm_stricmp(charName, name)) { return; } _char.setName(name); + _char._ani->gfxobj = _gfx->loadAnim(name); + _char._ani->gfxobj->setFlags(kGfxObjCharacter); _char._talk = _disk->loadTalk(name); } diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index a2217e4a73..850123de97 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -135,12 +135,16 @@ int Parallaction_ns::init() { initResources(); initFonts(); initCursors(); - initOpcodes(); _locationParser = new LocationParser_ns(this); _locationParser->init(); _programParser = new ProgramParser_ns(this); _programParser->init(); + _cmdExec = new CommandExec_ns(this); + _cmdExec->init(); + _programExec = new ProgramExec_ns(this); + _programExec->init(); + _introSarcData1 = 0; _introSarcData2 = 1; _introSarcData3 = 200; @@ -353,11 +357,11 @@ void Parallaction_ns::changeLocation(char *location) { // and acommands are executed, so that it can be set again if needed. _engineFlags &= ~kEngineChangeLocation; - runCommands(_location._commands); + _cmdExec->run(_location._commands); doLocationEnterTransition(); - runCommands(_location._aCommands); + _cmdExec->run(_location._aCommands); if (_location._hasSound) _soundMan->playSfx(_location._soundFile, 0, true); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 0a8ded9e29..7d74dd0e0a 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -347,7 +347,7 @@ uint16 Parallaction::checkDoor() { _zoneTrap = nullZonePtr; } else { - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); } } @@ -356,13 +356,13 @@ uint16 Parallaction::checkDoor() { if (z) { setLocationFlags(kFlagsEnter); - runCommands(z->_commands, z); + _cmdExec->run(z->_commands, z); clearLocationFlags(kFlagsEnter); _zoneTrap = z; } else if (_zoneTrap) { setLocationFlags(kFlagsExit); - runCommands(_zoneTrap->_commands, _zoneTrap); + _cmdExec->run(_zoneTrap->_commands, _zoneTrap); clearLocationFlags(kFlagsExit); _zoneTrap = nullZonePtr; } -- cgit v1.2.3 From 8ba56e98cf1887600b204f347af4ee183c326cd1 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 11 Jul 2008 13:36:22 +0000 Subject: Cleanup. svn-id: r33006 --- engines/parallaction/exec.h | 8 ++- engines/parallaction/exec_br.cpp | 80 ++++++++++++------------ engines/parallaction/exec_ns.cpp | 129 +++++++++++++++++++-------------------- 3 files changed, 108 insertions(+), 109 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h index ca359c2a8e..f41ce52302 100644 --- a/engines/parallaction/exec.h +++ b/engines/parallaction/exec.h @@ -47,7 +47,7 @@ protected: struct ParallactionStruct1 { CommandPtr cmd; ZonePtr z; - } _cmdRunCtxt; + } _ctxt; OpcodeSet _opcodes; @@ -153,14 +153,16 @@ protected: InstructionList::iterator inst; uint16 modCounter; bool suspend; - } _instRunCtxt; + } _ctxt; OpcodeSet _opcodes; + uint16 _modCounter; + public: virtual void init() = 0; virtual void runScripts(ProgramList::iterator first, ProgramList::iterator last); - ProgramExec() { + ProgramExec() : _modCounter(0) { } virtual ~ProgramExec() { for (Common::Array::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i) diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index eca01ea06a..edb832cffc 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -116,7 +116,7 @@ DECLARE_COMMAND_OPCODE(location) { warning("Parallaction_br::cmdOp_location command not yet implemented"); // TODO: handle startPos and startPos2 - _vm->scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); + _vm->scheduleLocationSwitch(_ctxt.cmd->u._string); } @@ -131,7 +131,7 @@ DECLARE_COMMAND_OPCODE(close) { DECLARE_COMMAND_OPCODE(on) { - CommandData *data = &_cmdRunCtxt.cmd->u; + CommandData *data = &_ctxt.cmd->u; ZonePtr z = data->_zone; if (z) { @@ -146,7 +146,7 @@ DECLARE_COMMAND_OPCODE(on) { DECLARE_COMMAND_OPCODE(off) { - CommandData *data = &_cmdRunCtxt.cmd->u; + CommandData *data = &_ctxt.cmd->u; ZonePtr z = data->_zone; if (z) { @@ -160,7 +160,7 @@ DECLARE_COMMAND_OPCODE(off) { DECLARE_COMMAND_OPCODE(call) { - _vm->callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); + _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z); } @@ -174,17 +174,17 @@ DECLARE_COMMAND_OPCODE(move) { } DECLARE_COMMAND_OPCODE(start) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing; + _ctxt.cmd->u._zone->_flags |= kFlagsActing; } DECLARE_COMMAND_OPCODE(stop) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing; + _ctxt.cmd->u._zone->_flags &= ~kFlagsActing; } DECLARE_COMMAND_OPCODE(character) { - debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _cmdRunCtxt.cmd->u._string); - _vm->changeCharacter(_cmdRunCtxt.cmd->u._string); + debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _ctxt.cmd->u._string); + _vm->changeCharacter(_ctxt.cmd->u._string); } @@ -214,17 +214,17 @@ DECLARE_COMMAND_OPCODE(leave) { DECLARE_COMMAND_OPCODE(inc) { - _vm->_counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_ctxt.cmd->u._lvalue] += _ctxt.cmd->u._rvalue; } DECLARE_COMMAND_OPCODE(dec) { - _vm->_counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_ctxt.cmd->u._lvalue] -= _ctxt.cmd->u._rvalue; } DECLARE_COMMAND_OPCODE(ifeq) { - if (_vm->_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) { + if (_vm->_counters[_ctxt.cmd->u._lvalue] == _ctxt.cmd->u._rvalue) { _vm->setLocationFlags(kFlagsTestTrue); } else { _vm->clearLocationFlags(kFlagsTestTrue); @@ -232,7 +232,7 @@ DECLARE_COMMAND_OPCODE(ifeq) { } DECLARE_COMMAND_OPCODE(iflt) { - if (_vm->_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) { + if (_vm->_counters[_ctxt.cmd->u._lvalue] < _ctxt.cmd->u._rvalue) { _vm->setLocationFlags(kFlagsTestTrue); } else { _vm->clearLocationFlags(kFlagsTestTrue); @@ -240,7 +240,7 @@ DECLARE_COMMAND_OPCODE(iflt) { } DECLARE_COMMAND_OPCODE(ifgt) { - if (_vm->_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) { + if (_vm->_counters[_ctxt.cmd->u._lvalue] > _ctxt.cmd->u._rvalue) { _vm->setLocationFlags(kFlagsTestTrue); } else { _vm->clearLocationFlags(kFlagsTestTrue); @@ -249,7 +249,7 @@ DECLARE_COMMAND_OPCODE(ifgt) { DECLARE_COMMAND_OPCODE(let) { - _vm->_counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue; + _vm->_counters[_ctxt.cmd->u._lvalue] = _ctxt.cmd->u._rvalue; } @@ -259,25 +259,25 @@ DECLARE_COMMAND_OPCODE(music) { DECLARE_COMMAND_OPCODE(fix) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsFixed; + _ctxt.cmd->u._zone->_flags |= kFlagsFixed; } DECLARE_COMMAND_OPCODE(unfix) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; + _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed; } DECLARE_COMMAND_OPCODE(zeta) { - _vm->_location._zeta0 = _cmdRunCtxt.cmd->u._zeta0; - _vm->_location._zeta1 = _cmdRunCtxt.cmd->u._zeta1; - _vm->_location._zeta2 = _cmdRunCtxt.cmd->u._zeta2; + _vm->_location._zeta0 = _ctxt.cmd->u._zeta0; + _vm->_location._zeta1 = _ctxt.cmd->u._zeta1; + _vm->_location._zeta2 = _ctxt.cmd->u._zeta2; } DECLARE_COMMAND_OPCODE(scroll) { warning("Parallaction_br::cmdOp_scroll not yet implemented"); - _vm->_gfx->setVar("scroll_x", _cmdRunCtxt.cmd->u._rvalue ); + _vm->_gfx->setVar("scroll_x", _ctxt.cmd->u._rvalue ); } @@ -292,7 +292,7 @@ DECLARE_COMMAND_OPCODE(give) { DECLARE_COMMAND_OPCODE(text) { - CommandData *data = &_cmdRunCtxt.cmd->u; + CommandData *data = &_ctxt.cmd->u; _vm->setupSubtitles(data->_string, data->_string2, data->_zeta0); } @@ -326,7 +326,7 @@ DECLARE_COMMAND_OPCODE(offsave) { DECLARE_INSTRUCTION_OPCODE(on) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; ZonePtr z = inst->_z; if (z) { @@ -341,7 +341,7 @@ DECLARE_INSTRUCTION_OPCODE(on) { DECLARE_INSTRUCTION_OPCODE(off) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; ZonePtr z = inst->_z; if (z) { @@ -355,7 +355,7 @@ DECLARE_INSTRUCTION_OPCODE(off) { DECLARE_INSTRUCTION_OPCODE(set) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 rvalue = inst->_opB.getRValue(); int16* lvalue = inst->_opA.getLValue(); @@ -366,21 +366,21 @@ DECLARE_INSTRUCTION_OPCODE(set) { DECLARE_INSTRUCTION_OPCODE(loop) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; - _instRunCtxt.program->_loopCounter = inst->_opB.getRValue(); - _instRunCtxt.program->_loopStart = _instRunCtxt.inst; + _ctxt.program->_loopCounter = inst->_opB.getRValue(); + _ctxt.program->_loopStart = _ctxt.inst; } DECLARE_INSTRUCTION_OPCODE(inc) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 rvalue = inst->_opB.getRValue(); if (inst->_flags & kInstMod) { // mod int16 _bx = (rvalue > 0 ? rvalue : -rvalue); - if (_instRunCtxt.modCounter % _bx != 0) return; + if (_ctxt.modCounter % _bx != 0) return; rvalue = (rvalue > 0 ? 1 : -1); } @@ -427,12 +427,12 @@ DECLARE_INSTRUCTION_OPCODE(wait) { DECLARE_INSTRUCTION_OPCODE(start) { - (*_instRunCtxt.inst)->_z->_flags |= kFlagsActing; + (*_ctxt.inst)->_z->_flags |= kFlagsActing; } DECLARE_INSTRUCTION_OPCODE(process) { - _vm->_activeZone2 = (*_instRunCtxt.inst)->_z; + _vm->_activeZone2 = (*_ctxt.inst)->_z; } @@ -442,7 +442,7 @@ DECLARE_INSTRUCTION_OPCODE(move) { DECLARE_INSTRUCTION_OPCODE(color) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 entry = inst->_opB.getRValue(); @@ -453,7 +453,7 @@ DECLARE_INSTRUCTION_OPCODE(color) { DECLARE_INSTRUCTION_OPCODE(mask) { #if 0 - Instruction *inst = *_instRunCtxt.inst; + Instruction *inst = *_ctxt.inst; _gfx->_bgLayers[0] = inst->_opA.getRValue(); _gfx->_bgLayers[1] = inst->_opB.getRValue(); _gfx->_bgLayers[2] = inst->_opC.getRValue(); @@ -466,7 +466,7 @@ DECLARE_INSTRUCTION_OPCODE(print) { } DECLARE_INSTRUCTION_OPCODE(text) { - InstructionPtr inst = (*_instRunCtxt.inst); + InstructionPtr inst = (*_ctxt.inst); _vm->setupSubtitles(inst->_text, inst->_text2, inst->_y); } @@ -496,14 +496,14 @@ DECLARE_INSTRUCTION_OPCODE(stop) { } DECLARE_INSTRUCTION_OPCODE(endscript) { - if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) { - _instRunCtxt.anim->_flags &= ~kFlagsActing; - _vm->_cmdExec->run(_instRunCtxt.anim->_commands, _instRunCtxt.anim); - _instRunCtxt.program->_status = kProgramDone; + if ((_ctxt.anim->_flags & kFlagsLooping) == 0) { + _ctxt.anim->_flags &= ~kFlagsActing; + _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim); + _ctxt.program->_status = kProgramDone; } - _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin(); + _ctxt.program->_ip = _ctxt.program->_instructions.begin(); - _instRunCtxt.suspend = true; + _ctxt.suspend = true; } void CommandExec_br::init() { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 1250d276f6..9a93197f04 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -65,7 +65,7 @@ typedef Common::Functor0Mem OpcodeV2; DECLARE_INSTRUCTION_OPCODE(on) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; inst->_a->_flags |= kFlagsActive; inst->_a->_flags &= ~kFlagsRemove; @@ -73,31 +73,31 @@ DECLARE_INSTRUCTION_OPCODE(on) { DECLARE_INSTRUCTION_OPCODE(off) { - (*_instRunCtxt.inst)->_a->_flags |= kFlagsRemove; + (*_ctxt.inst)->_a->_flags |= kFlagsRemove; } DECLARE_INSTRUCTION_OPCODE(loop) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; - _instRunCtxt.program->_loopCounter = inst->_opB.getRValue(); - _instRunCtxt.program->_loopStart = _instRunCtxt.inst; + _ctxt.program->_loopCounter = inst->_opB.getRValue(); + _ctxt.program->_loopStart = _ctxt.inst; } DECLARE_INSTRUCTION_OPCODE(endloop) { - if (--_instRunCtxt.program->_loopCounter > 0) { - _instRunCtxt.inst = _instRunCtxt.program->_loopStart; + if (--_ctxt.program->_loopCounter > 0) { + _ctxt.inst = _ctxt.program->_loopStart; } } DECLARE_INSTRUCTION_OPCODE(inc) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 _si = inst->_opB.getRValue(); if (inst->_flags & kInstMod) { // mod int16 _bx = (_si > 0 ? _si : -_si); - if (_instRunCtxt.modCounter % _bx != 0) return; + if (_modCounter % _bx != 0) return; _si = (_si > 0 ? 1 : -1); } @@ -118,7 +118,7 @@ DECLARE_INSTRUCTION_OPCODE(inc) { DECLARE_INSTRUCTION_OPCODE(set) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; int16 _si = inst->_opB.getRValue(); int16 *lvalue = inst->_opA.getLValue(); @@ -129,7 +129,7 @@ DECLARE_INSTRUCTION_OPCODE(set) { DECLARE_INSTRUCTION_OPCODE(put) { - InstructionPtr inst = *_instRunCtxt.inst; + InstructionPtr inst = *_ctxt.inst; Graphics::Surface v18; v18.w = inst->_a->width(); v18.h = inst->_a->height(); @@ -147,32 +147,32 @@ DECLARE_INSTRUCTION_OPCODE(null) { } DECLARE_INSTRUCTION_OPCODE(invalid) { - error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index); + error("Can't execute invalid opcode %i", (*_ctxt.inst)->_index); } DECLARE_INSTRUCTION_OPCODE(call) { - _vm->callFunction((*_instRunCtxt.inst)->_immediate, 0); + _vm->callFunction((*_ctxt.inst)->_immediate, 0); } DECLARE_INSTRUCTION_OPCODE(wait) { if (_engineFlags & kEngineWalking) - _instRunCtxt.suspend = true; + _ctxt.suspend = true; } DECLARE_INSTRUCTION_OPCODE(start) { - (*_instRunCtxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive); + (*_ctxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive); } DECLARE_INSTRUCTION_OPCODE(sound) { - _vm->_activeZone = (*_instRunCtxt.inst)->_z; + _vm->_activeZone = (*_ctxt.inst)->_z; } DECLARE_INSTRUCTION_OPCODE(move) { - InstructionPtr inst = (*_instRunCtxt.inst); + InstructionPtr inst = (*_ctxt.inst); int16 x = inst->_opA.getRValue(); int16 y = inst->_opB.getRValue(); @@ -181,82 +181,82 @@ DECLARE_INSTRUCTION_OPCODE(move) { } DECLARE_INSTRUCTION_OPCODE(endscript) { - if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) { - _instRunCtxt.anim->_flags &= ~kFlagsActing; - _vm->_cmdExec->run(_instRunCtxt.anim->_commands, _instRunCtxt.anim); - _instRunCtxt.program->_status = kProgramDone; + if ((_ctxt.anim->_flags & kFlagsLooping) == 0) { + _ctxt.anim->_flags &= ~kFlagsActing; + _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim); + _ctxt.program->_status = kProgramDone; } - _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin(); + _ctxt.program->_ip = _ctxt.program->_instructions.begin(); - _instRunCtxt.suspend = true; + _ctxt.suspend = true; } DECLARE_COMMAND_OPCODE(invalid) { - error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id); + error("Can't execute invalid command '%i'", _ctxt.cmd->_id); } DECLARE_COMMAND_OPCODE(set) { - if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { - _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; - _commandFlags |= _cmdRunCtxt.cmd->u._flags; + if (_ctxt.cmd->u._flags & kFlagsGlobal) { + _ctxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags |= _ctxt.cmd->u._flags; } else { - _vm->setLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->setLocationFlags(_ctxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(clear) { - if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { - _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; - _commandFlags &= ~_cmdRunCtxt.cmd->u._flags; + if (_ctxt.cmd->u._flags & kFlagsGlobal) { + _ctxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags &= ~_ctxt.cmd->u._flags; } else { - _vm->clearLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->clearLocationFlags(_ctxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(start) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing; + _ctxt.cmd->u._zone->_flags |= kFlagsActing; } DECLARE_COMMAND_OPCODE(speak) { - _vm->_activeZone = _cmdRunCtxt.cmd->u._zone; + _vm->_activeZone = _ctxt.cmd->u._zone; } DECLARE_COMMAND_OPCODE(get) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed; - _vm->runZone(_cmdRunCtxt.cmd->u._zone); + _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed; + _vm->runZone(_ctxt.cmd->u._zone); } DECLARE_COMMAND_OPCODE(location) { - _vm->scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string); + _vm->scheduleLocationSwitch(_ctxt.cmd->u._string); } DECLARE_COMMAND_OPCODE(open) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed; - if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) { - _vm->updateDoor(_cmdRunCtxt.cmd->u._zone); + _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed; + if (_ctxt.cmd->u._zone->u.door->gfxobj) { + _vm->updateDoor(_ctxt.cmd->u._zone); } } DECLARE_COMMAND_OPCODE(close) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed; - if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) { - _vm->updateDoor(_cmdRunCtxt.cmd->u._zone); + _ctxt.cmd->u._zone->_flags |= kFlagsClosed; + if (_ctxt.cmd->u._zone->u.door->gfxobj) { + _vm->updateDoor(_ctxt.cmd->u._zone); } } DECLARE_COMMAND_OPCODE(on) { - ZonePtr z = _cmdRunCtxt.cmd->u._zone; + ZonePtr z = _ctxt.cmd->u._zone; // 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. @@ -274,27 +274,27 @@ DECLARE_COMMAND_OPCODE(on) { DECLARE_COMMAND_OPCODE(off) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove; + _ctxt.cmd->u._zone->_flags |= kFlagsRemove; } DECLARE_COMMAND_OPCODE(call) { - _vm->callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z); + _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z); } DECLARE_COMMAND_OPCODE(toggle) { - if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) { - _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal; - _commandFlags ^= _cmdRunCtxt.cmd->u._flags; + if (_ctxt.cmd->u._flags & kFlagsGlobal) { + _ctxt.cmd->u._flags &= ~kFlagsGlobal; + _commandFlags ^= _ctxt.cmd->u._flags; } else { - _vm->toggleLocationFlags(_cmdRunCtxt.cmd->u._flags); + _vm->toggleLocationFlags(_ctxt.cmd->u._flags); } } DECLARE_COMMAND_OPCODE(drop){ - _vm->dropItem( _cmdRunCtxt.cmd->u._object ); + _vm->dropItem( _ctxt.cmd->u._object ); } @@ -304,12 +304,12 @@ DECLARE_COMMAND_OPCODE(quit) { DECLARE_COMMAND_OPCODE(move) { - _vm->_char.scheduleWalk(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y); + _vm->_char.scheduleWalk(_ctxt.cmd->u._move.x, _ctxt.cmd->u._move.y); } DECLARE_COMMAND_OPCODE(stop) { - _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing; + _ctxt.cmd->u._zone->_flags &= ~kFlagsActing; } @@ -365,8 +365,6 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator debugC(9, kDebugExec, "runScripts"); - static uint16 modCounter = 0; - for (ProgramList::iterator it = first; it != last; it++) { AnimationPtr a = (*it)->_anim; @@ -384,17 +382,16 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator debugC(9, kDebugExec, "Animation: %s, instruction: %i", a->_name, (*inst)->_index); //_instructionNamesRes[(*inst)->_index - 1]); - _instRunCtxt.inst = inst; - _instRunCtxt.anim = AnimationPtr(a); - _instRunCtxt.program = *it; - _instRunCtxt.modCounter = modCounter; - _instRunCtxt.suspend = false; + _ctxt.inst = inst; + _ctxt.anim = AnimationPtr(a); + _ctxt.program = *it; + _ctxt.suspend = false; (*_opcodes[(*inst)->_index])(); - inst = _instRunCtxt.inst; // handles endloop correctly + inst = _ctxt.inst; // handles endloop correctly - if (_instRunCtxt.suspend) + if (_ctxt.suspend) goto label1; inst++; @@ -407,7 +404,7 @@ label1: a->_z = a->_top + a->height(); } - modCounter++; + _modCounter++; return; } @@ -437,8 +434,8 @@ void CommandExec::run(CommandList& list, ZonePtr z) { if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue; if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue; - _cmdRunCtxt.z = z; - _cmdRunCtxt.cmd = cmd; + _ctxt.z = z; + _ctxt.cmd = cmd; (*_opcodes[cmd->_id])(); } @@ -711,7 +708,7 @@ void ProgramExec_ns::init() { } ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) { - } +} ProgramExec_ns::~ProgramExec_ns() { } -- cgit v1.2.3 From 815d75e870bc4d365cfa979f3786840eecece2ec Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 11 Jul 2008 20:28:14 +0000 Subject: Don't use kPlainSoundType if you don't have to svn-id: r33009 --- engines/gob/sound/soundmixer.h | 2 +- engines/igor/igor.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h index 5789885a99..3e8e6b5c1b 100644 --- a/engines/gob/sound/soundmixer.h +++ b/engines/gob/sound/soundmixer.h @@ -37,7 +37,7 @@ namespace Gob { class SoundMixer : public Audio::AudioStream { public: - SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType); + SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type); ~SoundMixer(); virtual void play(SoundDesc &sndDesc, int16 repCount, diff --git a/engines/igor/igor.cpp b/engines/igor/igor.cpp index 018709f34f..4d4fb97762 100644 --- a/engines/igor/igor.cpp +++ b/engines/igor/igor.cpp @@ -404,7 +404,7 @@ void IgorEngine::playSound(int num, int type) { debugC(9, kDebugEngine, "playSound() %d", num); --num; int soundOffset = -1; - Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType; + Audio::Mixer::SoundType soundType; Audio::SoundHandle *soundHandle = 0; if (type == 1) { if (_mixer->isSoundHandleActive(_sfxHandle)) { -- cgit v1.2.3 From 7ddd961bf2ded1d9cad114ea03018d44258e9ca8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 11 Jul 2008 20:28:50 +0000 Subject: cleanup svn-id: r33010 --- engines/scumm/saveload.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 36b82519e9..f9e4eb415c 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -411,15 +411,15 @@ void ScummEngine::listSavegames(bool *marks, int num) { char prefix[256]; char slot[3]; int slotNum; - Common::StringList filenames; + Common::StringList files; makeSavegameName(prefix, 99, false); prefix[strlen(prefix)-2] = '*'; prefix[strlen(prefix)-1] = 0; memset(marks, false, num * sizeof(bool)); //assume no savegames for this title - filenames = _saveFileMan->listSavefiles(prefix); + files = _saveFileMan->listSavefiles(prefix); - for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++){ + for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) { //Obtain the last 2 digits of the filename, since they correspond to the save slot slot[0] = file->c_str()[file->size()-2]; slot[1] = file->c_str()[file->size()-1]; -- cgit v1.2.3 From c1ec21d999253d86513ce66876c692be198b91c0 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sat, 12 Jul 2008 15:21:38 +0000 Subject: Changed tricky variable access from pointers to a new class that minds endianess. This should fix a few regressions with BE games on LE systems and vice versa that I introduced when I changed how variables are stored (which was necessary to get Woodruff work on BE systems). svn-id: r33014 --- engines/gob/goblin.cpp | 330 +++++++++++++++++++--------------------------- engines/gob/goblin.h | 103 ++++++++------- engines/gob/inter.h | 2 +- engines/gob/inter_v1.cpp | 173 ++++++++++++------------ engines/gob/inter_v2.cpp | 12 +- engines/gob/mult.cpp | 26 +++- engines/gob/mult.h | 9 +- engines/gob/mult_v1.cpp | 33 +++-- engines/gob/mult_v2.cpp | 26 ++-- engines/gob/sound/sound.h | 2 +- engines/gob/variables.cpp | 58 ++++++++ engines/gob/variables.h | 26 ++++ 12 files changed, 441 insertions(+), 359 deletions(-) (limited to 'engines') diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index e7aed0790e..5add0b9cea 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -78,58 +78,6 @@ Goblin::Goblin(GobEngine *vm) : _vm(vm) { _pressedMapY = 0; _pathExistence = 0; - _some0ValPtr = 0; - - _gobRetVarPtr = 0; - _curGobVarPtr = 0; - _curGobXPosVarPtr = 0; - _curGobYPosVarPtr = 0; - _itemInPocketVarPtr = 0; - - _curGobStateVarPtr = 0; - _curGobFrameVarPtr = 0; - _curGobMultStateVarPtr = 0; - _curGobNextStateVarPtr = 0; - _curGobScrXVarPtr = 0; - _curGobScrYVarPtr = 0; - _curGobLeftVarPtr = 0; - _curGobTopVarPtr = 0; - _curGobRightVarPtr = 0; - _curGobBottomVarPtr = 0; - _curGobDoAnimVarPtr = 0; - _curGobOrderVarPtr = 0; - _curGobNoTickVarPtr = 0; - _curGobTypeVarPtr = 0; - _curGobMaxTickVarPtr = 0; - _curGobTickVarPtr = 0; - _curGobActStartStateVarPtr = 0; - _curGobLookDirVarPtr = 0; - _curGobPickableVarPtr = 0; - _curGobRelaxVarPtr = 0; - _curGobMaxFrameVarPtr = 0; - - _destItemStateVarPtr = 0; - _destItemFrameVarPtr = 0; - _destItemMultStateVarPtr = 0; - _destItemNextStateVarPtr = 0; - _destItemScrXVarPtr = 0; - _destItemScrYVarPtr = 0; - _destItemLeftVarPtr = 0; - _destItemTopVarPtr = 0; - _destItemRightVarPtr = 0; - _destItemBottomVarPtr = 0; - _destItemDoAnimVarPtr = 0; - _destItemOrderVarPtr = 0; - _destItemNoTickVarPtr = 0; - _destItemTypeVarPtr = 0; - _destItemMaxTickVarPtr = 0; - _destItemTickVarPtr = 0; - _destItemActStartStVarPtr = 0; - _destItemLookDirVarPtr = 0; - _destItemPickableVarPtr = 0; - _destItemRelaxVarPtr = 0; - _destItemMaxFrameVarPtr = 0; - _destItemType = 0; _destItemState = 0; for (int i = 0; i < 20; i++) { @@ -690,7 +638,7 @@ void Goblin::switchGoblin(int16 index) { _gobDestY = tmp; _vm->_map->_curGoblinY = tmp; - *_curGobVarPtr = _currentGoblin; + _curGobVarPtr = (uint32) _currentGoblin; _pathExistence = 0; _readyToAct = 0; } @@ -1250,172 +1198,172 @@ void Goblin::loadObjects(const char *source) { void Goblin::saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal) { Gob_Object *obj; - *_some0ValPtr = someVal; - *_curGobXPosVarPtr = xPos; - *_curGobYPosVarPtr = yPos; - *_itemInPocketVarPtr = _itemIndInPocket; + _some0ValPtr = (uint32) someVal; + _curGobXPosVarPtr = (uint32) xPos; + _curGobYPosVarPtr = (uint32) yPos; + _itemInPocketVarPtr = (uint32) _itemIndInPocket; obj = _goblins[_currentGoblin]; - *_curGobStateVarPtr = obj->state; - *_curGobFrameVarPtr = obj->curFrame; - *_curGobMultStateVarPtr = obj->multState; - *_curGobNextStateVarPtr = obj->nextState; - *_curGobScrXVarPtr = obj->xPos; - *_curGobScrYVarPtr = obj->yPos; - *_curGobLeftVarPtr = obj->left; - *_curGobTopVarPtr = obj->top; - *_curGobRightVarPtr = obj->right; - *_curGobBottomVarPtr = obj->bottom; - *_curGobDoAnimVarPtr = obj->doAnim; - *_curGobOrderVarPtr = obj->order; - *_curGobNoTickVarPtr = obj->noTick; - *_curGobTypeVarPtr = obj->type; - *_curGobMaxTickVarPtr = obj->maxTick; - *_curGobTickVarPtr = obj->tick; - *_curGobActStartStateVarPtr = obj->actionStartState; - *_curGobLookDirVarPtr = obj->curLookDir; - *_curGobPickableVarPtr = obj->pickable; - *_curGobRelaxVarPtr = obj->relaxTime; - *_curGobMaxFrameVarPtr = getObjMaxFrame(obj); + _curGobStateVarPtr = (uint32) obj->state; + _curGobFrameVarPtr = (uint32) obj->curFrame; + _curGobMultStateVarPtr = (uint32) obj->multState; + _curGobNextStateVarPtr = (uint32) obj->nextState; + _curGobScrXVarPtr = (uint32) obj->xPos; + _curGobScrYVarPtr = (uint32) obj->yPos; + _curGobLeftVarPtr = (uint32) obj->left; + _curGobTopVarPtr = (uint32) obj->top; + _curGobRightVarPtr = (uint32) obj->right; + _curGobBottomVarPtr = (uint32) obj->bottom; + _curGobDoAnimVarPtr = (uint32) obj->doAnim; + _curGobOrderVarPtr = (uint32) obj->order; + _curGobNoTickVarPtr = (uint32) obj->noTick; + _curGobTypeVarPtr = (uint32) obj->type; + _curGobMaxTickVarPtr = (uint32) obj->maxTick; + _curGobTickVarPtr = (uint32) obj->tick; + _curGobActStartStateVarPtr = (uint32) obj->actionStartState; + _curGobLookDirVarPtr = (uint32) obj->curLookDir; + _curGobPickableVarPtr = (uint32) obj->pickable; + _curGobRelaxVarPtr = (uint32) obj->relaxTime; + _curGobMaxFrameVarPtr = (uint32) getObjMaxFrame(obj); if (_actDestItemDesc == 0) return; obj = _actDestItemDesc; - *_destItemStateVarPtr = obj->state; - *_destItemFrameVarPtr = obj->curFrame; - *_destItemMultStateVarPtr = obj->multState; - *_destItemNextStateVarPtr = obj->nextState; - *_destItemScrXVarPtr = obj->xPos; - *_destItemScrYVarPtr = obj->yPos; - *_destItemLeftVarPtr = obj->left; - *_destItemTopVarPtr = obj->top; - *_destItemRightVarPtr = obj->right; - *_destItemBottomVarPtr = obj->bottom; - *_destItemDoAnimVarPtr = obj->doAnim; - *_destItemOrderVarPtr = obj->order; - *_destItemNoTickVarPtr = obj->noTick; - *_destItemTypeVarPtr = obj->type; - *_destItemMaxTickVarPtr = obj->maxTick; - *_destItemTickVarPtr = obj->tick; - *_destItemActStartStVarPtr = obj->actionStartState; - *_destItemLookDirVarPtr = obj->curLookDir; - *_destItemPickableVarPtr = obj->pickable; - *_destItemRelaxVarPtr = obj->relaxTime; - *_destItemMaxFrameVarPtr = getObjMaxFrame(obj); + _destItemStateVarPtr = (uint32) obj->state; + _destItemFrameVarPtr = (uint32) obj->curFrame; + _destItemMultStateVarPtr = (uint32) obj->multState; + _destItemNextStateVarPtr = (uint32) obj->nextState; + _destItemScrXVarPtr = (uint32) obj->xPos; + _destItemScrYVarPtr = (uint32) obj->yPos; + _destItemLeftVarPtr = (uint32) obj->left; + _destItemTopVarPtr = (uint32) obj->top; + _destItemRightVarPtr = (uint32) obj->right; + _destItemBottomVarPtr = (uint32) obj->bottom; + _destItemDoAnimVarPtr = (uint32) obj->doAnim; + _destItemOrderVarPtr = (uint32) obj->order; + _destItemNoTickVarPtr = (uint32) obj->noTick; + _destItemTypeVarPtr = (uint32) obj->type; + _destItemMaxTickVarPtr = (uint32) obj->maxTick; + _destItemTickVarPtr = (uint32) obj->tick; + _destItemActStartStVarPtr = (uint32) obj->actionStartState; + _destItemLookDirVarPtr = (uint32) obj->curLookDir; + _destItemPickableVarPtr = (uint32) obj->pickable; + _destItemRelaxVarPtr = (uint32) obj->relaxTime; + _destItemMaxFrameVarPtr = (uint32) getObjMaxFrame(obj); _destItemState = obj->state; _destItemType = obj->type; } void Goblin::initVarPointers(void) { - _gobRetVarPtr = (int32 *)VAR_ADDRESS(59); - _curGobStateVarPtr = (int32 *)VAR_ADDRESS(60); - _curGobFrameVarPtr = (int32 *)VAR_ADDRESS(61); - _curGobMultStateVarPtr = (int32 *)VAR_ADDRESS(62); - _curGobNextStateVarPtr = (int32 *)VAR_ADDRESS(63); - _curGobScrXVarPtr = (int32 *)VAR_ADDRESS(64); - _curGobScrYVarPtr = (int32 *)VAR_ADDRESS(65); - _curGobLeftVarPtr = (int32 *)VAR_ADDRESS(66); - _curGobTopVarPtr = (int32 *)VAR_ADDRESS(67); - _curGobRightVarPtr = (int32 *)VAR_ADDRESS(68); - _curGobBottomVarPtr = (int32 *)VAR_ADDRESS(69); - _curGobDoAnimVarPtr = (int32 *)VAR_ADDRESS(70); - _curGobOrderVarPtr = (int32 *)VAR_ADDRESS(71); - _curGobNoTickVarPtr = (int32 *)VAR_ADDRESS(72); - _curGobTypeVarPtr = (int32 *)VAR_ADDRESS(73); - _curGobMaxTickVarPtr = (int32 *)VAR_ADDRESS(74); - _curGobTickVarPtr = (int32 *)VAR_ADDRESS(75); - _curGobActStartStateVarPtr = (int32 *)VAR_ADDRESS(76); - _curGobLookDirVarPtr = (int32 *)VAR_ADDRESS(77); - _curGobPickableVarPtr = (int32 *)VAR_ADDRESS(80); - _curGobRelaxVarPtr = (int32 *)VAR_ADDRESS(81); - _destItemStateVarPtr = (int32 *)VAR_ADDRESS(82); - _destItemFrameVarPtr = (int32 *)VAR_ADDRESS(83); - _destItemMultStateVarPtr = (int32 *)VAR_ADDRESS(84); - _destItemNextStateVarPtr = (int32 *)VAR_ADDRESS(85); - _destItemScrXVarPtr = (int32 *)VAR_ADDRESS(86); - _destItemScrYVarPtr = (int32 *)VAR_ADDRESS(87); - _destItemLeftVarPtr = (int32 *)VAR_ADDRESS(88); - _destItemTopVarPtr = (int32 *)VAR_ADDRESS(89); - _destItemRightVarPtr = (int32 *)VAR_ADDRESS(90); - _destItemBottomVarPtr = (int32 *)VAR_ADDRESS(91); - _destItemDoAnimVarPtr = (int32 *)VAR_ADDRESS(92); - _destItemOrderVarPtr = (int32 *)VAR_ADDRESS(93); - _destItemNoTickVarPtr = (int32 *)VAR_ADDRESS(94); - _destItemTypeVarPtr = (int32 *)VAR_ADDRESS(95); - _destItemMaxTickVarPtr = (int32 *)VAR_ADDRESS(96); - _destItemTickVarPtr = (int32 *)VAR_ADDRESS(97); - _destItemActStartStVarPtr = (int32 *)VAR_ADDRESS(98); - _destItemLookDirVarPtr = (int32 *)VAR_ADDRESS(99); - _destItemPickableVarPtr = (int32 *)VAR_ADDRESS(102); - _destItemRelaxVarPtr = (int32 *)VAR_ADDRESS(103); - _destItemMaxFrameVarPtr = (int32 *)VAR_ADDRESS(105); - _curGobVarPtr = (int32 *)VAR_ADDRESS(106); - _some0ValPtr = (int32 *)VAR_ADDRESS(107); - _curGobXPosVarPtr = (int32 *)VAR_ADDRESS(108); - _curGobYPosVarPtr = (int32 *)VAR_ADDRESS(109); - _curGobMaxFrameVarPtr = (int32 *)VAR_ADDRESS(110); - - _itemInPocketVarPtr = (int32 *)VAR_ADDRESS(114); - - *_itemInPocketVarPtr = -2; + _gobRetVarPtr.set(*_vm->_inter->_variables, 236); + _curGobStateVarPtr.set(*_vm->_inter->_variables, 240); + _curGobFrameVarPtr.set(*_vm->_inter->_variables, 244); + _curGobMultStateVarPtr.set(*_vm->_inter->_variables, 248); + _curGobNextStateVarPtr.set(*_vm->_inter->_variables, 252); + _curGobScrXVarPtr.set(*_vm->_inter->_variables, 256); + _curGobScrYVarPtr.set(*_vm->_inter->_variables, 260); + _curGobLeftVarPtr.set(*_vm->_inter->_variables, 264); + _curGobTopVarPtr.set(*_vm->_inter->_variables, 268); + _curGobRightVarPtr.set(*_vm->_inter->_variables, 272); + _curGobBottomVarPtr.set(*_vm->_inter->_variables, 276); + _curGobDoAnimVarPtr.set(*_vm->_inter->_variables, 280); + _curGobOrderVarPtr.set(*_vm->_inter->_variables, 284); + _curGobNoTickVarPtr.set(*_vm->_inter->_variables, 288); + _curGobTypeVarPtr.set(*_vm->_inter->_variables, 292); + _curGobMaxTickVarPtr.set(*_vm->_inter->_variables, 296); + _curGobTickVarPtr.set(*_vm->_inter->_variables, 300); + _curGobActStartStateVarPtr.set(*_vm->_inter->_variables, 304); + _curGobLookDirVarPtr.set(*_vm->_inter->_variables, 308); + _curGobPickableVarPtr.set(*_vm->_inter->_variables, 320); + _curGobRelaxVarPtr.set(*_vm->_inter->_variables, 324); + _destItemStateVarPtr.set(*_vm->_inter->_variables, 328); + _destItemFrameVarPtr.set(*_vm->_inter->_variables, 332); + _destItemMultStateVarPtr.set(*_vm->_inter->_variables, 336); + _destItemNextStateVarPtr.set(*_vm->_inter->_variables, 340); + _destItemScrXVarPtr.set(*_vm->_inter->_variables, 344); + _destItemScrYVarPtr.set(*_vm->_inter->_variables, 348); + _destItemLeftVarPtr.set(*_vm->_inter->_variables, 352); + _destItemTopVarPtr.set(*_vm->_inter->_variables, 356); + _destItemRightVarPtr.set(*_vm->_inter->_variables, 360); + _destItemBottomVarPtr.set(*_vm->_inter->_variables, 364); + _destItemDoAnimVarPtr.set(*_vm->_inter->_variables, 368); + _destItemOrderVarPtr.set(*_vm->_inter->_variables, 372); + _destItemNoTickVarPtr.set(*_vm->_inter->_variables, 376); + _destItemTypeVarPtr.set(*_vm->_inter->_variables, 380); + _destItemMaxTickVarPtr.set(*_vm->_inter->_variables, 384); + _destItemTickVarPtr.set(*_vm->_inter->_variables, 388); + _destItemActStartStVarPtr.set(*_vm->_inter->_variables, 392); + _destItemLookDirVarPtr.set(*_vm->_inter->_variables, 396); + _destItemPickableVarPtr.set(*_vm->_inter->_variables, 408); + _destItemRelaxVarPtr.set(*_vm->_inter->_variables, 412); + _destItemMaxFrameVarPtr.set(*_vm->_inter->_variables, 420); + _curGobVarPtr.set(*_vm->_inter->_variables, 424); + _some0ValPtr.set(*_vm->_inter->_variables, 428); + _curGobXPosVarPtr.set(*_vm->_inter->_variables, 432); + _curGobYPosVarPtr.set(*_vm->_inter->_variables, 436); + _curGobMaxFrameVarPtr.set(*_vm->_inter->_variables, 440); + + _itemInPocketVarPtr.set(*_vm->_inter->_variables, 456); + + _itemInPocketVarPtr = (uint32) -2; } void Goblin::loadGobDataFromVars(void) { Gob_Object *obj; - _itemIndInPocket = *_itemInPocketVarPtr; + _itemIndInPocket = (int32) _itemInPocketVarPtr; obj = _goblins[_currentGoblin]; - obj->state = *_curGobStateVarPtr; - obj->curFrame = *_curGobFrameVarPtr; - obj->multState = *_curGobMultStateVarPtr; - obj->nextState = *_curGobNextStateVarPtr; - obj->xPos = *_curGobScrXVarPtr; - obj->yPos = *_curGobScrYVarPtr; - obj->left = *_curGobLeftVarPtr; - obj->top = *_curGobTopVarPtr; - obj->right = *_curGobRightVarPtr; - obj->bottom = *_curGobBottomVarPtr; - obj->doAnim = *_curGobDoAnimVarPtr; - obj->order = *_curGobOrderVarPtr; - obj->noTick = *_curGobNoTickVarPtr; - obj->type = *_curGobTypeVarPtr; - obj->maxTick = *_curGobMaxTickVarPtr; - obj->tick = *_curGobTickVarPtr; - obj->actionStartState = *_curGobActStartStateVarPtr; - obj->curLookDir = *_curGobLookDirVarPtr; - obj->pickable = *_curGobPickableVarPtr; - obj->relaxTime = *_curGobRelaxVarPtr; + obj->state = (int32) _curGobStateVarPtr; + obj->curFrame = (int32) _curGobFrameVarPtr; + obj->multState = (int32) _curGobMultStateVarPtr; + obj->nextState = (int32) _curGobNextStateVarPtr; + obj->xPos = (int32) _curGobScrXVarPtr; + obj->yPos = (int32) _curGobScrYVarPtr; + obj->left = (int32) _curGobLeftVarPtr; + obj->top = (int32) _curGobTopVarPtr; + obj->right = (int32) _curGobRightVarPtr; + obj->bottom = (int32) _curGobBottomVarPtr; + obj->doAnim = (int32) _curGobDoAnimVarPtr; + obj->order = (int32) _curGobOrderVarPtr; + obj->noTick = (int32) _curGobNoTickVarPtr; + obj->type = (int32) _curGobTypeVarPtr; + obj->maxTick = (int32) _curGobMaxTickVarPtr; + obj->tick = (int32) _curGobTickVarPtr; + obj->actionStartState = (int32) _curGobActStartStateVarPtr; + obj->curLookDir = (int32) _curGobLookDirVarPtr; + obj->pickable = (int32) _curGobPickableVarPtr; + obj->relaxTime = (int32) _curGobRelaxVarPtr; if (_actDestItemDesc == 0) return; obj = _actDestItemDesc; - obj->state = *_destItemStateVarPtr; - obj->curFrame = *_destItemFrameVarPtr; - obj->multState = *_destItemMultStateVarPtr; - obj->nextState = *_destItemNextStateVarPtr; - obj->xPos = *_destItemScrXVarPtr; - obj->yPos = *_destItemScrYVarPtr; - obj->left = *_destItemLeftVarPtr; - obj->top = *_destItemTopVarPtr; - obj->right = *_destItemRightVarPtr; - obj->bottom = *_destItemBottomVarPtr; - obj->doAnim = *_destItemDoAnimVarPtr; - obj->order = *_destItemOrderVarPtr; - obj->noTick = *_destItemNoTickVarPtr; - obj->type = *_destItemTypeVarPtr; - obj->maxTick = *_destItemMaxTickVarPtr; - obj->tick = *_destItemTickVarPtr; - obj->actionStartState = *_destItemActStartStVarPtr; - obj->curLookDir = *_destItemLookDirVarPtr; - obj->pickable = *_destItemPickableVarPtr; - obj->relaxTime = *_destItemRelaxVarPtr; + obj->state = (int32) _destItemStateVarPtr; + obj->curFrame = (int32) _destItemFrameVarPtr; + obj->multState = (int32) _destItemMultStateVarPtr; + obj->nextState = (int32) _destItemNextStateVarPtr; + obj->xPos = (int32) _destItemScrXVarPtr; + obj->yPos = (int32) _destItemScrYVarPtr; + obj->left = (int32) _destItemLeftVarPtr; + obj->top = (int32) _destItemTopVarPtr; + obj->right = (int32) _destItemRightVarPtr; + obj->bottom = (int32) _destItemBottomVarPtr; + obj->doAnim = (int32) _destItemDoAnimVarPtr; + obj->order = (int32) _destItemOrderVarPtr; + obj->noTick = (int32) _destItemNoTickVarPtr; + obj->type = (int32) _destItemTypeVarPtr; + obj->maxTick = (int32) _destItemMaxTickVarPtr; + obj->tick = (int32) _destItemTickVarPtr; + obj->actionStartState = (int32) _destItemActStartStVarPtr; + obj->curLookDir = (int32) _destItemLookDirVarPtr; + obj->pickable = (int32) _destItemPickableVarPtr; + obj->relaxTime = (int32) _destItemRelaxVarPtr; if (obj->type != _destItemType) obj->toRedraw = 1; diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h index 3fd8a9f93b..2100bcbdac 100644 --- a/engines/gob/goblin.h +++ b/engines/gob/goblin.h @@ -28,6 +28,7 @@ #include "gob/util.h" #include "gob/mult.h" +#include "gob/variables.h" #include "gob/sound/sounddesc.h" namespace Gob { @@ -115,57 +116,57 @@ public: char _pathExistence; // Pointers to interpreter variables - int32 *_some0ValPtr; - - int32 *_gobRetVarPtr; - int32 *_curGobVarPtr; - int32 *_curGobXPosVarPtr; - int32 *_curGobYPosVarPtr; - int32 *_itemInPocketVarPtr; - - int32 *_curGobStateVarPtr; - int32 *_curGobFrameVarPtr; - int32 *_curGobMultStateVarPtr; - int32 *_curGobNextStateVarPtr; - int32 *_curGobScrXVarPtr; - int32 *_curGobScrYVarPtr; - int32 *_curGobLeftVarPtr; - int32 *_curGobTopVarPtr; - int32 *_curGobRightVarPtr; - int32 *_curGobBottomVarPtr; - int32 *_curGobDoAnimVarPtr; - int32 *_curGobOrderVarPtr; - int32 *_curGobNoTickVarPtr; - int32 *_curGobTypeVarPtr; - int32 *_curGobMaxTickVarPtr; - int32 *_curGobTickVarPtr; - int32 *_curGobActStartStateVarPtr; - int32 *_curGobLookDirVarPtr; - int32 *_curGobPickableVarPtr; - int32 *_curGobRelaxVarPtr; - int32 *_curGobMaxFrameVarPtr; - - int32 *_destItemStateVarPtr; - int32 *_destItemFrameVarPtr; - int32 *_destItemMultStateVarPtr; - int32 *_destItemNextStateVarPtr; - int32 *_destItemScrXVarPtr; - int32 *_destItemScrYVarPtr; - int32 *_destItemLeftVarPtr; - int32 *_destItemTopVarPtr; - int32 *_destItemRightVarPtr; - int32 *_destItemBottomVarPtr; - int32 *_destItemDoAnimVarPtr; - int32 *_destItemOrderVarPtr; - int32 *_destItemNoTickVarPtr; - int32 *_destItemTypeVarPtr; - int32 *_destItemMaxTickVarPtr; - int32 *_destItemTickVarPtr; - int32 *_destItemActStartStVarPtr; - int32 *_destItemLookDirVarPtr; - int32 *_destItemPickableVarPtr; - int32 *_destItemRelaxVarPtr; - int32 *_destItemMaxFrameVarPtr; + VariableReference _some0ValPtr; + + VariableReference _gobRetVarPtr; + VariableReference _curGobVarPtr; + VariableReference _curGobXPosVarPtr; + VariableReference _curGobYPosVarPtr; + VariableReference _itemInPocketVarPtr; + + VariableReference _curGobStateVarPtr; + VariableReference _curGobFrameVarPtr; + VariableReference _curGobMultStateVarPtr; + VariableReference _curGobNextStateVarPtr; + VariableReference _curGobScrXVarPtr; + VariableReference _curGobScrYVarPtr; + VariableReference _curGobLeftVarPtr; + VariableReference _curGobTopVarPtr; + VariableReference _curGobRightVarPtr; + VariableReference _curGobBottomVarPtr; + VariableReference _curGobDoAnimVarPtr; + VariableReference _curGobOrderVarPtr; + VariableReference _curGobNoTickVarPtr; + VariableReference _curGobTypeVarPtr; + VariableReference _curGobMaxTickVarPtr; + VariableReference _curGobTickVarPtr; + VariableReference _curGobActStartStateVarPtr; + VariableReference _curGobLookDirVarPtr; + VariableReference _curGobPickableVarPtr; + VariableReference _curGobRelaxVarPtr; + VariableReference _curGobMaxFrameVarPtr; + + VariableReference _destItemStateVarPtr; + VariableReference _destItemFrameVarPtr; + VariableReference _destItemMultStateVarPtr; + VariableReference _destItemNextStateVarPtr; + VariableReference _destItemScrXVarPtr; + VariableReference _destItemScrYVarPtr; + VariableReference _destItemLeftVarPtr; + VariableReference _destItemTopVarPtr; + VariableReference _destItemRightVarPtr; + VariableReference _destItemBottomVarPtr; + VariableReference _destItemDoAnimVarPtr; + VariableReference _destItemOrderVarPtr; + VariableReference _destItemNoTickVarPtr; + VariableReference _destItemTypeVarPtr; + VariableReference _destItemMaxTickVarPtr; + VariableReference _destItemTickVarPtr; + VariableReference _destItemActStartStVarPtr; + VariableReference _destItemLookDirVarPtr; + VariableReference _destItemPickableVarPtr; + VariableReference _destItemRelaxVarPtr; + VariableReference _destItemMaxFrameVarPtr; int16 _destItemType; int16 _destItemState; diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 60b3974d6d..b684be6c07 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -79,7 +79,7 @@ protected: }; struct OpGobParams { int16 extraData; - int32 *retVarPtr; + VariableReference retVarPtr; Goblin::Gob_Object *objDesc; }; diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index e2b8d65112..865d188a2e 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -912,12 +912,21 @@ void Inter_v1::o1_initMult() { animDataVar = _vm->_parse->parseVarIndex(); if (_vm->_mult->_objects && (oldObjCount != _vm->_mult->_objCount)) { + warning("Initializing new objects without having " "cleaned up the old ones at first"); + + for (int i = 0; i < _vm->_mult->_objCount; i++) { + delete _vm->_mult->_objects[i].pPosX; + delete _vm->_mult->_objects[i].pPosY; + } + delete[] _vm->_mult->_objects; delete[] _vm->_mult->_renderData; + _vm->_mult->_objects = 0; _vm->_mult->_renderObjs = 0; + } if (_vm->_mult->_objects == 0) { @@ -933,8 +942,8 @@ void Inter_v1::o1_initMult() { uint32 offPosY = i * 4 + (posYVar / 4) * 4; uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; - _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX); - _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY); + _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX); + _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); _vm->_mult->_objects[i].pAnimData = (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, @@ -1774,7 +1783,7 @@ bool Inter_v1::o1_goblinFunc(OpFuncParams ¶ms) { gobParams.extraData = 0; gobParams.objDesc = 0; - gobParams.retVarPtr = (int32 *) VAR_ADDRESS(59); + gobParams.retVarPtr.set(*_vm->_inter->_variables, 236); cmd = load16(); _vm->_global->_inter_execPtr += 2; @@ -2268,49 +2277,49 @@ bool Inter_v1::o1_manageDataFile(OpFuncParams ¶ms) { void Inter_v1::o1_setState(OpGobParams ¶ms) { params.objDesc->state = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemStateVarPtr = params.extraData; + _vm->_goblin->_destItemStateVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setCurFrame(OpGobParams ¶ms) { params.objDesc->curFrame = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemFrameVarPtr = params.extraData; + _vm->_goblin->_destItemFrameVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setNextState(OpGobParams ¶ms) { params.objDesc->nextState = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemNextStateVarPtr = params.extraData; + _vm->_goblin->_destItemNextStateVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setMultState(OpGobParams ¶ms) { params.objDesc->multState = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemMultStateVarPtr = params.extraData; + _vm->_goblin->_destItemMultStateVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setOrder(OpGobParams ¶ms) { params.objDesc->order = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemOrderVarPtr = params.extraData; + _vm->_goblin->_destItemOrderVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setActionStartState(OpGobParams ¶ms) { params.objDesc->actionStartState = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemActStartStVarPtr = params.extraData; + _vm->_goblin->_destItemActStartStVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setCurLookDir(OpGobParams ¶ms) { params.objDesc->curLookDir = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemLookDirVarPtr = params.extraData; + _vm->_goblin->_destItemLookDirVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setType(OpGobParams ¶ms) { params.objDesc->type = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemTypeVarPtr = params.extraData; + _vm->_goblin->_destItemTypeVarPtr = (uint32) params.extraData; if (params.extraData == 0) params.objDesc->toRedraw = 1; @@ -2319,107 +2328,107 @@ void Inter_v1::o1_setType(OpGobParams ¶ms) { void Inter_v1::o1_setNoTick(OpGobParams ¶ms) { params.objDesc->noTick = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemNoTickVarPtr = params.extraData; + _vm->_goblin->_destItemNoTickVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setPickable(OpGobParams ¶ms) { params.objDesc->pickable = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemPickableVarPtr = params.extraData; + _vm->_goblin->_destItemPickableVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setXPos(OpGobParams ¶ms) { params.objDesc->xPos = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemScrXVarPtr = params.extraData; + _vm->_goblin->_destItemScrXVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setYPos(OpGobParams ¶ms) { params.objDesc->yPos = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemScrYVarPtr = params.extraData; + _vm->_goblin->_destItemScrYVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setDoAnim(OpGobParams ¶ms) { params.objDesc->doAnim = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemDoAnimVarPtr = params.extraData; + _vm->_goblin->_destItemDoAnimVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setRelaxTime(OpGobParams ¶ms) { params.objDesc->relaxTime = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemRelaxVarPtr = params.extraData; + _vm->_goblin->_destItemRelaxVarPtr = (uint32) params.extraData; } void Inter_v1::o1_setMaxTick(OpGobParams ¶ms) { params.objDesc->maxTick = params.extraData; if (params.objDesc == _vm->_goblin->_actDestItemDesc) - *_vm->_goblin->_destItemMaxTickVarPtr = params.extraData; + _vm->_goblin->_destItemMaxTickVarPtr = (uint32) params.extraData; } void Inter_v1::o1_getState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->state; + params.retVarPtr = (uint32) params.objDesc->state; } void Inter_v1::o1_getCurFrame(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->curFrame; + params.retVarPtr = (uint32) params.objDesc->curFrame; } void Inter_v1::o1_getNextState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->nextState; + params.retVarPtr = (uint32) params.objDesc->nextState; } void Inter_v1::o1_getMultState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->multState; + params.retVarPtr = (uint32) params.objDesc->multState; } void Inter_v1::o1_getOrder(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->order; + params.retVarPtr = (uint32) params.objDesc->order; } void Inter_v1::o1_getActionStartState(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->actionStartState; + params.retVarPtr = (uint32) params.objDesc->actionStartState; } void Inter_v1::o1_getCurLookDir(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->curLookDir; + params.retVarPtr = (uint32) params.objDesc->curLookDir; } void Inter_v1::o1_getType(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->type; + params.retVarPtr = (uint32) params.objDesc->type; } void Inter_v1::o1_getNoTick(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->noTick; + params.retVarPtr = (uint32) params.objDesc->noTick; } void Inter_v1::o1_getPickable(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->pickable; + params.retVarPtr = (uint32) params.objDesc->pickable; } void Inter_v1::o1_getObjMaxFrame(OpGobParams ¶ms) { - *params.retVarPtr = _vm->_goblin->getObjMaxFrame(params.objDesc); + params.retVarPtr = (uint32) _vm->_goblin->getObjMaxFrame(params.objDesc); } void Inter_v1::o1_getXPos(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->xPos; + params.retVarPtr = (uint32) params.objDesc->xPos; } void Inter_v1::o1_getYPos(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->yPos; + params.retVarPtr = (uint32) params.objDesc->yPos; } void Inter_v1::o1_getDoAnim(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->doAnim; + params.retVarPtr = (uint32) params.objDesc->doAnim; } void Inter_v1::o1_getRelaxTime(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->relaxTime; + params.retVarPtr = (uint32) params.objDesc->relaxTime; } void Inter_v1::o1_getMaxTick(OpGobParams ¶ms) { - *params.retVarPtr = params.objDesc->maxTick; + params.retVarPtr = (uint32) params.objDesc->maxTick; } void Inter_v1::o1_manipulateMap(OpGobParams ¶ms) { @@ -2435,9 +2444,9 @@ void Inter_v1::o1_getItem(OpGobParams ¶ms) { int16 yPos = load16(); if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - *params.retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8; + params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); else - *params.retVarPtr = _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; } void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { @@ -2460,9 +2469,9 @@ void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) { yPos = VAR(yPos); if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - *params.retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8; + params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); else - *params.retVarPtr = _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; } void Inter_v1::o1_setPassMap(OpGobParams ¶ms) { @@ -2500,11 +2509,11 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams ¶ms) { params.objDesc->curFrame = 0; params.objDesc->state = 21; if (_vm->_goblin->_currentGoblin == item) { - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = 18; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = 18; _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x; _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y; } @@ -2512,12 +2521,12 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams ¶ms) { void Inter_v1::o1_getGoblinPosXH(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].x >> 1; + params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].x >> 1); } void Inter_v1::o1_getGoblinPosYH(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].y >> 1; + params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].y >> 1); } void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { @@ -2539,14 +2548,14 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { params.objDesc->xPos = animLayer->posX; params.objDesc->yPos = animLayer->posY; - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = params.objDesc->state; - *_vm->_goblin->_curGobNextStateVarPtr = params.objDesc->nextState; - *_vm->_goblin->_curGobMultStateVarPtr = params.objDesc->multState; - *_vm->_goblin->_curGobMaxFrameVarPtr = - _vm->_goblin->getObjMaxFrame(params.objDesc); + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = (uint32) params.objDesc->state; + _vm->_goblin->_curGobNextStateVarPtr = (uint32) params.objDesc->nextState; + _vm->_goblin->_curGobMultStateVarPtr = (uint32) params.objDesc->multState; + _vm->_goblin->_curGobMaxFrameVarPtr = + (uint32) _vm->_goblin->getObjMaxFrame(params.objDesc); _vm->_goblin->_noPick = 1; return; } @@ -2573,12 +2582,12 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { _vm->_goblin->_pressedMapY = yPos; _vm->_map->_curGoblinY = yPos; - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = 21; - *_vm->_goblin->_curGobNextStateVarPtr = 21; - *_vm->_goblin->_curGobMultStateVarPtr = -1; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = 21; + _vm->_goblin->_curGobNextStateVarPtr = 21; + _vm->_goblin->_curGobMultStateVarPtr = (uint32) -1; _vm->_goblin->_noPick = 0; } @@ -2598,11 +2607,11 @@ void Inter_v1::o1_setItemIndInPocket(OpGobParams ¶ms) { } void Inter_v1::o1_getItemIdInPocket(OpGobParams ¶ms) { - *params.retVarPtr = _vm->_goblin->_itemIdInPocket; + params.retVarPtr = (uint32) _vm->_goblin->_itemIdInPocket; } void Inter_v1::o1_getItemIndInPocket(OpGobParams ¶ms) { - *params.retVarPtr = _vm->_goblin->_itemIndInPocket; + params.retVarPtr = (uint32) _vm->_goblin->_itemIndInPocket; } void Inter_v1::o1_setGoblinPos(OpGobParams ¶ms) { @@ -2632,10 +2641,10 @@ void Inter_v1::o1_setGoblinPos(OpGobParams ¶ms) { params.objDesc->state = 21; if (_vm->_goblin->_currentGoblin == item) { - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = 18; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = 18; _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x; _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y; @@ -2659,11 +2668,11 @@ void Inter_v1::o1_setGoblinState(OpGobParams ¶ms) { params.objDesc->yPos = animLayer->posY; if (item == _vm->_goblin->_currentGoblin) { - *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos; - *_vm->_goblin->_curGobFrameVarPtr = 0; - *_vm->_goblin->_curGobStateVarPtr = params.objDesc->state; - *_vm->_goblin->_curGobMultStateVarPtr = params.objDesc->multState; + _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos; + _vm->_goblin->_curGobFrameVarPtr = 0; + _vm->_goblin->_curGobStateVarPtr = (uint32) params.objDesc->state; + _vm->_goblin->_curGobMultStateVarPtr = (uint32) params.objDesc->multState; } } @@ -2686,13 +2695,13 @@ void Inter_v1::o1_setGoblinStateRedraw(OpGobParams ¶ms) { params.objDesc->toRedraw = 1; params.objDesc->type = 0; if (params.objDesc == _vm->_goblin->_actDestItemDesc) { - *_vm->_goblin->_destItemScrXVarPtr = params.objDesc->xPos; - *_vm->_goblin->_destItemScrYVarPtr = params.objDesc->yPos; + _vm->_goblin->_destItemScrXVarPtr = (uint32) params.objDesc->xPos; + _vm->_goblin->_destItemScrYVarPtr = (uint32) params.objDesc->yPos; - *_vm->_goblin->_destItemStateVarPtr = params.objDesc->state; - *_vm->_goblin->_destItemNextStateVarPtr = -1; - *_vm->_goblin->_destItemMultStateVarPtr = -1; - *_vm->_goblin->_destItemFrameVarPtr = 0; + _vm->_goblin->_destItemStateVarPtr = (uint32) params.objDesc->state; + _vm->_goblin->_destItemNextStateVarPtr = (uint32) -1; + _vm->_goblin->_destItemMultStateVarPtr = (uint32) -1; + _vm->_goblin->_destItemFrameVarPtr = 0; } } @@ -2712,12 +2721,12 @@ void Inter_v1::o1_decRelaxTime(OpGobParams ¶ms) { void Inter_v1::o1_getGoblinPosX(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].x; + params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].x; } void Inter_v1::o1_getGoblinPosY(OpGobParams ¶ms) { int16 item = load16(); - *params.retVarPtr = _vm->_goblin->_gobPositions[item].y; + params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].y; } void Inter_v1::o1_clearPathExistence(OpGobParams ¶ms) { @@ -2741,9 +2750,9 @@ void Inter_v1::o1_getObjectIntersect(OpGobParams ¶ms) { params.objDesc = _vm->_goblin->_objects[params.extraData]; if (_vm->_goblin->objIntersected(params.objDesc, _vm->_goblin->_goblins[item])) - *params.retVarPtr = 1; + params.retVarPtr = 1; else - *params.retVarPtr = 0; + params.retVarPtr = 0; } void Inter_v1::o1_getGoblinIntersect(OpGobParams ¶ms) { @@ -2753,9 +2762,9 @@ void Inter_v1::o1_getGoblinIntersect(OpGobParams ¶ms) { params.objDesc = _vm->_goblin->_goblins[params.extraData]; if (_vm->_goblin->objIntersected(params.objDesc, _vm->_goblin->_goblins[item])) - *params.retVarPtr = 1; + params.retVarPtr = 1; else - *params.retVarPtr = 0; + params.retVarPtr = 0; } void Inter_v1::o1_setItemPos(OpGobParams ¶ms) { @@ -2886,7 +2895,7 @@ void Inter_v1::o1_initGoblin(OpGobParams ¶ms) { _vm->_map->_destY = _vm->_goblin->_gobPositions[0].y; _vm->_goblin->_gobDestY = _vm->_goblin->_gobPositions[0].y; - *_vm->_goblin->_curGobVarPtr = 0; + _vm->_goblin->_curGobVarPtr = 0; _vm->_goblin->_pathExistence = 0; _vm->_goblin->_readyToAct = 0; } diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index d8c33fcce6..2f1d2ec0be 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -880,9 +880,15 @@ void Inter_v2::o2_initMult() { _vm->_mult->clearObjectVideos(); + for (int i = 0; i < _vm->_mult->_objCount; i++) { + delete _vm->_mult->_objects[i].pPosX; + delete _vm->_mult->_objects[i].pPosY; + } + delete[] _vm->_mult->_objects; delete[] _vm->_mult->_renderObjs; delete[] _vm->_mult->_orderArray; + _vm->_mult->_objects = 0; _vm->_mult->_renderObjs = 0; _vm->_mult->_orderArray = 0; @@ -907,8 +913,8 @@ void Inter_v2::o2_initMult() { uint32 offPosY = i * 4 + (posYVar / 4) * 4; uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; - _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX); - _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY); + _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX); + _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); _vm->_mult->_objects[i].pAnimData = (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, @@ -1046,7 +1052,7 @@ void Inter_v2::o2_loadMultObject() { } else if ((objAnim.animType != 100) && (objAnim.animType != 101)) { - if ((*(obj.pPosX) == -1234) && (*(obj.pPosY) == -4321)) { + if ((((int32) *(obj.pPosX)) == -1234) && (((int32) *(obj.pPosY)) == -4321)) { if (obj.videoSlot > 0) _vm->_vidPlayer->slotClose(obj.videoSlot - 1); diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index 3d6a7942f9..b9373d48b3 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -93,12 +93,18 @@ Mult::Mult(GobEngine *vm) : _vm(vm) { } Mult::~Mult() { + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _orderArray; delete[] _renderData; delete[] _renderObjs; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; delete _multData; } @@ -123,6 +129,12 @@ void Mult::freeAll(void) { void Mult::freeMult() { clearObjectVideos(); + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _renderData; delete[] _renderObjs; @@ -203,11 +215,17 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, if (_animDataAllocated) { clearObjectVideos(); + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _renderData; delete[] _renderObjs; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; delete[] _orderArray; diff --git a/engines/gob/mult.h b/engines/gob/mult.h index aaf2e2826c..3bb3af17b3 100644 --- a/engines/gob/mult.h +++ b/engines/gob/mult.h @@ -27,6 +27,7 @@ #define GOB_MULT_H #include "gob/video.h" +#include "gob/variables.h" namespace Gob { @@ -77,8 +78,8 @@ public: } PACKED_STRUCT; struct Mult_Object { - int32 *pPosX; - int32 *pPosY; + VariableReference *pPosX; + VariableReference *pPosY; Mult_AnimData *pAnimData; int16 tick; int16 lastLeft; @@ -267,8 +268,8 @@ protected: bool _doPalSubst; - int32 *_animArrayX; - int32 *_animArrayY; + Variables *_animArrayX; + Variables *_animArrayY; Mult_AnimData *_animArrayData; int16 _palKeyIndex; diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp index 22683437e7..a369e7d297 100644 --- a/engines/gob/mult_v1.cpp +++ b/engines/gob/mult_v1.cpp @@ -216,10 +216,16 @@ void Mult_v1::freeMultKeys() { if (_animDataAllocated) { clearObjectVideos(); + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + delete[] _objects; delete[] _renderData; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _objects = 0; @@ -263,6 +269,14 @@ void Mult_v1::playMultInit() { _oldPalette = _vm->_global->_pPaletteDesc->vgaPal; if (!_animSurf) { + if (_objects) + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + + delete[] _objects; + _vm->_util->setFrameRate(_multData->frameRate); _animTop = 0; _animLeft = 0; @@ -270,30 +284,27 @@ void Mult_v1::playMultInit() { _animHeight = 200; _objCount = 4; - delete[] _objects; delete[] _renderData; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _objects = new Mult_Object[_objCount]; _renderData = new int16[9 * _objCount]; - _animArrayX = new int32[_objCount]; - _animArrayY = new int32[_objCount]; + _animArrayX = new VariablesLE(_objCount * 4); + _animArrayY = new VariablesLE(_objCount * 4); _animArrayData = new Mult_AnimData[_objCount]; memset(_objects, 0, _objCount * sizeof(Mult_Object)); memset(_renderData, 0, _objCount * 9 * sizeof(int16)); - memset(_animArrayX, 0, _objCount * sizeof(int32)); - memset(_animArrayY, 0, _objCount * sizeof(int32)); memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData)); for (_counter = 0; _counter < _objCount; _counter++) { Mult_Object &multObj = _objects[_counter]; Mult_AnimData &animData = _animArrayData[_counter]; - multObj.pPosX = (int32 *) &_animArrayX[_counter]; - multObj.pPosY = (int32 *) &_animArrayY[_counter]; + multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4); + multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4); multObj.pAnimData = &animData; animData.isStatic = 1; diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 3a83ac1867..20a81174e5 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -329,8 +329,8 @@ void Mult_v2::freeMultKeys() { if (_animDataAllocated) { freeMult(); - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _animArrayX = 0; @@ -510,6 +510,13 @@ void Mult_v2::playMultInit() { if (!_animSurf) { int16 width, height; + for (int i = 0; i < _objCount; i++) { + delete _objects[i].pPosX; + delete _objects[i].pPosY; + } + + delete[] _objects; + _vm->_util->setFrameRate(_multData->frameRate); _animTop = 0; _animLeft = 0; @@ -517,33 +524,30 @@ void Mult_v2::playMultInit() { _animHeight = _vm->_video->_surfHeight; _objCount = 4; - delete[] _objects; delete[] _orderArray; delete[] _renderObjs; - delete[] _animArrayX; - delete[] _animArrayY; + delete _animArrayX; + delete _animArrayY; delete[] _animArrayData; _objects = new Mult_Object[_objCount]; _orderArray = new int8[_objCount]; _renderObjs = new Mult_Object*[_objCount]; - _animArrayX = new int32[_objCount]; - _animArrayY = new int32[_objCount]; + _animArrayX = new VariablesLE(_objCount * 4); + _animArrayY = new VariablesLE(_objCount * 4); _animArrayData = new Mult_AnimData[_objCount]; memset(_objects, 0, _objCount * sizeof(Mult_Object)); memset(_orderArray, 0, _objCount * sizeof(int8)); memset(_renderObjs, 0, _objCount * sizeof(Mult_Object *)); - memset(_animArrayX, 0, _objCount * sizeof(int32)); - memset(_animArrayY, 0, _objCount * sizeof(int32)); memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData)); for (_counter = 0; _counter < _objCount; _counter++) { Mult_Object &multObj = _objects[_counter]; Mult_AnimData &animData = _animArrayData[_counter]; - multObj.pPosX = (int32 *) &_animArrayX[_counter]; - multObj.pPosY = (int32 *) &_animArrayY[_counter]; + multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4); + multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4); multObj.pAnimData = &animData; animData.isStatic = 1; diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h index b59510e4bb..07b5a737db 100644 --- a/engines/gob/sound/sound.h +++ b/engines/gob/sound/sound.h @@ -144,4 +144,4 @@ private: } // End of namespace Gob -#endif // GOB_SOUND_H +#endif // GOB_SOUND_SOUND_H diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp index 0eea2f6547..805aaeb839 100644 --- a/engines/gob/variables.cpp +++ b/engines/gob/variables.cpp @@ -308,4 +308,62 @@ uint32 VariablesBE::read32(const byte *buf) const { return READ_BE_UINT32(buf); } +VariableReference::VariableReference() { + _vars = 0; + _offset = 0; +} + +VariableReference::VariableReference(Variables &vars, uint32 offset, Variables::Type type) { + set(vars, offset, type); +} + +VariableReference::~VariableReference() { +} + +void VariableReference::set(Variables &vars, uint32 offset, Variables::Type type) { + _vars = &vars; + _offset = offset; + _type = type; +} + +VariableReference &VariableReference::operator=(uint32 value) { + if (_vars) { + switch (_type) { + case Variables::kVariableType8: + _vars->writeOff8(_offset, (uint8) value); + break; + case Variables::kVariableType16: + _vars->writeOff16(_offset, (uint16) value); + break; + case Variables::kVariableType32: + _vars->writeOff32(_offset, value); + break; + } + } + return *this; +} + +VariableReference::operator uint32() { + if (_vars) { + switch (_type) { + case Variables::kVariableType8: + return (uint32) _vars->readOff8(_offset); + case Variables::kVariableType16: + return (uint32) _vars->readOff16(_offset); + case Variables::kVariableType32: + return _vars->readOff32(_offset); + } + } + + return 0; +} + +VariableReference &VariableReference::operator+=(uint32 value) { + return (*this = (*this + value)); +} + +VariableReference &VariableReference::operator*=(uint32 value) { + return (*this = (*this * value)); +} + } // End of namespace Gob diff --git a/engines/gob/variables.h b/engines/gob/variables.h index 5989ed38ee..32f160a6bd 100644 --- a/engines/gob/variables.h +++ b/engines/gob/variables.h @@ -30,6 +30,12 @@ namespace Gob { class Variables { public: + enum Type { + kVariableType8, + kVariableType16, + kVariableType32 + }; + Variables(uint32 size); virtual ~Variables(); @@ -142,6 +148,26 @@ protected: uint32 read32(const byte *buf) const; }; +class VariableReference { + public: + VariableReference(); + VariableReference(Variables &vars, uint32 offset, + Variables::Type type = Variables::kVariableType32); + ~VariableReference(); + + void set(Variables &vars, uint32 offset, Variables::Type type = Variables::kVariableType32); + + VariableReference &operator=(uint32 value); + VariableReference &operator+=(uint32 value); + VariableReference &operator*=(uint32 value); + operator uint32(); + + private: + Variables *_vars; + uint32 _offset; + Variables::Type _type; +}; + } // End of namespace Gob #endif // GOB_VARIABLES_H -- cgit v1.2.3 From 5de579930d9ff33c2e7eeb1c267d3ef61227e558 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Sat, 12 Jul 2008 20:35:44 +0000 Subject: Minor constness fix to help with aliasing svn-id: r33017 --- engines/gob/driver_vga.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/gob/driver_vga.cpp b/engines/gob/driver_vga.cpp index f68ce47783..2d3a10b570 100644 --- a/engines/gob/driver_vga.cpp +++ b/engines/gob/driver_vga.cpp @@ -112,7 +112,7 @@ void VGAVideoDriver::drawSprite(SurfaceDesc *source, SurfaceDesc *dest, if ((width < 1) || (height < 1)) return; - byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left; + const byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left; byte *destPos = dest->getVidMem() + (y * dest->getWidth()) + x; uint32 size = width * height; -- cgit v1.2.3 From 9c2d96530be10b2f8badb500330f744bd6cdc937 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 13 Jul 2008 03:30:14 +0000 Subject: Properly implemented the OFF command. The new rendering order for graphics let this mistake finally surface. svn-id: r33021 --- engines/parallaction/exec.h | 2 ++ engines/parallaction/exec_ns.cpp | 27 +++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h index f41ce52302..887d6be526 100644 --- a/engines/parallaction/exec.h +++ b/engines/parallaction/exec.h @@ -68,6 +68,8 @@ class CommandExec_ns : public CommandExec { Parallaction_ns *_vm; protected: + void updateGetZone(ZonePtr z, bool visible); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid); DECLARE_UNQUALIFIED_COMMAND_OPCODE(set); DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear); diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 9a93197f04..4ee0aca6c1 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -254,27 +254,34 @@ DECLARE_COMMAND_OPCODE(close) { } } +void CommandExec_ns::updateGetZone(ZonePtr z, bool visible) { + if (!z) { + return; + } + + if ((z->_type & 0xFFFF) == kZoneGet) { + _vm->_gfx->showGfxObj(z->u.get->gfxobj, visible); + } +} DECLARE_COMMAND_OPCODE(on) { ZonePtr z = _ctxt.cmd->u._zone; - // 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 (z) { z->_flags &= ~kFlagsRemove; z->_flags |= kFlagsActive; - if ((z->_type & 0xFFFF) == kZoneGet) { - _vm->_gfx->showGfxObj(z->u.get->gfxobj, true); - } + updateGetZone(z, true); } } DECLARE_COMMAND_OPCODE(off) { - _ctxt.cmd->u._zone->_flags |= kFlagsRemove; + ZonePtr z = _ctxt.cmd->u._zone; + + if (z) { + _ctxt.cmd->u._zone->_flags |= kFlagsRemove; + updateGetZone(z, false); + } } -- cgit v1.2.3 From 2a80bd0678c29787dd9959cf66842f2e0483327e Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 13 Jul 2008 03:39:42 +0000 Subject: Cleanup and improved debugging output for CommandExec::run() svn-id: r33022 --- engines/parallaction/exec_ns.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 4ee0aca6c1..d1cfb14557 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -418,28 +418,38 @@ label1: void CommandExec::run(CommandList& list, ZonePtr z) { - if (list.size() == 0) + if (list.size() == 0) { + debugC(3, kDebugExec, "runCommands: nothing to do"); return; + } + + debugC(3, kDebugExec, "runCommands starting"); - debugC(3, kDebugExec, "runCommands"); + uint32 useFlags = 0; + bool useLocalFlags; CommandList::iterator it = list.begin(); for ( ; it != list.end(); it++) { - - CommandPtr cmd = *it; - uint32 v8 = _vm->getLocationFlags(); - if (_engineFlags & kEngineQuit) break; + CommandPtr cmd = *it; + if (cmd->_flagsOn & kFlagsGlobal) { - v8 = _commandFlags | kFlagsGlobal; + useFlags = _commandFlags | kFlagsGlobal; + useLocalFlags = false; + } else { + useFlags = _vm->getLocationFlags(); + useLocalFlags = true; } - debugC(3, kDebugExec, "runCommands[%i] (on: %x, off: %x)", cmd->_id, cmd->_flagsOn, cmd->_flagsOff); + bool onMatch = (cmd->_flagsOn & useFlags) == cmd->_flagsOn; + bool offMatch = (cmd->_flagsOff & ~useFlags) == cmd->_flagsOff; + + debugC(3, kDebugExec, "runCommands[%i] (on: %x, off: %x), (%s = %x)", cmd->_id, cmd->_flagsOn, cmd->_flagsOff, + useLocalFlags ? "LOCALFLAGS" : "GLOBALFLAGS", useFlags); - if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue; - if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue; + if (!onMatch || !offMatch) continue; _ctxt.z = z; _ctxt.cmd = cmd; -- cgit v1.2.3 From 059936854c897c8090a776a4af23965e72fa48f9 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 13 Jul 2008 06:27:31 +0000 Subject: Cleanup of walk code. svn-id: r33023 --- engines/parallaction/parallaction.cpp | 2 +- engines/parallaction/parallaction.h | 12 ++--- engines/parallaction/walk.cpp | 96 ++++++++++++++++------------------- 3 files changed, 50 insertions(+), 60 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 295f10820f..d03d61fc59 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -390,7 +390,7 @@ void Parallaction::runGame() { if (_char._ani->gfxobj) { _char._ani->gfxobj->z = _char._ani->_z; } - walk(); + walk(_char); drawAnimations(); } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 13c56cf57b..2d0a201686 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -261,9 +261,9 @@ public: void pauseJobs(); void resumeJobs(); - void finalizeWalk(WalkNodeList *list); - int16 selectWalkFrame(const Common::Point& pos, const WalkNodePtr from); - void clipMove(Common::Point& pos, const WalkNodePtr from); + void finalizeWalk(Character &character); + int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to); + void clipMove(Common::Point& pos, const WalkNodePtr to); ZonePtr findZone(const char *name); ZonePtr hitZone(uint32 type, uint16 x, uint16 y); @@ -357,7 +357,7 @@ protected: // members void displayComment(ExamineData *data); - uint16 checkDoor(); + void checkDoor(Character &character); void freeCharacter(); @@ -379,7 +379,7 @@ public: void updateDoor(ZonePtr z); - virtual void walk() = 0; + virtual void walk(Character &character) = 0; virtual void drawAnimations() = 0; void beep(); @@ -575,7 +575,7 @@ private: const Callable *_callables; protected: - void walk(); + void walk(Character &character); void drawAnimations(); void parseLocation(const char *filename); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 7d74dd0e0a..7a16960cbf 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -27,9 +27,11 @@ namespace Parallaction { +// should be reset on location switch static uint16 _doorData1 = 1000; static ZonePtr _zoneTrap; +// should be reset on character switch static uint16 walkData1 = 0; static uint16 walkData2 = 0; // next walk frame @@ -259,30 +261,30 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) { return 1; } -void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr from) { +void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr to) { - 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 < to->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { + pos.x = (pos.x + 2 < to->_x) ? pos.x + 2 : to->_x; } - 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.x > to->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { + pos.x = (pos.x - 2 > to->_x) ? pos.x - 2 : to->_x; } - 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 < to->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { + pos.y = (pos.y + 2 <= to->_y) ? pos.y + 2 : to->_y; } - 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; + if ((pos.y > to->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { + pos.y = (pos.y - 2 >= to->_y) ? pos.y - 2 : to->_y; } return; } -int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr from) { +int16 Parallaction::selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to) { - Common::Point dist(from->_x - pos.x, from->_y - pos.y); + Common::Point dist(to->_x - pos.x, to->_y - pos.y); if (dist.x < 0) dist.x = -dist.x; @@ -293,14 +295,14 @@ int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr // walk frame selection int16 v16; - if (_char._ani->getFrameNum() == 20) { + if (character._ani->getFrameNum() == 20) { if (dist.x > dist.y) { - walkData2 = (from->_x > pos.x) ? 0 : 7; + walkData2 = (to->_x > pos.x) ? 0 : 7; walkData1 %= 12; v16 = walkData1 / 2; } else { - walkData2 = (from->_y > pos.y) ? 14 : 17; + walkData2 = (to->_y > pos.y) ? 14 : 17; walkData1 %= 8; v16 = walkData1 / 4; } @@ -308,11 +310,11 @@ int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr } else { if (dist.x > dist.y) { - walkData2 = (from->_x > pos.x) ? 0 : 9; + walkData2 = (to->_x > pos.x) ? 0 : 9; walkData1 %= 16; v16 = walkData1 / 2; } else { - walkData2 = (from->_y > pos.y) ? 18 : 21; + walkData2 = (to->_y > pos.y) ? 18 : 21; walkData1 %= 8; v16 = walkData1 / 4; } @@ -322,9 +324,7 @@ int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr return v16; } -uint16 Parallaction::checkDoor() { -// printf("checkDoor()..."); - +void Parallaction::checkDoor(Character &character) { if (_currentLocationIndex != _doorData1) { _doorData1 = _currentLocationIndex; _zoneTrap = nullZonePtr; @@ -334,7 +334,7 @@ uint16 Parallaction::checkDoor() { Common::Point foot; - _char.getFoot(foot); + character.getFoot(foot); ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y); if (z) { @@ -351,7 +351,7 @@ uint16 Parallaction::checkDoor() { } } - _char.getFoot(foot); + character.getFoot(foot); z = hitZone(kZoneTrap, foot.x, foot.y); if (z) { @@ -367,61 +367,51 @@ uint16 Parallaction::checkDoor() { _zoneTrap = nullZonePtr; } -// printf("done\n"); - - _char._ani->_frame = walkData2; - return _char._ani->_frame; } -void Parallaction::finalizeWalk(WalkNodeList *list) { - checkDoor(); - delete list; +void Parallaction::finalizeWalk(Character &character) { + checkDoor(character); + delete character._walkPath; + character._walkPath = 0; + + character._ani->_frame = walkData2; } -void Parallaction_ns::walk() { +void Parallaction_ns::walk(Character &character) { if ((_engineFlags & kEngineWalking) == 0) { return; } - WalkNodeList *list = _char._walkPath; + Common::Point curPos; + character.getFoot(curPos); - _char._ani->_oldPos.x = _char._ani->_left; - _char._ani->_oldPos.y = _char._ani->_top; + WalkNodeList::iterator it = character._walkPath->begin(); - Common::Point pos; - _char.getFoot(pos); - - WalkNodeList::iterator it = list->begin(); - - if (it != list->end()) { - if ((*it)->_x == pos.x && (*it)->_y == pos.y) { + if (it != character._walkPath->end()) { + if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y); - it = list->erase(it); + it = character._walkPath->erase(it); } } - if (it == list->end()) { + if (it == character._walkPath->end()) { debugC(1, kDebugWalk, "walk reached last node"); -// j->_finished = 1; - finalizeWalk(list); + finalizeWalk(character); return; } - _char._walkPath = list; // selectWalkFrame must be performed before position is changed by clipMove - int16 v16 = selectWalkFrame(pos, *it); - clipMove(pos, *it); - - _char.setFoot(pos); + int16 walkFrame = selectWalkFrame(character, curPos, *it); - Common::Point newpos(_char._ani->_left, _char._ani->_top); + Common::Point newPos(curPos); + clipMove(newPos, *it); + character.setFoot(newPos); - if (newpos == _char._ani->_oldPos) { + if (newPos == curPos) { debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); -// j->_finished = 1; - finalizeWalk(list); + finalizeWalk(character); } else { - _char._ani->_frame = v16 + walkData2 + 1; + character._ani->_frame = walkFrame + walkData2 + 1; } return; -- cgit v1.2.3 From ba5f14692febafdad9c58be67eb6aa87b9afba2f Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 13 Jul 2008 12:20:24 +0000 Subject: - fix for bug #2016965: KYRA: does not compile in MSVC71 svn-id: r33030 --- engines/kyra/sound_towns.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 6be2cae7a4..e96cef735c 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -34,11 +34,6 @@ #include "common/util.h" -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif -#include - #define EUPHONY_FADEOUT_TICKS 600 namespace Kyra { @@ -2657,7 +2652,7 @@ void TownsPC98_OpnDriver::generateTables() { delete [] _oprSinTbl; _oprSinTbl = new uint32[1024]; for (int i = 0; i < 1024; i++) { - double val = sin((double) (((i << 1) + 1) * M_PI / 1024.0)); + double val = sin((double) (((i << 1) + 1) * PI / 1024.0)); double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; int32 i_dcb = (int32)(2.0 * d_dcb); i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); -- cgit v1.2.3 From ef95c6ff70c1b428ab1d086a9b0b551fc82c8451 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 13 Jul 2008 13:04:36 +0000 Subject: More refactoring of walk code. svn-id: r33033 --- engines/parallaction/parallaction.cpp | 56 +++++++++++++ engines/parallaction/parallaction.h | 10 ++- engines/parallaction/parallaction_ns.cpp | 2 + engines/parallaction/walk.cpp | 133 ++++++++++--------------------- 4 files changed, 107 insertions(+), 94 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index d03d61fc59..3cde21b49c 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -503,6 +503,34 @@ void Parallaction::freeZones() { } +enum { + WALK_LEFT = 0, + WALK_RIGHT = 1, + WALK_DOWN = 2, + WALK_UP = 3 +}; + +struct WalkFrames { + int16 stillFrame[4]; + int16 firstWalkFrame[4]; + int16 numWalkFrames[4]; + int16 frameRepeat[4]; +}; + +WalkFrames _char20WalkFrames = { + { 0, 7, 14, 17 }, + { 1, 8, 15, 18 }, + { 6, 6, 2, 2 }, + { 2, 2, 4, 4 } +}; + +WalkFrames _char24WalkFrames = { + { 0, 9, 18, 21 }, + { 1, 10, 19, 22 }, + { 8, 8, 2, 2 }, + { 2, 2, 4, 4 } +}; + const char Character::_prefixMini[] = "mini"; const char Character::_suffixTras[] = "tras"; const char Character::_empty[] = "\0"; @@ -513,6 +541,9 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder( _head = NULL; _objs = NULL; + _direction = WALK_DOWN; + _step = 0; + _dummy = false; _ani->_left = 150; @@ -633,4 +664,29 @@ void Parallaction::scheduleLocationSwitch(const char *location) { } + + + +void Character::updateDirection(const Common::Point& pos, const Common::Point& to) { + + Common::Point dist(to.x - pos.x, to.y - pos.y); + WalkFrames *frames = (_ani->getFrameNum() == 20) ? &_char20WalkFrames : &_char24WalkFrames; + + _step++; + + if (dist.x == 0 && dist.y == 0) { + _ani->_frame = frames->stillFrame[_direction]; + return; + } + + if (dist.x < 0) + dist.x = -dist.x; + if (dist.y < 0) + dist.y = -dist.y; + + _direction = (dist.x > dist.y) ? ((to.x > pos.x) ? WALK_LEFT : WALK_RIGHT) : ((to.y > pos.y) ? WALK_DOWN : WALK_UP); + _ani->_frame = frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction]; +} + + } // namespace Parallaction diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 2d0a201686..ef2dad9884 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -229,12 +229,17 @@ protected: static const char _suffixTras[]; static const char _empty[]; + int16 _direction, _step; + public: void setName(const char *name); const char *getName() const; const char *getBaseName() const; const char *getFullName() const; bool dummy() const; + + void updateDirection(const Common::Point& pos, const Common::Point& to); + }; @@ -263,7 +268,7 @@ public: void finalizeWalk(Character &character); int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to); - void clipMove(Common::Point& pos, const WalkNodePtr to); + void clipMove(Common::Point& pos, const Common::Point& to); ZonePtr findZone(const char *name); ZonePtr hitZone(uint32 type, uint16 x, uint16 y); @@ -357,7 +362,7 @@ protected: // members void displayComment(ExamineData *data); - void checkDoor(Character &character); + void checkDoor(const Common::Point &foot); void freeCharacter(); @@ -384,6 +389,7 @@ public: void beep(); + ZonePtr _zoneTrap; public: // const char **_zoneFlagNamesRes; diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 850123de97..d1b25f189a 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -305,6 +305,8 @@ void Parallaction_ns::changeLocation(char *location) { _gfx->hideFloatingLabel(); _gfx->freeLabels(); + _zoneTrap = nullZonePtr; + _input->stopHovering(); if (_engineFlags & kEngineBlockInput) { setArrowCursor(); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 7a16960cbf..40dfddb903 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -27,14 +27,6 @@ namespace Parallaction { -// should be reset on location switch -static uint16 _doorData1 = 1000; -static ZonePtr _zoneTrap; - -// should be reset on character switch -static uint16 walkData1 = 0; -static uint16 walkData2 = 0; // next walk frame - inline byte PathBuffer::getValue(uint16 x, uint16 y) { byte m = data[(x >> 3) + y * internalWidth]; @@ -261,99 +253,43 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) { return 1; } -void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr to) { +void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { - if ((pos.x < to->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { - pos.x = (pos.x + 2 < to->_x) ? pos.x + 2 : to->_x; + if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { + pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x; } - if ((pos.x > to->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { - pos.x = (pos.x - 2 > to->_x) ? pos.x - 2 : to->_x; + if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { + pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x; } - if ((pos.y < to->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { - pos.y = (pos.y + 2 <= to->_y) ? pos.y + 2 : to->_y; + if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { + pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y; } - if ((pos.y > to->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { - pos.y = (pos.y - 2 >= to->_y) ? pos.y - 2 : to->_y; + if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { + pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y; } return; } -int16 Parallaction::selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to) { - - Common::Point dist(to->_x - pos.x, to->_y - pos.y); - - if (dist.x < 0) - dist.x = -dist.x; - if (dist.y < 0) - dist.y = -dist.y; - - walkData1++; - - // walk frame selection - int16 v16; - if (character._ani->getFrameNum() == 20) { - - if (dist.x > dist.y) { - walkData2 = (to->_x > pos.x) ? 0 : 7; - walkData1 %= 12; - v16 = walkData1 / 2; - } else { - walkData2 = (to->_y > pos.y) ? 14 : 17; - walkData1 %= 8; - v16 = walkData1 / 4; - } - - } else { - - if (dist.x > dist.y) { - walkData2 = (to->_x > pos.x) ? 0 : 9; - walkData1 %= 16; - v16 = walkData1 / 2; - } else { - walkData2 = (to->_y > pos.y) ? 18 : 21; - walkData1 %= 8; - v16 = walkData1 / 4; - } - - } - - return v16; -} - -void Parallaction::checkDoor(Character &character) { - if (_currentLocationIndex != _doorData1) { - _doorData1 = _currentLocationIndex; - _zoneTrap = nullZonePtr; - } - - _engineFlags &= ~kEngineWalking; - Common::Point foot; +void Parallaction::checkDoor(const Common::Point &foot) { - character.getFoot(foot); ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y); - if (z) { - if ((z->_flags & kFlagsClosed) == 0) { _location._startPosition = z->u.door->_startPos; _location._startFrame = z->u.door->_startFrame; - scheduleLocationSwitch(z->u.door->_location); _zoneTrap = nullZonePtr; - } else { _cmdExec->run(z->_commands, z); } } - character.getFoot(foot); z = hitZone(kZoneTrap, foot.x, foot.y); - if (z) { setLocationFlags(kFlagsEnter); _cmdExec->run(z->_commands, z); @@ -371,11 +307,14 @@ void Parallaction::checkDoor(Character &character) { void Parallaction::finalizeWalk(Character &character) { - checkDoor(character); + _engineFlags &= ~kEngineWalking; + + Common::Point foot; + character.getFoot(foot); + checkDoor(foot); + delete character._walkPath; character._walkPath = 0; - - character._ani->_frame = walkData2; } void Parallaction_ns::walk(Character &character) { @@ -386,35 +325,45 @@ void Parallaction_ns::walk(Character &character) { Common::Point curPos; character.getFoot(curPos); + // update target, if previous was reached WalkNodeList::iterator it = character._walkPath->begin(); - if (it != character._walkPath->end()) { if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y); it = character._walkPath->erase(it); } } + + // advance character towards the target + Common::Point targetPos; if (it == character._walkPath->end()) { debugC(1, kDebugWalk, "walk reached last node"); finalizeWalk(character); - return; - } - - // selectWalkFrame must be performed before position is changed by clipMove - int16 walkFrame = selectWalkFrame(character, curPos, *it); + targetPos = curPos; + } else { + if (*it) { + // targetPos is saved to help setting character direction + targetPos.x = (*it)->_x; + targetPos.y = (*it)->_y; + } - Common::Point newPos(curPos); - clipMove(newPos, *it); - character.setFoot(newPos); + Common::Point newPos(curPos); + clipMove(newPos, targetPos); + character.setFoot(newPos); - if (newPos == curPos) { - debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); - finalizeWalk(character); - } else { - character._ani->_frame = walkFrame + walkData2 + 1; + if (newPos == curPos) { + debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); + finalizeWalk(character); + } } - return; + // targetPos is used to select the direction (and the walkFrame) of a character, + // since it doesn't cause the sudden changes in orientation that newPos would. + // Since newPos is 'adjusted' according to walkable areas, an imaginary line drawn + // from curPos to newPos is prone to abrutply change in direction, thus making the + // code select 'too different' frames when walking diagonally against obstacles, + // and yielding an annoying shaking effect in the character. + character.updateDirection(curPos, targetPos); } -- cgit v1.2.3 From 7b2645248c0d645266107bd732256c1c541f7278 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 14 Jul 2008 00:13:31 +0000 Subject: Made sure characters are not removed from the rendering list during switches. svn-id: r33052 --- engines/parallaction/parallaction_ns.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index d1b25f189a..cbf9ee985d 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -420,6 +420,7 @@ void Parallaction_ns::changeCharacter(const char *name) { Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); _char._ani->gfxobj = _gfx->loadAnim(_char.getFullName()); _char._ani->gfxobj->setFlags(kGfxObjCharacter); + _char._ani->gfxobj->clearFlags(kGfxObjNormal); if (!_char.dummy()) { if (getPlatform() == Common::kPlatformAmiga) { -- cgit v1.2.3 From d0ae6885ac34510cea3363b72f9467dbe62de762 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 14 Jul 2008 00:21:05 +0000 Subject: Fixed regression in walk code. Now standing frames are correctly selected when the character encounters an unexpected blocking object in his/her path. svn-id: r33053 --- engines/parallaction/walk.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 40dfddb903..a717b615e6 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -354,6 +354,7 @@ void Parallaction_ns::walk(Character &character) { if (newPos == curPos) { debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); finalizeWalk(character); + targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected } } -- cgit v1.2.3 From eaeb1587f408e540a1449d4b035e794e65937220 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 14 Jul 2008 10:33:57 +0000 Subject: Fix for missing data in the savegame format that could result in not being able to talk to Goewin in the apothecary after restoring a savegame svn-id: r33057 --- engines/lure/luredefs.h | 2 +- engines/lure/res_struct.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/lure/luredefs.h b/engines/lure/luredefs.h index 603102a099..922e1207d0 100644 --- a/engines/lure/luredefs.h +++ b/engines/lure/luredefs.h @@ -36,7 +36,7 @@ namespace Lure { #define LURE_DAT_MAJOR 1 #define LURE_DAT_MINOR 29 #define LURE_MIN_SAVEGAME_MINOR 25 -#define LURE_SAVEGAME_MINOR 32 +#define LURE_SAVEGAME_MINOR 33 #define LURE_DEBUG 1 diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp index de09f982d1..92cea948f9 100644 --- a/engines/lure/res_struct.cpp +++ b/engines/lure/res_struct.cpp @@ -456,6 +456,8 @@ void HotspotData::saveToStream(WriteStream *stream) { stream->writeSint16LE(startY); stream->writeUint16LE(roomNumber); stream->writeByte(layer); + stream->writeUint16LE(walkX); + stream->writeUint16LE(walkY); stream->writeUint16LE(width); stream->writeUint16LE(height); @@ -503,6 +505,10 @@ void HotspotData::loadFromStream(ReadStream *stream) { uint8 saveVersion = LureEngine::getReference().saveVersion(); if (saveVersion >= 29) layer = stream->readByte(); + if (saveVersion >= 33) { + walkX = stream->readUint16LE(); + walkY = stream->readUint16LE(); + } width = stream->readUint16LE(); height = stream->readUint16LE(); -- cgit v1.2.3 From c48f3ca8d8341d642690dbeb0207b77ecd58d291 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 14 Jul 2008 13:35:43 +0000 Subject: Removed all labels from the rendering list to avoid random crashes after introduction is over. svn-id: r33058 --- engines/parallaction/callables_ns.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 7c053715f6..ed60a193ce 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -424,6 +424,7 @@ void Parallaction_ns::_c_testResult(void *parm) { } _inTestResult = true; + _gfx->freeLabels(); _gfx->updateScreen(); _disk->selectArchive("disk1"); -- cgit v1.2.3 From c25c406c00175155f635aa1e1d37adb5e37cdb4c Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 14 Jul 2008 19:14:26 +0000 Subject: cleanup (and test for Marwan's branch.... ;) svn-id: r33061 --- engines/scumm/detection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 753ad45212..68d3010199 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -949,7 +949,7 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const { sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; - for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) { + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { // Obtain the last 2 digits of the filename, since they correspond to the save slot int slotNum = atoi(file->c_str() + file->size() - 2); -- cgit v1.2.3 From 9c91f091ff7a389da31534bce99908ba4e856163 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Mon, 14 Jul 2008 20:34:31 +0000 Subject: Register spilling avoided in AGOS background drawing (and 2x unrolling) svn-id: r33062 --- engines/agos/gfx.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'engines') diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index c014413bdc..2d7d6641dc 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -744,10 +744,6 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { } void AGOSEngine::drawBackGroundImage(VC10_state *state) { - const byte *src; - byte *dst; - uint h, i; - state->width = _screenWidth; if (_window3Flag == 1) { state->width = 0; @@ -755,15 +751,19 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) { state->y_skip = 0; } - src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); - dst = state->surf_addr; + const byte* src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); + byte* dst = state->surf_addr; state->draw_width *= 2; - h = state->draw_height; + uint h = state->draw_height; + const uint w = state->draw_width; + const byte paletteMod = state->paletteMod; do { - for (i = 0; i != state->draw_width; i++) - dst[i] = src[i] + state->paletteMod; + for (uint i = 0; i != w; i+=2) { + dst[i] = src[i] + paletteMod; + dst[i+1] = src[i+1] + paletteMod; + } dst += state->surf_pitch; src += state->width; } while (--h); -- cgit v1.2.3 From ff5f3730c57a81816e3bc2e3365c4fc30701ca1f Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Mon, 14 Jul 2008 21:00:39 +0000 Subject: Don't draw scumm saveload dialog while reflowing layout, as that would use uninitialized values svn-id: r33063 --- engines/scumm/dialogs.cpp | 33 +++++++++++++++++++++++---------- engines/scumm/dialogs.h | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'engines') diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 6d1cf1bbd8..89532b8961 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -31,6 +31,8 @@ #include "graphics/scaler.h" +#include "valgrind/memcheck.h" + #ifdef __DS__ #include "scummhelp.h" #endif @@ -297,7 +299,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da break; case GUI::kListSelectionChangedCmd: { if (_gfxWidget) { - updateInfos(); + updateInfos(true); } if (_saveMode) { @@ -326,6 +328,10 @@ void SaveLoadChooser::reflowLayout() { _container->resize(thumbX - hPad, thumbY - vPad, kThumbnailWidth + hPad * 2, thumbH + vPad * 2 + kLineHeight * 4); + VALGRIND_CHECK_VALUE_IS_DEFINED(thumbX); + VALGRIND_CHECK_VALUE_IS_DEFINED(thumbY); + VALGRIND_CHECK_VALUE_IS_DEFINED(thumbH); + // Add the thumbnail display _gfxWidget->resize(thumbX, thumbY, kThumbnailWidth, thumbH); @@ -350,7 +356,7 @@ void SaveLoadChooser::reflowLayout() { _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR"); _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG"); _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB"); - updateInfos(); + updateInfos(false); } else { _container->setFlags(GUI::WIDGET_INVISIBLE); _gfxWidget->setFlags(GUI::WIDGET_INVISIBLE); @@ -362,7 +368,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -void SaveLoadChooser::updateInfos() { +void SaveLoadChooser::updateInfos(bool draw) { int selItem = _list->getSelected(); Graphics::Surface *thumb; thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem); @@ -376,7 +382,8 @@ void SaveLoadChooser::updateInfos() { } delete thumb; - _gfxWidget->draw(); + if (draw) + _gfxWidget->draw(); InfoStuff infos; memset(&infos, 0, sizeof(InfoStuff)); @@ -386,12 +393,14 @@ void SaveLoadChooser::updateInfos() { (infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF, infos.date & 0xFFFF); _date->setLabel(buffer); - _date->draw(); + if (draw) + _date->draw(); snprintf(buffer, 32, "Time: %.2d:%.2d", (infos.time >> 8) & 0xFF, infos.time & 0xFF); _time->setLabel(buffer); - _time->draw(); + if (draw) + _time->draw(); int minutes = infos.playtime / 60; int hours = minutes / 60; @@ -400,19 +409,23 @@ void SaveLoadChooser::updateInfos() { snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours & 0xFF, minutes & 0xFF); _playtime->setLabel(buffer); - _playtime->draw(); + if (draw) + _playtime->draw(); } else { snprintf(buffer, 32, "No date saved"); _date->setLabel(buffer); - _date->draw(); + if (draw) + _date->draw(); snprintf(buffer, 32, "No time saved"); _time->setLabel(buffer); - _time->draw(); + if (draw) + _time->draw(); snprintf(buffer, 32, "No playtime saved"); _playtime->setLabel(buffer); - _playtime->draw(); + if (draw) + _playtime->draw(); } } diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index 7c99a0ebcc..730952676c 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -69,7 +69,7 @@ protected: uint8 _fillR, _fillG, _fillB; - void updateInfos(); + void updateInfos(bool draw); public: SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine); ~SaveLoadChooser(); -- cgit v1.2.3 From ba4ba85124d5cffdd75093abb6759f7588280f06 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Mon, 14 Jul 2008 21:04:42 +0000 Subject: remove accidentally committed debugging code; fix shadowing warning svn-id: r33064 --- engines/scumm/dialogs.cpp | 22 ++++++++-------------- engines/scumm/dialogs.h | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) (limited to 'engines') diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 89532b8961..e4e2b2b620 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -31,8 +31,6 @@ #include "graphics/scaler.h" -#include "valgrind/memcheck.h" - #ifdef __DS__ #include "scummhelp.h" #endif @@ -328,10 +326,6 @@ void SaveLoadChooser::reflowLayout() { _container->resize(thumbX - hPad, thumbY - vPad, kThumbnailWidth + hPad * 2, thumbH + vPad * 2 + kLineHeight * 4); - VALGRIND_CHECK_VALUE_IS_DEFINED(thumbX); - VALGRIND_CHECK_VALUE_IS_DEFINED(thumbY); - VALGRIND_CHECK_VALUE_IS_DEFINED(thumbH); - // Add the thumbnail display _gfxWidget->resize(thumbX, thumbY, kThumbnailWidth, thumbH); @@ -368,7 +362,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -void SaveLoadChooser::updateInfos(bool draw) { +void SaveLoadChooser::updateInfos(bool redraw) { int selItem = _list->getSelected(); Graphics::Surface *thumb; thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem); @@ -382,7 +376,7 @@ void SaveLoadChooser::updateInfos(bool draw) { } delete thumb; - if (draw) + if (redraw) _gfxWidget->draw(); InfoStuff infos; @@ -393,13 +387,13 @@ void SaveLoadChooser::updateInfos(bool draw) { (infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF, infos.date & 0xFFFF); _date->setLabel(buffer); - if (draw) + if (redraw) _date->draw(); snprintf(buffer, 32, "Time: %.2d:%.2d", (infos.time >> 8) & 0xFF, infos.time & 0xFF); _time->setLabel(buffer); - if (draw) + if (redraw) _time->draw(); int minutes = infos.playtime / 60; @@ -409,22 +403,22 @@ void SaveLoadChooser::updateInfos(bool draw) { snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours & 0xFF, minutes & 0xFF); _playtime->setLabel(buffer); - if (draw) + if (redraw) _playtime->draw(); } else { snprintf(buffer, 32, "No date saved"); _date->setLabel(buffer); - if (draw) + if (redraw) _date->draw(); snprintf(buffer, 32, "No time saved"); _time->setLabel(buffer); - if (draw) + if (redraw) _time->draw(); snprintf(buffer, 32, "No playtime saved"); _playtime->setLabel(buffer); - if (draw) + if (redraw) _playtime->draw(); } } diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index 730952676c..0d04d8faea 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -69,7 +69,7 @@ protected: uint8 _fillR, _fillG, _fillB; - void updateInfos(bool draw); + void updateInfos(bool redraw); public: SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine); ~SaveLoadChooser(); -- cgit v1.2.3 From 60357650e03c8504b06631bba3ca520285977f15 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 14 Jul 2008 23:10:51 +0000 Subject: Fix for bug #2016647 (FW: crash with italian amiga version). - Consists of a workaround for a script bug that used local variable 251 when it should've used global variable 251. - Also added a fix for a crash when failing copy protection in Amiga or Atari ST versions of Future Wars. NOTE: That any of the Amiga or Atari ST versions of Future Wars haven't crashed right in the beginning before seems like plain luck because accessing local variable 251 is out of bounds! svn-id: r33068 --- engines/cine/cine.h | 1 + engines/cine/prc.cpp | 9 ++++++--- engines/cine/prc.h | 2 +- engines/cine/script_fw.cpp | 14 ++++++++++++++ engines/cine/various.cpp | 14 ++++++++++++-- 5 files changed, 34 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 710840c17e..7568d8310e 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -107,6 +107,7 @@ private: extern CineEngine *g_cine; #define BOOT_PRC_NAME "AUTO00.PRC" +#define COPY_PROT_FAIL_PRC_NAME "L201.ANI" enum { VAR_MOUSE_X_MODE = 253, diff --git a/engines/cine/prc.cpp b/engines/cine/prc.cpp index 402c97b1a6..27b1044620 100644 --- a/engines/cine/prc.cpp +++ b/engines/cine/prc.cpp @@ -40,8 +40,9 @@ ScriptList objectScripts; /*! \todo Is script size of 0 valid? * \todo Fix script dump code + * @return Was the loading successful? */ -void loadPrc(const char *pPrcName) { +bool loadPrc(const char *pPrcName) { byte i; uint16 numScripts; byte *scriptPtr, *dataPtr; @@ -52,9 +53,9 @@ void loadPrc(const char *pPrcName) { scriptTable.clear(); // This is copy protection. Used to hang the machine - if (!scumm_stricmp(pPrcName, "L201.ANI")) { + if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) { exitEngine = 1; - return; + return false; } checkDataDisk(-1); @@ -107,6 +108,8 @@ void loadPrc(const char *pPrcName) { } } #endif + + return true; } } // End of namespace Cine diff --git a/engines/cine/prc.h b/engines/cine/prc.h index f5129d28b1..05bb240372 100644 --- a/engines/cine/prc.h +++ b/engines/cine/prc.h @@ -31,7 +31,7 @@ namespace Cine { extern ScriptList globalScripts; extern ScriptList objectScripts; -void loadPrc(const char *pPrcName); +bool loadPrc(const char *pPrcName); } // End of namespace Cine diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 148e673095..54a4976000 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1019,6 +1019,20 @@ int FWScript::o1_divVar() { } int FWScript::o1_compareVar() { + // WORKAROUND: A workaround for a script bug in script file CODE2.PRC + // in at least some of the Amiga and Atari ST versions of Future Wars. + // Fixes bug #2016647 (FW: crash with italian amiga version). A local + // variable 251 is compared against value 0 although it's quite apparent + // from the context in the script that instead global variable 251 should + // be compared against value 0. So looks like someone made a typo when + // making the scripts. Therefore we change that particular comparison + // from using the local variable 251 to using the global variable 251. + if (g_cine->getGameType() == Cine::GType_FW && scumm_stricmp(currentPrcName, "CODE2.PRC") == 0 && + (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) && + _script.getByte(_pos) == 251 && _script.getByte(_pos + 1) == 0 && _script.getWord(_pos + 2) == 0) { + return o1_compareGlobalVar(); + } + byte varIdx = getNextByte(); byte varType = getNextByte(); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 4b5d4efe13..69851aeff2 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1518,12 +1518,22 @@ void mainLoopSub6(void) { void checkForPendingDataLoad(void) { if (newPrcName[0] != 0) { - loadPrc(newPrcName); + bool loadPrcOk = loadPrc(newPrcName); strcpy(currentPrcName, newPrcName); strcpy(newPrcName, ""); - addScriptToList0(1); + // Check that the loading of the script file was successful before + // trying to add script 1 from it to the global scripts list. This + // fixes a crash when failing copy protection in Amiga or Atari ST + // versions of Future Wars. + if (loadPrcOk) { + addScriptToList0(1); + } else if (scumm_stricmp(currentPrcName, COPY_PROT_FAIL_PRC_NAME)) { + // We only show an error here for other files than the file that + // is loaded if copy protection fails (i.e. L201.ANI). + warning("checkForPendingDataLoad: loadPrc(%s) failed", currentPrcName); + } } if (newRelName[0] != 0) { -- cgit v1.2.3 From 551f6d71c3821fac0f9245ed667c8547e05d6778 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 15 Jul 2008 10:59:58 +0000 Subject: Made frame unpacking buffer dynamic (this frees some BSS space). svn-id: r33072 --- engines/parallaction/gfxbase.cpp | 3 --- engines/parallaction/graphics.cpp | 10 ++++++++++ engines/parallaction/graphics.h | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 9e7eb12ed8..e8250ac8fd 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -267,9 +267,6 @@ void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte } -// this is the maximum size of an unpacked frame in BRA -byte _unpackedBitmap[640*401]; - #if 0 void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 32d0e303eb..9b9ea8605a 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -33,6 +33,11 @@ namespace Parallaction { +// this is the size of the receiving buffer for unpacked frames, +// since BRA uses some insanely big animations. +#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401 + + void Gfx::registerVar(const Common::String &name, int32 initialValue) { if (_vars.contains(name)) { warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str()); @@ -752,6 +757,9 @@ Gfx::Gfx(Parallaction* vm) : _halfbrite = false; _hbCircleRadius = 0; + _unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE]; + assert(_unpackedBitmap); + registerVar("background_mode", 1); _varBackgroundMode = 1; @@ -769,6 +777,8 @@ Gfx::~Gfx() { freeBackground(); freeLabels(); + delete []_unpackedBitmap; + return; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 09f4b2f244..a7242ba6f4 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -547,6 +547,8 @@ public: uint _screenX; // scrolling position uint _screenY; + byte *_unpackedBitmap; + protected: Parallaction* _vm; bool _halfbrite; -- cgit v1.2.3 From 2bae0df17e2c2a77295b13b107b208e63147638d Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Tue, 15 Jul 2008 20:26:12 +0000 Subject: fix bug #1995042: stop previous sfx playback when starting a new sfx (matches original dos code). Also removed the "sound skipping" hack in final bam scene. svn-id: r33078 --- engines/queen/graphics.cpp | 11 ++--------- engines/queen/graphics.h | 4 ---- engines/queen/sound.cpp | 13 +++++++------ engines/queen/sound.h | 1 - 4 files changed, 9 insertions(+), 20 deletions(-) (limited to 'engines') diff --git a/engines/queen/graphics.cpp b/engines/queen/graphics.cpp index f863f7663c..6d0a11ccfe 100644 --- a/engines/queen/graphics.cpp +++ b/engines/queen/graphics.cpp @@ -1175,15 +1175,8 @@ BamScene::BamScene(QueenEngine *vm) } void BamScene::playSfx() { - // Don't try to play all the sounds. This is only necessary for the - // fight bam, in which the number of 'sfx bam frames' is too much - // important / too much closer. The original game does not have - // this problem since its playSfx() function returns immediately - // if a sound is already being played. - if (_lastSoundIndex == 0 || _index - _lastSoundIndex >= SFX_SKIP) { - _vm->sound()->playSfx(_vm->logic()->currentRoomSfx()); - _lastSoundIndex = _index; - } + _vm->sound()->playSfx(_vm->logic()->currentRoomSfx()); + _lastSoundIndex = _index; } void BamScene::prepareAnimation() { diff --git a/engines/queen/graphics.h b/engines/queen/graphics.h index 6f00111635..7eadf9a191 100644 --- a/engines/queen/graphics.h +++ b/engines/queen/graphics.h @@ -248,10 +248,6 @@ public: F_REQ_STOP = 2 }; - enum { - SFX_SKIP = 8 - }; - uint16 _flag, _index; private: diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index d70fe7209d..3672eecce8 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -229,11 +229,6 @@ void PCSound::setVolume(int vol) { _music->setVolume(vol); } -void PCSound::waitFinished(bool isSpeech) { - while (_mixer->isSoundHandleActive(isSpeech ? _speechHandle : _sfxHandle)) - _vm->input()->delay(10); -} - void PCSound::playSound(const char *base, bool isSpeech) { char name[13]; strcpy(name, base); @@ -243,7 +238,13 @@ void PCSound::playSound(const char *base, bool isSpeech) { name[i] = '0'; } strcat(name, ".SB"); - waitFinished(isSpeech); + if (isSpeech) { + while (_mixer->isSoundHandleActive(_speechHandle)) { + _vm->input()->delay(10); + } + } else { + _mixer->stopHandle(_sfxHandle); + } uint32 size; Common::File *f = _vm->resource()->findSound(name, &size); if (f) { diff --git a/engines/queen/sound.h b/engines/queen/sound.h index c2c1481cc6..331034f746 100644 --- a/engines/queen/sound.h +++ b/engines/queen/sound.h @@ -143,7 +143,6 @@ public: void setVolume(int vol); protected: - void waitFinished(bool isSpeech); void playSound(const char *base, bool isSpeech); virtual void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) = 0; -- cgit v1.2.3 From cdade7eff3e481ef7aca404ca13138cccd920365 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Tue, 15 Jul 2008 20:31:11 +0000 Subject: fix bug #1876741: changed .SB playback rate to 11840Hz (matches dos game) svn-id: r33079 --- engines/queen/sound.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index 3672eecce8..f4e0116cf1 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -256,6 +256,8 @@ void PCSound::playSound(const char *base, bool isSpeech) { } void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { + // In order to simplify the code, we don't parse the .sb header but hard-code the + // values. Refer to tracker item #1876741 for details on the format/fields. int headerSize; f->seek(2, SEEK_CUR); uint16 version = f->readUint16LE(); @@ -277,7 +279,7 @@ void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *so if (sound) { f->read(sound, size); byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; - _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11025, flags); + _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11840, flags); } } -- cgit v1.2.3 From bd17a600dcf86255be4e5d7d359b190e4b1351b1 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Wed, 16 Jul 2008 09:08:44 +0000 Subject: Split the drawVertImage function in the agos engine to make it clearer and easier to profile svn-id: r33083 --- engines/agos/agos.h | 2 + engines/agos/gfx.cpp | 103 ++++++++++++++++++++++++++++----------------------- 2 files changed, 59 insertions(+), 46 deletions(-) (limited to 'engines') diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 74a0b026e9..8ad5487b35 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -1075,6 +1075,8 @@ protected: virtual void drawImage(VC10_state *state); void drawBackGroundImage(VC10_state *state); void drawVertImage(VC10_state *state); + void drawVertImageCompressed(VC10_state *state); + void drawVertImageUncompressed(VC10_state *state); void setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height); diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 2d7d6641dc..6e91c5d94c 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -771,63 +771,74 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) { void AGOSEngine::drawVertImage(VC10_state *state) { if (state->flags & kDFCompressed) { - uint w, h; - byte *src, *dst, *dstPtr; + drawVertImageCompressed(state); + } else { + drawVertImageUncompressed(state); + } +} - state->x_skip *= 4; /* reached */ +void AGOSEngine::drawVertImageUncompressed(VC10_state *state) { + assert ((state->flags & kDFCompressed) == 0) ; - state->dl = state->width; - state->dh = state->height; + const byte *src; + byte *dst; + uint count; - vc10_skip_cols(state); + src = state->srcPtr + (state->width * state->y_skip) * 8; + dst = state->surf_addr; + state->x_skip *= 4; - dstPtr = state->surf_addr; - if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ - dstPtr += vcReadVar(252); - } - w = 0; - do { + do { + for (count = 0; count != state->draw_width; count++) { byte color; + color = (src[count + state->x_skip] / 16) + state->paletteMod; + if ((state->flags & kDFNonTrans) || color) + dst[count * 2] = color | state->palette; + color = (src[count + state->x_skip] & 15) + state->paletteMod; + if ((state->flags & kDFNonTrans) || color) + dst[count * 2 + 1] = color | state->palette; + } + dst += state->surf_pitch; + src += state->width * 8; + } while (--state->draw_height); +} - src = vc10_depackColumn(state); - dst = dstPtr; +void AGOSEngine::drawVertImageCompressed(VC10_state *state) { + assert (state->flags & kDFCompressed) ; + uint w, h; + byte *src, *dst, *dstPtr; - h = 0; - do { - color = (*src / 16); - if ((state->flags & kDFNonTrans) || color != 0) - dst[0] = color | state->palette; - color = (*src & 15); - if ((state->flags & kDFNonTrans) || color != 0) - dst[1] = color | state->palette; - dst += state->surf_pitch; - src++; - } while (++h != state->draw_height); - dstPtr += 2; - } while (++w != state->draw_width); - } else { - const byte *src; - byte *dst; - uint count; + state->x_skip *= 4; /* reached */ - src = state->srcPtr + (state->width * state->y_skip) * 8; - dst = state->surf_addr; - state->x_skip *= 4; + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + dstPtr = state->surf_addr; + if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ + dstPtr += vcReadVar(252); + } + w = 0; + do { + byte color; + + src = vc10_depackColumn(state); + dst = dstPtr; + + h = 0; do { - for (count = 0; count != state->draw_width; count++) { - byte color; - color = (src[count + state->x_skip] / 16) + state->paletteMod; - if ((state->flags & kDFNonTrans) || color) - dst[count * 2] = color | state->palette; - color = (src[count + state->x_skip] & 15) + state->paletteMod; - if ((state->flags & kDFNonTrans) || color) - dst[count * 2 + 1] = color | state->palette; - } + color = (*src / 16); + if ((state->flags & kDFNonTrans) || color != 0) + dst[0] = color | state->palette; + color = (*src & 15); + if ((state->flags & kDFNonTrans) || color != 0) + dst[1] = color | state->palette; dst += state->surf_pitch; - src += state->width * 8; - } while (--state->draw_height); - } + src++; + } while (++h != state->draw_height); + dstPtr += 2; + } while (++w != state->draw_width); } void AGOSEngine::drawImage(VC10_state *state) { -- cgit v1.2.3 From 17d86414cb5d7c2b4c5159b5b5d1b2330fa8eb83 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 17 Jul 2008 00:38:11 +0000 Subject: Fixed regression bug in dialogue, which de-facto allowed user to skip in-game protection. svn-id: r33086 --- engines/parallaction/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 6e91dd8a88..6d9dfa5e10 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -166,7 +166,7 @@ bool DialogueManager::displayAnswer(uint16 i) { assert(id >= 0); _visAnswers[id] = i; - _askPassword = (strstr(a->_text, "%p") != NULL); + _askPassword = (strstr(a->_text, "%P") != NULL); _numVisAnswers++; return true; -- cgit v1.2.3 From 67bef188d3977478c7d57b4016885c9293642cd2 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Thu, 17 Jul 2008 07:13:41 +0000 Subject: Patch #2019455: Patch for reducing the BSS size of Cine engine. svn-id: r33087 --- engines/cine/cine.h | 1 + engines/cine/gfx.cpp | 4 ++-- engines/cine/texte.cpp | 10 ++++------ engines/cine/texte.h | 5 ++++- 4 files changed, 11 insertions(+), 9 deletions(-) (limited to 'engines') diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 7568d8310e..06f2dfd982 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -94,6 +94,7 @@ public: Common::StringList _volumeResourceFiles; StringPtrHashMap _volumeEntriesMap; + TextHandler _textHandler; private: void initialize(void); diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 2b7f3b8890..1f868ccb75 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -337,7 +337,7 @@ int FWRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { idx = fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw(textTable[idx][0], textTable[idx][1], 16, 8, _backBuffer, x, y); + drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); x += width + 1; } @@ -938,7 +938,7 @@ int OSRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { idx = fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw2(textTable[idx][0], 0, 16, 8, _backBuffer, x, y); + drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); x += width + 1; } diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index 9b4b83f420..e4fd334926 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -31,8 +31,6 @@ namespace Cine { byte *textDataPtr; -byte textTable[256][2][16 * 8]; - const char **failureMessages; const CommandeType *defaultActionCommand; const CommandeType *systemMenu; @@ -77,14 +75,14 @@ void loadTextData(const char *pFileName, byte *pDestinationBuffer) { loadRelatedPalette(pFileName); for (i = 0; i < numCharacters; i++) { - gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 16, 8); - generateMask(textTable[i][0], textTable[i][1], 16 * 8, 0); + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 16, 8); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 16 * 8, 0); tempBuffer += dataSize; } } else { for (i = 0; i < 90; i++) { - gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 8, 8); - generateMask(textTable[i][0], textTable[i][1], 8 * 8, 0); + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 8, 8); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 8 * 8, 0); tempBuffer += 0x40; } } diff --git a/engines/cine/texte.h b/engines/cine/texte.h index ae82832aea..f471c3c49e 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -34,7 +34,10 @@ namespace Cine { typedef char CommandeType[20]; extern byte *textDataPtr; -extern byte textTable[256][2][16 * 8]; + +struct TextHandler { + byte textTable[256][2][16 * 8]; +}; extern const char **failureMessages; extern const CommandeType *defaultActionCommand; -- cgit v1.2.3 From 702e26965c48e99490c25ca635e41c14ac88add2 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Fri, 18 Jul 2008 04:16:00 +0000 Subject: Don't crash if you try to use music file #2 as music file #1. When the music wasn't found, it would close the file even if something else was already playing from it. (Some music is in both files.) svn-id: r33094 --- engines/sword2/music.cpp | 21 ++++++++++++++------- engines/sword2/sound.h | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/sword2/music.cpp b/engines/sword2/music.cpp index fd72ba8d52..3b5a09578b 100644 --- a/engines/sword2/music.cpp +++ b/engines/sword2/music.cpp @@ -52,9 +52,11 @@ namespace Sword2 { static Audio::AudioStream *makeCLUStream(Common::File *fp, int size); static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) { - debug(3, "Playing %s from CD %d", base, cd); + bool alreadyOpen; if (!fh->file.isOpen()) { + alreadyOpen = false; + struct { const char *ext; int mode; @@ -75,16 +77,14 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, char filename[20]; for (int i = 0; i < ARRAYSIZE(file_types); i++) { - Common::File f; - sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext); - if (f.open(filename)) { + if (Common::File::exists(filename)) { soundMode = file_types[i].mode; break; } sprintf(filename, "%s.%s", base, file_types[i].ext); - if (f.open(filename)) { + if (Common::File::exists(filename)) { soundMode = file_types[i].mode; break; } @@ -105,7 +105,8 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, fh->idxTab = NULL; } } - } + } else + alreadyOpen = true; uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3; @@ -134,7 +135,13 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, *numSamples = len; if (!pos || !len) { - fh->file.close(); + // We couldn't find the sound. Possibly as a result of a bad + // installation (e.g. using the music file from CD 2 as the + // first music file). Don't close the file if it was already + // open though, because something is playing from it. + warning("getAudioStream: Could not find %s ID %d! Possibly the wrong file", base, id); + if (!alreadyOpen) + fh->file.close(); return NULL; } diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h index 70bae6f851..b89ef8f12b 100644 --- a/engines/sword2/sound.h +++ b/engines/sword2/sound.h @@ -106,7 +106,7 @@ private: void refill(); inline bool eosIntern() const { - return _pos >= _bufferEnd; + return !_file->isOpen() || _pos >= _bufferEnd; } public: -- cgit v1.2.3 From 8757326b5f2b464ddc6cc2b523f573c31a191ad3 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Fri, 18 Jul 2008 14:01:53 +0000 Subject: Added savefile position comments to savegame loading routine (Helpful for debugging the formats). svn-id: r33096 --- engines/cine/various.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 69851aeff2..ab2fa645c7 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -466,17 +466,26 @@ bool CineEngine::makeLoad(char *saveName) { broken = brokenSave(*fHandle); + // At savefile position 0x0000: currentDisk = fHandle->readUint16BE(); + // At 0x0002: fHandle->read(currentPartName, 13); + // At 0x000F: fHandle->read(currentDatName, 13); + // At 0x001C: saveVar2 = fHandle->readSint16BE(); + // At 0x001E: fHandle->read(currentPrcName, 13); + // At 0x002B: fHandle->read(currentRelName, 13); + // At 0x0038: fHandle->read(currentMsgName, 13); + // At 0x0045: fHandle->read(bgName, 13); + // At 0x0052: fHandle->read(currentCtName, 13); checkDataDisk(currentDisk); @@ -501,52 +510,84 @@ bool CineEngine::makeLoad(char *saveName) { loadCtFW(currentCtName); } + // At 0x005F: fHandle->readUint16BE(); + // At 0x0061: fHandle->readUint16BE(); + // At 0x0063: for (i = 0; i < 255; i++) { + // At 0x0063 + i * 32 + 0: objectTable[i].x = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 2: objectTable[i].y = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 4: objectTable[i].mask = fHandle->readUint16BE(); + // At 0x0063 + i * 32 + 6: objectTable[i].frame = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 8: objectTable[i].costume = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 10: fHandle->read(objectTable[i].name, 20); + // At 0x0063 + i * 32 + 30: objectTable[i].part = fHandle->readUint16BE(); } + // At 0x2043 (i.e. 0x0063 + 255 * 32): renderer->restorePalette(*fHandle); + // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): globalVars.load(*fHandle, NUM_MAX_VAR - 1); + // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { + // At 0x2281 + i * 2: zoneData[i] = fHandle->readUint16BE(); } + // At 0x22A1 (i.e. 0x2281 + 16 * 2): for (i = 0; i < 4; i++) { + // At 0x22A1 + i * 2: commandVar3[i] = fHandle->readUint16BE(); } + // At 0x22A9 (i.e. 0x22A1 + 4 * 2): fHandle->read(commandBuffer, 0x50); renderer->setCommand(commandBuffer); + // At 0x22F9 (i.e. 0x22A9 + 0x50): renderer->_cmdY = fHandle->readUint16BE(); + // At 0x22FB: bgVar0 = fHandle->readUint16BE(); + // At 0x22FD: allowPlayerInput = fHandle->readUint16BE(); + // At 0x22FF: playerCommand = fHandle->readSint16BE(); + // At 0x2301: commandVar1 = fHandle->readSint16BE(); + // At 0x2303: isDrawCommandEnabled = fHandle->readUint16BE(); + // At 0x2305: var5 = fHandle->readUint16BE(); + // At 0x2307: var4 = fHandle->readUint16BE(); + // At 0x2309: var3 = fHandle->readUint16BE(); + // At 0x230B: var2 = fHandle->readUint16BE(); + // At 0x230D: commandVar2 = fHandle->readSint16BE(); + // At 0x230F: renderer->_messageBg = fHandle->readUint16BE(); + // At 0x2311: fHandle->readUint16BE(); + // At 0x2313: fHandle->readUint16BE(); + // At 0x2315: loadResourcesFromSave(*fHandle, broken); // TODO: handle screen params (really required ?) -- cgit v1.2.3 From a49a3c6aaa31e3a59c0fa2fec87f82764e6c2bc2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 20 Jul 2008 16:27:12 +0000 Subject: cleanup svn-id: r33135 --- engines/scumm/imuse_digi/dimuse_sndmgr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp index 1511b9aefc..b18b0ba70f 100644 --- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -102,10 +102,10 @@ void ImuseDigiSndMgr::prepareSoundFromRMAP(Common::File *file, SoundDesc *sound, int32 version = file->readUint32BE(); if (version != 3) { if (version == 2) { - warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2."); - warning("Suggested to recompress with latest tool from daily builds."); + warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2"); + warning("Suggested to recompress with latest tool from daily builds"); } else - error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d.", version); + error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d", version); } sound->bits = file->readUint32BE(); sound->freq = file->readUint32BE(); -- cgit v1.2.3 From 2354ea80c6ec0da27594fab91b8dc0e1439cff56 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 20 Jul 2008 18:00:00 +0000 Subject: KYRA: disable incomplete PC-98 audio support for 0.12.0 release (use towns audio instead) svn-id: r33145 --- engines/kyra/kyra_v1.cpp | 2 +- engines/kyra/sound_towns.cpp | 6 +++--- engines/kyra/staticres.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 117194aea2..85c03dc1bb 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -114,7 +114,7 @@ int KyraEngine_v1::init() { _sound = new SoundTownsPC98_v2(this, _mixer); } else if (_flags.platform == Common::kPlatformPC98) { if (_flags.gameID == GI_KYRA1) - _sound = new SoundPC98(this, _mixer); + _sound = new SoundTowns/*SoundPC98*/(this, _mixer); else _sound = new SoundTownsPC98_v2(this, _mixer); } else if (midiDriver == MD_ADLIB) { diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index e96cef735c..0f2b916c9d 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -2363,7 +2363,7 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { setTempo(84); - _baserate = (3579545.0 / (double)getRate()) / 144.0; + _baserate = (double)getRate() / 10368.0; } TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { @@ -3095,8 +3095,8 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() { } bool SoundTownsPC98_v2::init() { - _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? - TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); + _driver = new TownsPC98_OpnDriver(_mixer, /*_vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_OpnDriver::OD_TYPE86 :*/ TownsPC98_OpnDriver::OD_TOWNS); _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 4f577c1d1e..03b832bf79 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1060,7 +1060,7 @@ void KyraEngine_LoK::initStaticResource() { else if (_flags.platform == Common::kPlatformFMTowns) _soundData = soundData_TOWNS; else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_PC98; + _soundData = soundData_TOWNS/*soundData_PC98*/; } @@ -1286,7 +1286,7 @@ void KyraEngine_HoF::initStaticResource() { else if (_flags.platform == Common::kPlatformFMTowns) _soundData = soundData_TOWNS; else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_PC98; + _soundData = soundData_TOWNS/*soundData_PC98*/; // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); -- cgit v1.2.3 From 0b8602f9950dcc6e6f11b719786244094564bb8e Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Sun, 20 Jul 2008 19:25:16 +0000 Subject: Commented out some more PC-98 audio stuff, to avoid warnings. svn-id: r33146 --- engines/kyra/staticres.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'engines') diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 03b832bf79..c05795dacd 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1034,8 +1034,10 @@ void KyraEngine_LoK::initStaticResource() { } // audio data tables +#if 0 static const char *tIntro98[] = { "intro%d.dat" }; static const char *tIngame98[] = { "kyram%d.dat" }; +#endif static const AudioDataStruct soundData_PC[] = { { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, @@ -1049,11 +1051,13 @@ void KyraEngine_LoK::initStaticResource() { { 0, 0, 0, 0} }; +#if 0 static const AudioDataStruct soundData_PC98[] = { { tIntro98, 1, 0, 0 }, { tIngame98, 1, 0, 0 }, { 0, 0, 0, 0} }; +#endif if (_flags.platform == Common::kPlatformPC) _soundData = soundData_PC; @@ -1259,9 +1263,11 @@ void KyraEngine_HoF::initStaticResource() { static const char *fmtMusicFileListFinale[] = { "finale%d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; +#if 0 static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; +#endif static const AudioDataStruct soundData_PC[] = { { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, @@ -1275,11 +1281,13 @@ void KyraEngine_HoF::initStaticResource() { { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } }; +#if 0 static const AudioDataStruct soundData_PC98[] = { { pc98MusicFileListIntro, 1, 0, 0 }, { pc98MusicFileListIngame, 1, 0, 0 }, { pc98MusicFileListFinale, 1, 0, 0 } }; +#endif if (_flags.platform == Common::kPlatformPC) _soundData = soundData_PC; -- cgit v1.2.3 From 361bed0a9535104611d3e0e88d5b3e1ad788639d Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 21 Jul 2008 06:08:30 +0000 Subject: Massive refactoring of dialogue code, which is now implemented as a finite state machine. Related code in other files has been updated has well. svn-id: r33162 --- engines/parallaction/dialogue.cpp | 384 +++++++++++++++++++------------ engines/parallaction/exec_ns.cpp | 17 +- engines/parallaction/input.cpp | 11 + engines/parallaction/input.h | 5 +- engines/parallaction/parallaction.cpp | 35 +-- engines/parallaction/parallaction.h | 12 +- engines/parallaction/parallaction_br.cpp | 12 +- 7 files changed, 300 insertions(+), 176 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 6d9dfa5e10..290f8cfd4f 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -42,13 +42,23 @@ namespace Parallaction { #define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_Y 80 + class DialogueManager { + enum { + RUN_QUESTION, + RUN_ANSWER, + NEXT_QUESTION, + NEXT_ANSWER, + DIALOGUE_OVER + } _state; + Parallaction *_vm; - SpeakData *_data; Dialogue *_dialogue; bool _askPassword; + int _passwordLen; + bool _passwordChanged; bool isNpc; GfxObj *_questioner; @@ -59,98 +69,70 @@ class DialogueManager { uint16 _visAnswers[5]; int _numVisAnswers; + int _answerId; + + int _selection, _oldSelection; + + uint32 _mouseButtons; + Common::Point _mousePos; + bool _isKeyDown; + uint16 _downKey; + + public: - DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) { - _dialogue = _data->_dialogue; - isNpc = scumm_stricmp(_data->_name, "yourself") && _data->_name[0] != '\0'; - _questioner = isNpc ? _vm->_disk->loadTalk(_data->_name) : _vm->_char._talk; - _answerer = _vm->_char._talk; - } + DialogueManager(Parallaction *vm, ZonePtr z); + ~DialogueManager(); - ~DialogueManager() { - if (isNpc) { - delete _questioner; - } + bool isOver() { + return _state == DIALOGUE_OVER; } - void run(); + ZonePtr _z; + CommandList *_cmdList; + protected: - void displayQuestion(); + bool displayQuestion(); bool displayAnswers(); bool displayAnswer(uint16 i); - uint16 getAnswer(); - int16 selectAnswer(); - uint16 askPassword(); + int16 selectAnswer1(); + int16 selectAnswerN(); + int16 askPassword(); int16 getHoverAnswer(int16 x, int16 y); -}; - -uint16 DialogueManager::askPassword() { - debugC(3, kDebugExec, "checkDialoguePassword()"); - - uint16 passwordLen = 0; - _password[0] = '\0'; - - _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); - _vm->_gfx->setItemFrame(id, 0); - - Common::Event e; - bool changed = true; // force first refresh - - while (true) { - e.kbd.ascii = 0; - - if (g_system->getEventManager()->pollEvent(e)) { - if (e.type == Common::EVENT_QUIT) { - _engineFlags |= kEngineQuit; - break; - } - - if ((e.type == Common::EVENT_KEYDOWN) && isdigit(e.kbd.ascii)) { - _password[passwordLen] = e.kbd.ascii; - passwordLen++; - _password[passwordLen] = '\0'; - changed = true; - } - } - - if (changed) { - _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); - _vm->_gfx->updateScreen(); - changed = false; - } - - if ((passwordLen == MAX_PASSWORD_LENGTH) || (e.kbd.ascii == Common::KEYCODE_RETURN)) { + void runQuestion(); + void runAnswer(); + void nextQuestion(); + void nextAnswer(); - if ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) || - (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) || - (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))) { + bool checkPassword(); + void resetPassword(); + void accumPassword(uint16 ascii); +}; - break; +DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) { + _dialogue = _z->u.speak->_dialogue; + isNpc = scumm_stricmp(_z->u.speak->_name, "yourself") && _z->u.speak->_name[0] != '\0'; + _questioner = isNpc ? _vm->_disk->loadTalk(_z->u.speak->_name) : _vm->_char._talk; + _answerer = _vm->_char._talk; - } else { - passwordLen = 0; - _password[0] = '\0'; - changed = true; - } + _askPassword = false; + _q = _dialogue->_questions[0]; - } + _cmdList = 0; + _answerId = 0; - g_system->delayMillis(20); + _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER; +} +DialogueManager::~DialogueManager() { + if (isNpc) { + delete _questioner; } - - _vm->hideDialogueStuff(); - - return 0; - + _z = nullZonePtr; } - - bool DialogueManager::displayAnswer(uint16 i) { Answer *a = _q->_answers[i]; @@ -183,134 +165,242 @@ bool DialogueManager::displayAnswers() { displayAnswer(i); } + if (_askPassword) { + resetPassword(); +// _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, 0); + } else + if (_numVisAnswers == 1) { + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); + _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); + } else + if (_numVisAnswers > 1) { + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, _q->_answers[_visAnswers[0]]->_mood & 0xF); + _oldSelection = -1; + _selection = 0; + } + return _numVisAnswers > 0; } -void DialogueManager::displayQuestion() { - - if (!scumm_stricmp(_q->_text, "NULL")) return; +bool DialogueManager::displayQuestion() { + if (!scumm_stricmp(_q->_text, "NULL")) return false; _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); - _vm->_gfx->updateScreen(); - _vm->_input->waitUntilLeftClick(); - _vm->hideDialogueStuff(); - - return; + return true; } -uint16 DialogueManager::getAnswer() { - uint16 answer = 0; +bool DialogueManager::checkPassword() { + return ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) || + (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) || + (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))); +} - if (_askPassword == false) { - answer = selectAnswer(); - } else { - answer = askPassword(); - } +void DialogueManager::resetPassword() { + _passwordLen = 0; + _password[0] = '\0'; + _passwordChanged = true; +} - debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer); +void DialogueManager::accumPassword(uint16 ascii) { + if (!isdigit(ascii)) { + return; + } - return answer; + _password[_passwordLen] = ascii; + _passwordLen++; + _password[_passwordLen] = '\0'; + _passwordChanged = true; } -void DialogueManager::run() { +int16 DialogueManager::askPassword() { - _askPassword = false; - CommandList *cmdlist = NULL; + if (_isKeyDown) { + accumPassword(_downKey); + } - _q = _dialogue->_questions[0]; - int16 answer; + if (_passwordChanged) { + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); + _passwordChanged = false; + } - while (_q) { + if ((_passwordLen == MAX_PASSWORD_LENGTH) || ((_isKeyDown) && (_downKey == Common::KEYCODE_RETURN))) { + if (checkPassword()) { + return 0; + } else { + resetPassword(); + } + } - answer = 0; + return -1; +} - displayQuestion(); +int16 DialogueManager::selectAnswer1() { - if (_engineFlags & kEngineQuit) - return; + if (_mouseButtons == kMouseLeftUp) { + return 0; + } - if (_q->_answers[0] == NULL) break; + return -1; +} - if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) { - if (!displayAnswers()) break; - answer = getAnswer(); +int16 DialogueManager::selectAnswerN() { - if (_engineFlags & kEngineQuit) - return; + _selection = _vm->_balloonMan->hitTestDialogueBalloon(_mousePos.x, _mousePos.y); - cmdlist = &_q->_answers[answer]->_commands; + if (_selection != _oldSelection) { + if (_oldSelection != -1) { + _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3); } - _q = _q->_answers[answer]->_following._question; + if (_selection != -1) { + _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0); + _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF); + } } - if (cmdlist) - _vm->_cmdExec->run(*cmdlist); + _oldSelection = _selection; + + if ((_mouseButtons == kMouseLeftUp) && (_selection != -1)) { + return _visAnswers[_selection]; + } + return -1; } -int16 DialogueManager::selectAnswer() { +void DialogueManager::runQuestion() { + debugC(9, kDebugDialogue, "runQuestion\n"); - int16 numAvailableAnswers = _numVisAnswers; + if (_mouseButtons == kMouseLeftUp) { + _vm->hideDialogueStuff(); + _state = NEXT_ANSWER; + } + +} + + +void DialogueManager::nextAnswer() { + debugC(9, kDebugDialogue, "nextAnswer\n"); - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); - _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); + if (_q->_answers[0] == NULL) { + _state = DIALOGUE_OVER; + return; + } + + if (!scumm_stricmp(_q->_answers[0]->_text, "NULL")) { + _answerId = 0; + _state = NEXT_QUESTION; + return; + } + + _state = displayAnswers() ? RUN_ANSWER : DIALOGUE_OVER; +} - if (numAvailableAnswers == 1) { - _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 0); - _vm->_input->waitUntilLeftClick(); +void DialogueManager::runAnswer() { + debugC(9, kDebugDialogue, "runAnswer\n"); + + if (_askPassword) { + _answerId = askPassword(); + } else + if (_numVisAnswers == 1) { + _answerId = selectAnswer1(); + } else { + _answerId = selectAnswerN(); + } + + if (_answerId != -1) { + _cmdList = &_q->_answers[_answerId]->_commands; _vm->hideDialogueStuff(); - return 0; + _state = NEXT_QUESTION; } +} - int oldSelection = -1; - int selection = 0; +void DialogueManager::nextQuestion() { + debugC(9, kDebugDialogue, "nextQuestion\n"); - uint32 event; - Common::Point p; - while ((_engineFlags & kEngineQuit) == 0) { + _q = _q->_answers[_answerId]->_following._question; + if (_q == 0) { + _state = DIALOGUE_OVER; + } else { + _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER; + } +} - _vm->_input->readInput(); - _vm->_input->getCursorPos(p); - event = _vm->_input->getLastButtonEvent(); - selection = _vm->_balloonMan->hitTestDialogueBalloon(p.x, p.y); - if (selection != oldSelection) { - if (oldSelection != -1) { - _vm->_balloonMan->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); - } +void DialogueManager::run() { - if (selection != -1) { - _vm->_balloonMan->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); - _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF); - } - } + // cache event data + _mouseButtons = _vm->_input->getLastButtonEvent(); + _vm->_input->getCursorPos(_mousePos); + _isKeyDown = _vm->_input->getLastKeyDown(_downKey); - if ((selection != -1) && (event == kMouseLeftUp)) { - break; + switch (_state) { + case RUN_QUESTION: + runQuestion(); + break; + + case NEXT_ANSWER: + nextAnswer(); + break; + + case NEXT_QUESTION: + nextQuestion(); + break; + + case RUN_ANSWER: + runAnswer(); + break; + + case DIALOGUE_OVER: + if (_cmdList) { + _vm->_cmdExec->run(*_cmdList); } + break; - _vm->_gfx->updateScreen(); - g_system->delayMillis(20); + default: + error("unknown state in DialogueManager"); - oldSelection = selection; } - _vm->hideDialogueStuff(); +} - return _visAnswers[selection]; +void Parallaction::enterDialogueMode(ZonePtr z) { + debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u.speak->_name); + _dialogueMan = new DialogueManager(this, z); + _input->_inputMode = Input::kInputModeDialogue; } +void Parallaction::exitDialogueMode() { + debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()"); + _input->_inputMode = Input::kInputModeGame; -void Parallaction::runDialogue(SpeakData *data) { - debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name); + // The current instance of _dialogueMan must be destroyed before the zone commands + // are executed, because they may create another instance of _dialogueMan that + // overwrite the current one. This would cause headaches (and it did, actually). + ZonePtr z = _dialogueMan->_z; + delete _dialogueMan; + _dialogueMan = 0; - DialogueManager man(this, data); - man.run(); + _cmdExec->run(z->_commands, z); +} + +void Parallaction::runDialogueFrame() { + if (_input->_inputMode != Input::kInputModeDialogue) { + return; + } + + _dialogueMan->run(); + + if (_dialogueMan->isOver()) { + exitDialogueMode(); + } return; } diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index d1cfb14557..9cde27a853 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -224,7 +224,11 @@ DECLARE_COMMAND_OPCODE(start) { DECLARE_COMMAND_OPCODE(speak) { - _vm->_activeZone = _ctxt.cmd->u._zone; + if ((_ctxt.cmd->u._zone->_type & 0xFFFF) == kZoneSpeak) { + _vm->enterDialogueMode(_ctxt.cmd->u._zone); + } else { + _vm->_activeZone = _ctxt.cmd->u._zone; + } } @@ -321,6 +325,7 @@ DECLARE_COMMAND_OPCODE(stop) { void Parallaction_ns::drawAnimations() { + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); uint16 layer = 0; @@ -361,6 +366,8 @@ void Parallaction_ns::drawAnimations() { } } + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); + return; } @@ -416,7 +423,6 @@ label1: return; } - void CommandExec::run(CommandList& list, ZonePtr z) { if (list.size() == 0) { debugC(3, kDebugExec, "runCommands: nothing to do"); @@ -537,11 +543,8 @@ uint16 Parallaction::runZone(ZonePtr z) { break; case kZoneSpeak: - runDialogue(z->u.speak); - if (_engineFlags & kEngineQuit) - return 0; - break; - + enterDialogueMode(z); + return 0; } debugC(3, kDebugExec, "runZone completed"); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 3797158661..4d0b7085c2 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -42,12 +42,14 @@ uint16 Input::readInput() { uint16 KeyDown = 0; _mouseButtons = kMouseNone; + _lastKeyDownAscii = -1; Common::EventManager *eventMan = _vm->_system->getEventManager(); while (eventMan->pollEvent(e)) { switch (e.type) { case Common::EVENT_KEYDOWN: + _lastKeyDownAscii = e.kbd.ascii; if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd') _vm->_debugger->attach(); if (_vm->getFeatures() & GF_DEMO) break; @@ -97,6 +99,11 @@ uint16 Input::readInput() { } +bool Input::getLastKeyDown(uint16 &ascii) { + ascii = _lastKeyDownAscii; + return (_lastKeyDownAscii != -1); +} + // FIXME: see comment for readInput() void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { @@ -192,6 +199,10 @@ InputData* Input::updateInput() { case kInputModeGame: updateGameInput(); break; + + case kInputModeDialogue: + readInput(); + break; } return &_inputData; diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index e06fe96705..acc9898e90 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -66,6 +66,7 @@ class Input { Common::Point _mousePos; uint16 _mouseButtons; + int32 _lastKeyDownAscii; bool _mouseHidden; ZonePtr _hoverZone; @@ -73,7 +74,8 @@ class Input { public: enum { kInputModeGame = 0, - kInputModeComment = 1 + kInputModeComment = 1, + kInputModeDialogue = 2 }; @@ -102,6 +104,7 @@ public: void waitUntilLeftClick(); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } + bool getLastKeyDown(uint16 &ascii); void stopHovering() { _hoverZone = nullZonePtr; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 3cde21b49c..bd5ff74473 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -161,6 +161,11 @@ void Parallaction::updateView() { } +void Parallaction::hideDialogueStuff() { + _gfx->freeItems(); + _balloonMan->freeBalloons(); +} + void Parallaction::freeCharacter() { debugC(1, kDebugExec, "freeCharacter()"); @@ -363,24 +368,28 @@ void Parallaction::processInput(InputData *data) { void Parallaction::runGame() { InputData *data = _input->updateInput(); - if (data->_event != kEvNone) { - processInput(data); - } - if (_engineFlags & kEngineQuit) return; - runPendingZones(); + if (_input->_inputMode == Input::kInputModeDialogue) { + runDialogueFrame(); + } else { + if (data->_event != kEvNone) { + processInput(data); + } - if (_engineFlags & kEngineQuit) - return; + if (_engineFlags & kEngineQuit) + return; - if (_engineFlags & kEngineChangeLocation) { - changeLocation(_location._name); - } + runPendingZones(); - if (_engineFlags & kEngineQuit) - return; + if (_engineFlags & kEngineQuit) + return; + + if (_engineFlags & kEngineChangeLocation) { + changeLocation(_location._name); + } + } _gfx->beginFrame(); @@ -396,7 +405,6 @@ void Parallaction::runGame() { // change this to endFrame? updateView(); - } @@ -659,6 +667,7 @@ void Parallaction::beep() { } void Parallaction::scheduleLocationSwitch(const char *location) { + debugC(9, kDebugExec, "scheduleLocationSwitch(%s)\n", location); strcpy(_location._name, location); _engineFlags |= kEngineChangeLocation; } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index ef2dad9884..409f274683 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -165,6 +165,7 @@ class Debugger; class Gfx; class SoundMan; class Input; +class DialogueManager; struct Location { @@ -275,8 +276,6 @@ public: uint16 runZone(ZonePtr z); void freeZones(); - void runDialogue(SpeakData*); - AnimationPtr findAnimation(const char *name); void freeAnimations(); @@ -419,10 +418,11 @@ public: void setupBalloonManager(); - void hideDialogueStuff() { - _gfx->freeItems(); - _balloonMan->freeBalloons(); - } + void hideDialogueStuff(); + DialogueManager *_dialogueMan; + void enterDialogueMode(ZonePtr z); + void exitDialogueMode(); + void runDialogueFrame(); }; diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 6606550132..9e2a0f10f1 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -212,13 +212,21 @@ void Parallaction_br::runPendingZones() { if (_activeZone) { z = _activeZone; // speak Zone or sound _activeZone = nullZonePtr; - runZone(z); // FIXME: BRA doesn't handle sound yet + if ((z->_type & 0xFFFF) == kZoneSpeak) { + enterDialogueMode(z); + } else { + runZone(z); // FIXME: BRA doesn't handle sound yet + } } if (_activeZone2) { z = _activeZone2; // speak Zone or sound _activeZone2 = nullZonePtr; - runZone(z); + if ((z->_type & 0xFFFF) == kZoneSpeak) { + enterDialogueMode(z); + } else { + runZone(z); // FIXME: BRA doesn't handle sound yet + } } } -- cgit v1.2.3 From 5a71d764e7278fd4c9d83ba80e500e05b9b18fc7 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 21 Jul 2008 09:25:40 +0000 Subject: Some refactoring for tracking of floating labels. svn-id: r33165 --- engines/parallaction/input.cpp | 44 ++++++++++++++++++++------------ engines/parallaction/input.h | 6 ++--- engines/parallaction/parallaction.cpp | 11 -------- engines/parallaction/parallaction.h | 2 -- engines/parallaction/parallaction_ns.cpp | 5 ++-- 5 files changed, 31 insertions(+), 37 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 4d0b7085c2..9601ae3b36 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -208,6 +208,29 @@ InputData* Input::updateInput() { return &_inputData; } +void Input::trackMouse(ZonePtr z) { + if ((z != _hoverZone) && (_hoverZone)) { + stopHovering(); + return; + } + + if (!z) { + return; + } + + if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) { + _hoverZone = z; + _vm->_gfx->showFloatingLabel(_hoverZone->_label); + return; + } +} + +void Input::stopHovering() { + _hoverZone = nullZonePtr; + _vm->_gfx->hideFloatingLabel(); +} + + bool Input::translateGameInput() { if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) { @@ -242,23 +265,10 @@ bool Input::translateGameInput() { return true; } - if ((z != _hoverZone) && (_hoverZone)) { - _hoverZone = nullZonePtr; - _inputData._event = kEvExitZone; - return true; - } - - if (!z) { - _inputData._event = kEvNone; - return true; - } - - if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) { - _hoverZone = z; - _inputData._event = kEvEnterZone; - _inputData._label = z->_label; - return true; - } + trackMouse(z); + if (!z) { + return true; + } if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index acc9898e90..f260352dba 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -101,15 +101,13 @@ public: uint16 readInput(); InputData* updateInput(); + void trackMouse(ZonePtr z); void waitUntilLeftClick(); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } bool getLastKeyDown(uint16 &ascii); - void stopHovering() { - _hoverZone = nullZonePtr; - } - + void stopHovering(); }; } // namespace Parallaction diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index bd5ff74473..cd852f7c84 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -299,16 +299,6 @@ void Parallaction::showLocationComment(const char *text, bool end) { void Parallaction::processInput(InputData *data) { switch (data->_event) { - case kEvEnterZone: - debugC(2, kDebugInput, "processInput: kEvEnterZone"); - _gfx->showFloatingLabel(data->_label); - break; - - case kEvExitZone: - debugC(2, kDebugInput, "processInput: kEvExitZone"); - _gfx->hideFloatingLabel(); - break; - case kEvAction: debugC(2, kDebugInput, "processInput: kEvAction"); _input->stopHovering(); @@ -319,7 +309,6 @@ void Parallaction::processInput(InputData *data) { case kEvOpenInventory: _input->stopHovering(); - _gfx->hideFloatingLabel(); if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { setArrowCursor(); } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 409f274683..c45d32b013 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -114,8 +114,6 @@ enum EngineFlags { enum { kEvNone = 0, - kEvEnterZone = 1, - kEvExitZone = 2, kEvAction = 3, kEvOpenInventory = 4, kEvCloseInventory = 5, diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index cbf9ee985d..9e925d1e1d 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -191,7 +191,7 @@ void Parallaction_ns::setArrowCursor() { debugC(1, kDebugInput, "setting mouse cursor to arrow"); // this stuff is needed to avoid artifacts with labels and selected items when switching cursors - _gfx->hideFloatingLabel(); + _input->stopHovering(); _input->_activeItem._id = 0; _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); @@ -302,12 +302,11 @@ void Parallaction_ns::changeLocation(char *location) { _soundMan->playLocationMusic(location); - _gfx->hideFloatingLabel(); + _input->stopHovering(); _gfx->freeLabels(); _zoneTrap = nullZonePtr; - _input->stopHovering(); if (_engineFlags & kEngineBlockInput) { setArrowCursor(); } -- cgit v1.2.3 From ecd44b8f90ec3f1e749f3b8787f6348e95030b0b Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Mon, 21 Jul 2008 10:13:44 +0000 Subject: Avoid branching in the inner loop of AGOS drawVertImageCompressed svn-id: r33167 --- engines/agos/gfx.cpp | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'engines') diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 6e91c5d94c..867a411962 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -8,7 +8,7 @@ * 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. - +d * 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 @@ -806,7 +806,6 @@ void AGOSEngine::drawVertImageUncompressed(VC10_state *state) { void AGOSEngine::drawVertImageCompressed(VC10_state *state) { assert (state->flags & kDFCompressed) ; uint w, h; - byte *src, *dst, *dstPtr; state->x_skip *= 4; /* reached */ @@ -815,7 +814,7 @@ void AGOSEngine::drawVertImageCompressed(VC10_state *state) { vc10_skip_cols(state); - dstPtr = state->surf_addr; + byte *dstPtr = state->surf_addr; if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ dstPtr += vcReadVar(252); } @@ -823,20 +822,34 @@ void AGOSEngine::drawVertImageCompressed(VC10_state *state) { do { byte color; - src = vc10_depackColumn(state); - dst = dstPtr; + const byte *src = vc10_depackColumn(state); + byte *dst = dstPtr; h = 0; - do { - color = (*src / 16); - if ((state->flags & kDFNonTrans) || color != 0) + if (state->flags & kDFNonTrans) { + do { + byte colors = *src; + color = (colors / 16); dst[0] = color | state->palette; - color = (*src & 15); - if ((state->flags & kDFNonTrans) || color != 0) + color = (colors & 15); dst[1] = color | state->palette; - dst += state->surf_pitch; - src++; - } while (++h != state->draw_height); + dst += state->surf_pitch; + src++; + } while (++h != state->draw_height); + } + else { + do { + byte colors = *src; + color = (colors / 16); + if (color != 0) + dst[0] = color | state->palette; + color = (colors & 15); + if (color != 0) + dst[1] = color | state->palette; + dst += state->surf_pitch; + src++; + } while (++h != state->draw_height); + } dstPtr += 2; } while (++w != state->draw_width); } -- cgit v1.2.3 From e1c71dab99c9bf60ee1cc26da09ebd797a693a3a Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Mon, 21 Jul 2008 10:32:20 +0000 Subject: Spacing. svn-id: r33168 --- engines/agos/gfx.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 867a411962..9a3962ea21 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -8,7 +8,7 @@ * 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. -d + * 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 @@ -836,8 +836,7 @@ void AGOSEngine::drawVertImageCompressed(VC10_state *state) { dst += state->surf_pitch; src++; } while (++h != state->draw_height); - } - else { + } else { do { byte colors = *src; color = (colors / 16); -- cgit v1.2.3 From 791d2b3ba2aea96c45c3221c1ce84a06b4f1f6e3 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 22 Jul 2008 09:00:39 +0000 Subject: Changed comment display code so that input polling is integrated into the main loop, instead of being performed in a blocking way from a separate routine. svn-id: r33188 --- engines/parallaction/exec_ns.cpp | 33 ++++++++++++++++++++++++++++++--- engines/parallaction/input.cpp | 6 +++--- engines/parallaction/parallaction.cpp | 7 ++++--- engines/parallaction/parallaction.h | 5 +++++ 4 files changed, 42 insertions(+), 9 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 9cde27a853..e596f2e971 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -481,7 +481,15 @@ CommandExec_ns::~CommandExec_ns() { // ZONE TYPE: EXAMINE // -void Parallaction::displayComment(ExamineData *data) { +void Parallaction::enterCommentMode(ZonePtr z) { + if (z == nullZonePtr) { + return; + } + + _commentZone = z; + + ExamineData *data = _commentZone->u.examine; + if (!data->_description) { return; } @@ -510,6 +518,25 @@ void Parallaction::displayComment(ExamineData *data) { _input->_inputMode = Input::kInputModeComment; } +void Parallaction::exitCommentMode() { + _input->_inputMode = Input::kInputModeGame; + + hideDialogueStuff(); + _gfx->setHalfbriteMode(false); + + _cmdExec->run(_commentZone->_commands, _commentZone); + _commentZone = nullZonePtr; +} + +void Parallaction::runCommentFrame() { + if (_input->_inputMode != Input::kInputModeComment) { + return; + } + + if (_input->getLastButtonEvent() == kMouseLeftUp) { + exitCommentMode(); + } +} uint16 Parallaction::runZone(ZonePtr z) { @@ -521,8 +548,8 @@ uint16 Parallaction::runZone(ZonePtr z) { switch(subtype) { case kZoneExamine: - displayComment(z->u.examine); - break; + enterCommentMode(z); + return 0; case kZoneGet: if (z->_flags & kFlagsFixed) break; diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 9601ae3b36..63ab01438d 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -179,13 +179,13 @@ void Input::updateGameInput() { } void Input::updateCommentInput() { - waitUntilLeftClick(); +/* waitUntilLeftClick(); _vm->hideDialogueStuff(); _vm->_gfx->setHalfbriteMode(false); _inputMode = kInputModeGame; -} +*/} InputData* Input::updateInput() { @@ -193,7 +193,7 @@ InputData* Input::updateInput() { switch (_inputMode) { case kInputModeComment: - updateCommentInput(); + readInput(); break; case kInputModeGame: diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index cd852f7c84..f7a6fbf260 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -360,9 +360,10 @@ void Parallaction::runGame() { if (_engineFlags & kEngineQuit) return; - if (_input->_inputMode == Input::kInputModeDialogue) { - runDialogueFrame(); - } else { + runDialogueFrame(); + runCommentFrame(); + + if (_input->_inputMode == Input::kInputModeGame) { if (data->_event != kEvNone) { processInput(data); } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index c45d32b013..20d0d90d68 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -422,6 +422,11 @@ public: void exitDialogueMode(); void runDialogueFrame(); + ZonePtr _commentZone; + void enterCommentMode(ZonePtr z); + void exitCommentMode(); + void runCommentFrame(); + }; -- cgit v1.2.3 From 85f56095bf4e3637a59cf1fd5a442fd08e6a9c47 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 22 Jul 2008 09:12:10 +0000 Subject: Removed unneeded input code. svn-id: r33189 --- engines/parallaction/input.cpp | 13 +------------ engines/parallaction/input.h | 1 - 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 63ab01438d..a2f42508c9 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -178,14 +178,6 @@ void Input::updateGameInput() { } -void Input::updateCommentInput() { -/* waitUntilLeftClick(); - - _vm->hideDialogueStuff(); - _vm->_gfx->setHalfbriteMode(false); - - _inputMode = kInputModeGame; -*/} InputData* Input::updateInput() { @@ -193,16 +185,13 @@ InputData* Input::updateInput() { switch (_inputMode) { case kInputModeComment: + case kInputModeDialogue: readInput(); break; case kInputModeGame: updateGameInput(); break; - - case kInputModeDialogue: - readInput(); - break; } return &_inputData; diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index f260352dba..c0630e410a 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -49,7 +49,6 @@ struct InputData { class Input { void updateGameInput(); - void updateCommentInput(); // input-only InputData _inputData; -- cgit v1.2.3 From 446a0406de97dba9417df8f82c4363cd3542a64b Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 22 Jul 2008 10:12:20 +0000 Subject: Fixed regression in dialogue code: certain commands weren't executed anymore after dialogue ended. svn-id: r33191 --- engines/parallaction/dialogue.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 290f8cfd4f..5f0d9f76f2 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -359,9 +359,6 @@ void DialogueManager::run() { break; case DIALOGUE_OVER: - if (_cmdList) { - _vm->_cmdExec->run(*_cmdList); - } break; default: @@ -381,6 +378,10 @@ void Parallaction::exitDialogueMode() { debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()"); _input->_inputMode = Input::kInputModeGame; + if (_dialogueMan->_cmdList) { + _vm->_cmdExec->runList(*_dialogueMan->_cmdList); + } + // The current instance of _dialogueMan must be destroyed before the zone commands // are executed, because they may create another instance of _dialogueMan that // overwrite the current one. This would cause headaches (and it did, actually). -- cgit v1.2.3 From 2a90435e5dccc0085613e35cc7177d1766cea6d0 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 22 Jul 2008 10:15:58 +0000 Subject: Fix for bug #2019355 (FW: broken compatibility with 0.11.1 saves): - Changed savegame loading related functions to use SeekableReadStream rather than InSaveFile so MemoryReadStream can be used transparently. - Fixed loadResourcesFromSave to load multiframe animations correctly and to load 0.11.0/0.11.1 Future Wars savegames which used a slightly different format. - Added a savegame format detector that tries to detect between the old Future Wars savegame format, the new one and a broken revision of the new one. - Changed makeLoad to first load the savegame fully into memory and only then handle it (If the savegame's packed then it's unpacked first). If the packed savegame can't tell its unpacked size (i.e. it's using zlib format) then we'll try to load up to 256kB of the savegame data. Thanks to wjp for his help with nailing this release critical bug. svn-id: r33192 --- engines/cine/anim.cpp | 74 ++++++++---- engines/cine/anim.h | 2 +- engines/cine/bg_list.cpp | 2 +- engines/cine/bg_list.h | 2 +- engines/cine/gfx.cpp | 2 +- engines/cine/gfx.h | 2 +- engines/cine/script.h | 6 +- engines/cine/script_fw.cpp | 6 +- engines/cine/various.cpp | 276 ++++++++++++++++++++++++++------------------- engines/cine/various.h | 33 ++++++ 10 files changed, 256 insertions(+), 149 deletions(-) (limited to 'engines') diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 055eb733c3..8dbccebedf 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -769,19 +769,18 @@ void loadAbs(const char *resourceName, uint16 idx) { /*! \brief Load animDataTable from save * \param fHandle Savefile open for reading - * \param broken Broken/correct file format switch + * \param saveGameFormat The used savegame format * \todo Add Operation Stealth savefile support * * Unlike the old code, this one actually rebuilds the table one frame * at a time. */ -void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken) { +void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) { int16 currentAnim, foundFileIdx; int8 isMask = 0, isSpl = 0; byte *dataPtr, *ptr; char *animName, part[256]; byte transparentColor = 0; - AnimData *currentPtr; AnimHeaderStruct animHeader; uint16 width, height, bpp, var1; @@ -791,30 +790,46 @@ void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken) { strcpy(part, currentPartName); - for (currentAnim = 0; currentAnim < NUM_MAX_ANIMDATA; currentAnim++) { - currentPtr = &animDataTable[currentAnim]; + // We only support these variations of the savegame format at the moment. + assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); + const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30); + const int fileStartPos = fHandle.pos(); + for (currentAnim = 0; currentAnim < NUM_MAX_ANIMDATA; currentAnim += animHeader.numFrames) { + // Initialize the number of frames variable to a sane number. + // This is needed when using continue later in this function. + animHeader.numFrames = 1; + + // Seek to the start of the current animation's entry + fHandle.seek(fileStartPos + currentAnim * entrySize); + // Read in the current animation entry width = fHandle.readUint16BE(); var1 = fHandle.readUint16BE(); bpp = fHandle.readUint16BE(); height = fHandle.readUint16BE(); - if (!broken) { - if (!fHandle.readUint32BE()) { - fHandle.skip(18); - continue; - } - fHandle.readUint32BE(); + bool validPtr = false; + // Handle variables only present in animation entries of size 30 + if (entrySize == 30) { + validPtr = (fHandle.readUint32BE() != 0); // Read data pointer + fHandle.readUint32BE(); // Discard mask pointer } foundFileIdx = fHandle.readSint16BE(); frame = fHandle.readSint16BE(); fHandle.read(name, 10); - if (foundFileIdx < 0 || (broken && !fHandle.readByte())) { + // Handle variables only present in animation entries of size 23 + if (entrySize == 23) { + validPtr = (fHandle.readByte() != 0); + } + + // Don't try to load invalid entries. + if (foundFileIdx < 0 || !validPtr) { continue; } + // Alright, the animation entry looks to be valid so let's start handling it... if (strcmp(currentPartName, name)) { closePart(); loadPart(name); @@ -823,13 +838,14 @@ void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken) { animName = partBuffer[foundFileIdx].partName; ptr = dataPtr = readBundleFile(foundFileIdx); + // isSpl and isMask are mutually exclusive cases isSpl = (strstr(animName, ".SPL")) ? 1 : 0; isMask = (strstr(animName, ".MSK")) ? 1 : 0; if (isSpl) { width = (uint16) partBuffer[foundFileIdx].unpackedSize; height = 1; - frame = 0; + animHeader.numFrames = 1; type = ANIM_RAW; } else { Common::MemoryReadStream readS(ptr, 0x16); @@ -843,25 +859,35 @@ void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken) { type = ANIM_MASK; } else { type = ANIM_MASKSPRITE; + } + } - loadRelatedPalette(animName); - transparentColor = getAnimTransparentColor(animName); - - // special case transparency handling - if (!strcmp(animName, "L2202.ANI")) { - transparentColor = (frame < 2) ? 0 : 7; - } else if (!strcmp(animName, "L4601.ANI")) { - transparentColor = (frame < 1) ? 0xE : 0; - } + loadRelatedPalette(animName); + transparentColor = getAnimTransparentColor(animName); + // Make sure we load at least one frame and also that we + // don't overflow the animDataTable by writing beyond its end. + animHeader.numFrames = CLIP(animHeader.numFrames, 1, NUM_MAX_ANIMDATA - currentAnim); + + // Load the frames + for (frame = 0; frame < animHeader.numFrames; frame++) { + // special case transparency handling + if (!strcmp(animName, "L2202.ANI")) { + transparentColor = (frame < 2) ? 0 : 7; + } else if (!strcmp(animName, "L4601.ANI")) { + transparentColor = (frame < 1) ? 0xE : 0; } + + // Load a single frame + animDataTable[currentAnim + frame].load(ptr + frame * width * height, type, width, height, foundFileIdx, frame, name, transparentColor); } - ptr += frame * width * height; - currentPtr->load(ptr, type, width, height, foundFileIdx, frame, name, transparentColor); free(dataPtr); } loadPart(part); + + // Make sure we jump over all the animation entries + fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize); } } // End of namespace Cine diff --git a/engines/cine/anim.h b/engines/cine/anim.h index d63033e670..f32a146e35 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -101,7 +101,7 @@ void freeAnimDataTable(void); void freeAnimDataRange(byte startIdx, byte numIdx); void loadResource(const char *resourceName); void loadAbs(const char *resourceName, uint16 idx); -void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken); +void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat); void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); } // End of namespace Cine diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index b10211282f..fddca078e5 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -83,7 +83,7 @@ void resetBgIncrustList(void) { /*! \brief Restore incrust list from savefile * \param fHandle Savefile open for reading */ -void loadBgIncrustFromSave(Common::InSaveFile &fHandle) { +void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) { BGIncrust tmp; int size = fHandle.readSint16BE(); diff --git a/engines/cine/bg_list.h b/engines/cine/bg_list.h index 1849d6ec3d..9a402baee8 100644 --- a/engines/cine/bg_list.h +++ b/engines/cine/bg_list.h @@ -51,7 +51,7 @@ void addSpriteFilledToBGList(int16 idx); void createBgIncrustListElement(int16 objIdx, int16 param); void resetBgIncrustList(void); -void loadBgIncrustFromSave(Common::InSaveFile &fHandle); +void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle); } // End of namespace Cine diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 1f868ccb75..f95794a409 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -614,7 +614,7 @@ void FWRenderer::saveBg(Common::OutSaveFile &fHandle) { /*! \brief Restore active and backup palette from save * \param fHandle Savefile open for reading */ -void FWRenderer::restorePalette(Common::InSaveFile &fHandle) { +void FWRenderer::restorePalette(Common::SeekableReadStream &fHandle) { int i; if (!_palette) { diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index c63c79ac82..910a4326e9 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -113,7 +113,7 @@ public: virtual void refreshPalette(); virtual void reloadPalette(); - void restorePalette(Common::InSaveFile &fHandle); + void restorePalette(Common::SeekableReadStream &fHandle); void savePalette(Common::OutSaveFile &fHandle); virtual void rotatePalette(int a, int b, int c); virtual void transformPalette(int first, int last, int r, int g, int b); diff --git a/engines/cine/script.h b/engines/cine/script.h index fcd21990fa..fe39272c4c 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -61,7 +61,7 @@ private: public: // Explicit to prevent var=0 instead of var[i]=0 typos. explicit ScriptVars(unsigned int len = 50); - ScriptVars(Common::InSaveFile &fHandle, unsigned int len = 50); + ScriptVars(Common::SeekableReadStream &fHandle, unsigned int len = 50); ScriptVars(const ScriptVars &src); ~ScriptVars(void); @@ -71,8 +71,8 @@ public: void save(Common::OutSaveFile &fHandle) const; void save(Common::OutSaveFile &fHandle, unsigned int len) const; - void load(Common::InSaveFile &fHandle); - void load(Common::InSaveFile &fHandle, unsigned int len); + void load(Common::SeekableReadStream &fHandle); + void load(Common::SeekableReadStream &fHandle, unsigned int len); void reset(void); }; diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 54a4976000..57b1e8f7b4 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -230,7 +230,7 @@ ScriptVars::ScriptVars(unsigned int len) : _size(len), _vars(new int16[len]) { * \param fHandle Savefile open for reading * \param len Size of array */ -ScriptVars::ScriptVars(Common::InSaveFile &fHandle, unsigned int len) +ScriptVars::ScriptVars(Common::SeekableReadStream &fHandle, unsigned int len) : _size(len), _vars(new int16[len]) { assert(_vars); @@ -306,7 +306,7 @@ void ScriptVars::save(Common::OutSaveFile &fHandle, unsigned int len) const { /*! \brief Restore array from savefile * \param fHandle Savefile open for reading */ -void ScriptVars::load(Common::InSaveFile &fHandle) { +void ScriptVars::load(Common::SeekableReadStream &fHandle) { load(fHandle, _size); } @@ -314,7 +314,7 @@ void ScriptVars::load(Common::InSaveFile &fHandle) { * \param fHandle Savefile open for reading * \param len Length of data to be read */ -void ScriptVars::load(Common::InSaveFile &fHandle, unsigned int len) { +void ScriptVars::load(Common::SeekableReadStream &fHandle, unsigned int len) { debug(6, "assert(%d <= %d)", len, _size); assert(len <= _size); for (unsigned int i = 0; i < len; i++) { diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index ab2fa645c7..8e6f3fce76 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -246,21 +246,130 @@ bool CineEngine::loadSaveDirectory(void) { return true; } +/*! \brief Savegame format detector + * \param fHandle Savefile to check + * \return Savegame format on success, ANIMSIZE_UNKNOWN on failure + * + * This function seeks through the savefile and tries to determine the + * savegame format it uses. There's a miniscule chance that the detection + * algorithm could get confused and think that the file uses both the older + * and the newer format but that is such a remote possibility that I wouldn't + * worry about it at all. + */ +enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) { + // The animDataTable begins at savefile position 0x2315. + // Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443) + // and 30 bytes in the save format after that (Revision 31444 and onwards). + // There are 255 entries in the animDataTable in both of the savefile formats. + static const uint animDataTableStart = 0x2315; + static const uint animEntriesCount = 255; + static const uint oldAnimEntrySize = 23; + static const uint newAnimEntrySize = 30; + static const uint defaultAnimEntrySize = newAnimEntrySize; + static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; + Common::Array animEntrySizeMatches; + const uint32 prevStreamPos = fHandle.pos(); + + // Try to walk through the savefile using different animDataTable entry sizes + // and make a list of all the successful entry sizes. + for (uint i = 0; i < ARRAYSIZE(animEntrySizeChoices); i++) { + // 206 = 2 * 50 * 2 + 2 * 3 (Size of global and object script entries) + // 20 = 4 * 2 + 2 * 6 (Size of overlay and background incrust entries) + static const uint sizeofScreenParams = 2 * 6; + static const uint globalScriptEntrySize = 206; + static const uint objectScriptEntrySize = 206; + static const uint overlayEntrySize = 20; + static const uint bgIncrustEntrySize = 20; + static const uint chainEntrySizes[] = { + globalScriptEntrySize, + objectScriptEntrySize, + overlayEntrySize, + bgIncrustEntrySize + }; + + uint animEntrySize = animEntrySizeChoices[i]; + // Jump over the animDataTable entries and the screen parameters + uint32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams; + // Check that there's data left after the point we're going to jump to + if (newPos >= fHandle.size()) { + continue; + } + fHandle.seek(newPos); + + // Jump over the remaining items in the savegame file + // (i.e. the global scripts, object scripts, overlays and background incrusts). + bool chainWalkSuccess = true; + for (uint chainIndex = 0; chainIndex < ARRAYSIZE(chainEntrySizes); chainIndex++) { + // Read entry count and jump over the entries + int entryCount = fHandle.readSint16BE(); + newPos = fHandle.pos() + chainEntrySizes[chainIndex] * entryCount; + // Check that we didn't go past the end of file. + // Note that getting exactly to the end of file is acceptable. + if (newPos > fHandle.size()) { + chainWalkSuccess = false; + break; + } + fHandle.seek(newPos); + } + + // If we could walk the chain successfully and + // got exactly to the end of file then we've got a match. + if (chainWalkSuccess && fHandle.pos() == fHandle.size()) { + // We found a match, let's save it + animEntrySizeMatches.push_back(animEntrySize); + } + } + + // Check that we got only one entry size match. + // If we didn't, then return an error. + enum CineSaveGameFormat result = ANIMSIZE_UNKNOWN; + if (animEntrySizeMatches.size() == 1) { + const uint animEntrySize = animEntrySizeMatches[0]; + assert(animEntrySize == oldAnimEntrySize || animEntrySize == newAnimEntrySize); + if (animEntrySize == oldAnimEntrySize) { + result = ANIMSIZE_23; + } else { // animEntrySize == newAnimEntrySize + // Check data and mask pointers in all of the animDataTable entries + // to see whether we've got the version with the broken data and mask pointers or not. + // In the broken format all data and mask pointers were always zero. + static const uint relativeDataPos = 2 * 4; + bool pointersIntact = false; + for (uint i = 0; i < animEntriesCount; i++) { + fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos); + uint32 data = fHandle.readUint32BE(); + uint32 mask = fHandle.readUint32BE(); + if (data != NULL || mask != NULL) { + pointersIntact = true; + break; + } + } + result = (pointersIntact ? ANIMSIZE_30_PTRS_INTACT : ANIMSIZE_30_PTRS_BROKEN); + } + } else if (animEntrySizeMatches.size() > 1) { + warning("Savegame format detector got confused by input data. Detecting savegame to be using an unknown format"); + } else { // animEtrySizeMatches.size() == 0 + debug(3, "Savegame format detector was unable to detect savegame's format"); + } + + fHandle.seek(prevStreamPos); + return result; +} + /*! \brief Restore script list item from savefile - * \param fHandle Savefile handlem open for reading + * \param fHandle Savefile handle open for reading * \param isGlobal Restore object or global script? */ -void loadScriptFromSave(Common::InSaveFile *fHandle, bool isGlobal) { +void loadScriptFromSave(Common::SeekableReadStream &fHandle, bool isGlobal) { ScriptVars localVars, labels; uint16 compare, pos; int16 idx; - labels.load(*fHandle); - localVars.load(*fHandle); + labels.load(fHandle); + localVars.load(fHandle); - compare = fHandle->readUint16BE(); - pos = fHandle->readUint16BE(); - idx = fHandle->readUint16BE(); + compare = fHandle.readUint16BE(); + pos = fHandle.readUint16BE(); + idx = fHandle.readUint16BE(); // no way to reinitialize these if (idx < 0) { @@ -283,7 +392,7 @@ void loadScriptFromSave(Common::InSaveFile *fHandle, bool isGlobal) { /*! \brief Restore overlay sprites from savefile * \param fHandle Savefile open for reading */ -void loadOverlayFromSave(Common::InSaveFile &fHandle) { +void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { overlay tmp; fHandle.readUint32BE(); @@ -299,115 +408,17 @@ void loadOverlayFromSave(Common::InSaveFile &fHandle) { overlayList.push_back(tmp); } -/*! \brief Savefile format tester - * \param fHandle Savefile to check - * - * This function seeks through savefile and tries to guess if it's the original - * savegame format or broken format from ScummVM 0.10/0.11 - * The test is incomplete but this should cover 99.99% of cases. - * If anyone makes a savefile which could confuse this test, assert will - * report it - */ -bool brokenSave(Common::InSaveFile &fHandle) { - // Backward seeking not supported in compressed savefiles - // if you really want it, finish it yourself - return false; - - // fixed size part: 14093 bytes (12308 bytes in broken save) - // animDataTable begins at byte 6431 - - int filesize = fHandle.size(); - int startpos = fHandle.pos(); - int pos, tmp; - bool correct = false, broken = false; - - // check for correct format - while (filesize > 14093) { - pos = 14093; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - - if (pos == filesize) correct = true; - break; - } - debug(5, "brokenSave: correct format check %s: size=%d, pos=%d", - correct ? "passed" : "failed", filesize, pos); - - // check for broken format - while (filesize > 12308) { - pos = 12308; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - - if (pos == filesize) broken = true; - break; - } - debug(5, "brokenSave: broken format check %s: size=%d, pos=%d", - broken ? "passed" : "failed", filesize, pos); - - // there's a very small chance that both cases will match - // if anyone runs into it, you'll have to walk through - // the animDataTable and try to open part file for each entry - if (!correct && !broken) { - error("brokenSave: file format check failed"); - } else if (correct && broken) { - error("brokenSave: both file formats seem to apply"); - } - - fHandle.seek(startpos); - debug(5, "brokenSave: detected %s file format", - correct ? "correct" : "broken"); - - return broken; -} - /*! \todo Implement Operation Stealth loading, this is obviously Future Wars only * \todo Add support for loading the zoneQuery table (Operation Stealth specific) */ bool CineEngine::makeLoad(char *saveName) { int16 i; int16 size; - bool broken; - Common::InSaveFile *fHandle; char bgName[13]; - fHandle = g_saveFileMan->openForLoading(saveName); + Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); - if (!fHandle) { + if (!saveFile) { drawString(otherMessages[0], 0); waitPlayerInput(); // restoreScreen(); @@ -415,6 +426,46 @@ bool CineEngine::makeLoad(char *saveName) { return false; } + uint32 saveSize = saveFile->size(); + if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it + // Can't get information about the savefile's size so let's try + // reading as much as we can from the file up to a predefined upper limit. + // + // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each): + // With 256 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB + // With 512 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB + // + // I think it extremely unlikely that there would be over 512 global scripts, object scripts, + // overlays and background incrusts so 256kB seems like quite a safe upper limit. + // NOTE: If the savegame format is changed then this value might have to be re-evaluated! + // Hopefully devices with more limited memory can also cope with this memory allocation. + saveSize = 256 * 1024; + } + Common::SharedPtr fHandle(saveFile->readStream(saveSize)); + + // Try to detect the used savegame format + enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*fHandle); + + // Handle problematic savegame formats + if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { + // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but + // that's not implemented here because it was never used in a stable + // release of ScummVM but only during development (From revision 31453, + // which introduced the problem, until revision 32073, which fixed it). + // Therefore be bail out if we detect this particular savegame format. + warning("Detected a known broken savegame format, not loading savegame"); + return false; + } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { + // If we can't detect the savegame format + // then let's try the default format and hope for the best. + warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); + saveGameFormat = ANIMSIZE_30_PTRS_INTACT; + } + // Now we should have either of these formats + assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); + g_sound->stopMusic(); freeAnimDataTable(); overlayList.clear(); @@ -464,7 +515,6 @@ bool CineEngine::makeLoad(char *saveName) { checkForPendingDataLoadSwitch = 0; - broken = brokenSave(*fHandle); // At savefile position 0x0000: currentDisk = fHandle->readUint16BE(); @@ -588,7 +638,7 @@ bool CineEngine::makeLoad(char *saveName) { fHandle->readUint16BE(); // At 0x2315: - loadResourcesFromSave(*fHandle, broken); + loadResourcesFromSave(*fHandle, saveGameFormat); // TODO: handle screen params (really required ?) fHandle->readUint16BE(); @@ -600,12 +650,12 @@ bool CineEngine::makeLoad(char *saveName) { size = fHandle->readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(fHandle, true); + loadScriptFromSave(*fHandle, true); } size = fHandle->readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(fHandle, false); + loadScriptFromSave(*fHandle, false); } size = fHandle->readSint16BE(); @@ -615,8 +665,6 @@ bool CineEngine::makeLoad(char *saveName) { loadBgIncrustFromSave(*fHandle); - delete fHandle; - if (strlen(currentMsgName)) { loadMsg(currentMsgName); } diff --git a/engines/cine/various.h b/engines/cine/various.h index 840f1674a2..9507876307 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -33,6 +33,39 @@ namespace Cine { +/** + * Cine engine's save game formats. + * Enumeration entries (Excluding the one used as an error) + * are sorted according to age (i.e. top one is oldest, last one newest etc). + * + * ANIMSIZE_UNKNOWN: + * - Animation data entry size is unknown (Used as an error). + * + * ANIMSIZE_23: + * - Animation data entry size is 23 bytes. + * - Used at least by 0.11.0 and 0.11.1 releases of ScummVM. + * - Introduced in revision 21772, stopped using in revision 31444. + * + * ANIMSIZE_30_PTRS_BROKEN: + * - Animation data entry size is 30 bytes. + * - Data and mask pointers in the saved structs are always NULL. + * - Introduced in revision 31453, stopped using in revision 32073. + * + * ANIMSIZE_30_PTRS_INTACT: + * - Animation data entry size is 30 bytes. + * - Data and mask pointers in the saved structs are intact, + * so you can test them for equality or inequality with NULL + * but don't try using them for anything else, it won't work. + * - Introduced in revision 31444, got broken in revision 31453, + * got fixed in revision 32073 and used after that. + */ +enum CineSaveGameFormat { + ANIMSIZE_UNKNOWN, + ANIMSIZE_23, + ANIMSIZE_30_PTRS_BROKEN, + ANIMSIZE_30_PTRS_INTACT +}; + void initLanguage(Common::Language lang); int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false); -- cgit v1.2.3 From cc0f95ce744b4078b3399e196101c239b7b094c9 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 22 Jul 2008 10:17:19 +0000 Subject: Fix build. svn-id: r33193 --- engines/parallaction/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 5f0d9f76f2..0d8b933907 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -379,7 +379,7 @@ void Parallaction::exitDialogueMode() { _input->_inputMode = Input::kInputModeGame; if (_dialogueMan->_cmdList) { - _vm->_cmdExec->runList(*_dialogueMan->_cmdList); + _vm->_cmdExec->run(*_dialogueMan->_cmdList); } // The current instance of _dialogueMan must be destroyed before the zone commands -- cgit v1.2.3 From a38234d6e6f564b3eb6ed7db63bd907fc1d695fb Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 22 Jul 2008 12:17:44 +0000 Subject: Fix CineSaveGameFormat enumeration's include order (Caused problems at least with GCC). svn-id: r33196 --- engines/cine/anim.h | 33 +++++++++++++++++++++++++++++++++ engines/cine/various.h | 33 --------------------------------- 2 files changed, 33 insertions(+), 33 deletions(-) (limited to 'engines') diff --git a/engines/cine/anim.h b/engines/cine/anim.h index f32a146e35..c04513149c 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -28,6 +28,39 @@ namespace Cine { +/** + * Cine engine's save game formats. + * Enumeration entries (Excluding the one used as an error) + * are sorted according to age (i.e. top one is oldest, last one newest etc). + * + * ANIMSIZE_UNKNOWN: + * - Animation data entry size is unknown (Used as an error). + * + * ANIMSIZE_23: + * - Animation data entry size is 23 bytes. + * - Used at least by 0.11.0 and 0.11.1 releases of ScummVM. + * - Introduced in revision 21772, stopped using in revision 31444. + * + * ANIMSIZE_30_PTRS_BROKEN: + * - Animation data entry size is 30 bytes. + * - Data and mask pointers in the saved structs are always NULL. + * - Introduced in revision 31453, stopped using in revision 32073. + * + * ANIMSIZE_30_PTRS_INTACT: + * - Animation data entry size is 30 bytes. + * - Data and mask pointers in the saved structs are intact, + * so you can test them for equality or inequality with NULL + * but don't try using them for anything else, it won't work. + * - Introduced in revision 31444, got broken in revision 31453, + * got fixed in revision 32073 and used after that. + */ +enum CineSaveGameFormat { + ANIMSIZE_UNKNOWN, + ANIMSIZE_23, + ANIMSIZE_30_PTRS_BROKEN, + ANIMSIZE_30_PTRS_INTACT +}; + struct AnimHeaderStruct { byte field_0; byte field_1; diff --git a/engines/cine/various.h b/engines/cine/various.h index 9507876307..840f1674a2 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -33,39 +33,6 @@ namespace Cine { -/** - * Cine engine's save game formats. - * Enumeration entries (Excluding the one used as an error) - * are sorted according to age (i.e. top one is oldest, last one newest etc). - * - * ANIMSIZE_UNKNOWN: - * - Animation data entry size is unknown (Used as an error). - * - * ANIMSIZE_23: - * - Animation data entry size is 23 bytes. - * - Used at least by 0.11.0 and 0.11.1 releases of ScummVM. - * - Introduced in revision 21772, stopped using in revision 31444. - * - * ANIMSIZE_30_PTRS_BROKEN: - * - Animation data entry size is 30 bytes. - * - Data and mask pointers in the saved structs are always NULL. - * - Introduced in revision 31453, stopped using in revision 32073. - * - * ANIMSIZE_30_PTRS_INTACT: - * - Animation data entry size is 30 bytes. - * - Data and mask pointers in the saved structs are intact, - * so you can test them for equality or inequality with NULL - * but don't try using them for anything else, it won't work. - * - Introduced in revision 31444, got broken in revision 31453, - * got fixed in revision 32073 and used after that. - */ -enum CineSaveGameFormat { - ANIMSIZE_UNKNOWN, - ANIMSIZE_23, - ANIMSIZE_30_PTRS_BROKEN, - ANIMSIZE_30_PTRS_INTACT -}; - void initLanguage(Common::Language lang); int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false); -- cgit v1.2.3 From 5ea9bdd99aac134e739f06b4934a8ff5278633a1 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 22 Jul 2008 12:35:46 +0000 Subject: Merged inventory input code from different files. svn-id: r33198 --- engines/parallaction/input.cpp | 73 +++++++++++++++++++++-------------- engines/parallaction/input.h | 3 ++ engines/parallaction/parallaction.cpp | 19 --------- 3 files changed, 47 insertions(+), 48 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index a2f42508c9..1af1ed15fa 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -235,14 +235,7 @@ bool Input::translateGameInput() { if (_mouseButtons == kMouseRightDown) { // right button down shows inventory - - if (_vm->hitZone(kZoneYou, _mousePos.x, _mousePos.y) && (_activeItem._id != 0)) { - _activeItem._index = (_activeItem._id >> 16) & 0xFFFF; - _engineFlags |= kEngineDragging; - } - - _inputData._event = kEvOpenInventory; - _transCurrentHoverItem = -1; + enterInventoryMode(); return true; } @@ -282,31 +275,38 @@ bool Input::translateGameInput() { } return true; - } -bool Input::translateInventoryInput() { - if ((_engineFlags & kEngineInventory) == 0) { - return false; +void Input::enterInventoryMode() { + bool hitCharacter = _vm->hitZone(kZoneYou, _mousePos.x, _mousePos.y); + + if (hitCharacter) { + if (_activeItem._id != 0) { + _activeItem._index = (_activeItem._id >> 16) & 0xFFFF; + _engineFlags |= kEngineDragging; + } else { + _vm->setArrowCursor(); + } } - // in inventory - int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + stopHovering(); + _vm->pauseJobs(); + _vm->openInventory(); - if (_mouseButtons == kMouseRightUp) { - // right up hides inventory + _transCurrentHoverItem = -1; +} - _inputData._event = kEvCloseInventory; - _inputData._inventoryIndex = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); - _vm->highlightInventoryItem(-1); // disable +void Input::exitInventoryMode() { + // right up hides inventory - if ((_engineFlags & kEngineDragging) == 0) { - return true; - } + int item = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + _vm->highlightInventoryItem(-1); // disable + + if ((_engineFlags & kEngineDragging)) { _engineFlags &= ~kEngineDragging; - ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(_inputData._inventoryIndex)); + ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(item)); if (z) { _vm->dropItem(z->u.merge->_obj1); @@ -315,17 +315,32 @@ bool Input::translateInventoryInput() { _vm->_cmdExec->run(z->_commands); } - return true; } - if (_si == _transCurrentHoverItem) { - _inputData._event = kEvNone; + _vm->closeInventory(); + _vm->setInventoryCursor(item); + _vm->resumeJobs(); +} + +bool Input::translateInventoryInput() { + + if ((_engineFlags & kEngineInventory) == 0) { + return false; + } + + // in inventory + int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + + if (_mouseButtons == kMouseRightUp) { + exitInventoryMode(); return true; } - _transCurrentHoverItem = _si; - _inputData._event = kEvHoverInventory; - _inputData._inventoryIndex = _si; + if (_si != _transCurrentHoverItem) { + _transCurrentHoverItem = _si; + _vm->highlightInventoryItem(_si); // enable + } + return true; } diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index c0630e410a..2a97077603 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -70,6 +70,9 @@ class Input { bool _mouseHidden; ZonePtr _hoverZone; + void enterInventoryMode(); + void exitInventoryMode(); + public: enum { kInputModeGame = 0, diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index f7a6fbf260..a45e678e73 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -307,25 +307,6 @@ void Parallaction::processInput(InputData *data) { resumeJobs(); break; - case kEvOpenInventory: - _input->stopHovering(); - if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { - setArrowCursor(); - } - pauseJobs(); - openInventory(); - break; - - case kEvCloseInventory: // closes inventory and possibly select item - closeInventory(); - setInventoryCursor(data->_inventoryIndex); - resumeJobs(); - break; - - case kEvHoverInventory: - highlightInventoryItem(data->_inventoryIndex); // enable - break; - case kEvWalk: debugC(2, kDebugInput, "processInput: kEvWalk"); _input->stopHovering(); -- cgit v1.2.3 From c92f154b90ef5c09e500978d6e60f9d8f2db1868 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 22 Jul 2008 14:38:54 +0000 Subject: Fix warnings in CINE svn-id: r33202 --- engines/cine/various.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 8e6f3fce76..f3b8cc2582 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -265,7 +265,7 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle static const uint animEntriesCount = 255; static const uint oldAnimEntrySize = 23; static const uint newAnimEntrySize = 30; - static const uint defaultAnimEntrySize = newAnimEntrySize; +// static const uint defaultAnimEntrySize = newAnimEntrySize; static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; Common::Array animEntrySizeMatches; const uint32 prevStreamPos = fHandle.pos(); @@ -338,7 +338,7 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos); uint32 data = fHandle.readUint32BE(); uint32 mask = fHandle.readUint32BE(); - if (data != NULL || mask != NULL) { + if ((data != 0) || (mask != 0)) { pointersIntact = true; break; } -- cgit v1.2.3 From b422f0ba734190ed5807f4fcf58aee3bf9b6f49e Mon Sep 17 00:00:00 2001 From: Paweł Kołodziejski Date: Tue, 22 Jul 2008 15:24:39 +0000 Subject: shutup valgrind warning svn-id: r33206 --- engines/scumm/imuse_digi/dimuse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp index fa50eca604..d3359fa33e 100644 --- a/engines/scumm/imuse_digi/dimuse.cpp +++ b/engines/scumm/imuse_digi/dimuse.cpp @@ -57,8 +57,8 @@ IMuseDigital::IMuseDigital(ScummEngine_v7 *scumm, Audio::Mixer *mixer, int fps) for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) { _track[l] = new Track; assert(_track[l]); + memset(_track[l], 0, sizeof(Track)); _track[l]->trackId = l; - _track[l]->used = false; } _vm->_timer->installTimerProc(timer_handler, 1000000 / _callbackFps, this); -- cgit v1.2.3 From 5eec5f6b17d7e403408699d9eaf71a1956574cd9 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 23 Jul 2008 01:07:39 +0000 Subject: More merging of input code. svn-id: r33219 --- engines/parallaction/input.cpp | 33 ++++++++++++++++++++++++--------- engines/parallaction/input.h | 12 ++++++++---- engines/parallaction/parallaction.cpp | 19 ------------------- 3 files changed, 32 insertions(+), 32 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 1af1ed15fa..af55753d65 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -219,6 +219,18 @@ void Input::stopHovering() { _vm->_gfx->hideFloatingLabel(); } +void Input::takeAction(ZonePtr z) { + stopHovering(); + _vm->pauseJobs(); + _vm->runZone(z); + _vm->resumeJobs(); +} + +void Input::walkTo(const Common::Point &dest) { + stopHovering(); + _vm->setArrowCursor(); + _vm->_char.scheduleWalk(dest.x, dest.y); +} bool Input::translateGameInput() { @@ -226,10 +238,11 @@ bool Input::translateGameInput() { return false; } - if (_actionAfterWalk) { + if (_hasDelayedAction) { // if walking is over, then take programmed action - _inputData._event = kEvAction; - _actionAfterWalk = false; + takeAction(_delayedActionZone); + _hasDelayedAction = false; + _delayedActionZone = nullZonePtr; return true; } @@ -241,9 +254,10 @@ bool Input::translateGameInput() { // test if mouse is hovering on an interactive zone for the currently selected inventory item ZonePtr z = _vm->hitZone(_activeItem._id, _mousePos.x, _mousePos.y); + Common::Point dest(_mousePos); if (((_mouseButtons == kMouseLeftUp) && (_activeItem._id == 0) && ((_engineFlags & kEngineWalking) == 0)) && ((!z) || ((z->_type & 0xFFFF) != kZoneCommand))) { - _inputData._event = kEvWalk; + walkTo(dest); return true; } @@ -257,16 +271,17 @@ bool Input::translateGameInput() { _inputData._zone = z; if (z->_flags & kFlagsNoWalk) { // character doesn't need to walk to take specified action - _inputData._event = kEvAction; - + takeAction(z); } else { // action delayed: if Zone defined a moveto position the character is programmed to move there, // else it will move to the mouse position - _inputData._event = kEvWalk; - _actionAfterWalk = true; + _delayedActionZone = z; + _hasDelayedAction = true; if (z->_moveTo.y != 0) { - _inputData._mousePos = z->_moveTo; + dest = z->_moveTo; } + + walkTo(dest); } _vm->beep(); diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 2a97077603..19825c8baa 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -52,14 +52,17 @@ class Input { // input-only InputData _inputData; - bool _actionAfterWalk; // actived when the character needs to move before taking an action - // these two could/should be merged as they carry on the same duty in two member functions, - // respectively processInput and translateInput + + bool _hasDelayedAction; // actived when the character needs to move before taking an action + ZonePtr _delayedActionZone; + int16 _transCurrentHoverItem; InputData *translateInput(); bool translateGameInput(); bool translateInventoryInput(); + void takeAction(ZonePtr z); + void walkTo(const Common::Point &dest); Parallaction *_vm; @@ -83,11 +86,12 @@ public: Input(Parallaction *vm) : _vm(vm) { _transCurrentHoverItem = 0; - _actionAfterWalk = false; // actived when the character needs to move before taking an action + _hasDelayedAction = false; // actived when the character needs to move before taking an action _mouseHidden = false; _activeItem._index = 0; _activeItem._id = 0; _mouseButtons = 0; + _delayedActionZone = nullZonePtr; } virtual ~Input() { } diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index a45e678e73..cdc19c32c4 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -299,25 +299,6 @@ void Parallaction::showLocationComment(const char *text, bool end) { void Parallaction::processInput(InputData *data) { switch (data->_event) { - case kEvAction: - debugC(2, kDebugInput, "processInput: kEvAction"); - _input->stopHovering(); - pauseJobs(); - runZone(data->_zone); - resumeJobs(); - break; - - case kEvWalk: - debugC(2, kDebugInput, "processInput: kEvWalk"); - _input->stopHovering(); - setArrowCursor(); - _char.scheduleWalk(data->_mousePos.x, data->_mousePos.y); - break; - - case kEvQuitGame: - _engineFlags |= kEngineQuit; - break; - case kEvSaveGame: _input->stopHovering(); saveGame(); -- cgit v1.2.3 From a5ebc88dbc9d02ddbf96f49f43e448cd4de9caaf Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 23 Jul 2008 02:01:15 +0000 Subject: Fixed mouse cursor when closing inventory. svn-id: r33220 --- engines/parallaction/input.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index af55753d65..243eaec94f 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -333,7 +333,11 @@ void Input::exitInventoryMode() { } _vm->closeInventory(); - _vm->setInventoryCursor(item); + if (item == -1) { + _vm->setArrowCursor(); + } else { + _vm->setInventoryCursor(item); + } _vm->resumeJobs(); } -- cgit v1.2.3 From 5544e180a33a820ca89eae6ac3f7c1ac974c8fc6 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 23 Jul 2008 02:41:02 +0000 Subject: More savegame-endianness fixes :/ svn-id: r33222 --- engines/gob/gob.cpp | 9 +++++++++ engines/gob/gob.h | 6 ++++++ engines/gob/inter.cpp | 4 +--- engines/gob/saveload.cpp | 49 ++++++++++++++++++++++++++++----------------- engines/gob/saveload.h | 29 +++++++++++++++++---------- engines/gob/saveload_v2.cpp | 20 +++++++++++------- engines/gob/saveload_v3.cpp | 34 ++++++++++++++++++------------- engines/gob/saveload_v4.cpp | 24 +++++++++++++--------- 8 files changed, 112 insertions(+), 63 deletions(-) (limited to 'engines') diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index a3fe0ebbe2..34443251d8 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -147,6 +147,15 @@ void GobEngine::validateVideoMode(int16 videoMode) { error("Video mode 0x%X is not supported!", videoMode); } +Endianness GobEngine::getEndianness() const { + if ((_vm->getPlatform() == Common::kPlatformAmiga) || + (_vm->getPlatform() == Common::kPlatformMacintosh) || + (_vm->getPlatform() == Common::kPlatformAtariST)) + return kEndiannessBE; + + return kEndiannessLE; +} + Common::Platform GobEngine::getPlatform() const { return _platform; } diff --git a/engines/gob/gob.h b/engines/gob/gob.h index ae2b53bc31..041658baea 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -79,6 +79,11 @@ class SaveLoad; #define VAR(var) READ_VAR_UINT32(var) +enum Endianness { + kEndiannessLE, + kEndiannessBE +}; + enum GameType { kGameTypeNone = 0, kGameTypeGob1, @@ -230,6 +235,7 @@ public: void validateLanguage(); void validateVideoMode(int16 videoMode); + Endianness getEndianness() const; Common::Platform getPlatform() const; GameType getGameType() const; bool isCD() const; diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index df9c1353a0..02e7f99cbd 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -296,9 +296,7 @@ void Inter::callSub(int16 retFlag) { } void Inter::allocateVars(uint32 count) { - if ((_vm->getPlatform() == Common::kPlatformAmiga) || - (_vm->getPlatform() == Common::kPlatformMacintosh) || - (_vm->getPlatform() == Common::kPlatformAtariST)) + if (_vm->getEndianness() == kEndiannessBE) _variables = new VariablesBE(count * 4); else _variables = new VariablesLE(count * 4); diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp index 2788716858..fa9f8ea7a9 100644 --- a/engines/gob/saveload.cpp +++ b/engines/gob/saveload.cpp @@ -153,7 +153,7 @@ bool TempSprite::fromBuffer(const byte *buffer, int32 size, bool palette) { } -PlainSave::PlainSave() { +PlainSave::PlainSave(Endianness endianness) : _endianness(endianness) { } PlainSave::~PlainSave() { @@ -230,7 +230,8 @@ bool PlainSave::save(int16 dataVar, int32 size, int32 offset, const char *name, } bool retVal; - retVal = SaveLoad::saveDataEndian(*out, dataVar, size, variables, variableSizes); + retVal = SaveLoad::saveDataEndian(*out, dataVar, size, + variables, variableSizes, _endianness); out->finalize(); if (out->ioFailed()) { @@ -258,13 +259,14 @@ bool PlainSave::load(int16 dataVar, int32 size, int32 offset, const char *name, return false; } - bool retVal = SaveLoad::loadDataEndian(*in, dataVar, size, variables, variableSizes); + bool retVal = SaveLoad::loadDataEndian(*in, dataVar, size, + variables, variableSizes, _endianness); delete in; return retVal; } -StagedSave::StagedSave() { +StagedSave::StagedSave(Endianness endianness) : _endianness(endianness) { _mode = kModeNone; _name = 0; _loaded = false; @@ -487,7 +489,7 @@ bool StagedSave::write() const { } else result = SaveLoad::saveDataEndian(*out, 0, _stages[i].size, - _stages[i].bufVar, _stages[i].bufVarSizes); + _stages[i].bufVar, _stages[i].bufVarSizes, _endianness); } if (result) { @@ -533,7 +535,7 @@ bool StagedSave::read() { _stages[i].bufVarSizes = new byte[_stages[i].size]; result = SaveLoad::loadDataEndian(*in, 0, _stages[i].size, - _stages[i].bufVar, _stages[i].bufVarSizes); + _stages[i].bufVar, _stages[i].bufVarSizes, _endianness); } } @@ -734,12 +736,14 @@ void SaveLoad::buildIndex(byte *buffer, char *name, int n, int32 size, int32 off } } -bool SaveLoad::fromEndian(byte *buf, const byte *sizes, uint32 count) { +bool SaveLoad::fromEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness) { + bool LE = (endianness == kEndiannessLE); + while (count-- > 0) { if (*sizes == 3) - *((uint32 *) buf) = READ_LE_UINT32(buf); + *((uint32 *) buf) = LE ? READ_LE_UINT32(buf) : READ_BE_UINT32(buf); else if (*sizes == 1) - *((uint16 *) buf) = READ_LE_UINT16(buf); + *((uint16 *) buf) = LE ? READ_LE_UINT16(buf) : READ_BE_UINT16(buf); else if (*sizes != 0) { warning("SaveLoad::fromEndian(): Corrupted variables sizes"); return false; @@ -753,12 +757,19 @@ bool SaveLoad::fromEndian(byte *buf, const byte *sizes, uint32 count) { return true; } -bool SaveLoad::toEndian(byte *buf, const byte *sizes, uint32 count) { +bool SaveLoad::toEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness) { while (count-- > 0) { - if (*sizes == 3) - WRITE_LE_UINT32(buf, *((uint32 *) buf)); - else if (*sizes == 1) - WRITE_LE_UINT16(buf, *((uint16 *) buf)); + if (*sizes == 3) { + if (endianness == kEndiannessLE) + WRITE_LE_UINT32(buf, *((uint32 *) buf)); + else + WRITE_BE_UINT32(buf, *((uint32 *) buf)); + } else if (*sizes == 1) { + if (endianness == kEndiannessLE) + WRITE_LE_UINT16(buf, *((uint16 *) buf)); + else + WRITE_BE_UINT16(buf, *((uint16 *) buf)); + } else if (*sizes != 0) { warning("SaveLoad::toEndian(): Corrupted variables sizes"); return false; @@ -811,7 +822,8 @@ uint32 SaveLoad::write(Common::WriteStream &out, } bool SaveLoad::loadDataEndian(Common::ReadStream &in, - int16 dataVar, uint32 size, byte *variables, byte *variableSizes) { + int16 dataVar, uint32 size, + byte *variables, byte *variableSizes, Endianness endianness) { bool retVal = false; @@ -821,7 +833,7 @@ bool SaveLoad::loadDataEndian(Common::ReadStream &in, assert(varBuf && sizeBuf); if (read(in, varBuf, sizeBuf, size) == size) { - if (fromEndian(varBuf, sizeBuf, size)) { + if (fromEndian(varBuf, sizeBuf, size, endianness)) { memcpy(variables + dataVar, varBuf, size); memcpy(variableSizes + dataVar, sizeBuf, size); retVal = true; @@ -835,7 +847,8 @@ bool SaveLoad::loadDataEndian(Common::ReadStream &in, } bool SaveLoad::saveDataEndian(Common::WriteStream &out, - int16 dataVar, uint32 size, const byte *variables, const byte *variableSizes) { + int16 dataVar, uint32 size, + const byte *variables, const byte *variableSizes, Endianness endianness) { bool retVal = false; @@ -847,7 +860,7 @@ bool SaveLoad::saveDataEndian(Common::WriteStream &out, memcpy(varBuf, variables + dataVar, size); memcpy(sizeBuf, variableSizes + dataVar, size); - if (toEndian(varBuf, sizeBuf, size)) + if (toEndian(varBuf, sizeBuf, size, endianness)) if (write(out, varBuf, sizeBuf, size) == size) retVal = true; diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h index 29f7ee2594..52c3a9b260 100644 --- a/engines/gob/saveload.h +++ b/engines/gob/saveload.h @@ -65,7 +65,7 @@ private: class PlainSave { public: - PlainSave(); + PlainSave(Endianness endianness); ~PlainSave(); bool save(int16 dataVar, int32 size, int32 offset, const char *name, @@ -77,11 +77,14 @@ public: const byte *variables, const byte *variableSizes) const; bool load(int16 dataVar, int32 size, int32 offset, const char *name, byte *variables, byte *variableSizes) const; + +private: + Endianness _endianness; }; class StagedSave { public: - StagedSave(); + StagedSave(Endianness endianness); ~StagedSave(); void addStage(int32 size, bool endianed = true); @@ -114,6 +117,8 @@ private: kModeLoad }; + Endianness _endianness; + Common::Array _stages; enum Mode _mode; char *_name; @@ -178,17 +183,19 @@ public: static const char *stripPath(const char *fileName); - static bool fromEndian(byte *buf, const byte *sizes, uint32 count); - static bool toEndian(byte *buf, const byte *sizes, uint32 count); + static bool fromEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness); + static bool toEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness); static uint32 read(Common::ReadStream &in, byte *buf, byte *sizes, uint32 count); static uint32 write(Common::WriteStream &out, const byte *buf, const byte *sizes, uint32 count); static bool loadDataEndian(Common::ReadStream &in, - int16 dataVar, uint32 size, byte *variables, byte *variableSizes); + int16 dataVar, uint32 size, + byte *variables, byte *variableSizes, Endianness endianness); static bool saveDataEndian(Common::WriteStream &out, - int16 dataVar, uint32 size, const byte *variables, const byte *variableSizes); + int16 dataVar, uint32 size, + const byte *variables, const byte *variableSizes, Endianness endianness); protected: GobEngine *_vm; @@ -228,8 +235,8 @@ protected: int32 _varSize; TempSprite _tmpSprite; - PlainSave _notes; - StagedSave _save; + PlainSave *_notes; + StagedSave *_save; byte _indexBuffer[600]; bool _hasIndex; @@ -306,8 +313,8 @@ protected: TempSprite _screenshot; TempSprite _tmpSprite; - PlainSave _notes; - StagedSave _save; + PlainSave *_notes; + StagedSave *_save; byte _propBuffer[1000]; byte _indexBuffer[1200]; @@ -370,7 +377,7 @@ protected: int32 _varSize; - StagedSave _save; + StagedSave *_save; byte _propBuffer[1000]; byte _indexBuffer[1200]; diff --git a/engines/gob/saveload_v2.cpp b/engines/gob/saveload_v2.cpp index a92fe8cf01..fc11950368 100644 --- a/engines/gob/saveload_v2.cpp +++ b/engines/gob/saveload_v2.cpp @@ -45,6 +45,9 @@ SaveLoad_v2::SaveFile SaveLoad_v2::_saveFiles[] = { SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : SaveLoad(vm, targetName) { + _notes = new PlainSave(_vm->getEndianness()); + _save = new StagedSave(_vm->getEndianness()); + _saveFiles[0].destName = new char[strlen(targetName) + 5]; _saveFiles[1].destName = _saveFiles[0].destName; _saveFiles[2].destName = 0; @@ -58,6 +61,9 @@ SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : } SaveLoad_v2::~SaveLoad_v2() { + delete _notes; + delete _save; + delete[] _saveFiles[0].destName; delete[] _saveFiles[3].destName; } @@ -227,7 +233,7 @@ bool SaveLoad_v2::loadGame(SaveFile &saveFile, return false; } - if (!_save.load(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) + if (!_save->load(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) return false; } @@ -268,7 +274,7 @@ bool SaveLoad_v2::loadNotes(SaveFile &saveFile, debugC(2, kDebugSaveLoad, "Loading the notes"); - return _notes.load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); + return _notes->load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); } bool SaveLoad_v2::saveGame(SaveFile &saveFile, @@ -313,10 +319,10 @@ bool SaveLoad_v2::saveGame(SaveFile &saveFile, byte sizes[40]; memset(sizes, 0, 40); - if(!_save.save(0, 40, 0, saveFile.destName, _indexBuffer + (slot * 40), sizes)) + if(!_save->save(0, 40, 0, saveFile.destName, _indexBuffer + (slot * 40), sizes)) return false; - if (!_save.save(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) + if (!_save->save(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) return false; } @@ -350,7 +356,7 @@ bool SaveLoad_v2::saveNotes(SaveFile &saveFile, debugC(2, kDebugSaveLoad, "Saving the notes"); - return _notes.save(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); + return _notes->save(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); return false; } @@ -360,8 +366,8 @@ void SaveLoad_v2::assertInited() { _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - _save.addStage(40); - _save.addStage(_varSize); + _save->addStage(40); + _save->addStage(_varSize); } } // End of namespace Gob diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp index 67879db3d1..dab5fd9385 100644 --- a/engines/gob/saveload_v3.cpp +++ b/engines/gob/saveload_v3.cpp @@ -48,6 +48,9 @@ SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, uint32 screenshotSize, int32 indexOffset, int32 screenshotOffset) : SaveLoad(vm, targetName) { + _notes = new PlainSave(_vm->getEndianness()); + _save = new StagedSave(_vm->getEndianness()); + _screenshotSize = screenshotSize; _indexOffset = indexOffset; _screenshotOffset = screenshotOffset; @@ -71,6 +74,9 @@ SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, } SaveLoad_v3::~SaveLoad_v3() { + delete _notes; + delete _save; + delete[] _saveFiles[0].destName; delete[] _saveFiles[3].destName; } @@ -243,7 +249,7 @@ int32 SaveLoad_v3::getSizeNotes(SaveFile &saveFile) { int32 SaveLoad_v3::getSizeScreenshot(SaveFile &saveFile) { if (!_useScreenshots) { _useScreenshots = true; - _save.addStage(_screenshotSize, false); + _save->addStage(_screenshotSize, false); } Common::SaveFileManager *saveMan = g_system->getSavefileManager(); @@ -312,7 +318,7 @@ bool SaveLoad_v3::loadGame(SaveFile &saveFile, return false; } - if (!_save.load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + if (!_save->load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) return false; } @@ -353,7 +359,7 @@ bool SaveLoad_v3::loadNotes(SaveFile &saveFile, debugC(2, kDebugSaveLoad, "Loading the notes"); - return _notes.load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); + return _notes->load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); } bool SaveLoad_v3::loadScreenshot(SaveFile &saveFile, @@ -363,7 +369,7 @@ bool SaveLoad_v3::loadScreenshot(SaveFile &saveFile, if (!_useScreenshots) { _useScreenshots = true; - _save.addStage(_screenshotSize, false); + _save->addStage(_screenshotSize, false); } if (offset == _indexOffset) { @@ -395,7 +401,7 @@ bool SaveLoad_v3::loadScreenshot(SaveFile &saveFile, byte *buffer = new byte[_screenshotSize]; - if (!_save.load(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { + if (!_save->load(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { delete[] buffer; return false; } @@ -483,13 +489,13 @@ bool SaveLoad_v3::saveGame(SaveFile &saveFile, _hasIndex = false; - if(!_save.save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) + if(!_save->save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) return false; - if(!_save.save(0, 40, 500, saveFile.destName, _indexBuffer + (saveFile.slot * 40), 0)) + if(!_save->save(0, 40, 500, saveFile.destName, _indexBuffer + (saveFile.slot * 40), 0)) return false; - if (!_save.save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + if (!_save->save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) return false; } @@ -523,7 +529,7 @@ bool SaveLoad_v3::saveNotes(SaveFile &saveFile, debugC(2, kDebugSaveLoad, "Saving the notes"); - return _notes.save(dataVar, size - 160, offset, saveFile.destName, _vm->_inter->_variables); + return _notes->save(dataVar, size - 160, offset, saveFile.destName, _vm->_inter->_variables); return false; } @@ -534,7 +540,7 @@ bool SaveLoad_v3::saveScreenshot(SaveFile &saveFile, if (!_useScreenshots) { _useScreenshots = true; - _save.addStage(_screenshotSize, false); + _save->addStage(_screenshotSize, false); } if (offset >= _screenshotOffset) { @@ -571,7 +577,7 @@ bool SaveLoad_v3::saveScreenshot(SaveFile &saveFile, return false; } - if (!_save.save(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { + if (!_save->save(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { delete[] buffer; return false; } @@ -588,9 +594,9 @@ void SaveLoad_v3::assertInited() { _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - _save.addStage(500); - _save.addStage(40, false); - _save.addStage(_varSize); + _save->addStage(500); + _save->addStage(40, false); + _save->addStage(_varSize); } void SaveLoad_v3::buildScreenshotIndex(byte *buffer, char *name, int n) { diff --git a/engines/gob/saveload_v4.cpp b/engines/gob/saveload_v4.cpp index a6548dd82d..0bd3dc03e6 100644 --- a/engines/gob/saveload_v4.cpp +++ b/engines/gob/saveload_v4.cpp @@ -50,6 +50,8 @@ SaveLoad_v4::SaveFile SaveLoad_v4::_saveFiles[] = { SaveLoad_v4::SaveLoad_v4(GobEngine *vm, const char *targetName) : SaveLoad(vm, targetName) { + _save = new StagedSave(_vm->getEndianness()); + _firstSizeGame = true; _saveFiles[0].destName = 0; @@ -76,6 +78,8 @@ SaveLoad_v4::SaveLoad_v4(GobEngine *vm, const char *targetName) : } SaveLoad_v4::~SaveLoad_v4() { + delete _save; + delete[] _screenProps; delete[] _saveFiles[1].destName; } @@ -297,7 +301,7 @@ bool SaveLoad_v4::loadGame(SaveFile &saveFile, return false; } - if (!_save.load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + if (!_save->load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) return false; } @@ -314,7 +318,7 @@ bool SaveLoad_v4::loadGameScreenProps(SaveFile &saveFile, setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); - if (!_save.load(0, 256000, _varSize + 540, saveFile.destName, + if (!_save->load(0, 256000, _varSize + 540, saveFile.destName, _screenProps, _screenProps + 256000)) return false; @@ -393,13 +397,13 @@ bool SaveLoad_v4::saveGame(SaveFile &saveFile, _hasIndex = false; - if(!_save.save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) + if(!_save->save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) return false; - if(!_save.save(0, 40, 500, saveFile.destName, _indexBuffer + (slot * 40), 0)) + if(!_save->save(0, 40, 500, saveFile.destName, _indexBuffer + (slot * 40), 0)) return false; - if (!_save.save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + if (!_save->save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) return false; } @@ -417,7 +421,7 @@ bool SaveLoad_v4::saveGameScreenProps(SaveFile &saveFile, setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); - if (!_save.save(0, 256000, _varSize + 540, saveFile.destName, + if (!_save->save(0, 256000, _varSize + 540, saveFile.destName, _screenProps, _screenProps + 256000)) return false; @@ -430,10 +434,10 @@ void SaveLoad_v4::assertInited() { _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - _save.addStage(500); - _save.addStage(40, false); - _save.addStage(_varSize); - _save.addStage(256000); + _save->addStage(500); + _save->addStage(40, false); + _save->addStage(_varSize); + _save->addStage(256000); } } // End of namespace Gob -- cgit v1.2.3 From 8932619ee273967821c3c5fc93ae162f75f7d6c8 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 23 Jul 2008 02:45:09 +0000 Subject: More decoupling of inventory code. svn-id: r33224 --- engines/parallaction/graphics.cpp | 6 +++++- engines/parallaction/input.cpp | 26 +++++++++++++------------- engines/parallaction/input.h | 5 +++-- engines/parallaction/inventory.cpp | 4 +--- engines/parallaction/parallaction.cpp | 2 +- engines/parallaction/parallaction.h | 2 +- 6 files changed, 24 insertions(+), 21 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 9b9ea8605a..6f29a6cf3f 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -307,10 +307,14 @@ void Gfx::setProjectorProgram(int16 *data) { } void Gfx::drawInventory() { - +/* if ((_engineFlags & kEngineInventory) == 0) { return; } +*/ + if (_vm->_input->_inputMode != Input::kInputModeInventory) { + return; + } Common::Rect r; _vm->_inventoryRenderer->getRect(r); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 243eaec94f..518c165155 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -171,9 +171,7 @@ void Input::updateGameInput() { } else { _inputData._mousePos = _mousePos; _inputData._event = kEvNone; - if (!translateGameInput()) { - translateInventoryInput(); - } + translateGameInput(); } } @@ -192,6 +190,11 @@ InputData* Input::updateInput() { case kInputModeGame: updateGameInput(); break; + + case kInputModeInventory: + readInput(); + updateInventoryInput(); + break; } return &_inputData; @@ -234,7 +237,7 @@ void Input::walkTo(const Common::Point &dest) { bool Input::translateGameInput() { - if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) { + if (_engineFlags & kEnginePauseJobs) { return false; } @@ -310,6 +313,8 @@ void Input::enterInventoryMode() { _vm->openInventory(); _transCurrentHoverItem = -1; + + _inputMode = kInputModeInventory; } void Input::exitInventoryMode() { @@ -339,22 +344,17 @@ void Input::exitInventoryMode() { _vm->setInventoryCursor(item); } _vm->resumeJobs(); -} - -bool Input::translateInventoryInput() { - if ((_engineFlags & kEngineInventory) == 0) { - return false; - } - - // in inventory - int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + _inputMode = kInputModeGame; +} +bool Input::updateInventoryInput() { if (_mouseButtons == kMouseRightUp) { exitInventoryMode(); return true; } + int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); if (_si != _transCurrentHoverItem) { _transCurrentHoverItem = _si; _vm->highlightInventoryItem(_si); // enable diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 19825c8baa..4d22d7b59b 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -60,7 +60,7 @@ class Input { InputData *translateInput(); bool translateGameInput(); - bool translateInventoryInput(); + bool updateInventoryInput(); void takeAction(ZonePtr z); void walkTo(const Common::Point &dest); @@ -80,7 +80,8 @@ public: enum { kInputModeGame = 0, kInputModeComment = 1, - kInputModeDialogue = 2 + kInputModeDialogue = 2, + kInputModeInventory = 3 }; diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index 58848196d7..71c336bbab 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -131,7 +131,7 @@ void InventoryRenderer::showInventory() { if (!_inv) error("InventoryRenderer not bound to inventory"); - _engineFlags |= kEngineInventory; +// _engineFlags |= kEngineInventory; uint16 lines = getNumLines(); @@ -147,8 +147,6 @@ void InventoryRenderer::showInventory() { void InventoryRenderer::hideInventory() { if (!_inv) error("InventoryRenderer not bound to inventory"); - - _engineFlags &= ~kEngineInventory; } void InventoryRenderer::getRect(Common::Rect& r) const { diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index cdc19c32c4..20f6129d78 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -151,7 +151,7 @@ void Parallaction::clearSet(OpcodeSet &opcodes) { void Parallaction::updateView() { - if ((_engineFlags & kEnginePauseJobs) && (_engineFlags & kEngineInventory) == 0) { + if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) { return; } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 20d0d90d68..387fa43c09 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -101,7 +101,7 @@ enum { enum EngineFlags { kEngineQuit = (1 << 0), kEnginePauseJobs = (1 << 1), - kEngineInventory = (1 << 2), +// kEngineInventory = (1 << 2), kEngineWalking = (1 << 3), kEngineChangeLocation = (1 << 4), kEngineBlockInput = (1 << 5), -- cgit v1.2.3 From 78ccedf8985151c594ef384fda95de295d39bb5c Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 23 Jul 2008 07:31:35 +0000 Subject: Removed useless event management code and made readInput() more general. svn-id: r33225 --- engines/parallaction/input.cpp | 38 +++++++++++++++-------------------- engines/parallaction/input.h | 8 ++++++-- engines/parallaction/parallaction.cpp | 11 ++++------ engines/parallaction/parallaction.h | 6 ------ 4 files changed, 26 insertions(+), 37 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 518c165155..4de5ff711b 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -36,25 +36,23 @@ namespace Parallaction { // loops which could possibly be merged into this one with some effort in changing // caller code, i.e. adding condition checks. // -uint16 Input::readInput() { +void Input::readInput() { Common::Event e; - uint16 KeyDown = 0; _mouseButtons = kMouseNone; - _lastKeyDownAscii = -1; + _hasKeyPressEvent = false; Common::EventManager *eventMan = _vm->_system->getEventManager(); while (eventMan->pollEvent(e)) { switch (e.type) { case Common::EVENT_KEYDOWN: - _lastKeyDownAscii = e.kbd.ascii; + _hasKeyPressEvent = true; + _keyPressed = e.kbd; + if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd') _vm->_debugger->attach(); - if (_vm->getFeatures() & GF_DEMO) break; - if (e.kbd.keycode == Common::KEYCODE_l) KeyDown = kEvLoadGame; - if (e.kbd.keycode == Common::KEYCODE_s) KeyDown = kEvSaveGame; break; case Common::EVENT_LBUTTONDOWN: @@ -83,7 +81,7 @@ uint16 Input::readInput() { case Common::EVENT_QUIT: _engineFlags |= kEngineQuit; - return KeyDown; + return; default: break; @@ -95,13 +93,13 @@ uint16 Input::readInput() { if (_vm->_debugger->isAttached()) _vm->_debugger->onFrame(); - return KeyDown; + return; } bool Input::getLastKeyDown(uint16 &ascii) { - ascii = _lastKeyDownAscii; - return (_lastKeyDownAscii != -1); + ascii = _keyPressed.ascii; + return (_hasKeyPressEvent); } // FIXME: see comment for readInput() @@ -143,7 +141,7 @@ void Input::waitUntilLeftClick() { void Input::updateGameInput() { - int16 keyDown = readInput(); + readInput(); debugC(3, kDebugInput, "translateInput: input flags (%i, %i, %i, %i)", !_mouseHidden, @@ -160,17 +158,13 @@ void Input::updateGameInput() { return; } - if (keyDown == kEvQuitGame) { - _inputData._event = kEvQuitGame; - } else - if (keyDown == kEvSaveGame) { - _inputData._event = kEvSaveGame; - } else - if (keyDown == kEvLoadGame) { - _inputData._event = kEvLoadGame; - } else { + if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) { + if (_keyPressed.keycode == Common::KEYCODE_l) _inputData._event = kEvLoadGame; + if (_keyPressed.keycode == Common::KEYCODE_s) _inputData._event = kEvSaveGame; + } + + if (_inputData._event == kEvNone) { _inputData._mousePos = _mousePos; - _inputData._event = kEvNone; translateGameInput(); } diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 4d22d7b59b..679417c0e5 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -26,6 +26,8 @@ #ifndef PARALLACTION_INPUT_H #define PARALLACTION_INPUT_H +#include "common/keyboard.h" + #include "parallaction/objects.h" #include "parallaction/inventory.h" @@ -53,6 +55,9 @@ class Input { // input-only InputData _inputData; + bool _hasKeyPressEvent; + Common::KeyState _keyPressed; + bool _hasDelayedAction; // actived when the character needs to move before taking an action ZonePtr _delayedActionZone; @@ -68,7 +73,6 @@ class Input { Common::Point _mousePos; uint16 _mouseButtons; - int32 _lastKeyDownAscii; bool _mouseHidden; ZonePtr _hoverZone; @@ -106,7 +110,7 @@ public: int _inputMode; InventoryItem _activeItem; - uint16 readInput(); + void readInput(); InputData* updateInput(); void trackMouse(ZonePtr z); void waitUntilLeftClick(); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 20f6129d78..59a97d1dd4 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -297,6 +297,9 @@ void Parallaction::showLocationComment(const char *text, bool end) { void Parallaction::processInput(InputData *data) { + if (!data) { + return; + } switch (data->_event) { case kEvSaveGame: @@ -326,13 +329,7 @@ void Parallaction::runGame() { runCommentFrame(); if (_input->_inputMode == Input::kInputModeGame) { - if (data->_event != kEvNone) { - processInput(data); - } - - if (_engineFlags & kEngineQuit) - return; - + processInput(data); runPendingZones(); if (_engineFlags & kEngineQuit) diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 387fa43c09..d8ab93e257 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -114,12 +114,6 @@ enum EngineFlags { enum { kEvNone = 0, - kEvAction = 3, - kEvOpenInventory = 4, - kEvCloseInventory = 5, - kEvHoverInventory = 6, - kEvWalk = 7, - kEvQuitGame = 1000, kEvSaveGame = 2000, kEvLoadGame = 4000 }; -- cgit v1.2.3 From 53615c91288b32892e9a8334ea67d4c0059b575c Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 23 Jul 2008 07:52:43 +0000 Subject: Removed the historical waitUntilLeftClick function and adapted code to use the more general readInput and waitForButtonEvent. svn-id: r33226 --- engines/parallaction/callables_ns.cpp | 17 +++---- engines/parallaction/gui_ns.cpp | 83 ++++++++++++++++++-------------- engines/parallaction/input.cpp | 12 ----- engines/parallaction/input.h | 1 - engines/parallaction/parallaction.cpp | 5 +- engines/parallaction/parallaction_ns.cpp | 4 +- 6 files changed, 59 insertions(+), 63 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index ed60a193ce..558d6fdc33 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -340,7 +340,7 @@ void Parallaction_ns::_c_endComment(void *param) { g_system->delayMillis(20); } - _input->waitUntilLeftClick(); + _input->waitForButtonEvent(kMouseLeftUp); _balloonMan->freeBalloons(); return; @@ -396,7 +396,9 @@ void Parallaction_ns::_c_finito(void *parm) { _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100); _gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 130); _gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 160); - _input->waitUntilLeftClick(); + + _gfx->updateScreen(); + _input->waitForButtonEvent(kMouseLeftUp); _gfx->freeLabels(); @@ -498,18 +500,15 @@ void Parallaction_ns::_c_endIntro(void *parm) { id[0] = _gfx->createLabel(_menuFont, "CLICK MOUSE BUTTON TO START", 1); _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80); - - _input->waitUntilLeftClick(); - + _gfx->updateScreen(); + _input->waitForButtonEvent(kMouseLeftUp); _gfx->freeLabels(); - _engineFlags &= ~kEngineBlockInput; selectStartLocation(); - cleanupGame(); - } else { - _input->waitUntilLeftClick(); + _gfx->updateScreen(); + _input->waitForButtonEvent(kMouseLeftUp); } return; diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 9c48586dbc..6068a6a0dd 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -271,15 +271,22 @@ uint16 Parallaction_ns::guiChooseLanguage() { Common::Point p; int selection = -1; + int event; while (selection == -1) { - _input->waitUntilLeftClick(); - _input->getCursorPos(p); - for (uint16 i = 0; i < 4; i++) { - if (blocks[i].contains(p)) { - selection = i; - break; + _input->readInput(); + event = _input->getLastButtonEvent(); + + if (event == kMouseLeftUp) { + _input->getCursorPos(p); + for (uint16 i = 0; i < 4; i++) { + if (blocks[i].contains(p)) { + selection = i; + break; + } } } + + _gfx->updateScreen(); } beep(); @@ -305,9 +312,7 @@ uint16 Parallaction_ns::guiSelectGame() { Common::Point p; - _input->readInput(); - uint32 event = _input->getLastButtonEvent(); - + uint32 event = kMouseNone; while (event != kMouseLeftUp) { _input->readInput(); @@ -432,37 +437,41 @@ int Parallaction_ns::guiSelectCharacter() { _gfx->showLabel(id[0], 60, 30); _di = 0; + int event; while (_di < PASSWORD_LEN) { - - _input->waitUntilLeftClick(); - _input->getCursorPos(p); - - int _si = guiGetSelectedBlock(p); - - if (_si != -1) { - _gfx->grabBackground(codeTrueBlocks[_si], block); - _gfx->patchBackground(block, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, false); - - if (keys[0][_di] == _si) { - points[0]++; - } else - if (keys[1][_di] == _si) { - points[1]++; - } else - if (keys[2][_di] == _si) { - points[2]++; - } else { - fail = true; + _input->readInput(); + event = _input->getLastButtonEvent(); + if (event == kMouseLeftUp) { + + _input->getCursorPos(p); + + int _si = guiGetSelectedBlock(p); + + if (_si != -1) { + _gfx->grabBackground(codeTrueBlocks[_si], block); + _gfx->patchBackground(block, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, false); + + if (keys[0][_di] == _si) { + points[0]++; + } else + if (keys[1][_di] == _si) { + points[1]++; + } else + if (keys[2][_di] == _si) { + points[2]++; + } else { + fail = true; + } + + // build user preference + points[0] += (keys[0][_di] == _si); + points[1] += (keys[1][_di] == _si); + points[2] += (keys[2][_di] == _si); + + _di++; } - - // build user preference - points[0] += (keys[0][_di] == _si); - points[1] += (keys[1][_di] == _si); - points[2] += (keys[2][_di] == _si); - - _di++; } - + _gfx->updateScreen(); } if (!fail) { diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 4de5ff711b..c26e28b377 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -126,18 +126,6 @@ void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { } -// FIXME: see comment for readInput() -void Input::waitUntilLeftClick() { - - do { - readInput(); - _vm->_gfx->updateScreen(); - _vm->_system->delayMillis(30); - } while (_mouseButtons != kMouseLeftUp); - - return; -} - void Input::updateGameInput() { diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 679417c0e5..68acce6554 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -113,7 +113,6 @@ public: void readInput(); InputData* updateInput(); void trackMouse(ZonePtr z); - void waitUntilLeftClick(); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } bool getLastKeyDown(uint16 &ascii); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 59a97d1dd4..e7455220ec 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -384,11 +384,10 @@ void Parallaction::doLocationEnterTransition() { _programExec->runScripts(_location._programs.begin(), _location._programs.end()); drawAnimations(); - + showLocationComment(_location._comment, false); _gfx->updateScreen(); - showLocationComment(_location._comment, false); - _input->waitUntilLeftClick(); + _input->waitForButtonEvent(kMouseLeftUp); _balloonMan->freeBalloons(); // fades maximum intensity palette towards approximation of main palette diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 9e925d1e1d..b2e60c5851 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -323,7 +323,9 @@ void Parallaction_ns::changeLocation(char *location) { showSlide(locname.slide()); uint id = _gfx->createLabel(_menuFont, _location._slideText[0], 1); _gfx->showLabel(id, CENTER_LABEL_HORIZONTAL, 14); - _input->waitUntilLeftClick(); + _gfx->updateScreen(); + + _input->waitForButtonEvent(kMouseLeftUp); _gfx->freeLabels(); freeBackground(); } -- cgit v1.2.3 From c441c5261ff3e6ad114c0384ef818b942655f3a6 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 09:02:47 +0000 Subject: Added Tinsel engine to main repos (no news item for it ON PURPOSE) svn-id: r33230 --- engines/engines.mk | 5 + engines/tinsel/actors.cpp | 896 ++++++++ engines/tinsel/actors.h | 126 ++ engines/tinsel/anim.cpp | 404 ++++ engines/tinsel/anim.h | 72 + engines/tinsel/background.cpp | 240 +++ engines/tinsel/background.h | 165 ++ engines/tinsel/bg.cpp | 189 ++ engines/tinsel/cliprect.cpp | 312 +++ engines/tinsel/cliprect.h | 76 + engines/tinsel/config.cpp | 125 ++ engines/tinsel/config.h | 72 + engines/tinsel/coroutine.h | 124 ++ engines/tinsel/cursor.cpp | 647 ++++++ engines/tinsel/cursor.h | 56 + engines/tinsel/debugger.cpp | 162 ++ engines/tinsel/debugger.h | 49 + engines/tinsel/detection.cpp | 278 +++ engines/tinsel/dw.h | 119 ++ engines/tinsel/effect.cpp | 134 ++ engines/tinsel/events.cpp | 439 ++++ engines/tinsel/events.h | 84 + engines/tinsel/faders.cpp | 175 ++ engines/tinsel/faders.h | 55 + engines/tinsel/film.h | 50 + engines/tinsel/font.cpp | 96 + engines/tinsel/font.h | 48 + engines/tinsel/graphics.cpp | 437 ++++ engines/tinsel/graphics.h | 103 + engines/tinsel/handle.cpp | 366 ++++ engines/tinsel/handle.h | 53 + engines/tinsel/heapmem.cpp | 594 ++++++ engines/tinsel/heapmem.h | 110 + engines/tinsel/inventory.cpp | 4533 +++++++++++++++++++++++++++++++++++++++++ engines/tinsel/inventory.h | 143 ++ engines/tinsel/mareels.cpp | 132 ++ engines/tinsel/module.mk | 52 + engines/tinsel/move.cpp | 1618 +++++++++++++++ engines/tinsel/move.h | 43 + engines/tinsel/multiobj.cpp | 533 +++++ engines/tinsel/multiobj.h | 124 ++ engines/tinsel/music.cpp | 554 +++++ engines/tinsel/music.h | 118 ++ engines/tinsel/object.cpp | 527 +++++ engines/tinsel/object.h | 207 ++ engines/tinsel/palette.cpp | 424 ++++ engines/tinsel/palette.h | 157 ++ engines/tinsel/pcode.cpp | 597 ++++++ engines/tinsel/pcode.h | 158 ++ engines/tinsel/pdisplay.cpp | 649 ++++++ engines/tinsel/pid.h | 72 + engines/tinsel/play.cpp | 507 +++++ engines/tinsel/polygons.cpp | 1805 ++++++++++++++++ engines/tinsel/polygons.h | 186 ++ engines/tinsel/rince.cpp | 708 +++++++ engines/tinsel/rince.h | 209 ++ engines/tinsel/saveload.cpp | 472 +++++ engines/tinsel/savescn.cpp | 335 +++ engines/tinsel/savescn.h | 103 + engines/tinsel/scene.cpp | 308 +++ engines/tinsel/scene.h | 79 + engines/tinsel/sched.cpp | 344 ++++ engines/tinsel/sched.h | 100 + engines/tinsel/scn.cpp | 80 + engines/tinsel/scn.h | 68 + engines/tinsel/scroll.cpp | 432 ++++ engines/tinsel/scroll.h | 77 + engines/tinsel/serializer.h | 131 ++ engines/tinsel/sound.cpp | 257 +++ engines/tinsel/sound.h | 83 + engines/tinsel/strres.cpp | 209 ++ engines/tinsel/strres.h | 69 + engines/tinsel/text.cpp | 279 +++ engines/tinsel/text.h | 101 + engines/tinsel/timers.cpp | 192 ++ engines/tinsel/timers.h | 53 + engines/tinsel/tinlib.cpp | 2980 +++++++++++++++++++++++++++ engines/tinsel/tinlib.h | 41 + engines/tinsel/tinsel.cpp | 1005 +++++++++ engines/tinsel/tinsel.h | 141 ++ engines/tinsel/token.cpp | 129 ++ engines/tinsel/token.h | 57 + 82 files changed, 29042 insertions(+) create mode 100644 engines/tinsel/actors.cpp create mode 100644 engines/tinsel/actors.h create mode 100644 engines/tinsel/anim.cpp create mode 100644 engines/tinsel/anim.h create mode 100644 engines/tinsel/background.cpp create mode 100644 engines/tinsel/background.h create mode 100644 engines/tinsel/bg.cpp create mode 100644 engines/tinsel/cliprect.cpp create mode 100644 engines/tinsel/cliprect.h create mode 100644 engines/tinsel/config.cpp create mode 100644 engines/tinsel/config.h create mode 100644 engines/tinsel/coroutine.h create mode 100644 engines/tinsel/cursor.cpp create mode 100644 engines/tinsel/cursor.h create mode 100644 engines/tinsel/debugger.cpp create mode 100644 engines/tinsel/debugger.h create mode 100644 engines/tinsel/detection.cpp create mode 100644 engines/tinsel/dw.h create mode 100644 engines/tinsel/effect.cpp create mode 100644 engines/tinsel/events.cpp create mode 100644 engines/tinsel/events.h create mode 100644 engines/tinsel/faders.cpp create mode 100644 engines/tinsel/faders.h create mode 100644 engines/tinsel/film.h create mode 100644 engines/tinsel/font.cpp create mode 100644 engines/tinsel/font.h create mode 100644 engines/tinsel/graphics.cpp create mode 100644 engines/tinsel/graphics.h create mode 100644 engines/tinsel/handle.cpp create mode 100644 engines/tinsel/handle.h create mode 100644 engines/tinsel/heapmem.cpp create mode 100644 engines/tinsel/heapmem.h create mode 100644 engines/tinsel/inventory.cpp create mode 100644 engines/tinsel/inventory.h create mode 100644 engines/tinsel/mareels.cpp create mode 100644 engines/tinsel/module.mk create mode 100644 engines/tinsel/move.cpp create mode 100644 engines/tinsel/move.h create mode 100644 engines/tinsel/multiobj.cpp create mode 100644 engines/tinsel/multiobj.h create mode 100644 engines/tinsel/music.cpp create mode 100644 engines/tinsel/music.h create mode 100644 engines/tinsel/object.cpp create mode 100644 engines/tinsel/object.h create mode 100644 engines/tinsel/palette.cpp create mode 100644 engines/tinsel/palette.h create mode 100644 engines/tinsel/pcode.cpp create mode 100644 engines/tinsel/pcode.h create mode 100644 engines/tinsel/pdisplay.cpp create mode 100644 engines/tinsel/pid.h create mode 100644 engines/tinsel/play.cpp create mode 100644 engines/tinsel/polygons.cpp create mode 100644 engines/tinsel/polygons.h create mode 100644 engines/tinsel/rince.cpp create mode 100644 engines/tinsel/rince.h create mode 100644 engines/tinsel/saveload.cpp create mode 100644 engines/tinsel/savescn.cpp create mode 100644 engines/tinsel/savescn.h create mode 100644 engines/tinsel/scene.cpp create mode 100644 engines/tinsel/scene.h create mode 100644 engines/tinsel/sched.cpp create mode 100644 engines/tinsel/sched.h create mode 100644 engines/tinsel/scn.cpp create mode 100644 engines/tinsel/scn.h create mode 100644 engines/tinsel/scroll.cpp create mode 100644 engines/tinsel/scroll.h create mode 100644 engines/tinsel/serializer.h create mode 100644 engines/tinsel/sound.cpp create mode 100644 engines/tinsel/sound.h create mode 100644 engines/tinsel/strres.cpp create mode 100644 engines/tinsel/strres.h create mode 100644 engines/tinsel/text.cpp create mode 100644 engines/tinsel/text.h create mode 100644 engines/tinsel/timers.cpp create mode 100644 engines/tinsel/timers.h create mode 100644 engines/tinsel/tinlib.cpp create mode 100644 engines/tinsel/tinlib.h create mode 100644 engines/tinsel/tinsel.cpp create mode 100644 engines/tinsel/tinsel.h create mode 100644 engines/tinsel/token.cpp create mode 100644 engines/tinsel/token.h (limited to 'engines') diff --git a/engines/engines.mk b/engines/engines.mk index cfb8e69f3e..4dba913173 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -97,6 +97,11 @@ DEFINES += -DENABLE_SWORD2=$(ENABLE_SWORD2) MODULES += engines/sword2 endif +ifdef ENABLE_TINSEL +DEFINES += -DENABLE_TINSEL=$(ENABLE_TINSEL) +MODULES += engines/tinsel +endif + ifdef ENABLE_TOUCHE DEFINES += -DENABLE_TOUCHE=$(ENABLE_TOUCHE) MODULES += engines/touche diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp new file mode 100644 index 0000000000..e0689f1374 --- /dev/null +++ b/engines/tinsel/actors.cpp @@ -0,0 +1,896 @@ +/* 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$ + * + * Handles things to do with actors, delegates much moving actor stuff. + */ + +#include "tinsel/actors.h" +#include "tinsel/events.h" +#include "tinsel/film.h" // for FREEL +#include "tinsel/handle.h" +#include "tinsel/inventory.h" // INV_NOICON +#include "tinsel/move.h" +#include "tinsel/multiobj.h" +#include "tinsel/object.h" // for POBJECT +#include "tinsel/pcode.h" +#include "tinsel/pid.h" +#include "tinsel/rince.h" +#include "tinsel/sched.h" +#include "tinsel/serializer.h" +#include "tinsel/token.h" + +#include "common/util.h" + +namespace Tinsel { + + +//----------------- LOCAL DEFINES -------------------- + + +#include "common/pack-start.h" // START STRUCT PACKING + +/** actor struct - one per actor */ +struct ACTOR_STRUC { + int32 masking; //!< type of actor masking + SCNHANDLE hActorId; //!< handle actor ID string index + SCNHANDLE hActorCode; //!< handle to actor script +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static int LeadActorId = 0; // The lead actor + +static int NumActors = 0; // The total number of actors in the game + +struct ACTORINFO { + bool alive; // TRUE == alive + bool hidden; // TRUE == hidden + bool completed; // TRUE == script played out + + int x, y, z; + + int32 mtype; // DEFAULT(b'ground), MASK, ALWAYS + SCNHANDLE actorCode; // The actor's script + + const FREEL *presReel; // the present reel + int presRnum; // the present reel number + SCNHANDLE presFilm; // the film that reel belongs to + OBJECT *presObj; // reference for position information + int presX, presY; + + bool tagged; // actor tagged? + SCNHANDLE hTag; // handle to tag text + int tType; // e.g. TAG_Q1TO3 + + bool escOn; + int escEv; + + COLORREF tColour; // Text colour + + SCNHANDLE playFilm; // revert to this after talks + SCNHANDLE talkFilm; // this be deleted in the future! + SCNHANDLE latestFilm; // the last film ordered + bool talking; + + int steps; + +}; + +static ACTORINFO *actorInfo = 0; + +static COLORREF defaultColour = 0; // Text colour + +static bool bActorsOn = false; + +static int ti = 0; + +/** + * Called once at start-up time, and again at restart time. + * Registers the total number of actors in the game. + * @param num Chunk Id + */ +void RegisterActors(int num) { + if (actorInfo == NULL) { + // Store the total number of actors in the game + NumActors = num; + + // Check we can save so many + assert(NumActors <= MAX_SAVED_ALIVES); + + // Allocate RAM for actorInfo + // FIXME: For now, we always allocate MAX_SAVED_ALIVES blocks, + // as this makes the save/load code simpler + actorInfo = (ACTORINFO *)calloc(MAX_SAVED_ALIVES, sizeof(ACTORINFO)); + + // make sure memory allocated + if (actorInfo == NULL) { + error("Cannot allocate memory for actors"); + } + } else { + // Check the total number of actors is still the same + assert(num == NumActors); + + memset(actorInfo, 0, MAX_SAVED_ALIVES * sizeof(ACTORINFO)); + } + + // All actors start off alive. + while (num--) + actorInfo[num].alive = true; +} + +void FreeActors() { + if (actorInfo) { + free(actorInfo); + actorInfo = NULL; + } +} + +/** + * Called from dec_lead(), i.e. normally once at start of master script. + * @param leadID Lead Id + */ +void setleadid(int leadID) { + LeadActorId = leadID; + actorInfo[leadID-1].mtype = ACT_MASK; +} + +/** + * No comment. + */ +int LeadId(void) { + return LeadActorId; +} + +struct ATP_INIT { + int id; // Actor number + USER_EVENT event; // Event + BUTEVENT bev; // Causal mouse event +}; + +/** + * Runs actor's glitter code. + */ +static void ActorTinselProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + CORO_END_CONTEXT(_ctx); + + // get the stuff copied to process when it was created + ATP_INIT *atp = (ATP_INIT *)ProcessGetParamsSelf(); + + CORO_BEGIN_CODE(_ctx); + + CORO_INVOKE_1(AllowDclick, atp->bev); // May kill us if single click + + // Run the Glitter code + assert(actorInfo[atp->id - 1].actorCode); // no code to run + + _ctx->pic = InitInterpretContext(GS_ACTOR, actorInfo[atp->id - 1].actorCode, atp->event, NOPOLY, atp->id, NULL); + CORO_INVOKE_1(Interpret, _ctx->pic); + + // If it gets here, actor's code has run to completion + actorInfo[atp->id - 1].completed = true; + + CORO_END_CODE; +} + + +//--------------------------------------------------------------------------- + +struct RATP_INIT { + PINT_CONTEXT pic; + int id; // Actor number +}; + +static void ActorRestoredProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + CORO_END_CONTEXT(_ctx); + + // get the stuff copied to process when it was created + RATP_INIT *r = (RATP_INIT *)ProcessGetParamsSelf(); + + CORO_BEGIN_CODE(_ctx); + + _ctx->pic = RestoreInterpretContext(r->pic); + CORO_INVOKE_1(Interpret, _ctx->pic); + + // If it gets here, actor's code has run to completion + actorInfo[r->id - 1].completed = true; + + CORO_END_CODE; +} + +void RestoreActorProcess(int id, PINT_CONTEXT pic) { + RATP_INIT r = { pic, id }; + + CoroutineInstall(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); +} + +/** + * Starts up process to runs actor's glitter code. + * @param ano Actor Id + * @param event Event structure + * @param be ButEvent + */ +void actorEvent(int ano, USER_EVENT event, BUTEVENT be) { + ATP_INIT atp; + + // Only if there is Glitter code associated with this actor. + if (actorInfo[ano - 1].actorCode) { + atp.id = ano; + atp.event = event; + atp.bev = be; + CoroutineInstall(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); + } +} + +/** + * Called at the start of each scene for each actor with a code block. + * @param as Actor structure + * @param bRunScript Flag for whether to run actor's script for the scene + */ +void StartActor(const ACTOR_STRUC *as, bool bRunScript) { + SCNHANDLE hActorId = FROM_LE_32(as->hActorId); + + // Zero-out many things + actorInfo[hActorId - 1].hidden = false; + actorInfo[hActorId - 1].completed = false; + actorInfo[hActorId - 1].x = 0; + actorInfo[hActorId - 1].y = 0; + actorInfo[hActorId - 1].presReel = NULL; + actorInfo[hActorId - 1].presFilm = 0; + actorInfo[hActorId - 1].presObj = NULL; + + // Store current scene's parameters for this actor + actorInfo[hActorId - 1].mtype = FROM_LE_32(as->masking); + actorInfo[hActorId - 1].actorCode = FROM_LE_32(as->hActorCode); + + // Run actor's script for this scene + if (bRunScript) { + if (bActorsOn) + actorInfo[hActorId - 1].alive = true; + + if (actorInfo[hActorId - 1].alive && FROM_LE_32(as->hActorCode)) + actorEvent(hActorId, STARTUP, BE_NONE); + } +} + +/** + * Called at the start of each scene. Start each actor with a code block. + * @param ah Scene handle + * @param numActors Number of actors + * @param bRunScript Flag for whether to run actor scene scripts + */ +void StartActors(SCNHANDLE ah, int numActors, bool bRunScript) { + int i; + + // Only actors with code blocks got (x, y) re-initialised, so... + for (i = 0; i < NumActors; i++) { + actorInfo[i].x = actorInfo[i].y = 0; + actorInfo[i].mtype = 0; + } + + const ACTOR_STRUC *as = (const ACTOR_STRUC *)LockMem(ah); + for (i = 0; i < numActors; i++, as++) { + StartActor(as, bRunScript); + } +} + +/** + * Called between scenes, zeroises all actors. + */ +void DropActors(void) { + for (int i = 0; i < NumActors; i++) { + actorInfo[i].actorCode = 0; // No script + actorInfo[i].presReel = NULL; // No reel running + actorInfo[i].presFilm = 0; // ditto + actorInfo[i].presObj = NULL; // No object + actorInfo[i].x = 0; // No position + actorInfo[i].y = 0; // ditto + + actorInfo[i].talkFilm = 0; + actorInfo[i].latestFilm = 0; + actorInfo[i].playFilm = 0; + actorInfo[i].talking = false; + } +} + +/** + * Kill actors. + * @param ano Actor Id + */ +void DisableActor(int ano) { + PMACTOR pActor; + + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].alive = false; // Record as dead + actorInfo[ano - 1].x = actorInfo[ano - 1].y = 0; + + // Kill off moving actor properly + pActor = GetMover(ano); + if (pActor) + KillMActor(pActor); +} + +/** + * Enable actors. + * @param ano Actor Id + */ +void EnableActor(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + // Re-incarnate only if it's dead, or it's script ran to completion + if (!actorInfo[ano - 1].alive || actorInfo[ano - 1].completed) { + actorInfo[ano - 1].alive = true; + actorInfo[ano - 1].hidden = false; + actorInfo[ano - 1].completed = false; + + // Re-run actor's script for this scene + if (actorInfo[ano-1].actorCode) + actorEvent(ano, STARTUP, BE_NONE); + } +} + +/** + * Returns the aliveness (to coin a word) of the actor. + * @param ano Actor Id + */ +bool actorAlive(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].alive; +} + +/** + * Define an actor as being tagged. + * @param ano Actor Id + * @param tagtext Scene handle + * @param tp tType + */ +void Tag_Actor(int ano, SCNHANDLE tagtext, int tp) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano-1].tagged = true; + actorInfo[ano-1].hTag = tagtext; + actorInfo[ano-1].tType = tp; +} + +/** + * Undefine an actor as being tagged. + * @param ano Actor Id + * @param tagtext Scene handle + * @param tp tType + */ +void UnTagActor(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano-1].tagged = false; +} + +/** + * Redefine an actor as being tagged. + * @param ano Actor Id + * @param tagtext Scene handle + * @param tp tType + */ +void ReTagActor(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + if (actorInfo[ano-1].hTag) + actorInfo[ano-1].tagged = true; +} + +/** + * Returns a tagged actor's tag type. e.g. TAG_Q1TO3 + * @param ano Actor Id + */ +int TagType(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano-1].tType; +} + +/** + * Returns handle to tagged actor's tag text + * @param ano Actor Id + */ +SCNHANDLE GetActorTag(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].hTag; +} + +/** + * Called from TagProcess, FirstTaggedActor() resets the index, then + * NextTagged Actor is repeatedly called until the caller gets fed up + * or there are no more tagged actors to look at. + */ +void FirstTaggedActor(void) { + ti = 0; +} + +/** + * Called from TagProcess, FirstTaggedActor() resets the index, then + * NextTagged Actor is repeatedly called until the caller gets fed up + * or there are no more tagged actors to look at. + */ +int NextTaggedActor(void) { + PMACTOR pActor; + bool hid; + + do { + if (actorInfo[ti].tagged) { + pActor = GetMover(ti+1); + if (pActor) + hid = getMActorHideState(pActor); + else + hid = actorInfo[ti].hidden; + + if (!hid) { + return ++ti; + } + } + } while (++ti < NumActors); + + return 0; +} + +/** + * Returns the masking type of the actor. + * @param ano Actor Id + */ +int32 actorMaskType(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].mtype; +} + +/** + * Store/Return the currently stored co-ordinates of the actor. + * Delegate the task for moving actors. + * @param ano Actor Id + * @param x X position + * @param y Y position + */ +void storeActorPos(int ano, int x, int y) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].x = x; + actorInfo[ano - 1].y = y; +} + +void storeActorSteps(int ano, int steps) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].steps = steps; +} + +int getActorSteps(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].steps; +} + +void storeActorZpos(int ano, int z) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].z = z; +} + + +void GetActorPos(int ano, int *x, int *y) { + PMACTOR pActor; + + assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // unknown actor + + pActor = GetMover(ano); + + if (pActor) + GetMActorPosition(pActor, x, y); + else { + *x = actorInfo[ano - 1].x; + *y = actorInfo[ano - 1].y; + } +} + +/** + * Returns the position of the mid-top of the actor. + * Delegate the task for moving actors. + * @param ano Actor Id + * @param x Output x + * @param y Output y + */ +void GetActorMidTop(int ano, int *x, int *y) { + // Not used in JAPAN version + PMACTOR pActor; + + assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // unknown actor + + pActor = GetMover(ano); + + if (pActor) + GetMActorMidTopPosition(pActor, x, y); + else if (actorInfo[ano - 1].presObj) { + *x = (MultiLeftmost(actorInfo[ano - 1].presObj) + + MultiRightmost(actorInfo[ano - 1].presObj)) / 2; + *y = MultiHighest(actorInfo[ano - 1].presObj); + } else + GetActorPos(ano, x, y); // The best we can do! +} + +/** + * Return the appropriate co-ordinate of the actor. + * @param ano Actor Id + */ +int GetActorLeft(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + if (!actorInfo[ano - 1].presObj) + return 0; + + return MultiLeftmost(actorInfo[ano - 1].presObj); +} + +/** + * Return the appropriate co-ordinate of the actor. + * @param ano Actor Id + */ +int GetActorRight(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + if (!actorInfo[ano - 1].presObj) + return 0; + + return MultiRightmost(actorInfo[ano - 1].presObj); +} + +/** + * Return the appropriate co-ordinate of the actor. + * @param ano Actor Id + */ +int GetActorTop(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + if (!actorInfo[ano - 1].presObj) + return 0; + + return MultiHighest(actorInfo[ano - 1].presObj); +} + +/** + * Return the appropriate co-ordinate of the actor. + */ +int GetActorBottom(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + if (!actorInfo[ano - 1].presObj) + return 0; + + return MultiLowest(actorInfo[ano - 1].presObj); +} + +/** + * Set actor hidden status to true. + * For a moving actor, actually hide it. + * @param ano Actor Id + */ +void HideActor(int ano) { + PMACTOR pActor; + + assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // illegal actor + + // Get moving actor involved + pActor = GetMover(ano); + + if (pActor) + hideMActor(pActor, 0); + else + actorInfo[ano - 1].hidden = true; +} + +/** + * Hide an actor if it's a moving actor. + * @param ano Actor Id + * @param sf sf + */ +bool HideMovingActor(int ano, int sf) { + PMACTOR pActor; + + assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // illegal actor + + // Get moving actor involved + pActor = GetMover(ano); + + if (pActor) { + hideMActor(pActor, sf); + return true; + } else { + if (actorInfo[ano - 1].presObj != NULL) + MultiHideObject(actorInfo[ano - 1].presObj); // Hidee object + return false; + } +} + +/** + * Unhide an actor if it's a moving actor. + * @param ano Actor Id + */ +void unHideMovingActor(int ano) { + PMACTOR pActor; + + assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // illegal actor + + // Get moving actor involved + pActor = GetMover(ano); + + assert(pActor); // not a moving actor + + unhideMActor(pActor); +} + +/** + * Called after a moving actor had been replaced by an splay(). + * Moves the actor to where the splay() left it, and continues the + * actor's walk (if any) from the new co-ordinates. + */ +void restoreMovement(int ano) { + PMACTOR pActor; + + assert(ano > 0 && ano <= NumActors); // illegal actor number + + // Get moving actor involved + pActor = GetMover(ano); + + assert(pActor); // not a moving actor + + if (pActor->objx == actorInfo[ano - 1].x && pActor->objy == actorInfo[ano - 1].y) + return; + + pActor->objx = actorInfo[ano - 1].x; + pActor->objy = actorInfo[ano - 1].y; + + if (pActor->actorObj) + SSetActorDest(pActor); +} + +/** + * More properly should be called: + * 'store_actor_reel_and/or_film_and/or_object()' + */ +void storeActorReel(int ano, const FREEL *reel, SCNHANDLE film, OBJECT *pobj, int reelnum, int x, int y) { + PMACTOR pActor; + + assert(ano > 0 && ano <= NumActors); // illegal actor number + + pActor = GetMover(ano); + + // Only store the reel and film for a moving actor if NOT called from MActorProcess() + // (MActorProcess() calls with reel=film=NULL, pobj not NULL) + if (!pActor + || !(reel == NULL && film == 0 && pobj != NULL)) { + actorInfo[ano - 1].presReel = reel; // Store reel + actorInfo[ano - 1].presRnum = reelnum; // Store reel number + actorInfo[ano - 1].presFilm = film; // Store film + actorInfo[ano - 1].presX = x; + actorInfo[ano - 1].presY = y; + } + + // Only store the object for a moving actor if called from MActorProcess() + if (!pActor) { + actorInfo[ano - 1].presObj = pobj; // Store object + } else if (reel == NULL && film == 0 && pobj != NULL) { + actorInfo[ano - 1].presObj = pobj; // Store object + } +} + +/** + * Return the present reel/film of the actor. + */ +const FREEL *actorReel(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].presReel; // the present reel +} + +/***************************************************************************/ + +void setActorPlayFilm(int ano, SCNHANDLE film) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].playFilm = film; +} + +SCNHANDLE getActorPlayFilm(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].playFilm; +} + +void setActorTalkFilm(int ano, SCNHANDLE film) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].talkFilm = film; +} + +SCNHANDLE getActorTalkFilm(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].talkFilm; +} + +void setActorTalking(int ano, bool tf) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].talking = tf;; +} + +bool isActorTalking(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].talking; +} + +void setActorLatestFilm(int ano, SCNHANDLE film) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].latestFilm = film; + actorInfo[ano - 1].steps = 0; +} + +SCNHANDLE getActorLatestFilm(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].latestFilm; +} + +/***************************************************************************/ + +void updateActorEsc(int ano, bool escOn, int escEvent) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + actorInfo[ano - 1].escOn = escOn; + actorInfo[ano - 1].escEv = escEvent; +} + +bool actorEsc(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].escOn; +} + +int actorEev(int ano) { + assert(ano > 0 && ano <= NumActors); // illegal actor number + + return actorInfo[ano - 1].escEv; +} + +/** + * Guess what these do. + */ +int AsetZPos(OBJECT *pObj, int y, int32 z) { + int zPos; + + z += z ? -1 : 0; + + zPos = y + (z << 10); + MultiSetZPosition(pObj, zPos); + return zPos; +} + +/** + * Guess what these do. + */ +void MAsetZPos(PMACTOR pActor, int y, int32 zFactor) { + if (!pActor->aHidden) + AsetZPos(pActor->actorObj, y, zFactor); +} + +/** + * Stores actor's attributes. + * Currently only the speech colours. + */ +void storeActorAttr(int ano, int r1, int g1, int b1) { + assert((ano > 0 && ano <= NumActors) || ano == -1); // illegal actor number + + if (r1 > MAX_INTENSITY) r1 = MAX_INTENSITY; // } Ensure + if (g1 > MAX_INTENSITY) g1 = MAX_INTENSITY; // } within limits + if (b1 > MAX_INTENSITY) b1 = MAX_INTENSITY; // } + + if (ano == -1) + defaultColour = RGB(r1, g1, b1); + else + actorInfo[ano - 1].tColour = RGB(r1, g1, b1); +} + +/** + * Get the actor's stored speech colour. + * @param ano Actor Id + */ +COLORREF getActorTcol(int ano) { + // Not used in JAPAN version + assert(ano > 0 && ano <= NumActors); // illegal actor number + + if (actorInfo[ano - 1].tColour) + return actorInfo[ano - 1].tColour; + else + return defaultColour; +} + +/** + * Store relevant information pertaining to currently existing actors. + */ +int SaveActors(PSAVED_ACTOR sActorInfo) { + int i, j; + + for (i = 0, j = 0; i < NumActors; i++) { + if (actorInfo[i].presObj != NULL) { + assert(j < MAX_SAVED_ACTORS); // Saving too many actors + +// sActorInfo[j].hidden = actorInfo[i].hidden; + sActorInfo[j].bAlive = actorInfo[i].alive; +// sActorInfo[j].x = (short)actorInfo[i].x; +// sActorInfo[j].y = (short)actorInfo[i].y; + sActorInfo[j].z = (short)actorInfo[i].z; +// sActorInfo[j].presReel = actorInfo[i].presReel; + sActorInfo[j].presRnum = (short)actorInfo[i].presRnum; + sActorInfo[j].presFilm = actorInfo[i].presFilm; + sActorInfo[j].presX = (short)actorInfo[i].presX; + sActorInfo[j].presY = (short)actorInfo[i].presY; + sActorInfo[j].actorID = (short)(i+1); + j++; + } + } + + return j; +} + +void setactorson(void) { + bActorsOn = true; +} + +void ActorsLife(int ano, bool bAlive) { + assert((ano > 0 && ano <= NumActors) || ano == -1); // illegal actor number + + actorInfo[ano-1].alive = bAlive; +} + + +void syncAllActorsAlive(Serializer &s) { + for (int i = 0; i < MAX_SAVED_ALIVES; i++) { + s.syncAsByte(actorInfo[i].alive); + s.syncAsByte(actorInfo[i].tagged); + s.syncAsByte(actorInfo[i].tType); + s.syncAsUint32LE(actorInfo[i].hTag); + } +} + + +} // end of namespace Tinsel diff --git a/engines/tinsel/actors.h b/engines/tinsel/actors.h new file mode 100644 index 0000000000..7707dd636d --- /dev/null +++ b/engines/tinsel/actors.h @@ -0,0 +1,126 @@ +/* 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$ + * + * Prototypes of actor functions + */ + +#ifndef TINSEL_ACTOR_H // prevent multiple includes +#define TINSEL_ACTOR_H + + +#include "tinsel/dw.h" // for SCNHANDLE +#include "tinsel/events.h" // for USER_EVENT +#include "tinsel/palette.h" // for COLORREF + +namespace Tinsel { + +struct FREEL; +struct INT_CONTEXT; +struct MACTOR; +struct OBJECT; + + +/*----------------------------------------------------------------------*/ + +void RegisterActors(int num); +void FreeActors(void); +void setleadid(int rid); +int LeadId(void); +void StartActors(SCNHANDLE ah, int numActors, bool bRunScript); +void DropActors(void); // No actor reels running +void DisableActor(int actor); +void EnableActor(int actor); +void Tag_Actor(int ano, SCNHANDLE tagtext, int tp); +void UnTagActor(int ano); +void ReTagActor(int ano); +int TagType(int ano); +bool actorAlive(int ano); +int32 actorMaskType(int ano); +void GetActorPos(int ano, int *x, int *y); +void SetActorPos(int ano, int x, int y); +void GetActorMidTop(int ano, int *x, int *y); +int GetActorLeft(int ano); +int GetActorRight(int ano); +int GetActorTop(int ano); +int GetActorBottom(int ano); +void HideActor(int ano); +bool HideMovingActor(int id, int sf); +void unHideMovingActor(int id); +void restoreMovement(int id); +void storeActorReel(int ano, const FREEL *reel, SCNHANDLE film, OBJECT *pobj, int reelnum, int x, int y); +const FREEL *actorReel(int ano); +SCNHANDLE actorFilm(int ano); + +void setActorPlayFilm(int ano, SCNHANDLE film); +SCNHANDLE getActorPlayFilm(int ano); +void setActorTalkFilm(int ano, SCNHANDLE film); +SCNHANDLE getActorTalkFilm(int ano); +void setActorTalking(int ano, bool tf); +bool isActorTalking(int ano); +void setActorLatestFilm(int ano, SCNHANDLE film); +SCNHANDLE getActorLatestFilm(int ano); + +void updateActorEsc(int ano, bool escOn, int escEv); +bool actorEsc(int ano); +int actorEev(int ano); +void storeActorPos(int ano, int x, int y); +void storeActorSteps(int ano, int steps); +int getActorSteps(int ano); +void storeActorZpos(int ano, int z); +SCNHANDLE GetActorTag(int ano); +void FirstTaggedActor(void); +int NextTaggedActor(void); +int AsetZPos(OBJECT *pObj, int y, int32 zFactor); +void MAsetZPos(MACTOR *pActor, int y, int32 zFactor); +void actorEvent(int ano, USER_EVENT event, BUTEVENT be); + +void storeActorAttr(int ano, int r1, int g1, int b1); +COLORREF getActorTcol(int ano); + +void setactorson(void); + +void ActorsLife(int id, bool bAlive); + +/*----------------------------------------------------------------------*/ + +struct SAVED_ACTOR { + short actorID; + short z; + bool bAlive; + SCNHANDLE presFilm; //!< the film that reel belongs to + short presRnum; //!< the present reel number + short presX, presY; +}; +typedef SAVED_ACTOR *PSAVED_ACTOR; + +int SaveActors(PSAVED_ACTOR sActorInfo); + + +void RestoreActorProcess(int id, INT_CONTEXT *pic); + + +/*----------------------------------------------------------------------*/ + +} // end of namespace Tinsel + +#endif /* TINSEL_ACTOR_H */ diff --git a/engines/tinsel/anim.cpp b/engines/tinsel/anim.cpp new file mode 100644 index 0000000000..266c39bca8 --- /dev/null +++ b/engines/tinsel/anim.cpp @@ -0,0 +1,404 @@ +/* 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$ + * + * This file contains utilities to handle object animation. + */ + +#include "tinsel/anim.h" +#include "tinsel/handle.h" +#include "tinsel/multiobj.h" // multi-part object defintions etc. +#include "tinsel/object.h" +#include "tinsel/sched.h" + +#include "common/util.h" + +namespace Tinsel { + +/** Animation script commands */ +enum { + ANI_END = 0, //!< end of animation script + ANI_JUMP = 1, //!< animation script jump + ANI_HFLIP = 2, //!< flip animated object horizontally + ANI_VFLIP = 3, //!< flip animated object vertically + ANI_HVFLIP = 4, //!< flip animated object in both directions + ANI_ADJUSTX = 5, //!< adjust animated object x animation point + ANI_ADJUSTY = 6, //!< adjust animated object y animation point + ANI_ADJUSTXY = 7, //!< adjust animated object x & y animation points + ANI_NOSLEEP = 8, //!< do not sleep for this frame + ANI_CALL = 9, //!< call routine + ANI_HIDE = 10 //!< hide animated object +}; + +/** animation script command possibilities */ +union ANI_SCRIPT { + int32 op; //!< treat as an opcode or operand + uint32 hFrame; //!< treat as a animation frame handle +}; + +/** + * Advance to next frame routine. + * @param pAnim Animation data structure + */ +SCRIPTSTATE DoNextFrame(PANIM pAnim) { + // get a pointer to the script + const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript); + + while (1) { // repeat until a real image + + switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) { + case ANI_END: // end of animation script + + // move to next opcode + pAnim->scriptIndex++; + + // indicate script has finished + return ScriptFinished; + + case ANI_JUMP: // do animation jump + + // move to jump address + pAnim->scriptIndex++; + + // jump to new frame position + pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); + + // go fetch a real image + break; + + case ANI_HFLIP: // flip animated object horizontally + + // next opcode + pAnim->scriptIndex++; + + MultiHorizontalFlip(pAnim->pObject); + + // go fetch a real image + break; + + case ANI_VFLIP: // flip animated object vertically + + // next opcode + pAnim->scriptIndex++; + + MultiVerticalFlip(pAnim->pObject); + + // go fetch a real image + break; + + case ANI_HVFLIP: // flip animated object in both directions + + // next opcode + pAnim->scriptIndex++; + + MultiHorizontalFlip(pAnim->pObject); + MultiVerticalFlip(pAnim->pObject); + + // go fetch a real image + break; + + case ANI_ADJUSTX: // adjust animated object x animation point + + // move to x adjustment operand + pAnim->scriptIndex++; + + MultiAdjustXY(pAnim->pObject, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op), 0); + + // next opcode + pAnim->scriptIndex++; + + // go fetch a real image + break; + + case ANI_ADJUSTY: // adjust animated object y animation point + + // move to y adjustment operand + pAnim->scriptIndex++; + + MultiAdjustXY(pAnim->pObject, 0, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)); + + // next opcode + pAnim->scriptIndex++; + + // go fetch a real image + break; + + case ANI_ADJUSTXY: // adjust animated object x & y animation points + { + int x, y; + + // move to x adjustment operand + pAnim->scriptIndex++; + x = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); + + // move to y adjustment operand + pAnim->scriptIndex++; + y = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); + + MultiAdjustXY(pAnim->pObject, x, y); + + // next opcode + pAnim->scriptIndex++; + + // go fetch a real image + break; + } + + case ANI_NOSLEEP: // do not sleep for this frame + + // next opcode + pAnim->scriptIndex++; + + // indicate not to sleep + return ScriptNoSleep; + + case ANI_CALL: // call routine + + // move to function address + pAnim->scriptIndex++; + + // make function call + + // REMOVED BUGGY CODE + // pFunc is a function pointer that's part of a union and is assumed to be 32-bits. + // There is no known place where a function pointer is stored inside the animation + // scripts, something which wouldn't have worked anyway. Having played through the + // entire game, there hasn't been any occurence of this case, so just error out here + // in case we missed something (highly unlikely though) + error("ANI_CALL opcode encountered! Please report this error to the ScummVM team"); + //(*pAni[pAnim->scriptIndex].pFunc)(pAnim); + + // next opcode + pAnim->scriptIndex++; + + // go fetch a real image + break; + + case ANI_HIDE: // hide animated object + + MultiHideObject(pAnim->pObject); + + // next opcode + pAnim->scriptIndex++; + + // dont skip a sleep + return ScriptSleep; + + default: // must be an actual animation frame handle + + // set objects new animation frame + pAnim->pObject->hShape = FROM_LE_32(pAni[pAnim->scriptIndex].hFrame); + + // re-shape the object + MultiReshape(pAnim->pObject); + + // next opcode + pAnim->scriptIndex++; + + // dont skip a sleep + return ScriptSleep; + } + } +} + +/** + * Init a ANIM structure for single stepping through a animation script. + * @param pAnim Animation data structure + * @param pAniObj Object to animate + * @param hNewScript Script of multipart frames + * @param aniSpeed Sets speed of animation in frames + */ +void InitStepAnimScript(PANIM pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) { + OBJECT *pObj; // multi-object list iterator + + pAnim->aniDelta = 1; // will animate on next call to NextAnimRate + pAnim->pObject = pAniObj; // set object to animate + pAnim->hScript = hNewScript; // set animation script + pAnim->scriptIndex = 0; // start of script + pAnim->aniRate = aniSpeed; // set speed of animation + + // reset flip flags for the object - let the script do the flipping + for (pObj = pAniObj; pObj != NULL; pObj = pObj->pSlave) { + AnimateObjectFlags(pObj, pObj->flags & ~(DMA_FLIPH | DMA_FLIPV), + pObj->hImg); + } +} + +/** + * Execute the next command in a animation script. + * @param pAnim Animation data structure + */ +SCRIPTSTATE StepAnimScript(PANIM pAnim) { + SCRIPTSTATE state; + + if (--pAnim->aniDelta == 0) { + // re-init animation delta counter + pAnim->aniDelta = pAnim->aniRate; + + // move to next frame + while ((state = DoNextFrame(pAnim)) == ScriptNoSleep) + ; + + return state; + } + + // indicate calling task should sleep + return ScriptSleep; +} + +/** + * Skip the specified number of frames. + * @param pAnim Animation data structure + * @param numFrames Number of frames to skip + */ +void SkipFrames(PANIM pAnim, int numFrames) { + // get a pointer to the script + const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript); + + if (numFrames <= 0) + // do nothing + return; + + while (1) { // repeat until a real image + + switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) { + case ANI_END: // end of animation script + // going off the end is probably a error + error("SkipFrames(): formally 'assert(0)!'"); + break; + + case ANI_JUMP: // do animation jump + + // move to jump address + pAnim->scriptIndex++; + + // jump to new frame position + pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); + break; + + case ANI_HFLIP: // flip animated object horizontally + + // next opcode + pAnim->scriptIndex++; + + MultiHorizontalFlip(pAnim->pObject); + break; + + case ANI_VFLIP: // flip animated object vertically + + // next opcode + pAnim->scriptIndex++; + + MultiVerticalFlip(pAnim->pObject); + break; + + case ANI_HVFLIP: // flip animated object in both directions + + // next opcode + pAnim->scriptIndex++; + + MultiHorizontalFlip(pAnim->pObject); + MultiVerticalFlip(pAnim->pObject); + break; + + case ANI_ADJUSTX: // adjust animated object x animation point + + // move to x adjustment operand + pAnim->scriptIndex++; + + MultiAdjustXY(pAnim->pObject, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op), 0); + + // next opcode + pAnim->scriptIndex++; + break; + + case ANI_ADJUSTY: // adjust animated object y animation point + + // move to y adjustment operand + pAnim->scriptIndex++; + + MultiAdjustXY(pAnim->pObject, 0, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)); + + // next opcode + pAnim->scriptIndex++; + break; + + case ANI_ADJUSTXY: // adjust animated object x & y animation points + { + int x, y; + + // move to x adjustment operand + pAnim->scriptIndex++; + x = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); + + // move to y adjustment operand + pAnim->scriptIndex++; + y = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); + + MultiAdjustXY(pAnim->pObject, x, y); + + // next opcode + pAnim->scriptIndex++; + + break; + } + + case ANI_NOSLEEP: // do not sleep for this frame + + // next opcode + pAnim->scriptIndex++; + break; + + case ANI_CALL: // call routine + + // skip function address + pAnim->scriptIndex += 2; + break; + + case ANI_HIDE: // hide animated object + + // next opcode + pAnim->scriptIndex++; + break; + + default: // must be an actual animation frame handle + + // one less frame + if (numFrames-- > 0) { + // next opcode + pAnim->scriptIndex++; + } else { + // set objects new animation frame + pAnim->pObject->hShape = FROM_LE_32(pAni[pAnim->scriptIndex].hFrame); + + // re-shape the object + MultiReshape(pAnim->pObject); + + // we have skipped to the correct place + return; + } + break; + } + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/anim.h b/engines/tinsel/anim.h new file mode 100644 index 0000000000..a6ac574350 --- /dev/null +++ b/engines/tinsel/anim.h @@ -0,0 +1,72 @@ +/* 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$ + * + * Object animation definitions + */ + +#ifndef TINSEL_ANIM_H // prevent multiple includes +#define TINSEL_ANIM_H + +#include "tinsel/dw.h" // for SCNHANDLE + +namespace Tinsel { + +struct OBJECT; + +/** animation structure */ +struct ANIM { + int aniRate; //!< animation speed + int aniDelta; //!< animation speed delta counter + OBJECT *pObject; //!< object to animate (assumed to be multi-part) + uint32 hScript; //!< animation script handle + int scriptIndex; //!< current position in animation script +}; +typedef ANIM *PANIM; + + +/*----------------------------------------------------------------------*\ +|* Anim Function Prototypes *| +\*----------------------------------------------------------------------*/ + +/** states for DoNextFrame */ +enum SCRIPTSTATE {ScriptFinished, ScriptNoSleep, ScriptSleep}; + +SCRIPTSTATE DoNextFrame( // Execute the next animation frame of a animation script + ANIM *pAnim); // animation data structure + +void InitStepAnimScript( // Init a ANIM struct for single stepping through a animation script + ANIM *pAnim, // animation data structure + OBJECT *pAniObj, // object to animate + SCNHANDLE hNewScript, // handle to script of multipart frames + int aniSpeed); // sets speed of animation in frames + +SCRIPTSTATE StepAnimScript( // Execute the next command in a animation script + ANIM *pAnim); // animation data structure + +void SkipFrames( // Skip the specified number of frames + ANIM *pAnim, // animation data structure + int numFrames); // number of frames to skip + +} // end of namespace Tinsel + +#endif // TINSEL_ANIM_H diff --git a/engines/tinsel/background.cpp b/engines/tinsel/background.cpp new file mode 100644 index 0000000000..05d36e9412 --- /dev/null +++ b/engines/tinsel/background.cpp @@ -0,0 +1,240 @@ +/* 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$ + * + * Background handling code. + */ + +#include "tinsel/background.h" +#include "tinsel/cliprect.h" // object clip rect defs +#include "tinsel/graphics.h" +#include "tinsel/sched.h" // process sheduler defs +#include "tinsel/object.h" +#include "tinsel/pid.h" // process identifiers +#include "tinsel/tinsel.h" + +namespace Tinsel { + +// screen clipping rectangle +Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + +// current background +BACKGND *pCurBgnd = NULL; + +// scroll flag - when set scrolling and velocity additions are paused +bool bNoScroll; + +/** + * Called to initialise a background. + * @param pBgnd Pointer to data struct for current background + */ + +void InitBackground(BACKGND *pBgnd) { + int i; // playfield counter + PPLAYFIELD pPlayfield; // pointer to current playfield + + // set current background + pCurBgnd = pBgnd; + + // init background sky colour + SetBgndColour(pBgnd->rgbSkyColour); + + // start of playfield array + pPlayfield = pBgnd->fieldArray; + + // for each background playfield + for (i = 0; i < pBgnd->numPlayfields; i++, pPlayfield++) { + // init playfield pos + pPlayfield->fieldX = intToFrac(pBgnd->ptInitWorld.x); + pPlayfield->fieldY = intToFrac(pBgnd->ptInitWorld.y); + + // no scrolling + pPlayfield->fieldXvel = intToFrac(0); + pPlayfield->fieldYvel = intToFrac(0); + + // clear playfield display list + pPlayfield->pDispList = NULL; + + // clear playfield moved flag + pPlayfield->bMoved = false; + } +} + +/** + * Sets the xy position of the specified playfield in the current background. + * @param which Which playfield + * @param newXpos New x position + * @param newYpos New y position + */ + +void PlayfieldSetPos(int which, int newXpos, int newYpos) { + PPLAYFIELD pPlayfield; // pointer to relavent playfield + + // make sure there is a background + assert(pCurBgnd != NULL); + + // make sure the playfield number is in range + assert(which >= 0 && which < pCurBgnd->numPlayfields); + + // get playfield pointer + pPlayfield = pCurBgnd->fieldArray + which; + + // set new integer position + pPlayfield->fieldX = intToFrac(newXpos); + pPlayfield->fieldY = intToFrac(newYpos); + + // set moved flag + pPlayfield->bMoved = true; +} + +/** + * Returns the xy position of the specified playfield in the current background. + * @param which Which playfield + * @param pXpos Returns current x position + * @param pYpos Returns current y position + */ + +void PlayfieldGetPos(int which, int *pXpos, int *pYpos) { + PPLAYFIELD pPlayfield; // pointer to relavent playfield + + // make sure there is a background + assert(pCurBgnd != NULL); + + // make sure the playfield number is in range + assert(which >= 0 && which < pCurBgnd->numPlayfields); + + // get playfield pointer + pPlayfield = pCurBgnd->fieldArray + which; + + // get current integer position + *pXpos = fracToInt(pPlayfield->fieldX); + *pYpos = fracToInt(pPlayfield->fieldY); +} + +/** + * Returns the display list for the specified playfield. + * @param which Which playfield + */ + +OBJECT *GetPlayfieldList(int which) { + PPLAYFIELD pPlayfield; // pointer to relavent playfield + + // make sure there is a background + assert(pCurBgnd != NULL); + + // make sure the playfield number is in range + assert(which >= 0 && which < pCurBgnd->numPlayfields); + + // get playfield pointer + pPlayfield = pCurBgnd->fieldArray + which; + + // return the display list pointer for this playfield + return (OBJECT *)&pPlayfield->pDispList; +} + +/** + * Draws all the playfield object lists for the current background. + * The playfield velocity is added to the playfield position in order + * to scroll each playfield before it is drawn. + */ + +void DrawBackgnd(void) { + int i; // playfield counter + PPLAYFIELD pPlay; // playfield pointer + int prevX, prevY; // save interger part of position + Common::Point ptWin; // window top left + + if (pCurBgnd == NULL) + return; // no current background + + // scroll each background playfield + for (i = 0; i < pCurBgnd->numPlayfields; i++) { + // get pointer to correct playfield + pPlay = pCurBgnd->fieldArray + i; + + // save integer part of position + prevX = fracToInt(pPlay->fieldX); + prevY = fracToInt(pPlay->fieldY); + + if (!bNoScroll) { + // update scrolling + pPlay->fieldX += pPlay->fieldXvel; + pPlay->fieldY += pPlay->fieldYvel; + + // convert fixed point window pos to a int + ptWin.x = fracToInt(pPlay->fieldX); + ptWin.y = fracToInt(pPlay->fieldY); + + // set the moved flag if the playfield has moved + if (prevX != ptWin.x || prevY != ptWin.y) + pPlay->bMoved = true; + } + + // sort the display list for this background - just in case somebody has changed object Z positions + SortObjectList((OBJECT *)&pPlay->pDispList); + + // generate clipping rects for all objects that have moved etc. + FindMovingObjects((OBJECT *)&pPlay->pDispList, &ptWin, + &pPlay->rcClip, bNoScroll, pPlay->bMoved); + + // clear playfield moved flag + pPlay->bMoved = false; + } + + // merge the clipping rectangles + MergeClipRect(); + + // redraw all playfields within the clipping rectangles + const RectList &clipRects = GetClipRects(); + for (RectList::const_iterator r = clipRects.begin(); r != clipRects.end(); ++r) { + // clear the clip rectangle on the virtual screen + // for each background playfield + for (i = 0; i < pCurBgnd->numPlayfields; i++) { + Common::Rect rcPlayClip; // clip rect for this playfield + + // get pointer to correct playfield + pPlay = pCurBgnd->fieldArray + i; + + // convert fixed point window pos to a int + ptWin.x = fracToInt(pPlay->fieldX); + ptWin.y = fracToInt(pPlay->fieldY); + + if (IntersectRectangle(rcPlayClip, pPlay->rcClip, *r)) + // redraw all objects within this clipping rect + UpdateClipRect((OBJECT *)&pPlay->pDispList, + &ptWin, &rcPlayClip); + } + } + + // transfer any new palettes to the video DAC + PalettesToVideoDAC(); + + // update the screen within the clipping rectangles + for (RectList::const_iterator r = clipRects.begin(); r != clipRects.end(); ++r) { + UpdateScreenRect(*r); + } + + // delete all the clipping rectangles + ResetClipRect(); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/background.h b/engines/tinsel/background.h new file mode 100644 index 0000000000..7409fd0785 --- /dev/null +++ b/engines/tinsel/background.h @@ -0,0 +1,165 @@ +/* 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$ + * + * Data structures used for handling backgrounds + */ + +#ifndef TINSEL_BACKGND_H // prevent multiple includes +#define TINSEL_BACKGND_H + +#include "tinsel/dw.h" // for SCNHANDLE +#include "tinsel/palette.h" // palette definitions +#include "common/frac.h" +#include "common/rect.h" + +namespace Tinsel { + +struct OBJECT; + + +/** Scrolling padding. Needed because scroll process does not normally run on every frame */ +enum { + SCROLLX_PAD = 64, + SCROLLY_PAD = 64 +}; + +/** When module BLK_INFO list is this long, switch from a binary to linear search */ +#define LINEAR_SEARCH 5 + + +/** structure of each individual background block */ +struct BLOCK { + short blkWidth; //!< block width + short blkHeight; //!< block height + SCNHANDLE hBlkBits; //!< block bitmap handle +}; +typedef BLOCK *PBLOCK; + + +/** structure to define position of blocks, which block and which palette */ +struct BLK_INFO { + uint16 wBlkX; //!< x position of this block + uint16 wBlkY; //!< y position of this block + uint16 wBlkZ; //!< z position of this block + uint8 byBlkFlags; //!< block flags used for drawing object associated with this block + uint8 byBlkPal; //!< which palette - index into "blkPals" for this block + int32 blkIndex; //!< which block - index into "blocks" +}; +typedef BLK_INFO *PBLK_INFO; + + +/** background module structure - a module is a container for blocks */ +struct MODULE { + int modWidth; //!< width of module + int modHeight; //!< height of module + int numBlocks; //!< number of blocks in this module + BLOCK *blocks; //!< pointer to array of all blocks used by this module + uint32 *blkPals; //!< pointer to array of all palette handles used by the blocks in this module + BLK_INFO *blkInfo; //!< pointer to array of which block goes where + //!< NOTE: This array must be sorted on x position +}; +typedef MODULE *PMODULE; + + +/** + * background module node structure - links a playfields modules together + * and specifies each module position. It is done this way so that modules + * are position independent and can be reused within a playfield + */ +struct MOD_NODE { + MOD_NODE *pNext; //!< next module node + MODULE *pModule; //!< pointer to actual module definition + char *onDispList; //!< pointer to modules (block on object list) flags - should alloc 1 byte per block + Common::Point ptModPos; //!< module world start position +}; +typedef MOD_NODE *PMOD_NODE; + + +/** background playfield structure - a playfield is a container for modules */ +struct PLAYFIELD { + MOD_NODE *pModNode; //!< head of module node chain for this playfield + OBJECT *pDispList; //!< object display list for this playfield + frac_t fieldX; //!< current world x position of playfield + frac_t fieldY; //!< current world y position of playfield + frac_t fieldXvel; //!< current x velocity of playfield + frac_t fieldYvel; //!< current y velocity of playfield + Common::Rect rcClip; //!< clip rectangle for this playfield + bool bMoved; //!< set when playfield has moved +}; +typedef PLAYFIELD *PPLAYFIELD; + +/** multi-playfield background structure - a backgnd is a container of playfields */ +struct BACKGND { + COLORREF rgbSkyColour; //!< background sky colour + Common::Point ptInitWorld; //!< initial world position + Common::Rect rcScrollLimits; //!< scroll limits + int refreshRate; //!< background update process refresh rate + frac_t *pXscrollTable; //!< pointer to x direction scroll table for this background + frac_t *pYscrollTable; //!< pointer to y direction scroll table for this background + int numPlayfields; //!< number of playfields for this background + PLAYFIELD *fieldArray; //!< pointer to array of all playfields for this background + bool bAutoErase; //!< when set - screen is cleared before anything is plotted (unused) +}; + + +/** screen clipping rect */ +extern Common::Rect rcScreen; + +/** scroll flag - when set scrolling and velocity additions are paused */ +extern bool bNoScroll; + + +/*----------------------------------------------------------------------*\ +|* Background Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void InitBackground( // called to initialise a background + BACKGND *pBgnd); // pointer to data struct for current background + +void StopBgndScrolling(void); // Stops all background playfields from scrolling + +void PlayfieldSetPos( // Sets the xy position of the specified playfield in the current background + int which, // which playfield + int newXpos, // new x position + int newYpos); // new y position + +void PlayfieldGetPos( // Returns the xy position of the specified playfield in the current background + int which, // which playfield + int *pXpos, // returns current x position + int *pYpos); // returns current y position + +OBJECT *GetPlayfieldList( // Returns the display list for the specified playfield + int which); // which playfield + +void KillPlayfieldList( // Kills all the objects on the display list for the specified playfield + int which); // which playfield + +void DrawBackgnd(void); // Draws all playfields for the current background + +void RedrawBackgnd(void); // Completely redraws all the playfield object lists for the current background + +SCNHANDLE BackPal(void); + +} // end of namespace Tinsel + +#endif // TINSEL_BACKGND_H diff --git a/engines/tinsel/bg.cpp b/engines/tinsel/bg.cpp new file mode 100644 index 0000000000..cf7e18dc08 --- /dev/null +++ b/engines/tinsel/bg.cpp @@ -0,0 +1,189 @@ +/* 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$ + * + * Plays the background film of a scene. + */ + +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/dw.h" +#include "tinsel/faders.h" +#include "tinsel/film.h" +#include "tinsel/font.h" +#include "tinsel/handle.h" +#include "tinsel/multiobj.h" +#include "tinsel/object.h" +#include "tinsel/pcode.h" // CONTROL_STARTOFF +#include "tinsel/pid.h" +#include "tinsel/sched.h" +#include "tinsel/timers.h" // For ONE_SECOND constant +#include "tinsel/tinlib.h" // For control() + +#include "common/util.h" + +namespace Tinsel { + +//----------------- LOCAL GLOBAL DATA -------------------- + +static SCNHANDLE BackPalette = 0; // Background's palette +static OBJECT *pBG = 0; // The main picture's object. +static int BGspeed = 0; +static SCNHANDLE BgroundHandle = 0; // Current scene handle - stored in case of Save_Scene() +static bool DoFadeIn = false; +static ANIM thisAnim; // used by BGmainProcess() + +/** + * BackPal + */ +SCNHANDLE BackPal(void) { + return BackPalette; +} + +/** + * SetDoFadeIn +*/ +void SetDoFadeIn(bool tf) { + DoFadeIn = tf; +} + +/** + * Called before scene change. + */ +void DropBackground(void) { + pBG = NULL; // No background + BackPalette = 0; // No background palette +} + +/** + * Return the width of the current background. + */ +int BackgroundWidth(void) { + assert(pBG); + return MultiRightmost(pBG) + 1; +} + +/** + * Return the height of the current background. + */ +int BackgroundHeight(void) { + assert(pBG); + return MultiLowest(pBG) + 1; +} + +/** + * Run main animation that comprises the scene background. + */ +static void BGmainProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + const FREEL *pfr; + const MULTI_INIT *pmi; + + // get the stuff copied to process when it was created + pfr = (const FREEL *)ProcessGetParamsSelf(); + + if (pBG == NULL) { + /*** At start of scene ***/ + + // Get the MULTI_INIT structure + pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfr->mobj)); + + // Initialise and insert the object, and initialise its script. + pBG = MultiInitObject(pmi); + MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG); + InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed); + + if (DoFadeIn) { + FadeInFast(NULL); + DoFadeIn = false; + } + + while (StepAnimScript(&thisAnim) != ScriptFinished) + CORO_SLEEP(1); + + error("Background animation has finished!"); + } else { + // New background during scene + + // Just re-initialise the script. + InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed); + StepAnimScript(&thisAnim); + } + + CORO_END_CODE; +} + +/** + * setBackPal() + */ +void setBackPal(SCNHANDLE hPal) { + BackPalette = hPal; + + fettleFontPal(BackPalette); + CreateTranslucentPalette(BackPalette); +} + +void ChangePalette(SCNHANDLE hPal) { + SwapPalette(FindPalette(BackPalette), hPal); + + setBackPal(hPal); +} + +/** + * Given the scene background film, extracts the palette handle for + * everything else's use, then starts a display process for each reel + * in the film. + * @param bfilm Scene background film + */ +void startupBackground(SCNHANDLE bfilm) { + const FILM *pfilm; + PIMAGE pim; + + BgroundHandle = bfilm; // Save handle in case of Save_Scene() + + pim = GetImageFromFilm(bfilm, 0, NULL, NULL, &pfilm); + setBackPal(FROM_LE_32(pim->hImgPal)); + + // Extract the film speed + BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate); + + if (pBG == NULL) + control(CONTROL_STARTOFF); // New feature - start scene with control off + + // Start display process for each reel in the film + assert(FROM_LE_32(pfilm->numreels) == 1); // Multi-reeled backgrounds withdrawn + CoroutineInstall(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); +} + +/** + * Return the current scene handle. + */ +SCNHANDLE GetBgroundHandle(void) { + return BgroundHandle; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/cliprect.cpp b/engines/tinsel/cliprect.cpp new file mode 100644 index 0000000000..632a84f723 --- /dev/null +++ b/engines/tinsel/cliprect.cpp @@ -0,0 +1,312 @@ +/* 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$ + * + * This file contains the clipping rectangle code. + */ + +#include "tinsel/cliprect.h" // object clip rect defs +#include "tinsel/graphics.h" // normal object drawing +#include "tinsel/object.h" +#include "tinsel/palette.h" + +namespace Tinsel { + +/** list of all clip rectangles */ +static RectList s_rectList; + +/** + * Resets the clipping rectangle allocator. + */ +void ResetClipRect(void) { + s_rectList.clear(); +} + +/** + * Allocate a clipping rectangle from the free list. + * @param pClip clip rectangle dimensions to allocate + */ +void AddClipRect(const Common::Rect &pClip) { + s_rectList.push_back(pClip); +} + +const RectList &GetClipRects() { + return s_rectList; +} + +/** + * Creates the intersection of two rectangles. + * Returns True if there is a intersection. + * @param pDest Pointer to destination rectangle that is to receive the intersection + * @param pSrc1 Pointer to a source rectangle + * @param pSrc2 Pointer to a source rectangle + */ +bool IntersectRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) { + pDest.left = (pSrc1.left > pSrc2.left) ? pSrc1.left : pSrc2.left; + pDest.top = (pSrc1.top > pSrc2.top) ? pSrc1.top : pSrc2.top; + pDest.right = (pSrc1.right < pSrc2.right) ? pSrc1.right : pSrc2.right; + pDest.bottom = (pSrc1.bottom < pSrc2.bottom) ? pSrc1.bottom : pSrc2.bottom; + + return (pDest.right > pDest.left && pDest.bottom > pDest.top); +} + +/** + * Creates the union of two rectangles. + * Returns True if there is a union. + * @param pDest destination rectangle that is to receive the new union + * @param pSrc1 a source rectangle + * @param pSrc2 a source rectangle + */ +bool UnionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) { + pDest.left = (pSrc1.left < pSrc2.left) ? pSrc1.left : pSrc2.left; + pDest.top = (pSrc1.top < pSrc2.top) ? pSrc1.top : pSrc2.top; + pDest.right = (pSrc1.right > pSrc2.right) ? pSrc1.right : pSrc2.right; + pDest.bottom = (pSrc1.bottom > pSrc2.bottom) ? pSrc1.bottom : pSrc2.bottom; + + return (pDest.right > pDest.left && pDest.bottom > pDest.top); +} + +/** + * Check if the two rectangles are next to each other. + * @param pSrc1 a source rectangle + * @param pSrc2 a source rectangle + */ +static bool LooseIntersectRectangle(const Common::Rect &pSrc1, const Common::Rect &pSrc2) { + Common::Rect pDest; + + pDest.left = (pSrc1.left > pSrc2.left) ? pSrc1.left : pSrc2.left; + pDest.top = (pSrc1.top > pSrc2.top) ? pSrc1.top : pSrc2.top; + pDest.right = (pSrc1.right < pSrc2.right) ? pSrc1.right : pSrc2.right; + pDest.bottom = (pSrc1.bottom < pSrc2.bottom) ? pSrc1.bottom : pSrc2.bottom; + + return (pDest.right >= pDest.left && pDest.bottom >= pDest.top); +} + +/** + * Adds velocities and creates clipping rectangles for all the + * objects that have moved on the specified object list. + * @param pObjList Playfield display list to draw + * @param pWin Playfield window top left position + * @param pClip Playfield clipping rectangle + * @param bNoVelocity When reset, objects pos is updated with velocity + * @param bScrolled) When set, playfield has scrolled + */ +void FindMovingObjects(OBJECT *pObjList, Common::Point *pWin, Common::Rect *pClip, bool bNoVelocity, bool bScrolled) { + OBJECT *pObj; // object list traversal pointer + + for (pObj = pObjList->pNext; pObj != NULL; pObj = pObj->pNext) { + if (!bNoVelocity) { + // we want to add velocities to objects position + + if (bScrolled) { + // this playfield has scrolled + + // indicate change + pObj->flags |= DMA_CHANGED; + } + } + + if ((pObj->flags & DMA_CHANGED) || // object changed + HasPalMoved(pObj->pPal)) { // or palette moved + // object has changed in some way + + Common::Rect rcClip; // objects clipped bounding rectangle + Common::Rect rcObj; // objects bounding rectangle + + // calc intersection of objects previous bounding rectangle + // NOTE: previous position is in screen co-ords + if (IntersectRectangle(rcClip, pObj->rcPrev, *pClip)) { + // previous position is within clipping rect + AddClipRect(rcClip); + } + + // calc objects current bounding rectangle + if (pObj->flags & DMA_ABS) { + // object position is absolute + rcObj.left = fracToInt(pObj->xPos); + rcObj.top = fracToInt(pObj->yPos); + } else { + // object position is relative to window + rcObj.left = fracToInt(pObj->xPos) - pWin->x; + rcObj.top = fracToInt(pObj->yPos) - pWin->y; + } + rcObj.right = rcObj.left + pObj->width; + rcObj.bottom = rcObj.top + pObj->height; + + // calc intersection of object with clipping rect + if (IntersectRectangle(rcClip, rcObj, *pClip)) { + // current position is within clipping rect + AddClipRect(rcClip); + + // update previous position + pObj->rcPrev = rcClip; + } else { + // clear previous position + pObj->rcPrev = Common::Rect(); + } + + // clear changed flag + pObj->flags &= ~DMA_CHANGED; + } + } +} + +/** + * Merges any clipping rectangles that overlap to try and reduce + * the total number of clip rectangles. + */ +void MergeClipRect(void) { + if (s_rectList.size() > 1) { + RectList::iterator rOuter, rInner; + + for (rOuter = s_rectList.begin(); rOuter != s_rectList.end(); ++rOuter) { + rInner = rOuter; + while (++rInner != s_rectList.end()) { + + if (LooseIntersectRectangle(*rOuter, *rInner)) { + // these two rectangles overlap or + // are next to each other - merge them + + UnionRectangle(*rOuter, *rOuter, *rInner); + + // remove the inner rect from the list + s_rectList.erase(rInner); + + // move back to beginning of list + rInner = rOuter; + } + } + } + } +} + +/** + * Redraws all objects within this clipping rectangle. + * @param pObjList Object list to draw + * @param pWin Window top left position + * @param pClip Pointer to clip rectangle + */ +void UpdateClipRect(OBJECT *pObjList, Common::Point *pWin, Common::Rect *pClip) { + int x, y, right, bottom; // object corners + int hclip, vclip; // total size of object clipping + DRAWOBJECT currentObj; // filled in to draw the current object in list + OBJECT *pObj; // object list iterator + + // Initialise the fields of the drawing object to empty + memset(¤tObj, 0, sizeof(DRAWOBJECT)); + + for (pObj = pObjList->pNext; pObj != NULL; pObj = pObj->pNext) { + if (pObj->flags & DMA_ABS) { + // object position is absolute + x = fracToInt(pObj->xPos); + y = fracToInt(pObj->yPos); + } else { + // object position is relative to window + x = fracToInt(pObj->xPos) - pWin->x; + y = fracToInt(pObj->yPos) - pWin->y; + } + + // calc object right + right = x + pObj->width; + if (right < 0) + // totally clipped if negative + continue; + + // calc object bottom + bottom = y + pObj->height; + if (bottom < 0) + // totally clipped if negative + continue; + + // bottom clip = low right y - clip low right y + currentObj.botClip = bottom - pClip->bottom; + if (currentObj.botClip < 0) { + // negative - object is not clipped + currentObj.botClip = 0; + } + + // right clip = low right x - clip low right x + currentObj.rightClip = right - pClip->right; + if (currentObj.rightClip < 0) { + // negative - object is not clipped + currentObj.rightClip = 0; + } + + // top clip = clip top left y - top left y + currentObj.topClip = pClip->top - y; + if (currentObj.topClip < 0) { + // negative - object is not clipped + currentObj.topClip = 0; + } else { // clipped - adjust start position to top of clip rect + y = pClip->top; + } + + // left clip = clip top left x - top left x + currentObj.leftClip = pClip->left - x; + if (currentObj.leftClip < 0) { + // negative - object is not clipped + currentObj.leftClip = 0; + } + else + // NOTE: This else statement is disabled in tinsel v1 + { // clipped - adjust start position to left of clip rect + x = pClip->left; + } + + // calc object total horizontal clipping + hclip = currentObj.leftClip + currentObj.rightClip; + + // calc object total vertical clipping + vclip = currentObj.topClip + currentObj.botClip; + + if (hclip + vclip != 0) { + // object is clipped in some way + + if (pObj->width <= hclip) + // object totally clipped horizontally - ignore + continue; + + if (pObj->height <= vclip) + // object totally clipped vertically - ignore + continue; + + // set clip bit in objects flags + currentObj.flags = pObj->flags | DMA_CLIP; + } else { // object is not clipped - copy flags + currentObj.flags = pObj->flags; + } + + // copy objects properties to local object + currentObj.width = pObj->width; + currentObj.height = pObj->height; + currentObj.xPos = (short) x; + currentObj.yPos = (short) y; + currentObj.pPal = pObj->pPal; + currentObj.constant = pObj->constant; + currentObj.hBits = pObj->hBits; + + // draw the object + DrawObject(¤tObj); + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/cliprect.h b/engines/tinsel/cliprect.h new file mode 100644 index 0000000000..96b4b3314e --- /dev/null +++ b/engines/tinsel/cliprect.h @@ -0,0 +1,76 @@ +/* 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$ + * + * Clipping rectangle defines + */ + +#ifndef TINSEL_CLIPRECT_H // prevent multiple includes +#define TINSEL_CLIPRECT_H + +#include "common/list.h" +#include "common/rect.h" + +namespace Tinsel { + +struct OBJECT; + +typedef Common::List RectList; + +/*----------------------------------------------------------------------*\ +|* Clip Rect Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void ResetClipRect(void); // Resets the clipping rectangle allocator + +void AddClipRect( // Allocate a clipping rectangle from the free list + const Common::Rect &pClip); // clip rectangle dimensions to allocate + +const RectList &GetClipRects(); + +bool IntersectRectangle( // Creates the intersection of two rectangles + Common::Rect &pDest, // pointer to destination rectangle that is to receive the intersection + const Common::Rect &pSrc1, // pointer to a source rectangle + const Common::Rect &pSrc2); // pointer to a source rectangle + +bool UnionRectangle( // Creates the union of two rectangles + Common::Rect &pDest, // destination rectangle that is to receive the new union + const Common::Rect &pSrc1, // a source rectangle + const Common::Rect &pSrc2); // a source rectangle + +void FindMovingObjects( // Creates clipping rectangles for all the objects that have moved on the specified object list + OBJECT *pObjList, // playfield display list to draw + Common::Point *pWin, // playfield window top left position + Common::Rect *pClip, // playfield clipping rectangle + bool bVelocity, // when set, objects pos is updated with velocity + bool bScrolled); // when set, playfield has scrolled + +void MergeClipRect(void); // Merges any clipping rectangles that overlap + +void UpdateClipRect( // Redraws all objects within this clipping rectangle + OBJECT *pObjList, // object list to draw + Common::Point *pWin, // window top left position + Common::Rect *pClip); // pointer to clip rectangle + +} // end of namespace Tinsel + +#endif // TINSEL_CLIPRECT_H diff --git a/engines/tinsel/config.cpp b/engines/tinsel/config.cpp new file mode 100644 index 0000000000..4c143f1b8d --- /dev/null +++ b/engines/tinsel/config.cpp @@ -0,0 +1,125 @@ +/* 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$ + * + * This file contains configuration functionality + */ + +//#define USE_3FLAGS 1 + +#include "tinsel/config.h" +#include "tinsel/dw.h" +#include "tinsel/sound.h" +#include "tinsel/music.h" + +#include "common/file.h" +#include "common/config-manager.h" + +#include "sound/mixer.h" + +namespace Tinsel { + +//----------------- GLOBAL GLOBAL DATA -------------------- + +int dclickSpeed = DOUBLE_CLICK_TIME; +int volMidi = MAXMIDIVOL; +int volSound = MAXSAMPVOL; +int volVoice = MAXSAMPVOL; +int speedText = DEFTEXTSPEED; +int bSubtitles = false; +int bSwapButtons = 0; +LANGUAGE language = TXT_ENGLISH; +int bAmerica = 0; + + +// Shouldn't really be here, but time is short... +bool bNoBlocking; + +/** + * WriteConfig() + */ + +void WriteConfig(void) { + ConfMan.setInt("dclick_speed", dclickSpeed); + ConfMan.setInt("music_volume", (volMidi * Audio::Mixer::kMaxChannelVolume) / MAXMIDIVOL); + ConfMan.setInt("sfx_volume", (volSound * Audio::Mixer::kMaxChannelVolume) / MAXSAMPVOL); + ConfMan.setInt("speech_volume", (volVoice * Audio::Mixer::kMaxChannelVolume) / MAXSAMPVOL); + ConfMan.setInt("talkspeed", (speedText * 255) / 100); + ConfMan.setBool("subtitles", bSubtitles); + //ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0); + //ConfigData.language = language; // not necessary, as language has been set in the launcher + //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB +} + +/*---------------------------------------------------------------------*\ +| ReadConfig() | +|-----------------------------------------------------------------------| +| +\*---------------------------------------------------------------------*/ +void ReadConfig(void) { + if (ConfMan.hasKey("dclick_speed")) + dclickSpeed = ConfMan.getInt("dclick_speed"); + + volMidi = (ConfMan.getInt("music_volume") * MAXMIDIVOL) / Audio::Mixer::kMaxChannelVolume; + volSound = (ConfMan.getInt("sfx_volume") * MAXSAMPVOL) / Audio::Mixer::kMaxChannelVolume; + volVoice = (ConfMan.getInt("speech_volume") * MAXSAMPVOL) / Audio::Mixer::kMaxChannelVolume; + + if (ConfMan.hasKey("talkspeed")) + speedText = (ConfMan.getInt("talkspeed") * 100) / 255; + if (ConfMan.hasKey("subtitles")) + bSubtitles = ConfMan.getBool("subtitles"); + + // FIXME: If JAPAN is set, subtitles are forced OFF in the original engine + + //bSwapButtons = ConfMan.getBool("swap_buttons") == 1 ? true : false; + //ConfigData.language = language; // not necessary, as language has been set in the launcher + //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB + +// The flags here control how many country flags are displayed in one of the option dialogs. +#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) + language = ConfigData.language; + #ifdef USE_3FLAGS + if (language == TXT_ENGLISH || language == TXT_ITALIAN) { + language = TXT_GERMAN; + bSubtitles = true; + } + #endif + #ifdef USE_4FLAGS + if (language == TXT_ENGLISH) { + language = TXT_GERMAN; + bSubtitles = true; + } + #endif +#else + language = TXT_ENGLISH; +#endif +} + +bool isJapanMode() { +#ifdef JAPAN + return true; +#else + return false; +#endif +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/config.h b/engines/tinsel/config.h new file mode 100644 index 0000000000..73cc411cb6 --- /dev/null +++ b/engines/tinsel/config.h @@ -0,0 +1,72 @@ +/* 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 TINSEL_CONFIG_H +#define TINSEL_CONFIG_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +// None of these defined -> 1 language, in ENGLISH.TXT +//#define USE_5FLAGS 1 // All 5 flags +//#define USE_4FLAGS 1 // French, German, Italian, Spanish +//#define USE_3FLAGS 1 // French, German, Spanish + +// The Hebrew version appears to the software as being English +// but it needs to have subtitles on... +//#define HEBREW 1 + +//#define JAPAN 1 + + +// double click timer initial value +#define DOUBLE_CLICK_TIME 6 // 6 @ 18Hz = .33 sec + +#define DEFTEXTSPEED 0 + + +extern int dclickSpeed; +extern int volMidi; +extern int volSound; +extern int volVoice; +extern int speedText; +extern int bSubtitles; +extern int bSwapButtons; +extern LANGUAGE language; +extern int bAmerica; + +void WriteConfig(void); +void ReadConfig(void); + +extern bool isJapanMode(); + + +// Shouldn't really be here, but time is short... +extern bool bNoBlocking; + +} // end of namespace Tinsel + +#endif diff --git a/engines/tinsel/coroutine.h b/engines/tinsel/coroutine.h new file mode 100644 index 0000000000..4a8997fe00 --- /dev/null +++ b/engines/tinsel/coroutine.h @@ -0,0 +1,124 @@ +/* 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 TINSEL_COROUTINE_H +#define TINSEL_COROUTINE_H + +#include "common/scummsys.h" + +namespace Tinsel { + +// The following is loosely based on , +// Proper credit to Simon Tatham shall be given. + +/* + + * `ccr' macros for re-entrant coroutines. + + */ + +struct CoroBaseContext { + int _line; + int _sleep; + CoroBaseContext *_subctx; + CoroBaseContext() : _line(0), _sleep(0), _subctx(0) {} + ~CoroBaseContext() { delete _subctx; } +}; + +typedef CoroBaseContext *CoroContext; + + +/** + * Wrapper class which holds a pointer to a pointer to a CoroBaseContext. + * The interesting part is the destructor, which kills the context being held, + * but ONLY if the _sleep val of that context is zero. + */ +struct CoroContextHolder { + CoroContext &_ctx; + CoroContextHolder(CoroContext &ctx) : _ctx(ctx) {} + ~CoroContextHolder() { if (_ctx && _ctx->_sleep == 0) { delete _ctx; _ctx = 0; } } +}; + +#define CORO_PARAM CoroContext &coroParam + + +#define CORO_BEGIN_CONTEXT struct CoroContextTag : CoroBaseContext { int DUMMY +#define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam + +#define CORO_BEGIN_CODE(x) \ + if (!x) {coroParam = x = new CoroContextTag();}\ + assert(coroParam);\ + assert(coroParam->_sleep >= 0);\ + coroParam->_sleep = 0;\ + CoroContextHolder tmpHolder(coroParam);\ + switch(coroParam->_line) { case 0:; + +#define CORO_END_CODE \ + } + +#define CORO_SLEEP(delay) \ + do {\ + coroParam->_line=__LINE__;\ + coroParam->_sleep=delay;\ + return; case __LINE__:;\ + } while (0) + +// Stop the currently running coroutine +#define CORO_KILL_SELF() do { coroParam->_sleep = -1; return; } while(0) + +//#define CORO_ABORT() do { delete (ctx); ctx = 0; } while (0) + +#define CORO_INVOKE_ARGS(subCoro, ARGS) \ + do {\ + coroParam->_line=__LINE__;\ + coroParam->_subctx = 0;\ + do {\ + subCoro ARGS;\ + if (!coroParam->_subctx) break;\ + coroParam->_sleep = coroParam->_subctx->_sleep;\ + return; case __LINE__:;\ + } while(1);\ + } while (0) + +#define CORO_SUBCTX coroParam->_subctx + +#define CORO_INVOKE_0(subCoroutine) \ + CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX)) +#define CORO_INVOKE_1(subCoroutine, a0) \ + CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0)) +#define CORO_INVOKE_2(subCoroutine, a0,a1) \ + CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1)) +#define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \ + CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2)) +#define CORO_INVOKE_4(subCoroutine, a0,a1,a2,a3) \ + CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2,a3)) +#define CORO_INVOKE_5(subCoroutine, a0,a1,a2,a3,a4) \ + CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2,a3,a4)) + + + +} // end of namespace Tinsel + +#endif // TINSEL_COROUTINE_H diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp new file mode 100644 index 0000000000..087730c165 --- /dev/null +++ b/engines/tinsel/cursor.cpp @@ -0,0 +1,647 @@ +/* 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$ + * + * Cursor and cursor trails. + */ + +#include "tinsel/cursor.h" + +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/events.h" // For EventsManager class +#include "tinsel/film.h" +#include "tinsel/graphics.h" +#include "tinsel/handle.h" +#include "tinsel/inventory.h" +#include "tinsel/multiobj.h" // multi-part object defintions etc. +#include "tinsel/object.h" +#include "tinsel/pid.h" +#include "tinsel/sched.h" +#include "tinsel/timers.h" // For ONE_SECOND constant +#include "tinsel/tinlib.h" // resetidletime() +#include "tinsel/tinsel.h" // For engine access + + +namespace Tinsel { + +//----------------- LOCAL DEFINES -------------------- + +#define ITERATION_BASE FRAC_ONE +#define ITER_ACCELLERATION (10L << (FRAC_BITS - 4)) + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static OBJECT *McurObj = 0; // Main cursor object +static OBJECT *AcurObj = 0; // Auxiliary cursor object + +static ANIM McurAnim = {0,0,0,0,0}; // Main cursor animation structure +static ANIM AcurAnim = {0,0,0,0,0}; // Auxiliary cursor animation structure + +static bool bHiddenCursor = false; // Set when cursor is hidden +static bool bTempNoTrailers = false; // Set when cursor trails are hidden + +static bool bFrozenCursor = false; // Set when cursor position is frozen + +static frac_t IterationSize = 0; + +static SCNHANDLE CursorHandle = 0; // Handle to cursor reel data + +static int numTrails = 0; +static int nextTrail = 0; + +static bool bWhoa = false; // Set by DropCursor() at the end of a scene + // - causes cursor processes to do nothing + // Reset when main cursor has re-initialised + +static bool restart = false; // When main cursor has been bWhoa-ed, it waits + // for this to be set to true. + +static short ACoX = 0, ACoY = 0; // Auxillary cursor image's animation offsets + + + +#define MAX_TRAILERS 10 + +static struct { + + ANIM trailAnim; // Animation structure + OBJECT *trailObj; // This trailer's object + +} ntrailData [MAX_TRAILERS]; + +static int lastCursorX = 0, lastCursorY = 0; + + +//----------------- FORWARD REFERENCES -------------------- + +static void MoveCursor(void); + +/** + * Initialise and insert a cursor trail object, set its Z-pos, and hide + * it. Also initialise its animation script. + */ +static void InitCurTrailObj(int i, int x, int y) { + const FREEL *pfr; // pointer to reel + PIMAGE pim; // pointer to image + const MULTI_INIT *pmi; // MULTI_INIT structure + + const FILM *pfilm; + + if (!numTrails) + return; + + // Get rid of old object + if (ntrailData[i].trailObj != NULL) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj); + + pim = GetImageFromFilm(CursorHandle, i+1, &pfr, &pmi, &pfilm);// Get pointer to image + assert(BackPal()); // No background palette + pim->hImgPal = TO_LE_32(BackPal()); + + // Initialise and insert the object, set its Z-pos, and hide it + ntrailData[i].trailObj = MultiInitObject(pmi); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj); + MultiSetZPosition(ntrailData[i].trailObj, Z_CURSORTRAIL); + MultiSetAniXY(ntrailData[i].trailObj, x, y); + + // Initialise the animation script + InitStepAnimScript(&ntrailData[i].trailAnim, ntrailData[i].trailObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate)); + StepAnimScript(&ntrailData[i].trailAnim); +} + +/** + * Get the cursor position from the mouse driver. + */ +static bool GetDriverPosition(int *x, int *y) { + Common::Point ptMouse = _vm->getMousePosition(); + *x = ptMouse.x; + *y = ptMouse.y; + + return(*x >= 0 && *x <= SCREEN_WIDTH-1 && + *y >= 0 && *y <= SCREEN_HEIGHT-1); +} + +/** + * Move the cursor relative to current position. + */ +void AdjustCursorXY(int deltaX, int deltaY) { + int x, y; + + if (deltaX || deltaY) { + if (GetDriverPosition(&x, &y)) + _vm->setMousePosition(Common::Point(x + deltaX, y + deltaY)); + } + MoveCursor(); +} + +/** + * Move the cursor to an absolute position. + */ +void SetCursorXY(int newx, int newy) { + int x, y; + int Loffset, Toffset; // Screen offset + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + newx -= Loffset; + newy -= Toffset; + + if (GetDriverPosition(&x, &y)) + _vm->setMousePosition(Common::Point(newx, newy)); + MoveCursor(); +} + +/** + * Move the cursor to a screen position. + */ +void SetCursorScreenXY(int newx, int newy) { + int x, y; + + if (GetDriverPosition(&x, &y)) + _vm->setMousePosition(Common::Point(newx, newy)); + MoveCursor(); +} + +/** + * Called by the world and his brother. + * Returns the cursor's animation position in (x,y). + * Returns false if there is no cursor object. + */ +bool GetCursorXYNoWait(int *x, int *y, bool absolute) { + if (McurObj == NULL) { + *x = *y = 0; + return false; + } + + GetAniPosition(McurObj, x, y); + + if (absolute) { + int Loffset, Toffset; // Screen offset + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + *x += Loffset; + *y += Toffset; + } + + return true; +} + +/** + * Called by the world and his brother. + * Returns the cursor's animation position. + * If called while there is no cursor object, the calling process ends + * up waiting until there is. + */ +void GetCursorXY(int *x, int *y, bool absolute) { + //while (McurObj == NULL) + // ProcessSleepSelf(); + assert(McurObj); + GetCursorXYNoWait(x, y, absolute); +} + +/** + * Re-initialise the main cursor to use the main cursor reel. + * Called from TINLIB.C to restore cursor after hiding it. + * Called from INVENTRY.C to restore cursor after customising it. + */ +void RestoreMainCursor(void) { + const FILM *pfilm; + + if (McurObj != NULL) { + pfilm = (const FILM *)LockMem(CursorHandle); + + InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfilm->reels->script), ONE_SECOND / FROM_LE_32(pfilm->frate)); + StepAnimScript(&McurAnim); + } + bHiddenCursor = false; + bFrozenCursor = false; +} + +/** + * Called from INVENTRY.C to customise the main cursor. + */ +void SetTempCursor(SCNHANDLE pScript) { + if (McurObj != NULL) + InitStepAnimScript(&McurAnim, McurObj, pScript, 2); +} + +/** + * Hide the cursor. + */ +void DwHideCursor(void) { + int i; + + bHiddenCursor = true; + + if (McurObj) + MultiHideObject(McurObj); + if (AcurObj) + MultiHideObject(AcurObj); + + for (i = 0; i < numTrails; i++) { + if (ntrailData[i].trailObj != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj); + ntrailData[i].trailObj = NULL; + } + } +} + +/** + * Unhide the cursor. + */ +void UnHideCursor(void) { + bHiddenCursor = false; +} + +/** + * Freeze the cursor. + */ +void FreezeCursor(void) { + bFrozenCursor = true; +} + +/** + * HideCursorTrails + */ +void HideCursorTrails(void) { + int i; + + bTempNoTrailers = true; + + for (i = 0; i < numTrails; i++) { + if (ntrailData[i].trailObj != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj); + ntrailData[i].trailObj = NULL; + } + } +} + +/** + * UnHideCursorTrails + */ +void UnHideCursorTrails(void) { + bTempNoTrailers = false; +} + +/** + * Get pointer to image from a film reel. And the rest. + */ +IMAGE *GetImageFromReel(const FREEL *pfr, const MULTI_INIT **ppmi) { + const MULTI_INIT *pmi; + const FRAME *pFrame; + + pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfr->mobj)); + if (ppmi) + *ppmi = pmi; + + pFrame = (const FRAME *)LockMem(FROM_LE_32(pmi->hMulFrame)); + + // get pointer to image + return (IMAGE *)LockMem(READ_LE_UINT32(pFrame)); +} + +/** + * Get pointer to image from a film. And the rest. + */ +IMAGE *GetImageFromFilm(SCNHANDLE hFilm, int reel, const FREEL **ppfr, const MULTI_INIT **ppmi, const FILM **ppfilm) { + const FILM *pfilm; + const FREEL *pfr; + + pfilm = (const FILM *)LockMem(hFilm); + if (ppfilm) + *ppfilm = pfilm; + + pfr = &pfilm->reels[reel]; + if (ppfr) + *ppfr = pfr; + + return GetImageFromReel(pfr, ppmi); +} + +/** + * Delete auxillary cursor. Restore animation offsets in the image. + */ +void DelAuxCursor(void) { + if (AcurObj != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), AcurObj); + AcurObj = NULL; + } +} + +/** + * Set auxillary cursor. + * Save animation offsets from the image if required. + */ +void SetAuxCursor(SCNHANDLE hFilm) { + PIMAGE pim; // Pointer to auxillary cursor's image + const FREEL *pfr; + const MULTI_INIT *pmi; + const FILM *pfilm; + int x, y; // Cursor position + + DelAuxCursor(); // Get rid of previous + + GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear + + pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image + assert(BackPal()); // no background palette + pim->hImgPal = TO_LE_32(BackPal()); // Poke in the background palette + + ACoX = (short)(FROM_LE_16(pim->imgWidth)/2 - FROM_LE_16(pim->anioffX)); + ACoY = (short)(FROM_LE_16(pim->imgHeight)/2 - FROM_LE_16(pim->anioffY)); + + // Initialise and insert the auxillary cursor object + AcurObj = MultiInitObject(pmi); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), AcurObj); + + // Initialise the animation and set its position + InitStepAnimScript(&AcurAnim, AcurObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate)); + MultiSetAniXY(AcurObj, x - ACoX, y - ACoY); + MultiSetZPosition(AcurObj, Z_ACURSOR); + + if (bHiddenCursor) + MultiHideObject(AcurObj); +} + +/** + * MoveCursor + */ +static void MoveCursor(void) { + int startX, startY; + Common::Point ptMouse; + frac_t newX, newY; + unsigned dir; + + // get cursors start animation position + GetCursorXYNoWait(&startX, &startY, false); + + // get mouse drivers current position + ptMouse = _vm->getMousePosition(); + + // convert to fixed point + newX = intToFrac(ptMouse.x); + newY = intToFrac(ptMouse.y); + + // modify mouse driver position depending on cursor keys + if ((dir = _vm->getKeyDirection()) != 0) { + if (dir & MSK_LEFT) + newX -= IterationSize; + + if (dir & MSK_RIGHT) + newX += IterationSize; + + if (dir & MSK_UP) + newY -= IterationSize; + + if (dir & MSK_DOWN) + newY += IterationSize; + + IterationSize += ITER_ACCELLERATION; + + // set new mouse driver position + _vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY))); + } else + + IterationSize = ITERATION_BASE; + + // get new mouse driver position - could have been modified + ptMouse = _vm->getMousePosition(); + + if (lastCursorX != ptMouse.x || lastCursorY != ptMouse.y) { + resetUserEventTime(); + + if (!bTempNoTrailers && !bHiddenCursor) { + InitCurTrailObj(nextTrail++, lastCursorX, lastCursorY); + if (nextTrail == numTrails) + nextTrail = 0; + } + } + + // adjust cursor to new mouse position + if (McurObj) + MultiSetAniXY(McurObj, ptMouse.x, ptMouse.y); + if (AcurObj != NULL) + MultiSetAniXY(AcurObj, ptMouse.x - ACoX, ptMouse.y - ACoY); + + if (InventoryActive() && McurObj) { + // Notify the inventory + Xmovement(ptMouse.x - startX); + Ymovement(ptMouse.y - startY); + } + + lastCursorX = ptMouse.x; + lastCursorY = ptMouse.y; +} + +/** + * Initialise cursor object. + */ +static void InitCurObj(void) { + const FILM *pfilm; + const FREEL *pfr; + const MULTI_INIT *pmi; + PIMAGE pim; + + pim = GetImageFromFilm(CursorHandle, 0, &pfr, &pmi, &pfilm);// Get pointer to image + assert(BackPal()); // no background palette + pim->hImgPal = TO_LE_32(BackPal()); +//--- + + AcurObj = NULL; // No auxillary cursor + + McurObj = MultiInitObject(pmi); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), McurObj); + + InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate)); +} + +/** + * Initialise the cursor position. + */ +static void InitCurPos(void) { + Common::Point ptMouse = _vm->getMousePosition(); + lastCursorX = ptMouse.x; + lastCursorY = ptMouse.y; + + MultiSetZPosition(McurObj, Z_CURSOR); + MoveCursor(); + MultiHideObject(McurObj); + + IterationSize = ITERATION_BASE; +} + +/** + * CursorStoppedCheck + */ +static void CursorStoppedCheck(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + // If scene is closing down + if (bWhoa) { + // ...wait for next scene start-up + while (!restart) + CORO_SLEEP(1); + + // Re-initialise + InitCurObj(); + InitCurPos(); + InventoryIconCursor(); // May be holding something + + // Re-start the cursor trails + restart = false; // set all bits + bWhoa = false; + } + CORO_END_CODE; +} + +/** + * The main cursor process. + */ +void CursorProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + while (!CursorHandle || !BackPal()) + CORO_SLEEP(1); + + InitCurObj(); + InitCurPos(); + InventoryIconCursor(); // May be holding something + + bWhoa = false; + restart = false; + + while (1) { + // allow rescheduling + CORO_SLEEP(1); + + // Stop/start between scenes + CORO_INVOKE_0(CursorStoppedCheck); + + // Step the animation script(s) + StepAnimScript(&McurAnim); + if (AcurObj != NULL) + StepAnimScript(&AcurAnim); + for (int i = 0; i < numTrails; i++) { + if (ntrailData[i].trailObj != NULL) { + if (StepAnimScript(&ntrailData[i].trailAnim) == ScriptFinished) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj); + ntrailData[i].trailObj = NULL; + } + } + } + + // Move the cursor as appropriate + if (!bFrozenCursor) + MoveCursor(); + + // If the cursor should be hidden... + if (bHiddenCursor) { + // ...hide the cursor object(s) + MultiHideObject(McurObj); + if (AcurObj) + MultiHideObject(AcurObj); + + for (int i = 0; i < numTrails; i++) { + if (ntrailData[i].trailObj != NULL) + MultiHideObject(ntrailData[i].trailObj); + } + + // Wait 'til cursor is again required. + while (bHiddenCursor) { + CORO_SLEEP(1); + + // Stop/start between scenes + CORO_INVOKE_0(CursorStoppedCheck); + } + } + } + CORO_END_CODE; +} + +/** + * Called from dec_cursor() Glitter function. + * Register the handle to cursor reel data. + */ +void DwInitCursor(SCNHANDLE bfilm) { + const FILM *pfilm; + + CursorHandle = bfilm; + + pfilm = (const FILM *)LockMem(CursorHandle); + numTrails = FROM_LE_32(pfilm->numreels) - 1; + + assert(numTrails <= MAX_TRAILERS); +} + +/** + * DropCursor is called when a scene is closing down. + */ +void DropCursor(void) { + AcurObj = NULL; // No auxillary cursor + McurObj = NULL; // No cursor object (imminently deleted elsewhere) + bHiddenCursor = false; // Not hidden in next scene + bTempNoTrailers = false; // Trailers not hidden in next scene + bWhoa = true; // Suspend cursor processes + + for (int i = 0; i < numTrails; i++) { + if (ntrailData[i].trailObj != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj); + ntrailData[i].trailObj = NULL; + } + } +} + +/** + * RestartCursor is called when a new scene is starting up. + */ +void RestartCursor(void) { + restart = true; // Get the main cursor to re-initialise +} + +/** + * Called when restarting the game, ensures correct re-start with NULL + * pointers etc. + */ +void RebootCursor(void) { + McurObj = AcurObj = NULL; + for (int i = 0; i < MAX_TRAILERS; i++) + ntrailData[i].trailObj = NULL; + + bHiddenCursor = bTempNoTrailers = bFrozenCursor = false; + + CursorHandle = 0; + + bWhoa = false; + restart = false; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/cursor.h b/engines/tinsel/cursor.h new file mode 100644 index 0000000000..15349dda26 --- /dev/null +++ b/engines/tinsel/cursor.h @@ -0,0 +1,56 @@ +/* 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$ + * + * Clipping rectangle defines + */ + +#ifndef TINSEL_CURSOR_H // prevent multiple includes +#define TINSEL_CURSOR_H + +#include "tinsel/dw.h" // for SCNHANDLE + +namespace Tinsel { + +void AdjustCursorXY(int deltaX, int deltaY); +void SetCursorXY(int x, int y); +void SetCursorScreenXY(int newx, int newy); +void GetCursorXY(int *x, int *y, bool absolute); +bool GetCursorXYNoWait(int *x, int *y, bool absolute); + +void RestoreMainCursor(void); +void SetTempCursor(SCNHANDLE pScript); +void DwHideCursor(void); +void UnHideCursor(void); +void FreezeCursor(void); +void HideCursorTrails(void); +void UnHideCursorTrails(void); +void DelAuxCursor(void); +void SetAuxCursor(SCNHANDLE hFilm); +void DwInitCursor(SCNHANDLE bfilm); +void DropCursor(void); +void RestartCursor(void); +void RebootCursor(void); + +} // end of namespace Tinsel + +#endif // TINSEL_CURSOR_H diff --git a/engines/tinsel/debugger.cpp b/engines/tinsel/debugger.cpp new file mode 100644 index 0000000000..dc37e6a9a1 --- /dev/null +++ b/engines/tinsel/debugger.cpp @@ -0,0 +1,162 @@ +/* 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 "tinsel/tinsel.h" +#include "tinsel/debugger.h" +#include "tinsel/inventory.h" +#include "tinsel/pcode.h" +#include "tinsel/scene.h" +#include "tinsel/sound.h" +#include "tinsel/music.h" +#include "tinsel/font.h" +#include "tinsel/strres.h" + +namespace Tinsel { + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// In PDISPLAY.CPP +extern void TogglePathDisplay(void); +// In tinsel.cpp +extern void SetNewScene(SCNHANDLE scene, int entrance, int transition); +// In scene.cpp +extern SCNHANDLE GetSceneHandle(void); + +//----------------- SUPPORT FUNCTIONS --------------------- + +//static +int strToInt(const char *s) { + if (!*s) + // No string at all + return 0; + else if (toupper(s[strlen(s) - 1]) != 'H') + // Standard decimal string + return atoi(s); + + // Hexadecimal string + uint tmp; + sscanf(s, "%xh", &tmp); + return (int)tmp; +} + +//----------------- CONSOLE CLASS --------------------- + +Console::Console() : GUI::Debugger() { + DCmd_Register("item", WRAP_METHOD(Console, cmd_item)); + DCmd_Register("scene", WRAP_METHOD(Console, cmd_scene)); + DCmd_Register("music", WRAP_METHOD(Console, cmd_music)); + DCmd_Register("sound", WRAP_METHOD(Console, cmd_sound)); + DCmd_Register("string", WRAP_METHOD(Console, cmd_string)); +} + +Console::~Console() { +} + +bool Console::cmd_item(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("%s item_number\n", argv[0]); + DebugPrintf("Sets the currently active 'held' item\n"); + return true; + } + + HoldItem(INV_NOICON); + HoldItem(strToInt(argv[1])); + return false; +} + +bool Console::cmd_scene(int argc, const char **argv) { + if (argc < 1 || argc > 3) { + DebugPrintf("%s [scene_number [entry number]]\n", argv[0]); + DebugPrintf("If no parameters are given, prints the current scene.\n"); + DebugPrintf("Otherwise changes to the specified scene number. Entry number defaults to 1 if none provided\n"); + return true; + } + + if (argc == 1) { + DebugPrintf("Current scene is %d\n", GetSceneHandle() >> SCNHANDLE_SHIFT); + return true; + } + + uint32 sceneNumber = (uint32)strToInt(argv[1]) << SCNHANDLE_SHIFT; + int entryNumber = (argc >= 3) ? strToInt(argv[2]) : 1; + + SetNewScene(sceneNumber, entryNumber, TRANS_CUT); + return false; +} + +bool Console::cmd_music(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("%s track_number or %s -offset\n", argv[0], argv[0]); + DebugPrintf("Plays the MIDI track number provided, or the offset inside midi.dat\n"); + DebugPrintf("A positive number signifies a track number, whereas a negative signifies an offset\n"); + return true; + } + + int param = strToInt(argv[1]); + if (param == 0) { + DebugPrintf("Track number/offset can't be 0!\n", argv[0]); + } else if (param > 0) { + // Track provided + PlayMidiSequence(GetTrackOffset(param - 1), false); + } else if (param < 0) { + // Offset provided + param = param * -1; + PlayMidiSequence(param, false); + } + return true; +} + +bool Console::cmd_sound(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("%s id\n", argv[0]); + DebugPrintf("Plays the sound with the given ID\n"); + return true; + } + + int id = strToInt(argv[1]); + if (_vm->_sound->sampleExists(id)) + _vm->_sound->playSample(id, Audio::Mixer::kSpeechSoundType); + else + DebugPrintf("Sample %d does not exist!\n", id); + + return true; +} + +bool Console::cmd_string(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("%s id\n", argv[0]); + DebugPrintf("Prints the string with the given ID\n"); + return true; + } + + char tmp[TBUFSZ]; + int id = strToInt(argv[1]); + LoadStringRes(id, tmp, TBUFSZ); + DebugPrintf("%s\n", tmp); + + return true; +} + +} // End of namespace Tinsel diff --git a/engines/tinsel/debugger.h b/engines/tinsel/debugger.h new file mode 100644 index 0000000000..219bc71224 --- /dev/null +++ b/engines/tinsel/debugger.h @@ -0,0 +1,49 @@ +/* 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 TINSEL_DEBUGGER_H +#define TINSEL_DEBUGGER_H + +#include "gui/debugger.h" + +namespace Tinsel { + +class TinselEngine; + +class Console: public GUI::Debugger { +protected: + bool cmd_item(int argc, const char **argv); + bool cmd_scene(int argc, const char **argv); + bool cmd_music(int argc, const char **argv); + bool cmd_sound(int argc, const char **argv); + bool cmd_string(int argc, const char **argv); +public: + Console(); + virtual ~Console(void); +}; + +} // End of namespace Tinsel + +#endif diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp new file mode 100644 index 0000000000..a638dde2c5 --- /dev/null +++ b/engines/tinsel/detection.cpp @@ -0,0 +1,278 @@ +/* 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 "base/plugins.h" + +#include "common/advancedDetector.h" +#include "common/file.h" + +#include "tinsel/tinsel.h" + + +namespace Tinsel { + +struct TinselGameDescription { + Common::ADGameDescription desc; + + int gameID; + int gameType; + uint32 features; + uint16 version; +}; + +uint32 TinselEngine::getGameID() const { + return _gameDescription->gameID; +} + +uint32 TinselEngine::getFeatures() const { + return _gameDescription->features; +} + +Common::Language TinselEngine::getLanguage() const { + return _gameDescription->desc.language; +} + +Common::Platform TinselEngine::getPlatform() const { + return _gameDescription->desc.platform; +} + +uint16 TinselEngine::getVersion() const { + return _gameDescription->version; +} + +} + +static const PlainGameDescriptor tinselGames[] = { + {"tinsel", "Tinsel engine game"}, + {"dw", "Discworld"}, + {"dw2", "Discworld 2: Mortality Bytes!"}, + {0, 0} +}; + + +namespace Tinsel { + +static const TinselGameDescription gameDescriptions[] = { + + // Note: versions with *.gra files use tinsel v1 (28/2/1995), whereas + // versions with *.scn files tinsel v2 (7/5/1995) + // Update: this is not entirely true, there were some versions released + // with *.gra files and used tinsel v2 + + { + { // This version has *.gra files but uses tinsel v2 + "dw", + "Floppy", + AD_ENTRY1s("dw.gra", "c8808ccd988d603dd35dff42013ae7fd", 781656), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_DW1, + 0, + GF_FLOPPY, + TINSEL_V2, + }, + + { // English CD v1. This version has *.gra files but uses tinsel v2 + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_DW1, + 0, + GF_CD, + TINSEL_V2, + }, + + { // English CD v2 + { + "dw", + "CD", + { + {"dw.scn", 0, "70955425870c7720d6eebed903b2ef41", 776188}, + {"english.smp", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_DW1, + 0, + GF_CD | GF_SCNFILES, + TINSEL_V2, + }, + +#if 0 + { // English Saturn CD + { + "dw", + "CD", + { + {"dw.scn", 0, "6803f293c88758057cc685b9437f7637", 382248}, + {"english.smp", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_DW1, + 0, + GF_CD, + TINSEL_V2, + }, +#endif + + { // Demo from http://www.adventure-treff.de/specials/dl_demos.php + { + "dw", + "Demo", + AD_ENTRY1s("dw.gra", "ce1b57761ba705221bcf70955b827b97", 441192), + //AD_ENTRY1s("dw.scn", "ccd72f02183d0e96b6e7d8df9492cda8", 23308), + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_DEMO + }, + GID_DW1, + 0, + GF_DEMO, + TINSEL_V1, + }, + + { // German CD re-release "Neon Edition" + // Note: This release has ENGLISH.TXT (with german content) instead of GERMAN.TXT + { + "dw", + "CD", + AD_ENTRY1s("dw.scn", "6182c7986eaec893c62fb6ea13a9f225", 774556), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GID_DW1, + 0, + GF_CD | GF_SCNFILES, + TINSEL_V2, + }, + + { AD_TABLE_END_MARKER, 0, 0, 0, 0 } +}; + +/** + * The fallback game descriptor used by the Tinsel engine's fallbackDetector. + * Contents of this struct are to be overwritten by the fallbackDetector. + */ +static TinselGameDescription g_fallbackDesc = { + { + "", + "", + AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor + Common::UNK_LANG, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + 0, + 0, + 0, + 0, +}; + +} // End of namespace Tinsel + +static const Common::ADParams detectionParams = { + // Pointer to ADGameDescription or its superset structure + (const byte *)Tinsel::gameDescriptions, + // Size of that superset structure + sizeof(Tinsel::TinselGameDescription), + // Number of bytes to compute MD5 sum for + 5000, + // List of all engine targets + tinselGames, + // Structure for autoupgrading obsolete targets + 0, + // Name of single gameid (optional) + "tinsel", + // List of files for file-based fallback detection (optional) + 0, + // Flags + 0 +}; + +class TinselMetaEngine : public Common::AdvancedMetaEngine { +public: + TinselMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {} + + virtual const char *getName() const { + return "Tinsel Engine"; + } + + virtual const char *getCopyright() const { + return "Tinsel Engine"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + + const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; + +}; + +bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { + const Tinsel::TinselGameDescription *gd = (const Tinsel::TinselGameDescription *)desc; + if (gd) { + *engine = new Tinsel::TinselEngine(syst, gd); + } + return gd != 0; +} + +const Common::ADGameDescription *TinselMetaEngine::fallbackDetect(const FSList *fslist) const { + // Set the default values for the fallback descriptor's ADGameDescription part. + Tinsel::g_fallbackDesc.desc.language = Common::UNK_LANG; + Tinsel::g_fallbackDesc.desc.platform = Common::kPlatformPC; + Tinsel::g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; + + // Set default values for the fallback descriptor's TinselGameDescription part. + Tinsel::g_fallbackDesc.gameID = 0; + Tinsel::g_fallbackDesc.features = 0; + Tinsel::g_fallbackDesc.version = 0; + + //return (const Common::ADGameDescription *)&Tinsel::g_fallbackDesc; + return NULL; +} + +#if PLUGIN_ENABLED_DYNAMIC(TINSEL) + REGISTER_PLUGIN_DYNAMIC(TINSEL, PLUGIN_TYPE_ENGINE, TinselMetaEngine); +#else + REGISTER_PLUGIN_STATIC(TINSEL, PLUGIN_TYPE_ENGINE, TinselMetaEngine); +#endif diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h new file mode 100644 index 0000000000..d14dd43fa2 --- /dev/null +++ b/engines/tinsel/dw.h @@ -0,0 +1,119 @@ +/* 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 TINSEL_DW_H +#define TINSEL_DW_H + +#include "common/scummsys.h" +#include "common/endian.h" + +namespace Tinsel { + +/** scene handle data type */ +typedef uint32 SCNHANDLE; + +/** polygon handle */ +typedef int HPOLYGON; + + +#define EOS_CHAR '\0' // string terminator +#define LF_CHAR '\x0a' // line feed + +// file names +#define SAMPLE_FILE "english.smp" // all samples +#define SAMPLE_INDEX "english.idx" // sample index filename +#define MIDI_FILE "midi.dat" // all MIDI sequences +#define INDEX_FILENAME "index" // name of index file + +#define SCNHANDLE_SHIFT 23 // amount to shift scene handles by +#define NO_SCNHANDLES 300 // number of memory handles for scenes +#define MASTER_SCNHANDLE (0 << SCNHANDLE_SHIFT) // master scene memory handle + +// the minimum value a integer number can have +#define MIN_INT (1 << (8*sizeof(int) - 1)) +#define MIN_INT16 (-32767) + +// the maximum value a integer number can have +#define MAX_INT (~MIN_INT) + +// TODO: v1->v2 scene files +#ifdef FILE_SPLIT +// each scene is split into 2 files +#define INV_OBJ_SCNHANDLE (2 << SCNHANDLE_SHIFT) // inventory object handle (if there are inventory objects) +#else +#define INV_OBJ_SCNHANDLE (1 << SCNHANDLE_SHIFT) // inventory object handle (if there are inventory objects) +#endif + + +#define FIELD_WORLD 0 +#define FIELD_STATUS 1 + + + + +// We don't set the Z position for print and talk text +// i.e. it gets a Z position of 0 + +#define Z_INV_BRECT 10 // Inventory background rectangle +#define Z_INV_MFRAME 15 // Inventory window frame +#define Z_INV_HTEXT 15 // Inventory heading text +#define Z_INV_ICONS 16 // Icons in inventory +#define Z_INV_ITEXT 995 // Icon text + +#define Z_INV_RFRAME 22 // Re-sizing frame + +#define Z_CURSOR 1000 // Cursor +#define Z_CURSORTRAIL 999 // Cursor trails +#define Z_ACURSOR 990 // Auxillary cursor + +#define Z_TAG_TEXT 995 // In front of auxillary cursor + +#define Z_MDGROOVE 20 +#define Z_MDSLIDER 21 + +#define Z_TOPPLAY 100 + +#define Z_TOPW_TEXT Z_TAG_TEXT + +// Started a collection of assorted maximum numbers here: +#define MAX_MOVERS 6 // Moving actors using path system +#define MAX_SAVED_ACTORS 32 // Saved 'Normal' actors +#define MAX_SAVED_ALIVES 512 // Saves actors'lives + +// Legal non-existant entrance number for LoadScene() +#define NO_ENTRY_NUM (-3458) // Magic unlikely number + + +#define SAMPLETIMEOUT (15*ONE_SECOND) + +// Language for the resource strings +enum LANGUAGE { + TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, + TXT_ITALIAN, TXT_SPANISH +}; + +} // end of namespace Tinsel + +#endif // TINSEL_DW_H diff --git a/engines/tinsel/effect.cpp b/engines/tinsel/effect.cpp new file mode 100644 index 0000000000..825825ccec --- /dev/null +++ b/engines/tinsel/effect.cpp @@ -0,0 +1,134 @@ +/* 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$ + * + */ + +// Handles effect polygons. +// +// EffectPolyProcess() monitors triggering of effect code (i.e. a moving +// actor entering an effect polygon). +// EffectProcess() runs the appropriate effect code. +// +// NOTE: Currently will only run one effect process at a time, i.e. +// effect polygons will not currently nest. It won't be very difficult +// to fix this if required. + +#include "tinsel/actors.h" +#include "tinsel/dw.h" +#include "tinsel/events.h" +#include "tinsel/pid.h" +#include "tinsel/pcode.h" // LEAD_ACTOR +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/sched.h" + + +namespace Tinsel { + +struct EP_INIT { + HPOLYGON hEpoly; + PMACTOR pActor; + int index; +}; + +/** + * Runs an effect polygon's Glitter code with ENTER event, waits for the + * actor to leave that polygon. Then runs the polygon's Glitter code + * with LEAVE event. + */ +static void EffectProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + EP_INIT *to = (EP_INIT *)ProcessGetParamsSelf(); // get the stuff copied to process when it was created + + CORO_BEGIN_CODE(_ctx); + + int x, y; // Lead actor position + + // Run effect poly enter script + effRunPolyTinselCode(to->hEpoly, ENTER, to->pActor->actorID); + + do { + CORO_SLEEP(1); + GetMActorPosition(to->pActor, &x, &y); + } while (InPolygon(x, y, EFFECT) == to->hEpoly); + + // Run effect poly leave script + effRunPolyTinselCode(to->hEpoly, LEAVE, to->pActor->actorID); + + SetMAinEffectPoly(to->index, false); + + CORO_END_CODE; +} + +/** + * If the actor was not already in an effect polygon, checks to see if + * it has just entered one. If it has, a process is started up to run + * the polygon's Glitter code. + */ +static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) { + HPOLYGON hPoly; + EP_INIT epi; + + // If just entered an effect polygon, the effect should be triggered. + if (!IsMAinEffectPoly(index)) { + hPoly = InPolygon(x, y, EFFECT); + if (hPoly != NOPOLY) { + //Just entered effect polygon + SetMAinEffectPoly(index, true); + + epi.hEpoly = hPoly; + epi.pActor = pActor; + epi.index = index; + CoroutineInstall(PID_TCODE, EffectProcess, &epi, sizeof(epi)); + } + } +} + +/** + * Just calls FettleEffectPolys() every clock tick. + */ +void EffectPolyProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + while (1) { + for (int i = 0; i < MAX_MOVERS; i++) { + PMACTOR pActor = GetLiveMover(i); + if (pActor != NULL) { + int x, y; + GetMActorPosition(pActor, &x, &y); + FettleEffectPolys(x, y, i, pActor); + } + } + + CORO_SLEEP(1); // allow re-scheduling + } + CORO_END_CODE; +} + +} // End of namespace Tinsel diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp new file mode 100644 index 0000000000..8064bdd3f3 --- /dev/null +++ b/engines/tinsel/events.cpp @@ -0,0 +1,439 @@ +/* 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$ + * + * Main purpose is to process user events. + * Also provides a couple of utility functions. + */ + +#include "tinsel/actors.h" +#include "tinsel/config.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/events.h" +#include "tinsel/handle.h" // For LockMem() +#include "tinsel/inventory.h" +#include "tinsel/move.h" // For walking lead actor +#include "tinsel/pcode.h" // For Interpret() +#include "tinsel/pid.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" // For walking lead actor +#include "tinsel/sched.h" +#include "tinsel/scroll.h" // For DontScrollCursor() +#include "tinsel/timers.h" // DwGetCurrentTime() +#include "tinsel/tinlib.h" // For control() +#include "tinsel/token.h" + +namespace Tinsel { + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in PDISPLAY.C +extern int GetTaggedActor(void); +extern HPOLYGON GetTaggedPoly(void); + + +//----------------- EXTERNAL GLOBAL DATA --------------------- + +extern bool bEnableF1; + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static int userEvents = 0; // Whenever a button or a key comes in +static uint32 lastUserEvent = 0; // Time it hapenned +static int butEvents = 0; // Single or double, left or right. Or escape key. +static int escEvents = 0; // Escape key + + +static int eCount = 0; + +/** + * Gets called before each schedule, only 1 user action per schedule + * is allowed. + */ +void ResetEcount(void) { + eCount = 0; +} + + +void IncUserEvents(void) { + userEvents++; + lastUserEvent = DwGetCurrentTime(); +} + +/** + * If this is a single click, wait to check it's not the first half of a + * double click. + * If this is a double click, the process from the waiting single click + * gets killed. + */ +void AllowDclick(CORO_PARAM, BUTEVENT be) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + if (be == BE_SLEFT) { + GetToken(TOKEN_LEFT_BUT); + CORO_SLEEP(dclickSpeed+1); + FreeToken(TOKEN_LEFT_BUT); + + // Prevent activation of 2 events on the same tick + if (++eCount != 1) + CORO_KILL_SELF(); + + break; + + } else if (be == BE_DLEFT) { + GetToken(TOKEN_LEFT_BUT); + FreeToken(TOKEN_LEFT_BUT); + } + CORO_END_CODE; +} + +/** + * Take control from player, if the player has it. + * Return TRUE if control taken, FALSE if not. + */ + +bool GetControl(int param) { + if (TestToken(TOKEN_CONTROL)) { + control(param); + return true; + } else + return false; +} + +struct TP_INIT { + HPOLYGON hPoly; // Polygon + USER_EVENT event; // Trigerring event + BUTEVENT bev; // To allow for double clicks + bool take_control; // Set if control should be taken + // while code is running. + int actor; +}; + +/** + * Runs glitter code associated with a polygon. + */ +static void PolyTinselProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + bool took_control; // Set if this function takes control + CORO_END_CONTEXT(_ctx); + + TP_INIT *to = (TP_INIT *)ProcessGetParamsSelf(); // get the stuff copied to process when it was created + + CORO_BEGIN_CODE(_ctx); + + CORO_INVOKE_1(AllowDclick, to->bev); // May kill us if single click + + // Control may have gone off during AllowDclick() + if (!TestToken(TOKEN_CONTROL) + && (to->event == WALKTO || to->event == ACTION || to->event == LOOK)) + CORO_KILL_SELF(); + + // Take control, if requested + if (to->take_control) + _ctx->took_control = GetControl(CONTROL_OFF); + else + _ctx->took_control = false; + + // Hide conversation if appropriate + if (to->event == CONVERSE) + convHide(true); + + // Run the code + _ctx->pic = InitInterpretContext(GS_POLYGON, getPolyScript(to->hPoly), to->event, to->hPoly, to->actor, NULL); + CORO_INVOKE_1(Interpret, _ctx->pic); + + // Free control if we took it + if (_ctx->took_control) + control(CONTROL_ON); + + // Restore conv window if applicable + if (to->event == CONVERSE) + convHide(false); + + CORO_END_CODE; +} + +/** + * Runs glitter code associated with a polygon. + */ +void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc) { + TP_INIT to = { hPoly, event, be, tc, 0 }; + + CoroutineInstall(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); +} + +void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor) { + TP_INIT to = { hPoly, event, BE_NONE, false, actor }; + + CoroutineInstall(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); +} + +//----------------------------------------------------------------------- + +struct WP_INIT { + int x; // } Where to walk to + int y; // } +}; + +/** + * Perform a walk directly initiated by a click. + */ +static void WalkProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PMACTOR pActor; + CORO_END_CONTEXT(_ctx); + + WP_INIT *to = (WP_INIT *)ProcessGetParamsSelf(); // get the co-ordinates - copied to process when it was created + + CORO_BEGIN_CODE(_ctx); + + _ctx->pActor = GetMover(LEAD_ACTOR); + if (_ctx->pActor->MActorState == NORM_MACTOR) { + assert(_ctx->pActor->hCpath != NOPOLY); // Lead actor is not in a path + + GetToken(TOKEN_LEAD); + SetActorDest(_ctx->pActor, to->x, to->y, false, 0); + DontScrollCursor(); + + while (MAmoving(_ctx->pActor)) + CORO_SLEEP(1); + + FreeToken(TOKEN_LEAD); + } + + CORO_END_CODE; +} + +void walkto(int x, int y) { + WP_INIT to = { x, y }; + + CoroutineInstall(PID_TCODE, WalkProcess, &to, sizeof(to)); +} + +/** + * Run appropriate actor or polygon glitter code. + * If none, and it's a WALKTO event, do a walk. + */ +static void User_Event(USER_EVENT uEvent, BUTEVENT be) { + int actor; + int aniX, aniY; + HPOLYGON hPoly; + + // Prevent activation of 2 events on the same tick + if (++eCount != 1) + return; + + if ((actor = GetTaggedActor()) != 0) + actorEvent(actor, uEvent, be); + else if ((hPoly = GetTaggedPoly()) != NOPOLY) + RunPolyTinselCode(hPoly, uEvent, be, false); + else { + GetCursorXY(&aniX, &aniY, true); + + // There could be a poly involved which has no tag. + if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY + || (hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY) { + RunPolyTinselCode(hPoly, uEvent, be, false); + } else if (uEvent == WALKTO) + walkto(aniX, aniY); + } +} + + +/** + * ProcessButEvent + */ +void ProcessButEvent(BUTEVENT be) { + IncUserEvents(); + + if (bSwapButtons) { + switch (be) { + case BE_SLEFT: + be = BE_SRIGHT; + break; + case BE_DLEFT: + be = BE_DRIGHT; + break; + case BE_SRIGHT: + be = BE_SLEFT; + break; + case BE_DRIGHT: + be = BE_DLEFT; + break; + case BE_LDSTART: + be = BE_RDSTART; + break; + case BE_LDEND: + be = BE_RDEND; + break; + case BE_RDSTART: + be = BE_LDSTART; + break; + case BE_RDEND: + be = BE_LDEND; + break; + default: + break; + } + } + +// if (be == BE_SLEFT || be == BE_DLEFT || be == BE_SRIGHT || be == BE_DRIGHT) + if (be == BE_SLEFT || be == BE_SRIGHT) + butEvents++; + + if (!TestToken(TOKEN_CONTROL) && be != BE_LDEND) + return; + + if (InventoryActive()) { + ButtonToInventory(be); + } else { + switch (be) { + case BE_SLEFT: + User_Event(WALKTO, BE_SLEFT); + break; + + case BE_DLEFT: + User_Event(ACTION, BE_DLEFT); + break; + + case BE_SRIGHT: + User_Event(LOOK, BE_SRIGHT); + break; + + default: + break; + } + } +} + +/** + * ProcessKeyEvent + */ + +void ProcessKeyEvent(KEYEVENT ke) { + // This stuff to allow F1 key during startup. + if (bEnableF1 && ke == OPTION_KEY) + control(CONTROL_ON); + else + IncUserEvents(); + + if (ke == ESC_KEY) { + escEvents++; + butEvents++; // Yes, I do mean this + } + + // FIXME: This comparison is weird - I added (BUTEVENT) cast for now to suppress warning + if (!TestToken(TOKEN_CONTROL) && (BUTEVENT)ke != BE_LDEND) + return; + + switch (ke) { + case QUIT_KEY: + PopUpConf(QUIT); + break; + + case OPTION_KEY: + PopUpConf(OPTION); + break; + + case SAVE_KEY: + PopUpConf(SAVE); + break; + + case LOAD_KEY: + PopUpConf(LOAD); + break; + + case WALKTO_KEY: + if (InventoryActive()) + ButtonToInventory(BE_SLEFT); + else + User_Event(WALKTO, BE_NONE); + break; + + case ACTION_KEY: + if (InventoryActive()) + ButtonToInventory(BE_DLEFT); + else + User_Event(ACTION, BE_NONE); + break; + + case LOOK_KEY: + if (InventoryActive()) + ButtonToInventory(BE_SRIGHT); + else + User_Event(LOOK, BE_NONE); + break; + + case ESC_KEY: + case PGUP_KEY: + case PGDN_KEY: + case HOME_KEY: + case END_KEY: + if (InventoryActive()) + KeyToInventory(ke); + break; + + default: + break; + } +} + +/** + * For ESCapable Glitter sequences + */ + +int GetEscEvents(void) { + return escEvents; +} + +/** + * For cutting short talk()s etc. + */ + +int GetLeftEvents(void) { + return butEvents; +} + +/** + * For waitkey() Glitter function + */ + +int getUserEvents(void) { + return userEvents; +} + +uint32 getUserEventTime(void) { + return DwGetCurrentTime() - lastUserEvent; +} + +void resetUserEventTime(void) { + lastUserEvent = DwGetCurrentTime(); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/events.h b/engines/tinsel/events.h new file mode 100644 index 0000000000..bc49d68717 --- /dev/null +++ b/engines/tinsel/events.h @@ -0,0 +1,84 @@ +/* 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$ + * + * User events processing and utility functions + */ + +#ifndef TINSEL_EVENTS_H +#define TINSEL_EVENTS_H + +#include "tinsel/dw.h" +#include "tinsel/coroutine.h" + +namespace Tinsel { + +enum BUTEVENT { + BE_NONE, BE_SLEFT, BE_DLEFT, BE_SRIGHT, BE_DRIGHT, + BE_LDSTART, BE_LDEND, BE_RDSTART, BE_RDEND, + BE_UNKNOWN +}; + + +enum KEYEVENT { + ESC_KEY, QUIT_KEY, SAVE_KEY, LOAD_KEY, OPTION_KEY, + PGUP_KEY, PGDN_KEY, HOME_KEY, END_KEY, + WALKTO_KEY, ACTION_KEY, LOOK_KEY, + NOEVENT_KEY +}; + + +/** + * Reasons for running Glitter code. + * Do not re-order these as equivalent CONSTs are defined in the master + * scene Glitter source file for testing against the event() library function. + */ +enum USER_EVENT { + POINTED, WALKTO, ACTION, LOOK, + ENTER, LEAVE, STARTUP, CONVERSE, + UNPOINT, PUTDOWN, + NOEVENT +}; + + +void AllowDclick(CORO_PARAM, BUTEVENT be); +bool GetControl(int param); + +void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc); +void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor); + +void ProcessButEvent(BUTEVENT be); +void ProcessKeyEvent(KEYEVENT ke); + + +int GetEscEvents(void); +int GetLeftEvents(void); +int getUserEvents(void); + +uint32 getUserEventTime(void); +void resetUserEventTime(void); + +void ResetEcount(void); + +} // end of namespace Tinsel + +#endif /* TINSEL_EVENTS_H */ diff --git a/engines/tinsel/faders.cpp b/engines/tinsel/faders.cpp new file mode 100644 index 0000000000..9ac742800f --- /dev/null +++ b/engines/tinsel/faders.cpp @@ -0,0 +1,175 @@ +/* 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$ + * + * Palette Fader and Flasher processes. + */ + +#include "tinsel/pid.h" // list of all process IDs +#include "tinsel/sched.h" // scheduler defs +#include "tinsel/faders.h" // fader defs +#include "tinsel/handle.h" +#include "tinsel/palette.h" // Palette Manager defs + +namespace Tinsel { + +/** structure used by the "FadeProcess" process */ +struct FADE { + const long *pColourMultTable; // list of fixed point colour multipliers - terminated with negative entry + PPALQ pPalQ; // palette queue entry to fade +}; + +// fixed point fade multiplier tables +//const long fadeout[] = {0xf000, 0xd000, 0xb000, 0x9000, 0x7000, 0x5000, 0x3000, 0x1000, 0, -1}; +const long fadeout[] = {0xd000, 0xa000, 0x7000, 0x4000, 0x1000, 0, -1}; +//const long fadein[] = {0, 0x1000, 0x3000, 0x5000, 0x7000, 0x9000, 0xb000, 0xd000, 0x10000L, -1}; +const long fadein[] = {0, 0x1000, 0x4000, 0x7000, 0xa000, 0xd000, 0x10000L, -1}; + +/** + * Scale 'colour' by the fixed point colour multiplier 'colourMult' + * @param colour Colour to scale + * @param colourMult Fixed point multiplier + */ +static COLORREF ScaleColour(COLORREF colour, uint32 colourMult) { + // apply multiplier to RGB components + uint32 red = ((GetRValue(colour) * colourMult) << 8) >> 24; + uint32 green = ((GetGValue(colour) * colourMult) << 8) >> 24; + uint32 blue = ((GetBValue(colour) * colourMult) << 8) >> 24; + + // return new colour + return RGB(red, green, blue); +} + +/** + * Applies the fixed point multiplier 'mult' to all colours in + * 'pOrig' to produce 'pNew'. Each colour in the palette will be + * multiplied by 'mult'. + * @param pNew Pointer to new palette + * @param pOrig Pointer to original palette + * @param numColours Number of colours in the above palettes + * @param mult Fixed point multiplier + */ +static void FadePalette(COLORREF *pNew, COLORREF *pOrig, int numColours, uint32 mult) { + for (int i = 0; i < numColours; i++, pNew++, pOrig++) { + // apply multiplier to RGB components + *pNew = ScaleColour(*pOrig, mult); + } +} + +/** + * Process to fade one palette. + * A pointer to a 'FADE' structure must be passed to this process when + * it is created. + */ +static void FadeProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + COLORREF fadeRGB[MAX_COLOURS]; // local copy of palette + const long *pColMult; // pointer to colour multiplier table + PALETTE *pPalette; // pointer to palette + CORO_END_CONTEXT(_ctx); + + // get the fade data structure - copied to process when it was created + FADE *pFade = (FADE *)ProcessGetParamsSelf(); + + CORO_BEGIN_CODE(_ctx); + + // get pointer to palette - reduce pointer indirection a bit + _ctx->pPalette = (PALETTE *)LockMem(pFade->pPalQ->hPal); + + for (_ctx->pColMult = pFade->pColourMultTable; *_ctx->pColMult >= 0; _ctx->pColMult++) { + // go through all multipliers in table - until a negative entry + + // fade palette using next multiplier + FadePalette(_ctx->fadeRGB, _ctx->pPalette->palRGB, + FROM_LE_32(_ctx->pPalette->numColours), (uint32) *_ctx->pColMult); + + // send new palette to video DAC + UpdateDACqueue(pFade->pPalQ->posInDAC, FROM_LE_32(_ctx->pPalette->numColours), _ctx->fadeRGB); + + // allow time for video DAC to be updated + CORO_SLEEP(1); + } + + CORO_END_CODE; +} + +/** + * Generic palette fader/unfader. Creates a 'FadeProcess' process + * for each palette that is to fade. + * @param multTable Fixed point colour multiplier table + * @param noFadeTable List of palettes not to fade + */ +static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) { + PPALQ pPal; // palette manager iterator + + // create a process for each palette in the palette queue + for (pPal = GetNextPalette(NULL); pPal != NULL; pPal = GetNextPalette(pPal)) { + bool bFade = true; + // assume we want to fade this palette + + // is palette in the list of palettes not to fade + if (noFadeTable != NULL) { + // there is a list of palettes not to fade + for (int i = 0; noFadeTable[i] != 0; i++) { + if (pPal->hPal == noFadeTable[i]) { + // palette is in the list - dont fade it + bFade = false; + + // leave loop prematurely + break; + } + } + } + + if (bFade) { + FADE fade; + + // fill in FADE struct + fade.pColourMultTable = multTable; + fade.pPalQ = pPal; + + // create a fader process for this palette + CoroutineInstall(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); + } + } +} + +/** + * Fades a list of palettes down to black. + * @param noFadeTable A NULL terminated list of palettes not to fade. + */ +void FadeOutFast(SCNHANDLE noFadeTable[]) { + // call generic fader + Fader(fadeout, noFadeTable); +} + +/** + * Fades a list of palettes from black to their current colours. + * @param noFadeTable A NULL terminated list of palettes not to fade. + */ +void FadeInFast(SCNHANDLE noFadeTable[]) { + // call generic fader + Fader(fadein, noFadeTable); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/faders.h b/engines/tinsel/faders.h new file mode 100644 index 0000000000..1e9336fae8 --- /dev/null +++ b/engines/tinsel/faders.h @@ -0,0 +1,55 @@ +/* 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$ + * + * Data structures used by the fader and flasher processes + */ + +#ifndef TINSEL_FADERS_H // prevent multiple includes +#define TINSEL_FADERS_H + +#include "tinsel/dw.h" // for SCNHANDLE + +namespace Tinsel { + +enum { + /** + * Number of iterations in a fade out. + * Must match which FadeOut() is in use. + */ + COUNTOUT_COUNT = 6 +}; + +/*----------------------------------------------------------------------*\ +|* Fader Function Prototypes *| +\*----------------------------------------------------------------------*/ + +// usefull palette faders - they all need a list of palettes that +// should not be faded. This parameter can be +// NULL - fade all palettes. + +void FadeOutFast(SCNHANDLE noFadeTable[]); +void FadeInFast(SCNHANDLE noFadeTable[]); + +} // end of namespace Tinsel + +#endif // TINSEL_FADERS_H diff --git a/engines/tinsel/film.h b/engines/tinsel/film.h new file mode 100644 index 0000000000..c8bf4604bc --- /dev/null +++ b/engines/tinsel/film.h @@ -0,0 +1,50 @@ +/* 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 TINSEL_FILM_H // prevent multiple includes +#define TINSEL_FILM_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +#include "common/pack-start.h" // START STRUCT PACKING + +struct FREEL { + SCNHANDLE mobj; + SCNHANDLE script; +} PACKED_STRUCT; + +struct FILM { + int32 frate; + int32 numreels; + FREEL reels[1]; +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + +} // end of namespace Tinsel + +#endif diff --git a/engines/tinsel/font.cpp b/engines/tinsel/font.cpp new file mode 100644 index 0000000000..335ba031fe --- /dev/null +++ b/engines/tinsel/font.cpp @@ -0,0 +1,96 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "tinsel/dw.h" +#include "tinsel/font.h" +#include "tinsel/handle.h" +#include "tinsel/object.h" +#include "tinsel/text.h" + +namespace Tinsel { + +//----------------- LOCAL GLOBAL DATA -------------------- + +static char tBuffer[TBUFSZ]; + +static SCNHANDLE hTagFont = 0, hTalkFont = 0; + + +/** + * Return address of tBuffer + */ +char *tBufferAddr() { + return tBuffer; +} + +/** + * Return hTagFont handle. + */ +SCNHANDLE hTagFontHandle() { + return hTagFont; +} + +/** + * Return hTalkFont handle. + */ +SCNHANDLE hTalkFontHandle() { + return hTalkFont; +} + +/** + * Called from dec_tagfont() Glitter function. Store the tag font handle. + */ +void TagFontHandle(SCNHANDLE hf) { + hTagFont = hf; // Store the font handle +} + +/** + * Called from dec_talkfont() Glitter function. + * Store the talk font handle. + */ +void TalkFontHandle(SCNHANDLE hf) { + hTalkFont = hf; // Store the font handle +} + +/** + * Poke the background palette into character 0's images. + */ +void fettleFontPal(SCNHANDLE fontPal) { + const FONT *pFont; + PIMAGE pImg; + + assert(fontPal); + assert(hTagFont); // Tag font not declared + assert(hTalkFont); // Talk font not declared + + pFont = (const FONT *)LockMem(hTagFont); + pImg = (PIMAGE)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0 + pImg->hImgPal = TO_LE_32(fontPal); + + pFont = (const FONT *)LockMem(hTalkFont); + pImg = (PIMAGE)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0 + pImg->hImgPal = TO_LE_32(fontPal); +} + +} // End of namespace Tinsel diff --git a/engines/tinsel/font.h b/engines/tinsel/font.h new file mode 100644 index 0000000000..b75c36191c --- /dev/null +++ b/engines/tinsel/font.h @@ -0,0 +1,48 @@ +/* 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 TINSEL_FONT_H // prevent multiple includes +#define TINSEL_FONT_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +// A temporary buffer for extracting text into is defined in font.c +// Accessed using tBufferAddr(), this is how big it is: +#define TBUFSZ 512 + + +char *tBufferAddr(void); +SCNHANDLE hTagFontHandle(void); +SCNHANDLE hTalkFontHandle(void); + +void TagFontHandle(SCNHANDLE hf); +void TalkFontHandle(SCNHANDLE hf); +void fettleFontPal(SCNHANDLE fontPal); + +} // end of namespace Tinsel + +#endif // TINSEL_FONT_H diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp new file mode 100644 index 0000000000..751b8929ef --- /dev/null +++ b/engines/tinsel/graphics.cpp @@ -0,0 +1,437 @@ +/* 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$ + * + * Low level graphics interface. + */ + +#include "tinsel/graphics.h" +#include "tinsel/handle.h" // LockMem() +#include "tinsel/object.h" +#include "tinsel/palette.h" +#include "tinsel/tinsel.h" + +namespace Tinsel { + +//----------------- LOCAL DEFINES -------------------- + +// Defines used in graphic drawing +#define CHARPTR_OFFSET 16 +#define CHAR_WIDTH 4 +#define CHAR_HEIGHT 4 + +extern uint8 transPalette[MAX_COLOURS]; + +//----------------- SUPPORT FUNCTIONS --------------------- + +/** + * Straight rendering with transparency support + */ + +static void WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) { + // Set up the offset between destination blocks + int rightClip = applyClipping ? pObj->rightClip : 0; + Common::Rect boxBounds; + + if (applyClipping) { + // Adjust the height down to skip any bottom clipping + pObj->height -= pObj->botClip; + + // Make adjustment for the top clipping row + srcP += sizeof(uint16) * ((pObj->width + 3) >> 2) * (pObj->topClip >> 2); + pObj->height -= pObj->topClip; + pObj->topClip %= 4; + } + + // Vertical loop + while (pObj->height > 0) { + // Get the start of the next line output + uint8 *tempDest = destP; + + // Get the line width, and figure out which row range within the 4 row high blocks + // will be displayed if clipping is to be taken into account + int width = pObj->width; + + if (!applyClipping) { + // No clipping, so so set box bounding area for drawing full 4x4 pixel blocks + boxBounds.top = 0; + boxBounds.bottom = 3; + boxBounds.left = 0; + } else { + // Handle any possible clipping at the top of the char block. + // We already handled topClip partially at the beginning of this function. + // Hence the only non-zero values it can assume at this point are 1,2,3, + // and that only during the very first iteration (i.e. when the top char + // block is drawn only partially). In particular, we set topClip to zero, + // as all following blocks are not to be top clipped. + boxBounds.top = pObj->topClip; + pObj->topClip = 0; + + boxBounds.bottom = MIN(boxBounds.top + pObj->height - 1, 3); + + // Handle any possible clipping at the start of the line + boxBounds.left = pObj->leftClip; + if (boxBounds.left >= 4) { + srcP += sizeof(uint16) * (boxBounds.left >> 2); + width -= boxBounds.left & 0xfffc; + boxBounds.left %= 4; + } + + width -= boxBounds.left; + } + + // Horizontal loop + while (width > rightClip) { + boxBounds.right = MIN(boxBounds.left + width - rightClip - 1, 3); + assert(boxBounds.bottom >= boxBounds.top); + assert(boxBounds.right >= boxBounds.left); + + int16 indexVal = READ_LE_UINT16(srcP); + srcP += sizeof(uint16); + + if (indexVal >= 0) { + // Draw a 4x4 block based on the opcode as in index into the block list + const uint8 *p = (uint8 *)pObj->charBase + (indexVal << 4); + p += boxBounds.top * sizeof(uint32); + for (int yp = boxBounds.top; yp <= boxBounds.bottom; ++yp, p += sizeof(uint32)) { + Common::copy(p + boxBounds.left, p + boxBounds.right + 1, tempDest + (SCREEN_WIDTH * (yp - boxBounds.top))); + } + + } else { + // Draw a 4x4 block with transparency support + indexVal &= 0x7fff; + + // If index is zero, then skip drawing the block completely + if (indexVal > 0) { + // Use the index along with the object's translation offset + const uint8 *p = (uint8 *)pObj->charBase + ((pObj->transOffset + indexVal) << 4); + + // Loop through each pixel - only draw a pixel if it's non-zero + p += boxBounds.top * sizeof(uint32); + for (int yp = boxBounds.top; yp <= boxBounds.bottom; ++yp) { + p += boxBounds.left; + for (int xp = boxBounds.left; xp <= boxBounds.right; ++xp, ++p) { + if (*p) + *(tempDest + SCREEN_WIDTH * (yp - boxBounds.top) + (xp - boxBounds.left)) = *p; + } + p += 3 - boxBounds.right; + } + } + } + + tempDest += boxBounds.right - boxBounds.left + 1; + width -= 3 - boxBounds.left + 1; + + // None of the remaining horizontal blocks should be left clipped + boxBounds.left = 0; + } + + // If there is any width remaining, there must be a right edge clipping + if (width >= 0) + srcP += sizeof(uint16) * ((width + 3) >> 2); + + // Move to next line line + pObj->height -= boxBounds.bottom - boxBounds.top + 1; + destP += (boxBounds.bottom - boxBounds.top + 1) * SCREEN_WIDTH; + } +} + +/** + * Fill the destination area with a constant colour + */ + +static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) { + if (applyClipping) { + pObj->height -= pObj->topClip + pObj->botClip; + pObj->width -= pObj->leftClip + pObj->rightClip; + + if (pObj->width <= 0) + return; + } + + // Loop through any remaining lines + while (pObj->height > 0) { + Common::set_to(destP, destP + pObj->width, pObj->constant); + + --pObj->height; + destP += SCREEN_WIDTH; + } +} + +/** + * Translates the destination surface within the object's bounds using the transparency + * lookup table from transpal.cpp (the contents of which have been moved into palette.cpp) + */ + +static void WrtTrans(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) { + if (applyClipping) { + pObj->height -= pObj->topClip + pObj->botClip; + pObj->width -= pObj->leftClip + pObj->rightClip; + + if (pObj->width <= 0) + return; + } + + // Set up the offset between destination lines + int lineOffset = SCREEN_WIDTH - pObj->width; + + // Loop through any remaining lines + while (pObj->height > 0) { + for (int i = 0; i < pObj->width; ++i, ++destP) + *destP = transPalette[*destP]; + + --pObj->height; + destP += lineOffset; + } +} + + +#if 0 +// This commented out code is the untested original WrtNonZero/ClpWrtNonZero combo method +// from the v1 source. It may be needed to be included later on to support v1 gfx files + +/** + * Straight rendering with transparency support + * Possibly only used in the Discworld Demo + */ + +static void DemoWrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping) { + // FIXME: If this method is used for the demo, it still needs to be made Endian safe + + // Set up the offset between destination lines + pObj->lineoffset = SCREEN_WIDTH - pObj->width - (applyClipping ? pObj->leftClip - pObj->rightClip : 0); + + // Top clipped line handling + while (applyClipping && (pObj->topClip > 0)) { + // Loop through discarding the data for the line + int width = pObj->width; + while (width > 0) { + int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP); + srcP += sizeof(uint32); + + if (opcodeOrLen >= 0) { + // Dump the data + srcP += ((opcodeOrLen + 3) / 4) * 4; + width -= opcodeOrLen; + } else { + // Dump the run-length opcode + width -= -opcodeOrLen; + } + } + + --pObj->height; + --pObj->topClip; + } + + // Loop for the required number of rows + while (pObj->height > 0) { + + int width = pObj->width; + + // Handling for left edge clipping - this basically involves dumping data until we reach + // the part of the line to be displayed + int clipLeft = pObj->leftClip; + while (applyClipping && (clipLeft > 0)) { + int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP); + srcP += sizeof(uint32); + + if (opcodeOrLen >= 0) { + // Copy a specified number of bytes + // Make adjustments for past the clipping width + int remainder = 4 - (opcodeOrLen % 4); + srcP += MIN(clipLeft, opcodeOrLen); + opcodeOrLen -= MIN(clipLeft, opcodeOrLen); + clipLeft -= MIN(clipLeft, opcodeOrLen); + width -= opcodeOrLen; + + + // Handle any right edge clipping (if run length covers entire width) + if (width < pObj->rightClip) { + remainder += (pObj->rightClip - width); + opcodeOrLen -= (pObj->rightClip - width); + } + + if (opcodeOrLen > 0) + Common::copy(srcP, srcP + opcodeOrLen, destP); + + } else { + // Output a run length number of bytes + // Get data for byte value and run length + opcodeOrLen = -opcodeOrLen; + int runLength = opcodeOrLen & 0xff; + uint8 colourVal = (opcodeOrLen >> 8) & 0xff; + + // Make adjustments for past the clipping width + runLength -= MIN(clipLeft, runLength); + clipLeft -= MIN(clipLeft, runLength); + width -= runLength; + + // Handle any right edge clipping (if run length covers entire width) + if (width < pObj->rightClip) + runLength -= (pObj->rightClip - width); + + if (runLength > 0) { + // Displayable part starts partway through the slice + if (colourVal != 0) + Common::set_to(destP, destP + runLength, colourVal); + destP += runLength; + } + } + + if (width < pObj->rightClip) + width = 0; + } + + // Handling for the visible part of the line + int endWidth = applyClipping ? pObj->rightClip : 0; + while (width > endWidth) { + int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP); + srcP += sizeof(uint32); + + if (opcodeOrLen >= 0) { + // Copy the specified number of bytes + int remainder = 4 - (opcodeOrLen % 4); + + if (width < endWidth) { + // Shorten run length by right clipping + remainder += (pObj->rightClip - width); + opcodeOrLen -= (pObj->rightClip - width); + } + + Common::copy(srcP, srcP + opcodeOrLen, destP); + srcP += opcodeOrLen + remainder; + destP += opcodeOrLen; + width -= opcodeOrLen; + + } else { + // Handle a given run length + opcodeOrLen = -opcodeOrLen; + int runLength = opcodeOrLen & 0xff; + uint8 colourVal = (opcodeOrLen >> 8) & 0xff; + + if (width < endWidth) + // Shorten run length by right clipping + runLength -= (pObj->rightClip - width); + + // Only set pixels if colourVal non-zero (0 signifies transparency) + if (colourVal != 0) + // Fill out a run length of a specified colour + Common::set_to(destP, destP + runLength, colourVal); + + destP += runLength; + width -= runLength; + } + } + + // If right edge clipping is being applied, then width may still be non-zero - in + // that case all remaining line data until the end of the line must be ignored + while (width > 0) { + int32 opcodeOrLen = (int32)READ_LE_UINT32(srcP); + srcP += sizeof(uint32); + + if (opcodeOrLen >= 0) { + // Dump the data + srcP += ((opcodeOrLen + 3) / 4) * 4; + width -= opcodeOrLen; + } else { + // Dump the run-length opcode + width -= -opcodeOrLen; + } + } + + --pObj->height; + destP += pObj->lineoffset; + } +} +#endif + +//----------------- MAIN FUNCTIONS --------------------- + +/** + * Clears both the screen surface buffer and screen to the specified value + */ +void ClearScreen(uint32 val) { + uint32 *pDest = (uint32 *)_vm->screen().getData(); + Common::set_to(pDest, (uint32 *)((byte *)pDest + SCREEN_WIDTH * SCREEN_HEIGHT), val); + _vm->screen().update(); +} + +/** + * Updates the screen surface within the following rectangle + */ +void UpdateScreenRect(const Common::Rect &pClip) { + _vm->screen().updateRect(pClip); +} + +/** + * Draws the specified object onto the screen surface buffer + */ +void DrawObject(DRAWOBJECT *pObj) { + uint8 *srcPtr = NULL; + uint8 *destPtr; + + if ((pObj->width <= 0) || (pObj->height <= 0)) + // Empty image, so return immediately + return; + + // If writing constant data, don't bother locking the data pointer and reading src details + if ((pObj->flags & DMA_CONST) == 0) { + byte *p = (byte *)LockMem(pObj->hBits & 0xFF800000); + + srcPtr = p + (pObj->hBits & 0x7FFFFF); + pObj->charBase = (char *)p + READ_LE_UINT32(p + 0x10); + pObj->transOffset = READ_LE_UINT32(p + 0x14); + } + + // Get destination starting point + destPtr = _vm->screen().getBasePtr(pObj->xPos, pObj->yPos); + + // Handle various draw types + uint8 typeId = pObj->flags & 0xff; + switch (typeId) { + case 0x01: + case 0x08: + case 0x41: + case 0x48: + WrtNonZero(pObj, srcPtr, destPtr, typeId >= 0x40); + break; + + case 0x04: + case 0x44: + // ClpWrtConst with/without clipping + WrtConst(pObj,destPtr, typeId == 0x44); + break; + + case 0x84: + case 0xC4: + // WrtTrans with/without clipping + WrtTrans(pObj, destPtr, typeId == 0xC4); + break; + + default: + // NoOp + error("Unknown drawing type %d", typeId); + break; + } +} + +} // End of namespace Tinsel diff --git a/engines/tinsel/graphics.h b/engines/tinsel/graphics.h new file mode 100644 index 0000000000..e080e08f58 --- /dev/null +++ b/engines/tinsel/graphics.h @@ -0,0 +1,103 @@ +/* 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$ + * + * Low level graphics interface. + */ + +#ifndef TINSEL_GRAPHICS_H // prevent multiple includes +#define TINSEL_GRAPHICS_H + +#include "tinsel/dw.h" + +#include "common/rect.h" +#include "common/system.h" +#include "graphics/surface.h" + +namespace Tinsel { + +struct PALQ; + + +#define SCREEN_WIDTH 320 // PC screen dimensions +#define SCREEN_HEIGHT 200 +#define SCRN_CENTRE_X ((SCREEN_WIDTH - 1) / 2) // screen centre x +#define SCRN_CENTRE_Y ((SCREEN_HEIGHT - 1) / 2) // screen centre y + +/** Class representing either a buffered surface or the physical screen. */ +class Surface : public Graphics::Surface { +private: + bool _isScreen; +public: + Surface(bool isScreen = false) { _isScreen = isScreen; } + Surface(int Width, int Height) { create(Width, Height, 1); _isScreen = false; } + + // Surface methods + byte *getData() { return (byte *)pixels; } + byte *getBasePtr(int x, int y) { return (byte *)Graphics::Surface::getBasePtr(x, y); } + + void update() { + if (_isScreen) { + g_system->copyRectToScreen((const byte *)pixels, pitch, 0, 0, w, h); + g_system->updateScreen(); + } + } + void updateRect(const Common::Rect &r) { + g_system->copyRectToScreen(getBasePtr(r.left, r.top), pitch, r.left, r.top, r.width(), r.height()); + g_system->updateScreen(); + } + +}; + +/** draw object structure - only used when drawing objects */ +struct DRAWOBJECT { + char *charBase; // character set base address + int transOffset; // transparent character offset + int flags; // object flags - see above for list + PALQ *pPal; // objects palette Q position + int constant; // which colour in palette for monochrome objects + int width; // width of object + int height; // height of object + SCNHANDLE hBits; // image bitmap handle + int lineoffset; // offset to next line + int leftClip; // amount to clip off object left + int rightClip; // amount to clip off object right + int topClip; // amount to clip off object top + int botClip; // amount to clip off object bottom + short xPos; // x position of object + short yPos; // y position of object +}; + + +/*----------------------------------------------------------------------*\ +|* Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void ClearScreen(uint32 val); +void DrawObject(DRAWOBJECT *pObj); + +// called to update a rectangle on the video screen from a video page +void UpdateScreenRect(const Common::Rect &pClip); + +} // end of namespace Tinsel + +#endif diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp new file mode 100644 index 0000000000..610f23012f --- /dev/null +++ b/engines/tinsel/handle.cpp @@ -0,0 +1,366 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + * This file contains the handle based Memory Manager code + */ + +#define BODGE + +#include "common/file.h" + +#include "tinsel/dw.h" +#include "tinsel/scn.h" // name of "index" file +#include "tinsel/handle.h" +#include "tinsel/heapmem.h" // heap memory manager + + +// these are included only so the relevant structs can be used in convertLEStructToNative() +#include "tinsel/anim.h" +#include "tinsel/multiobj.h" +#include "tinsel/film.h" +#include "tinsel/object.h" +#include "tinsel/palette.h" +#include "tinsel/text.h" +#include "tinsel/scene.h" + +namespace Tinsel { + +//----------------- EXTERNAL GLOBAL DATA -------------------- + +#ifdef DEBUG +bool bLockedScene = 0; +#endif + + +//----------------- LOCAL DEFINES -------------------- + +struct MEMHANDLE { + char szName[12]; //!< 00 - file name of graphics file + int32 filesize; //!< 12 - file size and flags + PMEM_NODE pNode; //!< 16 - memory node for the graphics +}; + + +/** memory allocation flags - stored in the top bits of the filesize field */ +enum { + fPreload = 0x01000000L, //!< preload memory + fDiscard = 0x02000000L, //!< discard memory + fSound = 0x04000000L, //!< sound data + fGraphic = 0x08000000L, //!< graphic data + fCompressed = 0x10000000L, //!< compressed data + fLoaded = 0x20000000L //!< set when file data has been loaded +}; +#define FSIZE_MASK 0x00FFFFFFL //!< mask to isolate the filesize +#define MALLOC_MASK 0xFF000000L //!< mask to isolate the memory allocation flags +#define OFFSETMASK 0x007fffffL //!< get offset of address +//#define HANDLEMASK 0xFF800000L //!< get handle of address + +//----------------- LOCAL GLOBAL DATA -------------------- + +// handle table gets loaded from index file at runtime +static MEMHANDLE *handleTable = 0; + +// number of handles in the handle table +static uint numHandles = 0; + + +//----------------- FORWARD REFERENCES -------------------- + +static void LoadFile(MEMHANDLE *pH, bool bWarn); // load a memory block as a file + + +/** + * Loads the graphics handle table index file and preloads all the + * permanent graphics etc. + */ +void SetupHandleTable(void) { + enum { RECORD_SIZE = 20 }; + + int len; + uint i; + MEMHANDLE *pH; + Common::File f; + + if (f.open(INDEX_FILENAME)) { + // get size of index file + len = f.size(); + + if (len > 0) { + if ((len % RECORD_SIZE) != 0) { + // index file is corrupt + error("File %s is corrupt", INDEX_FILENAME); + } + + // calc number of handles + numHandles = len / RECORD_SIZE; + + // allocate memory for the index file + handleTable = (MEMHANDLE *)calloc(numHandles, sizeof(struct MEMHANDLE)); + + // make sure memory allocated + assert(handleTable); + + // load data + for (i = 0; i < numHandles; i++) { + f.read(handleTable[i].szName, 12); + handleTable[i].filesize = f.readUint32LE(); + // The pointer should always be NULL. We don't + // need to read that from the file. + handleTable[i].pNode = NULL; + f.seek(4, SEEK_CUR); + } + + if (f.ioFailed()) { + // index file is corrupt + error("File %s is corrupt", INDEX_FILENAME); + } + + // close the file + f.close(); + } else { // index file is corrupt + error("File %s is corrupt", INDEX_FILENAME); + } + } else { // cannot find the index file + error("Cannot find file %s", INDEX_FILENAME); + } + + // allocate memory nodes and load all permanent graphics + for (i = 0, pH = handleTable; i < numHandles; i++, pH++) { + if (pH->filesize & fPreload) { + // allocate a fixed memory node for permanent files + pH->pNode = MemoryAlloc(DWM_FIXED, pH->filesize & FSIZE_MASK); + + // make sure memory allocated + assert(pH->pNode); + + // load the data + LoadFile(pH, true); + } +#ifdef BODGE + else if ((pH->filesize & FSIZE_MASK) == 8) { + pH->pNode = NULL; + } +#endif + else { + // allocate a discarded memory node for other files + pH->pNode = MemoryAlloc( + DWM_MOVEABLE | DWM_DISCARDABLE | DWM_NOALLOC, + pH->filesize & FSIZE_MASK); + + // make sure memory allocated + assert(pH->pNode); + } + } +} + +void FreeHandleTable(void) { + if (handleTable) { + free(handleTable); + handleTable = NULL; + } +} + +/** + * Loads a memory block as a file. + * @param pH Memory block pointer + * @param bWarn If set, treat warnings as errors + */ +void LoadFile(MEMHANDLE *pH, bool bWarn) { + Common::File f; + char szFilename[sizeof(pH->szName) + 1]; + + if (pH->filesize & fCompressed) { + error("Compression handling has been removed!"); + } + + // extract and zero terminate the filename + strncpy(szFilename, pH->szName, sizeof(pH->szName)); + szFilename[sizeof(pH->szName)] = 0; + + if (f.open(szFilename)) { + // read the data + int bytes; + uint8 *addr; + + if (pH->filesize & fPreload) + // preload - no need to lock the memory + addr = (uint8 *)pH->pNode; + else { + // discardable - lock the memory + addr = (uint8 *)MemoryLock(pH->pNode); + } +#ifdef DEBUG + if (addr == NULL) { + if (pH->filesize & fPreload) + // preload - no need to lock the memory + addr = (uint8 *)pH->pNode; + else { + // discardable - lock the memory + addr = (uint8 *)MemoryLock(pH->pNode); + } + } +#endif + + // make sure address is valid + assert(addr); + + bytes = f.read(addr, pH->filesize & FSIZE_MASK); + + // close the file + f.close(); + + if ((pH->filesize & fPreload) == 0) { + // discardable - unlock the memory + MemoryUnlock(pH->pNode); + } + + // set the loaded flag + pH->filesize |= fLoaded; + + if (bytes == (pH->filesize & FSIZE_MASK)) { + return; + } + + if (bWarn) + // file is corrupt + error("File %s is corrupt", szFilename); + } + + if (bWarn) + // cannot find file + error("Cannot find file %s", szFilename); +} + +/** + * Returns the address of a image, given its memory handle. + * @param offset Handle and offset to data + */ +uint8 *LockMem(SCNHANDLE offset) { + uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use + MEMHANDLE *pH; // points to table entry + + // range check the memory handle + assert(handle < numHandles); + + pH = handleTable + handle; + + if (pH->filesize & fPreload) { + // permanent files are already loaded + return (uint8 *)pH->pNode + (offset & OFFSETMASK); + } else { + if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded)) + // already allocated and loaded + return pH->pNode->pBaseAddr + (offset & OFFSETMASK); + + if (pH->pNode->pBaseAddr == NULL) + // must have been discarded - reallocate the memory + MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, + DWM_MOVEABLE | DWM_DISCARDABLE); + + if (pH->pNode->pBaseAddr == NULL) + error("Out of memory"); + + LoadFile(pH, true); + + // make sure address is valid + assert(pH->pNode->pBaseAddr); + + return pH->pNode->pBaseAddr + (offset & OFFSETMASK); + } +} + +/** + * Called to make the current scene non-discardable. + * @param offset Handle and offset to data + */ +void LockScene(SCNHANDLE offset) { + + uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use + MEMHANDLE *pH; // points to table entry + +#ifdef DEBUG + assert(!bLockedScene); // Trying to lock more than one scene +#endif + + // range check the memory handle + assert(handle < numHandles); + + pH = handleTable + handle; + + // compact the heap to avoid fragmentation while scene is non-discardable + HeapCompact(MAX_INT, false); + + if ((pH->filesize & fPreload) == 0) { + // change the flags for the node + MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, DWM_MOVEABLE); +#ifdef DEBUG + bLockedScene = true; +#endif + } +} + +/** + * Called to make the current scene discardable again. + * @param offset Handle and offset to data + */ +void UnlockScene(SCNHANDLE offset) { + + uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use + MEMHANDLE *pH; // points to table entry + + // range check the memory handle + assert(handle < numHandles); + + pH = handleTable + handle; + + if ((pH->filesize & fPreload) == 0) { + // change the flags for the node + MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, DWM_MOVEABLE | DWM_DISCARDABLE); +#ifdef DEBUG + bLockedScene = false; +#endif + } +} + +/*----------------------------------------------------------------------*/ + +#ifdef BODGE + +/** + * Validates that a specified handle pointer is valid + * @param offset Handle and offset to data + */ +bool ValidHandle(SCNHANDLE offset) { + uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use + MEMHANDLE *pH; // points to table entry + + // range check the memory handle + assert(handle < numHandles); + + pH = handleTable + handle; + + return (pH->filesize & FSIZE_MASK) != 8; +} +#endif + +} // end of namespace Tinsel diff --git a/engines/tinsel/handle.h b/engines/tinsel/handle.h new file mode 100644 index 0000000000..2cb1638d9d --- /dev/null +++ b/engines/tinsel/handle.h @@ -0,0 +1,53 @@ +/* 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$ + * + * Graphics Memory Manager data structures + * TODO: This should really be named dos_hand.h, or the dos_hand.cpp should be renamed + */ + +#ifndef TINSEL_HANDLE_H // prevent multiple includes +#define TINSEL_HANDLE_H + +#include "tinsel/dw.h" // new data types + +namespace Tinsel { + +/*----------------------------------------------------------------------*\ +|* Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void SetupHandleTable(void); // Loads the graphics handle table index file and preloads all the permanent graphics etc. +void FreeHandleTable(void); + +uint8 *LockMem( // returns the addr of a image, given its memory handle + SCNHANDLE offset); // handle and offset to data + +void LockScene( // Called to make the current scene non-discardable + SCNHANDLE offset); // handle and offset to data + +void UnlockScene( // Called to make the current scene discardable again + SCNHANDLE offset); // handle and offset to data + +} // end of namespace Tinsel + +#endif // TINSEL_HANDLE_H diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp new file mode 100644 index 0000000000..f3df3d4391 --- /dev/null +++ b/engines/tinsel/heapmem.cpp @@ -0,0 +1,594 @@ +/* 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$ + * + * This file contains the handle based Memory Manager code. + */ + +#include "tinsel/heapmem.h" +#include "tinsel/timers.h" // For DwGetCurrentTime + +namespace Tinsel { + +// minimum memory required for MS-DOS version of game +#define MIN_MEM 2506752L + +// list of all memory nodes +MEM_NODE mnodeList[NUM_MNODES]; + +// pointer to the linked list of free mnodes +static PMEM_NODE pFreeMemNodes; + +#ifdef DEBUG +// diagnostic mnode counters +static int numNodes; +static int maxNodes; +#endif + +// the mnode heap sentinel +static MEM_NODE heapSentinel; + +// +static PMEM_NODE AllocMemNode(void); + + +/** + * Initialises the memory manager. + */ +void MemoryInit(void) { + PMEM_NODE pNode; + +#ifdef DEBUG + // clear number of nodes in use + numNodes = 0; +#endif + + // place first node on free list + pFreeMemNodes = mnodeList; + + // link all other objects after first + for (int i = 1; i < NUM_MNODES; i++) { + mnodeList[i - 1].pNext = mnodeList + i; + } + + // null the last mnode + mnodeList[NUM_MNODES - 1].pNext = NULL; + + // allocatea big chunk of memory + const uint32 size = 2*MIN_MEM+655360L; + uint8 *mem = (uint8 *)malloc(size); + assert(mem); + + // allocate a mnode for this memory + pNode = AllocMemNode(); + + // make sure mnode was allocated + assert(pNode); + + // convert segment to memory address + pNode->pBaseAddr = mem; + + // set size of the memory heap + pNode->size = size; + + // clear the memory + memset(pNode->pBaseAddr, 0, size); + + // set cyclic links to the sentinel + heapSentinel.pPrev = pNode; + heapSentinel.pNext = pNode; + pNode->pPrev = &heapSentinel; + pNode->pNext = &heapSentinel; + + // flag sentinel as locked + heapSentinel.flags = DWM_LOCKED | DWM_SENTINEL; +} + + +#ifdef DEBUG +/** + * Shows the maximum number of mnodes used at once. + */ + +void MemoryStats(void) { + printf("%i mnodes of %i used.\n", maxNodes, NUM_MNODES); +} +#endif + +/** + * Allocate a mnode from the free list. + */ +static PMEM_NODE AllocMemNode(void) { + // get the first free mnode + PMEM_NODE pMemNode = pFreeMemNodes; + + // make sure a mnode is available + assert(pMemNode); // Out of memory nodes + + // the next free mnode + pFreeMemNodes = pMemNode->pNext; + + // wipe out the mnode + memset(pMemNode, 0, sizeof(MEM_NODE)); + +#ifdef DEBUG + // one more mnode in use + if (++numNodes > maxNodes) + maxNodes = numNodes; +#endif + + // return new mnode + return pMemNode; +} + +/** + * Return a mnode back to the free list. + * @param pMemNode Node of the memory object + */ +void FreeMemNode(PMEM_NODE pMemNode) { + // validate mnode pointer + assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); + +#ifdef DEBUG + // one less mnode in use + --numNodes; + assert(numNodes >= 0); +#endif + + // place free list in mnode next + pMemNode->pNext = pFreeMemNodes; + + // add mnode to top of free list + pFreeMemNodes = pMemNode; +} + + +/** + * Tries to make space for the specified number of bytes on the specified heap. + * @param size Number of bytes to free up + * @param bDiscard When set - will discard blocks to fullfill the request + */ +bool HeapCompact(long size, bool bDiscard) { + PMEM_NODE pHeap = &heapSentinel; + PMEM_NODE pPrev, pCur, pOldest; + long largest; // size of largest free block + uint32 oldest; // time of the oldest discardable block + + while (true) { + bool bChanged; + + do { + bChanged = false; + for (pPrev = pHeap->pNext, pCur = pPrev->pNext; + pCur != pHeap; pPrev = pCur, pCur = pCur->pNext) { + if (pPrev->flags == 0 && pCur->flags == 0) { + // set the changed flag + bChanged = true; + + // both blocks are free - merge them + pPrev->size += pCur->size; + + // unlink the current mnode + pPrev->pNext = pCur->pNext; + pCur->pNext->pPrev = pPrev; + + // free the current mnode + FreeMemNode(pCur); + + // leave the loop + break; + } else if ((pPrev->flags & (DWM_MOVEABLE | DWM_LOCKED | DWM_DISCARDED)) == DWM_MOVEABLE + && pCur->flags == 0) { + // a free block after a moveable block - swap them + + // set the changed flag + bChanged = true; + + // move the unlocked blocks data up (can overlap) + memmove(pPrev->pBaseAddr + pCur->size, + pPrev->pBaseAddr, pPrev->size); + + // swap the order in the linked list + pPrev->pPrev->pNext = pCur; + pCur->pNext->pPrev = pPrev; + + pCur->pPrev = pPrev->pPrev; + pPrev->pPrev = pCur; + + pPrev->pNext = pCur->pNext; + pCur->pNext = pPrev; + + pCur->pBaseAddr = pPrev->pBaseAddr; + pPrev->pBaseAddr += pCur->size; + + // leave the loop + break; + } + } + } while (bChanged); + + // find the largest free block + for (largest = 0, pCur = pHeap->pNext; pCur != pHeap; pCur = pCur->pNext) { + if (pCur->flags == 0 && pCur->size > largest) + largest = pCur->size; + } + + if (largest >= size) + // we have freed enough memory + return true; + + if (!bDiscard) + // we cannot free enough without discarding blocks + return false; + + // find the oldest discardable block + oldest = DwGetCurrentTime(); + pOldest = NULL; + for (pCur = pHeap->pNext; pCur != pHeap; pCur = pCur->pNext) { + if ((pCur->flags & (DWM_DISCARDABLE | DWM_DISCARDED | DWM_LOCKED)) + == DWM_DISCARDABLE) { + // found a non-discarded discardable block + if (pCur->lruTime < oldest) { + oldest = pCur->lruTime; + pOldest = pCur; + } + } + } + + if (pOldest) + // discard the oldest block + MemoryDiscard(pOldest); + else + // cannot discard any blocks + return false; + } +} + +/** + * Allocates the specified number of bytes from the heap. + * @param flags Allocation attributes + * @param size Number of bytes to allocate + */ +PMEM_NODE MemoryAlloc(int flags, long size) { + PMEM_NODE pHeap = &heapSentinel; + PMEM_NODE pNode; + bool bCompacted = true; // set when heap has been compacted + + // compact the heap if we are allocating fixed memory + if (flags & DWM_FIXED) + HeapCompact(MAX_INT, false); + + while ((flags & DWM_NOALLOC) == 0 && bCompacted) { + // search the heap for a free block + + for (pNode = pHeap->pNext; pNode != pHeap; pNode = pNode->pNext) { + if (pNode->flags == 0 && pNode->size >= size) { + // a free block of the required size + pNode->flags = flags; + + // update the LRU time + pNode->lruTime = DwGetCurrentTime() + 1; + + if (pNode->size == size) { + // an exact fit + + // check for zeroing the block + if (flags & DWM_ZEROINIT) + memset(pNode->pBaseAddr, 0, size); + + if (flags & DWM_FIXED) + // lock the memory + return (PMEM_NODE)MemoryLock(pNode); + else + // just return the node + return pNode; + } else { + // allocate a node for the remainder of the free block + PMEM_NODE pTemp = AllocMemNode(); + + // calc size of the free block + long freeSize = pNode->size - size; + + // set size of free block + pTemp->size = freeSize; + + // set size of node + pNode->size = size; + + if (flags & DWM_FIXED) { + // place the free node after pNode + pTemp->pBaseAddr = pNode->pBaseAddr + size; + pTemp->pNext = pNode->pNext; + pTemp->pPrev = pNode; + pNode->pNext->pPrev = pTemp; + pNode->pNext = pTemp; + + // check for zeroing the block + if (flags & DWM_ZEROINIT) + memset(pNode->pBaseAddr, 0, size); + + return (PMEM_NODE)MemoryLock(pNode); + } else { + // place the free node before pNode + pTemp->pBaseAddr = pNode->pBaseAddr; + pNode->pBaseAddr += freeSize; + pTemp->pNext = pNode; + pTemp->pPrev = pNode->pPrev; + pNode->pPrev->pNext = pTemp; + pNode->pPrev = pTemp; + + // check for zeroing the block + if (flags & DWM_ZEROINIT) + memset(pNode->pBaseAddr, 0, size); + + return pNode; + } + } + } + } + // compact the heap if we get to here + bCompacted = HeapCompact(size, (flags & DWM_NOCOMPACT) ? false : true); + } + + // not allocated a block if we get to here + if (flags & DWM_DISCARDABLE) { + // chain a discarded node onto the end of the heap + pNode = AllocMemNode(); + pNode->flags = flags | DWM_DISCARDED; + + // set mnode at the end of the list + pNode->pPrev = pHeap->pPrev; + pNode->pNext = pHeap; + + // fix links to this mnode + pHeap->pPrev->pNext = pNode; + pHeap->pPrev = pNode; + + // return the discarded node + return pNode; + } + + // could not allocate a block + return NULL; +} + +/** + * Discards the specified memory object. + * @param pMemNode Node of the memory object + */ +void MemoryDiscard(PMEM_NODE pMemNode) { + // validate mnode pointer + assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); + + // object must be discardable + assert(pMemNode->flags & DWM_DISCARDABLE); + + // object cannot be locked + assert((pMemNode->flags & DWM_LOCKED) == 0); + + if ((pMemNode->flags & DWM_DISCARDED) == 0) { + // allocate a free node to replace this node + PMEM_NODE pTemp = AllocMemNode(); + + // copy node data + memcpy(pTemp, pMemNode, sizeof(MEM_NODE)); + + // flag as a free block + pTemp->flags = 0; + + // link in the free node + pTemp->pPrev->pNext = pTemp; + pTemp->pNext->pPrev = pTemp; + + // discard the node + pMemNode->flags |= DWM_DISCARDED; + pMemNode->pBaseAddr = NULL; + pMemNode->size = 0; + + // and place it at the end of the heap + while ((pTemp->flags & DWM_SENTINEL) != DWM_SENTINEL) + pTemp = pTemp->pNext; + + // pTemp now points to the heap sentinel + // set mnode at the end of the list + pMemNode->pPrev = pTemp->pPrev; + pMemNode->pNext = pTemp; + + // fix links to this mnode + pTemp->pPrev->pNext = pMemNode; + pTemp->pPrev = pMemNode; + } +} + +/** + * Frees the specified memory object and invalidates its node. + * @param pMemNode Node of the memory object + */ +void MemoryFree(PMEM_NODE pMemNode) { + PMEM_NODE pPrev, pNext; + + // validate mnode pointer + assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); + + // get pointer to the next mnode + pNext = pMemNode->pNext; + + // get pointer to the previous mnode + pPrev = pMemNode->pPrev; + + if (pPrev->flags == 0) { + // there is a previous free mnode + pPrev->size += pMemNode->size; + + // unlink this mnode + pPrev->pNext = pNext; // previous to next + pNext->pPrev = pPrev; // next to previous + + // free this mnode + FreeMemNode(pMemNode); + + pMemNode = pPrev; + } + if (pNext->flags == 0) { + // the next mnode is free + pMemNode->size += pNext->size; + + // flag as a free block + pMemNode->flags = 0; + + // unlink the next mnode + pMemNode->pNext = pNext->pNext; + pNext->pNext->pPrev = pMemNode; + + // free the next mnode + FreeMemNode(pNext); + } +} + +/** + * Locks a memory object and returns a pointer to the first byte + * of the objects memory block. + * @param pMemNode Node of the memory object + */ +void *MemoryLock(PMEM_NODE pMemNode) { + // validate mnode pointer + assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); + + // make sure memory object is not already locked + assert((pMemNode->flags & DWM_LOCKED) == 0); + + // check for a discarded or null memory object + if ((pMemNode->flags & DWM_DISCARDED) || pMemNode->size == 0) + return NULL; + + // set the lock flag + pMemNode->flags |= DWM_LOCKED; + + // return memory objects base address + return pMemNode->pBaseAddr; +} + +/** + * Changes the size or attributes of a specified memory object. + * @param pMemNode Node of the memory object + * @param size New size of block + * @param flags How to reallocate the object + */ +PMEM_NODE MemoryReAlloc(PMEM_NODE pMemNode, long size, int flags) { + PMEM_NODE pNew; + + // validate mnode pointer + assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); + + // validate the flags + // cannot be fixed and moveable + assert((flags & (DWM_FIXED | DWM_MOVEABLE)) != (DWM_FIXED | DWM_MOVEABLE)); + + // cannot be fixed and discardable + assert((flags & (DWM_FIXED | DWM_DISCARDABLE)) != (DWM_FIXED | DWM_DISCARDABLE)); + + // must be fixed or moveable + assert(flags & (DWM_FIXED | DWM_MOVEABLE)); + + // align the size to machine boundary requirements + size = (size + sizeof(int) - 1) & ~(sizeof(int) - 1); + + // validate the size + assert(size); + + // make sure we want the node on the same heap + assert((flags & (DWM_SOUND | DWM_GRAPHIC)) == (pMemNode->flags & (DWM_SOUND | DWM_GRAPHIC))); + + if (size == pMemNode->size) { + // must be just a change in flags + + // update the nodes flags + pMemNode->flags = flags; + } else { + // unlink the mnode from the current heap + pMemNode->pNext->pPrev = pMemNode->pPrev; + pMemNode->pPrev->pNext = pMemNode->pNext; + + // allocate a new node + pNew = MemoryAlloc((flags & ~DWM_FIXED) | DWM_MOVEABLE, size); + + // make sure memory allocated + assert(pNew != NULL); + + // update the nodes flags + pNew->flags = flags; + + // copy the node to the current node + memcpy(pMemNode, pNew, sizeof(MEM_NODE)); + + // relink the mnode into the list + pMemNode->pPrev->pNext = pMemNode; + pMemNode->pNext->pPrev = pMemNode; + + // free the new node + FreeMemNode(pNew); + } + + if (flags & DWM_FIXED) + // lock the memory + return (PMEM_NODE)MemoryLock(pMemNode); + else + // just return the node + return pMemNode; +} + +/** + * Unlocks a memory object. + * @param pMemNode Node of the memory object + */ +void MemoryUnlock(PMEM_NODE pMemNode) { + // validate mnode pointer + assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); + + // make sure memory object is already locked + assert(pMemNode->flags & DWM_LOCKED); + + // clear the lock flag + pMemNode->flags &= ~DWM_LOCKED; + + // update the LRU time + pMemNode->lruTime = DwGetCurrentTime(); +} + +/** + * Retrieves the mnode associated with the specified pointer to a memory object. + * @param pMem Address of memory object + */ +PMEM_NODE MemoryHandle(void *pMem) { + PMEM_NODE pNode; + // search the DOS heap + for (pNode = heapSentinel.pNext; pNode != &heapSentinel; pNode = pNode->pNext) { + if (pNode->pBaseAddr == pMem) + // found it + return pNode; + } + + // not found if we get to here + return NULL; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/heapmem.h b/engines/tinsel/heapmem.h new file mode 100644 index 0000000000..c5d022b7f9 --- /dev/null +++ b/engines/tinsel/heapmem.h @@ -0,0 +1,110 @@ +/* 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$ + * + * This file contains the handle based Memory Manager defines + */ + +#ifndef TINSEL_HEAPMEM_H +#define TINSEL_HEAPMEM_H + +#include "tinsel/dw.h" // new data types + +namespace Tinsel { + +#define NUM_MNODES 192 // the number of memory management nodes (was 128, then 192) + +struct MEM_NODE { + MEM_NODE *pNext; // link to the next node in the list + MEM_NODE *pPrev; // link to the previous node in the list + uint8 *pBaseAddr; // base address of the memory object + long size; // size of the memory object + uint32 lruTime; // time when memory object was last accessed + int flags; // allocation attributes +}; +typedef MEM_NODE *PMEM_NODE; + +// allocation flags for the MemoryAlloc function +#define DWM_FIXED 0x0001 // allocates fixed memory +#define DWM_MOVEABLE 0x0002 // allocates movable memory +#define DWM_DISCARDABLE 0x0004 // allocates discardable memory +#define DWM_NOALLOC 0x0008 // when used with discardable memory - allocates a discarded block +#define DWM_NOCOMPACT 0x0010 // does not discard memory to satisfy the allocation request +#define DWM_ZEROINIT 0x0020 // initialises memory contents to zero +#define DWM_SOUND 0x0040 // allocate from the sound pool +#define DWM_GRAPHIC 0x0080 // allocate from the graphics pool + +// return value from the MemoryFlags function +#define DWM_DISCARDED 0x0100 // the objects memory block has been discarded + +// internal allocation flags +#define DWM_LOCKED 0x0200 // the objects memory block is locked +#define DWM_SENTINEL 0x0400 // the objects memory block is a sentinel + + +/*----------------------------------------------------------------------*\ +|* Memory Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void MemoryInit(void); // initialises the memory manager + +#ifdef DEBUG +void MemoryStats(void); // Shows the maximum number of mnodes used at once +#endif + +PMEM_NODE MemoryAlloc( // allocates the specified number of bytes from the heap + int flags, // allocation attributes + long size); // number of bytes to allocate + +void MemoryDiscard( // discards the specified memory object + PMEM_NODE pMemNode); // node of the memory object + +int MemoryFlags( // returns information about the specified memory object + PMEM_NODE pMemNode); // node of the memory object + +void MemoryFree( // frees the specified memory object and invalidates its node + PMEM_NODE pMemNode); // node of the memory object + +PMEM_NODE MemoryHandle( // Retrieves the mnode associated with the specified pointer to a memory object + void *pMem); // address of memory object + +void *MemoryLock( // locks a memory object and returns a pointer to the first byte of the objects memory block + PMEM_NODE pMemNode); // node of the memory object + +PMEM_NODE MemoryReAlloc( // changes the size or attributes of a specified memory object + PMEM_NODE pMemNode, // node of the memory object + long size, // new size of block + int flags); // how to reallocate the object + +long MemorySize( // returns the size, in bytes, of the specified memory object + PMEM_NODE pMemNode); // node of the memory object + +void MemoryUnlock( // unlocks a memory object + PMEM_NODE pMemNode); // node of the memory object + +bool HeapCompact( // Allocates the specified number of bytes from the specified heap + long size, // number of bytes to free up + bool bDiscard); // when set - will discard blocks to fullfill the request + +} // end of namespace Tinsel + +#endif diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp new file mode 100644 index 0000000000..96ee01edf6 --- /dev/null +++ b/engines/tinsel/inventory.cpp @@ -0,0 +1,4533 @@ +/* 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$ + * + * Handles the inventory and conversation windows. + * + * And the save/load game windows. Some of this will be platform + * specific - I'll try to separate this ASAP. + * + * And there's still a bit of tidying and commenting to do yet. + */ + +//#define USE_3FLAGS 1 + +#include "tinsel/actors.h" +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/config.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/film.h" +#include "tinsel/font.h" +#include "tinsel/graphics.h" +#include "tinsel/handle.h" +#include "tinsel/inventory.h" +#include "tinsel/multiobj.h" +#include "tinsel/music.h" +#include "tinsel/polygons.h" +#include "tinsel/savescn.h" +#include "tinsel/sched.h" +#include "tinsel/serializer.h" +#include "tinsel/sound.h" +#include "tinsel/strres.h" +#include "tinsel/text.h" +#include "tinsel/timers.h" // For ONE_SECOND constant +#include "tinsel/tinsel.h" // For engine access +#include "tinsel/token.h" +#include "tinsel/pcode.h" +#include "tinsel/pid.h" + +namespace Tinsel { + +//----------------- EXTERNAL GLOBAL DATA -------------------- + +// In DOS_DW.C +extern bool bRestart; // restart flag - set to restart the game + +#ifdef MAC_OPTIONS +// In MAC_SOUND.C +extern int volMaster; +#endif + + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// Tag functions in PDISPLAY.C +extern void EnableTags(void); +extern void DisableTags(void); + + +//----------------- LOCAL DEFINES -------------------- + +//#define ALL_CURSORS + +#define INV_PICKUP BE_SLEFT // Local names +#define INV_LOOK BE_SRIGHT // for button events +#define INV_ACTION BE_DLEFT // + + +// For SlideSlider() and similar +enum SSFN { + S_START, S_SLIDE, S_END, S_TIMEUP, S_TIMEDN +}; + +/** attribute values - may become bit field if further attributes are added */ +enum { + IO_ONLYINV1 = 0x01, + IO_ONLYINV2 = 0x02, + IO_DROPCODE = 0x04 +}; + +//----------------------- +// Moveable window translucent rectangle position limits +enum { + MAXLEFT = 315, // + MINRIGHT = 3, // These values keep 2 pixcells + MINTOP = -13, // of header on the screen. + MAXTOP = 195 // +}; + +//----------------------- +// Indices into winPartsf's reels +#define IX_SLIDE 0 // Slider +#define IX_V26 1 +#define IX_V52 2 +#define IX_V78 3 +#define IX_V104 4 +#define IX_V130 5 +#define IX_H26 6 +#define IX_H52 7 +#define IX_H78 8 +#define IX_H104 9 +#define IX_H130 10 +#define IX_H156 11 +#define IX_H182 12 +#define IX_H208 13 +#define IX_H234 14 +#define IX_TL 15 // Top left corner +#define IX_TR 16 // Top right corner +#define IX_BL 17 // Bottom left corner +#define IX_BR 18 // Bottom right corner +#define IX_H25 19 +#define IX_V11 20 +#define IX_RTL 21 // Re-sizing top left corner +#define IX_RTR 22 // Re-sizing top right corner +#define IX_RBR 23 // Re-sizing bottom right corner +#define IX_CURLR 24 // } +#define IX_CURUD 25 // } +#define IX_CURDU 26 // } Custom cursors +#define IX_CURDD 27 // } +#define IX_CURUP 28 // } +#define IX_CURDOWN 29 // } +#define IX_MDGROOVE 30 // 'Mixing desk' slider background +#define IX_MDSLIDER 34 // 'Mixing desk' slider + +#define IX_BLANK1 35 // +#define IX_BLANK2 36 // +#define IX_BLANK3 37 // +#define IX_CIRCLE1 38 // +#define IX_CIRCLE2 39 // +#define IX_CROSS1 40 // +#define IX_CROSS2 41 // +#define IX_CROSS3 42 // +#define IX_QUIT1 43 // +#define IX_QUIT2 44 // +#define IX_QUIT3 45 // +#define IX_TICK1 46 // +#define IX_TICK2 47 // +#define IX_TICK3 48 // +#define IX_NTR 49 // New top right corner +#define HOPEDFORREELS 50 + +#define NORMGRAPH 0 +#define DOWNGRAPH 1 +#define HIGRAPH 2 +//----------------------- +#define FIX_UK 0 +#define FIX_FR 1 +#define FIX_GR 2 +#define FIX_IT 3 +#define FIX_SP 4 +#define FIX_USA 5 +#define HOPEDFORFREELS 6 // Expected flag reels +//----------------------- + +#define MAX_ININV 150 // Max in an inventory +#define MAX_CONVBASIC 10 // Max permanent conversation icons + +#define MAXHICONS 10 // Max dimensions of +#define MAXVICONS 6 // an inventory window + +#define ITEM_WIDTH 25 // Dimensions of an icon +#define ITEM_HEIGHT 25 // + +// Number of objects that makes up an empty window +#define MAX_WCOMP 21 // 4 corners + (3+3) sides + (2+2) extra sides + // + Bground + title + slider + // + more Needed for save game window + +#define MAX_ICONS MAXHICONS*MAXVICONS + + + +//----------------- LOCAL GLOBAL DATA -------------------- + +//----- Permanent data (compiled in) ----- + +// Save game name editing cursor + +#define CURSOR_CHAR '_' +char sCursor[2] = { CURSOR_CHAR, 0 }; +static const int hFillers[MAXHICONS] = { + IX_H26, // 2 icons wide + IX_H52, // 3 + IX_H78, // 4 + IX_H104, // 5 + IX_H130, // 6 + IX_H156, // 7 + IX_H182, // 8 + IX_H208, // 9 + IX_H234 // 10 icons wide +}; +static const int vFillers[MAXVICONS] = { + IX_V26, // 2 icons high + IX_V52, // 3 + IX_V78, // 4 + IX_V104, // 5 + IX_V130 // 6 icons high +}; + + +//----- Permanent data (set once) ----- + +static SCNHANDLE winPartsf = 0; // Window members and cursors' graphic data +static SCNHANDLE flagFilm = 0; // Window members and cursors' graphic data +static SCNHANDLE configStrings[20]; + +static PINV_OBJECT pio = 0; // Inventory objects' data +static int numObjects = 0; // Number of inventory objects + + +//----- Permanent data (updated, valid while inventory closed) ----- + +static enum {NO_INV, IDLE_INV, ACTIVE_INV, BOGUS_INV} InventoryState; + +static int HeldItem = INV_NOICON; // Current held item + +struct INV_DEF { + + int MinHicons; // } + int MinVicons; // } Dimension limits + int MaxHicons; // } + int MaxVicons; // } + + int NoofHicons; // } + int NoofVicons; // } Current dimentsions + + int ItemOrder[MAX_ININV]; // Contained items + int NoofItems; // Current number of held items + + int FirstDisp; // Index to first item currently displayed + + int inventoryX; // } Display position + int inventoryY; // } + int otherX; // } Display position + int otherY; // } + + int MaxInvObj; // Max. allowed contents + + SCNHANDLE hInvTitle; // Window heading + + bool resizable; // Re-sizable window? + bool moveable; // Moveable window? + + int sNoofHicons; // } + int sNoofVicons; // } Current dimensions + + bool bMax; // Maximised last time open? + +}; +typedef INV_DEF *PINV_DEF; + +static INV_DEF InvD[NUM_INV]; // Conversation + 2 inventories + ... + + +// Permanent contents of conversation inventory +static int Inv0Order[MAX_CONVBASIC]; // Basic items i.e. permanent contents +static int Num0Order = 0; // - copy to conv. inventory at pop-up time + + + +//----- Data pertinant to current active inventory ----- + +static int ino = 0; // Which inventory is currently active + +static bool InventoryHidden = false; +static bool InventoryMaximised = false; + +static enum { ID_NONE, ID_MOVE, ID_SLIDE, + ID_BOTTOM, ID_TOP, ID_LEFT, ID_RIGHT, + ID_TLEFT, ID_TRIGHT, ID_BLEFT, ID_BRIGHT, + ID_CSLIDE, ID_MDCONT } InvDragging; + +static int SuppH = 0; // 'Linear' element of +static int SuppV = 0; // dimensions during re-sizing + +static int Ychange = 0; // +static int Ycompensate = 0; // All to do with re-sizing. +static int Xchange = 0; // +static int Xcompensate = 0; // + +static bool ItemsChanged = 0; // When set, causes items to be re-drawn + +static bool bOpenConf = 0; + +static int TL = 0, TR = 0, BL = 0, BR = 0; // Used during window construction +static int TLwidth = 0, TLheight = 0; // +static int TRwidth = 0; // +static int BLheight = 0; // + + + +static OBJECT *objArray[MAX_WCOMP]; // Current display objects (window) +static OBJECT *iconArray[MAX_ICONS]; // Current display objects (icons) +static ANIM iconAnims[MAX_ICONS]; +static OBJECT *DobjArray[MAX_WCOMP]; // Current display objects (re-sizing window) + +static OBJECT *RectObject = 0, *SlideObject = 0; // Current display objects, for reference + // objects are in objArray. + +static int slideY = 0; // For positioning the slider +static int slideYmax = 0, slideYmin = 0; // + +// Also to do with the slider +static struct { int n; int y; } slideStuff[MAX_ININV+1]; + +#define MAXSLIDES 4 +struct MDSLIDES { + int num; + OBJECT *obj; + int min, max; +}; +static MDSLIDES mdSlides[MAXSLIDES]; +static int numMdSlides = 0; + +static int GlitterIndex = 0; + +static HPOLYGON thisConvPoly = 0; // Conversation code is in a polygon code block +static int thisConvIcon = 0; // Passed to polygon code via convIcon() +static int pointedIcon = INV_NOICON; // used by InvLabels - icon pointed to on last call +static volatile int PointedWaitCount = 0; // used by InvTinselProcess - fix the 'repeated pressing bug' +static int sX = 0; // used by SlideMSlider() - current x-coordinate +static int lX = 0; // used by SlideMSlider() - last x-coordinate + +//----- Data pertinant to configure (incl. load/save game) ----- + +#define COL_MAINBOX TBLUE1 // Base blue colour +#define COL_BOX TBLUE1 +#define COL_HILIGHT TBLUE4 + +#ifdef JAPAN +#define BOX_HEIGHT 17 +#define EDIT_BOX1_WIDTH 149 +#else +#define BOX_HEIGHT 13 +#define EDIT_BOX1_WIDTH 145 +#endif +#define EDIT_BOX2_WIDTH 166 + +// RGROUP Radio button group - 1 is selectable at a time. Action on double click +// ARSBUT Action if a radio button is selected +// AABUT Action always +// AATBUT Action always, text box +// AAGBUT Action always, graphic button +// SLIDER Not a button at all +typedef enum {RGROUP, ARSBUT, AABUT, AATBUT, ARSGBUT, AAGBUT, SLIDER, + TOGGLE, DCTEST, FLIP, FRGROUP, NOTHING} BTYPE; + +typedef enum {NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN, + OPENLOAD, OPENSAVE, OPENREST, + OPENSOUND, OPENCONT, +#ifndef JAPAN + OPENSUBT, +#endif + OPENQUIT, + INITGAME, MIDIVOL, + CLANG, RLANG +#ifdef MAC_OPTIONS + , MASTERVOL, SAMPVOL +#endif + } BFUNC; + +typedef struct { + BTYPE boxType; + BFUNC boxFunc; + char *boxText; + int ixText; + int xpos; + int ypos; + int w; // Doubles as max value for SLIDERs + int h; // Doubles as iteration size for SLIDERs + int *ival; + int bi; // Base index for AAGBUTs +} CONFBOX, *PCONFBOX; + + +#define NO_HEADING (-1) +#define USE_POINTER (-1) +#define SIX_LOAD_OPTION 0 +#define SIX_SAVE_OPTION 1 +#define SIX_RESTART_OPTION 2 +#define SIX_SOUND_OPTION 3 +#define SIX_CONTROL_OPTION 4 +#ifndef JAPAN +#define SIX_SUBTITLES_OPTION 5 +#endif +#define SIX_QUIT_OPTION 6 +#define SIX_RESUME_OPTION 7 +#define SIX_LOAD_HEADING 8 +#define SIX_SAVE_HEADING 9 +#define SIX_RESTART_HEADING 10 +#define SIX_MVOL_SLIDER 11 +#define SIX_SVOL_SLIDER 12 +#define SIX_VVOL_SLIDER 13 +#define SIX_DCLICK_SLIDER 14 +#define SIX_DCLICK_TEST 15 +#define SIX_SWAP_TOGGLE 16 +#define SIX_TSPEED_SLIDER 17 +#define SIX_STITLE_TOGGLE 18 +#define SIX_QUIT_HEADING 19 + + +/*-------------------------------------------------------------*\ +| This is the main menu (that comes up when you hit F1 on a PC) | +\*-------------------------------------------------------------*/ + +#ifdef JAPAN +#define FBY 11 // y-offset of first button +#define FBX 13 // x-offset of first button +#else +#define FBY 20 // y-offset of first button +#define FBX 15 // x-offset of first button +#endif + +CONFBOX optionBox[] = { + + { AATBUT, OPENLOAD, NULL, SIX_LOAD_OPTION, FBX, FBY, EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, OPENSAVE, NULL, SIX_SAVE_OPTION, FBX, FBY + (BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, OPENREST, NULL, SIX_RESTART_OPTION, FBX, FBY + 2*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, OPENSOUND, NULL, SIX_SOUND_OPTION, FBX, FBY + 3*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, OPENCONT, NULL, SIX_CONTROL_OPTION, FBX, FBY + 4*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, +#ifdef JAPAN +// TODO: If in JAPAN mode, simply disable the subtitles button? + { AATBUT, OPENQUIT, NULL, SIX_QUIT_OPTION, FBX, FBY + 5*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, CLOSEWIN, NULL, SIX_RESUME_OPTION, FBX, FBY + 6*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 } +#else + { AATBUT, OPENSUBT, NULL, SIX_SUBTITLES_OPTION,FBX, FBY + 5*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, OPENQUIT, NULL, SIX_QUIT_OPTION, FBX, FBY + 6*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 }, + { AATBUT, CLOSEWIN, NULL, SIX_RESUME_OPTION, FBX, FBY + 7*(BOX_HEIGHT + 2), EDIT_BOX1_WIDTH, BOX_HEIGHT, NULL, 0 } +#endif + +}; + +/*-------------------------------------------------------------*\ +| These are the load and save game menus. | +\*-------------------------------------------------------------*/ + +#ifdef JAPAN +#define NUM_SL_RGROUP 7 // number of visible slots +#define SY 32 // y-position of first slot +#else +#define NUM_SL_RGROUP 9 // number of visible slots +#define SY 31 // y-position of first slot +#endif + +CONFBOX loadBox[NUM_SL_RGROUP+2] = { + + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY, EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + (BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 2*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 3*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 4*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 5*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 6*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, +#ifndef JAPAN + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 7*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, LOADGAME, NULL, USE_POINTER, 28, SY + 8*(BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, +#endif + { ARSGBUT, LOADGAME, NULL, USE_POINTER, 230, 44, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 230, 44+47, 23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX saveBox[NUM_SL_RGROUP+2] = { + + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY, EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + (BOX_HEIGHT + 2), EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 2*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 3*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 4*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 5*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 6*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, +#ifndef JAPAN + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 7*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, + { RGROUP, SAVEGAME, NULL, USE_POINTER, 28, SY + 8*(BOX_HEIGHT + 2),EDIT_BOX2_WIDTH, BOX_HEIGHT, NULL, 0 }, +#endif + { ARSGBUT, SAVEGAME, NULL,USE_POINTER, 230, 44, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 230, 44+47, 23, 19, NULL, IX_CROSS1 } + +}; + + +/*-------------------------------------------------------------*\ +| This is the restart confirmation 'menu'. | +\*-------------------------------------------------------------*/ + +CONFBOX restartBox[] = { + +#ifdef JAPAN + { AAGBUT, INITGAME, NULL, USE_POINTER, 96, 44, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 56, 44, 23, 19, NULL, IX_CROSS1 } +#else + { AAGBUT, INITGAME, NULL, USE_POINTER, 70, 28, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 30, 28, 23, 19, NULL, IX_CROSS1 } +#endif + +}; + + +/*-------------------------------------------------------------*\ +| This is the sound control 'menu'. | +\*-------------------------------------------------------------*/ + +#ifdef MAC_OPTIONS + CONFBOX soundBox[] = { + { SLIDER, MASTERVOL, NULL, SIX_MVOL_SLIDER, 142, 20, 100, 2, &volMaster, 0 }, + { SLIDER, MIDIVOL, NULL, SIX_MVOL_SLIDER, 142, 20+40, 100, 2, &volMidi, 0 }, + { SLIDER, SAMPVOL, NULL, SIX_SVOL_SLIDER, 142, 20+2*40, 100, 2, &volSound, 0 }, + { SLIDER, SAMPVOL, NULL, SIX_VVOL_SLIDER, 142, 20+3*40, 100, 2, &volVoice, 0 } + }; +#else +CONFBOX soundBox[] = { + { SLIDER, MIDIVOL, NULL, SIX_MVOL_SLIDER, 142, 25, MAXMIDIVOL, 2, &volMidi, 0 }, + { SLIDER, NOFUNC, NULL, SIX_SVOL_SLIDER, 142, 25+40, MAXSAMPVOL, 2, &volSound, 0 }, + { SLIDER, NOFUNC, NULL, SIX_VVOL_SLIDER, 142, 25+2*40, MAXSAMPVOL, 2, &volVoice, 0 } +}; +#endif + + +/*-------------------------------------------------------------*\ +| This is the (mouse) control 'menu'. | +\*-------------------------------------------------------------*/ + +int bFlipped; // looks like this is just so the code has something to alter! + + +#ifdef MAC_OPTIONS +CONFBOX controlBox[] = { + + { SLIDER, NOFUNC, NULL, SIX_DCLICK_SLIDER, 142, 25, 3*DOUBLE_CLICK_TIME, 1, &dclickSpeed, 0 }, + { FLIP, NOFUNC, NULL, SIX_DCLICK_TEST, 142, 25+30, 23, 19, &bFlipped, IX_CIRCLE1 } + +}; +#else +CONFBOX controlBox[] = { + + { SLIDER, NOFUNC, NULL, SIX_DCLICK_SLIDER, 142, 25, 3*DOUBLE_CLICK_TIME, 1, &dclickSpeed, 0 }, + { FLIP, NOFUNC, NULL, SIX_DCLICK_TEST, 142, 25+30, 23, 19, &bFlipped, IX_CIRCLE1 }, +#ifdef JAPAN + { TOGGLE, NOFUNC, NULL, SIX_SWAP_TOGGLE, 205, 25+70, 23, 19, &bSwapButtons, 0 } +#else + { TOGGLE, NOFUNC, NULL, SIX_SWAP_TOGGLE, 155, 25+70, 23, 19, &bSwapButtons, 0 } +#endif + +}; +#endif + + +/*-------------------------------------------------------------*\ +| This is the subtitles 'menu'. | +\*-------------------------------------------------------------*/ + +#ifndef JAPAN +CONFBOX subtitlesBox[] = { + +#ifdef USE_5FLAGS + { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 100, 56, 32, NULL, FIX_UK }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 100, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 100, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 50, 137, 56, 32, NULL, FIX_IT }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 120, 137, 56, 32, NULL, FIX_SP }, +#endif +#ifdef USE_4FLAGS + { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP }, +#endif +#ifdef USE_3FLAGS + { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP }, +#endif + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + +#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) + { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } +#endif + +}; +#endif + + +/*-------------------------------------------------------------*\ +| This is the quit confirmation 'menu'. | +\*-------------------------------------------------------------*/ + +CONFBOX quitBox[] = { +#ifdef JAPAN + { AAGBUT, IQUITGAME, NULL, USE_POINTER,70, 44, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 30, 44, 23, 19, NULL, IX_CROSS1 } +#else + { AAGBUT, IQUITGAME, NULL, USE_POINTER,70, 28, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 30, 28, 23, 19, NULL, IX_CROSS1 } +#endif +}; + + +CONFBOX topwinBox[] = { + { NOTHING, NOFUNC, NULL, USE_POINTER, 0, 0, 0, 0, NULL, 0 } +}; + + + +typedef struct { + int h; + int v; + int x; + int y; + bool bExtraWin; + PCONFBOX Box; + int NumBoxes; + int ixHeading; +} CONFINIT, *PCONFINIT; + +CONFINIT ciOption = { 6, 5, 72, 23, false, optionBox, sizeof(optionBox)/sizeof(CONFBOX), NO_HEADING }; + +CONFINIT ciLoad = { 10, 6, 20, 16, true, loadBox, sizeof(loadBox)/sizeof(CONFBOX), SIX_LOAD_HEADING }; +CONFINIT ciSave = { 10, 6, 20, 16, true, saveBox, sizeof(saveBox)/sizeof(CONFBOX), SIX_SAVE_HEADING }; +#ifdef JAPAN +CONFINIT ciRestart = { 6, 2, 72, 53, false, restartBox, sizeof(restartBox)/sizeof(CONFBOX), SIX_RESTART_HEADING }; +#else +CONFINIT ciRestart = { 4, 2, 98, 53, false, restartBox, sizeof(restartBox)/sizeof(CONFBOX), SIX_RESTART_HEADING }; +#endif +CONFINIT ciSound = { 10, 5, 20, 16, false, soundBox, sizeof(soundBox)/sizeof(CONFBOX), NO_HEADING }; +#ifdef MAC_OPTIONS + CONFINIT ciControl = { 10, 3, 20, 40, false, controlBox, sizeof(controlBox)/sizeof(CONFBOX), NO_HEADING }; +#else + CONFINIT ciControl = { 10, 5, 20, 16, false, controlBox, sizeof(controlBox)/sizeof(CONFBOX), NO_HEADING }; +#endif +#ifndef JAPAN +#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) +CONFINIT ciSubtitles = { 10, 6, 20, 16, false, subtitlesBox, sizeof(subtitlesBox)/sizeof(CONFBOX), NO_HEADING }; +#else +CONFINIT ciSubtitles = { 10, 3, 20, 16, false, subtitlesBox, sizeof(subtitlesBox)/sizeof(CONFBOX), NO_HEADING }; +#endif +#endif +CONFINIT ciQuit = { 4, 2, 98, 53, false, quitBox, sizeof(quitBox)/sizeof(CONFBOX), SIX_QUIT_HEADING }; + +CONFINIT ciTopWin = { 6, 5, 72, 23, false, topwinBox, 0, NO_HEADING }; + +#define NOBOX (-1) + +// Conf window globals +static struct { + PCONFBOX Box; + int NumBoxes; + bool bExtraWin; + int ixHeading; + bool editableRgroup; + + int selBox; + int pointBox; // Box pointed to on last call + int saveModifier; + int fileBase; + int numSaved; +} cd = { + NULL, 0, false, 0, false, + NOBOX, NOBOX, 0, 0, 0 +}; + +// For editing save game names +char sedit[SG_DESC_LEN+2]; + +#define HL1 0 // Hilight that moves with the cursor +#define HL2 1 // Hilight on selected RGROUP box +#define HL3 2 // Text on selected RGROUP box +#define NUMHL 3 + + +// Data for button press/toggle effects +static struct { + bool bButAnim; + PCONFBOX box; + bool press; // true = button press; false = button toggle +} g_buttonEffect = { false, 0, false }; + + +//----- LOCAL FORWARD REFERENCES ----- + +enum { + IB_NONE = -1, // + IB_UP = -2, // negative numbers returned + IB_DOWN = -3, // by WhichInvBox() + IB_SLIDE = -4, // + IB_SLIDE_UP = -5, // + IB_SLIDE_DOWN = -6 // +}; + +enum { + HI_BIT = ((uint)MIN_INT >> 1), // The next to top bit + IS_LEFT = HI_BIT, + IS_SLIDER = (IS_LEFT >> 1), + IS_RIGHT = (IS_SLIDER >> 1), + IS_MASK = (IS_LEFT | IS_SLIDER | IS_RIGHT) +}; + +static int WhichInvBox(int curX, int curY, bool bSlides); +static void SlideMSlider(int x, SSFN fn); +static OBJECT *AddObject(const FREEL *pfreel, int num); +static void AddBoxes(bool posnSlide); + +static void ConfActionSpecial(int i); + + +/*-------------------------------------------------------------------------*/ +/*** Magic numbers ***/ + +#define M_SW 5 // Side width +#define M_TH 5 // Top height +#ifdef JAPAN +#define M_TOFF 6 // Title text Y offset from top +#define M_TBB 20 // Title box bottom Y offset +#else +#define M_TOFF 4 // Title text Y offset from top +#define M_TBB 14 // Title box bottom Y offset +#endif +#define M_SBL 26 // Scroll bar left X offset +#define M_SH 5 // Slider height (*) +#define M_SW 5 // Slider width (*) +#define M_SXOFF 9 // Slider X offset from right-hand side +#ifdef JAPAN +#define M_IUT 22 // Y offset of top of up arrow +#define M_IUB 30 // Y offset of bottom of up arrow +#else +#define M_IUT 16 // Y offset of top of up arrow +#define M_IUB 24 // Y offset of bottom of up arrow +#endif +#define M_IDT 10 // Y offset (from bottom) of top of down arrow +#define M_IDB 3 // Y offset (from bottom) of bottom of down arrow +#define M_IAL 12 // X offset (from right) of left of scroll arrows +#define M_IAR 3 // X offset (from right) of right of scroll arrows + +#define START_ICONX (M_SW+1) // } Relative offset of first icon +#define START_ICONY (M_TBB+M_TH+1) // } within the inventory window + +/*-------------------------------------------------------------------------*/ + + + +#ifndef JAPAN +bool LanguageChange(void) { + LANGUAGE nLang; + +#ifdef USE_3FLAGS + // VERY quick dodgy bodge + if (cd.selBox == 0) + nLang = TXT_FRENCH; + else if (cd.selBox == 1) + nLang = TXT_GERMAN; + else + nLang = TXT_SPANISH; + if (nLang != language) { +#elif defined(USE_4FLAGS) + nLang = (LANGUAGE)(cd.selBox + 1); + if (nLang != language) { +#else + if (cd.selBox != language) { + nLang = (LANGUAGE)cd.selBox; +#endif + KillInventory(); + ChangeLanguage(nLang); + language = nLang; + return true; + } + else + return false; +} +#endif + +/**************************************************************************/ +/******************** Some miscellaneous functions ************************/ +/**************************************************************************/ + +/*---------------------------------------------------------------------*\ +| DumpIconArray()/DumpDobjArray()/DumpObjArray() | +|-----------------------------------------------------------------------| +| Delete all the objects in iconArray[]/DobjArray[]/objArray[] | +\*---------------------------------------------------------------------*/ +static void DumpIconArray(void){ + for (int i = 0; i < MAX_ICONS; i++) { + if (iconArray[i] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[i]); + iconArray[i] = NULL; + } + } +} + +/** + * Delete all the objects in DobjArray[] + */ + +static void DumpDobjArray(void) { + for (int i = 0; i < MAX_WCOMP; i++) { + if (DobjArray[i] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), DobjArray[i]); + DobjArray[i] = NULL; + } + } +} + +/** + * Delete all the objects in objArray[] + */ + +static void DumpObjArray(void) { + for (int i = 0; i < MAX_WCOMP; i++) { + if (objArray[i] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), objArray[i]); + objArray[i] = NULL; + } + } +} + +/** + * Convert item ID number to pointer to item's compiled data + * i.e. Image data and Glitter code. + */ +PINV_OBJECT findInvObject(int num) { + PINV_OBJECT retval = pio; + + for (int i = 0; i < numObjects; i++, retval++) { + if (retval->id == num) + return retval; + } + + error("Trying to manipulate undefined inventory icon"); +} + +/** + * Returns position of an item in one of the inventories. + * The actual position is not important for the uses that this is put to. + */ + +int InventoryPos(int num) { + int i; + + for (i = 0; i < InvD[INV_1].NoofItems; i++) // First inventory + if (InvD[INV_1].ItemOrder[i] == num) + return i; + + for (i = 0; i < InvD[INV_2].NoofItems; i++) // Second inventory + if (InvD[INV_2].ItemOrder[i] == num) + return i; + + if (HeldItem == num) + return INV_HELDNOTIN; // Held, but not in either inventory + + return INV_NOICON; // Not held, not in either inventory +} + +bool IsInInventory(int object, int invnum) { + assert(invnum == INV_1 || invnum == INV_2); + + for (int i = 0; i < InvD[invnum].NoofItems; i++) // First inventory + if (InvD[invnum].ItemOrder[i] == object) + return true; + + return false; +} + +/** + * Returns which item is held (INV_NOICON (-1) if none) + */ + +int WhichItemHeld(void) { + return HeldItem; +} + +/** + * Called from the cursor module when it re-initialises (at the start of + * a new scene). For if we are holding something at scene-change time. + */ + +void InventoryIconCursor(void) { + PINV_OBJECT invObj; + + if (HeldItem != INV_NOICON) { + invObj = findInvObject(HeldItem); + SetAuxCursor(invObj->hFilm); + } +} + +/** + * Returns TRUE if the inventory is active. + */ + +bool InventoryActive(void) { + return (InventoryState == ACTIVE_INV); +} + +int WhichInventoryOpen(void) { + if (InventoryState != ACTIVE_INV) + return 0; + else + return ino; +} + + +/**************************************************************************/ +/************** Running inventory item's Glitter code *********************/ +/**************************************************************************/ + +struct ITP_INIT { + PINV_OBJECT pinvo; + USER_EVENT event; + BUTEVENT bev; +}; + +/** + * Run inventory item's Glitter code + */ +static void InvTinselProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + int ThisPointedWait; // Fix the 'repeated pressing bug' + CORO_END_CONTEXT(_ctx); + + // get the stuff copied to process when it was created + ITP_INIT *to = (ITP_INIT *)ProcessGetParamsSelf(); + + CORO_BEGIN_CODE(_ctx); + + CORO_INVOKE_1(AllowDclick, to->bev); + + _ctx->pic = InitInterpretContext(GS_INVENTORY, to->pinvo->hScript, to->event, NOPOLY, 0, to->pinvo); + CORO_INVOKE_1(Interpret, _ctx->pic); + + if (to->event == POINTED) { + _ctx->ThisPointedWait = ++PointedWaitCount; + while (1) { + CORO_SLEEP(1); + int x, y; + GetCursorXY(&x, &y, false); + if (InvItemId(x, y) != to->pinvo->id) + break; + + // Fix the 'repeated pressing bug' + if (_ctx->ThisPointedWait != PointedWaitCount) + CORO_KILL_SELF(); + } + + _ctx->pic = InitInterpretContext(GS_INVENTORY, to->pinvo->hScript, UNPOINT, NOPOLY, 0, to->pinvo); + CORO_INVOKE_1(Interpret, _ctx->pic); + } + + CORO_END_CODE; +} + +/** + * Run inventory item's Glitter code + */ +void RunInvTinselCode(PINV_OBJECT pinvo, USER_EVENT event, BUTEVENT be, int index) { + ITP_INIT to = { pinvo, event, be }; + + if (InventoryHidden) + return; + + GlitterIndex = index; + CoroutineInstall(PID_TCODE, InvTinselProcess, &to, sizeof(to)); +} + +/**************************************************************************/ +/****************** Load/Save game specific functions *********************/ +/**************************************************************************/ + +/** + * Set first load/save file entry displayed. + * Point Box[] text pointers to appropriate file descriptions. + */ + +void firstFile(int first) { + int i, j; + + i = getList(); + + cd.numSaved = i; + + if (first < 0) + first = 0; + else if (first > MAX_SFILES-NUM_SL_RGROUP) + first = MAX_SFILES-NUM_SL_RGROUP; + + if (first == 0 && i < MAX_SFILES && cd.Box == saveBox) { + // Blank first entry for new save + cd.Box[0].boxText = NULL; + cd.saveModifier = j = 1; + } else { + cd.saveModifier = j = 0; + } + + for (i = first; j < NUM_SL_RGROUP; j++, i++) { + cd.Box[j].boxText = ListEntry(i, LE_DESC); + } + + cd.fileBase = first; +} + +/** + * Save the game using filename from selected slot & current description. + */ + +void InvSaveGame(void) { + if (cd.selBox != NOBOX) { +#ifndef JAPAN + sedit[strlen(sedit)-1] = 0; // Don't include the cursor! +#endif + SaveGame(ListEntry(cd.selBox-cd.saveModifier+cd.fileBase, LE_NAME), sedit); + } +} + +/** + * Load the selected saved game. + */ +void InvLoadGame(void) { + int rGame; + + if (cd.selBox != NOBOX && (cd.selBox+cd.fileBase < cd.numSaved)) { + rGame = cd.selBox; + cd.selBox = NOBOX; + if (iconArray[HL3] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL3]); + iconArray[HL3] = NULL; + } + if (iconArray[HL2] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]); + iconArray[HL2] = NULL; + } + if (iconArray[HL1] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = NULL; + } + RestoreGame(rGame+cd.fileBase); + } +} + +/** + * Edit the string in sedit[] + * Returns TRUE if the string was altered. + */ +#ifndef JAPAN +bool UpdateString(const Common::KeyState &kbd) { + int cpos; + + if (!cd.editableRgroup) + return false; + + cpos = strlen(sedit)-1; + + if (kbd.keycode == Common::KEYCODE_BACKSPACE) { + if (!cpos) + return false; + sedit[cpos] = 0; + cpos--; + sedit[cpos] = CURSOR_CHAR; + return true; +// } else if (isalnum(c) || c == ',' || c == '.' || c == '\'' || (c == ' ' && cpos != 0)) { + } else if (IsCharImage(hTagFontHandle(), kbd.ascii) || (kbd.ascii == ' ' && cpos != 0)) { + if (cpos == SG_DESC_LEN) + return false; + sedit[cpos] = kbd.ascii; + cpos++; + sedit[cpos] = CURSOR_CHAR; + sedit[cpos+1] = 0; + return true; + } + return false; +} +#endif + +/** + * Keystrokes get sent here when load/save screen is up. + */ +bool InvKeyIn(const Common::KeyState &kbd) { + if (kbd.keycode == Common::KEYCODE_PAGEUP || + kbd.keycode == Common::KEYCODE_PAGEDOWN || + kbd.keycode == Common::KEYCODE_HOME || + kbd.keycode == Common::KEYCODE_END) + return true; // Key needs processing + + if (kbd.keycode == 0 && kbd.ascii == 0) { + ; + } else if (kbd.keycode == Common::KEYCODE_RETURN) { + return true; // Key needs processing + } else if (kbd.keycode == Common::KEYCODE_ESCAPE) { + return true; // Key needs processing + } else { +#ifndef JAPAN + if (UpdateString(kbd)) { + /* + * Delete display of text currently being edited, + * and replace it with freshly edited text. + */ + if (iconArray[HL3] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL3]); + iconArray[HL3] = NULL; + } + iconArray[HL3] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), sedit, 0, + InvD[ino].inventoryX + cd.Box[cd.selBox].xpos + 2, + InvD[ino].inventoryY + cd.Box[cd.selBox].ypos, + hTagFontHandle(), 0); + if (MultiRightmost(iconArray[HL3]) > 213) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL3]); + UpdateString(Common::KeyState(Common::KEYCODE_BACKSPACE)); + iconArray[HL3] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), sedit, 0, + InvD[ino].inventoryX + cd.Box[cd.selBox].xpos + 2, + InvD[ino].inventoryY + cd.Box[cd.selBox].ypos, + hTagFontHandle(), 0); + } + MultiSetZPosition(iconArray[HL3], Z_INV_ITEXT + 2); + } +#endif + } + return false; +} + +/*---------------------------------------------------------------------*\ +| Select() | +|-----------------------------------------------------------------------| +| Highlights selected box. | +| If it's editable (save game), copy existing description and add a | +| cursor. | +\*---------------------------------------------------------------------*/ +void Select(int i, bool force) { +#ifdef JAPAN + time_t secs_now; + struct tm *time_now; +#endif + + i &= ~IS_MASK; + + if (cd.selBox == i && !force) + return; + + cd.selBox = i; + + // Clear previous selected highlight and text + if (iconArray[HL2] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]); + iconArray[HL2] = NULL; + } + if (iconArray[HL3] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL3]); + iconArray[HL3] = NULL; + } + + // New highlight box + switch (cd.Box[i].boxType) { + case RGROUP: + iconArray[HL2] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[i].w, cd.Box[i].h); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]); + MultiSetAniXY(iconArray[HL2], + InvD[ino].inventoryX + cd.Box[i].xpos, + InvD[ino].inventoryY + cd.Box[i].ypos); + + // Z-position of box, and add edit text if appropriate + if (cd.editableRgroup) { + MultiSetZPosition(iconArray[HL2], Z_INV_ITEXT+1); + + assert(cd.Box[i].ixText == USE_POINTER); +#ifdef JAPAN + // Current date and time + time(&secs_now); + time_now = localtime(&secs_now); + strftime(sedit, SG_DESC_LEN, "%D %H:%M", time_now); +#else + // Current description with cursor appended + if (cd.Box[i].boxText != NULL) { + strcpy(sedit, cd.Box[i].boxText); + strcat(sedit, sCursor); + } else { + strcpy(sedit, sCursor); + } +#endif + iconArray[HL3] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), sedit, 0, + InvD[ino].inventoryX + cd.Box[i].xpos + 2, +#ifdef JAPAN + InvD[ino].inventoryY + cd.Box[i].ypos + 2, +#else + InvD[ino].inventoryY + cd.Box[i].ypos, +#endif + hTagFontHandle(), 0); + MultiSetZPosition(iconArray[HL3], Z_INV_ITEXT + 2); + } else { + MultiSetZPosition(iconArray[HL2], Z_INV_ICONS + 1); + } + + _vm->divertKeyInput(InvKeyIn); + + break; + +#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) + case FRGROUP: + iconArray[HL2] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[i].w+6, cd.Box[i].h+6); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]); + MultiSetAniXY(iconArray[HL2], + InvD[ino].inventoryX + cd.Box[i].xpos - 2, + InvD[ino].inventoryY + cd.Box[i].ypos - 2); + MultiSetZPosition(iconArray[HL2], Z_INV_BRECT+1); + + break; +#endif + default: + break; + } +} + + +/**************************************************************************/ +/***/ +/**************************************************************************/ + +/** + * If the item is not already held, hold it. + */ + +void HoldItem(int item) { + PINV_OBJECT invObj; + + if (HeldItem != item) { + if (item == INV_NOICON && HeldItem != INV_NOICON) + DelAuxCursor(); // no longer aux cursor + + if (item != INV_NOICON) { + invObj = findInvObject(item); + SetAuxCursor(invObj->hFilm); // and is aux. cursor + } + + HeldItem = item; // Item held + } + + // Redraw contents - held item not displayed as a content. + ItemsChanged = true; +} + +/** + * Stop holding an item. + */ + +void DropItem(int item) { + if (HeldItem == item) { + HeldItem = INV_NOICON; // Item not held + DelAuxCursor(); // no longer aux cursor + } + + // Redraw contents - held item was not displayed as a content. + ItemsChanged = true; +} + +/** + * Stick the item into an inventory list (ItemOrder[]), and hold the + * item if requested. + */ + +void AddToInventory(int invno, int icon, bool hold) { + int i; + bool bOpen; +#ifdef DEBUG + PINV_OBJECT invObj; +#endif + + assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_OPEN)); // Trying to add to illegal inventory + + if (invno == INV_OPEN) { + assert(InventoryState == ACTIVE_INV && (ino == INV_1 || ino == INV_2)); // addopeninv() with inventry not open + invno = ino; + bOpen = true; + + // Make sure it doesn't get in both! + RemFromInventory(ino == INV_1 ? INV_2 : INV_1, icon); + } else + bOpen = false; + +#ifdef DEBUG + invObj = findInvObject(icon); + if ((invObj->attribute & IO_ONLYINV1 && invno != INV_1) + || (invObj->attribute & IO_ONLYINV2 && invno != INV_2)) + error("Trying to add resticted object to wrong inventory"); +#endif + + if (invno == INV_1) + RemFromInventory(INV_2, icon); + else if (invno == INV_2) + RemFromInventory(INV_1, icon); + + // See if it's already there + for (i = 0; i < InvD[invno].NoofItems; i++) { + if (InvD[invno].ItemOrder[i] == icon) + break; + } + + // Add it if it isn't already there + if (i == InvD[invno].NoofItems) { + if (!bOpen) { + if (invno == INV_CONV) { + // For conversation, insert before last icon + // which will always be the goodbye icon + InvD[invno].ItemOrder[InvD[invno].NoofItems] = InvD[invno].ItemOrder[InvD[invno].NoofItems-1]; + InvD[invno].ItemOrder[InvD[invno].NoofItems-1] = icon; + InvD[invno].NoofItems++; + } else { + InvD[invno].ItemOrder[InvD[invno].NoofItems++] = icon; + } + ItemsChanged = true; + } else { + // It could be that the index is beyond what you'd expect + // as delinv may well have been called + if (GlitterIndex < InvD[invno].NoofItems) { + memmove(&InvD[invno].ItemOrder[GlitterIndex + 1], + &InvD[invno].ItemOrder[GlitterIndex], + (InvD[invno].NoofItems-GlitterIndex)*sizeof(int)); + InvD[invno].ItemOrder[GlitterIndex] = icon; + } else { + InvD[invno].ItemOrder[InvD[invno].NoofItems] = icon; + } + InvD[invno].NoofItems++; + } + } + + // Hold it if requested + if (hold) + HoldItem(icon); +} + +/** + * Take the item from the inventory list (ItemOrder[]). + * Return FALSE if item wasn't present, true if it was. + */ + +bool RemFromInventory(int invno, int icon) { + int i; + + assert(invno == INV_1 || invno == INV_2 || invno == INV_CONV); // Trying to delete from illegal inventory + + // See if it's there + for (i = 0; i < InvD[invno].NoofItems; i++) { + if (InvD[invno].ItemOrder[i] == icon) + break; + } + + if (i == InvD[invno].NoofItems) + return false; // Item wasn't there + else { + memmove(&InvD[invno].ItemOrder[i], &InvD[invno].ItemOrder[i+1], (InvD[invno].NoofItems-i)*sizeof(int)); + InvD[invno].NoofItems--; + ItemsChanged = true; + return true; // Item removed + } +} + + +/**************************************************************************/ +/***/ +/**************************************************************************/ + +/*---------------------------------------------------------------------*\ +| InvArea() | +|-----------------------------------------------------------------------| +| Work out which area of the inventory window the cursor is in. | +|-----------------------------------------------------------------------| +| This used to be worked out with appropriately defined magic numbers. | +| Then the graphic changed and I got it right again. Then the graphic | +| changed and I got fed up of faffing about. It's probably easier just | +| to rework all this. | +\*---------------------------------------------------------------------*/ +enum { I_NOTIN, I_MOVE, I_BODY, + I_TLEFT, I_TRIGHT, I_BLEFT, I_BRIGHT, + I_TOP, I_BOTTOM, I_LEFT, I_RIGHT, + I_UP, I_SLIDE_UP, I_SLIDE, I_SLIDE_DOWN, I_DOWN, + I_ENDCHANGE +}; + +#define EXTRA 1 // This was introduced when we decided to increase + // the active area of the borders for re-sizing. + +/*---------------------------------*/ +#define LeftX InvD[ino].inventoryX +#define TopY InvD[ino].inventoryY +/*---------------------------------*/ + +int InvArea(int x, int y) { + int RightX = MultiRightmost(RectObject) + 1; + int BottomY = MultiLowest(RectObject) + 1; + +// Outside the whole rectangle? + if (x <= LeftX - EXTRA || x > RightX + EXTRA + || y <= TopY - EXTRA || y > BottomY + EXTRA) + return I_NOTIN; + +// The bottom line + if (y > BottomY - 2 - EXTRA) { // Below top of bottom line? + if (x <= LeftX + 2 + EXTRA) + return I_BLEFT; // Bottom left corner + else if (x > RightX - 2 - EXTRA) + return I_BRIGHT; // Bottom right corner + else + return I_BOTTOM; // Just plain bottom + } + +// The top line + if (y <= TopY + 2 + EXTRA) { // Above bottom of top line? + if (x <= LeftX + 2 + EXTRA) + return I_TLEFT; // Top left corner + else if (x > RightX - 2 - EXTRA) + return I_TRIGHT; // Top right corner + else + return I_TOP; // Just plain top + } + +// Sides + if (x <= LeftX + 2 + EXTRA) // Left of right of left side? + return I_LEFT; + else if (x > RightX - 2 - EXTRA) // Right of left of right side? + return I_RIGHT; + +// From here down still needs fixing up properly +/* +* In the move area? +*/ + if (ino != INV_CONF + && x >= LeftX + M_SW - 2 && x <= RightX - M_SW + 3 && + y >= TopY + M_TH - 2 && y < TopY + M_TBB + 2) + return I_MOVE; + +/* +* Scroll bits +*/ + if (ino == INV_CONF && cd.bExtraWin) { + } else { + if (x > RightX - M_IAL + 3 && x <= RightX - M_IAR + 1) { + if (y > TopY + M_IUT + 1 && y < TopY + M_IUB - 1) + return I_UP; + if (y > BottomY - M_IDT + 4 && y <= BottomY - M_IDB + 1) + return I_DOWN; + + if (y >= TopY + slideYmin && y < TopY + slideYmax + M_SH) { + if (y < TopY + slideY) + return I_SLIDE_UP; + if (y < TopY + slideY + M_SH) + return I_SLIDE; + else + return I_SLIDE_DOWN; + } + } + } + + return I_BODY; +} + +/** + * Returns the id of the icon displayed under the given position. + * Also return co-ordinates of items tag display position, if requested. + */ + +int InvItem(int *x, int *y, bool update) { + int itop, ileft; + int row, col; + int item; + int IconsX; + + itop = InvD[ino].inventoryY + START_ICONY; + + IconsX = InvD[ino].inventoryX + START_ICONX; + + for (item = InvD[ino].FirstDisp, row = 0; row < InvD[ino].NoofVicons; row++) { + ileft = IconsX; + + for (col = 0; col < InvD[ino].NoofHicons; col++, item++) { + if (*x >= ileft && *x < ileft + ITEM_WIDTH && + *y >= itop && *y < itop + ITEM_HEIGHT) { + if (update) { + *x = ileft + ITEM_WIDTH/2; + *y = itop /*+ ITEM_HEIGHT/4*/; + } + return item; + } + + ileft += ITEM_WIDTH + 1; + } + itop += ITEM_HEIGHT + 1; + } + return INV_NOICON; +} + +/** + * Returns the id of the icon displayed under the given position. + */ + +int InvItemId(int x, int y) { + int itop, ileft; + int row, col; + int item; + + if (InventoryHidden || InventoryState == IDLE_INV) + return INV_NOICON; + + itop = InvD[ino].inventoryY + START_ICONY; + + int IconsX = InvD[ino].inventoryX + START_ICONX; + + for (item = InvD[ino].FirstDisp, row = 0; row < InvD[ino].NoofVicons; row++) { + ileft = IconsX; + + for (col = 0; col < InvD[ino].NoofHicons; col++, item++) { + if (x >= ileft && x < ileft + ITEM_WIDTH && + y >= itop && y < itop + ITEM_HEIGHT) { + return InvD[ino].ItemOrder[item]; + } + + ileft += ITEM_WIDTH + 1; + } + itop += ITEM_HEIGHT + 1; + } + return INV_NOICON; +} + +/*---------------------------------------------------------------------*\ +| WhichInvBox() | +|-----------------------------------------------------------------------| +| Finds which box the cursor is in. | +\*---------------------------------------------------------------------*/ +#define MD_YSLIDTOP 7 +#define MD_YSLIDBOT 18 +#define MD_YBUTTOP 9 +#define MD_YBUTBOT 16 +#define MD_XLBUTL 1 +#define MD_XLBUTR 10 +#define MD_XRBUTL 105 +#define MD_XRBUTR 114 + +static int WhichInvBox(int curX, int curY, bool bSlides) { + if (bSlides) { + for (int i = 0; i < numMdSlides; i++) { + if (curY > MultiHighest(mdSlides[i].obj) && curY < MultiLowest(mdSlides[i].obj) + && curX > MultiLeftmost(mdSlides[i].obj) && curX < MultiRightmost(mdSlides[i].obj)) + return mdSlides[i].num | IS_SLIDER; + } + } + + curX -= InvD[ino].inventoryX; + curY -= InvD[ino].inventoryY; + + for (int i = 0; i < cd.NumBoxes; i++) { + switch (cd.Box[i].boxType) { + case SLIDER: + if (bSlides) { + if (curY >= cd.Box[i].ypos+MD_YBUTTOP && curY < cd.Box[i].ypos+MD_YBUTBOT) { + if (curX >= cd.Box[i].xpos+MD_XLBUTL && curX < cd.Box[i].xpos+MD_XLBUTR) + return i | IS_LEFT; + if (curX >= cd.Box[i].xpos+MD_XRBUTL && curX < cd.Box[i].xpos+MD_XRBUTR) + return i | IS_RIGHT; + } + } + break; + + case AAGBUT: + case ARSGBUT: + case TOGGLE: + case FLIP: + if (curY > cd.Box[i].ypos && curY < cd.Box[i].ypos + cd.Box[i].h + && curX > cd.Box[i].xpos && curX < cd.Box[i].xpos + cd.Box[i].w) + return i; + break; + + default: + // 'Normal' box + if (curY >= cd.Box[i].ypos && curY < cd.Box[i].ypos + cd.Box[i].h + && curX >= cd.Box[i].xpos && curX < cd.Box[i].xpos + cd.Box[i].w) + return i; + break; + } + } + + if (cd.bExtraWin) { + if (curX > 20 + 181 && curX < 20 + 181 + 8 && + curY > 24 + 2 && curY < 24 + 139 + 5) { + + if (curY < 24 + 2 + 5) { + return IB_UP; + } else if (curY > 24 + 139) { + return IB_DOWN; + } else if (curY+InvD[ino].inventoryY >= slideY && curY+InvD[ino].inventoryY < slideY + 5) { + return IB_SLIDE; + } else if (curY+InvD[ino].inventoryY < slideY) { + return IB_SLIDE_UP; + } else if (curY+InvD[ino].inventoryY >= slideY + 5) { + return IB_SLIDE_DOWN; + } + } + } + + return IB_NONE; +} + +/**************************************************************************/ +/***/ +/**************************************************************************/ + +/** + * InBoxes + */ +void InvBoxes(bool InBody, int curX, int curY) { + int index; // Box pointed to on this call + const FILM *pfilm; + + // Find out which icon is currently pointed to + if (!InBody) + index = -1; + else { + index = WhichInvBox(curX, curY, false); + } + + // If no icon pointed to, or points to (logical position of) + // currently held icon, then no icon is pointed to! + if (index < 0) { + // unhigh-light box (if one was) + cd.pointBox = NOBOX; + if (iconArray[HL1] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = NULL; + } + } else if (index != cd.pointBox) { + cd.pointBox = index; + // A new box is pointed to - high-light it + if (iconArray[HL1] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = NULL; + } + if ((cd.Box[cd.pointBox].boxType == ARSBUT && cd.selBox != NOBOX) || +///* I don't agree */ cd.Box[cd.pointBox].boxType == RGROUP || + cd.Box[cd.pointBox].boxType == AATBUT || + cd.Box[cd.pointBox].boxType == AABUT) { + iconArray[HL1] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[cd.pointBox].w, cd.Box[cd.pointBox].h); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + MultiSetAniXY(iconArray[HL1], + InvD[ino].inventoryX + cd.Box[cd.pointBox].xpos, + InvD[ino].inventoryY + cd.Box[cd.pointBox].ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + } + else if (cd.Box[cd.pointBox].boxType == AAGBUT || + cd.Box[cd.pointBox].boxType == ARSGBUT || + cd.Box[cd.pointBox].boxType == TOGGLE) { + pfilm = (const FILM *)LockMem(winPartsf); + + iconArray[HL1] = AddObject(&pfilm->reels[cd.Box[cd.pointBox].bi+HIGRAPH], -1); + MultiSetAniXY(iconArray[HL1], + InvD[ino].inventoryX + cd.Box[cd.pointBox].xpos, + InvD[ino].inventoryY + cd.Box[cd.pointBox].ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + } + } +} + +static void ButtonPress(CORO_PARAM, PCONFBOX box) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + const FILM *pfilm; + + assert(box->boxType == AAGBUT || box->boxType == ARSGBUT); + + // Replace highlight image with normal image + pfilm = (const FILM *)LockMem(winPartsf); + if (iconArray[HL1] != NULL) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + pfilm = (const FILM *)LockMem(winPartsf); + iconArray[HL1] = AddObject(&pfilm->reels[box->bi+NORMGRAPH], -1); + MultiSetAniXY(iconArray[HL1], InvD[ino].inventoryX + box->xpos, InvD[ino].inventoryY + box->ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + + // Hold normal image for 1 frame + CORO_SLEEP(1); + if (iconArray[HL1] == NULL) + return; + + // Replace normal image with depresses image + pfilm = (const FILM *)LockMem(winPartsf); + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = AddObject(&pfilm->reels[box->bi+DOWNGRAPH], -1); + MultiSetAniXY(iconArray[HL1], InvD[ino].inventoryX + box->xpos, InvD[ino].inventoryY + box->ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + + // Hold depressed image for 2 frames + CORO_SLEEP(2); + if (iconArray[HL1] == NULL) + return; + + // Replace depressed image with normal image + pfilm = (const FILM *)LockMem(winPartsf); + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = AddObject(&pfilm->reels[box->bi+NORMGRAPH], -1); + MultiSetAniXY(iconArray[HL1], InvD[ino].inventoryX + box->xpos, InvD[ino].inventoryY + box->ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + + CORO_SLEEP(1); + + CORO_END_CODE; +} + +static void ButtonToggle(CORO_PARAM, PCONFBOX box) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + const FILM *pfilm; + + assert(box->boxType == TOGGLE); + + // Remove hilight image + if (iconArray[HL1] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = NULL; + } + + // Hold normal image for 1 frame + CORO_SLEEP(1); + if (InventoryState != ACTIVE_INV) + return; + + // Add depressed image + pfilm = (const FILM *)LockMem(winPartsf); + iconArray[HL1] = AddObject(&pfilm->reels[box->bi+DOWNGRAPH], -1); + MultiSetAniXY(iconArray[HL1], InvD[ino].inventoryX + box->xpos, InvD[ino].inventoryY + box->ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + + // Hold depressed image for 1 frame + CORO_SLEEP(1); + if (iconArray[HL1] == NULL) + return; + + // Toggle state + (*box->ival) = *(box->ival) ^ 1; // XOR with true + box->bi = *(box->ival) ? IX_TICK1 : IX_CROSS1; + AddBoxes(false); + // Keep highlight (e.g. flag) + if (cd.selBox != NOBOX) + Select(cd.selBox, true); + + // New state, depressed image + pfilm = (const FILM *)LockMem(winPartsf); + if (iconArray[HL1] != NULL) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = AddObject(&pfilm->reels[box->bi+DOWNGRAPH], -1); + MultiSetAniXY(iconArray[HL1], InvD[ino].inventoryX + box->xpos, InvD[ino].inventoryY + box->ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + + // Hold new depressed image for 1 frame + CORO_SLEEP(1); + if (iconArray[HL1] == NULL) + return; + + // New state, normal + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = NULL; + + // Hold normal image for 1 frame + CORO_SLEEP(1); + if (InventoryState != ACTIVE_INV) + return; + + // New state, highlighted + pfilm = (const FILM *)LockMem(winPartsf); + if (iconArray[HL1] != NULL) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL1]); + iconArray[HL1] = AddObject(&pfilm->reels[box->bi+HIGRAPH], -1); + MultiSetAniXY(iconArray[HL1], InvD[ino].inventoryX + box->xpos, InvD[ino].inventoryY + box->ypos); + MultiSetZPosition(iconArray[HL1], Z_INV_ICONS+1); + + CORO_END_CODE; +} + +/** + * Monitors for POINTED event for inventory icons. + */ + +void InvLabels(bool InBody, int aniX, int aniY) { + int index; // Icon pointed to on this call + PINV_OBJECT invObj; + + // Find out which icon is currently pointed to + if (!InBody) + index = INV_NOICON; + else { + index = InvItem(&aniX, &aniY, false); + if (index != INV_NOICON) { + if (index >= InvD[ino].NoofItems) + index = INV_NOICON; + else + index = InvD[ino].ItemOrder[index]; + } + } + + // If no icon pointed to, or points to (logical position of) + // currently held icon, then no icon is pointed to! + if (index == INV_NOICON || index == HeldItem) { + pointedIcon = INV_NOICON; + } else if (index != pointedIcon) { + // A new icon is pointed to - run its script with POINTED event + invObj = findInvObject(index); + if (invObj->hScript) + RunInvTinselCode(invObj, POINTED, BE_NONE, index); + pointedIcon = index; + } +} + +/**************************************************************************/ +/***/ +/**************************************************************************/ + +/** + * All to do with the slider. + * I can't remember how it works - or, indeed, what it does. + * It seems to set up slideStuff[], an array of possible first-displayed + * icons set against the matching y-positions of the slider. + */ + +void AdjustTop(void) { + int tMissing, bMissing, nMissing; + int nslideY; + int rowsWanted; + int slideRange; + int n, i; + + // Only do this if there's a slider + if (!SlideObject) + return; + + rowsWanted = (InvD[ino].NoofItems - InvD[ino].FirstDisp + InvD[ino].NoofHicons-1) / InvD[ino].NoofHicons; + + while (rowsWanted < InvD[ino].NoofVicons) { + if (InvD[ino].FirstDisp) { + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + if (InvD[ino].FirstDisp < 0) + InvD[ino].FirstDisp = 0; + rowsWanted++; + } else + break; + } + tMissing = InvD[ino].FirstDisp ? (InvD[ino].FirstDisp + InvD[ino].NoofHicons-1)/InvD[ino].NoofHicons : 0; + bMissing = (rowsWanted > InvD[ino].NoofVicons) ? rowsWanted - InvD[ino].NoofVicons : 0; + + nMissing = tMissing + bMissing; + slideRange = slideYmax - slideYmin; + + if (!tMissing) + nslideY = slideYmin; + else if (!bMissing) + nslideY = slideYmax; + else { + nslideY = tMissing*slideRange/nMissing; + nslideY += slideYmin; + } + + if (nMissing) { + n = InvD[ino].FirstDisp - tMissing*InvD[ino].NoofHicons; + for (i = 0; i <= nMissing; i++, n += InvD[ino].NoofHicons) { + slideStuff[i].n = n; + slideStuff[i].y = (i*slideRange/nMissing) + slideYmin; + } + if (slideStuff[0].n < 0) + slideStuff[0].n = 0; + assert(i < MAX_ININV + 1); + slideStuff[i].n = -1; + } else { + slideStuff[0].n = 0; + slideStuff[0].y = slideYmin; + slideStuff[1].n = -1; + } + + if (nslideY != slideY) { + MultiMoveRelXY(SlideObject, 0, nslideY - slideY); + slideY = nslideY; + } +} + +/** + * Insert an inventory icon object onto the display list. + */ + +OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) { + PINV_OBJECT invObj; // Icon data + const MULTI_INIT *pmi; // Its INIT structure - from the reel + PIMAGE pim; // ... you get the picture + OBJECT * pPlayObj; // The object we insert + + invObj = findInvObject(num); + + // Get pointer to image + pim = GetImageFromFilm(invObj->hFilm, 0, pfreel, &pmi, pfilm); + + // Poke in the background palette + pim->hImgPal = TO_LE_32(BackPal()); + + // Set up the multi-object + pPlayObj = MultiInitObject(pmi); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), pPlayObj); + + return pPlayObj; +} + +/** + * Create display objects for the displayed icons in an inventory window. + */ + +void FillInInventory(void) { + int Index; // Index into ItemOrder[] + int n = 0; // index into iconArray[] + int xpos, ypos; + int row, col; + const FREEL *pfr; + const FILM *pfilm; + + DumpIconArray(); + + if (InvDragging != ID_SLIDE) + AdjustTop(); // Set up slideStuff[] + + Index = InvD[ino].FirstDisp; // Start from first displayed object + n = 0; + ypos = START_ICONY; // Y-offset of first display row + + for (row = 0; row < InvD[ino].NoofVicons; row++, ypos += ITEM_HEIGHT + 1) { + xpos = START_ICONX; // X-offset of first display column + + for (col = 0; col < InvD[ino].NoofHicons; col++) { + if (Index >= InvD[ino].NoofItems) + break; + else if (InvD[ino].ItemOrder[Index] != HeldItem) { + // Create a display object and position it + iconArray[n] = AddInvObject(InvD[ino].ItemOrder[Index], &pfr, &pfilm); + MultiSetAniXY(iconArray[n], InvD[ino].inventoryX + xpos , InvD[ino].inventoryY + ypos); + MultiSetZPosition(iconArray[n], Z_INV_ICONS); + + InitStepAnimScript(&iconAnims[n], iconArray[n], FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate)); + + n++; + } + Index++; + xpos += ITEM_WIDTH + 1; // X-offset of next display column + } + } +} + +/** + * Set up a rectangle as the background to the inventory window. + * Additionally, sticks the window title up. + */ + +enum {FROM_HANDLE, FROM_STRING}; + +void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int textFrom) { + // Why not 2 ???? + int width = TLwidth + extraH + TRwidth - 3; + int height = TLheight + extraV + BLheight - 3; + + // Create a rectangle object + RectObject = *rect = TranslucentObject(width, height); + + // add it to display list and position it + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), *rect); + MultiSetAniXY(*rect, InvD[ino].inventoryX + 1, InvD[ino].inventoryY + 1); + MultiSetZPosition(*rect, Z_INV_BRECT); + + // Create text object using title string + if (textFrom == FROM_HANDLE) { + LoadStringRes(InvD[ino].hInvTitle, tBufferAddr(), TBUFSZ); + *title = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), 0, + InvD[ino].inventoryX + width/2, InvD[ino].inventoryY + M_TOFF, + hTagFontHandle(), TXT_CENTRE); + assert(*title); // Inventory title string produced NULL text + MultiSetZPosition(*title, Z_INV_HTEXT); + } else if (textFrom == FROM_STRING && cd.ixHeading != NO_HEADING) { + LoadStringRes(configStrings[cd.ixHeading], tBufferAddr(), TBUFSZ); + *title = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), 0, + InvD[ino].inventoryX + width/2, InvD[ino].inventoryY + M_TOFF, + hTagFontHandle(), TXT_CENTRE); + assert(*title); // Inventory title string produced NULL text + MultiSetZPosition(*title, Z_INV_HTEXT); + } +} + +/** + * Insert a part of the inventory window frame onto the display list. + */ + +static OBJECT *AddObject(const FREEL *pfreel, int num) { + const MULTI_INIT *pmi; // Get the MULTI_INIT structure + PIMAGE pim; + OBJECT * pPlayObj; + + // Get pointer to image + pim = GetImageFromReel(pfreel, &pmi); + + // Poke in the background palette + pim->hImgPal = TO_LE_32(BackPal()); + + // Horrible bodge involving global variables to save + // width and/or height of some window frame components + if (num == TL) { + TLwidth = FROM_LE_16(pim->imgWidth); + TLheight = FROM_LE_16(pim->imgHeight); + } else if (num == TR) { + TRwidth = FROM_LE_16(pim->imgWidth); + } else if (num == BL) { + BLheight = FROM_LE_16(pim->imgHeight); + } + + // Set up and insert the multi-object + pPlayObj = MultiInitObject(pmi); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), pPlayObj); + + return pPlayObj; +} + +/** + * Display the scroll bar slider. + */ + +void AddSlider(OBJECT **slide, const FILM *pfilm) { + SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1); + MultiSetAniXY(*slide, MultiRightmost(RectObject)-M_SXOFF+2, InvD[ino].inventoryY + slideY); + MultiSetZPosition(*slide, Z_INV_MFRAME); +} + +enum { + SLIDE_RANGE = 81, + SLIDE_MINX = 8, + SLIDE_MAXX = 8+SLIDE_RANGE, + + MDTEXT_YOFF = 6, + MDTEXT_XOFF = -4 +}; + +/** + * Display a box with some text in it. + */ + +void AddBox(int *pi, int i) { + int x = InvD[ino].inventoryX + cd.Box[i].xpos; + int y = InvD[ino].inventoryY + cd.Box[i].ypos; + int *pival = cd.Box[i].ival; + int xdisp; + const FILM *pfilm; + + switch (cd.Box[i].boxType) { + default: + // Give us a box + iconArray[*pi] = RectangleObject(BackPal(), COL_BOX, cd.Box[i].w, cd.Box[i].h); + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[*pi]); + MultiSetAniXY(iconArray[*pi], x, y); + MultiSetZPosition(iconArray[*pi], Z_INV_BRECT+1); + *pi += 1; + + // Stick in the text + if (cd.Box[i].ixText == USE_POINTER) { + if (cd.Box[i].boxText != NULL) { + if (cd.Box[i].boxType == RGROUP) { + iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), cd.Box[i].boxText, 0, +#ifdef JAPAN + x+2, y+2, hTagFontHandle(), 0); +#else + x+2, y, hTagFontHandle(), 0); +#endif + } else { + iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), cd.Box[i].boxText, 0, +#ifdef JAPAN +// Note: it never seems to go here! + x + cd.Box[i].w/2, y+2, hTagFontHandle(), TXT_CENTRE); +#else + x + cd.Box[i].w/2, y, hTagFontHandle(), TXT_CENTRE); +#endif + } + MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT); + *pi += 1; + } + } else { + LoadStringRes(configStrings[cd.Box[i].ixText], tBufferAddr(), TBUFSZ); + assert(cd.Box[i].boxType != RGROUP); // You'll need to add some code! + iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), 0, +#ifdef JAPAN + x + cd.Box[i].w/2, y+2, hTagFontHandle(), TXT_CENTRE); +#else + x + cd.Box[i].w/2, y, hTagFontHandle(), TXT_CENTRE); +#endif + MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT); + *pi += 1; + } + break; + + case AAGBUT: + case ARSGBUT: + pfilm = (const FILM *)LockMem(winPartsf); + + iconArray[*pi] = AddObject(&pfilm->reels[cd.Box[i].bi+NORMGRAPH], -1); + MultiSetAniXY(iconArray[*pi], x, y); + MultiSetZPosition(iconArray[*pi], Z_INV_BRECT+1); + *pi += 1; + + break; + +#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) + case FRGROUP: + assert(flagFilm != 0); // Language flags not declared! + + pfilm = (const FILM *)LockMem(flagFilm); + + if (bAmerica && cd.Box[i].bi == FIX_UK) + cd.Box[i].bi = FIX_USA; + + iconArray[*pi] = AddObject(&pfilm->reels[cd.Box[i].bi], -1); + MultiSetAniXY(iconArray[*pi], x, y); + MultiSetZPosition(iconArray[*pi], Z_INV_BRECT+2); + *pi += 1; + + break; +#endif + case FLIP: + pfilm = (const FILM *)LockMem(winPartsf); + + if (*(cd.Box[i].ival)) + iconArray[*pi] = AddObject(&pfilm->reels[cd.Box[i].bi], -1); + else + iconArray[*pi] = AddObject(&pfilm->reels[cd.Box[i].bi+1], -1); + MultiSetAniXY(iconArray[*pi], x, y); + MultiSetZPosition(iconArray[*pi], Z_INV_BRECT+1); + *pi += 1; + + // Stick in the text + assert(cd.Box[i].ixText != USE_POINTER); + LoadStringRes(configStrings[cd.Box[i].ixText], tBufferAddr(), TBUFSZ); + iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), 0, + x+MDTEXT_XOFF, y+MDTEXT_YOFF, hTagFontHandle(), TXT_RIGHT); + MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT); + *pi += 1; + break; + + case TOGGLE: + pfilm = (const FILM *)LockMem(winPartsf); + + cd.Box[i].bi = *(cd.Box[i].ival) ? IX_TICK1 : IX_CROSS1; + iconArray[*pi] = AddObject(&pfilm->reels[cd.Box[i].bi+NORMGRAPH], -1); + MultiSetAniXY(iconArray[*pi], x, y); + MultiSetZPosition(iconArray[*pi], Z_INV_BRECT+1); + *pi += 1; + + // Stick in the text + assert(cd.Box[i].ixText != USE_POINTER); + LoadStringRes(configStrings[cd.Box[i].ixText], tBufferAddr(), TBUFSZ); + iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), 0, + x+MDTEXT_XOFF, y+MDTEXT_YOFF, hTagFontHandle(), TXT_RIGHT); + MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT); + *pi += 1; + break; + + case SLIDER: + pfilm = (const FILM *)LockMem(winPartsf); + xdisp = SLIDE_RANGE*(*pival)/cd.Box[i].w; + + iconArray[*pi] = AddObject(&pfilm->reels[IX_MDGROOVE], -1); + MultiSetAniXY(iconArray[*pi], x, y); + MultiSetZPosition(iconArray[*pi], Z_MDGROOVE); + *pi += 1; + iconArray[*pi] = AddObject(&pfilm->reels[IX_MDSLIDER], -1); + MultiSetAniXY(iconArray[*pi], x+SLIDE_MINX+xdisp, y); + MultiSetZPosition(iconArray[*pi], Z_MDSLIDER); + assert(numMdSlides < MAXSLIDES); + mdSlides[numMdSlides].num = i; + mdSlides[numMdSlides].min = x+SLIDE_MINX; + mdSlides[numMdSlides].max = x+SLIDE_MAXX; + mdSlides[numMdSlides++].obj = iconArray[*pi]; + *pi += 1; + + // Stick in the text + assert(cd.Box[i].ixText != USE_POINTER); + LoadStringRes(configStrings[cd.Box[i].ixText], tBufferAddr(), TBUFSZ); + iconArray[*pi] = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), 0, + x+MDTEXT_XOFF, y+MDTEXT_YOFF, hTagFontHandle(), TXT_RIGHT); + MultiSetZPosition(iconArray[*pi], Z_INV_ITEXT); + *pi += 1; + break; + } +} + +/** + * Display some boxes. + */ +static void AddBoxes(bool posnSlide) { + int oCount = NUMHL; // Object count - allow for HL1, HL2 etc. + + DumpIconArray(); + numMdSlides = 0; + + for (int i = 0; i < cd.NumBoxes; i++) { + AddBox(&oCount, i); + } + + if (cd.bExtraWin) { + if (posnSlide) + slideY = slideYmin + (cd.fileBase*(slideYmax-slideYmin))/(MAX_SFILES-NUM_SL_RGROUP); + MultiSetAniXY(SlideObject, InvD[ino].inventoryX + 24 + 179, slideY); + } + + assert(oCount < MAX_ICONS); // added too many icons +} + +/** + * Display the scroll bar slider. + */ + +void AddEWSlider(OBJECT **slide, const FILM *pfilm) { + SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1); + MultiSetAniXY(*slide, InvD[ino].inventoryX + 24 + 127, slideY); + MultiSetZPosition(*slide, Z_INV_MFRAME); +} + +/** + * AddExtraWindow + */ + +int AddExtraWindow(int x, int y, OBJECT **retObj) { + int n = 0; + const FILM *pfilm; + + // Get the frame's data + pfilm = (const FILM *)LockMem(winPartsf); + + x += 20; + y += 24; + +// Draw the four corners + retObj[n] = AddObject(&pfilm->reels[IX_RTL], -1); // Top left + MultiSetAniXY(retObj[n], x, y); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_NTR], -1); // Top right + MultiSetAniXY(retObj[n], x + 152, y); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_BL], -1); // Bottom left + MultiSetAniXY(retObj[n], x, y + 124); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_BR], -1); // Bottom right + MultiSetAniXY(retObj[n], x + 152, y + 124); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + +// Draw the edges + retObj[n] = AddObject(&pfilm->reels[IX_H156], -1); // Top + MultiSetAniXY(retObj[n], x + 6, y); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_H156], -1); // Bottom + MultiSetAniXY(retObj[n], x + 6, y + 143); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_V104], -1); // Left + MultiSetAniXY(retObj[n], x, y + 20); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_V104], -1); // Right 1 + MultiSetAniXY(retObj[n], x + 179, y + 20); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + retObj[n] = AddObject(&pfilm->reels[IX_V104], -1); // Right 2 + MultiSetAniXY(retObj[n], x + 188, y + 20); + MultiSetZPosition(retObj[n], Z_INV_MFRAME); + n++; + + slideY = slideYmin = y + 9; + slideYmax = y + 134; + AddEWSlider(&retObj[n++], pfilm); + + return n; +} + + +enum InventoryType { EMPTY, FULL, CONF }; + +/** + * Construct an inventory window - either a standard one, with + * background, slider and icons, or a re-sizing window. + */ +void ConstructInventory(InventoryType filling) { + int eH, eV; // Extra width and height + int n = 0; // Index into object array + int zpos; // Z-position of frame + int invX = InvD[ino].inventoryX; + int invY = InvD[ino].inventoryY; + OBJECT **retObj; + const FILM *pfilm; + + extern bool RePosition(void); // Forward reference + // Select the object array to use + if (filling == FULL || filling == CONF) { + retObj = objArray; // Standard window + zpos = Z_INV_MFRAME; + } else { + retObj = DobjArray; // Re-sizing window + zpos = Z_INV_RFRAME; + } + + // Dispose of anything it may be replacing + for (int i = 0; i < MAX_WCOMP; i++) { + if (retObj[i] != NULL) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), retObj[i]); + retObj[i] = NULL; + } + } + + // Get the frame's data + pfilm = (const FILM *)LockMem(winPartsf); + + // Standard window is of granular dimensions + if (filling == FULL) { + // Round-up/down to nearest number of icons + if (SuppH > ITEM_WIDTH / 2) + InvD[ino].NoofHicons++; + if (SuppV > ITEM_HEIGHT / 2) + InvD[ino].NoofVicons++; + SuppH = SuppV = 0; + } + + // Extra width and height + eH = (InvD[ino].NoofHicons - 1) * (ITEM_WIDTH+1) + SuppH; + eV = (InvD[ino].NoofVicons - 1) * (ITEM_HEIGHT+1) + SuppV; + + // Which window frame corners to use + if (filling == FULL && ino != INV_CONV) { + TL = IX_TL; + TR = IX_TR; + BL = IX_BL; + BR = IX_BR; + } else { + TL = IX_RTL; + TR = IX_RTR; + BL = IX_BL; + BR = IX_RBR; + } + +// Draw the four corners + retObj[n] = AddObject(&pfilm->reels[TL], TL); + MultiSetAniXY(retObj[n], invX, invY); + MultiSetZPosition(retObj[n], zpos); + n++; + retObj[n] = AddObject(&pfilm->reels[TR], TR); + MultiSetAniXY(retObj[n], invX + TLwidth + eH, invY); + MultiSetZPosition(retObj[n], zpos); + n++; + retObj[n] = AddObject(&pfilm->reels[BL], BL); + MultiSetAniXY(retObj[n], invX, invY + TLheight + eV); + MultiSetZPosition(retObj[n], zpos); + n++; + retObj[n] = AddObject(&pfilm->reels[BR], BR); + MultiSetAniXY(retObj[n], invX + TLwidth + eH, invY + TLheight + eV); + MultiSetZPosition(retObj[n], zpos); + n++; + +// Draw extra Top and bottom parts + if (InvD[ino].NoofHicons > 1) { + // Top side + retObj[n] = AddObject(&pfilm->reels[hFillers[InvD[ino].NoofHicons-2]], -1); + MultiSetAniXY(retObj[n], invX + TLwidth, invY); + MultiSetZPosition(retObj[n], zpos); + n++; + + // Bottom of header box + if (filling == FULL) { + retObj[n] = AddObject(&pfilm->reels[hFillers[InvD[ino].NoofHicons-2]], -1); + MultiSetAniXY(retObj[n], invX + TLwidth, invY + M_TBB + 1); + MultiSetZPosition(retObj[n], zpos); + n++; + + // Extra bits for conversation - hopefully temporary + if (ino == INV_CONV) { + retObj[n] = AddObject(&pfilm->reels[IX_H26], -1); + MultiSetAniXY(retObj[n], invX + TLwidth - 2, invY + M_TBB + 1); + MultiSetZPosition(retObj[n], zpos); + n++; + + retObj[n] = AddObject(&pfilm->reels[IX_H52], -1); + MultiSetAniXY(retObj[n], invX + eH - 10, invY + M_TBB + 1); + MultiSetZPosition(retObj[n], zpos); + n++; + } + } + + // Bottom side + retObj[n] = AddObject(&pfilm->reels[hFillers[InvD[ino].NoofHicons-2]], -1); + MultiSetAniXY(retObj[n], invX + TLwidth, invY + TLheight + eV + BLheight - M_TH + 1); + MultiSetZPosition(retObj[n], zpos); + n++; + } + if (SuppH) { + int offx = TLwidth + eH - 26; + if (offx < TLwidth) // Not too far! + offx = TLwidth; + + // Top side extra + retObj[n] = AddObject(&pfilm->reels[IX_H26], -1); + MultiSetAniXY(retObj[n], invX + offx, invY); + MultiSetZPosition(retObj[n], zpos); + n++; + + // Bottom side extra + retObj[n] = AddObject(&pfilm->reels[IX_H26], -1); + MultiSetAniXY(retObj[n], invX + offx, invY + TLheight + eV + BLheight - M_TH + 1); + MultiSetZPosition(retObj[n], zpos); + n++; + } + +// Draw extra side parts + if (InvD[ino].NoofVicons > 1) { + // Left side + retObj[n] = AddObject(&pfilm->reels[vFillers[InvD[ino].NoofVicons-2]], -1); + MultiSetAniXY(retObj[n], invX, invY + TLheight); + MultiSetZPosition(retObj[n], zpos); + n++; + + // Left side of scroll bar + if (filling == FULL && ino != INV_CONV) { + retObj[n] = AddObject(&pfilm->reels[vFillers[InvD[ino].NoofVicons-2]], -1); + MultiSetAniXY(retObj[n], invX + TLwidth + eH + M_SBL + 1, invY + TLheight); + MultiSetZPosition(retObj[n], zpos); + n++; + } + + // Right side + retObj[n] = AddObject(&pfilm->reels[vFillers[InvD[ino].NoofVicons-2]], -1); + MultiSetAniXY(retObj[n], invX + TLwidth + eH + TRwidth - M_SW + 1, invY + TLheight); + MultiSetZPosition(retObj[n], zpos); + n++; + } + if (SuppV) { + int offy = TLheight + eV - 26; + if (offy < 5) + offy = 5; + + // Left side extra + retObj[n] = AddObject(&pfilm->reels[IX_V26], -1); + MultiSetAniXY(retObj[n], invX, invY + offy); + MultiSetZPosition(retObj[n], zpos); + n++; + + // Right side extra + retObj[n] = AddObject(&pfilm->reels[IX_V26], -1); + MultiSetAniXY(retObj[n], invX + TLwidth + eH + TRwidth - M_SW + 1, invY + offy); + MultiSetZPosition(retObj[n], zpos); + n++; + } + + OBJECT **rect, **title; + +// Draw background, slider and icons + if (filling == FULL) { + rect = &retObj[n++]; + title = &retObj[n++]; + + AddBackground(rect, title, eH, eV, FROM_HANDLE); + + if (ino == INV_CONV) + SlideObject = NULL; + else if (InvD[ino].NoofItems > InvD[ino].NoofHicons*InvD[ino].NoofVicons) { + slideYmin = TLheight - 2; + slideYmax = TLheight + eV + 10; + AddSlider(&retObj[n++], pfilm); + } + + FillInInventory(); + } + else if (filling == CONF) { + rect = &retObj[n++]; + title = &retObj[n++]; + + AddBackground(rect, title, eH, eV, FROM_STRING); + if (cd.bExtraWin) + n += AddExtraWindow(invX, invY, &retObj[n]); + AddBoxes(true); + } + + assert(n < MAX_WCOMP); // added more parts than we can handle! + + // Reposition returns TRUE if needs to move + if (InvD[ino].moveable && filling == FULL && RePosition()) { + ConstructInventory(FULL); + } +} + + +/** + * Call this when drawing a 'FULL', movable inventory. Checks that the + * position of the Translucent object is within limits. If it isn't, + * adjusts the x/y position of the current inventory and returns TRUE. + */ +bool RePosition(void) { + int p; + bool bMoveitMoveit = false; + + assert(RectObject); // no recangle object! + + // Test for off-screen horizontally + p = MultiLeftmost(RectObject); + if (p > MAXLEFT) { + // Too far to the right + InvD[ino].inventoryX += MAXLEFT - p; + bMoveitMoveit = true; // I like to.... + } else { + // Too far to the left? + p = MultiRightmost(RectObject); + if (p < MINRIGHT) { + InvD[ino].inventoryX += MINRIGHT - p; + bMoveitMoveit = true; // I like to.... + } + } + + // Test for off-screen vertically + p = MultiHighest(RectObject); + if (p < MINTOP) { + // Too high + InvD[ino].inventoryY += MINTOP - p; + bMoveitMoveit = true; // I like to.... + } else if (p > MAXTOP) { + // Too low + InvD[ino].inventoryY += MAXTOP - p; + bMoveitMoveit = true; // I like to.... + } + + return bMoveitMoveit; +} + +/**************************************************************************/ +/***/ +/**************************************************************************/ + +/** + * Get the cursor's reel, poke in the background palette, + * and customise the cursor. + */ +void AlterCursor(int num) { + const FREEL *pfreel; + PIMAGE pim; + + // Get pointer to image + pim = GetImageFromFilm(winPartsf, num, &pfreel); + + // Poke in the background palette + pim->hImgPal = TO_LE_32(BackPal()); + + SetTempCursor(FROM_LE_32(pfreel->script)); +} + +enum InvCursorFN {IC_AREA, IC_DROP}; + +/** + * InvCursor + */ +void InvCursor(InvCursorFN fn, int CurX, int CurY) { + static enum { IC_NORMAL, IC_DR, IC_UR, IC_TB, IC_LR, + IC_INV, IC_UP, IC_DN } ICursor = IC_NORMAL; // FIXME: local static var + + int area; // The part of the window the cursor is over + bool restoreMain = false; + + // If currently dragging, don't be messing about with the cursor shape + if (InvDragging != ID_NONE) + return; + + switch (fn) { + case IC_DROP: + ICursor = IC_NORMAL; + InvCursor(IC_AREA, CurX, CurY); + break; + + case IC_AREA: + area = InvArea(CurX, CurY); + + // Check for POINTED events + if (ino == INV_CONF) + InvBoxes(area == I_BODY, CurX, CurY); + else + InvLabels(area == I_BODY, CurX, CurY); + + // No cursor trails while within inventory window + if (area == I_NOTIN) + UnHideCursorTrails(); + else + HideCursorTrails(); + + switch (area) { + case I_NOTIN: + restoreMain = true; + break; + + case I_TLEFT: + case I_BRIGHT: + if (!InvD[ino].resizable) + restoreMain = true; + else if (ICursor != IC_DR) { + AlterCursor(IX_CURDD); + ICursor = IC_DR; + } + break; + + case I_TRIGHT: + case I_BLEFT: + if (!InvD[ino].resizable) + restoreMain = true; + else if (ICursor != IC_UR) { + AlterCursor(IX_CURDU); + ICursor = IC_UR; + } + break; + + case I_TOP: + case I_BOTTOM: + if (!InvD[ino].resizable) { + restoreMain = true; + break; + } + if (ICursor != IC_TB) { + AlterCursor(IX_CURUD); + ICursor = IC_TB; + } + break; + + case I_LEFT: + case I_RIGHT: + if (!InvD[ino].resizable) + restoreMain = true; + else if (ICursor != IC_LR) { + AlterCursor(IX_CURLR); + ICursor = IC_LR; + } + break; + + case I_UP: + case I_SLIDE_UP: + case I_DOWN: + case I_SLIDE_DOWN: + case I_SLIDE: + case I_MOVE: + case I_BODY: + restoreMain = true; + break; + } + break; + } + + if (restoreMain && ICursor != IC_NORMAL) { + RestoreMainCursor(); + ICursor = IC_NORMAL; + } +} + + + + +/*-------------------------------------------------------------------------*/ + + +/**************************************************************************/ +/******************** Conversation specific functions *********************/ +/**************************************************************************/ + + +void ConvAction(int index) { + assert(ino == INV_CONV); // not conv. window! + + switch (index) { + case INV_NOICON: + return; + + case INV_CLOSEICON: + thisConvIcon = -1; // Postamble + break; + + case INV_OPENICON: + thisConvIcon = -2; // Preamble + break; + + default: + thisConvIcon = InvD[ino].ItemOrder[index]; + break; + } + + RunPolyTinselCode(thisConvPoly, CONVERSE, BE_NONE, true); +} +/*-------------------------------------------------------------------------*/ + +void AddIconToPermanentDefaultList(int icon) { + int i; + + // See if it's already there + for (i = 0; i < Num0Order; i++) { + if (Inv0Order[i] == icon) + break; + } + + // Add it if it isn't already there + if (i == Num0Order) { + Inv0Order[Num0Order++] = icon; + } +} + +/*-------------------------------------------------------------------------*/ + +void convPos(int fn) { + if (fn == CONV_DEF) + InvD[INV_CONV].inventoryY = 8; + else if (fn == CONV_BOTTOM) + InvD[INV_CONV].inventoryY = 150; +} + +void ConvPoly(HPOLYGON hPoly) { + thisConvPoly = hPoly; +} + +int convIcon(void) { + return thisConvIcon; +} + +void CloseDownConv(void) { + if (InventoryState == ACTIVE_INV && ino == INV_CONV) { + KillInventory(); + } +} + +void convHide(bool hide) { + int aniX, aniY; + int i; + + if (InventoryState == ACTIVE_INV && ino == INV_CONV) { + if (hide) { + for (i = 0; objArray[i] && i < MAX_WCOMP; i++) { + MultiAdjustXY(objArray[i], 2*SCREEN_WIDTH, 0); + } + for (i = 0; iconArray[i] && i < MAX_ICONS; i++) { + MultiAdjustXY(iconArray[i], 2*SCREEN_WIDTH, 0); + } + InventoryHidden = true; + + InvLabels(false, 0, 0); + } else { + InventoryHidden = false; + + for (i = 0; objArray[i] && i < MAX_WCOMP; i++) { + MultiAdjustXY(objArray[i], -2*SCREEN_WIDTH, 0); + } + + // Don't flash if items changed. If they have, will be redrawn anyway. + if (!ItemsChanged) { + for (i = 0; iconArray[i] && i < MAX_ICONS; i++) { + MultiAdjustXY(iconArray[i], -2*SCREEN_WIDTH, 0); + } + } + + GetCursorXY(&aniX, &aniY, false); + InvLabels(true, aniX, aniY); + } + } +} + +bool convHid(void) { + return InventoryHidden; +} + + +/**************************************************************************/ +/******************* Open and closing functions ***************************/ +/**************************************************************************/ + +/** + * Start up an inventory window. + */ + +void PopUpInventory(int invno) { + assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_CONF)); // Trying to open illegal inventory + + if (InventoryState == IDLE_INV) { + bOpenConf = false; // Better safe than sorry... + + DisableTags(); // Tags disabled during inventory + + if (invno == INV_CONV) { // Conversation window? + // Start conversation with permanent contents + memset(InvD[INV_CONV].ItemOrder, 0, MAX_ININV*sizeof(int)); + memcpy(InvD[INV_CONV].ItemOrder, Inv0Order, Num0Order*sizeof(int)); + InvD[INV_CONV].NoofItems = Num0Order; + thisConvIcon = 0; + } else if (invno == INV_CONF) { // Configuration window? + cd.selBox = NOBOX; + cd.pointBox = NOBOX; + } + + ino = invno; // The open inventory + + ItemsChanged = false; // Nothing changed + InvDragging = ID_NONE; // Not dragging + InventoryState = ACTIVE_INV; // Inventory actiive + InventoryHidden = false; // Not hidden + InventoryMaximised = InvD[ino].bMax; + if (invno != INV_CONF) // Configuration window? + ConstructInventory(FULL); // Draw it up + else { + ConstructInventory(CONF); // Draw it up + } + } +} + +void SetConfGlobals(PCONFINIT ci) { + InvD[INV_CONF].MinHicons = InvD[INV_CONF].MaxHicons = InvD[INV_CONF].NoofHicons = ci->h; + InvD[INV_CONF].MaxVicons = InvD[INV_CONF].MinVicons = InvD[INV_CONF].NoofVicons = ci->v; + InvD[INV_CONF].inventoryX = ci->x; + InvD[INV_CONF].inventoryY = ci->y; + cd.bExtraWin = ci->bExtraWin; + cd.Box = ci->Box; + cd.NumBoxes = ci->NumBoxes; + cd.ixHeading = ci->ixHeading; +} + +/** + * PopupConf + */ + +void PopUpConf(CONFTYPE type) { + int curX, curY; + + if (InventoryState != IDLE_INV) + return; + + InvD[INV_CONF].resizable = false; + InvD[INV_CONF].moveable = false; + + switch (type) { + case SAVE: + case LOAD: + if (type == SAVE) { + SetCursorScreenXY(262, 91); + SetConfGlobals(&ciSave); + cd.editableRgroup = true; + } else { + SetConfGlobals(&ciLoad); + cd.editableRgroup = false; + } + firstFile(0); + break; + + case QUIT: +#ifdef JAPAN + SetCursorScreenXY(180, 106); +#else + SetCursorScreenXY(180, 90); +#endif + SetConfGlobals(&ciQuit); + break; + + case RESTART: +#ifdef JAPAN + SetCursorScreenXY(180, 106); +#else + SetCursorScreenXY(180, 90); +#endif + SetConfGlobals(&ciRestart); + break; + + case OPTION: + SetConfGlobals(&ciOption); + break; + + case CONTROLS: + SetConfGlobals(&ciControl); + break; + + case SOUND: + SetConfGlobals(&ciSound); + break; + +#ifndef JAPAN + case SUBT: + SetConfGlobals(&ciSubtitles); + break; +#endif + + case TOPWIN: + SetConfGlobals(&ciTopWin); + ino = INV_CONF; + ConstructInventory(CONF); // Draw it up + InventoryState = BOGUS_INV; + return; + + default: + return; + } + + if (HeldItem != INV_NOICON) + DelAuxCursor(); // no longer aux cursor + + PopUpInventory(INV_CONF); + + if (type == SAVE || type == LOAD) + Select(0, false); +#ifndef JAPAN +#if !defined(USE_3FLAGS) || !defined(USE_4FLAGS) || !defined(USE_5FLAGS) + else if (type == SUBT) { +#ifdef USE_3FLAGS + // VERY quick dirty bodges + if (language == TXT_FRENCH) + Select(0, false); + else if (language == TXT_GERMAN) + Select(1, false); + else + Select(2, false); +#elif defined(USE_4FLAGS) + Select(language-1, false); +#else + Select(language, false); +#endif + } +#endif +#endif // JAPAN + + GetCursorXY(&curX, &curY, false); + InvCursor(IC_AREA, curX, curY); +} + +/** + * Close down an inventory window. + */ + +void KillInventory(void) { + if (objArray[0] != NULL) { + DumpObjArray(); + DumpDobjArray(); + DumpIconArray(); + } + + if (InventoryState == ACTIVE_INV) { + EnableTags(); + + InvD[ino].bMax = InventoryMaximised; + + UnHideCursorTrails(); + _vm->divertKeyInput(NULL); + } + + InventoryState = IDLE_INV; + + if (bOpenConf) { + bOpenConf = false; + PopUpConf(OPTION); + } else if (ino == INV_CONF) + InventoryIconCursor(); +} + +void CloseInventory(void) { + // If not active, ignore this + if (InventoryState != ACTIVE_INV) + return; + + // If hidden, a conversation action is still underway - ignore this + if (InventoryHidden) + return; + + // If conversation, this is a closeing event + if (ino == INV_CONV) + ConvAction(INV_CLOSEICON); + + KillInventory(); + + RestoreMainCursor(); +} + + + +/**************************************************************************/ +/************************ The inventory process ***************************/ +/**************************************************************************/ + +/** + * Redraws the icons if appropriate. Also handle button press/toggle effects + */ +void InventoryProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + while (1) { + CORO_SLEEP(1); // allow scheduling + + if (objArray[0] != NULL) { + if (ItemsChanged && ino != INV_CONF && !InventoryHidden) { + FillInInventory(); + + // Needed when clicking on scroll bar. + int curX, curY; + GetCursorXY(&curX, &curY, false); + InvCursor(IC_AREA, curX, curY); + + ItemsChanged = false; + } + if (ino != INV_CONF) { + for (int i = 0; i < MAX_ICONS; i++) { + if (iconArray[i] != NULL) + StepAnimScript(&iconAnims[i]); + } + } + if (InvDragging == ID_MDCONT) { + // Mixing desk control + int sval, index, *pival; + + index = cd.selBox & ~IS_MASK; + pival = cd.Box[index].ival; + sval = *pival; + + if (cd.selBox & IS_LEFT) { + *pival -= cd.Box[index].h; + if (*pival < 0) + *pival = 0; + } else if (cd.selBox & IS_RIGHT) { + *pival += cd.Box[index].h; + if (*pival > cd.Box[index].w) + *pival = cd.Box[index].w; + } + + if (sval != *pival) { + SlideMSlider(0, (cd.selBox & IS_RIGHT) ? S_TIMEUP : S_TIMEDN); + } + } + } + + if (g_buttonEffect.bButAnim) { + assert(g_buttonEffect.box); + if (g_buttonEffect.press) { + if (g_buttonEffect.box->boxType == AAGBUT || g_buttonEffect.box->boxType == ARSGBUT) + CORO_INVOKE_1(ButtonPress, g_buttonEffect.box); + switch (g_buttonEffect.box->boxFunc) { + case SAVEGAME: + KillInventory(); + InvSaveGame(); + break; + case LOADGAME: + KillInventory(); + InvLoadGame(); + break; + case IQUITGAME: + _vm->quitFlag = true; + break; + case CLOSEWIN: + KillInventory(); + break; + case OPENLOAD: + KillInventory(); + PopUpConf(LOAD); + break; + case OPENSAVE: + KillInventory(); + PopUpConf(SAVE); + break; + case OPENREST: + KillInventory(); + PopUpConf(RESTART); + break; + case OPENSOUND: + KillInventory(); + PopUpConf(SOUND); + break; + case OPENCONT: + KillInventory(); + PopUpConf(CONTROLS); + break; + #ifndef JAPAN + case OPENSUBT: + KillInventory(); + PopUpConf(SUBT); + break; + #endif + case OPENQUIT: + KillInventory(); + PopUpConf(QUIT); + break; + case INITGAME: + KillInventory(); + bRestart = true; + break; + #if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) + case CLANG: + if (!LanguageChange()) + KillInventory(); + break; + case RLANG: + KillInventory(); + break; + #endif + default: + break; + } + } else + CORO_INVOKE_1(ButtonToggle, g_buttonEffect.box); + + g_buttonEffect.bButAnim = false; + } + + } + CORO_END_CODE; +} + +/**************************************************************************/ +/*************** Drag stuff - Resizing and moving window ******************/ +/**************************************************************************/ + +/** + * Appears to find the nearest entry in slideStuff[] to the supplied + * y-coordinate. + */ +int NearestSlideY(int fity) { + int nearDist = 1000; + int thisDist; + int nearI = 0; // Index of nearest fit + int i = 0; + + do { + thisDist = ABS(slideStuff[i].y - fity); + if (thisDist < nearDist) { + nearDist = thisDist; + nearI = i; + } + } while (slideStuff[++i].n != -1); + return nearI; +} + +/** + * Gets called at the start and end of a drag on the slider, and upon + * y-movement during such a drag. + */ +void SlideSlider(int y, SSFN fn) { + static int newY = 0, lasti = 0; // FIXME: local static var + int gotoY, ati; + + // Only do this if there's a slider + if (!SlideObject) + return; + + switch (fn) { + case S_START: // Start of a drag on the slider + newY = slideY; + lasti = NearestSlideY(slideY); + break; + + case S_SLIDE: // Y-movement during drag + newY = newY + y; // New y-position + + if (newY < slideYmin) + gotoY = slideYmin; // Above top limit + else if (newY > slideYmax) + gotoY = slideYmax; // Below bottom limit + else + gotoY = newY; // Hunky-Dory + + // Move slider to new position + MultiMoveRelXY(SlideObject, 0, gotoY - slideY); + slideY = gotoY; + + // Re-draw icons if necessary + ati = NearestSlideY(slideY); + if (ati != lasti) { + InvD[ino].FirstDisp = slideStuff[ati].n; + assert(InvD[ino].FirstDisp >= 0); // negative first displayed + ItemsChanged = true; + lasti = ati; + } + break; + + case S_END: // End of a drag on the slider + // Draw icons from new start icon + ati = NearestSlideY(slideY); + InvD[ino].FirstDisp = slideStuff[ati].n; + ItemsChanged = true; + break; + + default: + break; + } +} + +/** + * Gets called at the start and end of a drag on the slider, and upon + * y-movement during such a drag. + */ + +void SlideCSlider(int y, SSFN fn) { + static int newY = 0; // FIXME: local static var + int gotoY; + int fc; + + // Only do this if there's a slider + if (!SlideObject) + return; + + switch (fn) { + case S_START: // Start of a drag on the slider + newY = slideY; + break; + + case S_SLIDE: // Y-movement during drag + newY = newY + y; // New y-position + + if (newY < slideYmin) + gotoY = slideYmin; // Above top limit + else if (newY > slideYmax) + gotoY = slideYmax; // Below bottom limit + else + gotoY = newY; // Hunky-Dory + + slideY = gotoY; + + fc = cd.fileBase; + firstFile((slideY-slideYmin)*(MAX_SFILES-NUM_SL_RGROUP)/(slideYmax-slideYmin)); + if (fc != cd.fileBase) { + AddBoxes(false); + fc -= cd.fileBase; + cd.selBox += fc; + if (cd.selBox < 0) + cd.selBox = 0; + else if (cd.selBox >= NUM_SL_RGROUP) + cd.selBox = NUM_SL_RGROUP-1; + Select(cd.selBox, true); + } + break; + + case S_END: // End of a drag on the slider + break; + + default: + break; + } +} + +/** + * Gets called at the start and end of a drag on a mixing desk slider, + * and upon x-movement during such a drag. + */ + +static void SlideMSlider(int x, SSFN fn) { + static int newX = 0; // FIXME: local static var + int gotoX; + int index, i; + + if (fn == S_END || fn == S_TIMEUP || fn == S_TIMEDN) + ; + else if (!(cd.selBox & IS_SLIDER)) + return; + + // Work out the indices + index = cd.selBox & ~IS_MASK; + for (i = 0; i < numMdSlides; i++) + if (mdSlides[i].num == index) + break; + assert(i < numMdSlides); + + switch (fn) { + case S_START: // Start of a drag on the slider + // can use index as a throw-away value + GetAniPosition(mdSlides[i].obj, &newX, &index); + lX = sX = newX; + break; + + case S_SLIDE: // X-movement during drag + if (x == 0) + return; + + newX = newX + x; // New x-position + + if (newX < mdSlides[i].min) + gotoX = mdSlides[i].min; // Below bottom limit + else if (newX > mdSlides[i].max) + gotoX = mdSlides[i].max; // Above top limit + else + gotoX = newX; // Hunky-Dory + + // Move slider to new position + MultiMoveRelXY(mdSlides[i].obj, gotoX - sX, 0); + sX = gotoX; + + if (lX != sX) { + *cd.Box[index].ival = (sX - mdSlides[i].min)*cd.Box[index].w/SLIDE_RANGE; + if (cd.Box[index].boxFunc == MIDIVOL) + SetMidiVolume(*cd.Box[index].ival); +#ifdef MAC_OPTIONS + if (cd.Box[index].boxFunc == MASTERVOL) + SetSystemVolume(*cd.Box[index].ival); + + if (cd.Box[index].boxFunc == SAMPVOL) + SetSampleVolume(*cd.Box[index].ival); +#endif + lX = sX; + } + break; + + case S_TIMEUP: + case S_TIMEDN: + gotoX = SLIDE_RANGE*(*cd.Box[index].ival)/cd.Box[index].w; + MultiSetAniX(mdSlides[i].obj, mdSlides[i].min+gotoX); + + if (cd.Box[index].boxFunc == MIDIVOL) + SetMidiVolume(*cd.Box[index].ival); +#ifdef MAC_OPTIONS + if (cd.Box[index].boxFunc == MASTERVOL) + SetSystemVolume(*cd.Box[index].ival); + + if (cd.Box[index].boxFunc == SAMPVOL) + SetSampleVolume(*cd.Box[index].ival); +#endif + break; + + case S_END: // End of a drag on the slider + AddBoxes(false); // Might change position slightly +#ifndef JAPAN + if (ino == INV_CONF && cd.Box == subtitlesBox) + Select(language, false); +#endif + break; + } +} + +/** + * Called from ChangeingSize() during re-sizing. + */ + +void GettingTaller(void) { + if (SuppV) { + Ychange += SuppV; + if (Ycompensate == 'T') + InvD[ino].inventoryY += SuppV; + SuppV = 0; + } + while (Ychange > (ITEM_HEIGHT+1) && InvD[ino].NoofVicons < InvD[ino].MaxVicons) { + Ychange -= (ITEM_HEIGHT+1); + InvD[ino].NoofVicons++; + if (Ycompensate == 'T') + InvD[ino].inventoryY -= (ITEM_HEIGHT+1); + } + if (InvD[ino].NoofVicons < InvD[ino].MaxVicons) { + SuppV = Ychange; + Ychange = 0; + if (Ycompensate == 'T') + InvD[ino].inventoryY -= SuppV; + } +} + +/** + * Called from ChangeingSize() during re-sizing. + */ + +void GettingShorter(void) { + int StartNvi = InvD[ino].NoofVicons; + int StartUv = SuppV; + + if (SuppV) { + Ychange += (SuppV - (ITEM_HEIGHT+1)); + InvD[ino].NoofVicons++; + SuppV = 0; + } + while (Ychange < -(ITEM_HEIGHT+1) && InvD[ino].NoofVicons > InvD[ino].MinVicons) { + Ychange += (ITEM_HEIGHT+1); + InvD[ino].NoofVicons--; + } + if (InvD[ino].NoofVicons > InvD[ino].MinVicons && Ychange) { + SuppV = (ITEM_HEIGHT+1) + Ychange; + InvD[ino].NoofVicons--; + Ychange = 0; + } + if (Ycompensate == 'T') + InvD[ino].inventoryY += (ITEM_HEIGHT+1)*(StartNvi - InvD[ino].NoofVicons) - (SuppV - StartUv); +} + +/** + * Called from ChangeingSize() during re-sizing. + */ + +void GettingWider(void) { + int StartNhi = InvD[ino].NoofHicons; + int StartUh = SuppH; + + if (SuppH) { + Xchange += SuppH; + SuppH = 0; + } + while (Xchange > (ITEM_WIDTH+1) && InvD[ino].NoofHicons < InvD[ino].MaxHicons) { + Xchange -= (ITEM_WIDTH+1); + InvD[ino].NoofHicons++; + } + if (InvD[ino].NoofHicons < InvD[ino].MaxHicons) { + SuppH = Xchange; + Xchange = 0; + } + if (Xcompensate == 'L') + InvD[ino].inventoryX += (ITEM_WIDTH+1)*(StartNhi - InvD[ino].NoofHicons) - (SuppH - StartUh); +} + +/** + * Called from ChangeingSize() during re-sizing. + */ + +void GettingNarrower(void) { + int StartNhi = InvD[ino].NoofHicons; + int StartUh = SuppH; + + if (SuppH) { + Xchange += (SuppH - (ITEM_WIDTH+1)); + InvD[ino].NoofHicons++; + SuppH = 0; + } + while (Xchange < -(ITEM_WIDTH+1) && InvD[ino].NoofHicons > InvD[ino].MinHicons) { + Xchange += (ITEM_WIDTH+1); + InvD[ino].NoofHicons--; + } + if (InvD[ino].NoofHicons > InvD[ino].MinHicons && Xchange) { + SuppH = (ITEM_WIDTH+1) + Xchange; + InvD[ino].NoofHicons--; + Xchange = 0; + } + if (Xcompensate == 'L') + InvD[ino].inventoryX += (ITEM_WIDTH+1)*(StartNhi - InvD[ino].NoofHicons) - (SuppH - StartUh); +} + + +/** + * Called from Xmovement()/Ymovement() during re-sizing. + */ + +void ChangeingSize(void) { + /* Make it taller or shorter if necessary. */ + if (Ychange > 0) + GettingTaller(); + else if (Ychange < 0) + GettingShorter(); + + /* Make it wider or narrower if necessary. */ + if (Xchange > 0) + GettingWider(); + else if (Xchange < 0) + GettingNarrower(); + + ConstructInventory(EMPTY); +} + +/** + * Called from cursor module when cursor moves while inventory is up. + */ + +void Xmovement(int x) { + int aniX, aniY; + int i; + + if (x && objArray[0] != NULL) { + switch (InvDragging) { + case ID_MOVE: + GetAniPosition(objArray[0], &InvD[ino].inventoryX, &aniY); + InvD[ino].inventoryX +=x; + MultiSetAniX(objArray[0], InvD[ino].inventoryX); + for (i = 1; objArray[i] && i < MAX_WCOMP; i++) + MultiMoveRelXY(objArray[i], x, 0); + for (i = 0; iconArray[i] && i < MAX_ICONS; i++) + MultiMoveRelXY(iconArray[i], x, 0); + break; + + case ID_LEFT: + case ID_TLEFT: + case ID_BLEFT: + Xchange -= x; + ChangeingSize(); + break; + + case ID_RIGHT: + case ID_TRIGHT: + case ID_BRIGHT: + Xchange += x; + ChangeingSize(); + break; + + case ID_NONE: + GetCursorXY(&aniX, &aniY, false); + InvCursor(IC_AREA, aniX, aniY); + break; + + case ID_MDCONT: + SlideMSlider(x, S_SLIDE); + break; + + default: + break; + } + } +} + +/** + * Called from cursor module when cursor moves while inventory is up. + */ + +void Ymovement(int y) { + int aniX, aniY; + int i; + + if (y && objArray[0] != NULL) { + switch (InvDragging) { + case ID_MOVE: + GetAniPosition(objArray[0], &aniX, &InvD[ino].inventoryY); + InvD[ino].inventoryY +=y; + MultiSetAniY(objArray[0], InvD[ino].inventoryY); + for (i = 1; objArray[i] && i < MAX_WCOMP; i++) + MultiMoveRelXY(objArray[i], 0, y); + for (i = 0; iconArray[i] && i < MAX_ICONS; i++) + MultiMoveRelXY(iconArray[i], 0, y); + break; + + case ID_SLIDE: + SlideSlider(y, S_SLIDE); + break; + + case ID_CSLIDE: + SlideCSlider(y, S_SLIDE); + break; + + case ID_BOTTOM: + case ID_BLEFT: + case ID_BRIGHT: + Ychange += y; + ChangeingSize(); + break; + + case ID_TOP: + case ID_TLEFT: + case ID_TRIGHT: + Ychange -= y; + ChangeingSize(); + break; + + case ID_NONE: + GetCursorXY(&aniX, &aniY, false); + InvCursor(IC_AREA, aniX, aniY); + break; + + default: + break; + } + } +} + +/** + * Called when a drag is commencing. + */ + +void InvDragStart(void) { + int curX, curY; // cursor's animation position + + GetCursorXY(&curX, &curY, false); + +/* +* Do something different for Save/Restore screens +*/ + if (ino == INV_CONF) { + int whichbox; + + whichbox = WhichInvBox(curX, curY, true); + + if (whichbox == IB_SLIDE) { + InvDragging = ID_CSLIDE; + SlideCSlider(0, S_START); + } else if (whichbox > 0 && (whichbox & IS_MASK)) { + InvDragging = ID_MDCONT; // Mixing desk control + cd.selBox = whichbox; + SlideMSlider(0, S_START); + } + return; + } + +/* +* Normal operation +*/ + switch (InvArea(curX, curY)) { + case I_MOVE: + if (InvD[ino].moveable) { + InvDragging = ID_MOVE; + } + break; + + case I_SLIDE: + InvDragging = ID_SLIDE; + SlideSlider(0, S_START); + break; + + case I_BOTTOM: + if (InvD[ino].resizable) { + Ychange = 0; + InvDragging = ID_BOTTOM; + Ycompensate = 'B'; + } + break; + + case I_TOP: + if (InvD[ino].resizable) { + Ychange = 0; + InvDragging = ID_TOP; + Ycompensate = 'T'; + } + break; + + case I_LEFT: + if (InvD[ino].resizable) { + Xchange = 0; + InvDragging = ID_LEFT; + Xcompensate = 'L'; + } + break; + + case I_RIGHT: + if (InvD[ino].resizable) { + Xchange = 0; + InvDragging = ID_RIGHT; + Xcompensate = 'R'; + } + break; + + case I_TLEFT: + if (InvD[ino].resizable) { + Ychange = 0; + Ycompensate = 'T'; + Xchange = 0; + Xcompensate = 'L'; + InvDragging = ID_TLEFT; + } + break; + + case I_TRIGHT: + if (InvD[ino].resizable) { + Ychange = 0; + Ycompensate = 'T'; + Xchange = 0; + Xcompensate = 'R'; + InvDragging = ID_TRIGHT; + } + break; + + case I_BLEFT: + if (InvD[ino].resizable) { + Ychange = 0; + Ycompensate = 'B'; + Xchange = 0; + Xcompensate = 'L'; + InvDragging = ID_BLEFT; + } + break; + + case I_BRIGHT: + if (InvD[ino].resizable) { + Ychange = 0; + Ycompensate = 'B'; + Xchange = 0; + Xcompensate = 'R'; + InvDragging = ID_BRIGHT; + } + break; + } +} + +/** + * Called when a drag is over. + */ + +void InvDragEnd(void) { + int curX, curY; // cursor's animation position + + GetCursorXY(&curX, &curY, false); + + if (InvDragging != ID_NONE) { + if (InvDragging == ID_SLIDE) { + SlideSlider(0, S_END); + } else if (InvDragging == ID_CSLIDE) { + ; // No action + } else if (InvDragging == ID_MDCONT) { + SlideMSlider(0, S_END); + } else if (InvDragging == ID_MOVE) { + ; // No action + } else { + // Were re-sizing. Redraw the whole thing. + DumpDobjArray(); + DumpObjArray(); + ConstructInventory(FULL); + + // If this was the maximised, it no longer is! + if (InventoryMaximised) { + InventoryMaximised = false; + InvD[ino].otherX = InvD[ino].inventoryX; + InvD[ino].otherY = InvD[ino].inventoryY; + } + } + InvDragging = ID_NONE; + } + + // Cursor could well now be inappropriate + InvCursor(IC_AREA, curX, curY); + + Xchange = Ychange = 0; // Probably no need, but does no harm! +} + + +/**************************************************************************/ +/************** Incoming events - further processing **********************/ +/**************************************************************************/ + +/** + * ConfAction + */ +void ConfAction(int i, bool dbl) { + + if (i >= 0) { + switch (cd.Box[i].boxType) { + case FLIP: + if (dbl) { + *(cd.Box[i].ival) ^= 1; // XOR with true + AddBoxes(false); + } + break; + + case TOGGLE: + if (!g_buttonEffect.bButAnim) { + g_buttonEffect.bButAnim = true; + g_buttonEffect.box = &cd.Box[i]; + g_buttonEffect.press = false; + } + break; + + case RGROUP: + if (dbl) { + // Already highlighted + switch (cd.Box[i].boxFunc) { + case SAVEGAME: + KillInventory(); + InvSaveGame(); + break; + case LOADGAME: + KillInventory(); + InvLoadGame(); + break; + default: + break; + } + } else { + Select(i, false); + } + break; + +#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) + case FRGROUP: + if (dbl) { + Select(i, false); + LanguageChange(); + } else { + Select(i, false); + } + break; +#endif + + case AAGBUT: + case ARSGBUT: + case ARSBUT: + case AABUT: + case AATBUT: + if (g_buttonEffect.bButAnim) + break; + + g_buttonEffect.bButAnim = true; + g_buttonEffect.box = &cd.Box[i]; + g_buttonEffect.press = true; + break; + default: + break; + } + } else { + ConfActionSpecial(i); + } +} + +static void ConfActionSpecial(int i) { + switch (i) { + case IB_NONE: + break; + case IB_UP: // Scroll up + if (cd.fileBase > 0) { + firstFile(cd.fileBase-1); + AddBoxes(true); + if (cd.selBox < NUM_SL_RGROUP-1) + cd.selBox += 1; + Select(cd.selBox, true); + } + break; + case IB_DOWN: // Scroll down + if (cd.fileBase < MAX_SFILES-NUM_SL_RGROUP) { + firstFile(cd.fileBase+1); + AddBoxes(true); + if (cd.selBox) + cd.selBox -= 1; + Select(cd.selBox, true); + } + break; + case IB_SLIDE_UP: + if (cd.fileBase > 0) { + firstFile(cd.fileBase-(NUM_SL_RGROUP-1)); + AddBoxes(true); + cd.selBox = 0; + Select(cd.selBox, true); + } + break; + case IB_SLIDE_DOWN: // Scroll down + if (cd.fileBase < MAX_SFILES-NUM_SL_RGROUP) { + firstFile(cd.fileBase+(NUM_SL_RGROUP-1)); + AddBoxes(true); + cd.selBox = NUM_SL_RGROUP-1; + Select(cd.selBox, true); + } + break; + } +} +// SLIDE_UP and SLIDE_DOWN on d click?????? + +void InvPutDown(int index) { + int aniX, aniY; + // index is the drop position + int hiIndex; // Current position of held item (if in) + + // Find where the held item is positioned in this inventory (if it is) + for (hiIndex = 0; hiIndex < InvD[ino].NoofItems; hiIndex++) + if (InvD[ino].ItemOrder[hiIndex] == HeldItem) + break; + + // If drop position would leave a gap, move it up + if (index >= InvD[ino].NoofItems) { + if (hiIndex == InvD[ino].NoofItems) // Not in, add it + index = InvD[ino].NoofItems; + else + index = InvD[ino].NoofItems - 1; + } + + if (hiIndex == InvD[ino].NoofItems) { // Not in, add it + if (InvD[ino].NoofItems < InvD[ino].MaxInvObj) { + InvD[ino].NoofItems++; + + // Don't leave it in the other inventory! + if (InventoryPos(HeldItem) != INV_HELDNOTIN) + RemFromInventory(ino == INV_1 ? INV_2 : INV_1, HeldItem); + } else { + // No room at the inn! + return; + } + } + + // Position it in the inventory + if (index < hiIndex) { + memmove(&InvD[ino].ItemOrder[index + 1], &InvD[ino].ItemOrder[index], (hiIndex-index)*sizeof(int)); + InvD[ino].ItemOrder[index] = HeldItem; + } else if (index > hiIndex) { + memmove(&InvD[ino].ItemOrder[hiIndex], &InvD[ino].ItemOrder[hiIndex+1], (index-hiIndex)*sizeof(int)); + InvD[ino].ItemOrder[index] = HeldItem; + } else { + InvD[ino].ItemOrder[index] = HeldItem; + } + + HeldItem = INV_NOICON; + ItemsChanged = true; + DelAuxCursor(); + RestoreMainCursor(); + GetCursorXY(&aniX, &aniY, false); + InvCursor(IC_DROP, aniX, aniY); +} + +void InvPdProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + GetToken(TOKEN_LEFT_BUT); + CORO_SLEEP(dclickSpeed+1); + FreeToken(TOKEN_LEFT_BUT); + + // get the stuff copied to process when it was created + int *pindex = (int *)ProcessGetParamsSelf(); + + InvPutDown(*pindex); + + CORO_END_CODE; +} + +void InvPickup(int index) { + PINV_OBJECT invObj; + + if (index != INV_NOICON) { + if (HeldItem == INV_NOICON && InvD[ino].ItemOrder[index] && InvD[ino].ItemOrder[index] != HeldItem) { + // Pick-up + invObj = findInvObject(InvD[ino].ItemOrder[index]); + if (invObj->hScript) + RunInvTinselCode(invObj, WALKTO, INV_PICKUP, index); + } else if (HeldItem != INV_NOICON) { // Put icon down + // Put-down + invObj = findInvObject(HeldItem); + + if (invObj->attribute & IO_DROPCODE && invObj->hScript) + RunInvTinselCode(invObj, PUTDOWN, INV_PICKUP, index); + + else if (!(invObj->attribute & IO_ONLYINV1 && ino !=INV_1) + && !(invObj->attribute & IO_ONLYINV2 && ino !=INV_2)) + CoroutineInstall(PID_TCODE, InvPdProcess, &index, sizeof(index)); + } + } +} + +/** + * Pick up/put down icon + */ +void InvSLClick(void) { + int i; + int aniX, aniY; // Cursor's animation position + + GetCursorXY(&aniX, &aniY, false); + + switch (InvArea(aniX, aniY)) { + case I_NOTIN: + if (ino == INV_CONV) + ConvAction(INV_CLOSEICON); + KillInventory(); + break; + + case I_SLIDE_UP: + if (InvD[ino].NoofVicons == 1) + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + for (i = 1; i < InvD[ino].NoofVicons; i++) + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + if (InvD[ino].FirstDisp < 0) + InvD[ino].FirstDisp = 0; + ItemsChanged = true; + break; + + case I_UP: + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + if (InvD[ino].FirstDisp < 0) + InvD[ino].FirstDisp = 0; + ItemsChanged = true; + break; + + case I_SLIDE_DOWN: + if (InvD[ino].NoofVicons == 1) + if (InvD[ino].FirstDisp + InvD[ino].NoofHicons*InvD[ino].NoofVicons < InvD[ino].NoofItems) + InvD[ino].FirstDisp += InvD[ino].NoofHicons; + for (i = 1; i < InvD[ino].NoofVicons; i++) { + if (InvD[ino].FirstDisp + InvD[ino].NoofHicons*InvD[ino].NoofVicons < InvD[ino].NoofItems) + InvD[ino].FirstDisp += InvD[ino].NoofHicons; + } + ItemsChanged = true; + break; + + case I_DOWN: + if (InvD[ino].FirstDisp + InvD[ino].NoofHicons*InvD[ino].NoofVicons < InvD[ino].NoofItems) { + InvD[ino].FirstDisp += InvD[ino].NoofHicons; + ItemsChanged = true; + } + break; + + case I_BODY: + if (ino == INV_CONF) { + if (!InventoryHidden) + ConfAction(WhichInvBox(aniX, aniY, false), false); + } else { + i = InvItem(&aniX, &aniY, false); + + // Special bodge for David, to + // cater for drop in dead space between icons + if (i == INV_NOICON && HeldItem != INV_NOICON && (ino == INV_1 || ino == INV_2)) { + aniX += 1; // 1 to the right + i = InvItem(&aniX, &aniY, false); + if (i == INV_NOICON) { + aniX -= 1; // 1 down + aniY += 1; + i = InvItem(&aniX, &aniY, false); + if (i == INV_NOICON) { + aniX += 1; // 1 down-right + i = InvItem(&aniX, &aniY, false); + } + } + } + + if (ino == INV_CONV) { + ConvAction(i); + } else + InvPickup(i); + } + break; + } +} + +void InvAction(void) { + int index; + PINV_OBJECT invObj; + int aniX, aniY; + int i; + + GetCursorXY(&aniX, &aniY, false); + + switch (InvArea(aniX, aniY)) { + case I_BODY: + if (ino == INV_CONF) { + if (!InventoryHidden) + ConfAction(WhichInvBox(aniX, aniY, false), true); + } else if (ino == INV_CONV) { + index = InvItem(&aniX, &aniY, false); + ConvAction(index); + } else { + index = InvItem(&aniX, &aniY, false); + if (index != INV_NOICON) { + if (InvD[ino].ItemOrder[index] && InvD[ino].ItemOrder[index] != HeldItem) { + invObj = findInvObject(InvD[ino].ItemOrder[index]); + if (invObj->hScript) + RunInvTinselCode(invObj, ACTION, INV_ACTION, index); + } + } + } + break; + + case I_MOVE: // Maximise/unmaximise inventory + if (!InvD[ino].resizable) + break; + + if (!InventoryMaximised) { + InvD[ino].sNoofHicons = InvD[ino].NoofHicons; + InvD[ino].sNoofVicons = InvD[ino].NoofVicons; + InvD[ino].NoofHicons = InvD[ino].MaxHicons; + InvD[ino].NoofVicons = InvD[ino].MaxVicons; + InventoryMaximised = true; + + i = InvD[ino].inventoryX; + InvD[ino].inventoryX = InvD[ino].otherX; + InvD[ino].otherX = i; + i = InvD[ino].inventoryY; + InvD[ino].inventoryY = InvD[ino].otherY; + InvD[ino].otherY = i; + } else { + InvD[ino].NoofHicons = InvD[ino].sNoofHicons; + InvD[ino].NoofVicons = InvD[ino].sNoofVicons; + InventoryMaximised = false; + + i = InvD[ino].inventoryX; + InvD[ino].inventoryX = InvD[ino].otherX; + InvD[ino].otherX = i; + i = InvD[ino].inventoryY; + InvD[ino].inventoryY = InvD[ino].otherY; + InvD[ino].otherY = i; + } + + // Delete current, and re-draw + DumpDobjArray(); + DumpObjArray(); + ConstructInventory(FULL); + break; + + case I_UP: + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + if (InvD[ino].FirstDisp < 0) + InvD[ino].FirstDisp = 0; + ItemsChanged = true; + break; + case I_DOWN: + if (InvD[ino].FirstDisp + InvD[ino].NoofHicons*InvD[ino].NoofVicons < InvD[ino].NoofItems) { + InvD[ino].FirstDisp += InvD[ino].NoofHicons; + ItemsChanged = true; + } + break; + } + +} + + +void InvLook(void) { + int index; + PINV_OBJECT invObj; + int aniX, aniY; + + GetCursorXY(&aniX, &aniY, false); + + switch (InvArea(aniX, aniY)) { + case I_BODY: + index = InvItem(&aniX, &aniY, false); + if (index != INV_NOICON) { + if (InvD[ino].ItemOrder[index] && InvD[ino].ItemOrder[index] != HeldItem) { + invObj = findInvObject(InvD[ino].ItemOrder[index]); + if (invObj->hScript) + RunInvTinselCode(invObj, LOOK, INV_LOOK, index); + } + } + break; + + case I_NOTIN: + if (ino == INV_CONV) + ConvAction(INV_CLOSEICON); + KillInventory(); + break; + } +} + + +/**************************************************************************/ +/********************* Incoming events ************************************/ +/**************************************************************************/ + + +void ButtonToInventory(BUTEVENT be) { + if (InventoryHidden) + return; + + switch (be) { + case INV_PICKUP: // BE_SLEFT + InvSLClick(); + break; + + case INV_LOOK: // BE_SRIGHT + if (IsConfWindow()) + InvSLClick(); + else + InvLook(); + break; + + case INV_ACTION: // BE_DLEFT + if (InvDragging != ID_MDCONT) + InvDragEnd(); + InvAction(); + break; + + case BE_LDSTART: // Left drag start + InvDragStart(); + break; + + case BE_LDEND: // Left drag end + InvDragEnd(); + break; + +// case BE_DLEFT: // Double click left (also ends left drag) +// ButtonToInventory(LDEND); +// break; + + case BE_RDSTART: + case BE_RDEND: + case BE_UNKNOWN: + break; + default: + break; + } +} + +void KeyToInventory(KEYEVENT ke) { + int i; + + switch (ke) { + case ESC_KEY: + if (InventoryState == ACTIVE_INV && ino == INV_CONF && cd.Box != optionBox) + bOpenConf = true; + CloseInventory(); + break; + + case PGDN_KEY: + if (ino == INV_CONF) { + // Only act if load or save screen + if (cd.Box != loadBox && cd.Box != saveBox) + break; + + ConfActionSpecial(IB_SLIDE_DOWN); + } else { + // This code is a copy of SLClick on IB_SLIDE_DOWN + // TODO: So share this duplicate code + if (InvD[ino].NoofVicons == 1) + if (InvD[ino].FirstDisp + InvD[ino].NoofHicons*InvD[ino].NoofVicons < InvD[ino].NoofItems) + InvD[ino].FirstDisp += InvD[ino].NoofHicons; + for (i = 1; i < InvD[ino].NoofVicons; i++) { + if (InvD[ino].FirstDisp + InvD[ino].NoofHicons*InvD[ino].NoofVicons < InvD[ino].NoofItems) + InvD[ino].FirstDisp += InvD[ino].NoofHicons; + } + ItemsChanged = true; + } + break; + + case PGUP_KEY: + if (ino == INV_CONF) { + // Only act if load or save screen + if (cd.Box != loadBox && cd.Box != saveBox) + break; + + ConfActionSpecial(IB_SLIDE_UP); + } else { + // This code is a copy of SLClick on I_SLIDE_UP + // TODO: So share this duplicate code + if (InvD[ino].NoofVicons == 1) + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + for (i = 1; i < InvD[ino].NoofVicons; i++) + InvD[ino].FirstDisp -= InvD[ino].NoofHicons; + if (InvD[ino].FirstDisp < 0) + InvD[ino].FirstDisp = 0; + ItemsChanged = true; + } + break; + + case HOME_KEY: + if (ino == INV_CONF) { + // Only act if load or save screen + if (cd.Box != loadBox && cd.Box != saveBox) + break; + + firstFile(0); + AddBoxes(true); + cd.selBox = 0; + Select(cd.selBox, true); + } else { + InvD[ino].FirstDisp = 0; + ItemsChanged = true; + } + break; + + case END_KEY: + if (ino == INV_CONF) { + // Only act if load or save screen + if (cd.Box != loadBox && cd.Box != saveBox) + break; + + firstFile(MAX_SFILES); // Will get reduced to appropriate value + AddBoxes(true); + cd.selBox = 0; + Select(cd.selBox, true); + } else { + InvD[ino].FirstDisp = InvD[ino].NoofItems - InvD[ino].NoofHicons*InvD[ino].NoofVicons; + if (InvD[ino].FirstDisp < 0) + InvD[ino].FirstDisp = 0; + ItemsChanged = true; + } + break; + + default: + error("We're at KeyToInventory(), with default"); + } +} + +/**************************************************************************/ +/************************* Odds and Ends **********************************/ +/**************************************************************************/ + +/** + * Called from Glitter function invdepict() + * Changes (permanently) the animation film for that object. + */ + +void invObjectFilm(int object, SCNHANDLE hFilm) { + PINV_OBJECT invObj; + + invObj = findInvObject(object); + invObj->hFilm = hFilm; + + if (HeldItem != object) + ItemsChanged = true; +} + +/** + * (Un)serialize the inventory data for save/restore game. + */ + +void syncInvInfo(Serializer &s) { + for (int i = 0; i < NUM_INV; i++) { + s.syncAsSint32LE(InvD[i].MinHicons); + s.syncAsSint32LE(InvD[i].MinVicons); + s.syncAsSint32LE(InvD[i].MaxHicons); + s.syncAsSint32LE(InvD[i].MaxVicons); + s.syncAsSint32LE(InvD[i].NoofHicons); + s.syncAsSint32LE(InvD[i].NoofVicons); + for (int j = 0; j < MAX_ININV; j++) { + s.syncAsSint32LE(InvD[i].ItemOrder[j]); + } + s.syncAsSint32LE(InvD[i].NoofItems); + s.syncAsSint32LE(InvD[i].FirstDisp); + s.syncAsSint32LE(InvD[i].inventoryX); + s.syncAsSint32LE(InvD[i].inventoryY); + s.syncAsSint32LE(InvD[i].otherX); + s.syncAsSint32LE(InvD[i].otherY); + s.syncAsSint32LE(InvD[i].MaxInvObj); + s.syncAsSint32LE(InvD[i].hInvTitle); + s.syncAsSint32LE(InvD[i].resizable); + s.syncAsSint32LE(InvD[i].moveable); + s.syncAsSint32LE(InvD[i].sNoofHicons); + s.syncAsSint32LE(InvD[i].sNoofVicons); + s.syncAsSint32LE(InvD[i].bMax); + } +} + +/**************************************************************************/ +/************************ Initialisation stuff ****************************/ +/**************************************************************************/ + +/** + * Called from PlayGame(), stores handle to inventory objects' data - + * its id, animation film and Glitter script. + */ +// Note: the SCHANDLE type here has been changed to a void* +void RegisterIcons(void *cptr, int num) { + numObjects = num; + pio = (PINV_OBJECT) cptr; +} + +/** + * Called from Glitter function 'dec_invw()' - Declare the bits that the + * inventory windows are constructed from, and special cursors. + */ + +void setInvWinParts(SCNHANDLE hf) { +#ifdef DEBUG + const FILM *pfilm; +#endif + + winPartsf = hf; + +#ifdef DEBUG + pfilm = (const FILM *)LockMem(hf); + assert(FROM_LE_32(pfilm->numreels) >= HOPEDFORREELS); // not as many reels as expected +#endif +} + +/** + * Called from Glitter function 'dec_flags()' - Declare the language + * flag films + */ + +void setFlagFilms(SCNHANDLE hf) { +#ifdef DEBUG + const FILM *pfilm; +#endif + + flagFilm = hf; + +#ifdef DEBUG + pfilm = (const FILM *)LockMem(hf); + assert(FROM_LE_32(pfilm->numreels) >= HOPEDFORFREELS); // not as many reels as expected +#endif +} + +void setConfigStrings(SCNHANDLE *tp) { + memcpy(configStrings, tp, sizeof(configStrings)); +} + +/** + * Called from Glitter functions: dec_convw()/dec_inv1()/dec_inv2() + * - Declare the heading text and dimensions etc. + */ + +void idec_inv(int num, SCNHANDLE text, int MaxContents, + int MinWidth, int MinHeight, + int StartWidth, int StartHeight, + int MaxWidth, int MaxHeight, + int startx, int starty, bool moveable) { + if (MaxWidth > MAXHICONS) + MaxWidth = MAXHICONS; // Max window width + if (MaxHeight > MAXVICONS) + MaxHeight = MAXVICONS; // Max window height + if (MaxContents > MAX_ININV) + MaxContents = MAX_ININV; // Max contents + + if (StartWidth > MaxWidth) + StartWidth = MaxWidth; + if (StartHeight > MaxHeight) + StartHeight = MaxHeight; + + InventoryState = IDLE_INV; + + InvD[num].MaxHicons = MaxWidth; + InvD[num].MinHicons = MinWidth; + InvD[num].MaxVicons = MaxHeight; + InvD[num].MinVicons = MinHeight; + + InvD[num].NoofHicons = StartWidth; + InvD[num].NoofVicons = StartHeight; + + memset(InvD[num].ItemOrder, 0, sizeof(InvD[num].ItemOrder)); + InvD[num].NoofItems = 0; + + InvD[num].FirstDisp = 0; + + InvD[num].inventoryX = startx; + InvD[num].inventoryY = starty; + InvD[num].otherX = 21; + InvD[num].otherY = 15; + + InvD[num].MaxInvObj = MaxContents; + + InvD[num].hInvTitle = text; + + if (MaxWidth != MinWidth && MaxHeight != MinHeight) + InvD[num].resizable = true; + + InvD[num].moveable = moveable; + + InvD[num].bMax = false; +} + +/** + * Called from Glitter functions: dec_convw()/dec_inv1()/dec_inv2() + * - Declare the heading text and dimensions etc. + */ + +void idec_convw(SCNHANDLE text, int MaxContents, + int MinWidth, int MinHeight, + int StartWidth, int StartHeight, + int MaxWidth, int MaxHeight) { + idec_inv(INV_CONV, text, MaxContents, MinWidth, MinHeight, + StartWidth, StartHeight, MaxWidth, MaxHeight, + 20, 8, true); +} + +/** + * Called from Glitter functions: dec_convw()/dec_inv1()/dec_inv2() + * - Declare the heading text and dimensions etc. + */ + +void idec_inv1(SCNHANDLE text, int MaxContents, + int MinWidth, int MinHeight, + int StartWidth, int StartHeight, + int MaxWidth, int MaxHeight) { + idec_inv(INV_1, text, MaxContents, MinWidth, MinHeight, + StartWidth, StartHeight, MaxWidth, MaxHeight, + 100, 100, true); +} + +/** + * Called from Glitter functions: dec_convw()/dec_inv1()/dec_inv2() + * - Declare the heading text and dimensions etc. + */ + +void idec_inv2(SCNHANDLE text, int MaxContents, + int MinWidth, int MinHeight, + int StartWidth, int StartHeight, + int MaxWidth, int MaxHeight) { + idec_inv(INV_2, text, MaxContents, MinWidth, MinHeight, + StartWidth, StartHeight, MaxWidth, MaxHeight, + 100, 100, true); +} + +int InvGetLimit(int invno) { + assert(invno == INV_1 || invno == INV_2); // only INV_1 and INV_2 supported + + return InvD[invno].MaxInvObj; +} + +void InvSetLimit(int invno, int MaxContents) { + assert(invno == INV_1 || invno == INV_2); // only INV_1 and INV_2 supported + assert(MaxContents >= InvD[invno].NoofItems); // can't reduce maximum contents below current contents + + if (MaxContents > MAX_ININV) + MaxContents = MAX_ININV; // Max contents + + InvD[invno].MaxInvObj = MaxContents; +} + +void InvSetSize(int invno, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight) { + assert(invno == INV_1 || invno == INV_2); // only INV_1 and INV_2 supported + + if (StartWidth > MaxWidth) + StartWidth = MaxWidth; + if (StartHeight > MaxHeight) + StartHeight = MaxHeight; + + InvD[invno].MaxHicons = MaxWidth; + InvD[invno].MinHicons = MinWidth; + InvD[invno].MaxVicons = MaxHeight; + InvD[invno].MinVicons = MinHeight; + + InvD[invno].NoofHicons = StartWidth; + InvD[invno].NoofVicons = StartHeight; + + if (MaxWidth != MinWidth && MaxHeight != MinHeight) + InvD[invno].resizable = true; + else + InvD[invno].resizable = false; + + InvD[invno].bMax = false; +} + +/**************************************************************************/ + +bool IsTopWindow(void) { + return (InventoryState == BOGUS_INV); +} + + +bool IsConfWindow(void) { + return (InventoryState == ACTIVE_INV && ino == INV_CONF); +} + + +bool IsConvWindow(void) { + return (InventoryState == ACTIVE_INV && ino == INV_CONV); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/inventory.h b/engines/tinsel/inventory.h new file mode 100644 index 0000000000..6b0c10e3de --- /dev/null +++ b/engines/tinsel/inventory.h @@ -0,0 +1,143 @@ + +/* 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$ + * + * Inventory related functions + */ + +#ifndef TINSEL_INVENTORY_H // prevent multiple includes +#define TINSEL_INVENTORY_H + +#include "tinsel/dw.h" +#include "tinsel/events.h" // for KEYEVENT, BUTEVENT + +namespace Tinsel { + +class Serializer; + +enum { + INV_OPEN = -1, + INV_CONV = 0, + INV_1 = 1, + INV_2 = 2, + INV_CONF = 3, + + NUM_INV = 4 +}; + +/** structure of each inventory object */ +struct INV_OBJECT { + int32 id; // inventory objects id + SCNHANDLE hFilm; // inventory objects animation film + SCNHANDLE hScript; // inventory objects event handling script + int32 attribute; // inventory object's attribute +}; +typedef INV_OBJECT *PINV_OBJECT; + +void PopUpInventory(int invno); + +enum CONFTYPE { + SAVE, LOAD, QUIT, OPTION, RESTART, SOUND, CONTROLS, SUBT, TOPWIN +}; + +void PopUpConf(CONFTYPE type); + + +void Xmovement(int x); +void Ymovement(int y); + +void ButtonToInventory(BUTEVENT be); + +void KeyToInventory(KEYEVENT ke); + + +int WhichItemHeld(void); + +void HoldItem(int item); +void DropItem(int item); +void AddToInventory(int invno, int icon, bool hold); +bool RemFromInventory(int invno, int icon); + + +void RegisterIcons(void *cptr, int num); + +void idec_convw(SCNHANDLE text, int MaxContents, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight); +void idec_inv1(SCNHANDLE text, int MaxContents, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight); +void idec_inv2(SCNHANDLE text, int MaxContents, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight); + +bool InventoryActive(void); + +void AddIconToPermanentDefaultList(int icon); + +void convPos(int bpos); +void ConvPoly(HPOLYGON hp); +int convIcon(void); +void CloseDownConv(void); +void convHide(bool hide); +bool convHid(void); + +enum { + INV_NOICON = -1, + INV_CLOSEICON = -2, + INV_OPENICON = -3, + INV_HELDNOTIN = -4 +}; + +void ConvAction(int index); + +void InventoryIconCursor(void); + +void setInvWinParts(SCNHANDLE hf); +void setFlagFilms(SCNHANDLE hf); +void setConfigStrings(SCNHANDLE *tp); + +int InvItem(int *x, int *y, bool update); +int InvItemId(int x, int y); + +int InventoryPos(int num); + +bool IsInInventory(int object, int invnum); + +void KillInventory(void); + +void invObjectFilm(int object, SCNHANDLE hFilm); + +void syncInvInfo(Serializer &s); + +int InvGetLimit(int invno); +void InvSetLimit(int invno, int n); +void InvSetSize(int invno, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight); + +int WhichInventoryOpen(void); + +bool IsTopWindow(void); +bool IsConfWindow(void); +bool IsConvWindow(void); + +} // end of namespace Tinsel + +#endif /* TINSEL_INVENTRY_H */ diff --git a/engines/tinsel/mareels.cpp b/engines/tinsel/mareels.cpp new file mode 100644 index 0000000000..4c64eaf091 --- /dev/null +++ b/engines/tinsel/mareels.cpp @@ -0,0 +1,132 @@ +/* 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$ + * + * Functions to set up moving actors' reels. + */ + +#include "tinsel/pcode.h" // For D_UP, D_DOWN +#include "tinsel/rince.h" + +#include "common/util.h" + +namespace Tinsel { + +//----------------- LOCAL GLOBAL DATA -------------------- + +enum { + NUM_INTERVALS = NUM_MAINSCALES - 1, + + // 2 for up and down, 3 allow enough entries for 3 fully subscribed moving actors' worth + MAX_SCRENTRIES = NUM_INTERVALS*2*3 +}; + +struct SCIdataStruct { + int actor; + int scale; + int direction; + SCNHANDLE reels[4]; +}; + +static SCIdataStruct SCIdata[MAX_SCRENTRIES]; + +static int scrEntries = 0; + +/** + * Return handle to actor's talk reel at present scale and direction. + */ +SCNHANDLE GetMactorTalkReel(PMACTOR pActor, TFTYPE dirn) { + assert(1 <= pActor->scale && pActor->scale <= TOTAL_SCALES); + switch (dirn) { + case TF_NONE: + return pActor->TalkReels[pActor->scale-1][pActor->dirn]; + + case TF_UP: + return pActor->TalkReels[pActor->scale-1][AWAY]; + + case TF_DOWN: + return pActor->TalkReels[pActor->scale-1][FORWARD]; + + case TF_LEFT: + return pActor->TalkReels[pActor->scale-1][LEFTREEL]; + + case TF_RIGHT: + return pActor->TalkReels[pActor->scale-1][RIGHTREEL]; + + default: + error("GetMactorTalkReel() - illegal direction!"); + } +} + +/** + * scalingreels + */ +void setscalingreels(int actor, int scale, int direction, + SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away) { + assert(scale >= 1 && scale <= NUM_MAINSCALES); // invalid scale + assert(!(scale == 1 && direction == D_UP) && + !(scale == NUM_MAINSCALES && direction == D_DOWN)); // illegal direction from scale + + assert(scrEntries < MAX_SCRENTRIES); // Scaling reels limit reached! + + SCIdata[scrEntries].actor = actor; + SCIdata[scrEntries].scale = scale; + SCIdata[scrEntries].direction = direction; + SCIdata[scrEntries].reels[LEFTREEL] = left; + SCIdata[scrEntries].reels[RIGHTREEL] = right; + SCIdata[scrEntries].reels[FORWARD] = forward; + SCIdata[scrEntries].reels[AWAY] = away; + scrEntries++; +} + +/** + * ScalingReel + */ +SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRREEL reel) { + int d; // Direction + + // The smaller the number, the bigger the scale + if (scale1 < scale2) + d = D_DOWN; + else + d = D_UP; + + for (int i = 0; i < scrEntries; i++) { + if (SCIdata[i].actor == ano && SCIdata[i].scale == scale1 && SCIdata[i].direction == d) { + if (SCIdata[i].reels[reel] == TF_NONE) + return 0; + else + return SCIdata[i].reels[reel]; + } + } + return 0; +} + +/** + * RebootScalingReels + */ +void RebootScalingReels(void) { + scrEntries = 0; + memset(SCIdata, 0, sizeof(SCIdata)); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/module.mk b/engines/tinsel/module.mk new file mode 100644 index 0000000000..b00afcddbc --- /dev/null +++ b/engines/tinsel/module.mk @@ -0,0 +1,52 @@ +MODULE := engines/tinsel + +MODULE_OBJS = \ + actors.o \ + anim.o \ + background.o \ + bg.o \ + cliprect.o \ + config.o \ + cursor.o \ + debugger.o \ + detection.o \ + effect.o \ + events.o \ + faders.o \ + font.o \ + graphics.o \ + handle.o \ + heapmem.o \ + inventory.o \ + mareels.o \ + move.o \ + multiobj.o \ + music.o \ + object.o \ + palette.o \ + pcode.o \ + pdisplay.o \ + play.o \ + polygons.o \ + rince.o \ + saveload.o \ + savescn.o \ + scene.o \ + sched.o \ + scn.o \ + scroll.o \ + sound.o \ + strres.o \ + text.o \ + timers.o \ + tinlib.o \ + tinsel.o \ + token.o + +# This module can be built as a plugin +ifeq ($(ENABLE_TINSEL), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/tinsel/move.cpp b/engines/tinsel/move.cpp new file mode 100644 index 0000000000..803bc5fd7b --- /dev/null +++ b/engines/tinsel/move.cpp @@ -0,0 +1,1618 @@ +/* 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$ + * + * Handles walking and use of the path system. + * + * Contains the dodgiest code in the whole system. + */ + +#include "tinsel/actors.h" +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/graphics.h" +#include "tinsel/move.h" +#include "tinsel/multiobj.h" // multi-part object defintions etc. +#include "tinsel/object.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/scroll.h" +#include "tinsel/tinlib.h" // For stand() + +namespace Tinsel { + +//----------------- DEVELOPMENT OPTIONS -------------------- + +#define SLOW_RINCE_DOWN 0 + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in BG.C +extern int BackgroundWidth(void); +extern int BackgroundHeight(void); + + +// in POLYGONS.C +// Deliberatley defined here, and not in polygons.h +HPOLYGON InitExtraBlock(PMACTOR ca, PMACTOR ta); + +//----------------- LOCAL DEFINES -------------------- + +#define XMDIST 4 +#define XHMDIST 2 +#define YMDIST 2 +#define YHMDIST 2 + +#define XTHERE 1 +#define XRESTRICT 2 +#define YTHERE 4 +#define YRESTRICT 8 +#define STUCK 16 + +#define LEAVING_PATH 0x100 +#define ENTERING_BLOCK 0x200 +#define ENTERING_MBLOCK 0x400 + +#define ALL_SORTED 1 +#define NOT_SORTED 0 + + +//----------------- LOCAL GLOBAL DATA -------------------- + +#if SLOW_RINCE_DOWN +static int Interlude = 0; // For slowing down walking, for testing +static int BogusVar = 0; // For slowing down walking, for testing +#endif + +static int32 DefaultRefer = 0; +static int hSlowVar = 0; // used by MoveActor() + + +//----------------- FORWARD REFERENCES -------------------- + +static void NewCoOrdinates(int fromx, int fromy, int *targetX, int *targetY, + int *newx, int *newy, int *s1, int *s2, HPOLYGON *hS2p, + bool bOver, bool bBodge, + PMACTOR pActor, PMACTOR *collisionActor = 0); + + +#if SLOW_RINCE_DOWN +/** + * AddInterlude + */ + +void AddInterlude(int n) { + Interlude += n; + if (Interlude < 0) + Interlude = 0; +} +#endif + +/** + * Given (x, y) of a click within a path polygon, checks that the + * co-ordinates are not within a blocking polygon. If it is not, the + * destination is the click point, otherwise tries to find a legal point + * below or above the click point. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int ClickedOnPath(int clickX, int clickY, int *ptgtX, int *ptgtY) { + int Loffset, Toffset; + int i; + + /*-------------------------------------- + Clicked within a path, + go to where requested unless blocked. + --------------------------------------*/ + if (InPolygon(clickX, clickY, BLOCKING) == NOPOLY) { + // Not in a blocking polygon - go to where requested. + *ptgtX = clickX; + *ptgtY = clickY; + } else { + /*------------------------------------------------------ + In a Blocking polygon - try searching down and up. + If still nowhere (for now) give up! + ------------------------------------------------------*/ + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + for (i = clickY+1; i < SCREEN_HEIGHT + Toffset; i++) { + // Don't leave the path system + if (InPolygon(clickX, i, PATH) == NOPOLY) { + i = SCREEN_HEIGHT; + break; + } + if (InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + } + if (i == SCREEN_HEIGHT) { + for (i = clickY-1; i >= Toffset; i--) { + // Don't leave the path system + if (InPolygon(clickX, i, PATH) == NOPOLY) { + i = -1; + break; + } + if (InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + } + } + if (i < 0) { + return ALL_SORTED; + } + } + return NOT_SORTED; +} + +/** + * Given (x, y) of a click within a referral polygon, works out the + * destination according to the referral type. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int ClickedOnRefer(HPOLYGON hRefpoly, int clickX, int clickY, int *ptgtX, int *ptgtY) { + int i; + int end; // Extreme of the scene + int Loffset, Toffset; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + *ptgtX = *ptgtY = -1; + + switch (PolySubtype(hRefpoly)) { + case REF_POINT: // Go to specified node + getPolyNode(hRefpoly, ptgtX, ptgtY); + assert(InPolygon(*ptgtX, *ptgtY, PATH) != NOPOLY); // POINT Referral to illegal point + break; + + case REF_DOWN: // Search downwards + end = BackgroundHeight(); + for (i = clickY+1; i < end; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY + && InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + break; + + case REF_UP: // Search upwards + for (i = clickY-1; i >= 0; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY + && InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + break; + + case REF_RIGHT: // Search to the right + end = BackgroundWidth(); + for (i = clickX+1; i < end; i++) + if (InPolygon(i, clickY, PATH) != NOPOLY + && InPolygon(i, clickY, BLOCKING) == NOPOLY) { + *ptgtX = i; + *ptgtY = clickY; + break; + } + break; + + case REF_LEFT: // Search to the left + for (i = clickX-1; i >= 0; i--) + if (InPolygon(i, clickY, PATH) != NOPOLY + && InPolygon(i, clickY, BLOCKING) == NOPOLY) { + *ptgtX = i; + *ptgtY = clickY; + break; + } + break; + } + if (*ptgtX != -1 && *ptgtY != -1) { + return NOT_SORTED; + } else + return ALL_SORTED; +} + +/** + * Given (x, y) of a click, works out the destination according to the + * default referral type. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int ClickedOnNothing(int clickX, int clickY, int *ptgtX, int *ptgtY) { + int i; + int end; // Extreme of the scene + int Loffset, Toffset; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + switch (DefaultRefer) { + case REF_DEFAULT: + // Try searching down and up (onscreen). + for (i = clickY+1; i < SCREEN_HEIGHT+Toffset; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + for (i = clickY-1; i >= Toffset; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + // Try searching down and up (offscreen). + end = BackgroundHeight(); + for (i = clickY+1; i < end; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + for (i = clickY-1; i >= 0; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + break; + + case REF_UP: + for (i = clickY-1; i >= 0; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + break; + + case REF_DOWN: + end = BackgroundHeight(); + for (i = clickY+1; i < end; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + break; + + case REF_LEFT: + for (i = clickX-1; i >= 0; i--) + if (InPolygon(i, clickY, PATH) != NOPOLY) { + return ClickedOnPath(i, clickY, ptgtX, ptgtY); + } + break; + + case REF_RIGHT: + end = BackgroundWidth(); + for (i = clickX + 1; i < end; i++) + if (InPolygon(i, clickY, PATH) != NOPOLY) { + return ClickedOnPath(i, clickY, ptgtX, ptgtY); + } + break; + } + + // Going nowhere! + return ALL_SORTED; +} + +/** + * Given (x, y) of the click, ascertains whether the click is within a + * path, within a referral poly, or niether. The appropriate function + * then gets called to give us a revised destination. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int WorkOutDestination(int clickX, int clickY, int *ptgtX, int *ptgtY) { + HPOLYGON hPoly; + + /*-------------------------------------- + Clicked within a path? + if not, within a referral poly? + if not, try and sort something out. + ---------------------------------------*/ + if (InPolygon(clickX, clickY, PATH) != NOPOLY) { + return ClickedOnPath(clickX, clickY, ptgtX, ptgtY); + } else if ((hPoly = InPolygon(clickX, clickY, REFER)) != NOPOLY) { + return ClickedOnRefer(hPoly, clickX, clickY, ptgtX, ptgtY); + } else { + return ClickedOnNothing(clickX, clickY, ptgtX, ptgtY); + } +} + +/** + * Work out which reel to adopt for a section of movement. + */ +static DIRREEL GetDirectionReel(int fromx, int fromy, int tox, int toy, DIRREEL lastreel, HPOLYGON hPath) { + int xchange = 0, ychange = 0; + enum {X_NONE, X_LEFT, X_RIGHT, X_NO} xdir; + enum {Y_NONE, Y_UP, Y_DOWN, Y_NO} ydir; + + DIRREEL reel = lastreel; // Leave alone if can't decide + + /* + * Determine size and direction of X movement. + * i.e. left, right, none or not allowed. + */ + if (getPolyReelType(hPath) == REEL_VERT) + xdir = X_NO; + else if (tox == -1) + xdir = X_NONE; + else { + xchange = tox - fromx; + if (xchange > 0) + xdir = X_RIGHT; + else if (xchange < 0) { + xchange = -xchange; + xdir = X_LEFT; + } else + xdir = X_NONE; + } + + /* + * Determine size and direction of Y movement. + * i.e. up, down, none or not allowed. + */ + if (getPolyReelType(hPath) == REEL_HORIZ) + ydir = Y_NO; + else if (toy == -1) + ydir = Y_NONE; + else { + ychange = toy - fromy; + if (ychange > 0) + ydir = Y_DOWN; + else if (ychange < 0) { + ychange = -ychange; + ydir = Y_UP; + } else + ydir = Y_NONE; + } + + /* + * Some adjustment to allow for different x and y pixell sizes. + */ + ychange += ychange; // Double y distance to cover + + /* + * Determine which reel to use. + */ + if (xdir == X_NO) { + // Forced to be FORWARD or AWAY + switch (ydir) { + case Y_DOWN: + reel = FORWARD; + break; + case Y_UP: + reel = AWAY; + break; + default: + if (reel != AWAY) // No gratuitous turn + reel = FORWARD; + break; + } + } else if (ydir == Y_NO) { + // Forced to be LEFTREEL or RIGHTREEL + switch (xdir) { + case X_LEFT: + reel = LEFTREEL; + break; + case X_RIGHT: + reel = RIGHTREEL; + break; + default: + if (reel != LEFTREEL) // No gratuitous turn + reel = RIGHTREEL; + break; + } + } else if (xdir != X_NONE || ydir != Y_NONE) { + if (xdir == X_NONE) + reel = (ydir == Y_DOWN) ? FORWARD : AWAY; + else if (ydir == Y_NONE) + reel = (xdir == X_LEFT) ? LEFTREEL : RIGHTREEL; + else { + bool DontBother = false; + + if (xchange <= 4 && ychange <= 4) { + switch (reel) { + case LEFTREEL: + if (xdir == X_LEFT) + DontBother = true; + break; + case RIGHTREEL: + if (xdir == X_RIGHT) + DontBother = true; + break; + case FORWARD: + if (ydir == Y_DOWN) + DontBother = true; + break; + case AWAY: + if (ydir == Y_UP) + DontBother = true; + break; + } + } + if (!DontBother) { + if (xchange > ychange) + reel = (xdir == X_LEFT) ? LEFTREEL : RIGHTREEL; + else + reel = (ydir == Y_DOWN) ? FORWARD : AWAY; + } + } + } + return reel; +} + +/** + * Haven't moved, look towards the cursor. + */ +static void GotThereWithoutMoving(PMACTOR pActor) { + int curX, curY; + DIRREEL reel; + + if (!pActor->TagReelRunning) { + GetCursorXYNoWait(&curX, &curY, true); + + reel = GetDirectionReel(pActor->objx, pActor->objy, curX, curY, pActor->dirn, pActor->hCpath); + + if (reel != pActor->dirn) + SetMActorWalkReel(pActor, reel, pActor->scale, false); + } +} + +/** + * Arrived at final destination. + */ +static void GotThere(PMACTOR pActor) { + pActor->targetX = pActor->targetY = -1; // 4/1/95 + pActor->ItargetX = pActor->ItargetY = -1; + pActor->UtargetX = pActor->UtargetY = -1; + + // Perhaps we have'nt moved. + if (pActor->objx == (int)pActor->fromx && pActor->objy == (int)pActor->fromy) + GotThereWithoutMoving(pActor); + + ReTagActor(pActor->actorID); // Tag allowed while stationary + + SetMActorStanding(pActor); + + pActor->bMoving = false; +} + +enum cgt { GT_NOTL, GT_NOTB, GT_NOT2, GT_OK, GT_MAY }; + +/** + * Can we get straight there? + */ +static cgt CanGetThere(PMACTOR pActor, int tx, int ty) { + int s1, s2; // s2 not used here! + HPOLYGON hS2p; // nor is s2p! + int nextx, nexty; + + int targetX = tx; + int targetY = ty; // Ultimate destination + int x = pActor->objx; + int y = pActor->objy; // Present position + + while (targetX != -1 || targetY != -1) { + NewCoOrdinates(x, y, &targetX, &targetY, &nextx, &nexty, + &s1, &s2, &hS2p, pActor->over, false, pActor); + + if (s1 == (XTHERE | YTHERE)) { + return GT_OK; // Can get there directly. + } else if (s1 == (XTHERE | YRESTRICT) || s1 == (YTHERE | XRESTRICT)) { + return GT_MAY; // Can't get there directly. + } else if (s1 & STUCK) { + if (s2 == LEAVING_PATH) + return GT_NOTL; // Can't get there. + else + return GT_NOTB; // Can't get there. + } else if (x == nextx && y == nexty) { + return GT_NOT2; // Can't get there. + } + x = nextx; + y = nexty; + } + return GT_MAY; +} + + +/** + * Set final destination. + */ +static void SetMoverUltDest(PMACTOR pActor, int x, int y) { + pActor->UtargetX = x; + pActor->UtargetY = y; + pActor->hUpath = InPolygon(x, y, PATH); + + assert(pActor->hUpath != NOPOLY || pActor->bIgPath); // Invalid ultimate destination +} + +/** + * Set intermediate destination. + * + * If in final destination path, go straight to target. + * If in a neighbouring path to the final destination, if the target path + * is a follow nodes path, head for the end node, otherwise head straight + * for the target. + * Otherwise, head towards the pseudo-centre or end node of the first + * en-route path. + */ +static void SetMoverIntDest(PMACTOR pActor, int x, int y) { + HPOLYGON hIpath, hTpath; + int node; + + hTpath = InPolygon(x, y, PATH); // Target path +#ifdef DEBUG + if (!pActor->bIgPath) + assert(hTpath != NOPOLY); // SetMoverIntDest() - target not in path +#endif + + if (pActor->hCpath == hTpath || pActor->bIgPath + || IsInPolygon(pActor->objx, pActor->objy, hTpath)) { + // In destination path - head straight for the target. + pActor->ItargetX = x; + pActor->ItargetY = y; + pActor->hIpath = hTpath; + } else if (IsAdjacentPath(pActor->hCpath, hTpath)) { + // In path adjacent to target + if (PolySubtype(hTpath) != NODE) { + // Target path is normal - head for target. + // Added 26/01/95, innroom + if (CanGetThere(pActor, x, y) == GT_NOTL) { + NearestCorner(&x, &y, pActor->hCpath, hTpath); + } + pActor->ItargetX = x; + pActor->ItargetY = y; + } else { + // Target path is node - head for end node. + node = NearestEndNode(hTpath, pActor->objx, pActor->objy); + getNpathNode(hTpath, node, &pActor->ItargetX, &pActor->ItargetY); + + } + pActor->hIpath = hTpath; + } else { + assert(hTpath != NOPOLY); // Error 701 + hIpath = getPathOnTheWay(pActor->hCpath, hTpath); + + if (hIpath != NOPOLY) { + /* Head for an en-route path */ + if (PolySubtype(hIpath) != NODE) { + /* En-route path is normal - head for pseudo centre. */ + if (CanGetThere(pActor, x, y) == GT_OK) { + pActor->ItargetX = x; + pActor->ItargetY = y; + } else { + pActor->ItargetX = PolyCentreX(hIpath); + pActor->ItargetY = PolyCentreY(hIpath); + } + } else { + /* En-route path is node - head for end node. */ + node = NearestEndNode(hIpath, pActor->objx, pActor->objy); + getNpathNode(hIpath, node, &pActor->ItargetX, &pActor->ItargetY); + } + pActor->hIpath = hIpath; + } + } + + pActor->InDifficulty = NO_PROB; +} + +/** + * Set short-term destination and adopt the appropriate reel. + */ +static void SetMoverDest(PMACTOR pActor, int x, int y) { + int scale; + DIRREEL reel; + + // Set the co-ordinates requested. + pActor->targetX = x; + pActor->targetY = y; + pActor->InDifficulty = NO_PROB; + + reel = GetDirectionReel(pActor->objx, pActor->objy, x, y, pActor->dirn, pActor->hCpath); + scale = GetScale(pActor->hCpath, pActor->objy); + if (scale != pActor->scale || reel != pActor->dirn) { + SetMActorWalkReel(pActor, reel, scale, false); + } +} + +/** + * SetNextDest + */ +static void SetNextDest(PMACTOR pActor) { + int targetX, targetY; // Ultimate destination + int x, y; // Present position + int nextx, nexty; + int s1, lstatus = 0; + int s2; + HPOLYGON hS2p; + int i; + HPOLYGON hNpoly; + HPOLYGON hPath; + int znode; + int nx, ny; + int sx, sy; + HPOLYGON hEb; + + int ss1, ss2; + HPOLYGON shS2p; + PMACTOR collisionActor; +#if 1 + int sTargetX, sTargetY; +#endif + + /* + * Desired destination (Itarget) is already set + */ + x = pActor->objx; // Current position + y = pActor->objy; + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + + /* + * If we're where we're headed, end it all (the moving). + */ +// if (x == targetX && y == targetY) + if (ABS(x - targetX) < XMDIST && ABS(y - targetY) < YMDIST) { + if (targetX == pActor->UtargetX && targetY == pActor->UtargetY) { + // Desired position + GotThere(pActor); + return; + } else { + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5001 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + } + } + + if (pActor->bNoPath || pActor->bIgPath) { + /* Can get there directly. */ + SetMoverDest(pActor, targetX, targetY); + pActor->over = false; + return; + } + + /*---------------------------------------------------------------------- + | Some work to do here if we're in a follow nodes polygon - basically + | head for the next node. + ----------------------------------------------------------------------*/ + hNpoly = pActor->hFnpath; // The node path we're in (if any) + switch (pActor->npstatus) { + case NOT_IN: + break; + + case ENTERING: + znode = NearestEndNode(hNpoly, x, y); + /* Hang on, we're probably here already! */ + if (znode) { + pActor->npstatus = GOING_DOWN; + pActor->line = znode-1; + getNpathNode(hNpoly, znode - 1, &nx, &ny); + } else { + pActor->npstatus = GOING_UP; + pActor->line = znode; + getNpathNode(hNpoly, 1, &nx, &ny); + } + SetMoverDest(pActor, nx, ny); + + // Test for pseudo-one-node npaths + if (numNodes(hNpoly) == 2 && + ABS(pActor->objx - pActor->targetX) < XMDIST && + ABS(pActor->objy - pActor->targetY) < YMDIST) { + // That's enough, we're leaving + pActor->npstatus = LEAVING; + } else { + // Normal situation + pActor->over = true; + return; + } + // Fall through for LEAVING + + case LEAVING: + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5002 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + break; + + case GOING_UP: + i = pActor->line; // The line we're on + + // Is this the final target line? + if (i+1 == pActor->Tline && hNpoly == pActor->hUpath) { + // The final leg of the journey + pActor->line = i+1; + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + pActor->over = false; + return; + } else { + // Go to the next node unless we're at the last one + i++; // The node we're at + if (++i < numNodes(hNpoly)) { + getNpathNode(hNpoly, i, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->line = i-1; + if (ABS(pActor->UtargetX - pActor->targetX) < XMDIST && + ABS(pActor->UtargetY - pActor->targetY) < YMDIST) + pActor->over = false; + else + pActor->over = true; + return; + } else { + // Last node - we're off + pActor->npstatus = LEAVING; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5003 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + break; + } + } + + case GOING_DOWN: + i = pActor->line; // The line we're on and the node we're at + + // Is this the final target line? + if (i - 1 == pActor->Tline && hNpoly == pActor->hUpath) { + // The final leg of the journey + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + pActor->line = i-1; + pActor->over = false; + return; + } else { + // Go to the next node unless we're at the last one + if (--i >= 0) { + getNpathNode(hNpoly, i, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->line--; /* The next node to head for */ + if (ABS(pActor->UtargetX - pActor->targetX) < XMDIST && + ABS(pActor->UtargetY - pActor->targetY) < YMDIST) + pActor->over = false; + else + pActor->over = true; + return; + } else { + // Last node - we're off + pActor->npstatus = LEAVING; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5004 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + break; + } + } + } + + + + + /*------------------------------------------------------ + | See if it can get there directly. There may be an + | intermediate destination to head for. + ------------------------------------------------------*/ + + while (targetX != -1 || targetY != -1) { +#if 1 + // 'push' the target + sTargetX = targetX; + sTargetY = targetY; +#endif + NewCoOrdinates(x, y, &targetX, &targetY, &nextx, &nexty, + &s1, &s2, &hS2p, pActor->over, false, pActor, &collisionActor); + + if (s1 != (XTHERE | YTHERE) && x == nextx && y == nexty) { + ss1 = s1; + ss2 = s2; + shS2p = hS2p; +#if 1 + // 'pop' the target + targetX = sTargetX; + targetY = sTargetY; +#endif + // Note: this aint right - targetX/Y (may) have been + // nobbled by that last call to NewCoOrdinates() + // Re-instating them (can) leads to oscillation + NewCoOrdinates(x, y, &targetX, &targetY, &nextx, &nexty, + &s1, &s2, &hS2p, pActor->over, true, pActor, &collisionActor); + + if (x == nextx && y == nexty) { + s1 = ss1; + s2 = ss2; + hS2p = shS2p; + } + } + + if (s1 == (XTHERE | YTHERE)) { + /* Can get there directly. */ + SetMoverDest(pActor, nextx, nexty); + pActor->over = false; + break; + } else if ((s1 & STUCK) || s1 == (XRESTRICT + YRESTRICT) + || s1 == (XTHERE | YRESTRICT) || s1 == (YTHERE | XRESTRICT)) { + /*------------------------------------------------- + Can't go any further in this direction. | + If it's because of a blocking polygon, try to do | + something about it. | + -------------------------------------------------*/ + if (s2 & ENTERING_BLOCK) { + x = pActor->objx; // Current position + y = pActor->objy; + // Go to the nearest corner of the blocking polygon concerned + BlockingCorner(hS2p, &x, &y, pActor->ItargetX, pActor->ItargetY); + SetMoverDest(pActor, x, y); + pActor->over = false; + } else if (s2 & ENTERING_MBLOCK) { + if (InMActorBlock(pActor, pActor->UtargetX, pActor->UtargetY)) { + // The best we're going to achieve + SetMoverUltDest(pActor, x, y); + SetMoverDest(pActor, x, y); + } else { + sx = pActor->objx; + sy = pActor->objy; +// pActor->objx = x; +// pActor->objy = y; + + hEb = InitExtraBlock(pActor, collisionActor); + x = pActor->objx; + y = pActor->objy; + BlockingCorner(hEb, &x, &y, pActor->ItargetX, pActor->ItargetY); + + pActor->objx = sx; + pActor->objy = sy; + SetMoverDest(pActor, x, y); + pActor->over = false; + } + } else { + /*---------------------------------------- + Currently, this is as far as we can go. | + Definitely room for improvement here! | + ----------------------------------------*/ + hPath = InPolygon(pActor->ItargetX, pActor->ItargetY, PATH); + if (hPath != pActor->hIpath) { + if (IsInPolygon(pActor->ItargetX, pActor->ItargetY, pActor->hIpath)) + hPath = pActor->hIpath; + } + assert(hPath == pActor->hIpath); + + if (pActor->InDifficulty == NO_PROB) { + x = PolyCentreX(hPath); + y = PolyCentreY(hPath); + SetMoverDest(pActor, x, y); + pActor->InDifficulty = TRY_CENTRE; + pActor->over = false; + } else if (pActor->InDifficulty == TRY_CENTRE) { + NearestCorner(&x, &y, pActor->hCpath, pActor->hIpath); + SetMoverDest(pActor, x, y); + pActor->InDifficulty = TRY_CORNER; + pActor->over = false; + } else if (pActor->InDifficulty == TRY_CORNER) { + NearestCorner(&x, &y, pActor->hCpath, pActor->hIpath); + SetMoverDest(pActor, x, y); + pActor->InDifficulty = TRY_NEXTCORNER; + pActor->over = false; + } + } + break; + } + else if (((lstatus & YRESTRICT) && !(s1 & YRESTRICT)) + || ((lstatus & XRESTRICT) && !(s1 & XRESTRICT))) { + /*----------------------------------------------- + A restriction in a direction has been removed. | + Use this as an intermediate destination. | + -----------------------------------------------*/ + SetMoverDest(pActor, nextx, nexty); + pActor->over = false; + break; + } + + x = nextx; + y = nexty; + + /*------------------------- + Change of path polygon? | + -------------------------*/ + hPath = InPolygon(x, y, PATH); + if (pActor->hCpath != hPath && + !IsInPolygon(x, y, pActor->hCpath) && + !IsAdjacentPath(pActor->hCpath, pActor->hIpath)) { + /*---------------------------------------------------------- + If just entering a follow nodes polygon, go to first node.| + Else if just going to pass through, go to pseudo-centre. | + ----------------------------------------------------------*/ + if (PolySubtype(hPath) == NODE && pActor->hFnpath != hPath && pActor->npstatus != LEAVING) { + int node = NearestEndNode(hPath, x, y); + getNpathNode(hPath, node, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->over = true; + } else if (!IsInPolygon(pActor->ItargetX, pActor->ItargetY, hPath) && + !IsInPolygon(pActor->ItargetX, pActor->ItargetY, pActor->hCpath)) { + SetMoverDest(pActor, PolyCentreX(hPath), PolyCentreY(hPath)); + pActor->over = true; + } else { + SetMoverDest(pActor, pActor->ItargetX, pActor->ItargetY); + } + break; + } + + lstatus = s1; + } +} + +/** + * Work out where the next position should be. + * Check that it's in a path and not in a blocking polygon. + */ +static void NewCoOrdinates(int fromx, int fromy, int *targetX, int *targetY, + int *newx, int *newy, int *s1, int *s2, + HPOLYGON *hS2p, bool bOver, bool bBodge, + PMACTOR pActor, PMACTOR *collisionActor) { + HPOLYGON hPoly; + int sidem, depthm; + int sidesteps, depthsteps; + PMACTOR ma; + + *s1 = *s2 = 0; + + /*------------------------------------------------ + Don't overrun if this is the final destination. | + ------------------------------------------------*/ + if (*targetX == pActor->UtargetX && (*targetY == -1 || *targetY == pActor->UtargetY) || + *targetY == pActor->UtargetY && (*targetX == -1 || *targetX == pActor->UtargetX)) + bOver = false; + + /*---------------------------------------------------- + Decide how big a step to attempt in each direction. | + ----------------------------------------------------*/ + sidesteps = *targetX == -1 ? 0 : *targetX - fromx; + sidesteps = ABS(sidesteps); + + depthsteps = *targetY == -1 ? 0 : *targetY - fromy; + depthsteps = ABS(depthsteps); + + if (sidesteps && depthsteps > sidesteps) { + depthm = YMDIST; + sidem = depthm * sidesteps/depthsteps; + + if (!sidem) + sidem = 1; + } else if (depthsteps && sidesteps > depthsteps) { + sidem = XMDIST; + depthm = sidem * depthsteps/sidesteps; + + if (!depthm) { + if (bBodge) + depthm = 1; + } else if (depthm > YMDIST) + depthm = YMDIST; + } else { + sidem = sidesteps ? XMDIST : 0; + depthm = depthsteps ? YMDIST : 0; + } + + *newx = fromx; + *newy = fromy; + + /*------------------------------------------------------------ + If Left-Right movement is required - then make the move, | + but don't overshoot, and do notice when we're already there | + ------------------------------------------------------------*/ + if (*targetX == -1) + *s1 |= XTHERE; + else { + if (*targetX > fromx) { /* To the right? */ + *newx += sidem; // Move to the right... + if (*newx == *targetX) + *s1 |= XTHERE; + else if (*newx > *targetX) { // ...but don't overshoot + if (!bOver) + *newx = *targetX; + else + *targetX = *newx; + *s1 |= XTHERE; + } + } else if (*targetX < fromx) { /* To the left? */ + *newx -= sidem; // Move to the left... + if (*newx == *targetX) + *s1 |= XTHERE; + else if (*newx < *targetX) { // ...but don't overshoot + if (!bOver) + *newx = *targetX; + else + *targetX = *newx; + *s1 |= XTHERE; + } + } else { + *targetX = -1; // We're already there! + *s1 |= XTHERE; + } + } + + /*-------------------------------------------------------------- + If Up-Down movement is required - then make the move, + but don't overshoot, and do notice when we're already there + --------------------------------------------------------------*/ + if (*targetY == -1) + *s1 |= YTHERE; + else { + if (*targetY > fromy) { /* Downwards? */ + *newy += depthm; // Move down... + if (*newy == *targetY) // ...but don't overshoot + *s1 |= YTHERE; + else if (*newy > *targetY) { // ...but don't overshoot + if (!bOver) + *newy = *targetY; + else + *targetY = *newy; + *s1 |= YTHERE; + } + } else if (*targetY < fromy) { /* Upwards? */ + *newy -= depthm; // Move up... + if (*newy == *targetY) // ...but don't overshoot + *s1 |= YTHERE; + else if (*newy < *targetY) { // ...but don't overshoot + if (!bOver) + *newy = *targetY; + else + *targetY = *newy; + *s1 |= YTHERE; + } + } else { + *targetY = -1; // We're already there! + *s1 |= YTHERE; + } + } + + /* Give over if this is it */ + if (*s1 == (XTHERE | YTHERE)) + return; + + /*------------------------------------------------------ + Have worked out where an optimum step would take us. + Must now check if it's in a legal spot. + ------------------------------------------------------*/ + + if (!pActor->bNoPath && !pActor->bIgPath) { + /*------------------------------ + Must stay in a path polygon. + -------------------------------*/ + hPoly = InPolygon(*newx, *newy, PATH); + if (hPoly == NOPOLY) { + *s2 = LEAVING_PATH; // Trying to leave the path polygons + + if (*newx != fromx && InPolygon(*newx, fromy, PATH) != NOPOLY && InPolygon(*newx, fromy, BLOCKING) == NOPOLY) { + *newy = fromy; + *s1 |= YRESTRICT; + } else if (*newy != fromy && InPolygon(fromx, *newy, PATH) != NOPOLY && InPolygon(fromx, *newy, BLOCKING) == NOPOLY) { + *newx = fromx; + *s1 |= XRESTRICT; + } else { + *newx = fromx; + *newy = fromy; +#if 1 + *targetX = *targetY = -1; +#endif + *s1 |= STUCK; + return; + } + } + + /*-------------------------------------- + Must stay out of blocking polygons. + --------------------------------------*/ + hPoly = InPolygon(*newx, *newy, BLOCKING); + if (hPoly != NOPOLY) { + *s2 = ENTERING_BLOCK; // Trying to enter a blocking poly + *hS2p = hPoly; + + if (*newx != fromx && InPolygon(*newx, fromy, BLOCKING) == NOPOLY && InPolygon(*newx, fromy, PATH) != NOPOLY) { + *newy = fromy; + *s1 |= YRESTRICT; + } else if (*newy != fromy && InPolygon(fromx, *newy, BLOCKING) == NOPOLY && InPolygon(fromx, *newy, PATH) != NOPOLY) { + *newx = fromx; + *s1 |= XRESTRICT; + } else { + *newx = fromx; + *newy = fromy; +#if 1 + *targetX = *targetY = -1; +#endif + *s1 |= STUCK; + } + } + /*------------------------------------------------------ + Must stay out of moving actors' blocking polygons. + ------------------------------------------------------*/ + ma = InMActorBlock(pActor, *newx, *newy); + if (ma != NULL) { + // Ignore if already in it (it may have just appeared) + if (!InMActorBlock(pActor, pActor->objx, pActor->objy)) { + *s2 = ENTERING_MBLOCK; // Trying to walk through an actor + + *hS2p = -1; + if (collisionActor) + *collisionActor = ma; + + if (*newx != fromx && InMActorBlock(pActor, *newx, fromy) == NULL + && InPolygon(*newx, fromy, BLOCKING) == NOPOLY && InPolygon(*newx, fromy, PATH) != NOPOLY) { + *newy = fromy; + *s1 |= YRESTRICT; + } else if (*newy != fromy && InMActorBlock(pActor, fromx, *newy) == NULL + && InPolygon(fromx, *newy, BLOCKING) == NOPOLY && InPolygon(fromx, *newy, PATH) != NOPOLY) { + *newx = fromx; + *s1 |= XRESTRICT; + } else { + *newx = fromx; + *newy = fromy; +#if 1 + *targetX = *targetY = -1; +#endif + *s1 |= STUCK; + } + } + } + } +} + +/** + * SetOffWithinNodePath + */ +static void SetOffWithinNodePath(PMACTOR pActor, HPOLYGON StartPath, HPOLYGON DestPath, + int targetX, int targetY) { + int endnode; + HPOLYGON hIpath; + int nx, ny; + int x, y; + + if (StartPath == DestPath) { + if (pActor->line == pActor->Tline) { + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + pActor->over = false; + } else if (pActor->line < pActor->Tline) { + getNpathNode(StartPath, pActor->line+1, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_UP; + } else if (pActor->line > pActor->Tline) { + getNpathNode(StartPath, pActor->line, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_DOWN; + } + } else { + /* + * Leaving this path - work out + * which end of this path to head for. + */ + assert(DestPath != NOPOLY); // Error 702 + if ((hIpath = getPathOnTheWay(StartPath, DestPath)) == NOPOLY) { + // This should never happen! + // It's the old code that didn't always work. + endnode = NearestEndNode(StartPath, targetX, targetY); + } else { + if (PolySubtype(hIpath) != NODE) { + x = PolyCentreX(hIpath); + y = PolyCentreY(hIpath); + endnode = NearestEndNode(StartPath, x, y); + } else { + endnode = NearEndNode(StartPath, hIpath); + } + } + +#if 1 + if ((pActor->npstatus == LEAVING) && + endnode == NearestEndNode(StartPath, pActor->objx, pActor->objy)) { + // Leave it be + } else +#endif + { + if (endnode) { + getNpathNode(StartPath, pActor->line+1, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_UP; + } else { + getNpathNode(StartPath, pActor->line, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_DOWN; + } + } + } +} + +/** + * Restore a movement, called from restoreMovement() in ACTORS.CPP + */ +void SSetActorDest(PMACTOR pActor) { + if (pActor->UtargetX != -1 && pActor->UtargetY != -1) { + stand(pActor->actorID, pActor->objx, pActor->objy, 0); + + if (pActor->UtargetX != -1 && pActor->UtargetY != -1) { + SetActorDest(pActor, pActor->UtargetX, pActor->UtargetY, + pActor->bIgPath, 0); + } + } else { + stand(pActor->actorID, pActor->objx, pActor->objy, 0); + } +} + +/** + * Initiate a movement, called from WalkTo_Event() + */ +void SetActorDest(PMACTOR pActor, int clickX, int clickY, bool igPath, SCNHANDLE film) { + HPOLYGON StartPath, DestPath = 0; + int targetX, targetY; + + if (pActor->actorID == LeadId()) // Now only for lead actor + UnTagActor(pActor->actorID); // Tag not allowed while moving + pActor->ticket++; + pActor->stop = false; + pActor->over = false; + pActor->fromx = pActor->objx; + pActor->fromy = pActor->objy; + pActor->bMoving = true; + pActor->bIgPath = igPath; + + // Use the supplied reel or restore the normal actor. + if (film != 0) + AlterMActor(pActor, film, AR_WALKREEL); + else + AlterMActor(pActor, 0, AR_NORMAL); + + if (igPath) { + targetX = clickX; + targetY = clickY; + } else { + if (WorkOutDestination(clickX, clickY, &targetX, &targetY) == ALL_SORTED) { + GotThere(pActor); + return; + } + assert(InPolygon(targetX, targetY, PATH) != NOPOLY); // illegal destination! + assert(InPolygon(targetX, targetY, BLOCKING) == NOPOLY); // illegal destination! + } + + + /***** Now have a destination to aim for. *****/ + + /*---------------------------------- + | Don't move if it's not worth it. + ----------------------------------*/ + if (ABS(targetX - pActor->objx) < XMDIST && ABS(targetY - pActor->objy) < YMDIST) { + GotThere(pActor); + return; + } + + /*------------------------------------------------------ + | If the destiation is within a follow nodes polygon, + | set destination as the nearest node. + ------------------------------------------------------*/ + if (!igPath) { + DestPath = InPolygon(targetX, targetY, PATH); + if (PolySubtype(DestPath) == NODE) { + // Find the nearest point on a line, or nearest node + FindBestPoint(DestPath, &targetX, &targetY, &pActor->Tline); + } + } + + assert(pActor->bIgPath || InPolygon(targetX, targetY, PATH) != NOPOLY); // Error 5005 + SetMoverUltDest(pActor, targetX, targetY); + SetMoverIntDest(pActor, targetX, targetY); + + /*------------------------------------------------------------------- + | If in a follow nodes path, need to set off in the right direction! | + -------------------------------------------------------------------*/ + if ((StartPath = pActor->hFnpath) != NOPOLY && !igPath) { + SetOffWithinNodePath(pActor, StartPath, DestPath, targetX, targetY); + } else { + // Set off! + SetNextDest(pActor); + } +} + +/** + * Change scale if appropriate. + */ +static void CheckScale(PMACTOR pActor, HPOLYGON hPath, int ypos) { + int scale; + + scale = GetScale(hPath, ypos); + if (scale != pActor->scale) { + SetMActorWalkReel(pActor, pActor->dirn, scale, false); + } +} + +/** + * Not going anywhere - Kick off again if not at final destination. + */ +static void NotMoving(PMACTOR pActor, int x, int y) { + pActor->targetX = pActor->targetY = -1; + +// if (x == pActor->UtargetX && y == pActor->UtargetY) + if (ABS(x - pActor->UtargetX) < XMDIST && ABS(y - pActor->UtargetY) < YMDIST) { + GotThere(pActor); + return; + } + + if (pActor->ItargetX != -1 || pActor->ItargetY != -1) { + SetNextDest(pActor); + } else if (pActor->UtargetX != -1 || pActor->UtargetY != -1) { + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5006 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetNextDest(pActor); + } +} + +/** + * Does the necessary business when entering a different path polygon. + */ +static void EnteringNewPath(PMACTOR pActor, HPOLYGON hPath, int x, int y) { + int firstnode; // First node to go to + int lastnode; // Last node to go to + HPOLYGON hIpath; + int nx, ny; + int nxl, nyl; + + pActor->hCpath = hPath; // current path + + if (hPath == NOPOLY) { + // Not proved this ever happens, but just in case + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + return; + } + + // Is new path a node path? + if (PolySubtype(hPath) == NODE) { + // Node path - usually go to nearest end node + firstnode = NearestEndNode(hPath, x, y); + lastnode = -1; + + // If this is not the destination path, + // find which end nodfe we wish to leave via + if (hPath != pActor->hUpath) { + if (pActor->bIgPath) { + lastnode = NearestEndNode(hPath, pActor->UtargetX, pActor->UtargetY); + } else { + assert(pActor->hUpath != NOPOLY); // Error 703 + hIpath = getPathOnTheWay(hPath, pActor->hUpath); + assert(hIpath != NOPOLY); // No path on the way + + if (PolySubtype(hIpath) != NODE) { + lastnode = NearestEndNode(hPath, PolyCentreX(hIpath), PolyCentreY(hIpath)); + } else { + lastnode = NearEndNode(hPath, hIpath); + } + } + } + // Test for pseudo-one-node npaths + if (lastnode != -1 && numNodes(hPath) == 2) { + getNpathNode(hPath, firstnode, &nx, &ny); + getNpathNode(hPath, lastnode, &nxl, &nyl); + if (nxl == nx && nyl == ny) + firstnode = lastnode; + } + + // If leaving by same node as entering, don't bother. + if (lastnode == firstnode) { + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5007 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetNextDest(pActor); + } else { + // Head for first node + pActor->over = true; + pActor->npstatus = ENTERING; + pActor->hFnpath = hPath; + pActor->line = firstnode ? firstnode - 1 : firstnode; + if (pActor->line == pActor->Tline && hPath == pActor->hUpath) { + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5008 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + } else { + // This doesn't seem right + getNpathNode(hPath, firstnode, &nx, &ny); + if (ABS(pActor->objx - nx) < XMDIST + && ABS(pActor->objy - ny) < YMDIST) { + pActor->npstatus = ENTERING; + pActor->hFnpath = hPath; + SetNextDest(pActor); + } else { + getNpathNode(hPath, firstnode, &nx, &ny); + SetMoverDest(pActor, nx, ny); + } + } + } + return; + } else { + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5009 +// Added 26/01/95 + if (IsPolyCorner(hPath, pActor->ItargetX, pActor->ItargetY)) + return; + + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetNextDest(pActor); + } +} + +/** + * Move + */ +void Move(PMACTOR pActor, int newx, int newy, HPOLYGON hPath) { + MultiSetAniXY(pActor->actorObj, newx, newy); + MAsetZPos(pActor, newy, getPolyZfactor(hPath)); + if (StepAnimScript(&pActor->actorAnim) == ScriptFinished) { + // The end of a scale-change reel + // Revert to normal walking reel + pActor->walkReel = false; + pActor->scount = 0; + SetMActorWalkReel(pActor, pActor->dirn, pActor->scale, true); + } + pActor->objx = newx; + pActor->objy = newy; + + // Synchronised walking reels + if (++pActor->scount >= 6) + pActor->scount = 0; +} + +/** + * Called from MActorProcess() on every tick. + * + * Moves the actor as appropriate. + */ +void MoveActor(PMACTOR pActor) { + int newx, newy; + HPOLYGON hPath; + int status, s2; // s2 not used here! + HPOLYGON hS2p; // nor is s2p! + HPOLYGON hEb; + PMACTOR ma; + int sTargetX, sTargetY; + bool bNewPath = false; + + // Only do anything if the actor needs to move! + if (pActor->targetX == -1 && pActor->targetY == -1) + return; + + if (pActor->stop) { + GotThere(pActor); + pActor->stop = false; + SetMActorStanding(pActor); + return; + } + +#if SLOW_RINCE_DOWN +/**/ if (BogusVar++ < Interlude) // Temporary slow-down-the-action code +/**/ return; // +/**/ BogusVar = 0; // +#endif + + // During swalk()s, movement while hidden may be slowed down. + if (pActor->aHidden) { + if (++hSlowVar < pActor->SlowFactor) + return; + hSlowVar = 0; + } + + // 'push' the target + sTargetX = pActor->targetX; + sTargetY = pActor->targetY; + + NewCoOrdinates(pActor->objx, pActor->objy, &pActor->targetX, &pActor->targetY, + &newx, &newy, &status, &s2, &hS2p, pActor->over, false, pActor); + + if (newx == pActor->objx && newy == pActor->objy) { + // 'pop' the target + pActor->targetX = sTargetX; + pActor->targetY = sTargetY; + + NewCoOrdinates(pActor->objx, pActor->objy, &pActor->targetX, &pActor->targetY, &newx, &newy, + &status, &s2, &hS2p, pActor->over, true, pActor); + if (newx == pActor->objx && newy == pActor->objy) { + NotMoving(pActor, newx, newy); + return; + } + } + + // Find out which path we're in now + hPath = InPolygon(newx, newy, PATH); + if (hPath == NOPOLY) { + if (pActor->bNoPath) { + Move(pActor, newx, newy, pActor->hCpath); + return; + } else { + // May be marginally outside! + // OR bIgPath may be set. + hPath = pActor->hCpath; + } + } else if (pActor->bNoPath) { + pActor->bNoPath = false; + bNewPath = true; + } else if (hPath != pActor->hCpath) { + if (IsInPolygon(newx, newy, pActor->hCpath)) + hPath = pActor->hCpath; + } + + CheckScale(pActor, hPath, newy); + + /* + * Must stay out of moving actors' blocking polygons. + */ + ma = InMActorBlock(pActor, newx, newy); + if (ma != NULL) { + // Stop if there's no chance of arriving + if (InMActorBlock(pActor, pActor->UtargetX, pActor->UtargetY)) { + GotThere(pActor); + return; + } + + if (InMActorBlock(pActor, pActor->objx, pActor->objy)) + ; + else { + hEb = InitExtraBlock(pActor, ma); + newx = pActor->objx; + newy = pActor->objy; + BlockingCorner(hEb, &newx, &newy, pActor->ItargetX, pActor->ItargetY); + SetMoverDest(pActor, newx, newy); + return; + } + } + + /*-------------------------------------- + This is where it actually gets moved. + --------------------------------------*/ + Move(pActor, newx, newy, hPath); + + // Entering a new path polygon? + if (hPath != pActor->hCpath || bNewPath) + EnteringNewPath(pActor, hPath, newx, newy); +} + +/** + * Store the default refer type for the current scene. + */ +void SetDefaultRefer(int32 defRefer) { + DefaultRefer = defRefer; +} + +/** + * DoMoveActor + */ +void DoMoveActor(PMACTOR pActor) { + int wasx, wasy; + int i; + +#define NUMBER 1 + + wasx = pActor->objx; + wasy = pActor->objy; + + MoveActor(pActor); + + if ((pActor->targetX != -1 || pActor->targetY != -1) + && (wasx == pActor->objx && wasy == pActor->objy)) { + for (i=0; i < NUMBER; i++) { + MoveActor(pActor); + if (wasx != pActor->objx || wasy != pActor->objy) + break; + } +// assert(ihMulFrame) { + // we have a frame handle + pFrame = (FRAME *)LockMem(FROM_LE_32(pInitTbl->hMulFrame)); + + obj_init.hObjImg = READ_LE_UINT32(pFrame); // first objects shape + } else { // this must be a animation list for a NULL object + pFrame = NULL; + obj_init.hObjImg = 0; // first objects shape + } + + // init the object init table + obj_init.objFlags = (int)FROM_LE_32(pInitTbl->mulFlags); // all objects have same flags + obj_init.objID = (int)FROM_LE_32(pInitTbl->mulID); // all objects have same ID + obj_init.objX = (int)FROM_LE_32(pInitTbl->mulX); // all objects have same X ani pos + obj_init.objY = (int)FROM_LE_32(pInitTbl->mulY); // all objects have same Y ani pos + obj_init.objZ = (int)FROM_LE_32(pInitTbl->mulZ); // all objects have same Z pos + + // create and init the first object + pObj = pFirst = InitObject(&obj_init); + + if (pFrame) { + // if we have any animation frames + + pFrame++; + + while (READ_LE_UINT32(pFrame) != 0) { + // set next objects shape + obj_init.hObjImg = READ_LE_UINT32(pFrame); + + // create next object and link to previous + pObj = pObj->pSlave = InitObject(&obj_init); + + pFrame++; + } + } + + // null end of list for final object + pObj->pSlave = NULL; + + // return master object + return pFirst; +} + +/** + * Inserts the multi-part object onto the specified object list. + * @param pObjList List to insert multi-part object onto +* @param pInsObj Head of multi-part object to insert + + */ + +void MultiInsertObject(OBJECT *pObjList, OBJECT *pInsObj) { + // validate object pointer + assert(pInsObj >= objectList && pInsObj <= objectList + NUM_OBJECTS - 1); + + // for all the objects that make up this multi-part + do { + // add next part to the specified list + InsertObject(pObjList, pInsObj); + + // next obj in list + pInsObj = pInsObj->pSlave; + } while (pInsObj != NULL); +} + +/** + * Deletes all the pieces of a multi-part object from the + * specified object list. + * @param pObjList List to delete multi-part object from + * @param pMultiObj Multi-part object to be deleted + */ + +void MultiDeleteObject(OBJECT *pObjList, OBJECT *pMultiObj) { + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // for all the objects that make up this multi-part + do { + // delete object + DelObject(pObjList, pMultiObj); + + // next obj in list + pMultiObj = pMultiObj->pSlave; + } + while (pMultiObj != NULL); +} + +/** + * Hides a multi-part object by giving each object a "NullImage" + * image pointer. + * @param pMultiObj Multi-part object to be hidden + */ + +void MultiHideObject(OBJECT *pMultiObj) { + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // set master shape to null animation frame + pMultiObj->hShape = 0; + + // change all objects + MultiReshape(pMultiObj); +} + +/** + * Horizontally flip a multi-part object. + * @param pFlipObj Head of multi-part object to flip + */ + +void MultiHorizontalFlip(OBJECT *pFlipObj) { + // validate object pointer + assert(pFlipObj >= objectList && pFlipObj <= objectList + NUM_OBJECTS - 1); + + // for all the objects that make up this multi-part + do { + // horizontally flip the next part + AnimateObjectFlags(pFlipObj, pFlipObj->flags ^ DMA_FLIPH, + pFlipObj->hImg); + + // next obj in list + pFlipObj = pFlipObj->pSlave; + } while (pFlipObj != NULL); +} + +/** + * Vertically flip a multi-part object. + * @param pFlipObj Head of multi-part object to flip + */ + +void MultiVerticalFlip(OBJECT *pFlipObj) { + // validate object pointer + assert(pFlipObj >= objectList && pFlipObj <= objectList + NUM_OBJECTS - 1); + + // for all the objects that make up this multi-part + do { + // vertically flip the next part + AnimateObjectFlags(pFlipObj, pFlipObj->flags ^ DMA_FLIPV, + pFlipObj->hImg); + + // next obj in list + pFlipObj = pFlipObj->pSlave; + } + while (pFlipObj != NULL); +} + +/** + * Adjusts the coordinates of a multi-part object. The adjustments + * take into account the orientation of the object. + * @param pMultiObj Multi-part object to be adjusted + * @param deltaX X adjustment + * @param deltaY Y adjustment + */ + +void MultiAdjustXY(OBJECT *pMultiObj, int deltaX, int deltaY) { + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + if (deltaX == 0 && deltaY == 0) + return; // ignore no change + + if (pMultiObj->flags & DMA_FLIPH) { + // image is flipped horizontally - flip the x direction + deltaX = -deltaX; + } + + if (pMultiObj->flags & DMA_FLIPV) { + // image is flipped vertically - flip the y direction + deltaY = -deltaY; + } + + // for all the objects that make up this multi-part + do { + // signal a change in the object + pMultiObj->flags |= DMA_CHANGED; + + // adjust the x position + pMultiObj->xPos += intToFrac(deltaX); + + // adjust the y position + pMultiObj->yPos += intToFrac(deltaY); + + // next obj in list + pMultiObj = pMultiObj->pSlave; + + } while (pMultiObj != NULL); +} + +/** + * Moves all the pieces of a multi-part object by the specified + * amount. Does not take into account the objects orientation. + * @param pMultiObj Multi-part object to be adjusted + * @param deltaX X movement + * @param deltaY Y movement + */ + +void MultiMoveRelXY(OBJECT *pMultiObj, int deltaX, int deltaY) { + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + if (deltaX == 0 && deltaY == 0) + return; // ignore no change + + // for all the objects that make up this multi-part + do { + // signal a change in the object + pMultiObj->flags |= DMA_CHANGED; + + // adjust the x position + pMultiObj->xPos += intToFrac(deltaX); + + // adjust the y position + pMultiObj->yPos += intToFrac(deltaY); + + // next obj in list + pMultiObj = pMultiObj->pSlave; + + } while (pMultiObj != NULL); +} + +/** + * Sets the x & y anim position of all pieces of a multi-part object. + * @param pMultiObj Multi-part object whose position is to be changed + * @param newAniX New x animation position + * @param newAniY New y animation position + */ + +void MultiSetAniXY(OBJECT *pMultiObj, int newAniX, int newAniY) { + int curAniX, curAniY; // objects current animation position + + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // get master objects current animation position + GetAniPosition(pMultiObj, &curAniX, &curAniY); + + // calc difference between current and new positions + newAniX -= curAniX; + newAniY -= curAniY; + + // move all pieces by the difference + MultiMoveRelXY(pMultiObj, newAniX, newAniY); +} + +/** + * Sets the x anim position of all pieces of a multi-part object. + * @param pMultiObj Multi-part object whose x position is to be changed + * @param newAniX New x animation position + */ + +void MultiSetAniX(OBJECT *pMultiObj, int newAniX) { + int curAniX, curAniY; // objects current animation position + + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // get master objects current animation position + GetAniPosition(pMultiObj, &curAniX, &curAniY); + + // calc x difference between current and new positions + newAniX -= curAniX; + curAniY = 0; + + // move all pieces by the difference + MultiMoveRelXY(pMultiObj, newAniX, curAniY); +} + +/** + * Sets the y anim position of all pieces of a multi-part object. + * @param pMultiObj Multi-part object whose x position is to be changed + * @param newAniX New y animation position + */ + +void MultiSetAniY(OBJECT *pMultiObj, int newAniY) { + int curAniX, curAniY; // objects current animation position + + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // get master objects current animation position + GetAniPosition(pMultiObj, &curAniX, &curAniY); + + // calc y difference between current and new positions + curAniX = 0; + newAniY -= curAniY; + + // move all pieces by the difference + MultiMoveRelXY(pMultiObj, curAniX, newAniY); +} + +/** + * Sets the Z position of all pieces of a multi-part object. + * @param pMultiObj Multi-part object to be adjusted + * @param newZ New Z order + */ + +void MultiSetZPosition(OBJECT *pMultiObj, int newZ) { + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // for all the objects that make up this multi-part + do { + // signal a change in the object + pMultiObj->flags |= DMA_CHANGED; + + // set the new z position + pMultiObj->zPos = newZ; + + // next obj in list + pMultiObj = pMultiObj->pSlave; + } + while (pMultiObj != NULL); +} + +/** + * Reshape a multi-part object. + * @param pMultiObj Multi-part object to re-shape + */ + +void MultiReshape(OBJECT *pMultiObj) { + SCNHANDLE hFrame; + + // validate object pointer + assert(pMultiObj >= objectList && pMultiObj <= objectList + NUM_OBJECTS - 1); + + // get objects current anim frame + hFrame = pMultiObj->hShape; + + if (hFrame != 0 && hFrame != pMultiObj->hMirror) { + // a valid shape frame which is different from previous + + // get pointer to frame + const FRAME *pFrame = (const FRAME *)LockMem(hFrame); + + // update previous + pMultiObj->hMirror = hFrame; + + while (READ_LE_UINT32(pFrame) != 0 && pMultiObj != NULL) { + // a normal image - update the current object with this image + AnimateObject(pMultiObj, READ_LE_UINT32(pFrame)); + + // move to next image for this frame + pFrame++; + + // move to next part of object + pMultiObj = pMultiObj->pSlave; + } + + // null the remaining object parts + while (pMultiObj != NULL) { + // set a null image for this object part + AnimateObject(pMultiObj, 0); + + // move to next part of object + pMultiObj = pMultiObj->pSlave; + } + } else if (hFrame == 0) { + // update previous + pMultiObj->hMirror = hFrame; + + // null all the object parts + while (pMultiObj != NULL) { + // set a null image for this object part + AnimateObject(pMultiObj, 0); + + // move to next part of object + pMultiObj = pMultiObj->pSlave; + } + } +} + +/** + * Returns the left-most point of a multi-part object. + * @param pMulti Multi-part object + */ + +int MultiLeftmost(OBJECT *pMulti) { + int left; + + // validate object pointer + assert(pMulti >= objectList && pMulti <= objectList + NUM_OBJECTS - 1); + + // init leftmost point to first object + left = fracToInt(pMulti->xPos); + + // for all the objects in this multi + while ((pMulti = pMulti->pSlave) != NULL) { + if (pMulti->hImg != 0) { + // non null object part + + if (fracToInt(pMulti->xPos) < left) + // this object is further left + left = fracToInt(pMulti->xPos); + } + } + + // return left-most point + return left; +} + +/** + * Returns the right-most point of a multi-part object. + * @param pMulti Multi-part object + */ + +int MultiRightmost(OBJECT *pMulti) { + int right; + + // validate object pointer + assert(pMulti >= objectList && pMulti <= objectList + NUM_OBJECTS - 1); + + // init right-most point to first object + right = fracToInt(pMulti->xPos) + pMulti->width; + + // for all the objects in this multi + while ((pMulti = pMulti->pSlave) != NULL) { + if (pMulti->hImg != 0) { + // non null object part + + if (fracToInt(pMulti->xPos) + pMulti->width > right) + // this object is further right + right = fracToInt(pMulti->xPos) + pMulti->width; + } + } + + // return right-most point + return right - 1; +} + +/** + * Returns the highest point of a multi-part object. + * @param pMulti Multi-part object + */ + +int MultiHighest(OBJECT *pMulti) { + int highest; + + // validate object pointer + assert(pMulti >= objectList && pMulti <= objectList + NUM_OBJECTS - 1); + + // init highest point to first object + highest = fracToInt(pMulti->yPos); + + // for all the objects in this multi + while ((pMulti = pMulti->pSlave) != NULL) { + if (pMulti->hImg != 0) { + // non null object part + + if (fracToInt(pMulti->yPos) < highest) + // this object is higher + highest = fracToInt(pMulti->yPos); + } + } + + // return highest point + return highest; +} + +/** + * Returns the lowest point of a multi-part object. + * @param pMulti Multi-part object + */ + +int MultiLowest(OBJECT *pMulti) { + int lowest; + + // validate object pointer + assert(pMulti >= objectList && pMulti <= objectList + NUM_OBJECTS - 1); + + // init lowest point to first object + lowest = fracToInt(pMulti->yPos) + pMulti->height; + + // for all the objects in this multi + while ((pMulti = pMulti->pSlave) != NULL) { + if (pMulti->hImg != 0) { + // non null object part + + if (fracToInt(pMulti->yPos) + pMulti->height > lowest) + // this object is lower + lowest = fracToInt(pMulti->yPos) + pMulti->height; + } + } + + // return lowest point + return lowest - 1; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/multiobj.h b/engines/tinsel/multiobj.h new file mode 100644 index 0000000000..6d25600ea2 --- /dev/null +++ b/engines/tinsel/multiobj.h @@ -0,0 +1,124 @@ +/* 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$ + * + * Multi-part object definitions + */ + +#ifndef TINSEL_MULTIOBJ_H // prevent multiple includes +#define TINSEL_MULTIOBJ_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +struct OBJECT; + +#include "common/pack-start.h" // START STRUCT PACKING + +/** + * multi-object initialisation structure (parallels OBJ_INIT struct) + */ +struct MULTI_INIT { + SCNHANDLE hMulFrame; //!< multi-objects shape - NULL terminated list of IMAGE structures + int32 mulFlags; //!< multi-objects flags + int32 mulID; //!< multi-objects id + int32 mulX; //!< multi-objects initial x ani position + int32 mulY; //!< multi-objects initial y ani position + int32 mulZ; //!< multi-objects initial z position +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + +/*----------------------------------------------------------------------*\ +|* Multi Object Function Prototypes *| +\*----------------------------------------------------------------------*/ + +OBJECT *MultiInitObject( // Initialise a multi-part object + const MULTI_INIT *pInitTbl); // pointer to multi-object initialisation table + +void MultiInsertObject( // Insert a multi-part object onto a object list + OBJECT *pObjList, // list to insert multi-part object onto + OBJECT *pInsObj); // head of multi-part object to insert + +void MultiDeleteObject( // Delete all the pieces of a multi-part object + OBJECT *pObjList, // list to delete multi-part object from + OBJECT *pMultiObj); // multi-part object to be deleted + +void MultiHideObject( // Hide a multi-part object + OBJECT *pMultiObj); // multi-part object to be hidden + +void MultiHorizontalFlip( // Hortizontally flip a multi-part object + OBJECT *pFlipObj); // head of multi-part object to flip + +void MultiVerticalFlip( // Vertically flip a multi-part object + OBJECT *pFlipObj); // head of multi-part object to flip + +void MultiAdjustXY( // Adjust coords of a multi-part object. Takes into account the orientation + OBJECT *pMultiObj, // multi-part object to be adjusted + int deltaX, // x adjustment + int deltaY); // y adjustment + +void MultiMoveRelXY( // Move multi-part object relative. Does not take into account the orientation + OBJECT *pMultiObj, // multi-part object to be moved + int deltaX, // x movement + int deltaY); // y movement + +void MultiSetAniXY( // Set the x & y anim position of a multi-part object + OBJECT *pMultiObj, // multi-part object whose position is to be changed + int newAniX, // new x animation position + int newAniY); // new y animation position + +void MultiSetAniX( // Set the x anim position of a multi-part object + OBJECT *pMultiObj, // multi-part object whose x position is to be changed + int newAniX); // new x animation position + +void MultiSetAniY( // Set the y anim position of a multi-part object + OBJECT *pMultiObj, // multi-part object whose y position is to be adjusted + int newAniY); // new y animation position + +void MultiSetZPosition( // Sets the z position of a multi-part object + OBJECT *pMultiObj, // multi-part object to be adjusted + int newZ); // new Z order + +void MultiMatchAniPoints( // Matches a multi-parts pos and orientation to be the same as a reference object + OBJECT *pMoveObj, // multi-part object to be moved + OBJECT *pRefObj); // multi-part object to match with + +void MultiReshape( // Reshape a multi-part object + OBJECT *pMultiObj); // multi-part object to re-shape + +int MultiLeftmost( // Returns the left-most point of a multi-part object + OBJECT *pMulti); // multi-part object + +int MultiRightmost( // Returns the right-most point of a multi-part object + OBJECT *pMulti); // multi-part object + +int MultiHighest( // Returns the highest point of a multi-part object + OBJECT *pMulti); // multi-part object + +int MultiLowest( // Returns the lowest point of a multi-part object + OBJECT *pMulti); // multi-part object + +} // end of namespace Tinsel + +#endif // TINSEL_MULTIOBJ_H diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp new file mode 100644 index 0000000000..8af905b0c8 --- /dev/null +++ b/engines/tinsel/music.cpp @@ -0,0 +1,554 @@ +/* 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$ + * + */ + +// FIXME: This code is taken from MADE and may need more work (e.g. setVolume). + +// MIDI and digital music class + +#include "sound/audiostream.h" +#include "sound/mididrv.h" +#include "sound/midiparser.h" +#include "sound/audiocd.h" +#include "common/config-manager.h" +#include "common/file.h" + +#include "tinsel/config.h" +#include "tinsel/sound.h" +#include "tinsel/music.h" + +namespace Tinsel { + +//--------------------------- Midi data ------------------------------------- + +// sound buffer structure used for MIDI data and samples +struct SOUND_BUFFER { + uint8 *pDat; // pointer to actual buffer + uint32 size; // size of the buffer +}; + +// get set when music driver is installed +//static MDI_DRIVER *mDriver; +//static HSEQUENCE mSeqHandle; + +// if non-zero this is the index position of the next MIDI sequence to play +static uint32 dwMidiIndex = 0; + +// MIDI buffer +static SOUND_BUFFER midiBuffer = { 0, 0 }; + +static SCNHANDLE currentMidi; +static bool currentLoop; + +const SCNHANDLE midiOffsetsGRAVersion[] = { + 4, 4534, 14298, 18828, 23358, 38888, 54418, 57172, 59926, 62450, + 62952, 67482, 72258, 74538, 79314, 87722, 103252, 115176, 127100, 127898, + 130256, 132614, 134972, 137330, 139688, 150196, 152554, 154912, 167422, 174762, + 182102, 194612, 198880, 199536, 206128, 206380, 216372, 226364, 235676, 244988, + 249098, 249606, 251160, 252714, 263116, 268706, 274296, 283562, 297986, 304566, + 312028, 313524, 319192, 324860, 331772, 336548, 336838, 339950, 343062, 346174, + 349286, 356246, 359358, 360434, 361510, 369966, 374366, 382822, 384202, 394946, + 396022, 396730, 399524, 401020, 403814, 418364, 419466, 420568, 425132, 433540, + 434384, 441504, 452132, 462760, 472804, 486772, 491302, 497722, 501260, 507680, + 509726, 521858, 524136, 525452, 533480, 538236, 549018, 559870, 564626, 565306, + 566734, 567616, 570144, 574102, 574900, 582518, 586350, 600736, 604734, 613812, + 616566, 619626, 623460, 627294, 631128, 634188, 648738, 663288, 667864, 681832, + 682048, 683014, 688908, 689124, 698888, 708652, 718416, 728180, 737944, 747708, + 752238, 765522, 766554, 772944, 774546, 776148, 776994, 781698, 786262, 789016, + 794630, 796422, 798998 +}; + +const SCNHANDLE midiOffsetsSCNVersion[] = { + 4, 4504, 11762, 21532, 26070, 28754, 33254, 40512, 56310, 72108, + 74864, 77620, 80152, 80662, 85200, 89982, 92268, 97050, 105466, 121264, + 133194, 145124, 145928, 148294, 150660, 153026, 155392, 157758, 168272, 170638, + 173004, 185522, 192866, 200210, 212728, 217000, 217662, 224254, 224756, 234754, + 244752, 245256, 245950, 255256, 264562, 268678, 269192, 270752, 272312, 282712, + 288312, 293912, 303186, 317624, 324210, 331680, 333208, 338884, 344560, 351478, + 356262, 356552, 359670, 362788, 365906, 369024, 376014, 379132, 380214, 381296, + 389758, 394164, 402626, 404012, 414762, 415844, 416552, 419352, 420880, 423680, + 438236, 439338, 440440, 445010, 453426, 454276, 461398, 472032, 482666, 492716, + 506690, 511226, 517654, 521198, 527626, 529676, 541814, 546210, 547532, 555562, + 560316, 571104, 581962, 586716, 587402, 588836, 589718, 592246, 596212, 597016, + 604636, 608474, 622862, 626860, 635944, 638700, 641456, 645298, 649140, 652982, + 655738, 670294, 684850, 689432, 703628, 703850, 704816, 706350, 706572, 716342, + 726112, 735882, 745652, 755422, 765192, 774962, 784732, 794502, 804272, 814042, + 823812, 832996, 846286, 847324, 853714, 855324, 856934, 857786, 862496, 867066, + 869822, 875436, 877234, 879818 +}; + +// TODO: finish this (currently unmapped tracks are 0) +const int enhancedAudioSCNVersion[] = { + 0, 0, 2, 0, 0, 0, 0, 3, 3, 4, + 4, 0, 0, 0, 0, 0, 0, 10, 3, 11, + 11, 0, 13, 13, 13, 13, 13, 0, 13, 13, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 24, 0, 0, 27, 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, 55, 56, 56, 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, 4, 4, 83, 83, 83, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 52, 4, + 0, 0, 0, 0 +}; + +int GetTrackNumber(SCNHANDLE hMidi) { + if (_vm->getFeatures() & GF_SCNFILES) { + for (int i = 0; i < ARRAYSIZE(midiOffsetsSCNVersion); i++) { + if (midiOffsetsSCNVersion[i] == hMidi) + return i; + } + } else { + for (int i = 0; i < ARRAYSIZE(midiOffsetsGRAVersion); i++) { + if (midiOffsetsGRAVersion[i] == hMidi) + return i; + } + } + + return -1; +} + +SCNHANDLE GetTrackOffset(int trackNumber) { + if (_vm->getFeatures() & GF_SCNFILES) { + assert(trackNumber < ARRAYSIZE(midiOffsetsSCNVersion)); + return midiOffsetsSCNVersion[trackNumber]; + } else { + assert(trackNumber < ARRAYSIZE(midiOffsetsGRAVersion)); + return midiOffsetsGRAVersion[trackNumber]; + } +} + +/** + * Plays the specified MIDI sequence through the sound driver. + * @param dwFileOffset File offset of MIDI sequence data + * @param bLoop Whether to loop the sequence + */ + +bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { + currentMidi = dwFileOffset; + currentLoop = bLoop; + + if (volMidi != 0) { + SetMidiVolume(volMidi); + // Support for compressed music from the music enhancement project + AudioCD.stop(); + + int trackNumber = GetTrackNumber(dwFileOffset); + if (trackNumber >= 0) { +#if 0 + // TODO: GRA version + int track = enhancedAudioSCNVersion[trackNumber]; + if (track > 0) + AudioCD.play(track, -1, 0, 0); +#endif + } else { + warning("Unknown MIDI offset %d", dwFileOffset); + } + + if (AudioCD.isPlaying()) + return true; + } + + // set file offset for this sequence + dwMidiIndex = dwFileOffset; + + // the index and length of the last tune loaded + static uint32 dwLastMidiIndex; + static uint32 dwLastSeqLen; + + uint32 dwSeqLen = 0; // length of the sequence + + if (dwMidiIndex == 0) + return true; + + if (dwMidiIndex != dwLastMidiIndex) { + Common::File midiStream; + + // open MIDI sequence file in binary mode + if (!midiStream.open(MIDI_FILE)) + error("Cannot find file %s", MIDI_FILE); + + // update index of last tune loaded + dwLastMidiIndex = dwMidiIndex; + + // move to correct position in the file + midiStream.seek(dwMidiIndex, SEEK_SET); + + // read the length of the sequence + dwSeqLen = midiStream.readUint32LE(); + + // make sure buffer is large enough for this sequence + assert(dwSeqLen > 0 && dwSeqLen <= midiBuffer.size); + + // stop any currently playing tune + _vm->_music->stop(); + + // read the sequence + if (midiStream.read(midiBuffer.pDat, dwSeqLen) != dwSeqLen) + error("File %s is corrupt", MIDI_FILE); + + midiStream.close(); + + _vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop); + + // Store the length + dwLastSeqLen = dwSeqLen; + } else { + // dwMidiIndex == dwLastMidiIndex + _vm->_music->stop(); + _vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop); + } + + // allow another sequence to play + dwMidiIndex = 0; + + return true; +} + +/** + * Returns TRUE if a Midi tune is currently playing. + */ + +bool MidiPlaying(void) { + if (AudioCD.isPlaying()) return true; + return _vm->_music->isPlaying(); +} + +/** + * Stops any currently playing midi. + */ + +bool StopMidi(void) { + currentMidi = 0; + currentLoop = false; + + AudioCD.stop(); + _vm->_music->stop(); + return true; +} + + +/** + * Gets the volume of the MIDI music. + */ +int GetMidiVolume() { + return volMidi; +} + +/** + * Sets the volume of the MIDI music. + * @param vol New volume - 0..MAXMIDIVOL + */ +void SetMidiVolume(int vol) { + assert(vol >= 0 && vol <= MAXMIDIVOL); + + if (vol == 0 && volMidi == 0) { + // Nothing to do + } else if (vol == 0 && volMidi != 0) { + // Stop current midi sequence + AudioCD.stop(); + StopMidi(); + } else if (vol != 0 && volMidi == 0) { + // Perhaps restart last midi sequence + if (currentLoop) { + PlayMidiSequence(currentMidi, true); + _vm->_music->setVolume(vol); + } + } else if (vol != 0 && volMidi != 0) { + // Alter current volume + _vm->_music->setVolume(vol); + } + + volMidi = vol; +} + +/** + * Opens and inits all MIDI sequence files. + */ +void OpenMidiFiles(void) { + Common::File midiStream; + + // Demo version has no midi file + if (_vm->getFeatures() & GF_DEMO) + return; + + if (midiBuffer.pDat) + // already allocated + return; + + // open MIDI sequence file in binary mode + if (!midiStream.open(MIDI_FILE)) + error("Cannot find file %s", MIDI_FILE); + + // gen length of the largest sequence + midiBuffer.size = midiStream.readUint32LE(); + if (midiStream.ioFailed()) + error("File %s is corrupt", MIDI_FILE); + + if (midiBuffer.size) { + // allocate a buffer big enough for the largest MIDI sequence + if ((midiBuffer.pDat = (uint8 *)malloc(midiBuffer.size)) != NULL) { + // clear out the buffer + memset(midiBuffer.pDat, 0, midiBuffer.size); +// VMM_lock(midiBuffer.pDat, midiBuffer.size); + } else { + //mSeqHandle = NULL; + } + } + + midiStream.close(); +} + +void DeleteMidiBuffer() { + free(midiBuffer.pDat); + midiBuffer.pDat = NULL; +} + +MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false) { + memset(_channel, 0, sizeof(_channel)); + _masterVolume = 0; + this->open(); + _xmidiParser = MidiParser::createParser_XMIDI(); +} + +MusicPlayer::~MusicPlayer() { + _driver->setTimerCallback(NULL, NULL); + stop(); + this->close(); + _xmidiParser->setMidiDriver(NULL); + delete _xmidiParser; +} + +void MusicPlayer::setVolume(int volume) { + Common::StackLock lock(_mutex); + + // FIXME: Could we simply change MAXMIDIVOL to match ScummVM's range? + volume = CLIP((255 * volume) / MAXMIDIVOL, 0, 255); + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); + + if (_masterVolume == volume) + return; + + _masterVolume = volume; + + for (int i = 0; i < 16; ++i) { + if (_channel[i]) { + _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); + } + } +} + +int MusicPlayer::open() { + // Don't ever call open without first setting the output driver! + if (!_driver) + return 255; + + int ret = _driver->open(); + if (ret) + return ret; + + _driver->setTimerCallback(this, &onTimer); + return 0; +} + +void MusicPlayer::close() { + stop(); + if (_driver) + _driver->close(); + _driver = 0; +} + +void MusicPlayer::send(uint32 b) { + byte channel = (byte)(b & 0x0F); + if ((b & 0xFFF0) == 0x07B0) { + // Adjust volume changes by master volume + byte volume = (byte)((b >> 16) & 0x7F); + _channelVolume[channel] = volume; + volume = volume * _masterVolume / 255; + b = (b & 0xFF00FFFF) | (volume << 16); + } else if ((b & 0xFFF0) == 0x007BB0) { + //Only respond to All Notes Off if this channel + //has currently been allocated + if (_channel[b & 0x0F]) + return; + } + + if (!_channel[channel]) + _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + + if (_channel[channel]) { + _channel[channel]->send(b); + + if ((b & 0xFFF0) == 0x0079B0) { + // We've just Reset All Controllers, so we need to + // re-adjust the volume. Otherwise, volume is reset to + // default whenever the music changes. + _channel[channel]->send(0x000007B0 | (((_channelVolume[channel] * _masterVolume) / 255) << 16) | channel); + } + } +} + +void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) { + switch (type) { + case 0x2F: // End of Track + if (_looping) + _parser->jumpToTick(0); + else + stop(); + break; + default: + //warning("Unhandled meta event: %02x", type); + break; + } +} + +void MusicPlayer::onTimer(void *refCon) { + MusicPlayer *music = (MusicPlayer *)refCon; + Common::StackLock lock(music->_mutex); + + if (music->_isPlaying) + music->_parser->onTimer(); +} + +void MusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) { + if (_isPlaying) + return; + + stop(); + + // It seems like not all music (the main menu music, for instance) set + // all the instruments explicitly. That means the music will sound + // different, depending on which music played before it. This appears + // to be a genuine glitch in the original. For consistency, reset all + // instruments to the default one (piano). + + for (int i = 0; i < 16; i++) { + _driver->send(0xC0 | i, 0, 0); + } + + // Load XMID resource data + + if (_xmidiParser->loadMusic(midiData, size)) { + MidiParser *parser = _xmidiParser; + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + + _parser = parser; + + _looping = loop; + _isPlaying = true; + } +} + +void MusicPlayer::stop() { + Common::StackLock lock(_mutex); + + _isPlaying = false; + if (_parser) { + _parser->unloadMusic(); + _parser = NULL; + } +} + +void MusicPlayer::pause() { + setVolume(-1); + _isPlaying = false; +} + +void MusicPlayer::resume() { + setVolume(GetMidiVolume()); + _isPlaying = true; +} + +void CurrentMidiFacts(SCNHANDLE *pMidi, bool *pLoop) { + *pMidi = currentMidi; + *pLoop = currentLoop; +} + +void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) { + AudioCD.stop(); + StopMidi(); + + currentMidi = Midi; + currentLoop = Loop; + + if (volMidi != 0 && Loop) { + PlayMidiSequence(currentMidi, true); + SetMidiVolume(volMidi); + } +} + +#if 0 +// Dumps all of the game's music in external XMIDI *.xmi files +void dumpMusic() { + Common::File midiFile; + Common::File outFile; + char outName[20]; + midiFile.open(MIDI_FILE); + int outFileSize = 0; + char buffer[20000]; + + int total = (_vm->getFeatures() & GF_SCNFILES) ? + ARRAYSIZE(midiOffsetsSCNVersion) : + ARRAYSIZE(midiOffsetsGRAVersion); + + for (int i = 0; i < total; i++) { + sprintf(outName, "track%03d.xmi", i + 1); + outFile.open(outName, Common::File::kFileWriteMode); + + if (_vm->getFeatures() & GF_SCNFILES) { + if (i < total - 1) + outFileSize = midiOffsetsSCNVersion[i + 1] - midiOffsetsSCNVersion[i] - 4; + else + outFileSize = midiFile.size() - midiOffsetsSCNVersion[i] - 4; + + midiFile.seek(midiOffsetsSCNVersion[i] + 4, SEEK_SET); + } else { + if (i < total - 1) + outFileSize = midiOffsetsGRAVersion[i + 1] - midiOffsetsGRAVersion[i] - 4; + else + outFileSize = midiFile.size() - midiOffsetsGRAVersion[i] - 4; + + midiFile.seek(midiOffsetsGRAVersion[i] + 4, SEEK_SET); + } + + assert(outFileSize < 20000); + midiFile.read(buffer, outFileSize); + outFile.write(buffer, outFileSize); + + outFile.close(); + } + + midiFile.close(); +} +#endif + +} // End of namespace Made diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h new file mode 100644 index 0000000000..80456e2a76 --- /dev/null +++ b/engines/tinsel/music.h @@ -0,0 +1,118 @@ +/* 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$ + * + */ + +// Music class + +#ifndef TINSEL_MUSIC_H +#define TINSEL_MUSIC_H + +#include "sound/mididrv.h" +#include "sound/midiparser.h" +#include "common/mutex.h" + +namespace Tinsel { + +#define MAXMIDIVOL 127 + +bool PlayMidiSequence( // Plays the specified MIDI sequence through the sound driver + uint32 dwFileOffset, // handle of MIDI sequence data + bool bLoop); // Whether to loop the sequence + +bool MidiPlaying(void); // Returns TRUE if a Midi tune is currently playing + +bool StopMidi(void); // Stops any currently playing midi + +void SetMidiVolume( // Sets the volume of the MIDI music. Returns the old volume + int vol); // new volume - 0..MAXMIDIVOL + +int GetMidiVolume(); + +void OpenMidiFiles(); +void DeleteMidiBuffer(); + +void CurrentMidiFacts(SCNHANDLE *pMidi, bool *pLoop); +void RestoreMidiFacts(SCNHANDLE Midi, bool Loop); + +int GetTrackNumber(SCNHANDLE hMidi); +SCNHANDLE GetTrackOffset(int trackNumber); + +void dumpMusic(); + + +class MusicPlayer : public MidiDriver { +public: + MusicPlayer(MidiDriver *driver); + ~MusicPlayer(); + + bool isPlaying() { return _isPlaying; } + void setPlaying(bool playing) { _isPlaying = playing; } + + void setVolume(int volume); + int getVolume() { return _masterVolume; } + + void playXMIDI(byte *midiData, uint32 size, bool loop); + void stop(); + void pause(); + void resume(); + void setLoop(bool loop) { _looping = loop; } + + //MidiDriver interface implementation + int open(); + void close(); + void send(uint32 b); + + void metaEvent(byte type, byte *data, uint16 length); + + void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { } + + // The original sets the "sequence timing" to 109 Hz, whatever that + // means. The default is 120. + + uint32 getBaseTempo(void) { return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; } + + //Channel allocation functions + MidiChannel *allocateChannel() { return 0; } + MidiChannel *getPercussionChannel() { return 0; } + + MidiParser *_parser; + Common::Mutex _mutex; + +protected: + + static void onTimer(void *data); + + MidiChannel *_channel[16]; + MidiDriver *_driver; + MidiParser *_xmidiParser; + byte _channelVolume[16]; + + bool _isPlaying; + bool _looping; + byte _masterVolume; +}; + +} // End of namespace Made + +#endif diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp new file mode 100644 index 0000000000..5ec0ec46e6 --- /dev/null +++ b/engines/tinsel/object.cpp @@ -0,0 +1,527 @@ +/* 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$ + * + * This file contains the Object Manager code. + */ + +#include "tinsel/object.h" +#include "tinsel/background.h" // for rcScreen definition +#include "tinsel/cliprect.h" // object clip rect defs +#include "tinsel/graphics.h" // low level interface +#include "tinsel/handle.h" + +#define OID_EFFECTS 0x2000 // generic special effects object id + +namespace Tinsel { + +// list of all objects +OBJECT *objectList = 0; + +// pointer to free object list +static OBJECT *pFreeObjects = 0; + +#ifdef DEBUG +// diagnostic object counters +static int numObj = 0; +static int maxObj = 0; +#endif + +void FreeObjectList(void) { + if (objectList) { + free(objectList); + objectList = NULL; + } +} + +/** + * Kills all objects and places them on the free list. + */ + +void KillAllObjects(void) { + int i; + +#ifdef DEBUG + // clear number of objects in use + numObj = 0; +#endif + + if (objectList == NULL) { + // first time - allocate memory for object list + objectList = (OBJECT *)calloc(NUM_OBJECTS, sizeof(OBJECT)); + + // make sure memory allocated + if (objectList == NULL) { + error("Cannot allocate memory for object data"); + } + } + + // place first object on free list + pFreeObjects = objectList; + + // link all other objects after first + for (i = 1; i < NUM_OBJECTS; i++) { + objectList[i - 1].pNext = objectList + i; + } + + // null the last object + objectList[NUM_OBJECTS - 1].pNext = NULL; +} + + +#ifdef DEBUG +/** + * Shows the maximum number of objects used at once. + */ + +void ObjectStats(void) { + printf("%i objects of %i used.\n", maxObj, NUM_OBJECTS); +} +#endif + +/** + * Allocate a object from the free list. + */ +OBJECT *AllocObject(void) { + OBJECT *pObj = pFreeObjects; // get a free object + + // check for no free objects + assert(pObj != NULL); + + // a free object exists + + // get link to next free object + pFreeObjects = pObj->pNext; + + // clear out object + memset(pObj, 0, sizeof(OBJECT)); + + // set default drawing mode and set changed bit + pObj->flags = DMA_WNZ | DMA_CHANGED; + +#ifdef DEBUG + // one more object in use + if (++numObj > maxObj) + maxObj = numObj; +#endif + + // return new object + return pObj; +} + +/** + * Copy one object to another. + * @param pDest Destination object + * @param pSrc Source object + */ +void CopyObject(OBJECT *pDest, OBJECT *pSrc) { + // save previous dimensions etc. + Common::Rect rcSave = pDest->rcPrev; + + // make a copy + memcpy(pDest, pSrc, sizeof(OBJECT)); + + // restore previous dimensions etc. + pDest->rcPrev = rcSave; + + // set changed flag in destination + pDest->flags |= DMA_CHANGED; + + // null the links + pDest->pNext = pDest->pSlave = NULL; +} + +/** + * Inserts an object onto the specified object list. The object + * lists are sorted in Z Y order. + * @param pObjList List to insert object onto + * @param pInsObj Object to insert + */ + +void InsertObject(OBJECT *pObjList, OBJECT *pInsObj) { + OBJECT *pPrev, *pObj; // object list traversal pointers + + // validate object pointer + assert(pInsObj >= objectList && pInsObj <= objectList + NUM_OBJECTS - 1); + + for (pPrev = pObjList, pObj = pObjList->pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) { + // check Z order + if (pInsObj->zPos < pObj->zPos) { + // object Z is lower than list Z - insert here + break; + } else if (pInsObj->zPos == pObj->zPos) { + // Z values are the same - sort on Y + if (fracToDouble(pInsObj->yPos) <= fracToDouble(pObj->yPos)) { + // object Y is lower than or same as list Y - insert here + break; + } + } + } + + // insert obj between pPrev and pObj + pInsObj->pNext = pObj; + pPrev->pNext = pInsObj; +} + + +/** + * Deletes an object from the specified object list and places it + * on the free list. + * @param pObjList List to delete object from + * @param pDelObj Object to delete + */ +void DelObject(OBJECT *pObjList, OBJECT *pDelObj) { + OBJECT *pPrev, *pObj; // object list traversal pointers + + // validate object pointer + assert(pDelObj >= objectList && pDelObj <= objectList + NUM_OBJECTS - 1); + +#ifdef DEBUG + // one less object in use + --numObj; + assert(numObj >= 0); +#endif + + for (pPrev = pObjList, pObj = pObjList->pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) { + if (pObj == pDelObj) { + // found object to delete + + if (IntersectRectangle(pDelObj->rcPrev, pDelObj->rcPrev, rcScreen)) { + // allocate a clipping rect for objects previous pos + AddClipRect(pDelObj->rcPrev); + } + + // make PREV next = OBJ next - removes OBJ from list + pPrev->pNext = pObj->pNext; + + // place free list in OBJ next + pObj->pNext = pFreeObjects; + + // add OBJ to top of free list + pFreeObjects = pObj; + + // delete objects palette + if (pObj->pPal) + FreePalette(pObj->pPal); + + // quit + return; + } + } + + // if we get to here - object has not been found on the list + error("DelObject(): formally 'assert(0)!'"); +} + + +/** + * Sort the specified object list in Z Y order. + * @param pObjList List to sort + */ +void SortObjectList(OBJECT *pObjList) { + OBJECT *pPrev, *pObj; // object list traversal pointers + OBJECT head; // temporary head of list - because pObjList is not usually a OBJECT + + // put at head of list + head.pNext = pObjList->pNext; + + // set head of list dummy OBJ Z Y values to lowest possible + head.yPos = intToFrac(MIN_INT16); + head.zPos = MIN_INT; + + for (pPrev = &head, pObj = head.pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) { + // check Z order + if (pObj->zPos < pPrev->zPos) { + // object Z is lower than previous Z + + // remove object from list + pPrev->pNext = pObj->pNext; + + // re-insert object on list + InsertObject(pObjList, pObj); + + // back to beginning of list + pPrev = &head; + pObj = head.pNext; + } else if (pObj->zPos == pPrev->zPos) { + // Z values are the same - sort on Y + if (fracToDouble(pObj->yPos) < fracToDouble(pPrev->yPos)) { + // object Y is lower than previous Y + + // remove object from list + pPrev->pNext = pObj->pNext; + + // re-insert object on list + InsertObject(pObjList, pObj); + + // back to beginning of list + pPrev = &head; + pObj = head.pNext; + } + } + } +} + +/** + * Returns the animation offsets of a image, dependent on the + * images orientation flags. + * @param hImg Iimage to get animation offset of + * @param flags Images current flags + * @param pAniX Gets set to new X animation offset + * @param pAniY Gets set to new Y animation offset + */ +void GetAniOffset(SCNHANDLE hImg, int flags, int *pAniX, int *pAniY) { + if (hImg) { + const IMAGE *pImg = (const IMAGE *)LockMem(hImg); + + // set ani X + *pAniX = FROM_LE_16(pImg->anioffX); + + // set ani Y + *pAniY = FROM_LE_16(pImg->anioffY); + + if (flags & DMA_FLIPH) { + // we are flipped horizontally + + // set ani X = -ani X + width - 1 + *pAniX = -*pAniX + FROM_LE_16(pImg->imgWidth) - 1; + } + + if (flags & DMA_FLIPV) { + // we are flipped vertically + + // set ani Y = -ani Y + height - 1 + *pAniY = -*pAniY + FROM_LE_16(pImg->imgHeight) - 1; + } + } else + // null image + *pAniX = *pAniY = 0; +} + + +/** + * Returns the x,y position of an objects animation point. + * @param pObj Pointer to object + * @param pPosX Gets set to objects X animation position + * @param pPosY Gets set to objects Y animation position + */ +void GetAniPosition(OBJECT *pObj, int *pPosX, int *pPosY) { + // validate object pointer + assert(pObj >= objectList && pObj <= objectList + NUM_OBJECTS - 1); + + // get the animation offset of the object + GetAniOffset(pObj->hImg, pObj->flags, pPosX, pPosY); + + // from animation offset and objects position - determine objects animation point + *pPosX += fracToInt(pObj->xPos); + *pPosY += fracToInt(pObj->yPos); +} + +/** + * Initialise a object using a OBJ_INIT structure to supply parameters. + * @param pInitTbl Pointer to object initialisation table + */ +OBJECT *InitObject(const OBJ_INIT *pInitTbl) { + // allocate a new object + OBJECT *pObj = AllocObject(); + + // make sure object created + assert(pObj != NULL); + + // set objects shape + pObj->hImg = pInitTbl->hObjImg; + + // set objects ID + pObj->oid = pInitTbl->objID; + + // set objects flags + pObj->flags = DMA_CHANGED | pInitTbl->objFlags; + + // set objects Z position + pObj->zPos = pInitTbl->objZ; + + // get pointer to image + if (pInitTbl->hObjImg) { + int aniX, aniY; // objects animation offsets + PPALQ pPalQ; // palette queue pointer + const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image + + // allocate a palette for this object + pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal)); + + // make sure palette allocated + assert(pPalQ != NULL); + + // assign palette to object + pObj->pPal = pPalQ; + + // set objects size + pObj->width = FROM_LE_16(pImg->imgWidth); + pObj->height = FROM_LE_16(pImg->imgHeight); + + // set objects bitmap definition + pObj->hBits = FROM_LE_32(pImg->hImgBits); + + // get animation offset of object + GetAniOffset(pObj->hImg, pInitTbl->objFlags, &aniX, &aniY); + + // set objects X position - subtract ani offset + pObj->xPos = intToFrac(pInitTbl->objX - aniX); + + // set objects Y position - subtract ani offset + pObj->yPos = intToFrac(pInitTbl->objY - aniY); + } else { // no image handle - null image + + // set objects X position + pObj->xPos = intToFrac(pInitTbl->objX); + + // set objects Y position + pObj->yPos = intToFrac(pInitTbl->objY); + } + + // return new object + return pObj; +} + +/** + * Give a object a new image and new orientation flags. + * @param pAniObj Object to be updated + * @param newflags Objects new flags + * @param hNewImg Objects new image + */ +void AnimateObjectFlags(OBJECT *pAniObj, int newflags, SCNHANDLE hNewImg) { + // validate object pointer + assert(pAniObj >= objectList && pAniObj <= objectList + NUM_OBJECTS - 1); + + if (pAniObj->hImg != hNewImg + || (pAniObj->flags & DMA_HARDFLAGS) != (newflags & DMA_HARDFLAGS)) { + // something has changed + + int oldAniX, oldAniY; // objects old animation offsets + int newAniX, newAniY; // objects new animation offsets + + // get objects old animation offsets + GetAniOffset(pAniObj->hImg, pAniObj->flags, &oldAniX, &oldAniY); + + // get objects new animation offsets + GetAniOffset(hNewImg, newflags, &newAniX, &newAniY); + + if (hNewImg) { + // get pointer to image + const IMAGE *pNewImg = (IMAGE *)LockMem(hNewImg); + + // setup new shape + pAniObj->width = FROM_LE_16(pNewImg->imgWidth); + pAniObj->height = FROM_LE_16(pNewImg->imgHeight); + + // set objects bitmap definition + pAniObj->hBits = FROM_LE_32(pNewImg->hImgBits); + } else { // null image + pAniObj->width = 0; + pAniObj->height = 0; + pAniObj->hBits = 0; + } + + // set objects flags and signal a change + pAniObj->flags = newflags | DMA_CHANGED; + + // set objects image + pAniObj->hImg = hNewImg; + + // adjust objects position - subtract new from old for difference + pAniObj->xPos += intToFrac(oldAniX - newAniX); + pAniObj->yPos += intToFrac(oldAniY - newAniY); + } +} + +/** + * Give an object a new image. + * @param pAniObj Object to animate + * @param hNewImg Objects new image + */ +void AnimateObject(OBJECT *pAniObj, SCNHANDLE hNewImg) { + // dont change the objects flags + AnimateObjectFlags(pAniObj, pAniObj->flags, hNewImg); +} + +/** + * Creates a rectangle object of the given dimensions and returns + * a pointer to the object. + * @param hPal Palette for the rectangle object + * @param colour Which colour offset from the above palette + * @param width Width of rectangle + * @param height Height of rectangle + */ +OBJECT *RectangleObject(SCNHANDLE hPal, int colour, int width, int height) { + // template for initialising the rectangle object + static const OBJ_INIT rectObj = {0, DMA_CONST, OID_EFFECTS, 0, 0, 0}; + PPALQ pPalQ; // palette queue pointer + + // allocate and init a new object + OBJECT *pRect = InitObject(&rectObj); + + // allocate a palette for this object + pPalQ = AllocPalette(hPal); + + // make sure palette allocated + assert(pPalQ != NULL); + + // assign palette to object + pRect->pPal = pPalQ; + + // set colour in the palette + pRect->constant = colour; + + // set rectangle width + pRect->width = width; + + // set rectangle height + pRect->height = height; + + // return pointer to rectangle object + return pRect; +} + +/** + * Creates a translucent rectangle object of the given dimensions + * and returns a pointer to the object. + * @param width Width of rectangle + * @param height Height of rectangle + */ +OBJECT *TranslucentObject(int width, int height) { + // template for initialising the rectangle object + static const OBJ_INIT rectObj = {0, DMA_TRANS, OID_EFFECTS, 0, 0, 0}; + + // allocate and init a new object + OBJECT *pRect = InitObject(&rectObj); + + // set rectangle width + pRect->width = width; + + // set rectangle height + pRect->height = height; + + // return pointer to rectangle object + return pRect; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/object.h b/engines/tinsel/object.h new file mode 100644 index 0000000000..01c56737e4 --- /dev/null +++ b/engines/tinsel/object.h @@ -0,0 +1,207 @@ +/* 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$ + * + * Object Manager data structures + */ + +#ifndef TINSEL_OBJECT_H // prevent multiple includes +#define TINSEL_OBJECT_H + +#include "tinsel/dw.h" +#include "common/frac.h" +#include "common/rect.h" + +namespace Tinsel { + +struct PALQ; + +enum { + /** the maximum number of objects */ + NUM_OBJECTS = 256, + + // object flags + DMA_WNZ = 0x0001, //!< write non-zero data + DMA_CNZ = 0x0002, //!< write constant on non-zero data + DMA_CONST = 0x0004, //!< write constant on both zero & non-zero data + DMA_WA = 0x0008, //!< write all data + DMA_FLIPH = 0x0010, //!< flip object horizontally + DMA_FLIPV = 0x0020, //!< flip object vertically + DMA_CLIP = 0x0040, //!< clip object + DMA_TRANS = 0x0084, //!< translucent rectangle object + DMA_ABS = 0x0100, //!< position of object is absolute + DMA_CHANGED = 0x0200, //!< object has changed in some way since the last frame + DMA_USERDEF = 0x0400, //!< user defined flags start here + + /** flags that effect an objects appearance */ + DMA_HARDFLAGS = (DMA_WNZ | DMA_CNZ | DMA_CONST | DMA_WA | DMA_FLIPH | DMA_FLIPV | DMA_TRANS) +}; + +/** structure for image */ +struct IMAGE { + short imgWidth; //!< image width + short imgHeight; //!< image height + short anioffX; //!< image x animation offset + short anioffY; //!< image y animation offset + SCNHANDLE hImgBits; //!< image bitmap handle + SCNHANDLE hImgPal; //!< image palette handle +}; +typedef IMAGE *PIMAGE; + + +/** a multi-object animation frame is a list of multi-image handles */ +typedef uint32 FRAME; + + +// object structure +struct OBJECT { + OBJECT *pNext; //!< pointer to next object in list + OBJECT *pSlave; //!< pointer to slave object (multi-part objects) +// char *pOnDispList; //!< pointer to display list byte for background objects +// frac_t xVel; //!< x velocity of object +// frac_t yVel; //!< y velocity of object + frac_t xPos; //!< x position of object + frac_t yPos; //!< y position of object + int zPos; //!< z position of object + Common::Rect rcPrev; //!< previous screen coordinates of object bounding rectangle + int flags; //!< object flags - see above for list + PALQ *pPal; //!< objects palette Q position + int constant; //!< which colour in palette for monochrome objects + int width; //!< width of object + int height; //!< height of object + SCNHANDLE hBits; //!< image bitmap handle + SCNHANDLE hImg; //!< handle to object image definition + SCNHANDLE hShape; //!< objects current animation frame + SCNHANDLE hMirror; //!< objects previous animation frame + int oid; //!< object identifier +}; + +#include "common/pack-start.h" // START STRUCT PACKING + +// object initialisation structure +struct OBJ_INIT { + SCNHANDLE hObjImg; // objects shape - handle to IMAGE structure + int32 objFlags; // objects flags + int32 objID; // objects id + int32 objX; // objects initial x position + int32 objY; // objects initial y position + int32 objZ; // objects initial z position +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + + +/*----------------------------------------------------------------------*\ +|* Object Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void KillAllObjects(void); // kill all objects and place them on free list + +void FreeObjectList(void); // free the object list + +#ifdef DEBUG +void ObjectStats(void); // Shows the maximum number of objects used at once +#endif + +OBJECT *AllocObject(void); // allocate a object from the free list + +void FreeObject( // place a object back on the free list + OBJECT *pFreeObj); // object to free + +void CopyObject( // copy one object to another + OBJECT *pDest, // destination object + OBJECT *pSrc); // source object + +void InsertObject( // insert a object onto a sorted object list + OBJECT *pObjList, // list to insert object onto + OBJECT *pInsObj); // object to insert + +void DelObject( // delete a object from a object list and add to free list + OBJECT *pObjList, // list to delete object from + OBJECT *pDelObj); // object to delete + +void SortObjectList( // re-sort an object list + OBJECT *pObjList); // list to sort + +OBJECT *GetNextObject( // object list iterator - returns next obj in list + OBJECT *pObjList, // which object list + OBJECT *pStrtObj); // object to start from - when NULL will start from beginning of list + +OBJECT *FindObject( // Searches the specified obj list for a object matching the specified OID + OBJECT *pObjList, // object list to search + int oidDesired, // object identifer of object to find + int oidMask); // mask to apply to object identifiers before comparison + +void GetAniOffset( // returns the anim offsets of a image, takes into account orientation + SCNHANDLE hImg, // image to get animation offset of + int flags, // images current flags + int *pAniX, // gets set to new X animation offset + int *pAniY); // gets set to new Y animation offset + +void GetAniPosition( // Returns a objects x,y animation point + OBJECT *pObj, // pointer to object + int *pPosX, // gets set to objects X animation position + int *pPosY); // gets set to objects Y animation position + +OBJECT *InitObject( // Init a object using a OBJ_INIT struct + const OBJ_INIT *pInitTbl); // pointer to object initialisation table + +void AnimateObjectFlags( // Give a object a new image and new orientation flags + OBJECT *pAniObj, // object to be updated + int newflags, // objects new flags + SCNHANDLE hNewImg); // objects new image + +void AnimateObject( // give a object a new image + OBJECT *pAniObj, // object to animate + SCNHANDLE hNewImg); // objects new image + +void HideObject( // Hides a object by giving it a "NullImage" image pointer + OBJECT *pObj); // object to be hidden + +OBJECT *RectangleObject( // create a rectangle object of the given dimensions + SCNHANDLE hPal, // palette for the rectangle object + int colour, // which colour offset from the above palette + int width, // width of rectangle + int height); // height of rectangle + +OBJECT *TranslucentObject( // create a translucent rectangle object of the given dimensions + int width, // width of rectangle + int height); // height of rectangle + +void ResizeRectangle( // resizes a rectangle object + OBJECT *pRect, // rectangle object pointer + int width, // new width of rectangle + int height); // new height of rectangle + + +// FIXME: This does not belong here +struct FILM; +struct FREEL; +struct MULTI_INIT; +IMAGE *GetImageFromReel(const FREEL *pfreel, const MULTI_INIT **ppmi = 0); +IMAGE *GetImageFromFilm(SCNHANDLE hFilm, int reel, const FREEL **ppfr = 0, + const MULTI_INIT **ppmi = 0, const FILM **ppfilm = 0); + + +} // end of namespace Tinsel + +#endif // TINSEL_OBJECT_H diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp new file mode 100644 index 0000000000..50a908afe3 --- /dev/null +++ b/engines/tinsel/palette.cpp @@ -0,0 +1,424 @@ +/* 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$ + * + * Palette Allocator for IBM PC. + */ + +#include "tinsel/dw.h" // TBLUE1 definition +#include "tinsel/graphics.h" +#include "tinsel/handle.h" // LockMem definition +#include "tinsel/palette.h" // palette allocator structures etc. +#include "tinsel/tinsel.h" + +#include "common/system.h" + +namespace Tinsel { + +/** background colour */ +static COLORREF bgndColour = BLACK; + +/** palette allocator data */ +static PALQ palAllocData[NUM_PALETTES]; + + +/** video DAC transfer Q length */ +#define VDACQLENGTH (NUM_PALETTES+2) + +/** video DAC transfer Q */ +static VIDEO_DAC_Q vidDACdata[VDACQLENGTH]; + +/** video DAC transfer Q head pointer */ +static VIDEO_DAC_Q *pDAChead; + +/** colour index of the 4 colours used for the translucent palette */ +#define COL_HILIGHT TBLUE1 + +/** the translucent palette lookup table */ +uint8 transPalette[MAX_COLOURS]; // used in graphics.cpp + +#ifdef DEBUG +// diagnostic palette counters +static int numPals = 0; +static int maxPals = 0; +static int maxDACQ = 0; +#endif + +/** + * Transfer palettes in the palette Q to Video DAC. + */ +void PalettesToVideoDAC(void) { + PPALQ pPalQ; // palette Q iterator + PVIDEO_DAC_Q pDACtail = vidDACdata; // set tail pointer + bool needUpdate = false; + + // while Q is not empty + while (pDAChead != pDACtail) { + PALETTE *pPalette; // pointer to hardware palette + COLORREF *pColours; // pointer to list of RGB triples + +#ifdef DEBUG + // make sure palette does not overlap + assert(pDACtail->destDACindex + pDACtail->numColours <= MAX_COLOURS); +#else + // make sure palette does not overlap + if (pDACtail->destDACindex + pDACtail->numColours > MAX_COLOURS) + pDACtail->numColours = MAX_COLOURS - pDACtail->destDACindex; +#endif + + if (pDACtail->bHandle) { + // we are using a palette handle + + // get hardware palette pointer + pPalette = (PALETTE *)LockMem(pDACtail->pal.hRGBarray); + + // get RGB pointer + pColours = pPalette->palRGB; + } else { + // we are using a palette pointer + pColours = pDACtail->pal.pRGBarray; + } + + if (pDACtail->numColours > 0) + needUpdate = true; + + // update the system palette + g_system->setPalette((byte *)pColours, pDACtail->destDACindex, pDACtail->numColours); + + // update tail pointer + pDACtail++; + + } + + // reset video DAC transfer Q head pointer + pDAChead = vidDACdata; + + // clear all palette moved bits + for (pPalQ = palAllocData; pPalQ < palAllocData + NUM_PALETTES; pPalQ++) + pPalQ->posInDAC &= ~PALETTE_MOVED; + + if (needUpdate) + _vm->screen().update(); +} + +/** + * Commpletely reset the palette allocator. + */ +void ResetPalAllocator(void) { +#ifdef DEBUG + // clear number of palettes in use + numPals = 0; +#endif + + // wipe out the palette allocator data + memset(palAllocData, 0, sizeof(palAllocData)); + + // reset video DAC transfer Q head pointer + pDAChead = vidDACdata; +} + +#ifdef DEBUG +/** + * Shows the maximum number of palettes used at once. + */ +void PaletteStats(void) { + printf("%i palettes of %i used.\n", maxPals, NUM_PALETTES); + printf("%i DAC queue entries of %i used.\n", maxDACQ, VDACQLENGTH); +} +#endif + +/** + * Places a palette in the video DAC queue. + * @param posInDAC Position in video DAC + * @param numColours Number of colours in palette + * @param hPalette Handle to palette + */ +void UpdateDACqueueHandle(int posInDAC, int numColours, SCNHANDLE hPalette) { + // check Q overflow + assert(pDAChead < vidDACdata + VDACQLENGTH); + + pDAChead->destDACindex = posInDAC & ~PALETTE_MOVED; // set index in video DAC + pDAChead->numColours = numColours; // set number of colours + pDAChead->pal.hRGBarray = hPalette; // set handle of palette + pDAChead->bHandle = true; // we are using a palette handle + + // update head pointer + ++pDAChead; + +#ifdef DEBUG + if ((pDAChead-vidDACdata) > maxDACQ) + maxDACQ = pDAChead-vidDACdata; +#endif +} + +/** + * Places a palette in the video DAC queue. + * @param posInDAC Position in video DAC + * @param numColours, Number of colours in palette + * @param pColours List of RGB triples + */ +void UpdateDACqueue(int posInDAC, int numColours, COLORREF *pColours) { + // check Q overflow + assert(pDAChead < vidDACdata + NUM_PALETTES); + + pDAChead->destDACindex = posInDAC & ~PALETTE_MOVED; // set index in video DAC + pDAChead->numColours = numColours; // set number of colours + pDAChead->pal.pRGBarray = pColours; // set addr of palette + pDAChead->bHandle = false; // we are not using a palette handle + + // update head pointer + ++pDAChead; + +#ifdef DEBUG + if ((pDAChead-vidDACdata) > maxDACQ) + maxDACQ = pDAChead-vidDACdata; +#endif +} + +/** + * Allocate a palette. + * @param hNewPal Palette to allocate + */ +PPALQ AllocPalette(SCNHANDLE hNewPal) { + PPALQ pPrev, p; // walks palAllocData + int iDAC; // colour index in video DAC + PPALQ pNxtPal; // next PALQ struct in palette allocator + PALETTE *pNewPal; + + // get pointer to new palette + pNewPal = (PALETTE *)LockMem(hNewPal); + + // search all structs in palette allocator - see if palette already allocated + for (p = palAllocData; p < palAllocData + NUM_PALETTES; p++) { + if (p->hPal == hNewPal) { + // found the desired palette in palette allocator + p->objCount++; // update number of objects using palette + return p; // return palette queue position + } + } + + // search all structs in palette allocator - find a free slot + iDAC = FGND_DAC_INDEX; // init DAC index to first available foreground colour + + for (p = palAllocData; p < palAllocData + NUM_PALETTES; p++) { + if (p->hPal == 0) { + // found a free slot in palette allocator + p->objCount = 1; // init number of objects using palette + p->posInDAC = iDAC; // set palettes start pos in video DAC + p->hPal = hNewPal; // set hardware palette data + p->numColours = FROM_LE_32(pNewPal->numColours); // set number of colours in palette + +#ifdef DEBUG + // one more palette in use + if (++numPals > maxPals) + maxPals = numPals; +#endif + + // Q the change to the video DAC + UpdateDACqueueHandle(p->posInDAC, p->numColours, p->hPal); + + // move all palettes after this one down (if necessary) + for (pPrev = p, pNxtPal = pPrev + 1; pNxtPal < palAllocData + NUM_PALETTES; pNxtPal++) { + if (pNxtPal->hPal != 0) { + // palette slot is in use + if (pNxtPal->posInDAC >= pPrev->posInDAC + pPrev->numColours) + // no need to move palettes down + break; + + // move palette down - indicate change + pNxtPal->posInDAC = pPrev->posInDAC + + pPrev->numColours | PALETTE_MOVED; + + // Q the palette change in position to the video DAC + UpdateDACqueueHandle(pNxtPal->posInDAC, + pNxtPal->numColours, + pNxtPal->hPal); + + // update previous palette to current palette + pPrev = pNxtPal; + } + } + + // return palette pointer + return p; + } + + // set new DAC index + iDAC = p->posInDAC + p->numColours; + } + + // no free palettes + error("AllocPalette(): formally 'assert(0)!'"); +} + +/** + * Free a palette allocated with "AllocPalette". + * @param pFreePal Palette queue entry to free + */ +void FreePalette(PPALQ pFreePal) { + // validate palette Q pointer + assert(pFreePal >= palAllocData && pFreePal <= palAllocData + NUM_PALETTES - 1); + + // reduce the palettes object reference count + pFreePal->objCount--; + + // make sure palette has not been deallocated too many times + assert(pFreePal->objCount >= 0); + + if (pFreePal->objCount == 0) { + pFreePal->hPal = 0; // palette is no longer in use + +#ifdef DEBUG + // one less palette in use + --numPals; + assert(numPals >= 0); +#endif + } +} + +/** + * Find the specified palette. + * @param hSrchPal Hardware palette to search for + */ +PPALQ FindPalette(SCNHANDLE hSrchPal) { + PPALQ pPal; // palette allocator iterator + + // search all structs in palette allocator + for (pPal = palAllocData; pPal < palAllocData + NUM_PALETTES; pPal++) { + if (pPal->hPal == hSrchPal) + // found palette in palette allocator + return pPal; + } + + // palette not found + return NULL; +} + +/** + * Swaps the palettes at the specified palette queue position. + * @param pPalQ Palette queue position + * @param hNewPal New palette + */ +void SwapPalette(PPALQ pPalQ, SCNHANDLE hNewPal) { + // convert handle to palette pointer + PALETTE *pNewPal = (PALETTE *)LockMem(hNewPal); + + // validate palette Q pointer + assert(pPalQ >= palAllocData && pPalQ <= palAllocData + NUM_PALETTES - 1); + + if (pPalQ->numColours >= (int)FROM_LE_32(pNewPal->numColours)) { + // new palette will fit the slot + + // install new palette + pPalQ->hPal = hNewPal; + + // Q the change to the video DAC + UpdateDACqueueHandle(pPalQ->posInDAC, FROM_LE_32(pNewPal->numColours), hNewPal); + } else { + // # colours are different - will have to update all following palette entries + + PPALQ pNxtPalQ; // next palette queue position + + for (pNxtPalQ = pPalQ + 1; pNxtPalQ < palAllocData + NUM_PALETTES; pNxtPalQ++) { + if (pNxtPalQ->posInDAC >= pPalQ->posInDAC + pPalQ->numColours) + // no need to move palettes down + break; + + // move palette down + pNxtPalQ->posInDAC = pPalQ->posInDAC + + pPalQ->numColours | PALETTE_MOVED; + + // Q the palette change in position to the video DAC + UpdateDACqueueHandle(pNxtPalQ->posInDAC, + pNxtPalQ->numColours, + pNxtPalQ->hPal); + + // update previous palette to current palette + pPalQ = pNxtPalQ; + } + } +} + +/** + * Statless palette iterator. Returns the next palette in the list + * @param pStrtPal Palette to start from - when NULL will start from beginning of list + */ +PPALQ GetNextPalette(PPALQ pStrtPal) { + if (pStrtPal == NULL) { + // start of palette iteration - return 1st palette + return (palAllocData[0].objCount) ? palAllocData : NULL; + } + + // validate palette Q pointer + assert(pStrtPal >= palAllocData && pStrtPal <= palAllocData + NUM_PALETTES - 1); + + // return next active palette in list + while (++pStrtPal < palAllocData + NUM_PALETTES) { + if (pStrtPal->objCount) + // active palette found + return pStrtPal; + } + + // non found + return NULL; +} + +/** + * Sets the current background colour. + * @param colour Colour to set the background to + */ +void SetBgndColour(COLORREF colour) { + // update background colour struct + bgndColour = colour; + + // Q the change to the video DAC + UpdateDACqueue(BGND_DAC_INDEX, 1, &bgndColour); +} + +/** + * Builds the translucent palette from the current backgrounds palette. + * @param hPalette Handle to current background palette + */ +void CreateTranslucentPalette(SCNHANDLE hPalette) { + // get a pointer to the palette + PALETTE *pPal = (PALETTE *)LockMem(hPalette); + + // leave background colour alone + transPalette[0] = 0; + + for (uint i = 0; i < FROM_LE_32(pPal->numColours); i++) { + // get the RGB colour model values + uint8 red = GetRValue(pPal->palRGB[i]); + uint8 green = GetGValue(pPal->palRGB[i]); + uint8 blue = GetBValue(pPal->palRGB[i]); + + // calculate the Value field of the HSV colour model + unsigned val = (red > green) ? red : green; + val = (val > blue) ? val : blue; + + // map the Value field to one of the 4 colours reserved for the translucent palette + val /= 63; + transPalette[i + 1] = (uint8)((val == 0) ? 0 : val + COL_HILIGHT - 1); + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/palette.h b/engines/tinsel/palette.h new file mode 100644 index 0000000000..ed648950fd --- /dev/null +++ b/engines/tinsel/palette.h @@ -0,0 +1,157 @@ +/* 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$ + * + * Palette Allocator Definitions + */ + +#ifndef TINSEL_PALETTE_H // prevent multiple includes +#define TINSEL_PALETTE_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +typedef uint32 COLORREF; + +#define RGB(r,g,b) ((COLORREF)TO_LE_32(((uint8)(r)|((uint16)(g)<<8))|(((uint32)(uint8)(b))<<16))) + +#define GetRValue(rgb) ((uint8)(FROM_LE_32(rgb))) +#define GetGValue(rgb) ((uint8)(((uint16)(FROM_LE_32(rgb))) >> 8)) +#define GetBValue(rgb) ((uint8)((FROM_LE_32(rgb))>>16)) + +enum { + MAX_COLOURS = 256, //!< maximum number of colours - for VGA 256 + BITS_PER_PIXEL = 8, //!< number of bits per pixel for VGA 256 + MAX_INTENSITY = 255, //!< the biggest value R, G or B can have + NUM_PALETTES = 3, //!< number of palettes + + // Discworld has some fixed apportioned bits in the palette. + BGND_DAC_INDEX = 0, //!< index of background colour in Video DAC + FGND_DAC_INDEX = 1, //!< index of first foreground colour in Video DAC + TBLUE1 = 228, //!< Blue used in translucent rectangles + TBLUE2 = 229, //!< Blue used in translucent rectangles + TBLUE3 = 230, //!< Blue used in translucent rectangles + TBLUE4 = 231, //!< Blue used in translucent rectangles + TALKFONT_COL = 233 +}; + +// some common colours + +#define BLACK (RGB(0, 0, 0)) +#define WHITE (RGB(MAX_INTENSITY, MAX_INTENSITY, MAX_INTENSITY)) +#define RED (RGB(MAX_INTENSITY, 0, 0)) +#define GREEN (RGB(0, MAX_INTENSITY, 0)) +#define BLUE (RGB(0, 0, MAX_INTENSITY)) +#define YELLOW (RGB(MAX_INTENSITY, MAX_INTENSITY, 0)) +#define MAGENTA (RGB(MAX_INTENSITY, 0, MAX_INTENSITY)) +#define CYAN (RGB(0, MAX_INTENSITY, MAX_INTENSITY)) + + +/** video DAC transfer Q structure */ +struct VIDEO_DAC_Q { + union { + SCNHANDLE hRGBarray; //!< handle of palette or + COLORREF *pRGBarray; //!< list of palette colours + } pal; + bool bHandle; //!< when set - use handle of palette + int destDACindex; //!< start index of palette in video DAC + int numColours; //!< number of colours in "hRGBarray" +}; +typedef VIDEO_DAC_Q *PVIDEO_DAC_Q; + +#include "common/pack-start.h" // START STRUCT PACKING + +/** hardware palette structure */ +struct PALETTE { + int32 numColours; //!< number of colours in the palette + COLORREF palRGB[MAX_COLOURS]; //!< actual palette colours +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + + +/** palette queue structure */ +struct PALQ { + SCNHANDLE hPal; //!< handle to palette data struct + int objCount; //!< number of objects using this palette + int posInDAC; //!< palette position in the video DAC + int numColours; //!< number of colours in the palette +}; +typedef PALQ *PPALQ; + + +#define PALETTE_MOVED 0x8000 // when this bit is set in the "posInDAC" + // field - the palette entry has moved + +// Translucent objects have NULL pPal +#define HasPalMoved(pPal) (((pPal) != NULL) && ((pPal)->posInDAC & PALETTE_MOVED)) + + +/*----------------------------------------------------------------------*\ +|* Palette Manager Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void ResetPalAllocator(void); // wipe out all palettes + +#ifdef DEBUG +void PaletteStats(void); // Shows the maximum number of palettes used at once +#endif + +void PalettesToVideoDAC(void); // Update the video DAC with palettes currently the the DAC queue + +void UpdateDACqueueHandle( + int posInDAC, // position in video DAC + int numColours, // number of colours in palette + SCNHANDLE hPalette); // handle to palette + +void UpdateDACqueue( // places a palette in the video DAC queue + int posInDAC, // position in video DAC + int numColours, // number of colours in palette + COLORREF *pColours); // list of RGB tripples + +PPALQ AllocPalette( // allocate a new palette + SCNHANDLE hNewPal); // palette to allocate + +void FreePalette( // free a palette allocated with "AllocPalette" + PPALQ pFreePal); // palette queue entry to free + +PPALQ FindPalette( // find a palette in the palette queue + SCNHANDLE hSrchPal); // palette to search for + +void SwapPalette( // swaps palettes at the specified palette queue position + PPALQ pPalQ, // palette queue position + SCNHANDLE hNewPal); // new palette + +PPALQ GetNextPalette( // returns the next palette in the queue + PPALQ pStrtPal); // queue position to start from - when NULL will start from beginning of queue + +COLORREF GetBgndColour(void); // returns current background colour + +void SetBgndColour( // sets current background colour + COLORREF colour); // colour to set the background to + +void CreateTranslucentPalette(SCNHANDLE BackPal); + +} // end of namespace Tinsel + +#endif // TINSEL_PALETTE_H diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp new file mode 100644 index 0000000000..22b7ca8275 --- /dev/null +++ b/engines/tinsel/pcode.cpp @@ -0,0 +1,597 @@ +/* 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$ + * + * Virtual processor. + */ + +#include "tinsel/dw.h" +#include "tinsel/events.h" // 'POINTED' etc. +#include "tinsel/handle.h" // LockMem() +#include "tinsel/inventory.h" // for inventory id's +#include "tinsel/pcode.h" // opcodes etc. +#include "tinsel/scn.h" // FindChunk() +#include "tinsel/serializer.h" +#include "tinsel/tinlib.h" // Library routines + +#include "common/util.h" + +namespace Tinsel { + +//----------------- EXTERN FUNCTIONS -------------------- + +extern int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const PINT_CONTEXT pic, RESUME_STATE *pResumeState); + +//----------------- LOCAL DEFINES -------------------- + +/** list of all opcodes */ +enum OPCODE { + OP_HALT = 0, //!< end of program + OP_IMM = 1, //!< loads signed immediate onto stack + OP_ZERO = 2, //!< loads zero onto stack + OP_ONE = 3, //!< loads one onto stack + OP_MINUSONE = 4, //!< loads minus one onto stack + OP_STR = 5, //!< loads string offset onto stack + OP_FILM = 6, //!< loads film offset onto stack + OP_FONT = 7, //!< loads font offset onto stack + OP_PAL = 8, //!< loads palette offset onto stack + OP_LOAD = 9, //!< loads local variable onto stack + OP_GLOAD = 10, //!< loads global variable onto stack - long offset to variable + OP_STORE = 11, //!< pops stack and stores in local variable - long offset to variable + OP_GSTORE = 12, //!< pops stack and stores in global variable - long offset to variable + OP_CALL = 13, //!< procedure call + OP_LIBCALL = 14, //!< library procedure call - long offset to procedure + OP_RET = 15, //!< procedure return + OP_ALLOC = 16, //!< allocate storage on stack + OP_JUMP = 17, //!< unconditional jump - signed word offset + OP_JMPFALSE = 18, //!< conditional jump - signed word offset + OP_JMPTRUE = 19, //!< conditional jump - signed word offset + OP_EQUAL = 20, //!< tests top two items on stack for equality + OP_LESS, //!< tests top two items on stack + OP_LEQUAL, //!< tests top two items on stack + OP_NEQUAL, //!< tests top two items on stack + OP_GEQUAL, //!< tests top two items on stack + OP_GREAT = 25, //!< tests top two items on stack + OP_PLUS, //!< adds top two items on stack and replaces with result + OP_MINUS, //!< subs top two items on stack and replaces with result + OP_LOR, //!< logical or of top two items on stack and replaces with result + OP_MULT, //!< multiplies top two items on stack and replaces with result + OP_DIV = 30, //!< divides top two items on stack and replaces with result + OP_MOD, //!< divides top two items on stack and replaces with modulus + OP_AND, //!< bitwise ands top two items on stack and replaces with result + OP_OR, //!< bitwise ors top two items on stack and replaces with result + OP_EOR, //!< bitwise exclusive ors top two items on stack and replaces with result + OP_LAND = 35, //!< logical ands top two items on stack and replaces with result + OP_NOT, //!< logical nots top item on stack + OP_COMP, //!< complements top item on stack + OP_NEG, //!< negates top item on stack + OP_DUP, //!< duplicates top item on stack + OP_ESCON = 40, //!< start of escapable sequence + OP_ESCOFF = 41, //!< end of escapable sequence + OP_CIMM, //!< loads signed immediate onto stack (special to case statements) + OP_CDFILM //!< loads film offset onto stack but not in current scene +}; + +// modifiers for the above opcodes +#define OPSIZE8 0x40 //!< when this bit is set - the operand size is 8 bits +#define OPSIZE16 0x80 //!< when this bit is set - the operand size is 16 bits + +#define OPMASK 0x3F //!< mask to isolate the opcode + + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static int32 *pGlobals = 0; // global vars + +static int numGlobals = 0; // How many global variables to save/restore + +static PINT_CONTEXT icList = 0; + +/** + * Keeps the code array pointer up to date. + */ +void LockCode(PINT_CONTEXT ic) { + if (ic->GSort == GS_MASTER) + ic->code = (byte *)FindChunk(MASTER_SCNHANDLE, CHUNK_PCODE); + else + ic->code = (byte *)LockMem(ic->hCode); +} + +/** + * Find a free interpret context and allocate it to the calling process. + */ +static PINT_CONTEXT AllocateInterpretContext(GSORT gsort) { + PINT_CONTEXT pic; + int i; + + for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { + if (pic->GSort == GS_NONE) { + pic->pProc = CurrentProcess(); + pic->GSort = gsort; + return pic; + } +#ifdef DEBUG + else { + if (pic->pProc == CurrentProcess()) + error("Found unreleased interpret context"); + } +#endif + } + + error("Out of interpret contexts"); +} + +/** + * Normal release of an interpret context. + * Called from the end of Interpret(). + */ +static void FreeInterpretContextPi(PINT_CONTEXT pic) { + pic->GSort = GS_NONE; +} + +/** + * Free interpret context owned by a dying process. + * Ensures that interpret contexts don't get lost when an Interpret() + * call doesn't complete. + */ +void FreeInterpretContextPr(PROCESS *pProc) { + PINT_CONTEXT pic; + int i; + + for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { + if (pic->GSort != GS_NONE && pic->pProc == pProc) { + pic->GSort = GS_NONE; + break; + } + } +} + +/** + * Free all interpret contexts except for the master script's + */ +void FreeMostInterpretContexts(void) { + PINT_CONTEXT pic; + int i; + + for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { + if (pic->GSort != GS_MASTER) { + pic->GSort = GS_NONE; + } + } +} + +/** + * Free the master script's interpret context. + */ +void FreeMasterInterpretContext(void) { + PINT_CONTEXT pic; + int i; + + for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { + if (pic->GSort == GS_MASTER) { + pic->GSort = GS_NONE; + return; + } + } +} + +/** + * Allocate and initialise an interpret context. + * Called from a process prior to Interpret(). + * @param gsort which sort of code + * @param hCode Handle to code to execute + * @param event Causal event + * @param hpoly Associated polygon (if any) + * @param actorId Associated actor (if any) + * @param pinvo Associated inventory object + */ +PINT_CONTEXT InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event, + HPOLYGON hpoly, int actorid, PINV_OBJECT pinvo) { + PINT_CONTEXT ic; + + ic = AllocateInterpretContext(gsort); + + // Previously parameters to Interpret() + ic->hCode = hCode; + LockCode(ic); + ic->event = event; + ic->hpoly = hpoly; + ic->actorid = actorid; + ic->pinvo = pinvo; + + // Previously local variables in Interpret() + ic->bHalt = false; // set to exit interpeter + ic->escOn = false; + ic->myescEvent = 0; // only initialised to prevent compiler warning! + ic->sp = 0; + ic->bp = ic->sp + 1; + ic->ip = 0; // start of code + + ic->resumeState = RES_NOT; + + return ic; +} + +/** + * Allocate and initialise an interpret context with restored data. + */ +PINT_CONTEXT RestoreInterpretContext(PINT_CONTEXT ric) { + PINT_CONTEXT ic; + + ic = AllocateInterpretContext(GS_NONE); // Sort will soon be overridden + + memcpy(ic, ric, sizeof(INT_CONTEXT)); + ic->pProc = CurrentProcess(); + ic->resumeState = RES_1; + + LockCode(ic); + + return ic; +} + +/** + * Allocates enough RAM to hold the global Glitter variables. + */ +void RegisterGlobals(int num) { + if (pGlobals == NULL) { + numGlobals = num; + + // Allocate RAM for pGlobals and make sure it's allocated + pGlobals = (int32 *)calloc(numGlobals, sizeof(int32)); + if (pGlobals == NULL) { + error("Cannot allocate memory for global data"); + } + + // Allocate RAM for interpret contexts and make sure it's allocated + icList = (PINT_CONTEXT)calloc(MAX_INTERPRET, sizeof(INT_CONTEXT)); + if (icList == NULL) { + error("Cannot allocate memory for interpret contexts"); + } + + SetResourceCallback(FreeInterpretContextPr); + } else { + // Check size is still the same + assert(numGlobals == num); + + memset(pGlobals, 0, numGlobals * sizeof(int32)); + memset(icList, 0, MAX_INTERPRET * sizeof(INT_CONTEXT)); + } +} + +void FreeGlobals(void) { + if (pGlobals) { + free(pGlobals); + pGlobals = NULL; + } + + if (icList) { + free(icList); + icList = NULL; + } +} + +/** + * (Un)serialize the global data for save/restore game. + */ +void syncGlobInfo(Serializer &s) { + for (int i = 0; i < numGlobals; i++) { + s.syncAsSint32LE(pGlobals[i]); + } +} + +/** + * (Un)serialize an interpreter context for save/restore game. + */ +void INT_CONTEXT::syncWithSerializer(Serializer &s) { + if (s.isLoading()) { + // Null out the pointer fields + pProc = NULL; + code = NULL; + pinvo = NULL; + } + // Write out used fields + s.syncAsUint32LE(GSort); + s.syncAsUint32LE(hCode); + s.syncAsUint32LE(event); + s.syncAsSint32LE(hpoly); + s.syncAsSint32LE(actorid); + + for (int i = 0; i < PCODE_STACK_SIZE; ++i) + s.syncAsSint32LE(stack[i]); + + s.syncAsSint32LE(sp); + s.syncAsSint32LE(bp); + s.syncAsSint32LE(ip); + s.syncAsUint32LE(bHalt); + s.syncAsUint32LE(escOn); + s.syncAsSint32LE(myescEvent); +} + +/** + * Return pointer to and size of global data for save/restore game. + */ +void SaveInterpretContexts(PINT_CONTEXT sICInfo) { + memcpy(sICInfo, icList, MAX_INTERPRET * sizeof(INT_CONTEXT)); +} + +/** + * Fetch (and sign extend, if necessary) a 8/16/32 bit value from the code + * stream and advance the instruction pointer accordingly. + */ +static int32 Fetch(byte opcode, byte *code, int &ip) { + int32 tmp; + if (opcode & OPSIZE8) { + // Fetch and sign extend a 8 bit value to 32 bits. + tmp = *(int8 *)(code + ip); + ip += 1; + } else if (opcode & OPSIZE16) { + // Fetch and sign extend a 16 bit value to 32 bits. + tmp = (int16)READ_LE_UINT16(code + ip); + ip += 2; + } else { + // Fetch a 32 bit value. + tmp = (int32)READ_LE_UINT32(code + ip); + ip += 4; + } + return tmp; +} + +/** + * Interprets the PCODE instructions in the code array. + */ +void Interpret(CORO_PARAM, PINT_CONTEXT ic) { + do { + int tmp, tmp2; + int ip = ic->ip; + byte opcode = ic->code[ip++]; + debug(7, " Opcode %d (-> %d)", opcode, opcode & OPMASK); + switch (opcode & OPMASK) { + case OP_HALT: // end of program + + ic->bHalt = true; + break; + + case OP_IMM: // loads immediate data onto stack + case OP_STR: // loads string handle onto stack + case OP_FILM: // loads film handle onto stack + case OP_CDFILM: // loads film handle onto stack + case OP_FONT: // loads font handle onto stack + case OP_PAL: // loads palette handle onto stack + + ic->stack[++ic->sp] = Fetch(opcode, ic->code, ip); + break; + + case OP_ZERO: // loads zero onto stack + ic->stack[++ic->sp] = 0; + break; + + case OP_ONE: // loads one onto stack + ic->stack[++ic->sp] = 1; + break; + + case OP_MINUSONE: // loads minus one onto stack + ic->stack[++ic->sp] = -1; + break; + + case OP_LOAD: // loads local variable onto stack + + ic->stack[++ic->sp] = ic->stack[ic->bp + Fetch(opcode, ic->code, ip)]; + break; + + case OP_GLOAD: // loads global variable onto stack + + tmp = Fetch(opcode, ic->code, ip); + assert(0 <= tmp && tmp < numGlobals); + ic->stack[++ic->sp] = pGlobals[tmp]; + break; + + case OP_STORE: // pops stack and stores in local variable + + ic->stack[ic->bp + Fetch(opcode, ic->code, ip)] = ic->stack[ic->sp--]; + break; + + case OP_GSTORE: // pops stack and stores in global variable + + tmp = Fetch(opcode, ic->code, ip); + assert(0 <= tmp && tmp < numGlobals); + pGlobals[tmp] = ic->stack[ic->sp--]; + break; + + case OP_CALL: // procedure call + + tmp = Fetch(opcode, ic->code, ip); + //assert(0 <= tmp && tmp < codeSize); // TODO: Verify jumps are not out of bounds + ic->stack[ic->sp + 1] = 0; // static link + ic->stack[ic->sp + 2] = ic->bp; // dynamic link + ic->stack[ic->sp + 3] = ip; // return address + ic->bp = ic->sp + 1; // set new base pointer + ip = tmp; // set ip to procedure address + break; + + case OP_LIBCALL: // library procedure or function call + + tmp = Fetch(opcode, ic->code, ip); + // NOTE: Interpret() itself is not using the coroutine facilities, + // but still accepts a CORO_PARAM, so from the outside it looks + // like a coroutine. In fact it may still acts as a kind of "proxy" + // for some underlying coroutine. To enable this, we just pass on + // 'coroParam' to CallLibraryRoutine(). If we then detect that + // coroParam was set to a non-zero value, this means that some + // coroutine code did run at some point, and we are now supposed + // to sleep or die -- hence, we 'return' if coroParam != 0. + // + // This works because Interpret() is fully re-entrant: If we return + // now and are later called again, then we will end up in the very + // same spot (i.e. here). + // + // The reasons we do it this way, instead of turning Interpret into + // a 'proper' coroutine are (1) we avoid implementation problems + // (CORO_INVOKE involves adding 'case' statements, but Interpret + // already has a huge switch/case, so that would not work out of the + // box), (2) we incurr less overhead, (3) it's easier to debug, + // (4) it's simply cool ;). + tmp2 = CallLibraryRoutine(coroParam, tmp, &ic->stack[ic->sp], ic, &ic->resumeState); + if (coroParam) + return; + ic->sp += tmp2; + LockCode(ic); + break; + + case OP_RET: // procedure return + + ic->sp = ic->bp - 1; // restore stack + ip = ic->stack[ic->sp + 3]; // return address + ic->bp = ic->stack[ic->sp + 2]; // restore previous base pointer + break; + + case OP_ALLOC: // allocate storage on stack + + ic->sp += Fetch(opcode, ic->code, ip); + break; + + case OP_JUMP: // unconditional jump + + ip = Fetch(opcode, ic->code, ip); + break; + + case OP_JMPFALSE: // conditional jump + + tmp = Fetch(opcode, ic->code, ip); + if (ic->stack[ic->sp--] == 0) { + // condition satisfied - do the jump + ip = tmp; + } + break; + + case OP_JMPTRUE: // conditional jump + + tmp = Fetch(opcode, ic->code, ip); + if (ic->stack[ic->sp--] != 0) { + // condition satisfied - do the jump + ip = tmp; + } + break; + + case OP_EQUAL: // tests top two items on stack for equality + case OP_LESS: // tests top two items on stack + case OP_LEQUAL: // tests top two items on stack + case OP_NEQUAL: // tests top two items on stack + case OP_GEQUAL: // tests top two items on stack + case OP_GREAT: // tests top two items on stack + case OP_LOR: // logical or of top two items on stack and replaces with result + case OP_LAND: // logical ands top two items on stack and replaces with result + + // pop one operand + ic->sp--; + assert(ic->sp >= 0); + tmp = ic->stack[ic->sp]; + tmp2 = ic->stack[ic->sp + 1]; + + // replace other operand with result of operation + switch (opcode) { + case OP_EQUAL: tmp = (tmp == tmp2); break; + case OP_LESS: tmp = (tmp < tmp2); break; + case OP_LEQUAL: tmp = (tmp <= tmp2); break; + case OP_NEQUAL: tmp = (tmp != tmp2); break; + case OP_GEQUAL: tmp = (tmp >= tmp2); break; + case OP_GREAT: tmp = (tmp > tmp2); break; + + case OP_LOR: tmp = (tmp || tmp2); break; + case OP_LAND: tmp = (tmp && tmp2); break; + } + + ic->stack[ic->sp] = tmp; + break; + + case OP_PLUS: // adds top two items on stack and replaces with result + case OP_MINUS: // subs top two items on stack and replaces with result + case OP_MULT: // multiplies top two items on stack and replaces with result + case OP_DIV: // divides top two items on stack and replaces with result + case OP_MOD: // divides top two items on stack and replaces with modulus + case OP_AND: // bitwise ands top two items on stack and replaces with result + case OP_OR: // bitwise ors top two items on stack and replaces with result + case OP_EOR: // bitwise exclusive ors top two items on stack and replaces with result + + // pop one operand + ic->sp--; + assert(ic->sp >= 0); + tmp = ic->stack[ic->sp]; + tmp2 = ic->stack[ic->sp + 1]; + + // replace other operand with result of operation + switch (opcode) { + case OP_PLUS: tmp += tmp2; break; + case OP_MINUS: tmp -= tmp2; break; + case OP_MULT: tmp *= tmp2; break; + case OP_DIV: tmp /= tmp2; break; + case OP_MOD: tmp %= tmp2; break; + case OP_AND: tmp &= tmp2; break; + case OP_OR: tmp |= tmp2; break; + case OP_EOR: tmp ^= tmp2; break; + } + ic->stack[ic->sp] = tmp; + break; + + case OP_NOT: // logical nots top item on stack + + ic->stack[ic->sp] = !ic->stack[ic->sp]; + break; + + case OP_COMP: // complements top item on stack + ic->stack[ic->sp] = ~ic->stack[ic->sp]; + break; + + case OP_NEG: // negates top item on stack + ic->stack[ic->sp] = -ic->stack[ic->sp]; + break; + + case OP_DUP: // duplicates top item on stack + ic->stack[ic->sp + 1] = ic->stack[ic->sp]; + ic->sp++; + break; + + case OP_ESCON: + ic->escOn = true; + ic->myescEvent = GetEscEvents(); + break; + + case OP_ESCOFF: + ic->escOn = false; + break; + + default: + error("Interpret() - Unknown opcode"); + } + + // check for stack under-overflow + assert(ic->sp >= 0 && ic->sp < PCODE_STACK_SIZE); + ic->ip = ip; + } while (!ic->bHalt); + + // make sure stack is unwound + assert(ic->sp == 0); + + FreeInterpretContextPi(ic); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/pcode.h b/engines/tinsel/pcode.h new file mode 100644 index 0000000000..1fc87e6e50 --- /dev/null +++ b/engines/tinsel/pcode.h @@ -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$ + * + * Virtual processor definitions + */ + +#ifndef TINSEL_PCODE_H // prevent multiple includes +#define TINSEL_PCODE_H + +#include "tinsel/events.h" // for USER_EVENT +//#include "tinsel/inventory.h" // for PINV_OBJECT +#include "tinsel/polygons.h" // for PPOLYGON +#include "tinsel/sched.h" // for PROCESS + +namespace Tinsel { + +// forward declaration +class Serializer; +struct INV_OBJECT; + +enum RESUME_STATE { + RES_NOT, RES_1, RES_2 +}; + +enum { + PCODE_STACK_SIZE = 128 //!< interpeters stack size +}; + +enum GSORT { + GS_NONE, GS_ACTOR, GS_MASTER, GS_POLYGON, GS_INVENTORY, GS_SCENE +}; + +struct INT_CONTEXT { + + // Elements for interpret context management + PROCESS *pProc; //!< processes owning this context + GSORT GSort; //!< sort of this context + + // Previously parameters to Interpret() + SCNHANDLE hCode; //!< scene handle of the code to execute + byte *code; //!< pointer to the code to execute + USER_EVENT event; //!< causal event + HPOLYGON hpoly; //!< associated polygon (if any) + int actorid; //!< associated actor (if any) + INV_OBJECT *pinvo; //!< associated inventory object + + // Previously local variables in Interpret() + int32 stack[PCODE_STACK_SIZE]; //!< interpeters run time stack + int sp; //!< stack pointer + int bp; //!< base pointer + int ip; //!< instruction pointer + bool bHalt; //!< set to exit interpeter + bool escOn; + int myescEvent; //!< only initialised to prevent compiler warning! + + RESUME_STATE resumeState; + + void syncWithSerializer(Serializer &s); +}; +typedef INT_CONTEXT *PINT_CONTEXT; + + +/*----------------------------------------------------------------------*\ +|* Interpreter Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void Interpret(CORO_PARAM, INT_CONTEXT *ic); // Interprets the PCODE instructions in the code array + +PINT_CONTEXT InitInterpretContext( + GSORT gsort, + SCNHANDLE hCode, // code to execute + USER_EVENT event, // causal event + HPOLYGON hpoly, // associated polygon (if any) + int actorid, // associated actor (if any) + INV_OBJECT *pinvo); // associated inventory object + +INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric); + +void FreeMostInterpretContexts(void); +void FreeMasterInterpretContext(void); + +void SaveInterpretContexts(INT_CONTEXT *sICInfo); + +void RegisterGlobals(int num); +void FreeGlobals(void); + + +#define MAX_INTERPRET (NUM_PROCESS - 20) + +/*----------------------------------------------------------------------*\ +|* Library Procedure and Function codes parameter enums *| +\*----------------------------------------------------------------------*/ + +#define TAG_DEF 0 // For tagactor() +#define TAG_Q1TO3 1 // tag types +#define TAG_Q1TO4 2 // tag types + +#define CONV_DEF 0 // +#define CONV_BOTTOM 1 // conversation() parameter +#define CONV_END 2 // + +#define CONTROL_OFF 0 // control() +#define CONTROL_ON 1 // parameter +#define CONTROL_OFFV 2 // +#define CONTROL_OFFV2 3 // +#define CONTROL_STARTOFF 4 // + +#define NULL_ACTOR (-1) // For actor parameters +#define LEAD_ACTOR (-2) // + +#define RAND_NORM 0 // For random() frills +#define RAND_NORPT 1 // + +#define D_UP 1 +#define D_DOWN 0 + +#define TW_START 1 // topwindow() parameter +#define TW_END 2 // + +#define MIDI_DEF 0 +#define MIDI_LOOP 1 + +#define TRANS_DEF 0 +#define TRANS_CUT 1 +#define TRANS_FADE 2 + +#define FM_IN 0 // +#define FM_OUT 1 // fademidi() + +#define FG_ON 0 // +#define FG_OFF 1 // FrameGrab() + +#define ST_ON 0 // +#define ST_OFF 1 // SubTitles() + +} // end of namespace Tinsel + +#endif // TINSEL_PCODE_H diff --git a/engines/tinsel/pdisplay.cpp b/engines/tinsel/pdisplay.cpp new file mode 100644 index 0000000000..a51f13e62e --- /dev/null +++ b/engines/tinsel/pdisplay.cpp @@ -0,0 +1,649 @@ +/* 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$ + * + * CursorPositionProcess() + * TagProcess() + * PointProcess() + */ + +#include "tinsel/actors.h" +#include "tinsel/background.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/events.h" +#include "tinsel/font.h" +#include "tinsel/graphics.h" +#include "tinsel/multiobj.h" +#include "tinsel/object.h" +#include "tinsel/pcode.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/sched.h" +#include "tinsel/strres.h" +#include "tinsel/text.h" + +namespace Tinsel { + +//----------------- EXTERNAL GLOBAL DATA -------------------- + +#ifdef DEBUG +//extern int Overrun; // The overrun counter, in DOS_DW.C + +extern int newestString; // The overrun counter, in STRRES.C +#endif + + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in BG.C +extern int BackgroundWidth(void); +extern int BackgroundHeight(void); + + + +//----------------- LOCAL DEFINES -------------------- + +#define LPOSX 295 // X-co-ord of lead actor's position display +#define CPOSX 24 // X-co-ord of cursor's position display +#define OPOSX SCRN_CENTRE_X // X-co-ord of overrun counter's display +#define SPOSX SCRN_CENTRE_X // X-co-ord of string numbner's display + +#define POSY 0 // Y-co-ord of these position displays + +#define ACTOR_TAG 0xffffffff + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static bool DispPath = false; +static bool bShowString = false; + +static int TaggedActor = 0; +static HPOLYGON hTaggedPolygon = NOPOLY; + +static enum { TAGS_OFF, TAGS_ON } TagsActive = TAGS_ON; + + +#ifdef DEBUG +/** + * Displays the cursor and lead actor's co-ordinates and the overrun + * counter. Also which path polygon the cursor is in, if required. + * + * This process is only started up if a Glitter showpos() call is made. + * Obviously, this is for testing purposes only... + */ +void CursorPositionProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + int prevsX, prevsY; // Last screen top left + int prevcX, prevcY; // Last displayed cursor position + int prevlX, prevlY; // Last displayed lead actor position +// int prevOver; // Last displayed overrun + int prevString; // Last displayed string number + + OBJECT *cpText; // cursor position text object pointer + OBJECT *cpathText; // cursor path text object pointer + OBJECT *rpText; // text object pointer +// OBJECT *opText; // text object pointer + OBJECT *spText; // string number text object pointer + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + _ctx->prevsX = -1; + _ctx->prevsY = -1; + _ctx->prevcX = -1; + _ctx->prevcY = -1; + _ctx->prevlX = -1; + _ctx->prevlY = -1; +// _ctx->prevOver = -1; + _ctx->prevString = -1; + + _ctx->cpText = NULL; + _ctx->cpathText = NULL; + _ctx->rpText = NULL; +// _ctx->opText = NULL; + _ctx->spText = NULL; + + + int aniX, aniY; // cursor/lead actor position + int Loffset, Toffset; // Screen top left + + char PositionString[64]; // sprintf() things into here + + PMACTOR pActor; // Lead actor + + while (1) { + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + /*-----------------------------------*\ + | Cursor's position and path display. | + \*-----------------------------------*/ + GetCursorXY(&aniX, &aniY, false); + + // Change in cursor position? + if (aniX != _ctx->prevcX || aniY != _ctx->prevcY || + Loffset != _ctx->prevsX || Toffset != _ctx->prevsY) { + // kill current text objects + if (_ctx->cpText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->cpText); + } + if (_ctx->cpathText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->cpathText); + _ctx->cpathText = NULL; + } + + // New text objects + sprintf(PositionString, "%d %d", aniX + Loffset, aniY + Toffset); + _ctx->cpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString, + 0, CPOSX, POSY, hTagFontHandle(), TXT_CENTRE); + if (DispPath) { + HPOLYGON hp = InPolygon(aniX + Loffset, aniY + Toffset, PATH); + if (hp == NOPOLY) + sprintf(PositionString, "No path"); + else + sprintf(PositionString, "%d,%d %d,%d %d,%d %d,%d", + PolyCornerX(hp, 0), PolyCornerY(hp, 0), + PolyCornerX(hp, 1), PolyCornerY(hp, 1), + PolyCornerX(hp, 2), PolyCornerY(hp, 2), + PolyCornerX(hp, 3), PolyCornerY(hp, 3)); + _ctx->cpathText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString, + 0, 4, POSY+ 10, hTagFontHandle(), 0); + } + + // update previous position + _ctx->prevcX = aniX; + _ctx->prevcY = aniY; + } + +#if 0 + /*------------------------*\ + | Overrun counter display. | + \*------------------------*/ + if (Overrun != _ctx->prevOver) { + // kill current text objects + if (_ctx->opText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->opText); + } + + sprintf(PositionString, "%d", Overrun); + _ctx->opText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString, + 0, OPOSX, POSY, hTagFontHandle(), TXT_CENTRE); + + // update previous value + _ctx->prevOver = Overrun; + } +#endif + + /*----------------------*\ + | Lead actor's position. | + \*----------------------*/ + pActor = GetMover(LEAD_ACTOR); + if (pActor && pActor->MActorState == NORM_MACTOR) { + // get lead's animation position + GetActorPos(LEAD_ACTOR, &aniX, &aniY); + + // Change in position? + if (aniX != _ctx->prevlX || aniY != _ctx->prevlY || + Loffset != _ctx->prevsX || Toffset != _ctx->prevsY) { + // Kill current text objects + if (_ctx->rpText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->rpText); + } + + // create new text object list + sprintf(PositionString, "%d %d", aniX, aniY); + _ctx->rpText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString, + 0, LPOSX, POSY, hTagFontHandle(), TXT_CENTRE); + + // update previous position + _ctx->prevlX = aniX; + _ctx->prevlY = aniY; + } + } + + /*-------------*\ + | String number | + \*-------------*/ + if (bShowString && newestString != _ctx->prevString) { + // kill current text objects + if (_ctx->spText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->spText); + } + + sprintf(PositionString, "String: %d", newestString); + _ctx->spText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), PositionString, + 0, SPOSX, POSY+10, hTalkFontHandle(), TXT_CENTRE); + + // update previous value + _ctx->prevString = newestString; + } + + // update previous playfield position + _ctx->prevsX = Loffset; + _ctx->prevsY = Toffset; + + CORO_SLEEP(1); // allow re-scheduling + } + CORO_END_CODE; +} +#endif + +/** + * Tag process keeps us updated as to which tagged actor is currently tagged + * (if one is). Tag process asks us for this information, as does User_Event(). + */ +static void SaveTaggedActor(int ano) { + TaggedActor = ano; +} + +/** + * Tag process keeps us updated as to which tagged actor is currently tagged + * (if one is). Tag process asks us for this information, as does User_Event(). + */ +int GetTaggedActor(void) { + return TaggedActor; +} + +/** + * Tag process keeps us updated as to which polygon is currently tagged + * (if one is). Tag process asks us for this information, as does User_Event(). + */ +static void SaveTaggedPoly(HPOLYGON hp) { + hTaggedPolygon = hp; +} + +HPOLYGON GetTaggedPoly(void) { + return hTaggedPolygon; +} + +/** + * Given cursor position and an actor number, ascertains whether the + * cursor is within the actor's tag area. + * Returns TRUE for a positive result, FALSE for negative. + * If TRUE, the mid-top co-ordinates of the actor's tag area are also + * returned. + */ +static bool InHotSpot(int ano, int aniX, int aniY, int *pxtext, int *pytext) { + int Top, Bot; // Top and bottom limits of active area + int left, right; // left and right of active area + int qrt = 0; // 1/4 of height (sometimes 1/2) + + // First check if within x-range + if (aniX > (left = GetActorLeft(ano)) && aniX < (right = GetActorRight(ano))) { + Top = GetActorTop(ano); + Bot = GetActorBottom(ano); + + // y-range varies according to tag-type + switch (TagType(ano)) { + case TAG_DEF: + // Next to bottom 1/4 of the actor's area + qrt = (Bot - Top) >> 1; // Half actor's height + Top += qrt; // Top = mid-height + + qrt = qrt >> 1; // Quarter height + Bot -= qrt; // Bot = 1/4 way up + break; + + case TAG_Q1TO3: + // Top 3/4 of the actor's area + qrt = (Bot - Top) >> 2; // 1/4 actor's height + Bot -= qrt; // Bot = 1/4 way up + break; + + case TAG_Q1TO4: + // All the actor's area + break; + + default: + error("illegal tag area type"); + } + + // Now check if within y-range + if (aniY >= Top && aniY <= Bot) { + if (TagType(ano) == TAG_Q1TO3) + *pytext = Top + qrt; + else + *pytext = Top; + *pxtext = (left + right) / 2; + return true; + } + } + return false; +} + +/** + * See if the cursor is over a tagged actor's hot-spot. If so, display + * the tag or, if tag already displayed, maintain the tag's position on + * the screen. + */ +static bool ActorTag(int curX, int curY, SCNHANDLE *pTag, OBJECT **ppText) { + static int Loffset = 0, Toffset = 0; // Values when tag was displayed + int nLoff, nToff; // new values, to keep tag in place + int ano; + int xtext, ytext; + bool newActor; + + // For each actor with a tag.... + FirstTaggedActor(); + while ((ano = NextTaggedActor()) != 0) { + if (InHotSpot(ano, curX, curY, &xtext, &ytext)) { + // Put up or maintain actor tag + if (*pTag != ACTOR_TAG) + newActor = true; + else if (ano != GetTaggedActor()) + newActor = true; // Different actor + else + newActor = false; // Same actor + + if (newActor) { + // Display actor's tag + + if (*ppText) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText); + + *pTag = ACTOR_TAG; + SaveTaggedActor(ano); // This actor tagged + SaveTaggedPoly(NOPOLY); // No tagged polygon + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + LoadStringRes(GetActorTag(ano), tBufferAddr(), TBUFSZ); + *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), + 0, xtext - Loffset, ytext - Toffset, hTagFontHandle(), TXT_CENTRE); + assert(*ppText); // Actor tag string produced NULL text + MultiSetZPosition(*ppText, Z_TAG_TEXT); + } else { + // Maintain actor tag's position + + PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff); + if (nLoff != Loffset || nToff != Toffset) { + MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff); + Loffset = nLoff; + Toffset = nToff; + } + } + return true; + } + } + + // No tagged actor + if (*pTag == ACTOR_TAG) { + *pTag = 0; + SaveTaggedActor(0); + } + return false; +} + +/** + * Perhaps some comment in due course. + * + * Under control of PointProcess(), when the cursor is over a TAG or + * EXIT polygon, its pointState flag is set to POINTING. If its Glitter + * code contains a printtag() call, its tagState flag gets set to TAG_ON. + */ +static bool PolyTag(SCNHANDLE *pTag, OBJECT **ppText) { + static int Loffset = 0, Toffset = 0; // Values when tag was displayed + int nLoff, nToff; // new values, to keep tag in place + HPOLYGON hp; + bool newPoly; + int shift; + + int tagx, tagy; // Tag display co-ordinates + SCNHANDLE hTagtext; // Tag text + + // For each polgon with a tag.... + for (int i = 0; i < MAX_POLY; i++) { + hp = GetPolyHandle(i); + + // Added code for un-tagged tags + if (hp != NOPOLY && PolyPointState(hp) == POINTING && PolyTagState(hp) != TAG_ON) { + // This poly is entitled to be tagged + if (hp != GetTaggedPoly()) { + if (*ppText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText); + *ppText = NULL; + } + *pTag = POLY_TAG; + SaveTaggedActor(0); // No tagged actor + SaveTaggedPoly(hp); // This polygon tagged + } + return true; + } else if (hp != NOPOLY && PolyTagState(hp) == TAG_ON) { + // Put up or maintain polygon tag + if (*pTag != POLY_TAG) + newPoly = true; // A new polygon (no current) + else if (hp != GetTaggedPoly()) + newPoly = true; // Different polygon + else + newPoly = false; // Same polygon + + if (newPoly) { + if (*ppText) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText); + + *pTag = POLY_TAG; + SaveTaggedActor(0); // No tagged actor + SaveTaggedPoly(hp); // This polygon tagged + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + getPolyTagInfo(hp, &hTagtext, &tagx, &tagy); + + int strLen; + if (PolyTagHandle(hp) != 0) + strLen = LoadStringRes(PolyTagHandle(hp), tBufferAddr(), TBUFSZ); + else + strLen = LoadStringRes(hTagtext, tBufferAddr(), TBUFSZ); + + if (strLen == 0) + // No valid string returned, so leave ppText as NULL + ppText = NULL; + else { + // Handle displaying the tag text on-screen + *ppText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), + 0, tagx - Loffset, tagy - Toffset, + hTagFontHandle(), TXT_CENTRE); + assert(*ppText); // Polygon tag string produced NULL text + MultiSetZPosition(*ppText, Z_TAG_TEXT); + + + /* + * New feature: Don't go off the side of the background + */ + shift = MultiRightmost(*ppText) + Loffset + 2; + if (shift >= BackgroundWidth()) // Not off right + MultiMoveRelXY(*ppText, BackgroundWidth() - shift, 0); + shift = MultiLeftmost(*ppText) + Loffset - 1; + if (shift <= 0) // Not off left + MultiMoveRelXY(*ppText, -shift, 0); + shift = MultiLowest(*ppText) + Toffset; + if (shift > BackgroundHeight()) // Not off bottom + MultiMoveRelXY(*ppText, 0, BackgroundHeight() - shift); + } + } else { + PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff); + if (nLoff != Loffset || nToff != Toffset) { + MultiMoveRelXY(*ppText, Loffset - nLoff, Toffset - nToff); + Loffset = nLoff; + Toffset = nToff; + } + } + return true; + } + } + + // No tagged polygon + if (*pTag == POLY_TAG) { + *pTag = 0; + SaveTaggedPoly(NOPOLY); + } + return false; +} + +/** + * Handle display of tagged actor and polygon tags. + * Tagged actor's get priority over polygons. + */ +void TagProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + OBJECT *pText; // text object pointer + SCNHANDLE Tag; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + _ctx->pText = NULL; + _ctx->Tag = 0; + + SaveTaggedActor(0); // No tagged actor yet + SaveTaggedPoly(NOPOLY); // No tagged polygon yet + + while (1) { + if (TagsActive == TAGS_ON) { + int curX, curY; // cursor position + while (!GetCursorXYNoWait(&curX, &curY, true)) + CORO_SLEEP(1); + + if (!ActorTag(curX, curY, &_ctx->Tag, &_ctx->pText) + && !PolyTag(&_ctx->Tag, &_ctx->pText)) { + // Nothing tagged. Remove tag, if there is one + if (_ctx->pText) { + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText); + _ctx->pText = NULL; + } + } + } else { + SaveTaggedActor(0); + SaveTaggedPoly(NOPOLY); + + // Remove tag, if there is one + if (_ctx->pText) { + // kill current text objects + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText); + _ctx->pText = NULL; + _ctx->Tag = 0; + } + } + + CORO_SLEEP(1); // allow re-scheduling + } + + CORO_END_CODE; +} + +/** + * Called from PointProcess() as appropriate. + */ +static void enteringpoly(HPOLYGON hp) { + SetPolyPointState(hp, POINTING); + + RunPolyTinselCode(hp, POINTED, BE_NONE, false); +} + +/** + * Called from PointProcess() as appropriate. + */ +static void leavingpoly(HPOLYGON hp) { + SetPolyPointState(hp, NOT_POINTING); + + if (PolyTagState(hp) == TAG_ON) { + // Delete this tag entry + SetPolyTagState(hp, TAG_OFF); + } +} + +/** + * For TAG and EXIT polygons, monitor cursor entering and leaving. + * Maintain the polygons' pointState and tagState flags accordingly. + * Also run the polygon's Glitter code when the cursor enters. + */ +void PointProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + while (1) { + int aniX, aniY; // cursor/tagged actor position + while (!GetCursorXYNoWait(&aniX, &aniY, true)) + CORO_SLEEP(1); + + /*----------------------------------*\ + | For polygons of type TAG and EXIT. | + \*----------------------------------*/ + for (int i = 0; i < MAX_POLY; i++) { + HPOLYGON hp = GetPolyHandle(i); + + if (hp != NOPOLY && (PolyType(hp) == TAG || PolyType(hp) == EXIT)) { + if (PolyPointState(hp) == NOT_POINTING) { + if (IsInPolygon(aniX, aniY, hp)) { + enteringpoly(hp); + } + } else if (PolyPointState(hp) == POINTING) { + if (!IsInPolygon(aniX, aniY, hp)) { + leavingpoly(hp); + } + } + } + } + + // allow re-scheduling + CORO_SLEEP(1); + } + + CORO_END_CODE; +} + +void DisableTags(void) { + TagsActive = TAGS_OFF; +} + +void EnableTags(void) { + TagsActive = TAGS_ON; +} + +bool DisableTagsIfEnabled(void) { + if (TagsActive == TAGS_OFF) + return false; + else { + TagsActive = TAGS_OFF; + return true; + } +} + +/** + * For testing purposes only. + * Causes CursorPositionProcess() to display, or not, the path that the + * cursor is in. + */ +void TogglePathDisplay(void) { + DispPath ^= 1; // Toggle path display (XOR with true) +} + + +void setshowstring(void) { + bShowString = true; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/pid.h b/engines/tinsel/pid.h new file mode 100644 index 0000000000..c2af1a5fcb --- /dev/null +++ b/engines/tinsel/pid.h @@ -0,0 +1,72 @@ +/* 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$ + * + * List of all process identifiers + */ + +#ifndef TINSEL_PID_H // prevent multiple includes +#define TINSEL_PID_H + +namespace Tinsel { + +#define PID_DESTROY 0x8000 // process id of any process that is to be destroyed between scenes + +#define PID_EFFECTS (0x0010 | PID_DESTROY) // generic special effects process id +#define PID_FLASH (PID_EFFECTS + 1) // flash colour process +#define PID_CYCLE (PID_EFFECTS + 2) // cycle colour range process +#define PID_MORPH (PID_EFFECTS + 3) // morph process +#define PID_FADER (PID_EFFECTS + 4) // fader process +#define PID_FADE_BGND (PID_EFFECTS + 5) // fade background colour process + +#define PID_BACKGND (0x0020 | PID_DESTROY) // background update process id + +#define PID_MOUSE 0x0030 // mouse button checking process id + +#define PID_JOYSTICK 0x0040 // joystick button checking process id + +#define PID_KEYBOARD 0x0050 // keyboard scanning process + +#define PID_CURSOR 0x0060 // cursor process +#define PID_CUR_TRAIL (PID_CURSOR + 1) // cursor trail process + +#define PID_SCROLL (0x0070 | PID_DESTROY) // scroll process + +#define PID_INVENTORY 0x0080 // inventory process + +#define PID_POSITION (0x0090 | PID_DESTROY) // cursor position process + +#define PID_TAG (0x00A0 | PID_DESTROY) // tag process + +#define PID_TCODE (0x00B0 | PID_DESTROY) // tinsel code process + +#define PID_MASTER_SCR 0x00C0 // tinsel master script process + +#define PID_MACTOR (0x00D0 | PID_DESTROY) // moving actor process + +#define PID_REEL (0x00E0 | PID_DESTROY) // process for each film reel + +#define PID_MIDI (0x00F0 | PID_DESTROY) // process to poll MIDI sound driver + +} // end of namespace Tinsel + +#endif // TINSEL_PID_H diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp new file mode 100644 index 0000000000..6daf851fd2 --- /dev/null +++ b/engines/tinsel/play.cpp @@ -0,0 +1,507 @@ +/* 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$ + * + * Plays films within a scene, takes into account the actor in each 'column'. | + */ + +#include "tinsel/actors.h" +#include "tinsel/background.h" +#include "tinsel/dw.h" +#include "tinsel/film.h" +#include "tinsel/handle.h" +#include "tinsel/multiobj.h" +#include "tinsel/object.h" +#include "tinsel/pid.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/sched.h" +#include "tinsel/timers.h" +#include "tinsel/tinlib.h" // stand() + +namespace Tinsel { + +/** + * Poke the background palette into an image. + */ +static void PokeInPalette(SCNHANDLE hMulFrame) { + const FRAME *pFrame; // Pointer to frame + PIMAGE pim; // Pointer to image + + // Could be an empty column + if (hMulFrame) { + pFrame = (const FRAME *)LockMem(hMulFrame); + + // get pointer to image + pim = (PIMAGE)LockMem(READ_LE_UINT32(pFrame)); // handle to image + + pim->hImgPal = TO_LE_32(BackPal()); + } +} + + +int32 NoNameFunc(int actorID, bool bNewMover) { + PMACTOR pActor; + int32 retval; + + pActor = GetMover(actorID); + + if (pActor != NULL && !bNewMover) { + // If no path, just use first path in the scene + if (pActor->hCpath == NOPOLY) + retval = getPolyZfactor(FirstPathPoly()); + else + retval = getPolyZfactor(pActor->hCpath); + } else { + switch (actorMaskType(actorID)) { + case ACT_DEFAULT: + retval = 0; + break; + case ACT_MASK: + retval = 0; + break; + case ACT_ALWAYS: + retval = 10; + break; + default: + retval = actorMaskType(actorID); + break; + } + } + + return retval; +} + +struct PPINIT { + SCNHANDLE hFilm; // The 'film' + short x; // } Co-ordinates from the play() + short y; // } - set to (-1, -1) if none. + short z; // normally 0, set if from restore + short speed; // Film speed + short actorid; // Set if called from an actor code block + bool splay; // Set if called from splay() + bool bTop; // Set if called from topplay() + short sf; // SlowFactor - only used for moving actors + short column; // Column number, first column = 0 + + bool escOn; + int myescEvent; +}; + + +/** + * - Don't bother if this reel is already playing for this actor. + * - If explicit co-ordinates, use these, If embedded co-ordinates, + * leave alone, otherwise use actor's current position. + * - Moving actors get hidden during this play, other actors get + * _ctx->replaced by this play. + * - Column 0 of a film gets its appropriate Z-position, slave columns + * get slightly bigger Z-positions, in column order. + * - Play proceeds until the script finishes, another reel starts up for + * this actor, or the actor gets killed. + * - If called from an splay(), moving actor's co-ordinates are updated + * after the play, any walk still in progress will go on from there. + */ +void PlayReel(CORO_PARAM, const PPINIT *ppi) { + CORO_BEGIN_CONTEXT; + OBJECT *pPlayObj; // Object + ANIM thisAnim; // Animation structure + + bool mActor; // Gets set if this is a moving actor + bool lifeNoMatter; + bool replaced; + + const FREEL *pfreel; // The 'column' to play + int stepCount; + int frameCount; + int reelActor; + CORO_END_CONTEXT(_ctx); + + static int firstColZ = 0; // Z-position of column zero + static int32 fColZfactor = 0; // Z-factor of column zero's actor + + CORO_BEGIN_CODE(_ctx); + + const MULTI_INIT *pmi; // MULTI_INIT structure + PMACTOR pActor; + bool bNewMover; // Gets set if a moving actor that isn't in scene yet + + const FILM *pfilm; + + _ctx->lifeNoMatter = false; + _ctx->replaced = false; + pActor = NULL; + bNewMover = false; + + pfilm = (const FILM *)LockMem(ppi->hFilm); + _ctx->pfreel = &pfilm->reels[ppi->column]; + + // Get the MULTI_INIT structure + pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(_ctx->pfreel->mobj)); + + // Save actor's ID + _ctx->reelActor = (int32)FROM_LE_32(pmi->mulID); + + /**** New (experimental? bit 5/1/95 ****/ + if (!actorAlive(_ctx->reelActor)) + return; + /**** Delete a bit down there if this stays ****/ + + updateActorEsc(_ctx->reelActor, ppi->escOn, ppi->myescEvent); + + // To handle the play()-talk(), talk()-play(), talk()-talk() and play()-play() scenarios + if (ppi->hFilm != getActorLatestFilm(_ctx->reelActor)) { + // This in not the last film scheduled for this actor + + // It may be the last non-talk film though + if (isActorTalking(_ctx->reelActor)) + setActorPlayFilm(_ctx->reelActor, ppi->hFilm); // Revert to this film after talk + + return; + } + if (isActorTalking(_ctx->reelActor)) { + // Note: will delete this and there'll be no need to store the talk film! + if (ppi->hFilm != getActorTalkFilm(_ctx->reelActor)) { + setActorPlayFilm(_ctx->reelActor, ppi->hFilm); // Revert to this film after talk + return; + } + } else { + setActorPlayFilm(_ctx->reelActor, ppi->hFilm); + } + + // If this reel is already playing for this actor, just forget it. + if (actorReel(_ctx->reelActor) == _ctx->pfreel) + return; + + // Poke in the background palette + PokeInPalette(FROM_LE_32(pmi->hMulFrame)); + + // Set up and insert the multi-object + _ctx->pPlayObj = MultiInitObject(pmi); + if (!ppi->bTop) + MultiInsertObject(GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj); + else + MultiInsertObject(GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj); + + // If co-ordinates are specified, use specified. + // Otherwise, use actor's position if there are not embedded co-ords. + // Add this first test for nth columns with offsets + // in plays with (x,y) + int tmpX, tmpY; + tmpX = ppi->x; + tmpY = ppi->y; + if (ppi->column != 0 && (pmi->mulX || pmi->mulY)) { + } else if (tmpX != -1 || tmpY != -1) { + MultiSetAniXY(_ctx->pPlayObj, tmpX, tmpY); + } else if (!pmi->mulX && !pmi->mulY) { + GetActorPos(_ctx->reelActor, &tmpX, &tmpY); + MultiSetAniXY(_ctx->pPlayObj, tmpX, tmpY); + } + + // If it's a moving actor, this hides the moving actor + // used to do this only if (actorid == 0) - I don't know why + _ctx->mActor = HideMovingActor(_ctx->reelActor, ppi->sf); + + // If it's a moving actor, get its MACTOR structure. + // If it isn't in the scene yet, get its task running - using + // stand() - to prevent a glitch at the end of the play. + if (_ctx->mActor) { + pActor = GetMover(_ctx->reelActor); + if (getMActorState(pActor) == NO_MACTOR) { + stand(_ctx->reelActor, MAGICX, MAGICY, 0); + bNewMover = true; + } + } + + // Register the fact that we're playing this for this actor + storeActorReel(_ctx->reelActor, _ctx->pfreel, ppi->hFilm, _ctx->pPlayObj, ppi->column, tmpX, tmpY); + + /**** Will get rid of this if the above is kept ****/ + // We may be temporarily resuscitating a dead actor + if (ppi->actorid == 0 && !actorAlive(_ctx->reelActor)) + _ctx->lifeNoMatter = true; + + InitStepAnimScript(&_ctx->thisAnim, _ctx->pPlayObj, FROM_LE_32(_ctx->pfreel->script), ppi->speed); + + // If first column, set Z position as per + // Otherwise, column 0's + column number + // N.B. It HAS been ensured that the first column gets here first + if (ppi->z != 0) { + MultiSetZPosition(_ctx->pPlayObj, ppi->z); + storeActorZpos(_ctx->reelActor, ppi->z); + } else if (ppi->bTop) { + if (ppi->column == 0) { + firstColZ = Z_TOPPLAY + actorMaskType(_ctx->reelActor); + MultiSetZPosition(_ctx->pPlayObj, firstColZ); + storeActorZpos(_ctx->reelActor, firstColZ); + } else { + MultiSetZPosition(_ctx->pPlayObj, firstColZ + ppi->column); + storeActorZpos(_ctx->reelActor, firstColZ + ppi->column); + } + } else if (ppi->column == 0) { + if (_ctx->mActor && !bNewMover) { + // If no path, just use first path in the scene + if (pActor->hCpath == NOPOLY) + fColZfactor = getPolyZfactor(FirstPathPoly()); + else + fColZfactor = getPolyZfactor(pActor->hCpath); + firstColZ = AsetZPos(_ctx->pPlayObj, MultiLowest(_ctx->pPlayObj), fColZfactor); + } else { + switch (actorMaskType(_ctx->reelActor)) { + case ACT_DEFAULT: + fColZfactor = 0; + firstColZ = 2; + MultiSetZPosition(_ctx->pPlayObj, firstColZ); + break; + case ACT_MASK: + fColZfactor = 0; + firstColZ = MultiLowest(_ctx->pPlayObj); + MultiSetZPosition(_ctx->pPlayObj, firstColZ); + break; + case ACT_ALWAYS: + fColZfactor = 10; + firstColZ = 10000; + MultiSetZPosition(_ctx->pPlayObj, firstColZ); + break; + default: + fColZfactor = actorMaskType(_ctx->reelActor); + firstColZ = AsetZPos(_ctx->pPlayObj, MultiLowest(_ctx->pPlayObj), fColZfactor); + if (firstColZ < 2) { + // This is an experiment! + firstColZ = 2; + MultiSetZPosition(_ctx->pPlayObj, firstColZ); + } + break; + } + } + storeActorZpos(_ctx->reelActor, firstColZ); + } else { + if (NoNameFunc(_ctx->reelActor, bNewMover) > fColZfactor) { + fColZfactor = NoNameFunc(_ctx->reelActor, bNewMover); + firstColZ = fColZfactor << 10; + } + MultiSetZPosition(_ctx->pPlayObj, firstColZ + ppi->column); + storeActorZpos(_ctx->reelActor, firstColZ + ppi->column); + } + + /* + * Play until the script finishes, + * another reel starts up for this actor, + * or the actor gets killed. + */ + _ctx->stepCount = 0; + _ctx->frameCount = 0; + do { + if (_ctx->stepCount++ == 0) { + _ctx->frameCount++; + storeActorSteps(_ctx->reelActor, _ctx->frameCount); + } + if (_ctx->stepCount == ppi->speed) + _ctx->stepCount = 0; + + if (StepAnimScript(&_ctx->thisAnim) == ScriptFinished) + break; + + int x, y; + GetAniPosition(_ctx->pPlayObj, &x, &y); + storeActorPos(_ctx->reelActor, x, y); + + CORO_SLEEP(1); + + if (actorReel(_ctx->reelActor) != _ctx->pfreel) { + _ctx->replaced = true; + break; + } + + if (actorEsc(_ctx->reelActor) && actorEev(_ctx->reelActor) != GetEscEvents()) + break; + + } while (_ctx->lifeNoMatter || actorAlive(_ctx->reelActor)); + + // Register the fact that we're NOT playing this for this actor + if (actorReel(_ctx->reelActor) == _ctx->pfreel) + storeActorReel(_ctx->reelActor, NULL, 0, NULL, 0, 0, 0); + + // Ditch the object + if (!ppi->bTop) + MultiDeleteObject(GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj); + else + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj); + + if (_ctx->mActor) { + if (!_ctx->replaced) + unHideMovingActor(_ctx->reelActor); // Restore moving actor + + // Update it's co-ordinates if this is an splay() + if (ppi->splay) + restoreMovement(_ctx->reelActor); + } + CORO_END_CODE; +} + +/** + * Run all animations that comprise the play film. + */ +static void playProcess(CORO_PARAM) { + // get the stuff copied to process when it was created + PPINIT *ppi = (PPINIT *)ProcessGetParamsSelf(); + + PlayReel(coroParam, ppi); +} + +// ******************************************************* + + +// To handle the play()-talk(), talk()-play(), talk()-talk() and play()-play() scenarios +void newestFilm(SCNHANDLE film, const FREEL *reel) { + const MULTI_INIT *pmi; // MULTI_INIT structure + + // Get the MULTI_INIT structure + pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(reel->mobj)); + + setActorLatestFilm((int32)FROM_LE_32(pmi->mulID), film); +} + +// ******************************************************* + +/** + * Start up a play process for each column in a film. + * + * NOTE: The processes are started in reverse order so that the first + * column's process kicks in first. + */ +void playFilm(SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, bool escOn, + int myescEvent, bool bTop) { + const FILM *pfilm = (const FILM *)LockMem(film); + PPINIT ppi; + + assert(film != 0); // Trying to play NULL film + + // Now allowed empty films! + if (pfilm->numreels == 0) + return; // Nothing to do! + + ppi.hFilm = film; + ppi.x = x; + ppi.y = y; + ppi.z = 0; + ppi.speed = (ONE_SECOND / FROM_LE_32(pfilm->frate)); + ppi.actorid = actorid; + ppi.splay = splay; + ppi.bTop = bTop; + ppi.sf = sfact; + ppi.escOn = escOn; + ppi.myescEvent = myescEvent; + + // Start display process for each reel in the film + for (int i = FROM_LE_32(pfilm->numreels) - 1; i >= 0; i--) { + newestFilm(film, &pfilm->reels[i]); + + ppi.column = i; + CoroutineInstall(PID_REEL, playProcess, &ppi, sizeof(ppi)); + } +} + +/** + * Start up a play process for each slave column in a film. + * Play the first column directly from the parent process. + */ +void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, + bool escOn, int myescEvent, bool bTop) { + CORO_BEGIN_CONTEXT; + PPINIT ppi; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + assert(film != 0); // Trying to play NULL film + const FILM *pfilm; + + pfilm = (const FILM *)LockMem(film); + + // Now allowed empty films! + if (pfilm->numreels == 0) + return; // Already played to completion! + + _ctx->ppi.hFilm = film; + _ctx->ppi.x = x; + _ctx->ppi.y = y; + _ctx->ppi.z = 0; + _ctx->ppi.speed = (ONE_SECOND / FROM_LE_32(pfilm->frate)); + _ctx->ppi.actorid = actorid; + _ctx->ppi.splay = splay; + _ctx->ppi.bTop = bTop; + _ctx->ppi.sf = sfact; + _ctx->ppi.escOn = escOn; + _ctx->ppi.myescEvent = myescEvent; + + // Start display process for each secondary reel in the film + for (int i = FROM_LE_32(pfilm->numreels) - 1; i > 0; i--) { + newestFilm(film, &pfilm->reels[i]); + + _ctx->ppi.column = i; + CoroutineInstall(PID_REEL, playProcess, &_ctx->ppi, sizeof(PPINIT)); + } + + newestFilm(film, &pfilm->reels[0]); + + _ctx->ppi.column = 0; + CORO_INVOKE_1(PlayReel, &_ctx->ppi); + + CORO_END_CODE; +} + +/** + * Start up a play process for a particular column in a film. + * + * NOTE: This is specifically for actors during a restore scene. + */ +void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y) { + const FILM *pfilm = (const FILM *)LockMem(film); + PPINIT ppi; + + ppi.hFilm = film; + ppi.x = x; + ppi.y = y; + ppi.z = z; + ppi.speed = (ONE_SECOND / FROM_LE_32(pfilm->frate)); + ppi.actorid = 0; + ppi.splay = false; + ppi.bTop = false; + ppi.sf = 0; + ppi.column = reelnum; + + // FIXME: The PlayReel play loop was previously breaking out, and then deleting objects, when + // returning to a scene because escOn and myescEvent were undefined. Need to make sure whether + // restored objects should have any particular combination of these two values + ppi.escOn = false; + ppi.myescEvent = GetEscEvents(); + + assert(pfilm->numreels); + + newestFilm(film, &pfilm->reels[reelnum]); + + // Start display process for the reel + CoroutineInstall(PID_REEL, playProcess, &ppi, sizeof(ppi)); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/polygons.cpp b/engines/tinsel/polygons.cpp new file mode 100644 index 0000000000..21047afcf5 --- /dev/null +++ b/engines/tinsel/polygons.cpp @@ -0,0 +1,1805 @@ +/* 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 "tinsel/actors.h" +#include "tinsel/font.h" +#include "tinsel/handle.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/serializer.h" +#include "tinsel/token.h" + +#include "common/util.h" + +namespace Tinsel { + + +//----------------- LOCAL DEFINES -------------------- + +#define MAXONROUTE 40 + +typedef POLYGON *PPOLYGON; + + +#include "common/pack-start.h" // START STRUCT PACKING + +/** lineinfo struct - one per (node-1) in a node path */ +struct LINEINFO { + + int32 a; + int32 b; + int32 c; + + int32 a2; //!< a squared + int32 b2; //!< b squared + int32 a2pb2; //!< a squared + b squared + int32 ra2pb2; //!< root(a squared + b squared) + + int32 ab; + int32 ac; + int32 bc; +} PACKED_STRUCT; + +/** polygon struct - one per polygon */ +struct POLY { + int32 type; //!< type of polygon + int32 x[4], y[4]; // Polygon definition + + int32 tagx, tagy; // } For tagged polygons + SCNHANDLE hTagtext; // } i.e. EXIT, TAG, EFFECT + + int32 nodex, nodey; // EXIT, TAG, REFER + SCNHANDLE hFilm; //!< film reel handle for EXIT, TAG + + int32 reftype; //!< Type of REFER + + int32 id; // } EXIT and TAG + + int32 scale1, scale2; // } + int32 reel; // } PATH and NPATH + int32 zFactor; // } + + //The arrays now stored externally + int32 nodecount; //!= 0 && mvar <= noofPolys) || mvar == MAX_POLY); +#define CHECK_HP(mvar, str) assert(mvar >= 0 && mvar <= noofPolys); + +static HPOLYGON PolyIndex(PPOLYGON pp) { + for (int j = 0; j <= MAX_POLY; j++) { + if (Polys[j] == pp) + return j; + } + + error("PolyIndex(): polygon not found"); + return NOPOLY; +} + +/** + * Returns TRUE if the point is within the polygon supplied. + * + * Firstly, the point must be within the smallest imaginary rectangle + * which encloses the polygon. + * + * Then, from each corner of the polygon, if the point is within an + * imaginary rectangle enclosing the clockwise-going side from that + * corner, the gradient of a line from the corner to the point must be + * less than (or more negative than) the gradient of that side: + * + * If the corners' coordinates are designated (x1, y1) and (x2, y2), and + * the point in question's (xt, yt), then: + * gradient (x1,y1)->(x2,y2) > gradient (x1,y1)->(xt,yt) + * (y1-y2)/(x2-x1) > (y1-yt)/(xt-x1) + * (y1-y2)*(xt-x1) > (y1-yt)*(x2-x1) + * xt(y1-y2) -x1y1 + x1y2 > -yt(x2-x1) + y1x2 - x1y1 + * xt(y1-y2) + yt(x2-x1) > y1x2 - x1y2 + * + * If the point passed one of the four 'side tests', and failed none, + * then it must be within the polygon. If the point was not tested, it + * may be within the internal rectangle not covered by the above tests. + * + * Most polygons contain an internal rectangle which does not fall into + * any of the above side-related tests. Such a rectangle will always + * have two polygon corners above it and two corners to the left of it. + */ +bool IsInPolygon(int xt, int yt, HPOLYGON hp) { + PPOLYGON pp; + int i; + bool BeenTested = false; + int pl = 0, pa = 0; + + CHECK_HP_OR(hp, "Out of range polygon handle (1)"); + pp = Polys[hp]; + assert(pp != NULL); // Testing whether in a NULL polygon + + /* Is point within the external rectangle? */ + if (xt < pp->pleft || xt > pp->pright || yt < pp->ptop || yt > pp->pbottom) + return false; + + // For each corner/side + for (i = 0; i < 4; i++) { + // If within this side's 'testable' area + // i.e. within the width of the line in y direction of end of line + // or within the height of the line in x direction of end of line + if ((xt >= pp->lleft[i] && xt <= pp->lright[i] && ((yt > pp->cy[i]) == (pp->cy[(i+1)%4] > pp->cy[i]))) + || (yt >= pp->ltop[i] && yt <= pp->lbottom[i] && ((xt > pp->cx[i]) == (pp->cx[(i+1)%4] > pp->cx[i])))) { + if (((long)xt*pp->a[i] + (long)yt*pp->b[i]) < pp->c[i]) + return false; + else + BeenTested = true; + } + } + + if (BeenTested) { + // New dodgy code 29/12/94 + if (pp->polytype == BLOCKING) { + // For each corner/side + for (i = 0; i < 4; i++) { + // Pretend the corners of blocking polys are not in the poly. + if (xt == pp->cx[i] && yt == pp->cy[i]) + return false; + } + } + return true; + } else { + // Is point within the internal rectangle? + for (i = 0; i < 4; i++) { + if (pp->cx[i] < xt) + pl++; + if (pp->cy[i] < yt) + pa++; + } + + if (pa == 2 && pl == 2) + return true; + else + return false; + } +} + +/** + * Finds a polygon of the specified type containing the supplied point. + */ + +HPOLYGON InPolygon(int xt, int yt, PTYPE type) { + for (int j = 0; j <= MAX_POLY; j++) { + if (Polys[j] && Polys[j]->polytype == type) { + if (IsInPolygon(xt, yt, j)) + return j; + } + } + return NOPOLY; +} + +/** + * Given a blocking polygon, current co-ordinates of an actor, and the + * co-ordinates of where the actor is heading, works out which corner of + * the blocking polygon to head around. + */ + +void BlockingCorner(HPOLYGON hp, int *x, int *y, int tarx, int tary) { + PPOLYGON pp; + int i; + int xd, yd; // distance per axis + int ThisD, SmallestD = 1000; + int D1, D2; + int NearestToHere = 1000, NearestToTarget; + unsigned At = 10; // Corner already at + + int bcx[4], bcy[4]; // Bogus corners + + CHECK_HP_OR(hp, "Out of range polygon handle (2)"); + pp = Polys[hp]; + + // Work out a point outside each corner + for (i = 0; i < 4; i++) { + int next, prev; + + // X-direction + next = pp->cx[i] - pp->cx[(i+1)%4]; + prev = pp->cx[i] - pp->cx[(i+3)%4]; + if (next <= 0 && prev <= 0) + bcx[i] = pp->cx[i] - 4; // Both points to the right + else if (next >= 0 && prev >= 0) + bcx[i] = pp->cx[i] + 4; // Both points to the left + else + bcx[i] = pp->cx[i]; + + // Y-direction + next = pp->cy[i] - pp->cy[(i+1)%4]; + prev = pp->cy[i] - pp->cy[(i+3)%4]; + if (next <= 0 && prev <= 0) + bcy[i] = pp->cy[i] - 4; // Both points below + else if (next >= 0 && prev >= 0) + bcy[i] = pp->cy[i] + 4; // Both points above + else + bcy[i] = pp->cy[i]; + } + + // Find nearest corner to where we are, + // but not the one we're stood at. + + for (i = 0; i < 4; i++) { // For 4 corners +// ThisD = ABS(*x - pp->cx[i]) + ABS(*y - pp->cy[i]); + ThisD = ABS(*x - bcx[i]) + ABS(*y - bcy[i]); + if (ThisD < SmallestD) { + // Ignore this corner if it's not in a path + if (InPolygon(pp->cx[i], pp->cy[i], PATH) == NOPOLY || + InPolygon(bcx[i], bcy[i], PATH) == NOPOLY) + continue; + + // Are we stood at this corner? + if (ThisD > 4) { + // No - it's the nearest we've found yet. + NearestToHere = i; + SmallestD = ThisD; + } else { + // Stood at/next to this corner + At = i; + } + } + } + + // If we're not already at a corner, go to the nearest corner + + if (At == 10) { + // Not stood at a corner +// assert(NearestToHere != 1000); // At blocking corner, not found near corner! + // Better to give up than to assert fail! + if (NearestToHere == 1000) { + // Send it to where it is now + // i.e. leave x and y alone + } else { + *x = bcx[NearestToHere]; + *y = bcy[NearestToHere]; + } + } else { + // Already at a corner. Go to an adjacent corner. + // First, find out which adjacent corner is nearest the target. + xd = ABS(tarx - pp->cx[(At + 1) % 4]); + yd = ABS(tary - pp->cy[(At + 1) % 4]); + D1 = xd + yd; + xd = ABS(tarx - pp->cx[(At + 3) % 4]); + yd = ABS(tary - pp->cy[(At + 3) % 4]); + D2 = xd + yd; + NearestToTarget = (D2 > D1) ? (At + 1) % 4 : (At + 3) % 4; + if (NearestToTarget == NearestToHere) { + *x = bcx[NearestToHere]; + *y = bcy[NearestToHere]; + } else { + // Need to decide whether it's better to go to the nearest to + // here and then on to the target, or to the nearest to the + // target and on from there. + xd = ABS(pp->cx[At] - pp->cx[NearestToHere]); + D1 = xd; + xd = ABS(pp->cx[NearestToHere] - tarx); + D1 += xd; + + yd = ABS(pp->cy[At] - pp->cy[NearestToHere]); + D1 += yd; + yd = ABS(pp->cy[NearestToHere] - tary); + D1 += yd; + + xd = ABS(pp->cx[At] - pp->cx[NearestToTarget]); + D2 = xd; + xd = ABS(pp->cx[NearestToTarget] - tarx); + D2 += xd; + + yd = ABS(pp->cy[At] - pp->cy[NearestToTarget]); + D2 += yd; + yd = ABS(pp->cy[NearestToTarget] - tary); + D2 += yd; + + if (D2 > D1) { + *x = bcx[NearestToHere]; + *y = bcy[NearestToHere]; + } else { + *x = bcx[NearestToTarget]; + *y = bcy[NearestToTarget]; + } + } + } +} + + +/** + * Try do drop a perpendicular to each inter-node line from the point + * and remember the shortest (if any). + * Find which node is nearest to the point. + * The shortest of these gives the best point in the node path. +*/ +void FindBestPoint(HPOLYGON hp, int *x, int *y, int *pline) { + PPOLYGON pp; + + uint8 *pps; // Compiled polygon data + const POLY *ptp; // Compiled polygon data + int dropD; // length of perpendicular (i.e. distance of point from line) + int dropX, dropY; // (X, Y) where dropped perpendicular intersects the line + int d1, d2; // distance from perpendicular intersect to line's end nodes + int32 *nlistx, *nlisty; + + int shortestD = 10000; // Shortest distance found + int nearestL = -1; // Nearest line + int nearestN; // Nearest Node + + int h = *x; // For readability/conveniance + int k = *y; // - why aren't these #defines? + LINEINFO *llist; // Inter-node line structure + + CHECK_HP(hp, "Out of range polygon handle (3)"); + pp = Polys[hp]; + + // Pointer to polygon data + pps = LockMem(pHandle); // All polygons + ptp = (const POLY *)pps + pp->pIndex; // This polygon + + nlistx = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelistx)); + nlisty = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelisty)); + llist = (LINEINFO *)(pps + (int)FROM_LE_32(ptp->plinelist)); + + // Look for fit of perpendicular to lines between nodes + for (int i = 0; i < (int)FROM_LE_32(ptp->nodecount) - 1; i++) { + const int32 a = (int)FROM_LE_32(llist[i].a); + const int32 b = (int)FROM_LE_32(llist[i].b); + const int32 c = (int)FROM_LE_32(llist[i].c); + +#if 1 + if (true) { + //printf("a %d, b %d, c %d, a^2+b^2 = %d\n", a, b, c, a*a+b*b); + + // TODO: If the comments of the LINEINFO struct are correct, then it contains mostly + // duplicate data, probably in an effort to safe CPU cycles. Even on the slowest devices + // we support, calculatin a product of two ints is not an issue. + // So we can just load & endian convert a,b,c, then replace stuff like + // (int)FROM_LE_32(line->ab) + // by simply a*b, which makes it easier to understand what the code does, too. + // Just in case there is some bugged data, I leave this code here for verifying it. + // Let's leave it in for some time. + // + // One bad thing: We use sqrt to compute a square root. Might not be a good idea, + // speed wise. Maybe we should take Vicent's fp_sqroot. But that's a problem for later. + + LINEINFO *line = &llist[i]; + int32 a2 = (int)FROM_LE_32(line->a2); //!< a squared + int32 b2 = (int)FROM_LE_32(line->b2); //!< b squared + int32 a2pb2 = (int)FROM_LE_32(line->a2pb2); //!< a squared + b squared + int32 ra2pb2 = (int)FROM_LE_32(line->ra2pb2); //!< root(a squared + b squared) + + int32 ab = (int)FROM_LE_32(line->ab); + int32 ac = (int)FROM_LE_32(line->ac); + int32 bc = (int)FROM_LE_32(line->bc); + + assert(a*a == a2); + assert(b*b == b2); + assert(a*b == ab); + assert(a*c == ac); + assert(b*c == bc); + + assert(a2pb2 == a*a + b*b); + assert(ra2pb2 == (int)sqrt((float)a*a + (float)b*b)); + } +#endif + + + if (a == 0 && b == 0) + continue; // Line is just a point! + + // X position of dropped perpendicular intersection with line + dropX = ((b*b * h) - (a*b * k) - a*c) / (a*a + b*b); + + // X distances from intersection to end nodes + d1 = dropX - (int)FROM_LE_32(nlistx[i]); + d2 = dropX - (int)FROM_LE_32(nlistx[i+1]); + + // if both -ve or both +ve, no fit + if ((d1 < 0 && d2 < 0) || (d1 > 0 && d2 > 0)) + continue; +//#if 0 + // Y position of sidweays perpendicular intersection with line + dropY = ((a*a * k) - (a*b * h) - b*c) / (a*a + b*b); + + // Y distances from intersection to end nodes + d1 = dropY - (int)FROM_LE_32(nlisty[i]); + d2 = dropY - (int)FROM_LE_32(nlisty[i+1]); + + // if both -ve or both +ve, no fit + if ((d1 < 0 && d2 < 0) || (d1 > 0 && d2 > 0)) + continue; +//#endif + dropD = ((a * h) + (b * k) + c) / (int)sqrt((float)a*a + (float)b*b); + dropD = ABS(dropD); + if (dropD < shortestD) { + shortestD = dropD; + nearestL = i; + } + } + + // Distance to nearest node + nearestN = NearestNodeWithin(hp, h, k); + dropD = ABS(h - (int)FROM_LE_32(nlistx[nearestN])) + ABS(k - (int)FROM_LE_32(nlisty[nearestN])); + + // Go to a node or a point on a line + if (dropD < shortestD) { + // A node is nearest + *x = (int)FROM_LE_32(nlistx[nearestN]); + *y = (int)FROM_LE_32(nlisty[nearestN]); + *pline = nearestN; + } else { + assert(nearestL != -1); + + // A point on a line is nearest + const int32 a = (int)FROM_LE_32(llist[nearestL].a); + const int32 b = (int)FROM_LE_32(llist[nearestL].b); + const int32 c = (int)FROM_LE_32(llist[nearestL].c); + dropX = ((b*b * h) - (a*b * k) - a*c) / (a*a + b*b); + dropY = ((a*a * k) - (a*b * h) - b*c) / (a*a + b*b); + *x = dropX; + *y = dropY; + *pline = nearestL; + } + + assert(IsInPolygon(*x, *y, hp)); // Nearest point is not in polygon(!) +} + +/** + * Returns TRUE if two paths are asdjacent. + */ +bool IsAdjacentPath(HPOLYGON hPath1, HPOLYGON hPath2) { + PPOLYGON pp1, pp2; + + CHECK_HP(hPath1, "Out of range polygon handle (4)"); + CHECK_HP(hPath2, "Out of range polygon handle (500)"); + + if (hPath1 == hPath2) + return true; + + pp1 = Polys[hPath1]; + pp2 = Polys[hPath2]; + + for (int j = 0; j < MAXADJ; j++) + if (pp1->adjpaths[j] == pp2) + return true; + + return false; +} + +static POLYGON *TryPath(POLYGON *last, POLYGON *whereto, POLYGON *current) { + PPOLYGON x; + + // For each path adjacent to this one + for (int j = 0; j < MAXADJ; j++) { + x = current->adjpaths[j]; // call the adj. path x + if (x == whereto) { + RoutePaths[pathsOnRoute++] = x; + return x; // Got there! + } + + if (x == NULL) + break; // no more adj. paths to look at + + if (x->tried) + continue; // don't double back + + if (x == last) + continue; // don't double back + + x->tried = true; + if (TryPath(current, whereto, x) != NULL) { + RoutePaths[pathsOnRoute++] = x; + assert(pathsOnRoute < MAXONROUTE); + return x; // Got there in this direction + } else + x->tried = false; + } + + return NULL; +} + + +/** + * Sort out the first path to head to for the imminent leg of a walk. + */ +static HPOLYGON PathOnTheWay(HPOLYGON from, HPOLYGON to) { + // TODO: Fingolfin says: This code currently uses DFS (depth first search), + // in the TryPath function, to compute a path between 'from' and 'to'. + // However, a BFS (breadth first search) might yield more natural results, + // at least in cases where there are multiple possible paths. + // There is a small risk of regressions caused by such a change, though. + // + // Also, the overhead of computing a DFS again and again could be avoided + // by computing a path matrix (like we do in the SCUMM engine). + int i; + PPOLYGON p; + + CHECK_HP(from, "Out of range polygon handle (501a)"); + CHECK_HP(to, "Out of range polygon handle (501b)"); + + if (IsAdjacentPath(from, to)) + return to; + + for (i = 0; i < MAX_POLY; i++) { // For each polygon.. + p = Polys[i]; + if (p && p->polytype == PATH) //...if it's a path + p->tried = false; + } + Polys[from]->tried = true; + pathsOnRoute = 0; + + p = TryPath(Polys[from], Polys[to], Polys[from]); + + assert(p != NULL); // Trying to find route between unconnected paths + + // Don't go a roundabout way to an adjacent path. + for (i = 0; i < pathsOnRoute; i++) { + CHECK_HP(PolyIndex(RoutePaths[i]), "Out of range polygon handle (502)"); + if (IsAdjacentPath(from, PolyIndex(RoutePaths[i]))) + return PolyIndex(RoutePaths[i]); + } + return PolyIndex(p); +} + +/** + * Indirect method of calling PathOnTheWay(), to put the burden of + * recursion onto the main stack. + */ +HPOLYGON getPathOnTheWay(HPOLYGON hFrom, HPOLYGON hTo) { + CHECK_HP(hFrom, "Out of range polygon handle (6)"); + CHECK_HP(hTo, "Out of range polygon handle (7)"); + + // Reuse already computed result + if (RouteEnd == Polys[hTo]) { + for (int i = 0; i < pathsOnRoute; i++) { + CHECK_HP(PolyIndex(RoutePaths[i]), "Out of range polygon handle (503)"); + if (IsAdjacentPath(hFrom, PolyIndex(RoutePaths[i]))) { + return PolyIndex(RoutePaths[i]); + } + } + } + + RouteEnd = Polys[hTo]; + return PathOnTheWay(hFrom, hTo); +} + + +/** + * Given a node path, work out which end node is nearest the given point. + */ + +int NearestEndNode(HPOLYGON hPath, int x, int y) { + PPOLYGON pp; + + int d1, d2; + uint8 *pps; // Compiled polygon data + const POLY *ptp; // Pointer to compiled polygon data + int32 *nlistx, *nlisty; + + CHECK_HP(hPath, "Out of range polygon handle (8)"); + pp = Polys[hPath]; + + pps = LockMem(pHandle); // All polygons + ptp = (const POLY *)pps + pp->pIndex; // This polygon + + nlistx = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelistx)); + nlisty = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelisty)); + + const int nodecount = (int)FROM_LE_32(ptp->nodecount); + + d1 = ABS(x - (int)FROM_LE_32(nlistx[0])) + ABS(y - (int)FROM_LE_32(nlisty[0])); + d2 = ABS(x - (int)FROM_LE_32(nlistx[nodecount - 1])) + ABS(y - (int)FROM_LE_32(nlisty[nodecount - 1])); + + return (d2 > d1) ? 0 : nodecount - 1; +} + + +/** + * Given a start path and a destination path, find which pair of end + * nodes is nearest together. + * Return which node in the start path is part of the closest pair. + */ + +int NearEndNode(HPOLYGON hSpath, HPOLYGON hDpath) { + PPOLYGON pSpath, pDpath; + + int ns, nd; // 'top' nodes in each path + int dist, NearDist; + int NearNode; + uint8 *pps; // Compiled polygon data + const POLY *ps, *pd; // Pointer to compiled polygon data + int32 *snlistx, *snlisty; + int32 *dnlistx, *dnlisty; + + CHECK_HP(hSpath, "Out of range polygon handle (9)"); + CHECK_HP(hDpath, "Out of range polygon handle (10)"); + pSpath = Polys[hSpath]; + pDpath = Polys[hDpath]; + + pps = LockMem(pHandle); // All polygons + ps = (const POLY *)pps + pSpath->pIndex; // Start polygon + pd = (const POLY *)pps + pDpath->pIndex; // Dest polygon + + ns = (int)FROM_LE_32(ps->nodecount) - 1; + nd = (int)FROM_LE_32(pd->nodecount) - 1; + + snlistx = (int32 *)(pps + (int)FROM_LE_32(ps->pnodelistx)); + snlisty = (int32 *)(pps + (int)FROM_LE_32(ps->pnodelisty)); + dnlistx = (int32 *)(pps + (int)FROM_LE_32(pd->pnodelistx)); + dnlisty = (int32 *)(pps + (int)FROM_LE_32(pd->pnodelisty)); + + // start[0] to dest[0] + NearDist = ABS((int)FROM_LE_32(snlistx[0]) - (int)FROM_LE_32(dnlistx[0])) + ABS((int)FROM_LE_32(snlisty[0]) - (int)FROM_LE_32(dnlisty[0])); + NearNode = 0; + + // start[0] to dest[top] + dist = ABS((int)FROM_LE_32(snlistx[0]) - (int)FROM_LE_32(dnlistx[nd])) + ABS((int)FROM_LE_32(snlisty[0]) - (int)FROM_LE_32(dnlisty[nd])); + if (dist < NearDist) + NearDist = dist; + + // start[top] to dest[0] + dist = ABS((int)FROM_LE_32(snlistx[ns]) - (int)FROM_LE_32(dnlistx[0])) + ABS((int)FROM_LE_32(snlisty[ns]) - (int)FROM_LE_32(dnlisty[0])); + if (dist < NearDist) { + NearDist = dist; + NearNode = ns; + } + + // start[top] to dest[top] + dist = ABS((int)FROM_LE_32(snlistx[ns]) - (int)FROM_LE_32(dnlistx[nd])) + ABS((int)FROM_LE_32(snlisty[ns]) - (int)FROM_LE_32(dnlisty[nd])); + if (dist < NearDist) { + NearNode = ns; + } + + return NearNode; +} + +/** + * Given a follow nodes path and a co-ordinate, finds which node in the + * path is nearest to the co-ordinate. + */ +int NearestNodeWithin(HPOLYGON hNpath, int x, int y) { + int ThisDistance, SmallestDistance = 1000; + int NumNodes; // Number of nodes in this follow nodes path + int NearestYet = 0; // Number of nearest node + uint8 *pps; // Compiled polygon data + const POLY *ptp; // Pointer to compiled polygon data + int32 *nlistx, *nlisty; + + CHECK_HP(hNpath, "Out of range polygon handle (11)"); + + pps = LockMem(pHandle); // All polygons + ptp = (const POLY *)pps + Polys[hNpath]->pIndex; // This polygon + + nlistx = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelistx)); + nlisty = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelisty)); + + NumNodes = (int)FROM_LE_32(ptp->nodecount); + + for (int i = 0; i < NumNodes; i++) { + ThisDistance = ABS(x - (int)FROM_LE_32(nlistx[i])) + ABS(y - (int)FROM_LE_32(nlisty[i])); + + if (ThisDistance < SmallestDistance) { + NearestYet = i; + SmallestDistance = ThisDistance; + } + } + + return NearestYet; +} + +/** + * Given a point and start and destination paths, find the nearest + * corner (if any) of the start path which is within the destination + * path. If there is no such corner, find the nearest corner of the + * destination path which falls within the source path. + */ +void NearestCorner(int *x, int *y, HPOLYGON hStartPoly, HPOLYGON hDestPoly) { + PPOLYGON psp, pdp; + int j; + int ncorn = 0; // nearest corner + HPOLYGON hNpath = NOPOLY; // path containing nearest corner + int ThisD, SmallestD = 1000; + + CHECK_HP(hStartPoly, "Out of range polygon handle (12)"); + CHECK_HP(hDestPoly, "Out of range polygon handle (13)"); + + psp = Polys[hStartPoly]; + pdp = Polys[hDestPoly]; + + // Nearest corner of start path in destination path. + + for (j = 0; j < 4; j++) { + if (IsInPolygon(psp->cx[j], psp->cy[j], hDestPoly)) { + ThisD = ABS(*x - psp->cx[j]) + ABS(*y - psp->cy[j]); + if (ThisD < SmallestD) { + hNpath = hStartPoly; + ncorn = j; + // Try to ignore it if virtually stood on it + if (ThisD > 4) + SmallestD = ThisD; + } + } + } + if (SmallestD == 1000) { + // Nearest corner of destination path in start path. + for (j = 0; j < 4; j++) { + if (IsInPolygon(pdp->cx[j], pdp->cy[j], hStartPoly)) { + ThisD = ABS(*x - pdp->cx[j]) + ABS(*y - pdp->cy[j]); + if (ThisD < SmallestD) { + hNpath = hDestPoly; + ncorn = j; + // Try to ignore it if virtually stood on it + if (ThisD > 4) + SmallestD = ThisD; + } + } + } + } + + if (hNpath != NOPOLY) { + *x = Polys[hNpath]->cx[ncorn]; + *y = Polys[hNpath]->cy[ncorn]; + } else + error("NearestCorner() failure"); +} + +bool IsPolyCorner(HPOLYGON hPath, int x, int y) { + CHECK_HP(hPath, "Out of range polygon handle (37)"); + + for (int i = 0; i < 4; i++) { + if (Polys[hPath]->cx[i] == x && Polys[hPath]->cy[i] == y) + return true; + } + return false; +} + +/** + * Given a path polygon and a Y co-ordinate, return a scale value. + */ +int GetScale(HPOLYGON hPath, int y) { + const POLY *ptp; // Pointer to compiled polygon data + int zones; // Number of different scales + int zlen; // Depth of each scale zone + int scale; + int top; + + // To try and fix some unknown potential bug + if (hPath == NOPOLY) + return SCALE_LARGE; + + CHECK_HP(hPath, "Out of range polygon handle (14)"); + + ptp = (const POLY *)LockMem(pHandle) + Polys[hPath]->pIndex; + + // Path is of a constant scale? + if (FROM_LE_32(ptp->scale2) == 0) + return FROM_LE_32(ptp->scale1); + + assert(FROM_LE_32(ptp->scale1) >= FROM_LE_32(ptp->scale2)); + + zones = FROM_LE_32(ptp->scale1) - FROM_LE_32(ptp->scale2) + 1; + zlen = (Polys[hPath]->pbottom - Polys[hPath]->ptop) / zones; + + scale = FROM_LE_32(ptp->scale1); + top = Polys[hPath]->ptop; + + do { + top += zlen; + if (y < top) + return scale; + } while (--scale); + + return FROM_LE_32(ptp->scale2); +} + +/** + * Give the co-ordinates of a node in a node path. + */ +void getNpathNode(HPOLYGON hNpath, int node, int *px, int *py) { + uint8 *pps; // Compiled polygon data + const POLY *ptp; // Pointer to compiled polygon data + int32 *nlistx, *nlisty; + + CHECK_HP(hNpath, "Out of range polygon handle (15)"); + assert(Polys[hNpath] != NULL && Polys[hNpath]->polytype == PATH && Polys[hNpath]->subtype == NODE); // must be given a node path! + + pps = LockMem(pHandle); // All polygons + ptp = (const POLY *)pps + Polys[hNpath]->pIndex; // This polygon + + nlistx = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelistx)); + nlisty = (int32 *)(pps + (int)FROM_LE_32(ptp->pnodelisty)); + + // Might have just walked to the node from above. + if (node == (int)FROM_LE_32(ptp->nodecount)) + node -= 1; + + *px = (int)FROM_LE_32(nlistx[node]); + *py = (int)FROM_LE_32(nlisty[node]); +} + +/** + * Get tag text handle and tag co-ordinates of a polygon. + */ + +void getPolyTagInfo(HPOLYGON hp, SCNHANDLE *hTagText, int *tagx, int *tagy) { + const POLY *pp; // Pointer to compiled polygon data + + CHECK_HP(hp, "Out of range polygon handle (16)"); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + *tagx = (int)FROM_LE_32(pp->tagx); + *tagy = (int)FROM_LE_32(pp->tagy); + *hTagText = FROM_LE_32(pp->hTagtext); +} + +/** + * Get polygon's film reel handle. + */ + +SCNHANDLE getPolyFilm(HPOLYGON hp) { + const POLY *pp; // Pointer to compiled polygon data + + CHECK_HP(hp, "Out of range polygon handle (17)"); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + return FROM_LE_32(pp->hFilm); +} + +/** + * Get polygon's associated node. + */ + +void getPolyNode(HPOLYGON hp, int *px, int *py) { + const POLY *pp; // Pointer to compiled polygon data + + CHECK_HP(hp, "Out of range polygon handle (18)"); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + *px = (int)FROM_LE_32(pp->nodex); + *py = (int)FROM_LE_32(pp->nodey); +} + +/** + * Get handle to polygon's glitter code. + */ + +SCNHANDLE getPolyScript(HPOLYGON hp) { + const POLY *pp; // Pointer to compiled polygon data + + CHECK_HP(hp, "Out of range polygon handle (19)"); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + return FROM_LE_32(pp->hScript); +} + +REEL getPolyReelType(HPOLYGON hp) { + const POLY *pp; // Pointer to compiled polygon data + + // To try and fix some unknown potential bug (toyshop entrance) + if (hp == NOPOLY) + return REEL_ALL; + + CHECK_HP(hp, "Out of range polygon handle (20)"); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + return (REEL)FROM_LE_32(pp->reel); +} + +int32 getPolyZfactor(HPOLYGON hp) { + const POLY *pp; // Pointer to compiled polygon data + + CHECK_HP(hp, "Out of range polygon handle (21)"); + assert(Polys[hp] != NULL); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + return (int)FROM_LE_32(pp->zFactor); +} + +int numNodes(HPOLYGON hp) { + const POLY *pp; // Pointer to compiled polygon data + + CHECK_HP(hp, "Out of range polygon handle (22)"); + assert(Polys[hp] != NULL); + + pp = (const POLY *)LockMem(pHandle) + Polys[hp]->pIndex; + + return (int)FROM_LE_32(pp->nodecount); +} + +// ************************************************************************* +// +// Code concerned with killing and reviving TAG and EXIT polygons. +// And code to enable this information to be saved and restored. +// +// ************************************************************************* + +struct TAGSTATE { + int tid; + bool enabled; +}; +typedef TAGSTATE *PTAGSTATE; + +#define MAX_SCENES 256 +#define MAX_TAGS 2048 +#define MAX_EXITS 512 + +static struct { + SCNHANDLE sid; + int nooftags; + int offset; +} SceneTags[MAX_SCENES], SceneExits[MAX_SCENES]; + +static TAGSTATE TagStates[MAX_TAGS]; +static TAGSTATE ExitStates[MAX_EXITS]; + +static int nextfreeT = 0, numScenesT = 0; +static int nextfreeE = 0, numScenesE = 0; + +static int currentTScene = 0; +static int currentEScene = 0; + +bool deadPolys[MAX_POLY]; // Currently just for dead blocks + +void RebootDeadTags(void) { + nextfreeT = numScenesT = 0; + nextfreeE = numScenesE = 0; + + memset(SceneTags, 0, sizeof(SceneTags)); + memset(SceneExits, 0, sizeof(SceneExits)); + memset(TagStates, 0, sizeof(TagStates)); + memset(ExitStates, 0, sizeof(ExitStates)); + memset(deadPolys, 0, sizeof(deadPolys)); +} + +/** + * (Un)serialize the dead tag and exit data for save/restore game. + */ +void syncPolyInfo(Serializer &s) { + int i; + + for (i = 0; i < MAX_SCENES; i++) { + s.syncAsUint32LE(SceneTags[i].sid); + s.syncAsSint32LE(SceneTags[i].nooftags); + s.syncAsSint32LE(SceneTags[i].offset); + } + + for (i = 0; i < MAX_SCENES; i++) { + s.syncAsUint32LE(SceneExits[i].sid); + s.syncAsSint32LE(SceneExits[i].nooftags); + s.syncAsSint32LE(SceneExits[i].offset); + } + + for (i = 0; i < MAX_TAGS; i++) { + s.syncAsUint32LE(TagStates[i].tid); + s.syncAsSint32LE(TagStates[i].enabled); + } + + for (i = 0; i < MAX_EXITS; i++) { + s.syncAsUint32LE(ExitStates[i].tid); + s.syncAsSint32LE(ExitStates[i].enabled); + } + + s.syncAsSint32LE(nextfreeT); + s.syncAsSint32LE(numScenesT); + s.syncAsSint32LE(nextfreeE); + s.syncAsSint32LE(numScenesE); +} + +/** + * This is all totally different to the way the rest of the way polygon + * data is stored and restored, more specifically, different to how dead + * tags and exits are handled, because of the piecemeal design-by-just- + * thought-of-this approach employed. + */ + +void SaveDeadPolys(bool *sdp) { + memcpy(sdp, deadPolys, MAX_POLY*sizeof(bool)); +} + +void RestoreDeadPolys(bool *sdp) { + memcpy(deadPolys, sdp, MAX_POLY*sizeof(bool)); +} + +/** + * Convert a BLOCKING to an EX_BLOCK poly. + */ +void DisableBlock(int blockno) { + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == BLOCKING && Polys[i]->polyID == blockno) { + Polys[i]->polytype = EX_BLOCK; + deadPolys[i] = true; + } + } +} + +/** + * Convert an EX_BLOCK to a BLOCKING poly. + */ +void EnableBlock(int blockno) { + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == EX_BLOCK && Polys[i]->polyID == blockno) { + Polys[i]->polytype = BLOCKING; + deadPolys[i] = false; + } + } +} + +/** + * Convert a TAG to an EX_TAG poly. + */ +void DisableTag(int tagno) { + PTAGSTATE pts; + + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == TAG && Polys[i]->polyID == tagno) { + Polys[i]->polytype = EX_TAG; + Polys[i]->tagState = TAG_OFF; + Polys[i]->pointState = NOT_POINTING; + } + } + + pts = &TagStates[SceneTags[currentTScene].offset]; + for (int j = 0; j < SceneTags[currentTScene].nooftags; j++, pts++) { + if (pts->tid == tagno) { + pts->enabled = false; + break; + } + } +} + +/** + * Convert an EX_TAG to a TAG poly. + */ +void EnableTag(int tagno) { + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == EX_TAG && Polys[i]->polyID == tagno) { + Polys[i]->polytype = TAG; + } + } + + PTAGSTATE pts; + pts = &TagStates[SceneTags[currentTScene].offset]; + for (int j = 0; j < SceneTags[currentTScene].nooftags; j++, pts++) { + if (pts->tid == tagno) { + pts->enabled = true; + break; + } + } +} + +/** + * Convert an EX_EXIT to a EXIT poly. + */ +void EnableExit(int exitno) { + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == EX_EXIT && Polys[i]->polyID == exitno) { + Polys[i]->polytype = EXIT; + } + } + + PTAGSTATE pts; + pts = &ExitStates[SceneExits[currentEScene].offset]; + for (int j = 0; j < SceneExits[currentEScene].nooftags; j++, pts++) { + if (pts->tid == exitno) { + pts->enabled = true; + break; + } + } +} + +/** + * Convert a EXIT to an EX_EXIT poly. + */ +void DisableExit(int exitno) { + PTAGSTATE pts; + + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == EXIT && Polys[i]->polyID == exitno) { + Polys[i]->polytype = EX_EXIT; + Polys[i]->tagState = TAG_OFF; + Polys[i]->pointState = NOT_POINTING; + } + } + + pts = &ExitStates[SceneExits[currentEScene].offset]; + for (int j = 0; j < SceneExits[currentEScene].nooftags; j++, pts++) { + if (pts->tid == exitno) { + pts->enabled = false; + break; + } + } +} + +HPOLYGON FirstPathPoly(void) { + for (int i = 0; i < noofPolys; i++) { + if (Polys[i]->polytype == PATH) + return i; + } + error("FirstPathPoly() - no PATH polygons!"); + return NOPOLY; +} + +HPOLYGON GetPolyHandle(int i) { + assert(i >= 0 && i <= MAX_POLY); + + return (Polys[i] != NULL) ? i : NOPOLY; +} + +// ************************************************************************** +// +// Code called to initialise or wrap up a scene: +// +// ************************************************************************** + +/** + * Called at the start of a scene, when all polygons have been + * initialised, to work out which paths are adjacent to which. + */ +static int DistinctCorners(HPOLYGON hp1, HPOLYGON hp2) { + PPOLYGON pp1, pp2; + int i, j; + int retval = 0; + + CHECK_HP(hp1, "Out of range polygon handle (23)"); + CHECK_HP(hp2, "Out of range polygon handle (24)"); + pp1 = Polys[hp1]; + pp2 = Polys[hp2]; + + // Work out (how many of p1's corners is in p2) + (how many of p2's corners is in p1) + for (i = 0; i < 4; i++) { + if (IsInPolygon(pp1->cx[i], pp1->cy[i], hp2)) + retval++; + if (IsInPolygon(pp2->cx[i], pp2->cy[i], hp1)) + retval++; + } + + // Common corners only count once + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + if (pp1->cx[i] == pp2->cx[j] && pp1->cy[i] == pp2->cy[j]) + retval--; + } + } + return retval; +} + +static void SetPathAdjacencies() { + PPOLYGON p1, p2; // Polygon pointers + + // For each polygon.. + for (int i1 = 0; i1 < MAX_POLY-1; i1++) { + // Get polygon, but only carry on if it's a path + p1 = Polys[i1]; + if (!p1 || p1->polytype != PATH) + continue; + + // For each subsequent polygon.. + for (int i2 = i1 + 1; i2 < MAX_POLY; i2++) { + // Get polygon, but only carry on if it's a path + p2 = Polys[i2]; + if (!p2 || p2->polytype != PATH) + continue; + + int j = DistinctCorners(i1, i2); + + if (j >= 2) { + // Paths are adjacent + for (j = 0; j < MAXADJ; j++) + if (p1->adjpaths[j] == NULL) { + p1->adjpaths[j] = p2; + break; + } +#ifdef DEBUG + if (j > highestYet) + highestYet = j; +#endif + assert(j < MAXADJ); // Number of adjacent paths limit + for (j = 0; j < MAXADJ; j++) { + if (p2->adjpaths[j] == NULL) { + p2->adjpaths[j] = p1; + break; + } + } +#ifdef DEBUG + if (j > highestYet) + highestYet = j; +#endif + assert(j < MAXADJ); // Number of adjacent paths limit + } + } + } +} + +/** + * Ensure NPATH nodes are not inside another PATH/NPATH polygon. + * Only bother with end nodes for now. + */ +#ifdef DEBUG +void CheckNPathIntegrity() { + uint8 *pps; // Compiled polygon data + PPOLYGON rp; // Run-time polygon structure + HPOLYGON hp; + const POLY *cp; // Compiled polygon structure + int i, j; // Loop counters + int n; // Last node in current path + int32 *nlistx, *nlisty; + + pps = LockMem(pHandle); // All polygons + + for (i = 0; i < MAX_POLY; i++) { // For each polygon.. + rp = Polys[i]; + if (rp && rp->polytype == PATH && rp->subtype == NODE) { //...if it's a node path + // Get compiled polygon structure + cp = (const POLY *)pps + rp->pIndex; // This polygon + nlistx = (int32 *)(pps + (int)FROM_LE_32(cp->pnodelistx)); + nlisty = (int32 *)(pps + (int)FROM_LE_32(cp->pnodelisty)); + + n = (int)FROM_LE_32(cp->nodecount) - 1; // Last node + assert(n >= 1); // Node paths must have at least 2 nodes + + hp = PolyIndex(rp); + for (j = 0; j <= n; j++) { + if (!IsInPolygon((int)FROM_LE_32(nlistx[j]), (int)FROM_LE_32(nlisty[j]), hp)) { + sprintf(tBufferAddr(), "Node (%d, %d) is not in its own path (starting (%d, %d))", + (int)FROM_LE_32(nlistx[j]), (int)FROM_LE_32(nlisty[j]), rp->cx[0], rp->cy[0]); + error(tBufferAddr()); + } + } + + // Check end nodes are not in adjacent path + for (j = 0; j < MAXADJ; j++) { // For each adjacent path + if (rp->adjpaths[j] == NULL) + break; + + if (IsInPolygon((int)FROM_LE_32(nlistx[0]), (int)FROM_LE_32(nlisty[0]), PolyIndex(rp->adjpaths[j]))) { + sprintf(tBufferAddr(), "Node (%d, %d) is in another path (starting (%d, %d))", + (int)FROM_LE_32(nlistx[0]), (int)FROM_LE_32(nlisty[0]), rp->adjpaths[j]->cx[0], rp->adjpaths[j]->cy[0]); + error(tBufferAddr()) + } + if (IsInPolygon((int)FROM_LE_32(nlistx[n]), (int)FROM_LE_32(nlisty[n]), PolyIndex(rp->adjpaths[j]))) { + sprintf(tBufferAddr(), "Node (%d, %d) is in another path (starting (%d, %d))", + (int)FROM_LE_32(nlistx[n]), (int)FROM_LE_32(nlisty[n]), rp->adjpaths[j]->cx[0], rp->adjpaths[j]->cy[0]); + error(tBufferAddr()) + } + } + } + } +} +#endif + +/** + * Called at the start of a scene, nobbles TAG polygons which should be dead. + */ +static void SetExBlocks() { + for (int i = 0; i < MAX_POLY; i++) { + if (deadPolys[i]) { + if (Polys[i] && Polys[i]->polytype == BLOCKING) + Polys[i]->polytype = EX_BLOCK; +#ifdef DEBUG + else + error("Impossible message!"); +#endif + } + } +} + +/** + * Called at the start of a scene, nobbles TAG polygons which should be dead. + */ +static void SetExTags(SCNHANDLE ph) { + PTAGSTATE pts; + int i, j; + + for (i = 0; i < numScenesT; i++) { + if (SceneTags[i].sid == ph) { + currentTScene = i; + + pts = &TagStates[SceneTags[i].offset]; + for (j = 0; j < SceneTags[i].nooftags; j++, pts++) { + if (!pts->enabled) + DisableTag(pts->tid); + } + return; + } + } + i = numScenesT++; + currentTScene = i; + assert(numScenesT < MAX_SCENES); // Dead tag remembering: scene limit + + SceneTags[i].sid = ph; + SceneTags[i].offset = nextfreeT; + SceneTags[i].nooftags = 0; + + for (j = 0; j < MAX_POLY; j++) { + if (Polys[j] && Polys[j]->polytype == TAG) { + TagStates[nextfreeT].tid = Polys[j]->polyID; + TagStates[nextfreeT].enabled = true; + nextfreeT++; + assert(nextfreeT < MAX_TAGS); // Dead tag remembering: tag limit + SceneTags[i].nooftags++; + } + } +} + +/** + * Called at the start of a scene, nobbles EXIT polygons which should be dead. + */ +#ifdef DEBUG +void SetExExits(SCNHANDLE ph) { +#else +static void SetExExits(SCNHANDLE ph) { +#endif + PTAGSTATE pts; + int i, j; + + for (i = 0; i < numScenesE; i++) { + if (SceneExits[i].sid == ph) { + currentEScene = i; + + pts = &ExitStates[SceneExits[i].offset]; + for (j = 0; j < SceneExits[i].nooftags; j++, pts++) { + if (!pts->enabled) + DisableExit(pts->tid); + } + return; + } + } + + i = numScenesE++; + currentEScene = i; + assert(numScenesE < MAX_SCENES); // Dead exit remembering: scene limit + + SceneExits[i].sid = ph; + SceneExits[i].offset = nextfreeE; + SceneExits[i].nooftags = 0; + + for (j = 0; j < MAX_POLY; j++) { + if (Polys[j] && Polys[j]->polytype == EXIT) { + ExitStates[nextfreeE].tid = Polys[j]->polyID; + ExitStates[nextfreeE].enabled = true; + nextfreeE++; + assert(nextfreeE < MAX_EXITS); // Dead exit remembering: exit limit + SceneExits[i].nooftags++; + } + } +} + +/** + * Works out some fixed numbers for a polygon. + */ +static void FiddlyBit(POLYGON *p) { + int t1, t2; // General purpose temp. variables + + // Enclosing external rectangle + t1 = p->cx[0] > p->cx[1] ? p->cx[0] : p->cx[1]; + t2 = p->cx[2] > p->cx[3] ? p->cx[2] : p->cx[3]; + p->pright = (short)(t1 > t2 ? t1 : t2); + + t1 = p->cx[0] < p->cx[1] ? p->cx[0] : p->cx[1]; + t2 = p->cx[2] < p->cx[3] ? p->cx[2] : p->cx[3]; + p->pleft = (short)(t1 < t2 ? t1 : t2); + + t1 = p->cy[0] > p->cy[1] ? p->cy[0] : p->cy[1]; + t2 = p->cy[2] > p->cy[3] ? p->cy[2] : p->cy[3]; + p->pbottom = (short)(t1 > t2 ? t1 : t2); + + t1 = p->cy[0] < p->cy[1] ? p->cy[0] : p->cy[1]; + t2 = p->cy[2] < p->cy[3] ? p->cy[2] : p->cy[3]; + p->ptop = (short)(t1 < t2 ? t1 : t2); + + // Rectangles enclosing each side and each side's magic numbers + for (t1 = 0; t1 < 4; t1++) { + p->lright[t1] = p->cx[t1] > p->cx[(t1+1)%4] ? p->cx[t1] : p->cx[(t1+1)%4]; + p->lleft[t1] = p->cx[t1] < p->cx[(t1+1)%4] ? p->cx[t1] : p->cx[(t1+1)%4]; + + p->ltop[t1] = p->cy[t1] < p->cy[(t1+1)%4] ? p->cy[t1] : p->cy[(t1+1)%4]; + p->lbottom[t1] = p->cy[t1] > p->cy[(t1+1)%4] ? p->cy[t1] : p->cy[(t1+1)%4]; + + p->a[t1] = p->cy[t1] - p->cy[(t1+1)%4]; + p->b[t1] = p->cx[(t1+1)%4] - p->cx[t1]; + p->c[t1] = (long)p->cy[t1]*p->cx[(t1+1)%4] - (long)p->cx[t1]*p->cy[(t1+1)%4]; + } +} + +/** + * Calculate a point approximating to the centre of a polygon. + * Not very sophisticated. + */ +#ifdef DEBUG +void PseudoCentre(POLYGON *p) { +#else +static void PseudoCentre(POLYGON *p) { +#endif + p->pcentrex = (p->cx[0] + p->cx[1] + p->cx[2] + p->cx[3])/4; + p->pcentrey = (p->cy[0] + p->cy[1] + p->cy[2] + p->cy[3])/4; + + if (!IsInPolygon(p->pcentrex, p->pcentrey, PolyIndex(p))) { + int i, top = 0, bot = 0; + + for (i = p->ptop; i <= p->pbottom; i++) { + if (IsInPolygon(p->pcentrex, i, PolyIndex(p))) { + top = i; + break; + } + } + for (i = p->pbottom; i >= p->ptop; i--) { + if (IsInPolygon(p->pcentrex, i, PolyIndex(p))) { + bot = i; + break; + } + } + p->pcentrex = (top+bot)/2; + } +#ifdef DEBUG + // assert(IsInPolygon(p->pcentrex, p->pcentrey, PolyIndex(p))); // Pseudo-centre is not in path + if (!IsInPolygon(p->pcentrex, p->pcentrey, PolyIndex(p))) { + sprintf(tBufferAddr(), "Pseudo-centre is not in path (starting (%d, %d)) - polygon reversed?", + p->cx[0], p->cy[0]); + error(tBufferAddr()); + } +#endif +} + +/** + * Allocate a POLYGON structure. + */ +static POLYGON *GetPolyEntry(PTYPE type, const POLY *pp, int pno) { + for (int i = 0; i < MaxPolys; i++) { + if (!Polys[i]) { + POLYGON *p = Polys[i] = &Polygons[i]; + memset(p, 0, sizeof(POLYGON)); + + p->polytype = type; // Polygon type + p->pIndex = pno; + p->tagState = TAG_OFF; + p->pointState = NOT_POINTING; + p->polyID = FROM_LE_32(pp->id); // Identifier + + for (int j = 0; j < 4; j++) { // Polygon definition + p->cx[j] = (short)FROM_LE_32(pp->x[j]); + p->cy[j] = (short)FROM_LE_32(pp->y[j]); + } + + return p; + } + } + + error("Exceeded MaxPolys"); + return NULL; +} + +/** + * Initialise an EXIT polygon. + */ +static void InitExit(const POLY *pp, int pno) { + FiddlyBit(GetPolyEntry(EXIT, pp, pno)); +} + +/** + * Initialise a PATH or NPATH polygon. + */ +static void InitPath(const POLY *pp, bool NodePath, int pno) { + POLYGON *p; + + p = GetPolyEntry(PATH, pp, pno); // Obtain a slot + + if (NodePath) { + p->subtype = NODE; + } else { + p->subtype = NORMAL; + } + + // Clear out ajacent path pointers + memset(p->adjpaths, 0, MAXADJ*sizeof(PPOLYGON)); + + FiddlyBit(p); + PseudoCentre(p); +} + + +/** + * Initialise a BLOCKING polygon. + */ +static void InitBlock(const POLY *pp, int pno) { + FiddlyBit(GetPolyEntry(BLOCKING, pp, pno)); +} + +/** + * Initialise an extra BLOCKING polygon related to a moving actor. + * The width of the polygon depends on the width of the actor which is + * trying to walk through the actor you first thought of. + * This is for dynamic blocking. + */ +HPOLYGON InitExtraBlock(PMACTOR ca, PMACTOR ta) { + int caX, caY; // Calling actor co-ords + int taX, taY; // Test actor co-ords + int left, right; + + GetMActorPosition(ca, &caX, &caY); // Calling actor co-ords + GetMActorPosition(ta, &taX, &taY); // Test actor co-ords + + left = GetMActorLeft(ta) - (GetMActorRight(ca) - caX); + right = GetMActorRight(ta) + (caX - GetMActorLeft(ca)); + + memset(&extraBlock, 0, sizeof(extraBlock)); + + // The 3s on the y co-ordinates used to be 10s + extraBlock.cx[0] = (short)(left - 2); + extraBlock.cy[0] = (short)(taY - 3); + extraBlock.cx[1] = (short)(right + 2); + extraBlock.cy[1] = (short)(taY - 3); + extraBlock.cx[2] = (short)(right + 2); + extraBlock.cy[2] = (short)(taY + 3); + extraBlock.cx[3] = (short)(left - 2); + extraBlock.cy[3] = (short)(taY + 3); + + FiddlyBit(&extraBlock); // Is this necessary? + + Polys[MAX_POLY] = &extraBlock; + return MAX_POLY; +} + +/** + * Initialise an EFFECT polygon. + */ +static void InitEffect(const POLY *pp, int pno) { + FiddlyBit(GetPolyEntry(EFFECT, pp, pno)); +} + + +/** + * Initialise a REFER polygon. + */ +static void InitRefer(const POLY *pp, int pno) { + POLYGON *p = GetPolyEntry(REFER, pp, pno); // Obtain a slot + + p->subtype = FROM_LE_32(pp->reftype); // Refer type + + FiddlyBit(p); +} + + +/** + * Initialise a TAG polygon. + */ +static void InitTag(const POLY *pp, int pno) { + FiddlyBit(GetPolyEntry(TAG, pp, pno)); +} + + +/** + * Called at the start of a scene to initialise the polys in that scene. + */ +void InitPolygons(SCNHANDLE ph, int numPoly, bool bRestart) { + const POLY *pp; // Pointer to compiled data polygon structure + + pHandle = ph; + noofPolys = numPoly; + + if (Polygons == NULL) { + // first time - allocate memory for process list + Polygons = (PPOLYGON)calloc(MaxPolys, sizeof(POLYGON)); + + // make sure memory allocated + if (Polygons == NULL) { + error("Cannot allocate memory for polygon data"); + } + } + + for (int i = 0; i < noofPolys; i++) { + if (Polys[i]) { + Polys[i]->pointState = NOT_POINTING; + Polys[i] = NULL; + } + } + + memset(RoutePaths, 0, sizeof(RoutePaths)); + + if (!bRestart) + memset(deadPolys, 0, sizeof(deadPolys)); + + pp = (const POLY *)LockMem(ph); + for (int i = 0; i < numPoly; i++, pp++) { + switch (FROM_LE_32(pp->type)) { + case POLY_PATH: + InitPath(pp, false, i); + break; + + case POLY_NPATH: + InitPath(pp, true, i); + break; + + case POLY_BLOCK: + InitBlock(pp, i); + break; + + case POLY_REFER: + InitRefer(pp, i); + break; + + case POLY_EFFECT: + InitEffect(pp, i); + break; + + case POLY_EXIT: + InitExit(pp, i); + break; + + case POLY_TAG: + InitTag(pp, i); + break; + + default: + error("Unknown polygon type"); + } + } + SetPathAdjacencies(); // Paths need to know the facts +#ifdef DEBUG + CheckNPathIntegrity(); +#endif + SetExTags(ph); // Some tags may have been killed + SetExExits(ph); // Some exits may have been killed + + if (bRestart) + SetExBlocks(); // Some blocks may have been killed +} + +/** + * Called at the end of a scene to ditch all polygons. + */ +void DropPolygons() { + pathsOnRoute = 0; + memset(RoutePaths, 0, sizeof(RoutePaths)); + RouteEnd = NULL; + + for (int i = 0; i < noofPolys; i++) { + if (Polys[i]) { + Polys[i]->pointState = NOT_POINTING; + Polys[i] = NULL; + } + } + noofPolys = 0; + free(Polygons); + Polygons = NULL; +} + + + +PTYPE PolyType(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (25)"); + + return Polys[hp]->polytype; +} + +int PolySubtype(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (26)"); + + return Polys[hp]->subtype; +} + +int PolyCentreX(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (27)"); + + return Polys[hp]->pcentrex; +} + +int PolyCentreY(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (28)"); + + return Polys[hp]->pcentrey; +} + +int PolyCornerX(HPOLYGON hp, int n) { + CHECK_HP(hp, "Out of range polygon handle (29)"); + + return Polys[hp]->cx[n]; +} + +int PolyCornerY(HPOLYGON hp, int n) { + CHECK_HP(hp, "Out of range polygon handle (30)"); + + return Polys[hp]->cy[n]; +} + +PSTATE PolyPointState(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (31)"); + + return Polys[hp]->pointState; +} + +TSTATE PolyTagState(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (32)"); + + return Polys[hp]->tagState; +} + +SCNHANDLE PolyTagHandle(HPOLYGON hp) { + CHECK_HP(hp, "Out of range polygon handle (33)"); + + return Polys[hp]->oTagHandle; +} + +void SetPolyPointState(HPOLYGON hp, PSTATE ps) { + CHECK_HP(hp, "Out of range polygon handle (34)"); + + Polys[hp]->pointState = ps; +} + +void SetPolyTagState(HPOLYGON hp, TSTATE ts) { + CHECK_HP(hp, "Out of range polygon handle (35)"); + + Polys[hp]->tagState = ts; +} + +void SetPolyTagHandle(HPOLYGON hp, SCNHANDLE th) { + CHECK_HP(hp, "Out of range polygon handle (36)"); + + Polys[hp]->oTagHandle = th; +} + +void MaxPolygons(int numPolys) { + assert(numPolys <= MAX_POLY); + + MaxPolys = numPolys; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/polygons.h b/engines/tinsel/polygons.h new file mode 100644 index 0000000000..464aa4e124 --- /dev/null +++ b/engines/tinsel/polygons.h @@ -0,0 +1,186 @@ +/* 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$ + * + * Definition of POLYGON structure and functions in POLYGONS.C + */ + +#ifndef TINSEL_POLYGONS_H // prevent multiple includes +#define TINSEL_POLYGONS_H + +#include "tinsel/dw.h" // for SCNHANDLE +#include "tinsel/scene.h" // for PPOLY and REEL + +namespace Tinsel { + +// Note 7/10/94, with adjacency reduction ANKHMAP max is 3, UNSEEN max is 4 +// so reduced this back to 6 (from 12) for now. +#define MAXADJ 6 // Max number of known adjacent paths + + +// Polygon Types +enum PTYPE { + TEST, PATH, EXIT, BLOCKING, + EFFECT, REFER, TAG, EX_TAG, EX_EXIT, EX_BLOCK +}; + +// subtype +#define NORMAL 0 +#define NODE 1 // For paths + +// tagState +enum TSTATE { + NO_TAG, TAG_OFF, TAG_ON +}; + +// pointState +enum PSTATE { + NO_POINT, NOT_POINTING, POINTING +}; + + + +struct POLYGON { + + PTYPE polytype; // Polygon type + + int subtype; // refer type in REFER polygons + // NODE/NORMAL in PATH polygons + + int pIndex; // Index into compiled polygon data + + /* + * Data duplicated from compiled polygon data + */ + short cx[4]; // Corners (clockwise direction) + short cy[4]; + int polyID; + + /* For TAG and EXIT (and EFFECT in future?) polygons only */ + TSTATE tagState; + PSTATE pointState; + SCNHANDLE oTagHandle; // Override tag. + + /* For Path polygons only */ + bool tried; + + /* + * Internal derived data for speed and conveniance + * set up by FiddlyBit() + */ + short ptop; // + short pbottom; // Enclosing external rectangle + short pleft; // + short pright; // + + short ltop[4]; // + short lbottom[4]; // Rectangles enclosing each side + short lleft[4]; // + short lright[4]; // + + int a[4]; // y1-y2 } + int b[4]; // x2-x1 } See IsInPolygon() + long c[4]; // y1x2 - x1y2 } + + /* + * Internal derived data for speed and conveniance + * set up by PseudoCentre() + */ + int pcentrex; // Pseudo-centre + int pcentrey; // + + /** + * List of adjacent polygons. For Path polygons only. + * set up by SetPathAdjacencies() + */ + POLYGON *adjpaths[MAXADJ]; + +}; + + +enum { + NOPOLY = -1 +}; + + + +/*-------------------------------------------------------------------------*/ + +bool IsInPolygon(int xt, int yt, HPOLYGON p); +HPOLYGON InPolygon(int xt, int yt, PTYPE type); +void BlockingCorner(HPOLYGON poly, int *x, int *y, int tarx, int tary); +void FindBestPoint(HPOLYGON path, int *x, int *y, int *line); +bool IsAdjacentPath(HPOLYGON path1, HPOLYGON path2); +HPOLYGON getPathOnTheWay(HPOLYGON from, HPOLYGON to); +int NearestEndNode(HPOLYGON path, int x, int y); +int NearEndNode(HPOLYGON spath, HPOLYGON dpath); +int NearestNodeWithin(HPOLYGON npath, int x, int y); +void NearestCorner(int *x, int *y, HPOLYGON spath, HPOLYGON dpath); +bool IsPolyCorner(HPOLYGON hPath, int x, int y); +int GetScale(HPOLYGON path, int y); +void getNpathNode(HPOLYGON npath, int node, int *px, int *py); +void getPolyTagInfo(HPOLYGON p, SCNHANDLE *hTagText, int *tagx, int *tagy); +SCNHANDLE getPolyFilm(HPOLYGON p); +void getPolyNode(HPOLYGON p, int *px, int *py); +SCNHANDLE getPolyScript(HPOLYGON p); +REEL getPolyReelType(HPOLYGON p); +int32 getPolyZfactor(HPOLYGON p); +int numNodes(HPOLYGON pp); +void RebootDeadTags(void); +void DisableBlock(int blockno); +void EnableBlock(int blockno); +void DisableTag(int tagno); +void EnableTag(int tagno); +void DisableExit(int exitno); +void EnableExit(int exitno); +HPOLYGON FirstPathPoly(void); +HPOLYGON GetPolyHandle(int i); +void InitPolygons(SCNHANDLE ph, int numPoly, bool bRestart); +void DropPolygons(void); + + +void SaveDeadPolys(bool *sdp); +void RestoreDeadPolys(bool *sdp); + +/*-------------------------------------------------------------------------*/ + +PTYPE PolyType(HPOLYGON hp); // ->type +int PolySubtype(HPOLYGON hp); // ->subtype +int PolyCentreX(HPOLYGON hp); // ->pcentrex +int PolyCentreY(HPOLYGON hp); // ->pcentrey +int PolyCornerX(HPOLYGON hp, int n); // ->cx[n] +int PolyCornerY(HPOLYGON hp, int n); // ->cy[n] +PSTATE PolyPointState(HPOLYGON hp); // ->pointState +TSTATE PolyTagState(HPOLYGON hp); // ->tagState +SCNHANDLE PolyTagHandle(HPOLYGON hp); // ->oTagHandle + +void SetPolyPointState(HPOLYGON hp, PSTATE ps); // ->pointState +void SetPolyTagState(HPOLYGON hp, TSTATE ts); // ->tagState +void SetPolyTagHandle(HPOLYGON hp, SCNHANDLE th);// ->oTagHandle + +void MaxPolygons(int maxPolys); + +/*-------------------------------------------------------------------------*/ + +} // end of namespace Tinsel + +#endif /* TINSEL_POLYGONS_H */ diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp new file mode 100644 index 0000000000..1ecf43f821 --- /dev/null +++ b/engines/tinsel/rince.cpp @@ -0,0 +1,708 @@ +/* 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$ + * + * Should really be called "moving actors.c" + */ + +#include "tinsel/actors.h" +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/config.h" +#include "tinsel/dw.h" +#include "tinsel/film.h" +#include "tinsel/handle.h" +#include "tinsel/inventory.h" +#include "tinsel/move.h" +#include "tinsel/multiobj.h" // multi-part object defintions etc. +#include "tinsel/object.h" +#include "tinsel/pcode.h" +#include "tinsel/pid.h" +#include "tinsel/rince.h" +#include "tinsel/sched.h" +#include "tinsel/timers.h" +#include "tinsel/token.h" + +#include "common/util.h" + +namespace Tinsel { + +//----------------- LOCAL GLOBAL DATA -------------------- + +static MACTOR Movers[MAX_MOVERS]; + + +/** + * RebootMovers + */ +void RebootMovers(void) { + memset(Movers, 0, sizeof(Movers)); +} + +/** + * Given an actor number, return pointer to its moving actor structure, + * if it is a moving actor. + */ +PMACTOR GetMover(int ano) { + int i; + + // Slot 0 is reserved for lead actor + if (ano == LeadId() || ano == LEAD_ACTOR) + return &Movers[0]; + + for (i = 1; i < MAX_MOVERS; i++) + if (Movers[i].actorID == ano) + return &Movers[i]; + + return NULL; +} + +/** + * Register an actor as being a moving one. + */ +PMACTOR SetMover(int ano) { + int i; + + // Slot 0 is reserved for lead actor + if (ano == LeadId() || ano == LEAD_ACTOR) { + Movers[0].actorToken = TOKEN_LEAD; + Movers[0].actorID = LeadId(); + return &Movers[0]; + } + + // Check it hasn't already been declared + for (i = 1; i < MAX_MOVERS; i++) { + if (Movers[i].actorID == ano) { + // Actor is already a moving actor + return &Movers[i]; + } + } + + // Find an empty slot + for (i = 1; i < MAX_MOVERS; i++) + if (!Movers[i].actorID) { + Movers[i].actorToken = TOKEN_LEAD + i; + Movers[i].actorID = ano; + return &Movers[i]; + } + + error("Too many moving actors"); +} + +/** + * Given an index, returns the associated moving actor. + * + * At the time of writing, used by the effect process. + */ +PMACTOR GetLiveMover(int index) { + assert(index >= 0 && index < MAX_MOVERS); // out of range + + if (Movers[index].MActorState == NORM_MACTOR) + return &Movers[index]; + else + return NULL; +} + +bool IsMAinEffectPoly(int index) { + assert(index >= 0 && index < MAX_MOVERS); // out of range + + return Movers[index].InEffect; +} + +void SetMAinEffectPoly(int index, bool tf) { + assert(index >= 0 && index < MAX_MOVERS); // out of range + + Movers[index].InEffect = tf; +} + +/** + * Remove a moving actor from the current scene. + */ +void KillMActor(PMACTOR pActor) { + if (pActor->MActorState == NORM_MACTOR) { + pActor->MActorState = NO_MACTOR; + MultiDeleteObject(GetPlayfieldList(FIELD_WORLD), pActor->actorObj); + pActor->actorObj = NULL; + assert(CurrentProcess() != pActor->pProc); + ProcessKill(pActor->pProc); + } +} + +/** + * getMActorState + */ +MAS getMActorState(PMACTOR pActor) { + return pActor->MActorState; +} + +/** + * If the actor's object exists, move it behind the background. + * MultiHideObject() is deliberately not used, as StepAnimScript() calls + * cause the object to re-appear. + */ +void hideMActor(PMACTOR pActor, int sf) { + assert(pActor); // Hiding null moving actor + + pActor->aHidden = true; + pActor->SlowFactor = sf; + + if (pActor->actorObj) + MultiSetZPosition(pActor->actorObj, -1); +} + +/** + * getMActorHideState + */ +bool getMActorHideState(PMACTOR pActor) { + if (pActor) + return pActor->aHidden; + else + return false; +} + +/** + * unhideMActor + */ +void unhideMActor(PMACTOR pActor) { + assert(pActor); // unHiding null moving actor + + pActor->aHidden = false; + + // Make visible on the screen + if (pActor->actorObj) { + // If no path, just use first path in the scene + if (pActor->hCpath != NOPOLY) + MAsetZPos(pActor, pActor->objy, getPolyZfactor(pActor->hCpath)); + else + MAsetZPos(pActor, pActor->objy, getPolyZfactor(FirstPathPoly())); + } +} + +/** + * Get it into our heads that there's nothing doing. + * Called at the end of a scene. + */ +void DropMActors(void) { + for (int i = 0; i < MAX_MOVERS; i++) { + Movers[i].MActorState = NO_MACTOR; + Movers[i].objx = 0; + Movers[i].objy = 0; + Movers[i].actorObj = NULL; // No moving actor objects + + Movers[i].hCpath = NOPOLY; // No moving actor path + } +} + + +/** + * Reposition a moving actor. + */ +void MoveMActor(PMACTOR pActor, int x, int y) { + int z; + int node; + HPOLYGON hPath; + + assert(pActor); // Moving null moving actor + assert(pActor->actorObj); + + pActor->objx = x; + pActor->objy = y; + MultiSetAniXY(pActor->actorObj, x, y); + + hPath = InPolygon(x, y, PATH); + if (hPath != NOPOLY) { + pActor->hCpath = hPath; + if (PolySubtype(hPath) == NODE) { + node = NearestNodeWithin(hPath, x, y); + getNpathNode(hPath, node, &pActor->objx, &pActor->objy); + pActor->hFnpath = hPath; + pActor->line = node; + pActor->npstatus = GOING_UP; + } else { + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + } + + z = GetScale(hPath, pActor->objy); + pActor->scale = z; + SetMActorStanding(pActor); + } else { + pActor->bNoPath = true; + + pActor->hFnpath = NOPOLY; // Ain't in one + pActor->npstatus = NOT_IN; + + // Ensure legal reel and scale + if (pActor->dirn < 0 || pActor->dirn > 3) + pActor->dirn = FORWARD; + if (pActor->scale < 0 || pActor->scale > TOTAL_SCALES) + pActor->scale = 1; + } +} + +/** + * Get position of a moving actor. + */ +void GetMActorPosition(PMACTOR pActor, int *paniX, int *paniY) { + assert(pActor); // Getting null moving actor's position + + if (pActor->actorObj != NULL) + GetAniPosition(pActor->actorObj, paniX, paniY); + else { + *paniX = 0; + *paniY = 0; + } +} + +/** + * Moving actor's mid-top position. + */ +void GetMActorMidTopPosition(PMACTOR pActor, int *aniX, int *aniY) { + assert(pActor); // Getting null moving actor's mid-top position + assert(pActor->actorObj); // Getting null moving actor's mid-top position + + *aniX = (MultiLeftmost(pActor->actorObj) + MultiRightmost(pActor->actorObj))/2; + *aniY = MultiHighest(pActor->actorObj); +} + +/** + * Moving actor's left-most co-ordinate. + */ +int GetMActorLeft(PMACTOR pActor) { + assert(pActor); // Getting null moving actor's leftmost position + assert(pActor->actorObj); // Getting null moving actor's leftmost position + + return MultiLeftmost(pActor->actorObj); +} + +/** + * Moving actor's right-most co-ordinate. + */ +int GetMActorRight(PMACTOR pActor) { + assert(pActor); // Getting null moving actor's rightmost position + assert(pActor->actorObj); // Getting null moving actor's rightmost position + + return MultiRightmost(pActor->actorObj); +} + +/** + * See if moving actor is stood within a polygon. + */ +bool MActorIsInPolygon(PMACTOR pActor, HPOLYGON hp) { + assert(pActor); // Checking if null moving actor is in polygon + assert(pActor->actorObj); // Checking if null moving actor is in polygon + + int aniX, aniY; + GetAniPosition(pActor->actorObj, &aniX, &aniY); + + return IsInPolygon(aniX, aniY, hp); +} + +/** + * Change which reel is playing for a moving actor. + */ +void AlterMActor(PMACTOR pActor, SCNHANDLE film, AR_FUNCTION fn) { + const FILM *pfilm; + + assert(pActor->actorObj); // Altering null moving actor's animation script + + if (fn == AR_POPREEL) { + film = pActor->pushedfilm; // Use the saved film + } + if (fn == AR_PUSHREEL) { + // Save the one we're replacing + pActor->pushedfilm = (pActor->TagReelRunning) ? pActor->lastfilm : 0; + } + + if (film == 0) { + if (pActor->TagReelRunning) { + // Revert to 'normal' actor + SetMActorWalkReel(pActor, pActor->dirn, pActor->scale, true); + pActor->TagReelRunning = false; + } + } else { + pActor->lastfilm = film; // Remember this one + + pfilm = (const FILM *)LockMem(film); + assert(pfilm != NULL); + + InitStepAnimScript(&pActor->actorAnim, pActor->actorObj, FROM_LE_32(pfilm->reels[0].script), ONE_SECOND / FROM_LE_32(pfilm->frate)); + pActor->scount = 0; + + // If no path, just use first path in the scene + if (pActor->hCpath != NOPOLY) + MAsetZPos(pActor, pActor->objy, getPolyZfactor(pActor->hCpath)); + else + MAsetZPos(pActor, pActor->objy, getPolyZfactor(FirstPathPoly())); + + if (fn == AR_WALKREEL) { + pActor->TagReelRunning = false; + pActor->walkReel = true; + } else { + pActor->TagReelRunning = true; + pActor->walkReel = false; + +#ifdef DEBUG + assert(StepAnimScript(&pActor->actorAnim) != ScriptFinished); // Actor reel has finished! +#else + StepAnimScript(&pActor->actorAnim); // 04/01/95 +#endif + } + + // Hang on, we may not want him yet! 04/01/95 + if (pActor->aHidden) + MultiSetZPosition(pActor->actorObj, -1); + } +} + +/** + * Return the actor's direction. + */ +DIRREEL GetMActorDirection(PMACTOR pActor) { + return pActor->dirn; +} + +/** + * Return the actor's scale. + */ +int GetMActorScale(PMACTOR pActor) { + return pActor->scale; +} + +/** + * Point actor in specified derection + */ +void SetMActorDirection(PMACTOR pActor, DIRREEL dirn) { + pActor->dirn = dirn; +} + +/** + * MAmoving + */ +bool MAmoving(PMACTOR pActor) { + return pActor->bMoving; +} + +/** + * Return an actor's walk ticket. + */ +int GetActorTicket(PMACTOR pActor) { + return pActor->ticket; +} + +/** + * Get actor to adopt its appropriate standing reel. + */ +void SetMActorStanding(PMACTOR pActor) { + assert(pActor->actorObj); + AlterMActor(pActor, pActor->StandReels[pActor->scale-1][pActor->dirn], AR_NORMAL); +} + +/** + * Get actor to adopt its appropriate walking reel. + */ +void SetMActorWalkReel(PMACTOR pActor, DIRREEL reel, int scale, bool force) { + SCNHANDLE whichReel; + const FILM *pfilm; + + // Kill off any play that may be going on for this actor + // and restore the real actor + storeActorReel(pActor->actorID, NULL, 0, NULL, 0, 0, 0); + unhideMActor(pActor); + + // Don't do it if using a special walk reel + if (pActor->walkReel) + return; + + if (force || pActor->scale != scale || pActor->dirn != reel) { + assert(reel >= 0 && reel <= 3 && scale > 0 && scale <= TOTAL_SCALES); // out of range scale or reel + + // If scale change and both are regular scales + // and there's a scaling reel in the right direction + if (pActor->scale != scale + && scale <= NUM_MAINSCALES && pActor->scale <= NUM_MAINSCALES + && (whichReel = ScalingReel(pActor->actorID, pActor->scale, scale, reel)) != 0) { +// error("Cripes!"); + ; // Use what is now in 'whichReel' + } else { + whichReel = pActor->WalkReels[scale-1][reel]; + assert(whichReel); // no reel + } + + pfilm = (const FILM *)LockMem(whichReel); + assert(pfilm != NULL); // no film + + InitStepAnimScript(&pActor->actorAnim, pActor->actorObj, FROM_LE_32(pfilm->reels[0].script), 1); + + // Synchronised walking reels + SkipFrames(&pActor->actorAnim, pActor->scount); + + pActor->scale = scale; + pActor->dirn = reel; + } +} + +/** + * Sort some stuff out at actor start-up time. + */ +static void InitialPathChecks(PMACTOR pActor, int xpos, int ypos) { + HPOLYGON hPath; + int node; + int z; + + pActor->objx = xpos; + pActor->objy = ypos; + + /*-------------------------------------- + | If Actor is in a follow nodes path, | + | position it at the nearest node. | + --------------------------------------*/ + hPath = InPolygon(xpos, ypos, PATH); + + if (hPath != NOPOLY) { + pActor->hCpath = hPath; + if (PolySubtype(hPath) == NODE) { + node = NearestNodeWithin(hPath, xpos, ypos); + getNpathNode(hPath, node, &pActor->objx, &pActor->objy); + pActor->hFnpath = hPath; + pActor->line = node; + pActor->npstatus = GOING_UP; + } + + z = GetScale(hPath, pActor->objy); + } else { + pActor->bNoPath = true; + + z = GetScale(FirstPathPoly(), pActor->objy); + } + SetMActorWalkReel(pActor, FORWARD, z, false); +} + +/** + * Clear everything out at actor start-up time. + */ +static void InitMActor(PMACTOR pActor) { + + pActor->objx = pActor->objy = 0; + pActor->targetX = pActor->targetY = -1; + pActor->ItargetX = pActor->ItargetY = -1; + pActor->hIpath = NOPOLY; + pActor->UtargetX = pActor->UtargetY = -1; + pActor->hUpath = NOPOLY; + pActor->hCpath = NOPOLY; + + pActor->over = false; + pActor->InDifficulty = NO_PROB; + + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + pActor->line = 0; + + pActor->Tline = 0; + + pActor->TagReelRunning = false; + + if (pActor->dirn != FORWARD || pActor->dirn != AWAY + || pActor->dirn != LEFTREEL || pActor->dirn != RIGHTREEL) + pActor->dirn = FORWARD; + + if (pActor->scale < 0 || pActor->scale > TOTAL_SCALES) + pActor->scale = 1; + + pActor->scount = 0; + + pActor->fromx = pActor->fromy = 0; + + pActor->bMoving = false; + pActor->bNoPath = false; + pActor->bIgPath = false; + pActor->walkReel = false; + + pActor->actorObj = NULL; + + pActor->lastfilm = 0; + pActor->pushedfilm = 0; + + pActor->InEffect = false; + pActor->aHidden = false; // 20/2/95 +} + +static void MActorProcessHelper(int X, int Y, int id, PMACTOR pActor) { + const FILM *pfilm; + const MULTI_INIT *pmi; + const FRAME *pFrame; + PIMAGE pim; + + + assert(BackPal()); // Can't start actor without a background palette + assert(pActor->WalkReels[0][FORWARD]); // Starting actor process without walk reels + + InitMActor(pActor); + InitialPathChecks(pActor, X, Y); + + pfilm = (const FILM *)LockMem(pActor->WalkReels[0][FORWARD]); + pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfilm->reels[0].mobj)); + +//--- + pFrame = (const FRAME *)LockMem(FROM_LE_32(pmi->hMulFrame)); + + // get pointer to image + pim = (PIMAGE)LockMem(READ_LE_UINT32(pFrame)); // handle to image + pim->hImgPal = TO_LE_32(BackPal()); +//--- + pActor->actorObj = MultiInitObject(pmi); + +/**/ assert(pActor->actorID == id); + pActor->actorID = id; + + // add it to display list + MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pActor->actorObj); + storeActorReel(id, NULL, 0, pActor->actorObj, 0, 0, 0); + + InitStepAnimScript(&pActor->actorAnim, pActor->actorObj, FROM_LE_32(pfilm->reels[0].script), ONE_SECOND / FROM_LE_32(pfilm->frate)); + pActor->scount = 0; + + MultiSetAniXY(pActor->actorObj, pActor->objx, pActor->objy); + + // If no path, just use first path in the scene + if (pActor->hCpath != NOPOLY) + MAsetZPos(pActor, pActor->objy, getPolyZfactor(pActor->hCpath)); + else + MAsetZPos(pActor, pActor->objy, getPolyZfactor(FirstPathPoly())); + + // Make him the right size + SetMActorStanding(pActor); + +//**** if added 18/11/94, am + if (X != MAGICX && Y != MAGICY) { + hideMActor(pActor, 0); // Allows a play to come in before this appears + pActor->aHidden = false; // ...but don't stay hidden + } + + pActor->MActorState = NORM_MACTOR; +} + +/** + * Moving actor process - 1 per moving actor in current scene. + */ +void MActorProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + PMACTOR pActor = *(PMACTOR *)ProcessGetParamsSelf(); + + CORO_BEGIN_CODE(_ctx); + + while (1) { + if (pActor->TagReelRunning) { + if (!pActor->aHidden) +#ifdef DEBUG + assert(StepAnimScript(&pActor->actorAnim) != ScriptFinished); // Actor reel has finished! +#else + StepAnimScript(&pActor->actorAnim); +#endif + } else + DoMoveActor(pActor); + + CORO_SLEEP(1); // allow rescheduling + + } + + CORO_END_CODE; +} + +void MActorProcessCreate(int X, int Y, int id, PMACTOR pActor) { + MActorProcessHelper(X, Y, id, pActor); + pActor->pProc = CoroutineInstall(PID_MACTOR, MActorProcess, &pActor, sizeof(PMACTOR)); +} + + +/** + * Check for moving actor collision. + */ +PMACTOR InMActorBlock(PMACTOR pActor, int x, int y) { + int caX; // Calling actor's pos'n + int caL, caR; // Calling actor's left and right + int taX, taY; // Test actor's pos'n + int taL, taR; // Test actor's left and right + + caX = pActor->objx; + if (pActor->hFnpath != NOPOLY || bNoBlocking) + return NULL; + + caL = GetMActorLeft(pActor) + x - caX; + caR = GetMActorRight(pActor) + x - caX; + + for (int i = 0; i < MAX_MOVERS; i++) { + if (pActor == &Movers[i] || Movers[i].MActorState == NO_MACTOR) + continue; + + // At around the same height? + GetMActorPosition(&Movers[i], &taX, &taY); + if (Movers[i].hFnpath != NOPOLY) + continue; + + if (ABS(y - taY) > 2) // 2 was 8 + continue; + + // To the left? + taL = GetMActorLeft(&Movers[i]); + if (caR <= taL) + continue; + + // To the right? + taR = GetMActorRight(&Movers[i]); + if (caL >= taR) + continue; + + return &Movers[i]; + } + return NULL; +} + +/** + * Copies key information for savescn.c to store away. + */ +void SaveMovers(SAVED_MOVER *sMoverInfo) { + for (int i = 0; i < MAX_MOVERS; i++) { + sMoverInfo[i].MActorState= Movers[i].MActorState; + sMoverInfo[i].actorID = Movers[i].actorID; + sMoverInfo[i].objx = Movers[i].objx; + sMoverInfo[i].objy = Movers[i].objy; + sMoverInfo[i].lastfilm = Movers[i].lastfilm; + + memcpy(sMoverInfo[i].WalkReels, Movers[i].WalkReels, TOTAL_SCALES*4*sizeof(SCNHANDLE)); + memcpy(sMoverInfo[i].StandReels, Movers[i].StandReels, TOTAL_SCALES*4*sizeof(SCNHANDLE)); + memcpy(sMoverInfo[i].TalkReels, Movers[i].TalkReels, TOTAL_SCALES*4*sizeof(SCNHANDLE)); + } +} + +void RestoreAuxScales(SAVED_MOVER *sMoverInfo) { + for (int i = 0; i < MAX_MOVERS; i++) { + memcpy(Movers[i].WalkReels, sMoverInfo[i].WalkReels, TOTAL_SCALES*4*sizeof(SCNHANDLE)); + memcpy(Movers[i].StandReels, sMoverInfo[i].StandReels, TOTAL_SCALES*4*sizeof(SCNHANDLE)); + memcpy(Movers[i].TalkReels, sMoverInfo[i].TalkReels, TOTAL_SCALES*4*sizeof(SCNHANDLE)); + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/rince.h b/engines/tinsel/rince.h new file mode 100644 index 0000000000..a3ed5bd845 --- /dev/null +++ b/engines/tinsel/rince.h @@ -0,0 +1,209 @@ +/* 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$ + * + * Should really be called "moving actors.h" + */ + +#ifndef TINSEL_RINCE_H // prevent multiple includes +#define TINSEL_RINCE_H + +#include "tinsel/anim.h" // for ANIM +#include "tinsel/scene.h" // for TFTYPE + +namespace Tinsel { + +struct OBJECT; +struct PROCESS; + +enum NPS {NOT_IN, GOING_UP, GOING_DOWN, LEAVING, ENTERING}; + +enum IND {NO_PROB, TRY_CENTRE, TRY_CORNER, TRY_NEXTCORNER}; + +enum MAS {NO_MACTOR, NORM_MACTOR}; + +enum DIRREEL{ LEFTREEL, RIGHTREEL, FORWARD, AWAY }; + +enum { + NUM_MAINSCALES = 5, + NUM_AUXSCALES = 5, + TOTAL_SCALES = NUM_MAINSCALES + NUM_AUXSCALES +}; + +struct MACTOR { + + int objx; /* Co-ordinates object */ + int objy; + + int targetX, targetY; + int ItargetX, ItargetY; /* Intermediate destination */ + HPOLYGON hIpath; + int UtargetX, UtargetY; /* Ultimate destination */ + HPOLYGON hUpath; + + HPOLYGON hCpath; + + bool over; + int ticket; + + IND InDifficulty; + +/* For use in 'follow nodes' polygons */ + HPOLYGON hFnpath; + NPS npstatus; + int line; + + int Tline; // NEW + + bool TagReelRunning; + + + /* Used internally */ + DIRREEL dirn; // Current reel + int scale; // Current scale + int scount; // Step count for walking reel synchronisation + + unsigned fromx; + unsigned fromy; + + bool bMoving; // Set this to TRUE during a walk + + bool bNoPath; + bool bIgPath; + bool walkReel; + + OBJECT *actorObj; // Actor's object + ANIM actorAnim; // Actor's animation script + + SCNHANDLE lastfilm; // } Used by AlterActor() + SCNHANDLE pushedfilm; // } + + int actorID; + int actorToken; + + SCNHANDLE WalkReels[TOTAL_SCALES][4]; + SCNHANDLE StandReels[TOTAL_SCALES][4]; + SCNHANDLE TalkReels[TOTAL_SCALES][4]; + + MAS MActorState; + + bool aHidden; + int SlowFactor; // Slow down movement while hidden + + bool stop; + + /* NOTE: If effect polys can overlap, this needs improving */ + bool InEffect; + + PROCESS *pProc; +}; +typedef MACTOR *PMACTOR; + +//--------------------------------------------------------------------------- + + +void MActorProcessCreate(int X, int Y, int id, MACTOR *pActor); + + +enum AR_FUNCTION { AR_NORMAL, AR_PUSHREEL, AR_POPREEL, AR_WALKREEL }; + + +MACTOR *GetMover(int ano); +MACTOR *SetMover(int ano); +void KillMActor(MACTOR *pActor); +MACTOR *GetLiveMover(int index); + +MAS getMActorState(MACTOR *psActor); + +void hideMActor(MACTOR *pActor, int sf); +bool getMActorHideState(MACTOR *pActor); +void unhideMActor(MACTOR *pActor); +void DropMActors(void); +void MoveMActor(MACTOR *pActor, int x, int y); + +void GetMActorPosition(MACTOR *pActor, int *aniX, int *aniY); +void GetMActorMidTopPosition(MACTOR *pActor, int *aniX, int *aniY); +int GetMActorLeft(MACTOR *pActor); +int GetMActorRight(MACTOR *pActor); + +bool MActorIsInPolygon(MACTOR *pActor, HPOLYGON hPoly); +void AlterMActor(MACTOR *actor, SCNHANDLE film, AR_FUNCTION fn); +DIRREEL GetMActorDirection(MACTOR *pActor); +int GetMActorScale(MACTOR *pActor); +void SetMActorDirection(MACTOR *pActor, DIRREEL dirn); +void SetMActorStanding(MACTOR *actor); +void SetMActorWalkReel(MACTOR *actor, DIRREEL reel, int scale, bool force); + +MACTOR *InMActorBlock(MACTOR *pActor, int x, int y); + +void RebootMovers(void); + +bool IsMAinEffectPoly(int index); +void SetMAinEffectPoly(int index, bool tf); + +bool MAmoving(MACTOR *pActor); + +int GetActorTicket(MACTOR *pActor); + +/*----------------------------------------------------------------------*/ + +struct SAVED_MOVER { + + MAS MActorState; + int actorID; + int objx; + int objy; + SCNHANDLE lastfilm; + + SCNHANDLE WalkReels[TOTAL_SCALES][4]; + SCNHANDLE StandReels[TOTAL_SCALES][4]; + SCNHANDLE TalkReels[TOTAL_SCALES][4]; + +}; + +void SaveMovers(SAVED_MOVER *sMoverInfo); +void RestoreAuxScales(SAVED_MOVER *sMoverInfo); + +/*----------------------------------------------------------------------*/ + +/* +* Dodgy bit... +* These functions are now in MAREELS.C, but I can't be bothered to +* create a new header file. +*/ +SCNHANDLE GetMactorTalkReel(MACTOR *pAactor, TFTYPE dirn); + +void setscalingreels(int actor, int scale, int direction, + SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away); +SCNHANDLE ScalingReel(int ano, int scale1, int scale2, DIRREEL reel); +void RebootScalingReels(void); + +enum { + MAGICX = -101, + MAGICY = -102 +}; + +/*----------------------------------------------------------------------*/ + +} // end of namespace Tinsel + +#endif /* TINSEL_RINCE_H */ diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp new file mode 100644 index 0000000000..5cb149eb37 --- /dev/null +++ b/engines/tinsel/saveload.cpp @@ -0,0 +1,472 @@ +/* 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$ + * + * Save and restore scene and game. + */ + +#include "tinsel/actors.h" +#include "tinsel/dw.h" +#include "tinsel/inventory.h" +#include "tinsel/rince.h" +#include "tinsel/savescn.h" +#include "tinsel/serializer.h" +#include "tinsel/timers.h" +#include "tinsel/tinlib.h" +#include "tinsel/tinsel.h" + +#include "common/savefile.h" + +namespace Tinsel { + + +/** + * The current savegame format version. + * Our save/load system uses an elaborate scheme to allow us to modify the + * savegame while keeping full backward compatibility, in the sense that newer + * ScummVM versions always are able to load old savegames. + * In order to achieve that, we store a version in the savegame files, and whenever + * the savegame layout is modified, the version is incremented. + * + * This roughly works by marking each savegame entry with a range of versions + * for which it is valid; the save/load code iterates over all entries, but + * only saves/loads those which are valid for the version of the savegame + * which is being loaded/saved currently. + */ +#define CURRENT_VER 1 +// TODO: Not yet used + +/** + * An auxillary macro, used to specify savegame versions. We use this instead + * of just writing the raw version, because this way they stand out more to + * the reading eye, making it a bit easier to navigate through the code. + */ +#define VER(x) x + + + + +//----------------- EXTERN FUNCTIONS -------------------- + +// in DOS_DW.C +extern void syncSCdata(Serializer &s); + +// in DOS_MAIN.C +//char HardDriveLetter(void); + +// in PCODE.C +extern void syncGlobInfo(Serializer &s); + +// in POLYGONS.C +extern void syncPolyInfo(Serializer &s); + +// in SAVESCN.CPP +extern void RestoreScene(SAVED_DATA *sd, bool bFadeOut); + +//----------------- LOCAL DEFINES -------------------- + +struct SaveGameHeader { + uint32 id; + uint32 size; + uint32 ver; + char desc[SG_DESC_LEN]; + struct tm dateTime; +}; + +enum { + SAVEGAME_ID = 0x44575399, // = 'DWSc' = "DiscWorld ScummVM" + SAVEGAME_HEADER_SIZE = 4 + 4 + 4 + SG_DESC_LEN + 7 +}; + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static int numSfiles = 0; +static SFILES savedFiles[MAX_SFILES]; + +static bool NeedLoad = true; + +static SAVED_DATA *srsd = 0; +static int RestoreGameNumber = 0; +static char *SaveSceneName = 0; +static const char *SaveSceneDesc = 0; +static int *SaveSceneSsCount = 0; +static char *SaveSceneSsData = 0; // points to 'SAVED_DATA ssdata[MAX_NEST]' + +static SRSTATE SRstate = SR_IDLE; + +//------------- SAVE/LOAD SUPPORT METHODS ---------------- + +static void syncTime(Serializer &s, struct tm &t) { + s.syncAsUint16LE(t.tm_year); + s.syncAsByte(t.tm_mon); + s.syncAsByte(t.tm_mday); + s.syncAsByte(t.tm_hour); + s.syncAsByte(t.tm_min); + s.syncAsByte(t.tm_sec); + if (s.isLoading()) { + t.tm_wday = 0; + t.tm_yday = 0; + t.tm_isdst = 0; + } +} + +static bool syncSaveGameHeader(Serializer &s, SaveGameHeader &hdr) { + s.syncAsUint32LE(hdr.id); + s.syncAsUint32LE(hdr.size); + s.syncAsUint32LE(hdr.ver); + + s.syncBytes((byte *)hdr.desc, SG_DESC_LEN); + + syncTime(s, hdr.dateTime); + + int tmp = hdr.size - s.bytesSynced(); + // Perform sanity check + if (tmp < 0 || hdr.id != SAVEGAME_ID || hdr.ver > CURRENT_VER || hdr.size > 1024) + return false; + // Skip over any extra bytes + while (tmp-- > 0) { + byte b = 0; + s.syncAsByte(b); + } + return true; +} + +static void syncSavedMover(Serializer &s, SAVED_MOVER &sm) { + SCNHANDLE *pList[3] = { (SCNHANDLE *)&sm.WalkReels, (SCNHANDLE *)&sm.StandReels, (SCNHANDLE *)&sm.TalkReels }; + + s.syncAsUint32LE(sm.MActorState); + s.syncAsSint32LE(sm.actorID); + s.syncAsSint32LE(sm.objx); + s.syncAsSint32LE(sm.objy); + s.syncAsUint32LE(sm.lastfilm); + + for (int pIndex = 0; pIndex < 3; ++pIndex) { + SCNHANDLE *p = pList[pIndex]; + for (int i = 0; i < TOTAL_SCALES * 4; ++i) + s.syncAsUint32LE(*p++); + } +} + +static void syncSavedActor(Serializer &s, SAVED_ACTOR &sa) { + s.syncAsUint16LE(sa.actorID); + s.syncAsUint16LE(sa.z); + s.syncAsUint32LE(sa.bAlive); + s.syncAsUint32LE(sa.presFilm); + s.syncAsUint16LE(sa.presRnum); + s.syncAsUint16LE(sa.presX); + s.syncAsUint16LE(sa.presY); +} + +extern void syncAllActorsAlive(Serializer &s); + +static void syncNoScrollB(Serializer &s, NOSCROLLB &ns) { + s.syncAsSint32LE(ns.ln); + s.syncAsSint32LE(ns.c1); + s.syncAsSint32LE(ns.c2); +} + +static void syncSavedData(Serializer &s, SAVED_DATA &sd) { + s.syncAsUint32LE(sd.SavedSceneHandle); + s.syncAsUint32LE(sd.SavedBgroundHandle); + for (int i = 0; i < MAX_MOVERS; ++i) + syncSavedMover(s, sd.SavedMoverInfo[i]); + for (int i = 0; i < MAX_SAVED_ACTORS; ++i) + syncSavedActor(s, sd.SavedActorInfo[i]); + + s.syncAsSint32LE(sd.NumSavedActors); + s.syncAsSint32LE(sd.SavedLoffset); + s.syncAsSint32LE(sd.SavedToffset); + for (int i = 0; i < MAX_INTERPRET; ++i) + sd.SavedICInfo[i].syncWithSerializer(s); + for (int i = 0; i < MAX_POLY; ++i) + s.syncAsUint32LE(sd.SavedDeadPolys[i]); + s.syncAsUint32LE(sd.SavedControl); + s.syncAsUint32LE(sd.SavedMidi); + s.syncAsUint32LE(sd.SavedLoop); + s.syncAsUint32LE(sd.SavedNoBlocking); + + // SavedNoScrollData + for (int i = 0; i < MAX_VNOSCROLL; ++i) + syncNoScrollB(s, sd.SavedNoScrollData.NoVScroll[i]); + for (int i = 0; i < MAX_HNOSCROLL; ++i) + syncNoScrollB(s, sd.SavedNoScrollData.NoHScroll[i]); + s.syncAsUint32LE(sd.SavedNoScrollData.NumNoV); + s.syncAsUint32LE(sd.SavedNoScrollData.NumNoH); +} + + +/** + * Called when saving a game to a new file. + * Generates a new, unique, filename. + */ +static char *NewName(void) { + static char result[FNAMELEN]; + int i; + int ano = 1; // Allocated number + + while (1) { + Common::String fname = _vm->getSavegameFilename(ano); + strcpy(result, fname.c_str()); + + for (i = 0; i < numSfiles; i++) + if (!strcmp(savedFiles[i].name, result)) + break; + + if (i == numSfiles) + break; + ano++; + } + + return result; +} + +/** + * Interrogate the current DOS directory for saved game files. + * Store the file details, ordered by time, in savedFiles[] and return + * the number of files found). + */ +int getList(void) { + // No change since last call? + // TODO/FIXME: Just always reload this data? Be careful about slow downs!!! + if (!NeedLoad) + return numSfiles; + + int i; + + const Common::String pattern = _vm->getSavegamePattern(); + Common::StringList files = _vm->getSaveFileMan()->listSavefiles(pattern.c_str()); + + numSfiles = 0; + + for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) { + if (numSfiles >= MAX_SFILES) + break; + + const Common::String &fname = *file; + Common::InSaveFile *f = _vm->getSaveFileMan()->openForLoading(fname.c_str()); + if (f == NULL) { + continue; + } + + // Try to load save game header + Serializer s(f, 0); + SaveGameHeader hdr; + bool validHeader = syncSaveGameHeader(s, hdr); + delete f; + if (!validHeader) { + continue; // Invalid header, or savegame too new -> skip it + // TODO: In SCUMM, we still show an entry for the save, but with description + // "incompatible version". + } + + i = numSfiles; +#ifndef DISABLE_SAVEGAME_SORTING + for (i = 0; i < numSfiles; i++) { + if (difftime(mktime(&hdr.dateTime), mktime(&savedFiles[i].dateTime)) > 0) { + Common::copy_backward(&savedFiles[i], &savedFiles[numSfiles], &savedFiles[numSfiles + 1]); + break; + } + } +#endif + + strncpy(savedFiles[i].name, fname.c_str(), FNAMELEN); + strncpy(savedFiles[i].desc, hdr.desc, SG_DESC_LEN); + savedFiles[i].dateTime = hdr.dateTime; + + ++numSfiles; + } + + // Next getList() needn't do its stuff again + NeedLoad = false; + + return numSfiles; +} + + +char *ListEntry(int i, letype which) { + if (i == -1) + i = numSfiles; + + assert(i >= 0); + + if (i < numSfiles) + return which == LE_NAME ? savedFiles[i].name : savedFiles[i].desc; + else + return NULL; +} + +static void DoSync(Serializer &s) { + int sg; + + syncSavedData(s, *srsd); + syncGlobInfo(s); // Glitter globals + syncInvInfo(s); // Inventory data + + // Held object + if (s.isSaving()) + sg = WhichItemHeld(); + s.syncAsSint32LE(sg); + if (s.isLoading()) + HoldItem(sg); + + syncTimerInfo(s); // Timer data + syncPolyInfo(s); // Dead polygon data + syncSCdata(s); // Hook Scene and delayed scene + + s.syncAsSint32LE(*SaveSceneSsCount); + + if (*SaveSceneSsCount != 0) { + SAVED_DATA *sdPtr = (SAVED_DATA *)SaveSceneSsData; + for (int i = 0; i < *SaveSceneSsCount; ++i, ++sdPtr) + syncSavedData(s, *sdPtr); + } + + syncAllActorsAlive(s); +} + +/** + * DoRestore + */ +static bool DoRestore(void) { + Common::InSaveFile *f; + uint32 id; + + f = _vm->getSaveFileMan()->openForLoading(savedFiles[RestoreGameNumber].name); + if (f == NULL) { + return false; + } + + Serializer s(f, 0); + SaveGameHeader hdr; + if (!syncSaveGameHeader(s, hdr)) { + delete f; // Invalid header, or savegame too new -> skip it + return false; + } + + DoSync(s); + + id = f->readSint32LE(); + if (id != (uint32)0xFEEDFACE) + error("Incompatible saved game"); + + bool failed = f->ioFailed(); + + delete f; + + return !failed; +} + +/** + * DoSave + */ +static void DoSave(void) { + Common::OutSaveFile *f; + const char *fname; + + // Next getList() must do its stuff again + NeedLoad = true; + + if (SaveSceneName == NULL) + SaveSceneName = NewName(); + if (SaveSceneDesc[0] == 0) + SaveSceneDesc = "unnamed"; + + fname = SaveSceneName; + + f = _vm->getSaveFileMan()->openForSaving(fname); + if (f == NULL) + return; + + Serializer s(0, f); + + // Write out a savegame header + SaveGameHeader hdr; + hdr.id = SAVEGAME_ID; + hdr.size = SAVEGAME_HEADER_SIZE; + hdr.ver = CURRENT_VER; + memcpy(hdr.desc, SaveSceneDesc, SG_DESC_LEN); + g_system->getTimeAndDate(hdr.dateTime); + if (!syncSaveGameHeader(s, hdr) || f->ioFailed()) { + goto save_failure; + } + + DoSync(s); + + // Write out the special Id for Discworld savegames + f->writeUint32LE(0xFEEDFACE); + if (f->ioFailed()) + goto save_failure; + + f->finalize(); + delete f; + return; + +save_failure: + delete f; + _vm->getSaveFileMan()->removeSavefile(fname); +} + +/** + * ProcessSRQueue + */ +void ProcessSRQueue(void) { + switch (SRstate) { + case SR_DORESTORE: + if (DoRestore()) { + RestoreScene(srsd, false); + } + SRstate = SR_IDLE; + break; + + case SR_DOSAVE: + DoSave(); + SRstate = SR_IDLE; + break; + default: + break; + } +} + + +void RequestSaveGame(char *name, char *desc, SAVED_DATA *sd, int *pSsCount, SAVED_DATA *pSsData) { + assert(SRstate == SR_IDLE); + + SaveSceneName = name; + SaveSceneDesc = desc; + SaveSceneSsCount = pSsCount; + SaveSceneSsData = (char *)pSsData; + srsd = sd; + SRstate = SR_DOSAVE; +} + +void RequestRestoreGame(int num, SAVED_DATA *sd, int *pSsCount, SAVED_DATA *pSsData) { + assert(num >= 0); + + RestoreGameNumber = num; + SaveSceneSsCount = pSsCount; + SaveSceneSsData = (char *)pSsData; + srsd = sd; + SRstate = SR_DORESTORE; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/savescn.cpp b/engines/tinsel/savescn.cpp new file mode 100644 index 0000000000..fa6e921a56 --- /dev/null +++ b/engines/tinsel/savescn.cpp @@ -0,0 +1,335 @@ +/* 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$ + * + * Save and restore scene and game. + */ + + +#include "tinsel/actors.h" +#include "tinsel/background.h" +#include "tinsel/config.h" +#include "tinsel/dw.h" +#include "tinsel/faders.h" // FadeOutFast() +#include "tinsel/graphics.h" // ClearScreen() +#include "tinsel/handle.h" +#include "tinsel/inventory.h" +#include "tinsel/music.h" +#include "tinsel/pid.h" +#include "tinsel/rince.h" +#include "tinsel/savescn.h" +#include "tinsel/sched.h" +#include "tinsel/scroll.h" +#include "tinsel/sound.h" +#include "tinsel/tinlib.h" +#include "tinsel/token.h" + +namespace Tinsel { + +//----------------- EXTERN FUNCTIONS -------------------- + +// in BG.C +extern void startupBackground(SCNHANDLE bfilm); +extern SCNHANDLE GetBgroundHandle(void); +extern void SetDoFadeIn(bool tf); + +// In DOS_DW.C +void RestoreMasterProcess(PINT_CONTEXT pic); + +// in EVENTS.C (declared here and not in events.h because of strange goings-on) +void RestoreProcess(PINT_CONTEXT pic); + +// in PLAY.C +extern void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y); + +// in SCENE.C +extern SCNHANDLE GetSceneHandle(void); +extern void NewScene(SCNHANDLE scene, int entry); + + + + +//----------------- LOCAL DEFINES -------------------- + +enum { + RS_COUNT = 5, // Restore scene count + + MAX_NEST = 4 +}; + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static bool ASceneIsSaved = false; + +static int savedSceneCount = 0; + +//static SAVED_DATA s_ssData[MAX_NEST]; +static SAVED_DATA *s_ssData = 0; +static SAVED_DATA sgData; + +static SAVED_DATA *s_rsd = 0; + +static int s_restoreSceneCount = 0; + +static bool bNoFade = false; + +//----------------- FORWARD REFERENCES -------------------- + + + +void InitialiseSs(void) { + if (s_ssData == NULL) { + s_ssData = (SAVED_DATA *)calloc(MAX_NEST, sizeof(SAVED_DATA)); + if (s_ssData == NULL) { + error("Cannot allocate memory for scene changes"); + } + } else + savedSceneCount = 0; +} + +void FreeSs(void) { + if (s_ssData) { + free(s_ssData); + s_ssData = NULL; + } +} + +/** + * Save current scene. + * @param sd Pointer to the scene data + */ +void SaveScene(SAVED_DATA *sd) { + sd->SavedSceneHandle = GetSceneHandle(); + sd->SavedBgroundHandle = GetBgroundHandle(); + SaveMovers(sd->SavedMoverInfo); + sd->NumSavedActors = SaveActors(sd->SavedActorInfo); + PlayfieldGetPos(FIELD_WORLD, &sd->SavedLoffset, &sd->SavedToffset); + SaveInterpretContexts(sd->SavedICInfo); + SaveDeadPolys(sd->SavedDeadPolys); + sd->SavedControl = TestToken(TOKEN_CONTROL); + CurrentMidiFacts(&sd->SavedMidi, &sd->SavedLoop); + sd->SavedNoBlocking = bNoBlocking; + GetNoScrollData(&sd->SavedNoScrollData); + + ASceneIsSaved = true; +} + +/** + * Initiate restoration of the saved scene. + * @param sd Pointer to the scene data + * @param bFadeOut Flag to perform a fade out + */ +void RestoreScene(SAVED_DATA *sd, bool bFadeOut) { + s_rsd = sd; + + if (bFadeOut) + s_restoreSceneCount = RS_COUNT + COUNTOUT_COUNT; // Set restore scene count + else + s_restoreSceneCount = RS_COUNT; // Set restore scene count +} + +/** + * Checks that all non-moving actors are playing the same reel as when + * the scene was saved. + * Also 'stand' all the moving actors at their saved positions. + */ +void sortActors(SAVED_DATA *rsd) { + for (int i = 0; i < rsd->NumSavedActors; i++) { + ActorsLife(rsd->SavedActorInfo[i].actorID, rsd->SavedActorInfo[i].bAlive); + + // Should be playing the same reel. + if (rsd->SavedActorInfo[i].presFilm != 0) { + if (!actorAlive(rsd->SavedActorInfo[i].actorID)) + continue; + + playThisReel(rsd->SavedActorInfo[i].presFilm, rsd->SavedActorInfo[i].presRnum, rsd->SavedActorInfo[i].z, + rsd->SavedActorInfo[i].presX, rsd->SavedActorInfo[i].presY); + } + } + + RestoreAuxScales(rsd->SavedMoverInfo); + for (int i = 0; i < MAX_MOVERS; i++) { + if (rsd->SavedMoverInfo[i].MActorState == NORM_MACTOR) + stand(rsd->SavedMoverInfo[i].actorID, rsd->SavedMoverInfo[i].objx, + rsd->SavedMoverInfo[i].objy, rsd->SavedMoverInfo[i].lastfilm); + } +} + + +//--------------------------------------------------------------------------- + +void ResumeInterprets(SAVED_DATA *rsd) { + // Master script only affected on restore game, not restore scene + if (rsd == &sgData) { + KillMatchingProcess(PID_MASTER_SCR, -1); + FreeMasterInterpretContext(); + } + + for (int i = 0; i < MAX_INTERPRET; i++) { + switch (rsd->SavedICInfo[i].GSort) { + case GS_NONE: + break; + + case GS_INVENTORY: + if (rsd->SavedICInfo[i].event != POINTED) { + RestoreProcess(&rsd->SavedICInfo[i]); + } + break; + + case GS_MASTER: + // Master script only affected on restore game, not restore scene + if (rsd == &sgData) + RestoreMasterProcess(&rsd->SavedICInfo[i]); + break; + + case GS_ACTOR: + RestoreActorProcess(rsd->SavedICInfo[i].actorid, &rsd->SavedICInfo[i]); + break; + + case GS_POLYGON: + case GS_SCENE: + RestoreProcess(&rsd->SavedICInfo[i]); + break; + } + } +} + +/** + * Do restore scene + * @param n Id + */ +static int DoRestoreScene(SAVED_DATA *rsd, int n) { + switch (n) { + case RS_COUNT + COUNTOUT_COUNT: + // Trigger pre-load and fade and start countdown + FadeOutFast(NULL); + break; + + case RS_COUNT: + _vm->_sound->stopAllSamples(); + ClearScreen(0L); + RestoreDeadPolys(rsd->SavedDeadPolys); + NewScene(rsd->SavedSceneHandle, NO_ENTRY_NUM); + SetDoFadeIn(!bNoFade); + bNoFade = false; + startupBackground(rsd->SavedBgroundHandle); + KillScroll(); + PlayfieldSetPos(FIELD_WORLD, rsd->SavedLoffset, rsd->SavedToffset); + bNoBlocking = rsd->SavedNoBlocking; + RestoreNoScrollData(&rsd->SavedNoScrollData); +/* + break; + + case RS_COUNT - 1: +*/ + sortActors(rsd); + break; + + case 2: + break; + + case 1: + RestoreMidiFacts(rsd->SavedMidi, rsd->SavedLoop); + if (rsd->SavedControl) + control(CONTROL_ON); // TOKEN_CONTROL was free + ResumeInterprets(rsd); + } + + return n - 1; +} + +/** + * Restore game + * @param num num + */ +void RestoreGame(int num) { + KillInventory(); + + RequestRestoreGame(num, &sgData, &savedSceneCount, s_ssData); + + // Actual restoring is performed by ProcessSRQueue +} + +/** + * Save game + * @param name Name of savegame + * @param desc Description of savegame + */ +void SaveGame(char *name, char *desc) { + // Get current scene data + SaveScene(&sgData); + + RequestSaveGame(name, desc, &sgData, &savedSceneCount, s_ssData); + + // Actual saving is performed by ProcessSRQueue +} + + +//--------------------------------------------------------------------------------- + +bool IsRestoringScene() { + if (s_restoreSceneCount) { + s_restoreSceneCount = DoRestoreScene(s_rsd, s_restoreSceneCount); + } + + return s_restoreSceneCount ? true : false; +} + +/** + * Please Restore Scene + */ +void PleaseRestoreScene(bool bFade) { + // only called by restore_scene PCODE + if (s_restoreSceneCount == 0) { + assert(savedSceneCount >= 1); // No saved scene to restore + + if (ASceneIsSaved) + RestoreScene(&s_ssData[--savedSceneCount], bFade); + if (!bFade) + bNoFade = true; + } +} + +/** + * Please Save Scene + */ +void PleaseSaveScene(CORO_PARAM) { + // only called by save_scene PCODE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + assert(savedSceneCount < MAX_NEST); // nesting limit reached + + // Don't save the same thing multiple times! + // FIXME/TODO: Maybe this can be changed to an assert? + if (savedSceneCount && s_ssData[savedSceneCount-1].SavedSceneHandle == GetSceneHandle()) + CORO_KILL_SELF(); + + SaveScene(&s_ssData[savedSceneCount++]); + + CORO_END_CODE; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/savescn.h b/engines/tinsel/savescn.h new file mode 100644 index 0000000000..a999c9bffa --- /dev/null +++ b/engines/tinsel/savescn.h @@ -0,0 +1,103 @@ +/* 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$ + * + * Should really be called "moving actors.h" + */ + +#ifndef TINSEL_SAVESCN_H +#define TINSEL_SAVESCN_H + +#include // for time_t struct + +#include "tinsel/actors.h" // SAVED_ACTOR +#include "tinsel/dw.h" // SCNHANDLE +#include "tinsel/rince.h" // SAVED_MOVER +#include "tinsel/pcode.h" // INT_CONTEXT +#include "tinsel/scroll.h" // SCROLLDATA + +namespace Tinsel { + +enum { + SG_DESC_LEN = 40, // Max. saved game description length + MAX_SFILES = 30, + + // FIXME: Save file names in ScummVM can be longer than 8.3, overflowing the + // name field in savedFiles. Raising it to 256 as a preliminary fix. + FNAMELEN = 256 // 8.3 +}; + +struct SFILES { + char name[FNAMELEN]; + char desc[SG_DESC_LEN + 2]; + struct tm dateTime; +}; + +struct SAVED_DATA { + SCNHANDLE SavedSceneHandle; // Scene handle + SCNHANDLE SavedBgroundHandle; // Background handle + SAVED_MOVER SavedMoverInfo[MAX_MOVERS]; // Moving actors + SAVED_ACTOR SavedActorInfo[MAX_SAVED_ACTORS]; // } Actors + int NumSavedActors; // } + int SavedLoffset, SavedToffset; // Screen offsets + INT_CONTEXT SavedICInfo[MAX_INTERPRET]; // Interpret contexts + bool SavedDeadPolys[MAX_POLY]; + bool SavedControl; + SCNHANDLE SavedMidi; // } + bool SavedLoop; // } Midi + bool SavedNoBlocking; + SCROLLDATA SavedNoScrollData; +}; + + +enum SRSTATE { + SR_IDLE, SR_DORESTORE, SR_DONERESTORE, + SR_DOSAVE, SR_DONESAVE, SR_ABORTED +}; + +void PleaseRestoreScene(bool bFade); +void PleaseSaveScene(CORO_PARAM); + +bool IsRestoringScene(); + + +enum letype{ + LE_NAME, LE_DESC +}; + +char *ListEntry(int i, letype which); +int getList(void); + +void RestoreGame(int num); +void SaveGame(char *name, char *desc); + +void ProcessSRQueue(void); + +void RequestSaveGame(char *name, char *desc, SAVED_DATA *sd, int *ssCount, SAVED_DATA *ssData); +void RequestRestoreGame(int num, SAVED_DATA *sd, int *ssCount, SAVED_DATA *ssData); + +void InitialiseSs(void); +void FreeSs(void); + +} // end of namespace Tinsel + +#endif /* TINSEL_SAVESCN_H */ diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp new file mode 100644 index 0000000000..006efd7b25 --- /dev/null +++ b/engines/tinsel/scene.cpp @@ -0,0 +1,308 @@ +/* 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$ + * + * Starts up new scenes. + */ + +#include "tinsel/actors.h" +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/config.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/graphics.h" +#include "tinsel/handle.h" +#include "tinsel/inventory.h" +#include "tinsel/film.h" +#include "tinsel/move.h" +#include "tinsel/rince.h" +#include "tinsel/sched.h" +#include "tinsel/scn.h" +#include "tinsel/scroll.h" +#include "tinsel/sound.h" // stopAllSamples() +#include "tinsel/object.h" +#include "tinsel/pcode.h" +#include "tinsel/pid.h" // process IDs +#include "tinsel/token.h" + + +namespace Tinsel { + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in BG.C +extern void DropBackground(void); + +// in EFFECT.C +extern void EffectPolyProcess(CORO_PARAM); + +// in PDISPLAY.C +#ifdef DEBUG +extern void CursorPositionProcess(CORO_PARAM); +#endif +extern void TagProcess(CORO_PARAM); +extern void PointProcess(CORO_PARAM); +extern void EnableTags(void); + + +//----------------- LOCAL DEFINES -------------------- + +#include "common/pack-start.h" // START STRUCT PACKING + +/** scene structure - one per scene */ +struct SCENE_STRUC { + int32 numEntrance; //!< number of entrances in this scene + int32 numPoly; //!< number of various polygons in this scene + int32 numActor; //!< number of actors in this scene + int32 defRefer; //!< Default refer direction + SCNHANDLE hSceneScript; //!< handle to scene script + SCNHANDLE hEntrance; //!< handle to table of entrances + SCNHANDLE hPoly; //!< handle to table of polygons + SCNHANDLE hActor; //!< handle to table of actors +} PACKED_STRUCT; + +/** entrance structure - one per entrance */ +struct ENTRANCE_STRUC { + int32 eNumber; //!< entrance number + SCNHANDLE hScript; //!< handle to entrance script +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + + +//----------------- LOCAL GLOBAL DATA -------------------- + +#ifdef DEBUG +static bool ShowPosition = false; // Set when showpos() has been called +#endif + +static SCNHANDLE SceneHandle = 0; // Current scene handle - stored in case of Save_Scene() + + +/** + * Started up for scene script and entrance script. + */ +static void SceneTinselProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + CORO_END_CONTEXT(_ctx); + + // get the stuff copied to process when it was created + SCNHANDLE *ss = (SCNHANDLE *)ProcessGetParamsSelf(); + assert(*ss); // Must have some code to run + + CORO_BEGIN_CODE(_ctx); + + _ctx->pic = InitInterpretContext(GS_SCENE, READ_LE_UINT32(ss), NOEVENT, NOPOLY, 0, NULL); + CORO_INVOKE_1(Interpret, _ctx->pic); + + CORO_END_CODE; +} + +/** + * Get the SCENE_STRUC + * Initialise polygons for the scene + * Initialise the actors for this scene + * Run the appropriate entrance code (if any) + * Get the default refer type + */ +static void LoadScene(SCNHANDLE scene, int entry) { + const SCENE_STRUC *ss; + const ENTRANCE_STRUC *es; + uint i; + + // Scene structure + SceneHandle = scene; // Save scene handle in case of Save_Scene() + + LockMem(SceneHandle); // Make sure scene is loaded + LockScene(SceneHandle); // Prevent current scene from being discarded + + ss = (const SCENE_STRUC *)FindChunk(scene, CHUNK_SCENE); + assert(ss != NULL); + + // Initialise all the polygons for this scene + InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), (entry == NO_ENTRY_NUM)); + + // Initialise the actors for this scene + StartActors(FROM_LE_32(ss->hActor), FROM_LE_32(ss->numActor), (entry != NO_ENTRY_NUM)); + + if (entry != NO_ENTRY_NUM) { + + // Run the appropriate entrance code (if any) + es = (const ENTRANCE_STRUC *)LockMem(FROM_LE_32(ss->hEntrance)); + for (i = 0; i < FROM_LE_32(ss->numEntrance); i++, es++) { + if (FROM_LE_32(es->eNumber) == (uint)entry) { + if (es->hScript) + CoroutineInstall(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript)); + break; + } + } + + if (i == FROM_LE_32(ss->numEntrance)) + error("Non-existant scene entry number"); + + if (ss->hSceneScript) + CoroutineInstall(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript)); + } + + // Default refer type + SetDefaultRefer(FROM_LE_32(ss->defRefer)); +} + + +/** + * Wrap up the last scene. + */ +void EndScene(void) { + if (SceneHandle != 0) { + UnlockScene(SceneHandle); + SceneHandle = 0; + } + + KillInventory(); // Close down any open inventory + + DropPolygons(); // No polygons + DropNoScrolls(); // No no-scrolls + DropBackground(); // No background + DropMActors(); // No moving actors + DropCursor(); // No cursor + DropActors(); // No actor reels running + FreeAllTokens(); // No-one has tokens + FreeMostInterpretContexts(); // Only master script still interpreting + + _vm->_sound->stopAllSamples(); // Kill off any still-running sample + + // init the palette manager + ResetPalAllocator(); + + // init the object manager + KillAllObjects(); + + // kill all destructable process + KillMatchingProcess(PID_DESTROY, PID_DESTROY); +} + +/** + * + */ +void PrimeBackground(void) +{ + // structure for playfields + static PLAYFIELD playfield[] = { + { // FIELD WORLD + NULL, // no modules + NULL, // display list + 0, // init field x + 0, // init field y + 0, // x vel + 0, // y vel + Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), // clip rect + false // moved flag + }, + { // FIELD STATUS + NULL, // no modules + NULL, // display list + 0, // init field x + 0, // init field y + 0, // x vel + 0, // y vel + Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), // clip rect + false // moved flag + } + }; + + // structure for background + static BACKGND backgnd = { + BLACK, // sky colour + Common::Point(0, 0), // initial world pos + Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), // scroll limits + 0, // no background update process + NULL, // no x scroll table + NULL, // no y scroll table + 2, // 2 playfields + playfield, // playfield pointer + false // no auto-erase + }; + + InitBackground(&backgnd); +} + +/** + * Start up the standard stuff for the next scene. + */ + +void PrimeScene(void) { + + bNoBlocking = false; + + RestartCursor(); // Restart the cursor + EnableTags(); // Next scene with tags enabled + + CoroutineInstall(PID_SCROLL, ScrollProcess, NULL, 0); + CoroutineInstall(PID_SCROLL, EffectPolyProcess, NULL, 0); + +#ifdef DEBUG + if (ShowPosition) + CoroutineInstall(PID_POSITION, CursorPositionProcess, NULL, 0); +#endif + + CoroutineInstall(PID_TAG, TagProcess, NULL, 0); + CoroutineInstall(PID_TAG, PointProcess, NULL, 0); + + // init the current background + PrimeBackground(); +} + +/** + * Wrap up the last scene and start up the next scene. + */ + +void NewScene(SCNHANDLE scene, int entry) { + EndScene(); // Wrap up the last scene. + + PrimeScene(); // Start up the standard stuff for the next scene. + + LoadScene(scene, entry); +} + +#ifdef DEBUG +/** + * Sets the ShowPosition flag, causing the cursor position process to be + * created in each scene. + */ + +void setshowpos(void) { + ShowPosition = true; +} +#endif + +/** + * Return the current scene handle. + */ + +SCNHANDLE GetSceneHandle(void) { + return SceneHandle; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/scene.h b/engines/tinsel/scene.h new file mode 100644 index 0000000000..baecac40b9 --- /dev/null +++ b/engines/tinsel/scene.h @@ -0,0 +1,79 @@ +/* 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$ + * + * Scene parsing defines + */ + +#ifndef TINSEL_SCENE_H +#define TINSEL_SCENE_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +enum { + MAX_NODES = 32, //!< maximum nodes in a Node Path + MAX_NOSCROLL = 16, //!< maximum number of NoScroll commands in a scene + MAX_ENTRANCE = 25, //!< maximum number of entrances in a scene + MAX_POLY = 256, //!< maximum number of polygons in a scene + MAX_ACTOR = 32 //!< maximum number of actors in a scene +}; + +/** reference direction */ +enum REFTYPE { + REF_DEFAULT, REF_UP, REF_DOWN, REF_LEFT, REF_RIGHT, REF_POINT +}; + +enum TFTYPE { + TF_NONE, TF_UP, TF_DOWN, TF_LEFT, TF_RIGHT, TF_BOGUS +}; + +/** different actor masks */ +enum MASK_TYPE{ + ACT_DEFAULT, + ACT_MASK = -1, + ACT_ALWAYS = -2 +}; + +/** different types of polygon */ +enum POLY_TYPE { + POLY_PATH, POLY_NPATH, POLY_BLOCK, POLY_REFER, POLY_EFFECT, + POLY_EXIT, POLY_TAG +}; + +/** different scales */ +enum SCALE { + SCALE_DEFAULT, SCALE_LARGE, SCALE_MEDIUM, SCALE_SMALL, + SCALE_COMPACT, SCALE_TINY, + SCALE_AUX1, SCALE_AUX2, SCALE_AUX3, + SCALE_AUX4, SCALE_AUX5 +}; + +/** different reels */ +enum REEL { + REEL_DEFAULT, REEL_ALL, REEL_HORIZ, REEL_VERT +}; + +} // end of namespace Tinsel + +#endif // TINSEL_SCENE_H diff --git a/engines/tinsel/sched.cpp b/engines/tinsel/sched.cpp new file mode 100644 index 0000000000..9391805040 --- /dev/null +++ b/engines/tinsel/sched.cpp @@ -0,0 +1,344 @@ +/* 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$ + * + * Process scheduler. + */ + +#include "tinsel/sched.h" + +#include "common/util.h" + +namespace Tinsel { + + +/** list of all processes */ +static PROCESS *processList = 0; + +/** active process list - also saves scheduler state */ +static PROCESS active; + +/** pointer to free process list */ +static PROCESS *pFreeProcesses = 0; + +/** the currently active process */ +static PROCESS *pCurrent = 0; + +#ifdef DEBUG +// diagnostic process counters +static int numProcs = 0; +static int maxProcs = 0; +#endif + +/** + * Called from ProcessKill() to enable other resources + * a process may be allocated to be released. + */ +static VFPTRPP pRCfunction = 0; + + +/** + * Kills all processes and places them on the free list. + */ +void InitScheduler(void) { + +#ifdef DEBUG + // clear number of process in use + numProcs = 0; +#endif + + if (processList == NULL) { + // first time - allocate memory for process list + processList = (PROCESS *)calloc(NUM_PROCESS, sizeof(PROCESS)); + + // make sure memory allocated + if (processList == NULL) { + error("Cannot allocate memory for process data"); + } + + // fill with garbage + memset(processList, 'S', NUM_PROCESS * sizeof(PROCESS)); + } + + // no active processes + pCurrent = active.pNext = NULL; + + // place first process on free list + pFreeProcesses = processList; + + // link all other processes after first + for (int i = 1; i < NUM_PROCESS; i++) { + processList[i - 1].pNext = processList + i; + } + + // null the last process + processList[NUM_PROCESS - 1].pNext = NULL; +} + +void FreeProcessList(void) { + if (processList) { + free(processList); + processList = NULL; + } +} + + +#ifdef DEBUG +/** + * Shows the maximum number of process used at once. + */ +void ProcessStats(void) { + printf("%i process of %i used.\n", maxProcs, NUM_PROCESS); +} +#endif + + +/** + * Give all active processes a chance to run + */ +void Scheduler(void) { + // start dispatching active process list + PROCESS *pPrevProc = &active; + PROCESS *pProc = active.pNext; + while (pProc != NULL) { + if (--pProc->sleepTime <= 0) { + // process is ready for dispatch, activate it + pCurrent = pProc; + pProc->coroAddr(pProc->state); + pCurrent = NULL; + if (!pProc->state || pProc->state->_sleep <= 0) { + // Coroutine finished + ProcessKill(pProc); + pProc = pPrevProc; + } else { + pProc->sleepTime = pProc->state->_sleep; + } + } + pPrevProc = pProc; + pProc = pProc->pNext; + } +} + + +/** + * Creates a new process. + * + * @param pid process identifier + * @param CORO_ADDR coroutine start address + * @param pParam process specific info + * @param sizeParam size of process specific info + */ +PROCESS *CoroutineInstall(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) { + PROCESS *pProc; + + // get a free process + pProc = pFreeProcesses; + + // trap no free process + assert(pProc != NULL); // Out of processes + +#ifdef DEBUG + // one more process in use + if (++numProcs > maxProcs) + maxProcs = numProcs; +#endif + + // get link to next free process + pFreeProcesses = pProc->pNext; + + if (pCurrent != NULL) { + // place new process before the next active process + pProc->pNext = pCurrent->pNext; + + // make this new process the next active process + pCurrent->pNext = pProc; + } else { // no active processes, place process at head of list + pProc->pNext = active.pNext; + active.pNext = pProc; + } + + // set coroutine entry point + pProc->coroAddr = coroAddr; + + // clear coroutine state + pProc->state = 0; + + // wake process up as soon as possible + pProc->sleepTime = 1; + + // set new process id + pProc->pid = pid; + + // set new process specific info + if (sizeParam) { + assert(sizeParam > 0 && sizeParam <= PARAM_SIZE); + + // set new process specific info + memcpy(pProc->param, pParam, sizeParam); + } + + + // return created process + return pProc; +} + +/** + * Kills the specified process. + * + * @param pKillProc which process to kill + */ +void ProcessKill(PROCESS *pKillProc) { + PROCESS *pProc, *pPrev; // process list pointers + + // make sure a valid process pointer + assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1); + + // can not kill the current process using ProcessKill ! + assert(pCurrent != pKillProc); + +#ifdef DEBUG + // one less process in use + --numProcs; + assert(numProcs >= 0); +#endif + + // search the active list for the process + for (pProc = active.pNext, pPrev = &active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { + if (pProc == pKillProc) { + // found process in active list + + // Free process' resources + if (pRCfunction != NULL) + (pRCfunction)(pProc); + + delete pProc->state; + + // make prev point to next to unlink pProc + pPrev->pNext = pProc->pNext; + + // link first free process after pProc + pProc->pNext = pFreeProcesses; + + // make pProc the first free process + pFreeProcesses = pProc; + + return; + } + } + + // process not found in active list if we get to here + error("ProcessKill(): tried to kill a process not in the list of active processes"); +} + + + +/** + * Returns a pointer to the currently running process. + */ +PROCESS *CurrentProcess(void) { + return pCurrent; +} + +char *ProcessGetParamsSelf() { + PROCESS *pProc = pCurrent; + + // make sure a valid process pointer + assert(pProc >= processList && pProc <= processList + NUM_PROCESS - 1); + + return pProc->param; +} + +/** + * Returns the process identifier of the specified process. + * + * @param pProc which process + */ +int ProcessGetPID(PROCESS *pProc) { + // make sure a valid process pointer + assert(pProc >= processList && pProc <= processList + NUM_PROCESS - 1); + + // return processes PID + return pProc->pid; +} + +/** + * Kills any process matching the specified PID. The current + * process cannot be killed. + * + * @param pidKill process identifier of process to kill + * @param pidMask mask to apply to process identifiers before comparison + * @return The number of processes killed is returned. + */ +int KillMatchingProcess(int pidKill, int pidMask) { + int numKilled = 0; + PROCESS *pProc, *pPrev; // process list pointers + + for (pProc = active.pNext, pPrev = &active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { + if ((pProc->pid & pidMask) == pidKill) { + // found a matching process + + // dont kill the current process + if (pProc != pCurrent) { + // kill this process + numKilled++; + + // make prev point to next to unlink pProc + pPrev->pNext = pProc->pNext; + + // link first free process after pProc + pProc->pNext = pFreeProcesses; + + // make pProc the first free process + pFreeProcesses = pProc; + + // set to a process on the active list + pProc = pPrev; + } + } + } + +#ifdef DEBUG + // adjust process in use + numProcs -= numKilled; + assert(numProcs >= 0); +#endif + + // return number of processes killed + return numKilled; +} + + + +/** + * Set pointer to a function to be called by ProcessKill(). + * + * May be called by a resource allocator, the function supplied is + * called by ProcessKill() to allow the resource allocator to free + * resources allocated to the dying process. + * + * @param pFunc Function to be called by ProcessKill() + */ +void SetResourceCallback(VFPTRPP pFunc) { + pRCfunction = pFunc; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/sched.h b/engines/tinsel/sched.h new file mode 100644 index 0000000000..6b89a60891 --- /dev/null +++ b/engines/tinsel/sched.h @@ -0,0 +1,100 @@ +/* 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$ + * + * Data structures used by the process scheduler + */ + +#ifndef TINSEL_SCHED_H // prevent multiple includes +#define TINSEL_SCHED_H + +#include "tinsel/dw.h" // new data types +#include "tinsel/coroutine.h" + +namespace Tinsel { + +// the size of process specific info +#define PARAM_SIZE 32 + +// the maximum number of processes +#define NUM_PROCESS 64 + +typedef void (*CORO_ADDR)(CoroContext &); + + +// process structure + +struct PROCESS { + PROCESS *pNext; // pointer to next process in active or free list + + CoroContext state; // the state of the coroutine + CORO_ADDR coroAddr; // the entry point of the coroutine + + int sleepTime; // number of scheduler cycles to sleep + int pid; // process ID + char param[PARAM_SIZE]; // process specific info +}; + + +/*----------------------------------------------------------------------*\ +|* Scheduler Function Prototypes *| +\*----------------------------------------------------------------------*/ + +void InitScheduler(void); // called to init scheduler - kills all processes and places them on free list + +void FreeProcessList(void); + +#ifdef DEBUG +void ProcessStats(void); // Shows the maximum number of process used at once +#endif + +void Scheduler(void); // called to start process dispatching + +PROCESS *CoroutineInstall(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam); + +void ProcessKill( // kill a process + PROCESS *pKillProc); // which process to kill (must be different from current one) + +PROCESS *CurrentProcess(void); // Returns a pointer to the currently running process + +int ProcessGetPID( // Returns the process identifier of the specified process + PROCESS *pProc); // which process + +char *ProcessGetParamsSelf(); + +int KillMatchingProcess( // kill any process matching the pid parameters + int pidKill, // process identifier of process to kill + int pidMask); // mask to apply to process identifiers before comparison + + +// Pointer to a function of the form "void function(PPROCESS)" +typedef void (*VFPTRPP)(PROCESS *); + +void SetResourceCallback(VFPTRPP pFunc); // May be called by a resource allocator, + // the function supplied is called by ProcessKill() + // to allow the resource allocator to free resources + // allocated to the dying process. + + +} // end of namespace Tinsel + +#endif // TINSEL_SCHED_H diff --git a/engines/tinsel/scn.cpp b/engines/tinsel/scn.cpp new file mode 100644 index 0000000000..b14b1c5962 --- /dev/null +++ b/engines/tinsel/scn.cpp @@ -0,0 +1,80 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + * A (some would say very) small collection of utility functions. + */ + +#include "common/endian.h" +#include "common/util.h" + +#include "tinsel/dw.h" +#include "tinsel/film.h" +#include "tinsel/handle.h" +#include "tinsel/multiobj.h" +#include "tinsel/scn.h" +#include "tinsel/tinsel.h" // for _vm + +namespace Tinsel { + +/** + * Given a scene handle and a chunk id, gets the scene in RAM and + * locates the requested chunk. + * @param handle Scene handle + * @param chunk Chunk Id + */ +byte *FindChunk(SCNHANDLE handle, uint32 chunk) { + byte *bptr = LockMem(handle); + uint32 *lptr = (uint32 *)bptr; + uint32 add; + + // V1 chunk types can be found by substracting 2 from the + // chunk type. Note that CHUNK_STRING and CHUNK_BITMAP are + // the same in V1 and V2 + if (_vm->getVersion() == TINSEL_V1 && + chunk != CHUNK_STRING && chunk != CHUNK_BITMAP) + chunk -= 0x2L; + + while (1) { + if (READ_LE_UINT32(lptr) == chunk) + return (byte *)(lptr + 2); + + ++lptr; + add = READ_LE_UINT32(lptr); + if (!add) + return NULL; + + lptr = (uint32 *)(bptr + add); + } +} + +/** + * Get the actor id from a film (column 0) + */ +int extractActor(SCNHANDLE film) { + const FILM *pfilm = (const FILM *)LockMem(film); + const FREEL *preel = &pfilm->reels[0]; + const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(preel->mobj)); + return (int)FROM_LE_32(pmi->mulID); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/scn.h b/engines/tinsel/scn.h new file mode 100644 index 0000000000..29f3dc51fc --- /dev/null +++ b/engines/tinsel/scn.h @@ -0,0 +1,68 @@ +/* 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 TINSEL_SCN_H // prevent multiple includes +#define TINSEL_SCN_H + +#include "tinsel/dw.h" + +namespace Tinsel { + + +// chunk identifier numbers + +// V2 chunks + +#define CHUNK_STRING 0x33340001L // same in V1 and V2 +#define CHUNK_BITMAP 0x33340002L // same in V1 and V2 +#define CHUNK_CHARPTR 0x33340003L // not used! +#define CHUNK_CHARMATRIX 0x33340004L // not used! +#define CHUNK_PALETTE 0x33340005L // not used! +#define CHUNK_IMAGE 0x33340006L // not used! +#define CHUNK_ANI_FRAME 0x33340007L // not used! +#define CHUNK_FILM 0x33340008L // not used! +#define CHUNK_FONT 0x33340009L // not used! +#define CHUNK_PCODE 0x3334000AL +#define CHUNK_ENTRANCE 0x3334000BL // not used! +#define CHUNK_POLYGONS 0x3334000CL // not used! +#define CHUNK_ACTORS 0x3334000DL // not used! +#define CHUNK_SCENE 0x3334000EL +#define CHUNK_TOTAL_ACTORS 0x3334000FL +#define CHUNK_TOTAL_GLOBALS 0x33340010L +#define CHUNK_TOTAL_OBJECTS 0x33340011L +#define CHUNK_OBJECTS 0x33340012L +#define CHUNK_MIDI 0x33340013L // not used! +#define CHUNK_SAMPLE 0x33340014L // not used! +#define CHUNK_TOTAL_POLY 0x33340015L +#define CHUNK_MBSTRING 0x33340022L // Multi-byte characters + +#define INDEX_FILENAME "index" // name of index file + +byte *FindChunk(SCNHANDLE handle, uint32 chunk); +int extractActor(SCNHANDLE film); + +} // end of namespace Tinsel + +#endif /* TINSEL_SCN_H */ diff --git a/engines/tinsel/scroll.cpp b/engines/tinsel/scroll.cpp new file mode 100644 index 0000000000..7c0b12730f --- /dev/null +++ b/engines/tinsel/scroll.cpp @@ -0,0 +1,432 @@ +/* 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$ + * + * Handles scrolling + */ + +#include "tinsel/actors.h" +#include "tinsel/background.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/graphics.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/scroll.h" +#include "tinsel/sched.h" + +namespace Tinsel { + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in BG.C +extern int BackgroundWidth(void); +extern int BackgroundHeight(void); + + + +//----------------- LOCAL DEFINES -------------------- + +#define LEFT 'L' +#define RIGHT 'R' +#define UP 'U' +#define DOWN 'D' + + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static int LeftScroll = 0, DownScroll = 0; // Number of iterations outstanding + +static int scrollActor = 0; +static PMACTOR psActor = 0; +static int oldx = 0, oldy = 0; + +/** Boundaries and numbers of boundaries */ +static SCROLLDATA sd = { + { + {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}, {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 + }; + +static int ImageH = 0, ImageW = 0; + +static bool ScrollCursor = 0; // If a TAG or EXIT polygon is clicked on, + // the cursor is kept over that polygon + // whilst scrolling + +static int scrollPixels = SCROLLPIXELS; + + +/** + * Reset the ScrollCursor flag + */ +void DontScrollCursor(void) { + ScrollCursor = false; +} + +/** + * Set the ScrollCursor flag + */ +void DoScrollCursor(void) { + ScrollCursor = true; +} + +/** + * Configure a no-scroll boundary for a scene. + */ +void SetNoScroll(int x1, int y1, int x2, int y2) { + if (x1 == x2) { + /* Vertical line */ + assert(sd.NumNoH < MAX_HNOSCROLL); + + sd.NoHScroll[sd.NumNoH].ln = x1; // X pos of vertical line + sd.NoHScroll[sd.NumNoH].c1 = y1; + sd.NoHScroll[sd.NumNoH].c2 = y2; + sd.NumNoH++; + } else if (y1 == y2) { + /* Horizontal line */ + assert(sd.NumNoV < MAX_VNOSCROLL); + + sd.NoVScroll[sd.NumNoV].ln = y1; // Y pos of horizontal line + sd.NoVScroll[sd.NumNoV].c1 = x1; + sd.NoVScroll[sd.NumNoV].c2 = x2; + sd.NumNoV++; + } else { + /* No-scroll lines must be horizontal or vertical */ + } +} + +/** + * Does the obvious - called at the end of a scene. + */ +void DropNoScrolls(void) { + sd.NumNoH = sd.NumNoV = 0; +} + +/** + * Called from scroll process when it thinks that a scroll is in order. + * Checks for no-scroll boundaries and sets off a scroll if allowed. + */ +static void NeedScroll(int direction) { + uint i; + int BottomLine, RightCol; + int Loffset, Toffset; + + // get background offsets + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + switch (direction) { + case LEFT: /* Picture will go left, 'camera' right */ + + BottomLine = Toffset + (SCREEN_HEIGHT - 1); + RightCol = Loffset + (SCREEN_WIDTH - 1); + + for (i = 0; i < sd.NumNoH; i++) { + if (RightCol >= sd.NoHScroll[i].ln - 1 && RightCol <= sd.NoHScroll[i].ln + 1 && + ((sd.NoHScroll[i].c1 >= Toffset && sd.NoHScroll[i].c1 <= BottomLine) || + (sd.NoHScroll[i].c2 >= Toffset && sd.NoHScroll[i].c2 <= BottomLine) || + (sd.NoHScroll[i].c1 < Toffset && sd.NoHScroll[i].c2 > BottomLine))) + return; + } + + if (LeftScroll <= 0) { + scrollPixels = SCROLLPIXELS; + LeftScroll = RLSCROLL; + } + break; + + case RIGHT: /* Picture will go right, 'camera' left */ + + BottomLine = Toffset + (SCREEN_HEIGHT - 1); + + for (i = 0; i < sd.NumNoH; i++) { + if (Loffset >= sd.NoHScroll[i].ln - 1 && Loffset <= sd.NoHScroll[i].ln + 1 && + ((sd.NoHScroll[i].c1 >= Toffset && sd.NoHScroll[i].c1 <= BottomLine) || + (sd.NoHScroll[i].c2 >= Toffset && sd.NoHScroll[i].c2 <= BottomLine) || + (sd.NoHScroll[i].c1 < Toffset && sd.NoHScroll[i].c2 > BottomLine))) + return; + } + + if (LeftScroll >= 0) { + scrollPixels = SCROLLPIXELS; + LeftScroll = -RLSCROLL; + } + break; + + case UP: /* Picture will go upwards, 'camera' downwards */ + + BottomLine = Toffset + (SCREEN_HEIGHT - 1); + RightCol = Loffset + (SCREEN_WIDTH - 1); + + for (i = 0; i < sd.NumNoV; i++) { + if ((BottomLine >= sd.NoVScroll[i].ln - 1 && BottomLine <= sd.NoVScroll[i].ln + 1) && + ((sd.NoVScroll[i].c1 >= Loffset && sd.NoVScroll[i].c1 <= RightCol) || + (sd.NoVScroll[i].c2 >= Loffset && sd.NoVScroll[i].c2 <= RightCol) || + (sd.NoVScroll[i].c1 < Loffset && sd.NoVScroll[i].c2 > RightCol))) + return; + } + + if (DownScroll <= 0) { + scrollPixels = SCROLLPIXELS; + DownScroll = UDSCROLL; + } + break; + + case DOWN: /* Picture will go downwards, 'camera' upwards */ + + RightCol = Loffset + (SCREEN_WIDTH - 1); + + for (i = 0; i < sd.NumNoV; i++) { + if (Toffset >= sd.NoVScroll[i].ln - 1 && Toffset <= sd.NoVScroll[i].ln + 1 && + ((sd.NoVScroll[i].c1 >= Loffset && sd.NoVScroll[i].c1 <= RightCol) || + (sd.NoVScroll[i].c2 >= Loffset && sd.NoVScroll[i].c2 <= RightCol) || + (sd.NoVScroll[i].c1 < Loffset && sd.NoVScroll[i].c2 > RightCol))) + return; + } + + if (DownScroll >= 0) { + scrollPixels = SCROLLPIXELS; + DownScroll = -UDSCROLL; + } + break; + } +} + +/** + * Called from scroll process - Scrolls the image as appropriate. + */ +static void ScrollImage(void) { + int OldLoffset = 0, OldToffset = 0; // Used when keeping cursor on a tag + int Loffset, Toffset; + int curX, curY; + + // get background offsets + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + /* + * Keeping cursor on a tag? + */ + if (ScrollCursor) { + GetCursorXY(&curX, &curY, true); + if (InPolygon(curX, curY, TAG) != NOPOLY || InPolygon(curX, curY, EXIT) != NOPOLY) { + OldLoffset = Loffset; + OldToffset = Toffset; + } else + ScrollCursor = false; + } + + /* + * Horizontal scrolling + */ + if (LeftScroll > 0) { + LeftScroll -= scrollPixels; + if (LeftScroll < 0) { + Loffset += LeftScroll; + LeftScroll = 0; + } + Loffset += scrollPixels; // Move right + if (Loffset > ImageW - SCREEN_WIDTH) + Loffset = ImageW - SCREEN_WIDTH;// Now at extreme right + } else if (LeftScroll < 0) { + LeftScroll += scrollPixels; + if (LeftScroll > 0) { + Loffset += LeftScroll; + LeftScroll = 0; + } + Loffset -= scrollPixels; // Move left + if (Loffset < 0) + Loffset = 0; // Now at extreme left + } + + /* + * Vertical scrolling + */ + if (DownScroll > 0) { + DownScroll -= scrollPixels; + if (DownScroll < 0) { + Toffset += DownScroll; + DownScroll = 0; + } + Toffset += scrollPixels; // Move down + + if (Toffset > ImageH - SCREEN_HEIGHT) + Toffset = ImageH - SCREEN_HEIGHT;// Now at extreme bottom + + } else if (DownScroll < 0) { + DownScroll += scrollPixels; + if (DownScroll > 0) { + Toffset += DownScroll; + DownScroll = 0; + } + Toffset -= scrollPixels; // Move up + + if (Toffset < 0) + Toffset = 0; // Now at extreme top + } + + /* + * Move cursor if keeping cursor on a tag. + */ + if (ScrollCursor) + AdjustCursorXY(OldLoffset - Loffset, OldToffset - Toffset); + + PlayfieldSetPos(FIELD_WORLD, Loffset, Toffset); +} + + +/** + * See if the actor on whom the camera is is approaching an edge. + * Request a scroll if he is. + */ +static void MonitorScroll(void) { + int newx, newy; + int Loffset, Toffset; + + /* + * Only do it if the actor is there and is visible + */ + if (!psActor || getMActorHideState(psActor) + || getMActorState(psActor) == NO_MACTOR) + return; + + GetActorPos(scrollActor, &newx, &newy); + + if (oldx == newx && oldy == newy) + return; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + /* + * Approaching right side or left side of the screen? + */ + if (newx > Loffset+SCREEN_WIDTH-RLDISTANCE && Loffset < ImageW-SCREEN_WIDTH) { + if (newx > oldx) + NeedScroll(LEFT); + } else if (newx < Loffset + RLDISTANCE && Loffset) { + if (newx < oldx) + NeedScroll(RIGHT); + } + + /* + * Approaching bottom or top of the screen? + */ + if (newy > Toffset+SCREEN_HEIGHT-UDDISTANCE && Toffset < ImageH-SCREEN_HEIGHT) { + if (newy > oldy) + NeedScroll(UP); + } else if (Toffset && newy < Toffset + UDDISTANCE + GetActorBottom(scrollActor) - GetActorTop(scrollActor)) { + if (newy < oldy) + NeedScroll(DOWN); + } + + oldx = newx; + oldy = newy; +} + +/** + * Decide when to scroll and scroll when decided to. + */ +void ScrollProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + ImageH = BackgroundHeight(); // Dimensions + ImageW = BackgroundWidth(); // of this scene. + + // Give up if there'll be no purpose in this process + if (ImageW == SCREEN_WIDTH && ImageH == SCREEN_HEIGHT) + CORO_KILL_SELF(); + + LeftScroll = DownScroll = 0; // No iterations outstanding + oldx = oldy = 0; + scrollPixels = SCROLLPIXELS; + + if (!scrollActor) + scrollActor = LeadId(); + + psActor = GetMover(scrollActor); + + while (1) { + MonitorScroll(); // Set scroll requirement + + if (LeftScroll || DownScroll) // Scroll if required + ScrollImage(); + + CORO_SLEEP(1); // allow re-scheduling + } + + CORO_END_CODE; +} + +/** + * Change which actor the camera is following. + */ +void ScrollFocus(int ano) { + if (scrollActor != ano) { + oldx = oldy = 0; + scrollActor = ano; + + psActor = ano ? GetMover(scrollActor) : NULL; + } +} + +/** + * Scroll to abslote position. + */ +void ScrollTo(int x, int y, int iter) { + int Loffset, Toffset; // for background offsets + + scrollPixels = iter != 0 ? iter : SCROLLPIXELS; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); // get background offsets + + LeftScroll = x - Loffset; + DownScroll = y - Toffset; +} + +/** + * Kill of any current scroll. + */ +void KillScroll(void) { + LeftScroll = DownScroll = 0; +} + + +void GetNoScrollData(SCROLLDATA *ssd) { + memcpy(ssd, &sd, sizeof(SCROLLDATA)); +} + +void RestoreNoScrollData(SCROLLDATA *ssd) { + memcpy(&sd, ssd, sizeof(SCROLLDATA)); +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/scroll.h b/engines/tinsel/scroll.h new file mode 100644 index 0000000000..02ce2afd5b --- /dev/null +++ b/engines/tinsel/scroll.h @@ -0,0 +1,77 @@ +/* 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 TINSEL_SCROLL_H // prevent multiple includes +#define TINSEL_SCROLL_H + +namespace Tinsel { + +#define SCROLLPIXELS 8 // Number of pixels to scroll per iteration + +#define RLDISTANCE 50 // Distance from edge that triggers a scroll +#define UDDISTANCE 20 + +// Number of iterations to make +#define RLSCROLL 160 // 20*8 = 160 = half a screen +#define UDSCROLL 100 // 12.5*8 = 100 = half a screen + + +// These structures defined here so boundaries can be saved +struct NOSCROLLB { + int ln; + int c1; + int c2; +}; + +#define MAX_HNOSCROLL 10 +#define MAX_VNOSCROLL 10 + +struct SCROLLDATA{ + NOSCROLLB NoVScroll[MAX_VNOSCROLL]; // Vertical no-scroll boundaries + NOSCROLLB NoHScroll[MAX_HNOSCROLL]; // Horizontal no-scroll boundaries + unsigned NumNoV, NumNoH; // Counts of no-scroll boundaries +}; + + + +void DontScrollCursor(void); +void DoScrollCursor(void); + +void SetNoScroll(int x1, int y1, int x2, int y2); +void DropNoScrolls(void); + +void ScrollProcess(CORO_PARAM); + +void ScrollFocus(int actor); +void ScrollTo(int x, int y, int iter); + +void KillScroll(void); + +void GetNoScrollData(SCROLLDATA *ssd); +void RestoreNoScrollData(SCROLLDATA *ssd); + +} // end of namespace Tinsel + +#endif /* TINSEL_SCROLL_H */ diff --git a/engines/tinsel/serializer.h b/engines/tinsel/serializer.h new file mode 100644 index 0000000000..98ee398ef8 --- /dev/null +++ b/engines/tinsel/serializer.h @@ -0,0 +1,131 @@ +/* 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$ + * + * Handles timers. + */ + +#ifndef TINSEL_SERIALIZER_H +#define TINSEL_SERIALIZER_H + +#include "common/scummsys.h" +#include "common/savefile.h" + + +namespace Tinsel { + + +#define SYNC_AS(SUFFIX,TYPE,SIZE) \ + template \ + void syncAs ## SUFFIX(T &val) { \ + if (_loadStream) \ + val = static_cast(_loadStream->read ## SUFFIX()); \ + else { \ + TYPE tmp = val; \ + _saveStream->write ## SUFFIX(tmp); \ + } \ + _bytesSynced += SIZE; \ + } + + +// TODO: Write comment for this +// TODO: Inspired by the SCUMM engine -- move to common/ code and use in more engines? +class Serializer { +public: + Serializer(Common::SeekableReadStream *in, Common::OutSaveFile *out) + : _loadStream(in), _saveStream(out), _bytesSynced(0) { + assert(in || out); + } + + bool isSaving() { return (_saveStream != 0); } + bool isLoading() { return (_loadStream != 0); } + + uint bytesSynced() const { return _bytesSynced; } + + void syncBytes(byte *buf, uint16 size) { + if (_loadStream) + _loadStream->read(buf, size); + else + _saveStream->write(buf, size); + _bytesSynced += size; + } + + SYNC_AS(Byte, byte, 1) + + SYNC_AS(Uint16LE, uint16, 2) + SYNC_AS(Uint16BE, uint16, 2) + SYNC_AS(Sint16LE, int16, 2) + SYNC_AS(Sint16BE, int16, 2) + + SYNC_AS(Uint32LE, uint32, 4) + SYNC_AS(Uint32BE, uint32, 4) + SYNC_AS(Sint32LE, int32, 4) + SYNC_AS(Sint32BE, int32, 4) + +protected: + Common::SeekableReadStream *_loadStream; + Common::OutSaveFile *_saveStream; + + uint _bytesSynced; +}; + +#undef SYNC_AS + +// TODO: Make a subclass "VersionedSerializer", which makes it easy to support +// multiple versions of a savegame format (again inspired by SCUMM). +/* +class VersionedSerializer : public Serializer { +public: + // "version" is the version of the savegame we are loading/creating + VersionedSerializer(Common::SeekableReadStream *in, Common::OutSaveFile *out, int version) + : Serializer(in, out), _version(version) { + assert(in || out); + } + + void syncBytes(byte *buf, uint16 size, int minVersion = 0, int maxVersion = INF) { + if (_version < minVersion || _version > maxVersion) + return; // Do nothing if too old or too new + if (_loadStream) { + _loadStream->read(buf, size); + } else { + _saveStream->write(buf, size); + } + } + ... + +}; + +*/ + +// Mixin class / interface +// TODO Maybe call it ISerializable or SerializableMixin ? +// TODO: Taken from SCUMM engine -- move to common/ code? +class Serializable { +public: + virtual ~Serializable() {} + virtual void saveLoadWithSerializer(Serializer *ser) = 0; +}; + + +} // end of namespace Tinsel + +#endif diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp new file mode 100644 index 0000000000..0a3b01089f --- /dev/null +++ b/engines/tinsel/sound.cpp @@ -0,0 +1,257 @@ +/* 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$ + * + * sound functionality + */ + +#include "tinsel/sound.h" + +#include "tinsel/dw.h" +#include "tinsel/config.h" +#include "tinsel/music.h" +#include "tinsel/strres.h" +#include "tinsel/tinsel.h" + +#include "common/endian.h" +#include "common/file.h" +#include "common/system.h" + +#include "sound/mixer.h" +#include "sound/audiocd.h" + +namespace Tinsel { + +//--------------------------- General data ---------------------------------- + +// get set when music/sample driver is installed +static bool bInstalled = false; + +SoundManager::SoundManager(TinselEngine *vm) : + //_vm(vm), // TODO: Enable this once global _vm var is gone + _sampleIndex(0), _sampleIndexLen(0) { +} + +SoundManager::~SoundManager() { + free(_sampleIndex); +} + +/** + * Plays the specified sample through the sound driver. + * @param id Identifier of sample to be played + * @param type type of sound (voice or sfx) + * @param handle sound handle + */ +bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle) { + // Floppy version has no sample file + if (_vm->getFeatures() & GF_FLOPPY) + return false; + + // no sample driver? + if (!_vm->_mixer->isReady()) + return false; + + // stop any currently playing sample + _vm->_mixer->stopHandle(_handle); + + // make sure id is in range + assert(id > 0 && id < _sampleIndexLen); + + // get file offset for this sample + uint32 dwSampleIndex = _sampleIndex[id]; + + // move to correct position in the sample file + _sampleStream.seek(dwSampleIndex); + if (_sampleStream.ioFailed() || _sampleStream.pos() != dwSampleIndex) + error("File %s is corrupt", SAMPLE_FILE); + + // read the length of the sample + uint32 sampleLen = _sampleStream.readUint32LE(); + if (_sampleStream.ioFailed()) + error("File %s is corrupt", SAMPLE_FILE); + + // allocate a buffer + void *sampleBuf = malloc(sampleLen); + assert(sampleBuf); + + // read all of the sample + if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen) + error("File %s is corrupt", SAMPLE_FILE); + + // FIXME: Should set this in a different place ;) + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound); + //_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volVoice); + + + // play it + _vm->_mixer->playRaw(type, &_handle, sampleBuf, sampleLen, 22050, + Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED); + + if (handle) + *handle = _handle; + + return true; +} + +/** + * Returns TRUE if there is a sample for the specified sample identifier. + * @param id Identifier of sample to be checked + */ +bool SoundManager::sampleExists(int id) { + if (_vm->_mixer->isReady()) { + // make sure id is in range + if (id > 0 && id < _sampleIndexLen) { + // check for a sample index + if (_sampleIndex[id]) + return true; + } + } + + // no sample driver or no sample + return false; +} + +/** + * Returns true if a sample is currently playing. + */ +bool SoundManager::sampleIsPlaying(void) { + return _vm->_mixer->isSoundHandleActive(_handle); +} + +/** + * Stops any currently playing sample. + */ +void SoundManager::stopAllSamples(void) { + // stop currently playing sample + _vm->_mixer->stopHandle(_handle); +} + +/** + * Opens and inits all sound sample files. + */ +void SoundManager::openSampleFiles(void) { + // Floppy and demo versions have no sample files + if (_vm->getFeatures() & GF_FLOPPY || _vm->getFeatures() & GF_DEMO) + return; + + Common::File f; + + if (_sampleIndex) + // already allocated + return; + + // open sample index file in binary mode + if (f.open(SAMPLE_INDEX)) { + // get length of index file + f.seek(0, SEEK_END); // move to end of file + _sampleIndexLen = f.pos(); // get file pointer + f.seek(0, SEEK_SET); // back to beginning + + if (_sampleIndex == NULL) { + // allocate a buffer for the indices + _sampleIndex = (uint32 *)malloc(_sampleIndexLen); + + // make sure memory allocated + if (_sampleIndex == NULL) { + // disable samples if cannot alloc buffer for indices + // TODO: Disabled sound if we can't load the sample index? + return; + } + } + + // load data + if (f.read(_sampleIndex, _sampleIndexLen) != (uint32)_sampleIndexLen) + // file must be corrupt if we get to here + error("File %s is corrupt", SAMPLE_FILE); + +#ifdef SCUMM_BIG_ENDIAN + // Convert all ids from LE to native format + for (uint i = 0; i < _sampleIndexLen / sizeof(uint32); ++i) { + _sampleIndex[i] = READ_LE_UINT32(_sampleIndex + i); + } +#endif + + // close the file + f.close(); + + // convert file size to size in DWORDs + _sampleIndexLen /= sizeof(uint32); + } else + error("Cannot find file %s", SAMPLE_INDEX); + + // open sample file in binary mode + if (!_sampleStream.open(SAMPLE_FILE)) + error("Cannot find file %s", SAMPLE_FILE); + +/* + // gen length of the largest sample + sampleBuffer.size = _sampleStream.readUint32LE(); + if (_sampleStream.ioFailed()) + error("File %s is corrupt", SAMPLE_FILE); +*/ +} + +/** + * Initialises the sound driver. + */ + +bool SoundInit(void) { + if (!bInstalled) { +// if (mDriver != NULL) { + if (true) { // TODO: Check that a MIDI music output device is available + // open MIDI files + OpenMidiFiles(); + } + + if (_vm->_mixer->isReady()) { + // open sample files + _vm->_sound->openSampleFiles(); + } + bInstalled = true; + return true; + } else { + // already installed + return false; + } +} + + +/** + * De-initialises the sound driver. + */ + +bool SoundDeinit(void) { + if (bInstalled) { + bInstalled = false; + AudioCD.stop(); + StopMidi(); + _vm->_sound->stopAllSamples(); + DeleteMidiBuffer(); + return true; + } else { + // not installed + return false; + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/sound.h b/engines/tinsel/sound.h new file mode 100644 index 0000000000..c80e7589ec --- /dev/null +++ b/engines/tinsel/sound.h @@ -0,0 +1,83 @@ +/* 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$ + * + * This file contains the Sound Driver data structures etc. + */ + +#ifndef TINSEL_SOUND_H +#define TINSEL_SOUND_H + +#include "common/file.h" +#include "common/file.h" + +#include "sound/mixer.h" + +#include "tinsel/dw.h" +#include "tinsel/tinsel.h" + +namespace Tinsel { + +#define MAXSAMPVOL 127 + +/*----------------------------------------------------------------------*\ +|* Function Prototypes *| +\*----------------------------------------------------------------------*/ + +class SoundManager { +protected: + + //TinselEngine *_vm; // TODO: Enable this once global _vm var is gone + + /** Sample handle */ + Audio::SoundHandle _handle; + + /** Sample index buffer and number of entries */ + uint32 *_sampleIndex; + + /** Number of entries in the sample index */ + long _sampleIndexLen; + + /** file stream for sample file */ + Common::File _sampleStream; + +public: + + SoundManager(TinselEngine *vm); + ~SoundManager(); + + bool playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle = 0); + void stopAllSamples(void); // Stops any currently playing sample + + bool sampleExists(int id); + bool sampleIsPlaying(void); + + // TODO: Internal method, make this protected? + void openSampleFiles(void); +}; + +bool SoundInit(void); // Initialises the sound driver +bool SoundDeinit(void); // De-initialises the sound driver + +} // end of namespace Tinsel + +#endif // TINSEL_SOUND_H diff --git a/engines/tinsel/strres.cpp b/engines/tinsel/strres.cpp new file mode 100644 index 0000000000..abf5a880f6 --- /dev/null +++ b/engines/tinsel/strres.cpp @@ -0,0 +1,209 @@ +/* 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$ + * + * String resource managment routines + */ + +#include "tinsel/dw.h" +#include "tinsel/sound.h" +#include "tinsel/strres.h" +#include "common/file.h" +#include "common/endian.h" + +namespace Tinsel { + +#ifdef DEBUG +// Diagnostic number +int newestString; +#endif + +// buffer for resource strings +static uint8 *textBuffer = 0; + +// language resource string filenames +static const char *languageFiles[] = { + "english.txt", + "french.txt", + "german.txt", + "italian.txt", + "spanish.txt" +}; + +// Set if we're handling 2-byte characters. +bool bMultiByte = false; + +/** + * Called to load a resource file for a different language + * @param newLang The new language + */ +void ChangeLanguage(LANGUAGE newLang) { + Common::File f; + uint32 textLen = 0; // length of buffer + + if (textBuffer) { + // free the previous buffer + free(textBuffer); + textBuffer = NULL; + } + + // Try and open the specified language file. If it fails, and the language + // isn't English, try falling back on opening 'english.txt' - some foreign + // language versions reused it rather than their proper filename + if (!f.open(languageFiles[newLang])) { + if ((newLang == TXT_ENGLISH) || !f.open(languageFiles[TXT_ENGLISH])) + error("Cannot find file %s", languageFiles[newLang]); + } + + // Check whether the file is compressed or not - for compressed files the + // first long is the filelength and for uncompressed files it is the chunk + // identifier + textLen = f.readUint32LE(); + if (f.ioFailed()) + error("File %s is corrupt", languageFiles[newLang]); + + if (textLen == CHUNK_STRING || textLen == CHUNK_MBSTRING) { + // the file is uncompressed + + bMultiByte = (textLen == CHUNK_MBSTRING); + + // get length of uncompressed file + textLen = f.size(); + f.seek(0, SEEK_SET); // Set to beginning of file + + if (textBuffer == NULL) { + // allocate a text buffer for the strings + textBuffer = (uint8 *)malloc(textLen); + + // make sure memory allocated + assert(textBuffer); + } + + // load data + if (f.read(textBuffer, textLen) != textLen) + // file must be corrupt if we get to here + error("File %s is corrupt", languageFiles[newLang]); + + // close the file + f.close(); + } else { // the file must be compressed + error("Compression handling has been removed!"); + } +} + +/** + * Loads a string resource identified by id. + * @param id identifier of string to be loaded + * @param pBuffer points to buffer that receives the string + * @param bufferMax maximum number of chars to be copied to the buffer + */ +int LoadStringRes(int id, char *pBuffer, int bufferMax) { +#ifdef DEBUG + // For diagnostics + newestString = id; +#endif + + // base of string resource table + uint8 *pText = textBuffer; + + // index into text resource file + uint32 index = 0; + + // number of chunks to skip + int chunkSkip = id / STRINGS_PER_CHUNK; + + // number of strings to skip when in the correct chunk + int strSkip = id % STRINGS_PER_CHUNK; + + // length of string + int len; + + // skip to the correct chunk + while (chunkSkip-- != 0) { + // make sure chunk id is correct + assert(READ_LE_UINT32(pText + index) == CHUNK_STRING || READ_LE_UINT32(pText + index) == CHUNK_MBSTRING); + + if (READ_LE_UINT32(pText + index + sizeof(uint32)) == 0) { + // TEMPORARY DIRTY BODGE + strcpy(pBuffer, "!! HIGH STRING !!"); + + // string does not exist + return 0; + } + + // get index to next chunk + index = READ_LE_UINT32(pText + index + sizeof(uint32)); + } + + // skip over chunk id and offset + index += (2 * sizeof(uint32)); + + // pointer to strings + pText = pText + index; + + // skip to the correct string + while (strSkip-- != 0) { + // skip to next string + pText += *pText + 1; + } + + // get length of string + len = *pText; + + if (len) { + // the string exists + + // copy the string to the buffer + if (len < bufferMax) { + memcpy(pBuffer, pText + 1, len); + + // null terminate + pBuffer[len] = 0; + + // number of chars copied + return len + 1; + } else { + memcpy(pBuffer, pText + 1, bufferMax - 1); + + // null terminate + pBuffer[bufferMax - 1] = 0; + + // number of chars copied + return bufferMax; + } + } + + // TEMPORARY DIRTY BODGE + strcpy(pBuffer, "!! NULL STRING !!"); + + // string does not exist + return 0; +} + +void FreeTextBuffer() { + if (textBuffer) { + free(textBuffer); + textBuffer = NULL; + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/strres.h b/engines/tinsel/strres.h new file mode 100644 index 0000000000..fac287492b --- /dev/null +++ b/engines/tinsel/strres.h @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + * String resource managment routines + */ + +#ifndef TINSEL_STRRES_H +#define TINSEL_STRRES_H + +#include "common/scummsys.h" +#include "tinsel/scn.h" + +namespace Tinsel { + +#define STRINGS_PER_CHUNK 64 // number of strings per chunk in the language text files +#define FIRST_STR_ID 1 // id number of first string in string table +#define MAX_STRING_SIZE 255 // maximum size of a string in the resource table +#define MAX_STRRES_SIZE 300000 // maximum size of string resource file + +// Set if we're handling 2-byte characters. +extern bool bMultiByte; + +/*----------------------------------------------------------------------*\ +|* Function Prototypes *| +\*----------------------------------------------------------------------*/ + +/** + * Called to load a resource file for a different language + * @param newLang The new language + */ +void ChangeLanguage(LANGUAGE newLang); + +/** + * Loads a string resource identified by id. + * @param id identifier of string to be loaded + * @param pBuffer points to buffer that receives the string + * @param bufferMax maximum number of chars to be copied to the buffer + */ +int LoadStringRes(int id, char *pBuffer, int bufferMax); + +/** + * Frees the text buffer allocated from ChangeLanguage() + */ +void FreeTextBuffer(); + +} // end of namespace Tinsel + +#endif + diff --git a/engines/tinsel/text.cpp b/engines/tinsel/text.cpp new file mode 100644 index 0000000000..dab97f7fdf --- /dev/null +++ b/engines/tinsel/text.cpp @@ -0,0 +1,279 @@ +/* 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$ + * + * Text utilities. + */ + +#include "tinsel/dw.h" +#include "tinsel/graphics.h" // object plotting +#include "tinsel/handle.h" +#include "tinsel/sched.h" // process scheduler defines +#include "tinsel/strres.h" // bMultiByte +#include "tinsel/text.h" // text defines + +namespace Tinsel { + +/** + * Returns the length of one line of a string in pixels. + * @param szStr String + * @param pFont Which font to use for dimensions + */ +int StringLengthPix(char *szStr, const FONT *pFont) { + int strLen; // accumulated length of string + byte c; + SCNHANDLE hImg; + + // while not end of string or end of line + for (strLen = 0; (c = *szStr) != EOS_CHAR && c != LF_CHAR; szStr++) { + if (bMultiByte) { + if (c & 0x80) + c = ((c & ~0x80) << 8) + *++szStr; + } + hImg = FROM_LE_32(pFont->fontDef[c]); + + if (hImg) { + // there is a IMAGE for this character + const IMAGE *pChar = (const IMAGE *)LockMem(hImg); + + // add width of font bitmap + strLen += FROM_LE_16(pChar->imgWidth); + } else + // use width of space character + strLen += FROM_LE_32(pFont->spaceSize); + + // finally add the inter-character spacing + strLen += FROM_LE_32(pFont->xSpacing); + } + + // return length of line in pixels - minus inter-char spacing for last character + strLen -= FROM_LE_32(pFont->xSpacing); + return (strLen > 0) ? strLen : 0; +} + +/** + * Returns the justified x start position of a line of text. + * @param szStr String to output + * @param xPos X position of string + * @param pFont Which font to use + * @param mode Mode flags for the string + */ +int JustifyText(char *szStr, int xPos, const FONT *pFont, int mode) { + if (mode & TXT_CENTRE) { + // centre justify the text + + // adjust x positioning by half the length of line in pixels + xPos -= StringLengthPix(szStr, pFont) / 2; + } else if (mode & TXT_RIGHT) { + // right justify the text + + // adjust x positioning by length of line in pixels + xPos -= StringLengthPix(szStr, pFont); + } + + // return text line x start position + return xPos; +} + +/** + * Main text outputting routine. If a object list is specified a + * multi-object is created for the whole text and a pointer to the head + * of the list is returned. + * @param pList Object list to add text to + * @param szStr String to output + * @param colour Colour for monochrome text + * @param xPos X position of string + * @param yPos Y position of string + * @param hFont Which font to use + * @param mode Mode flags for the string + */ +OBJECT *ObjectTextOut(OBJECT *pList, char *szStr, int colour, int xPos, int yPos, + SCNHANDLE hFont, int mode) { + int xJustify; // x position of text after justification + int yOffset; // offset to next line of text + OBJECT *pFirst; // head of multi-object text list + OBJECT *pChar = 0; // object ptr for the character + byte c; + SCNHANDLE hImg; + const IMAGE *pImg; + + // make sure there is a linked list to add text to + assert(pList); + + // get font pointer + const FONT *pFont = (const FONT *)LockMem(hFont); + + // init head of text list + pFirst = NULL; + + // get image for capital W + assert(pFont->fontDef[(int)'W']); + pImg = (const IMAGE *)LockMem(FROM_LE_32(pFont->fontDef[(int)'W'])); + + // get height of capital W for offset to next line + yOffset = FROM_LE_16(pImg->imgHeight); + + while (*szStr) { + // x justify the text according to the mode flags + xJustify = JustifyText(szStr, xPos, pFont, mode); + + // repeat until end of string or end of line + while ((c = *szStr) != EOS_CHAR && c != LF_CHAR) { + if (bMultiByte) { + if (c & 0x80) + c = ((c & ~0x80) << 8) + *++szStr; + } + hImg = FROM_LE_32(pFont->fontDef[c]); + + if (hImg == 0) { + // no image for this character + + // add font spacing for a space character + xJustify += FROM_LE_32(pFont->spaceSize); + } else { // printable character + + int aniX, aniY; // char image animation offsets + + OBJ_INIT oi; + oi.hObjImg = FROM_LE_32(pFont->fontInit.hObjImg); + oi.objFlags = FROM_LE_32(pFont->fontInit.objFlags); + oi.objID = FROM_LE_32(pFont->fontInit.objID); + oi.objX = FROM_LE_32(pFont->fontInit.objX); + oi.objY = FROM_LE_32(pFont->fontInit.objY); + oi.objZ = FROM_LE_32(pFont->fontInit.objZ); + + // allocate and init a character object + if (pFirst == NULL) + // first time - init head of list + pFirst = pChar = InitObject(&oi); // FIXME: endian issue using fontInit!!! + else + // chain to multi-char list + pChar = pChar->pSlave = InitObject(&oi); // FIXME: endian issue using fontInit!!! + + // convert image handle to pointer + pImg = (const IMAGE *)LockMem(hImg); + + // fill in character object + pChar->hImg = hImg; // image def + pChar->width = FROM_LE_16(pImg->imgWidth); // width of chars bitmap + pChar->height = FROM_LE_16(pImg->imgHeight); // height of chars bitmap + pChar->hBits = FROM_LE_32(pImg->hImgBits); // bitmap + + // check for absolute positioning + if (mode & TXT_ABSOLUTE) + pChar->flags |= DMA_ABS; + + // set characters colour - only effective for mono fonts + pChar->constant = colour; + + // get Y animation offset + GetAniOffset(hImg, pChar->flags, &aniX, &aniY); + + // set x position - ignore animation point + pChar->xPos = intToFrac(xJustify); + + // set y position - adjust for animation point + pChar->yPos = intToFrac(yPos - aniY); + + if (mode & TXT_SHADOW) { + // we want to shadow the character + OBJECT *pShad; + + // allocate a object for the shadow and chain to multi-char list + pShad = pChar->pSlave = AllocObject(); + + // copy the character for a shadow + CopyObject(pShad, pChar); + + // add shadow offsets to characters position + pShad->xPos += intToFrac(FROM_LE_32(pFont->xShadow)); + pShad->yPos += intToFrac(FROM_LE_32(pFont->yShadow)); + + // shadow is behind the character + pShad->zPos--; + + // shadow is always mono + pShad->flags = DMA_CNZ | DMA_CHANGED; + + // check for absolute positioning + if (mode & TXT_ABSOLUTE) + pShad->flags |= DMA_ABS; + + // shadow always uses first palette entry + // should really alloc a palette here also ???? + pShad->constant = 1; + + // add shadow to object list + InsertObject(pList, pShad); + } + + // add character to object list + InsertObject(pList, pChar); + + // move to end of list + if (pChar->pSlave) + pChar = pChar->pSlave; + + // add character spacing + xJustify += FROM_LE_16(pImg->imgWidth); + } + + // finally add the inter-character spacing + xJustify += FROM_LE_32(pFont->xSpacing); + + // next character in string + ++szStr; + } + + // adjust the text y position and add the inter-line spacing + yPos += yOffset + FROM_LE_32(pFont->ySpacing); + + // check for newline + if (c == LF_CHAR) + // next character in string + ++szStr; + } + + // return head of list + return pFirst; +} + +/** + * Is there an image for this character in this font? + * @param hFont which font to use + * @param c character to test + */ +bool IsCharImage(SCNHANDLE hFont, char c) { + byte c2 = (byte)c; + + // Inventory save game name editor needs to be more clever for + // multi-byte characters. This bodge will stop it erring. + if (bMultiByte && (c2 & 0x80)) + return false; + + // get font pointer + const FONT *pFont = (const FONT *)LockMem(hFont); + + return pFont->fontDef[c2] != 0; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/text.h b/engines/tinsel/text.h new file mode 100644 index 0000000000..78998831a1 --- /dev/null +++ b/engines/tinsel/text.h @@ -0,0 +1,101 @@ +/* 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$ + * + * Text utility defines + */ + +#ifndef TINSEL_TEXT_H // prevent multiple includes +#define TINSEL_TEXT_H + +#include "tinsel/object.h" // object manager defines + +namespace Tinsel { + +/** text mode flags - defaults to left justify */ +enum { + TXT_CENTRE = 0x0001, //!< centre justify text + TXT_RIGHT = 0x0002, //!< right justify text + TXT_SHADOW = 0x0004, //!< shadow each character + TXT_ABSOLUTE = 0x0008 //!< position of text is absolute (only for object text) +}; + +/** maximum number of characters in a font */ +#define MAX_FONT_CHARS 256 + + +#include "common/pack-start.h" // START STRUCT PACKING + +/** + * Text font data structure. + * @note only the pointer is used so the size of fontDef[] is not important. + * It is currently set at 300 because it suited me for debugging. + */ +struct FONT { + int xSpacing; //!< x spacing between characters + int ySpacing; //!< y spacing between characters + int xShadow; //!< x shadow offset + int yShadow; //!< y shadow offset + int spaceSize; //!< x spacing to use for a space character + OBJ_INIT fontInit; //!< structure used to init text objects + SCNHANDLE fontDef[300]; //!< image handle array for all characters in the font +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + + +/** structure for passing the correct parameters to ObjectTextOut */ +struct TEXTOUT { + OBJECT *pList; //!< object list to add text to + char *szStr; //!< string to output + int colour; //!< colour for monochrome text + int xPos; //!< x position of string + int yPos; //!< y position of string + SCNHANDLE hFont; //!< which font to use + int mode; //!< mode flags for the string + int sleepTime; //!< sleep time between each character (if non-zero) +}; + + +/*----------------------------------------------------------------------*\ +|* Text Function Prototypes *| +\*----------------------------------------------------------------------*/ + +OBJECT *ObjectTextOut( // output a string of text + OBJECT *pList, // object list to add text to + char *szStr, // string to output + int colour, // colour for monochrome text + int xPos, // x position of string + int yPos, // y position of string + SCNHANDLE hFont, // which font to use + int mode); // mode flags for the string + +OBJECT *ObjectTextOutIndirect( // output a string of text + TEXTOUT *pText); // pointer to TextOut struct with all parameters + +bool IsCharImage( // Is there an image for this character in this font? + SCNHANDLE hFont, // which font to use + char c); // character to test + +} // end of namespace Tinsel + +#endif // TINSEL_TEXT_H diff --git a/engines/tinsel/timers.cpp b/engines/tinsel/timers.cpp new file mode 100644 index 0000000000..c7b9d3708b --- /dev/null +++ b/engines/tinsel/timers.cpp @@ -0,0 +1,192 @@ +/* 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$ + * + * Handles timers. + * + * Note: As part of the transition to ScummVM, the ticks field of a timer has been changed + * to a millisecond value, rather than ticks at 24Hz. Most places should be able to use + * the timers without change, since the ONE_SECOND constant has been set to be in MILLISECONDS + */ + +#include "tinsel/timers.h" +#include "tinsel/dw.h" +#include "tinsel/serializer.h" + +#include "common/system.h" + +namespace Tinsel { + +//----------------- LOCAL DEFINES -------------------- + +#define MAX_TIMERS 16 + +struct TIMER { + int tno; /**< Timer number */ + int ticks; /**< Tick count */ + int secs; /**< Second count */ + int delta; /**< Increment/decrement value */ + bool frame; /**< If set, in ticks, otherwise in seconds */ +}; + + + +//----------------- LOCAL GLOBAL DATA -------------------- + +static TIMER timers[MAX_TIMERS]; + + +//-------------------------------------------------------- + +/** + * Gets the current time in number of ticks. + * + * DOS timer ticks is the number of 54.9254ms since midnight. Converting the + * millisecond count won't give the exact same 'since midnight' count, but I + * figure that as long as the timing interval is more or less accurate, it + * shouldn't be a problem. + */ + +uint32 DwGetCurrentTime() { + return g_system->getMillis() * 55 / 1000; +} + +/** + * Resets all of the timer slots + */ + +void RebootTimers(void) { + memset(timers, 0, sizeof(timers)); +} + +/** + * (Un)serialize the timer data for save/restore game. + */ +void syncTimerInfo(Serializer &s) { + for (int i = 0; i < MAX_TIMERS; i++) { + s.syncAsSint32LE(timers[i].tno); + s.syncAsSint32LE(timers[i].ticks); + s.syncAsSint32LE(timers[i].secs); + s.syncAsSint32LE(timers[i].delta); + s.syncAsSint32LE(timers[i].frame); + } +} + +/** + * Find the timer numbered thus, if one is thus numbered. + * @param num number of the timer + * @return the timer with the specified number, or NULL if there is none + */ +static TIMER *findTimer(int num) { + for (int i = 0; i < MAX_TIMERS; i++) { + if (timers[i].tno == num) + return &timers[i]; + } + return NULL; +} + +/** + * Find an empty timer slot. + */ +static TIMER *allocateTimer(int num) { + assert(num); // zero is not allowed as a timer number + assert(!findTimer(num)); // Allocating already existant timer + + for (int i = 0; i < MAX_TIMERS; i++) { + if (!timers[i].tno) { + timers[i].tno = num; + return &timers[i]; + } + } + + error("Too many timers"); +} + +/** + * Update all timers, as appropriate. + */ +void FettleTimers(void) { + for (int i = 0; i < MAX_TIMERS; i++) { + if (!timers[i].tno) + continue; + + timers[i].ticks += timers[i].delta; // Update tick value + + if (timers[i].frame) { + if (timers[i].ticks < 0) + timers[i].ticks = 0; // Have reached zero + } else { + if (timers[i].ticks < 0) { + timers[i].ticks = ONE_SECOND; + timers[i].secs--; + if (timers[i].secs < 0) + timers[i].secs = 0; // Have reached zero + } else if (timers[i].ticks == ONE_SECOND) { + timers[i].ticks = 0; + timers[i].secs++; // Another second has passed + } + } + } +} + +/** + * Start a timer up. + */ +void DwSetTimer(int num, int sval, bool up, bool frame) { + TIMER *pt; + + assert(num); // zero is not allowed as a timer number + + pt = findTimer(num); + if (pt == NULL) + pt = allocateTimer(num); + + pt->delta = up ? 1 : -1; // Increment/decrement value + pt->frame = frame; + + if (frame) { + pt->secs = 0; + pt->ticks = sval; + } else { + pt->secs = sval; + pt->ticks = 0; + } +} + +/** + * Return the current count of a timer. + */ +int Timer(int num) { + TIMER *pt; + + pt = findTimer(num); + + if (pt == NULL) + return -1; + + if (pt->frame) + return pt->ticks; + else + return pt->secs; +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/timers.h b/engines/tinsel/timers.h new file mode 100644 index 0000000000..75eb87ee2b --- /dev/null +++ b/engines/tinsel/timers.h @@ -0,0 +1,53 @@ +/* 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$ + * + * Handles timers. + */ + +#ifndef TINSEL_TIMERS_H // prevent multiple includes +#define TINSEL_TIMERS_H + +#include "common/scummsys.h" +#include "tinsel/dw.h" + +namespace Tinsel { + +class Serializer; + +#define ONE_SECOND 24 + +uint32 DwGetCurrentTime(void); + +void RebootTimers(void); + +void syncTimerInfo(Serializer &s); + +void FettleTimers(void); + +void DwSetTimer(int num, int sval, bool up, bool frame); + +int Timer(int num); + +} // end of namespace Tinsel + +#endif diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp new file mode 100644 index 0000000000..a07a16a205 --- /dev/null +++ b/engines/tinsel/tinlib.cpp @@ -0,0 +1,2980 @@ +/* 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$ + * + * Glitter library functions. + * + * In the main called only from PCODE.C + * Function names are the same as Glitter code function names. + * + * To ensure exclusive use of resources and exclusive control responsibilities. + */ + +#define BODGE + +#include "tinsel/actors.h" +#include "tinsel/background.h" +#include "tinsel/config.h" +#include "tinsel/coroutine.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/film.h" +#include "tinsel/font.h" +#include "tinsel/graphics.h" +#include "tinsel/handle.h" +#include "tinsel/inventory.h" +#include "tinsel/move.h" +#include "tinsel/multiobj.h" +#include "tinsel/music.h" +#include "tinsel/object.h" +#include "tinsel/palette.h" +#include "tinsel/pcode.h" +#include "tinsel/pid.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/savescn.h" +#include "tinsel/sched.h" +#include "tinsel/scn.h" +#include "tinsel/scroll.h" +#include "tinsel/sound.h" +#include "tinsel/strres.h" +#include "tinsel/text.h" +#include "tinsel/timers.h" // For ONE_SECOND constant +#include "tinsel/tinlib.h" +#include "tinsel/tinsel.h" +#include "tinsel/token.h" + + +namespace Tinsel { + +//----------------- EXTERNAL GLOBAL DATA -------------------- + +// In DOS_DW.C +extern bool bRestart; // restart flag - set to restart the game +extern bool bHasRestarted; // Set after a restart + +// In DOS_MAIN.C +// TODO/FIXME: From dos_main.c: "Only used on PSX so far" +int clRunMode = 0; + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in BG.C +extern void startupBackground(SCNHANDLE bfilm); +extern void ChangePalette(SCNHANDLE hPal); +extern int BackgroundWidth(void); +extern int BackgroundHeight(void); + +// in DOS_DW.C +extern void SetHookScene(SCNHANDLE scene, int entrance, int transition); +extern void SetNewScene(SCNHANDLE scene, int entrance, int transition); +extern void UnHookScene(void); +extern void SuspendHook(void); +extern void UnSuspendHook(void); + +// in PDISPLAY.C +extern void EnableTags(void); +extern void DisableTags(void); +bool DisableTagsIfEnabled(void); +extern void setshowstring(void); + +// in PLAY.C +extern void playFilm(SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, bool escOn, int myescEvent, bool bTop); +extern void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, bool escOn, int myescEvent, bool bTop); + +// in SCENE.C +extern void setshowpos(void); + +#ifdef BODGE +// In DOS_HAND.C +bool ValidHandle(SCNHANDLE offset); + +// In SCENE.C +SCNHANDLE GetSceneHandle(void); +#endif + +//----------------- GLOBAL GLOBAL DATA -------------------- + +bool bEnableF1; + + +//----------------- LOCAL DEFINES -------------------- + +#define JAP_TEXT_TIME (2*ONE_SECOND) + +/*----------------------------------------------------------------------*\ +|* Library Procedure and Function codes *| +\*----------------------------------------------------------------------*/ + +enum LIB_CODE { + ACTORATTR = 0, ACTORDIRECTION, ACTORREF, ACTORSCALE, ACTORXPOS = 4, + ACTORYPOS, ADDICON, ADDINV1, ADDINV2, ADDOPENINV, AUXSCALE = 10, + BACKGROUND, CAMERA, CLOSEINVENTORY, CONTROL, CONVERSATION = 15, + CONVICON, CURSORXPOS, CURSORYPOS, DEC_CONVW, DEC_CURSOR = 20, + DEC_INV1, DEC_INV2, DEC_INVW, DEC_LEAD, DEC_TAGFONT = 25, + DEC_TALKFONT, DELICON, DELINV, EFFECTACTOR, ESCAPE, EVENT = 31, + GETINVLIMIT, HELDOBJECT, HIDE, ININVENTORY, INVDEPICT = 36, + INVENTORY, KILLACTOR, KILLBLOCK, KILLEXIT, KILLTAG, LEFTOFFSET = 42, + MOVECURSOR, NEWSCENE, NOSCROLL, OBJECTHELD, OFFSET, PAUSE = 48, + PLAY, PLAYMIDI, PLAYSAMPLE, PREPARESCENE, PRINT, PRINTOBJ = 54, + PRINTTAG, RANDOM, RESTORE_SCENE, SAVE_SCENE, SCALINGREELS = 59, + SCANICON, SCROLL, SETACTOR, SETBLOCK, SETEXIT, SETINVLIMIT = 65, + SETPALETTE, SETTAG, SETTIMER, SHOWPOS, SHOWSTRING, SPLAY = 71, + STAND, STANDTAG, STOP, SWALK, TAGACTOR, TALK, TALKATTR, TIMER = 79, + TOPOFFSET, TOPPLAY, TOPWINDOW, UNTAGACTOR, VIBRATE, WAITKEY = 85, + WAITTIME, WALK, WALKED, WALKINGACTOR, WALKPOLY, WALKTAG = 91, + WHICHINVENTORY = 92, + ACTORSON, CUTSCENE, HOOKSCENE, IDLETIME, RESETIDLETIME = 97, + TALKAT, UNHOOKSCENE, WAITFRAME, DEC_CSTRINGS, STOPMIDI, STOPSAMPLE = 103, + TALKATS = 104, + DEC_FLAGS, FADEMIDI, CLEARHOOKSCENE, SETINVSIZE, INWHICHINV = 109, + NOBLOCKING, SAMPLEPLAYING, TRYPLAYSAMPLE, ENABLEF1 = 113, + RESTARTGAME, QUITGAME, FRAMEGRAB, PLAYRTF, CDPLAY, CDLOAD = 119, + HASRESTARTED, RESTORE_CUT, RUNMODE, SUBTITLES, SETLANGUAGE = 124 +}; + + + +//----------------- LOCAL GLOBAL DATA -------------------- + +// Saved cursor co-ordinates for control(on) to restore cursor position +// as it was at control(off). +// They are global so that movecursor(..) has a net effect if it +// precedes control(on). +static int controlX = 0, controlY = 0; + +static int offtype = 0; // used by control() +static uint32 lastValue = 0; // used by dw_random() +static int scrollCount = 0; // used by scroll() + +static bool NotPointedRunning = false; // Used in printobj and printobjPointed + +static COLORREF s_talkfontColor = 0; + +//----------------- FORWARD REFERENCES -------------------- + +void resetidletime(void); +void stopmidi(void); +void stopsample(void); +void walk(CORO_PARAM, int actor, int x, int y, SCNHANDLE film, int hold, bool igPath, bool escOn, int myescTime); + + +/** + * NOT A LIBRARY FUNCTION + * + * Poke supplied colours into the DAC queue. + */ +static void setTextPal(COLORREF col) { + s_talkfontColor = col; + UpdateDACqueue(TALKFONT_COL, 1, &s_talkfontColor); +} + + +static int TextTime(char *pTstring) { + if (isJapanMode()) + return JAP_TEXT_TIME; + else if (!speedText) + return strlen(pTstring) + ONE_SECOND; + else + return strlen(pTstring) + ONE_SECOND + (speedText * 5 * ONE_SECOND) / 100; +} + +/*--------------------------------------------------------------------------*/ + + +/** + * Set actor's attributes. + * - currently only the text colour. + */ +void actorattr(int actor, int r1, int g1, int b1) { + storeActorAttr(actor, r1, g1, b1); +} + +/** + * Return the actor's direction. + */ +int actordirection(int actor) { + PMACTOR pActor; + + pActor = GetMover(actor); + assert(pActor != NULL); // not a moving actor + + return (int)GetMActorDirection(pActor); +} + +/** + * Return the actor's scale. + */ +int actorscale(int actor) { + PMACTOR pActor; + + pActor = GetMover(actor); + assert(pActor != NULL); // not a moving actor + + return (int)GetMActorScale(pActor); +} + +/** + * Returns the x or y position of an actor. + */ +int actorpos(int xory, int actor) { + int x, y; + + GetActorPos(actor, &x, &y); + return (xory == ACTORXPOS) ? x : y; +} + +/** + * Make all actors alive at the start of each scene. + */ +void actorson(void) { + setactorson(); +} + +/** + * Adds an icon to the conversation window. + */ +void addicon(int icon) { + AddToInventory(INV_CONV, icon, false); +} + +/** + * Place the object in inventory 1 or 2. + */ +void addinv(int invno, int object) { + assert(invno == INV_1 || invno == INV_2 || invno == INV_OPEN); // illegal inventory number + + AddToInventory(invno, object, false); +} + +/** + * Define an actor's walk and stand reels for an auxilliary scale. + */ +void auxscale(int actor, int scale, SCNHANDLE *rp) { + PMACTOR pActor; + + pActor = GetMover(actor); + assert(pActor); // Can't set aux scale for a non-moving actor + + int j; + for (j = 0; j < 4; ++j) + pActor->WalkReels[scale-1][j] = *rp++; + for (j = 0; j < 4; ++j) + pActor->StandReels[scale-1][j] = *rp++; + for (j = 0; j < 4; ++j) + pActor->TalkReels[scale-1][j] = *rp++; +} + +/** + * Defines the background image for a scene. + */ +void background(SCNHANDLE bfilm) { + startupBackground(bfilm); +} + +/** + * Sets focus of the scroll process. + */ +void camera(int actor) { + ScrollFocus(actor); +} + +/** + * A CDPLAY() is imminent. + */ +void cdload(SCNHANDLE start, SCNHANDLE next) { + assert(start && next && start != next); // cdload() fault + +// TODO/FIXME +// LoadExtraGraphData(start, next); +} + +/** + * Clear the hooked scene (if any) + */ + +void clearhookscene() { + SetHookScene(0, 0, 0); +} + +/** + * Guess what. + */ + +void closeinventory(void) { + KillInventory(); +} + +/** + * Turn off cursor and take control from player - and variations on the theme. + * OR Restore cursor and return control to the player. + */ + +void control(int param) { + bEnableF1 = false; + + switch (param) { + case CONTROL_STARTOFF: + GetControlToken(); // Take control + DisableTags(); // Switch off tags + DwHideCursor(); // Blank out cursor + offtype = param; + break; + + case CONTROL_OFF: + case CONTROL_OFFV: + case CONTROL_OFFV2: + if (TestToken(TOKEN_CONTROL)) { + GetControlToken(); // Take control + + DisableTags(); // Switch off tags + GetCursorXYNoWait(&controlX, &controlY, true); // Store cursor position + + // There may be a button timing out + GetToken(TOKEN_LEFT_BUT); + FreeToken(TOKEN_LEFT_BUT); + } + + if (offtype == CONTROL_STARTOFF) + GetCursorXYNoWait(&controlX, &controlY, true); // Store cursor position + + offtype = param; + + if (param == CONTROL_OFF) + DwHideCursor(); // Blank out cursor + else if (param == CONTROL_OFFV) { + UnHideCursor(); + FreezeCursor(); + } else if (param == CONTROL_OFFV2) { + UnHideCursor(); + } + break; + + case CONTROL_ON: + if (offtype != CONTROL_OFFV2 && offtype != CONTROL_STARTOFF) + SetCursorXY(controlX, controlY);// ... where it was + + FreeControlToken(); // Release control + + if (!InventoryActive()) + EnableTags(); // Tags back on + + RestoreMainCursor(); // Re-instate cursor... + } +} + +/** + * Open or close the conversation window. + */ + +void conversation(int fn, HPOLYGON hp, bool escOn, int myescEvent) { + assert(hp != NOPOLY); // conversation() must (currently) be called from a polygon code block + + switch (fn) { + case CONV_END: // Close down conversation + CloseDownConv(); + break; + + case CONV_DEF: // Default (i.e. TOP of screen) + case CONV_BOTTOM: // BOTTOM of screen + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + break; + + if (IsConvWindow()) + break; + + KillInventory(); + convPos(fn); + ConvPoly(hp); + PopUpInventory(INV_CONV); // Conversation window + ConvAction(INV_OPENICON); // CONVERSATION event + break; + } +} + +/** + * Add icon to conversation window's permanent default list. + */ + +void convicon(int icon) { + AddIconToPermanentDefaultList(icon); +} + +/** + * Returns the x or y position of the cursor. + */ + +int cursorpos(int xory) { + int x, y; + + GetCursorXY(&x, &y, true); + return (xory == CURSORXPOS) ? x : y; +} + +/** + * Declare conversation window. + */ + +void dec_convw(SCNHANDLE text, int MaxContents, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight) { + idec_convw(text, MaxContents, MinWidth, MinHeight, + StartWidth, StartHeight, MaxWidth, MaxHeight); +} + +/** + * Declare config strings. + */ + +void dec_cstrings(SCNHANDLE *tp) { + setConfigStrings(tp); +} + +/** + * Declare cursor's reels. + */ + +void dec_cursor(SCNHANDLE bfilm) { + DwInitCursor(bfilm); +} + +/** + * Declare the language flags. + */ + +void dec_flags(SCNHANDLE hf) { + setFlagFilms(hf); +} + +/** + * Declare inventory 1's parameters. + */ + +void dec_inv1(SCNHANDLE text, int MaxContents, + int MinWidth, int MinHeight, + int StartWidth, int StartHeight, + int MaxWidth, int MaxHeight) { + idec_inv1(text, MaxContents, MinWidth, MinHeight, + StartWidth, StartHeight, MaxWidth, MaxHeight); +} + +/** + * Declare inventory 2's parameters. + */ + +void dec_inv2(SCNHANDLE text, int MaxContents, + int MinWidth, int MinHeight, + int StartWidth, int StartHeight, + int MaxWidth, int MaxHeight) { + idec_inv2(text, MaxContents, MinWidth, MinHeight, + StartWidth, StartHeight, MaxWidth, MaxHeight); +} + +/** + * Declare the bits that the inventory windows are constructed from. + */ + +void dec_invw(SCNHANDLE hf) { + setInvWinParts(hf); +} + +/** + * Declare lead actor. + * - the actor's id, walk and stand reels for all the regular scales, + * and the tag text. + */ + +void dec_lead(uint32 id, SCNHANDLE *rp, SCNHANDLE text) { + PMACTOR pActor; // Moving actor structure + + Tag_Actor(id, text, TAG_DEF); // The lead actor is automatically tagged + setleadid(id); // Establish this as the lead + SetMover(id); // Establish as a moving actor + + pActor = GetMover(id); // Get moving actor structure + assert(pActor); + + // Store all those reels + int i, j; + for (i = 0; i < 5; ++i) { + for (j = 0; j < 4; ++j) + pActor->WalkReels[i][j] = *rp++; + for (j = 0; j < 4; ++j) + pActor->StandReels[i][j] = *rp++; + for (j = 0; j < 4; ++j) + pActor->TalkReels[i][j] = *rp++; + } + + + for (i = NUM_MAINSCALES; i < TOTAL_SCALES; i++) { + for (j = 0; j < 4; ++j) { + pActor->WalkReels[i][j] = pActor->WalkReels[4][j]; + pActor->StandReels[i][j] = pActor->StandReels[2][j]; + pActor->TalkReels[i][j] = pActor->TalkReels[4][j]; + } + } +} + +/** + * Declare the text font. + */ + +void dec_tagfont(SCNHANDLE hf) { + TagFontHandle(hf); // Store the font handle +} + +/** + * Declare the text font. + */ + +void dec_talkfont(SCNHANDLE hf) { + TalkFontHandle(hf); // Store the font handle +} + +/** + * Remove an icon from the conversation window. + */ + +void delicon(int icon) { + RemFromInventory(INV_CONV, icon); +} + +/** + * Delete the object from inventory 1 or 2. + */ + +void delinv(int object) { + if (!RemFromInventory(INV_1, object)) // Remove from inventory 1... + RemFromInventory(INV_2, object); // ...or 2 (whichever) + + DropItem(object); // Stop holding it +} + +/** + * enablef1 + */ + +void enablef1(void) { + bEnableF1 = true; +} + +/** + * fademidi(in/out) + */ + +void fademidi(CORO_PARAM, int inout) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + assert(inout == FM_IN || inout == FM_OUT); + + // To prevent compiler complaining + if (inout == FM_IN || inout == FM_OUT) + CORO_SLEEP(1); + CORO_END_CODE; +} + +/** + * Guess what. + */ + +int getinvlimit(int invno) { + return InvGetLimit(invno); +} + +/** + * Returns TRUE if the game has been restarted, FALSE if not. + */ +bool hasrestarted(void) { + return bHasRestarted; +} + +/** + * Returns which object is currently held. + */ + +int heldobject(void) { + return WhichItemHeld(); +} + +/** + * Removes a player from the screen, probably when he's about to be + * replaced by an animation. + * + * Not believed to work anymore! (hide() is not used). + */ + +void hide(int actor) { + HideActor(actor); +} + +/** + * hookscene(scene, entrance, transition) + */ + +void hookscene(SCNHANDLE scene, int entrance, int transition) { + SetHookScene(scene, entrance, transition); +} + +/** + * idletime + */ + +int idletime(void) { + uint32 x; + + x = getUserEventTime() / ONE_SECOND; + + if (!TestToken(TOKEN_CONTROL)) + resetidletime(); + + return (int)x; +} + +/** + * invdepict + */ +void invdepict(int object, SCNHANDLE hFilm) { + invObjectFilm(object, hFilm); +} + +/** + * See if an object is in the inventory. + */ +int ininventory(int object) { + return (InventoryPos(object) != INV_NOICON); +} + +/** + * Open an inventory. + */ +void inventory(int invno, bool escOn, int myescEvent) { + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + assert((invno == INV_1 || invno == INV_2)); // Trying to open illegal inventory + + PopUpInventory(invno); +} + +/** + * See if an object is in the inventory. + */ +int inwhichinv(int object) { + if (WhichItemHeld() == object) + return 0; + + if (IsInInventory(object, INV_1)) + return 1; + + if (IsInInventory(object, INV_2)) + return 2; + + return -1; +} + +/** + * Kill an actor. + */ +void killactor(int actor) { + DisableActor(actor); +} + +/** + * Turn a blocking polygon off. + */ +void killblock(int block) { + DisableBlock(block); +} + +/** + * Turn an exit off. + */ +void killexit(int exit) { + DisableExit(exit); +} + +/** + * Turn a tag off. + */ +void killtag(int tagno) { + DisableTag(tagno); +} + +/** + * Returns the left or top offset of the screen. + */ +int ltoffset(int lort) { + int Loffset, Toffset; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + return (lort == LEFTOFFSET) ? Loffset : Toffset; +} + +/** + * Set new cursor position. + */ +void movecursor(int x, int y) { + SetCursorXY(x, y); + + controlX = x; // Save these values so that + controlY = y; // control(on) doesn't undo this +} + +/** + * Triggers change to a new scene. + */ +void newscene(CORO_PARAM, SCNHANDLE scene, int entrance, int transition) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + +#ifdef BODGE + if (!ValidHandle(scene)) { + scene = GetSceneHandle(); + entrance = 1; + } + assert(scene); // Non-existant first scene! +#endif + + SetNewScene(scene, entrance, transition); + +#if 1 + // Prevent tags and cursor re-appearing + GetControl(CONTROL_STARTOFF); +#endif + + // Prevent code subsequent to this call running before scene changes + if (ProcessGetPID(CurrentProcess()) != PID_MASTER_SCR) + CORO_KILL_SELF(); + CORO_END_CODE; +} + +/** + * Disable dynamic blocking for current scene. + */ +void noblocking(void) { + bNoBlocking = true; +} + +/** + * Define a no-scroll boundary for the current scene. + */ +void noscroll(int x1, int y1, int x2, int y2) { + SetNoScroll(x1, y1, x2, y2); +} + +/** + * Hold the specified object. + */ +void objectheld(int object) { + HoldItem(object); +} + +/** + * Set the top left offset of the screen. + */ +void offset(int x, int y) { + KillScroll(); + PlayfieldSetPos(FIELD_WORLD, x, y); +} + +/** + * Play a film. + */ +void play(CORO_PARAM, SCNHANDLE film, int x, int y, int compit, int actorid, bool splay, int sfact, + bool escOn, int myescEvent, bool bTop) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + assert(film != 0); // play(): Trying to play NULL film + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + // If this actor is dead, call a stop to the calling process + if (actorid && !actorAlive(actorid)) + CORO_KILL_SELF(); + + // 7/4/95 + if (!escOn) + myescEvent = GetEscEvents(); + + if (compit == 1) { + // Play to completion before returning + CORO_INVOKE_ARGS(playFilmc, (CORO_SUBCTX, film, x, y, actorid, splay, sfact, escOn, myescEvent, bTop)); + } else if (compit == 2) { + error("play(): compit == 2 - please advise John"); + } else { + // Kick off the play and return. + playFilm(film, x, y, actorid, splay, sfact, escOn, myescEvent, bTop); + } + CORO_END_CODE; +} + +/** + * Play a midi file. + */ +void playmidi(CORO_PARAM, SCNHANDLE hMidi, int loop, bool complete) { + // FIXME: This is a workaround for the FIXME below + if (GetMidiVolume() == 0) + return; + + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + assert(loop == MIDI_DEF || loop == MIDI_LOOP); + + PlayMidiSequence(hMidi, loop == MIDI_LOOP); + + // FIXME: The following check messes up the script arguments when + // entering the secret door in the bookshelf in the library, + // leading to a crash, when the music volume is set to 0 (MidiPlaying() + // always false then). + // + // Why exactly this happens is unclear. An analysis of the involved + // script(s) might reveal more. + // + // Note: This check&sleep was added in DW v2. It was most likely added + // to ensure that the MIDI song started playing before the next opcode + // is executed. + if (!MidiPlaying()) + CORO_SLEEP(1); + + if (complete) { + while (MidiPlaying()) + CORO_SLEEP(1); + } + CORO_END_CODE; +} + +/** + * Play a sample. + */ +void playsample(CORO_PARAM, int sample, bool complete, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + Audio::SoundHandle handle; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + // Don't play SFX if voice is already playing + if (_vm->_mixer->hasActiveChannelOfType(Audio::Mixer::kSpeechSoundType)) + return; + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) { + _vm->_sound->stopAllSamples(); // Stop any currently playing sample + return; + } + + if (volSound != 0 && _vm->_sound->sampleExists(sample)) { + _vm->_sound->playSample(sample, Audio::Mixer::kSFXSoundType, &_ctx->handle); + + if (complete) { + while (_vm->_mixer->isSoundHandleActive(_ctx->handle)) { + // Abort if escapable and ESCAPE is pressed + if (escOn && myescEvent != GetEscEvents()) { + _vm->_mixer->stopHandle(_ctx->handle); + break; + } + + CORO_SLEEP(1); + } + } + } else { + // Prevent Glitter lock-up + CORO_SLEEP(1); + } + CORO_END_CODE; +} + +/** + * Play a sample. + */ +void tryplaysample(CORO_PARAM, int sample, bool complete, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + // Don't do it if it's not appropriate + if (_vm->_sound->sampleIsPlaying()) { + // return, but prevent Glitter lock-up + CORO_SLEEP(1); + return; + } + + CORO_INVOKE_ARGS(playsample, (CORO_SUBCTX, sample, complete, escOn, myescEvent)); + CORO_END_CODE; +} + +/** + * Trigger pre-loading of a scene's data. + */ +void preparescene(SCNHANDLE scene) { +#ifdef BODGE + if (!ValidHandle(scene)) + return; +#endif +} + +/** + * Print the given text at the given place for the given time. + * + * Print(....., h) -> hold = 1 (not used) + * Print(....., s) -> hold = 2 (sustain) + */ +void print(CORO_PARAM, int x, int y, SCNHANDLE text, int time, int hold, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + OBJECT *pText; // text object pointer + int myleftEvent; + bool bSample; // Set if a sample is playing + Audio::SoundHandle handle; + int timeout; + int time; + CORO_END_CONTEXT(_ctx); + + bool bJapDoPrintText; // Bodge to get-around Japanese bodge + + CORO_BEGIN_CODE(_ctx); + + _ctx->pText = NULL; + _ctx->bSample = false; + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + // Kick off the voice sample + if (volVoice != 0 && _vm->_sound->sampleExists(text)) { + _vm->_sound->playSample(text, Audio::Mixer::kSpeechSoundType, &_ctx->handle); + _ctx->bSample = _vm->_mixer->isSoundHandleActive(_ctx->handle); + } + + // Calculate display time + LoadStringRes(text, tBufferAddr(), TBUFSZ); + bJapDoPrintText = false; + if (time == 0) { + // This is a 'talky' print + _ctx->time = TextTime(tBufferAddr()); + + // Cut short-able if sustain was not set + _ctx->myleftEvent = (hold == 2) ? 0 : GetLeftEvents(); + } else { + _ctx->time = time * ONE_SECOND; + _ctx->myleftEvent = 0; + if (isJapanMode()) + bJapDoPrintText = true; + } + + // Print the text + if (bJapDoPrintText || (!isJapanMode() && (bSubtitles || !_ctx->bSample))) { + int Loffset, Toffset; // Screen position + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), + 0, x - Loffset, y - Toffset, hTalkFontHandle(), TXT_CENTRE); + assert(_ctx->pText); // string produced NULL text + if (IsTopWindow()) + MultiSetZPosition(_ctx->pText, Z_TOPW_TEXT); + + /* + * New feature: Don't go off the side of the background + */ + int shift; + shift = MultiRightmost(_ctx->pText) + 2; + if (shift >= BackgroundWidth()) // Not off right + MultiMoveRelXY(_ctx->pText, BackgroundWidth() - shift, 0); + shift = MultiLeftmost(_ctx->pText) - 1; + if (shift <= 0) // Not off left + MultiMoveRelXY(_ctx->pText, -shift, 0); + shift = MultiLowest(_ctx->pText); + if (shift > BackgroundHeight()) // Not off bottom + MultiMoveRelXY(_ctx->pText, 0, BackgroundHeight() - shift); + } + + // Give up if nothing printed and no sample + if (_ctx->pText == NULL && !_ctx->bSample) + return; + + // Leave it up until time runs out or whatever + _ctx->timeout = SAMPLETIMEOUT; + do { + CORO_SLEEP(1); + + // Abort if escapable and ESCAPE is pressed + // Abort if left click - hardwired feature for talky-print! + // Will be ignored if myleftevent happens to be 0! + // Abort if sample times out + if ((escOn && myescEvent != GetEscEvents()) + || (_ctx->myleftEvent && _ctx->myleftEvent != GetLeftEvents()) + || (_ctx->bSample && --_ctx->timeout <= 0)) + break; + + if (_ctx->bSample) { + // Wait for sample to end whether or not + if (!_vm->_mixer->isSoundHandleActive(_ctx->handle)) { + if (_ctx->pText == NULL || speedText == DEFTEXTSPEED) { + // No text or speed modification - just depends on sample + break; + } else { + // Must wait for time + _ctx->bSample = false; + } + } + } else { + // No sample - just depends on time + if (_ctx->time-- <= 0) + break; + } + + } while (1); + + // Delete the text + if (_ctx->pText != NULL) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText); + _vm->_mixer->stopHandle(_ctx->handle); + + CORO_END_CODE; +} + + +static void printobjPointed(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, OBJECT *&pText, const int textx, const int texty, const int item); +static void printobjNonPointed(CORO_PARAM, const SCNHANDLE text, const OBJECT *pText); + +/** + * Print the given inventory object's name or whatever. + */ +void printobj(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, const int event) { + CORO_BEGIN_CONTEXT; + OBJECT *pText; // text object pointer + int textx, texty; + int item; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + assert(pinvo != 0); // printobj() may only be called from an object code block + + if (text == (SCNHANDLE)-1) { // 'OFF' + NotPointedRunning = true; + return; + } + if (text == (SCNHANDLE)-2) { // 'ON' + NotPointedRunning = false; + return; + } + + GetCursorXY(&_ctx->textx, &_ctx->texty, false); // Cursor position.. + _ctx->item = InvItem(&_ctx->textx, &_ctx->texty, true); // ..to text position + + if (_ctx->item == INV_NOICON) + return; + + if (event != POINTED) { + NotPointedRunning = true; // Get POINTED text to die + CORO_SLEEP(1); // Give it chance to + } else + NotPointedRunning = false; // There may have been an OFF without an ON + + // Display the text and set it's Z position + if (event == POINTED || (!isJapanMode() && (bSubtitles || !_vm->_sound->sampleExists(text)))) { + int xshift; + + LoadStringRes(text, tBufferAddr(), TBUFSZ); // The text string + _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), + 0, _ctx->textx, _ctx->texty, hTagFontHandle(), TXT_CENTRE); + assert(_ctx->pText); // printobj() string produced NULL text + MultiSetZPosition(_ctx->pText, Z_INV_ITEXT); + + // Don't go off the side of the screen + xshift = MultiLeftmost(_ctx->pText); + if (xshift < 0) { + MultiMoveRelXY(_ctx->pText, - xshift, 0); + _ctx->textx -= xshift; + } + xshift = MultiRightmost(_ctx->pText); + if (xshift > SCREEN_WIDTH) { + MultiMoveRelXY(_ctx->pText, SCREEN_WIDTH - xshift, 0); + _ctx->textx += SCREEN_WIDTH - xshift; + } + } else + _ctx->pText = NULL; + + if (event == POINTED) { + // FIXME: Is there ever an associated sound if in POINTED mode??? + assert(!_vm->_sound->sampleExists(text)); + CORO_INVOKE_ARGS(printobjPointed, (CORO_SUBCTX, text, pinvo, _ctx->pText, _ctx->textx, _ctx->texty, _ctx->item)); + } else { + CORO_INVOKE_2(printobjNonPointed, text, _ctx->pText); + } + + // Delete the text, if haven't already + if (_ctx->pText) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText); + + CORO_END_CODE; +} + +static void printobjPointed(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, OBJECT *&pText, const int textx, const int texty, const int item) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + // Have to give way to non-POINTED-generated text + // and go away if the item gets picked up + int x, y; + do { + // Give up if this item gets picked up + if (WhichItemHeld() == pinvo->id) + break; + + // Give way to non-POINTED-generated text + if (NotPointedRunning) { + // Delete the text, and wait for the all-clear + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), pText); + pText = NULL; + while (NotPointedRunning) + CORO_SLEEP(1); + + GetCursorXY(&x, &y, false); + if (InvItem(&x, &y, false) != item) + break; + + // Re-display in the same place + LoadStringRes(text, tBufferAddr(), TBUFSZ); + pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), + 0, textx, texty, hTagFontHandle(), TXT_CENTRE); + assert(pText); // printobj() string produced NULL text + MultiSetZPosition(pText, Z_INV_ITEXT); + } + + CORO_SLEEP(1); + + // Carry on until the cursor leaves this icon + GetCursorXY(&x, &y, false); + } while (InvItemId(x, y) == pinvo->id); + + CORO_END_CODE; +} + +static void printobjNonPointed(CORO_PARAM, const SCNHANDLE text, const OBJECT *pText) { + CORO_BEGIN_CONTEXT; + bool bSample; // Set if a sample is playing + Audio::SoundHandle handle; + + int myleftEvent; + bool took_control; + int ticks; + int timeout; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + // Kick off the voice sample + if (volVoice != 0 && _vm->_sound->sampleExists(text)) { + _vm->_sound->playSample(text, Audio::Mixer::kSpeechSoundType, &_ctx->handle); + _ctx->bSample = _vm->_mixer->isSoundHandleActive(_ctx->handle); + } else + _ctx->bSample = false; + + _ctx->myleftEvent = GetLeftEvents(); + _ctx->took_control = GetControl(CONTROL_OFF); + + // Display for a time, but abort if conversation gets hidden + if (isJapanMode()) + _ctx->ticks = JAP_TEXT_TIME; + else if (pText) + _ctx->ticks = TextTime(tBufferAddr()); + else + _ctx->ticks = 0; + + _ctx->timeout = SAMPLETIMEOUT; + do { + CORO_SLEEP(1); + --_ctx->timeout; + + // Abort if left click - hardwired feature for talky-print! + // Abort if sample times out + // Abort if conversation hidden + if (_ctx->myleftEvent != GetLeftEvents() || _ctx->timeout <= 0 || convHid()) + break; + + if (_ctx->bSample) { + // Wait for sample to end whether or not + if (!_vm->_mixer->isSoundHandleActive(_ctx->handle)) { + if (pText == NULL || speedText == DEFTEXTSPEED) { + // No text or speed modification - just depends on sample + break; + } else { + // Must wait for time + _ctx->bSample = false; + } + } + } else { + // No sample - just depends on time + if (_ctx->ticks-- <= 0) + break; + } + } while (1); + + NotPointedRunning = false; // Let POINTED text back in + + if (_ctx->took_control) + control(CONTROL_ON); // Free control if we took it + + _vm->_mixer->stopHandle(_ctx->handle); + + CORO_END_CODE; +} + +/** + * Register the fact that this poly would like its tag displayed. + */ +void printtag(HPOLYGON hp, SCNHANDLE text) { + assert(hp != NOPOLY); // printtag() may only be called from a polygon code block + + if (PolyTagState(hp) == TAG_OFF) { + SetPolyTagState(hp, TAG_ON); + SetPolyTagHandle(hp, text); + } +} + +/** + * quitgame + */ +void quitgame(void) { + stopmidi(); + stopsample(); + _vm->quitFlag = true; +} + +/** + * Return a random number between optional limits. + */ +int dw_random(int n1, int n2, int norpt) { + int i = 0; + uint32 value; + + do { + value = n1 + _vm->getRandomNumber(n2 - n1); + } while ((lastValue == value) && (norpt == RAND_NORPT) && (++i <= 10)); + + lastValue = value; + return value; +} + +/** + * resetidletime + */ +void resetidletime(void) { + resetUserEventTime(); +} + +/** + * restartgame + */ +void restartgame(void) { + stopmidi(); + stopsample(); + bRestart = true; +} + +/** + * Restore saved scene. + */ +void restore_scene(bool bFade) { + UnSuspendHook(); + PleaseRestoreScene(bFade); +} + +/** + * runmode + */ +int runmode(void) { + return clRunMode; +} + +/** + * sampleplaying + */ +bool sampleplaying(bool escOn, int myescEvent) { + // escape effects introduced 14/12/95 to fix + // while (sampleplaying()) pause; + + if (escOn && myescEvent != GetEscEvents()) + return false; + + return _vm->_sound->sampleIsPlaying(); +} + +/** + * Save current scene. + */ +void save_scene(CORO_PARAM) { + PleaseSaveScene(coroParam); + SuspendHook(); +} + +/** + * scalingreels + */ +void scalingreels(int actor, int scale, int direction, + SCNHANDLE left, SCNHANDLE right, SCNHANDLE forward, SCNHANDLE away) { + + setscalingreels(actor, scale, direction, left, right, forward, away); +} + +/** + * Return the icon that caused the CONVERSE event. + */ + +int scanicon(void) { + return convIcon(); +} + +/** + * Scroll the screen to target co-ordinates. + */ + +void scroll(CORO_PARAM, int x, int y, int iter, bool comp, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + int mycount; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + if (escOn && myescEvent != GetEscEvents()) { + // Instant completion! + offset(x, y); + } else { + _ctx->mycount = ++scrollCount; + + ScrollTo(x, y, iter); + + if (comp) { + int Loffset, Toffset; + do { + CORO_SLEEP(1); + + // If escapable and ESCAPE is pressed... + if (escOn && myescEvent != GetEscEvents()) { + // Instant completion! + offset(x, y); + break; + } + + // give up if have been superseded + if (_ctx->mycount != scrollCount) + CORO_KILL_SELF(); + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + } while (Loffset != x || Toffset != y); + } + } + CORO_END_CODE; +} + +/** + * Un-kill an actor. + */ +void setactor(int actor) { + EnableActor(actor); +} + +/** + * Turn a blocking polygon on. + */ + +void setblock(int blockno) { + EnableBlock(blockno); +} + +/** + * Turn an exit on. + */ + +void setexit(int exitno) { + EnableExit(exitno); +} + +/** + * Guess what. + */ +void setinvlimit(int invno, int n) { + InvSetLimit(invno, n); +} + +/** + * Guess what. + */ +void setinvsize(int invno, int MinWidth, int MinHeight, + int StartWidth, int StartHeight, int MaxWidth, int MaxHeight) { + InvSetSize(invno, MinWidth, MinHeight, StartWidth, StartHeight, MaxWidth, MaxHeight); +} + +/** + * Guess what. + */ +void setlanguage(LANGUAGE lang) { + assert(lang == TXT_ENGLISH || lang == TXT_FRENCH + || lang == TXT_GERMAN || lang == TXT_ITALIAN + || lang == TXT_SPANISH); // ensure language is valid + + ChangeLanguage(lang); +} + +/** + * Set palette + */ +void setpalette(SCNHANDLE hPal, bool escOn, int myescEvent) { + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + ChangePalette(hPal); +} + +/** + * Turn a tag on. + */ +void settag(int tagno) { + EnableTag(tagno); +} + +/** + * Initialise a timer. + */ +void settimer(int timerno, int start, bool up, bool frame) { + DwSetTimer(timerno, start, up != 0, frame != 0); +} + +#ifdef DEBUG +/** + * Enable display of diagnostic co-ordinates. + */ +void showpos(void) { + setshowpos(); +} + +/** + * Enable display of diagnostic co-ordinates. + */ +void showstring(void) { + setshowstring(); +} +#endif + +/** + * Special play - slow down associated actor's movement while the play + * is running. After the play, position the actor where the play left + * it and continue walking, if the actor still is. + */ + +void splay(CORO_PARAM, int sf, SCNHANDLE film, int x, int y, bool complete, int actorid, bool escOn, int myescEvent) { + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + play(coroParam, film, x, y, complete, actorid, true, sf, escOn, myescEvent, false); +} + +/** + * (Re)Position an actor. + * If moving actor is not around yet in this scene, start it up. + */ + +void stand(int actor, int x, int y, SCNHANDLE film) { + PMACTOR pActor; // Moving actor structure + + pActor = GetMover(actor); + if (pActor) { + if (pActor->MActorState == NO_MACTOR) { + // create a moving actor process + MActorProcessCreate(x, y, (actor == LEAD_ACTOR) ? LeadId() : actor, pActor); + + if (film == TF_NONE) { + SetMActorStanding(pActor); + } else { + switch (film) { + case TF_NONE: + break; + + case TF_UP: + SetMActorDirection(pActor, AWAY); + SetMActorStanding(pActor); + break; + case TF_DOWN: + SetMActorDirection(pActor, FORWARD); + SetMActorStanding(pActor); + break; + case TF_LEFT: + SetMActorDirection(pActor, LEFTREEL); + SetMActorStanding(pActor); + break; + case TF_RIGHT: + SetMActorDirection(pActor, RIGHTREEL); + SetMActorStanding(pActor); + break; + + default: + AlterMActor(pActor, film, AR_NORMAL); + break; + } + } + } else { + switch (film) { + case TF_NONE: + if (x != -1 && y != -1) + MoveMActor(pActor, x, y); + break; + + case TF_UP: + SetMActorDirection(pActor, AWAY); + if (x != -1 && y != -1) + MoveMActor(pActor, x, y); + SetMActorStanding(pActor); + break; + case TF_DOWN: + SetMActorDirection(pActor, FORWARD); + if (x != -1 && y != -1) + MoveMActor(pActor, x, y); + SetMActorStanding(pActor); + break; + case TF_LEFT: + SetMActorDirection(pActor, LEFTREEL); + if (x != -1 && y != -1) + MoveMActor(pActor, x, y); + SetMActorStanding(pActor); + break; + case TF_RIGHT: + SetMActorDirection(pActor, RIGHTREEL); + if (x != -1 && y != -1) + MoveMActor(pActor, x, y); + SetMActorStanding(pActor); + break; + + default: + if (x != -1 && y != -1) + MoveMActor(pActor, x, y); + AlterMActor(pActor, film, AR_NORMAL); + break; + } + } + } else if (actor == NULL_ACTOR) { + // + } else { + assert(film != 0); // Trying to play NULL film + + // Kick off the play and return. + playFilm(film, x, y, actor, false, 0, false, 0, false); + } +} + +/** + * Position the actor at the polygon's tag node. + */ +void standtag(int actor, HPOLYGON hp) { + SCNHANDLE film; + int pnodex, pnodey; + + assert(hp != NOPOLY); // standtag() may only be called from a polygon code block + + // Lead actor uses tag node film + film = getPolyFilm(hp); + getPolyNode(hp, &pnodex, &pnodey); + if (film && (actor == LEAD_ACTOR || actor == LeadId())) + stand(actor, pnodex, pnodey, film); + else + stand(actor, pnodex, pnodey, 0); +} + +/** + * Kill a moving actor's walk. + */ +void stop(int actor) { + PMACTOR pActor; + + pActor = GetMover(actor); + assert(pActor); // Trying to stop a null actor + + GetToken(pActor->actorToken); // Kill the walk process + pActor->stop = true; // Cause the actor to stop + FreeToken(pActor->actorToken); +} + +void stopmidi(void) { + StopMidi(); // Stop any currently playing midi +} + +void stopsample(void) { + _vm->_sound->stopAllSamples(); // Stop any currently playing sample +} + +void subtitles(int onoff) { + assert (onoff == ST_ON || onoff == ST_OFF); + + if (isJapanMode()) + return; // Subtitles are always off in JAPAN version (?) + + if (onoff == ST_ON) + bSubtitles = true; + else + bSubtitles = false; +} + +/** + * Special walk. + * Walk into or out of a legal path. + */ +void swalk(CORO_PARAM, int actor, int x1, int y1, int x2, int y2, SCNHANDLE film, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + bool took_control; // Set if this function takes control + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + // For lead actor, lock out the user (if not already locked out) + if (actor == LeadId() || actor == LEAD_ACTOR) + _ctx->took_control = GetControl(CONTROL_OFFV2); + else + _ctx->took_control = false; + + HPOLYGON hPath; + + hPath = InPolygon(x1, y1, PATH); + if (hPath != NOPOLY) { + // Walking out of a path + stand(actor, x1, y1, 0); + } else { + hPath = InPolygon(x2, y2, PATH); + // One of them has to be in a path + assert(hPath != NOPOLY); //one co-ordinate must be in a legal path + + // Walking into a path + stand(actor, x2, y2, 0); // Get path's characteristics + stand(actor, x1, y1, 0); + } + + CORO_INVOKE_ARGS(walk, (CORO_SUBCTX, actor, x2, y2, film, 0, true, escOn, myescEvent)); + + // Free control if we took it + if (_ctx->took_control) + control(CONTROL_ON); + + CORO_END_CODE; +} + +/** + * Define a tagged actor. + */ + +void tagactor(int actor, SCNHANDLE text, int tp) { + Tag_Actor(actor, text, tp); +} + +/** + * Text goes over actor's head while actor plays the talk reel. + */ + +void FinishTalkingReel(PMACTOR pActor, int actor) { + if (pActor) { + SetMActorStanding(pActor); + AlterMActor(pActor, 0, AR_POPREEL); + } else { + setActorTalking(actor, false); + playFilm(getActorPlayFilm(actor), -1, -1, 0, false, 0, false, 0, false); + } +} + +void talk(CORO_PARAM, SCNHANDLE film, const SCNHANDLE text, int actorid, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + int Loffset, Toffset; // Top left of display + int actor; // The speaking actor + PMACTOR pActor; // For moving actors + int myleftEvent; + int ticks; + bool bTookControl; // Set if this function takes control + bool bTookTags; // Set if this function disables tags + OBJECT *pText; // text object pointer + bool bSample; // Set if a sample is playing + bool bTalkReel; // Set while talk reel is playing + Audio::SoundHandle handle; + int timeout; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + _ctx->Loffset = 0; + _ctx->Toffset = 0; + _ctx->ticks = 0; + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + _ctx->myleftEvent = GetLeftEvents(); + + // If this actor is dead, call a stop to the calling process + if (actorid && !actorAlive(actorid)) + CORO_KILL_SELF(); + + /* + * Find out which actor is talking + * and with which direction if no film supplied + */ + TFTYPE direction; + switch (film) { + case TF_NONE: + case TF_UP: + case TF_DOWN: + case TF_LEFT: + case TF_RIGHT: + _ctx->actor = LeadId(); // If no film, actor is lead actor + direction = (TFTYPE)film; + break; + + default: + _ctx->actor = extractActor(film); + assert(_ctx->actor); // talk() - no actor ID in the reel + direction = TF_BOGUS; + break; + } + + /* + * Lock out the user (for lead actor, if not already locked out) + * May need to disable tags for other actors + */ + if (_ctx->actor == LeadId()) + _ctx->bTookControl = GetControl(CONTROL_OFF); + else + _ctx->bTookControl = false; + _ctx->bTookTags = DisableTagsIfEnabled(); + + /* + * Kick off the voice sample + */ + if (volVoice != 0 && _vm->_sound->sampleExists(text)) { + _vm->_sound->playSample(text, Audio::Mixer::kSpeechSoundType, &_ctx->handle); + _ctx->bSample = _vm->_mixer->isSoundHandleActive(_ctx->handle); + } else + _ctx->bSample = false; + + /* + * Replace actor with the talk reel, saving the current one + */ + _ctx->pActor = GetMover(_ctx->actor); + if (_ctx->pActor) { + if (direction != TF_BOGUS) + film = GetMactorTalkReel(_ctx->pActor, direction); + AlterMActor(_ctx->pActor, film, AR_PUSHREEL); + } else { + setActorTalking(_ctx->actor, true); + setActorTalkFilm(_ctx->actor, film); + playFilm(film, -1, -1, 0, false, 0, escOn, myescEvent, false); + } + _ctx->bTalkReel = true; + CORO_SLEEP(1); // Allow the play to come in + + /* + * Display the text. + */ + _ctx->pText = NULL; + if (isJapanMode()) { + _ctx->ticks = JAP_TEXT_TIME; + } else if (bSubtitles || !_ctx->bSample) { + int aniX, aniY; // actor position + int xshift, yshift; + /* + * Work out where to display the text + */ + PlayfieldGetPos(FIELD_WORLD, &_ctx->Loffset, &_ctx->Toffset); + GetActorMidTop(_ctx->actor, &aniX, &aniY); + aniY -= _ctx->Toffset; + + setTextPal(getActorTcol(_ctx->actor)); + LoadStringRes(text, tBufferAddr(), TBUFSZ); + _ctx->pText = ObjectTextOut(GetPlayfieldList(FIELD_STATUS), tBufferAddr(), + 0, aniX - _ctx->Loffset, aniY, hTalkFontHandle(), TXT_CENTRE); + assert(_ctx->pText); // talk() string produced NULL text; + if (IsTopWindow()) + MultiSetZPosition(_ctx->pText, Z_TOPW_TEXT); + + /* + * Set bottom of text just above the speaker's head + * But don't go off the top of the screen + */ + yshift = aniY - MultiLowest(_ctx->pText) - 2; // Just above head + MultiMoveRelXY(_ctx->pText, 0, yshift); // + yshift = MultiHighest(_ctx->pText); + if (yshift < 4) + MultiMoveRelXY(_ctx->pText, 0, 4 - yshift); // Not off top + + /* + * Don't go off the side of the screen + */ + xshift = MultiRightmost(_ctx->pText) + 2; + if (xshift >= SCREEN_WIDTH) // Not off right + MultiMoveRelXY(_ctx->pText, SCREEN_WIDTH - xshift, 0); + xshift = MultiLeftmost(_ctx->pText) - 1; + if (xshift <= 0) // Not off left + MultiMoveRelXY(_ctx->pText, -xshift, 0); + /* + * Work out how long to talk. + * During this time, reposition the text if the screen scrolls. + */ + _ctx->ticks = TextTime(tBufferAddr()); + } + + _ctx->timeout = SAMPLETIMEOUT; + do { + // Keep text in place if scrolling + if (_ctx->pText != NULL) { + int nLoff, nToff; + + PlayfieldGetPos(FIELD_WORLD, &nLoff, &nToff); + if (nLoff != _ctx->Loffset || nToff != _ctx->Toffset) { + MultiMoveRelXY(_ctx->pText, _ctx->Loffset - nLoff, _ctx->Toffset - nToff); + _ctx->Loffset = nLoff; + _ctx->Toffset = nToff; + } + } + + CORO_SLEEP(1); + --_ctx->timeout; + + // Abort if escapable and ESCAPE is pressed + // Abort if left click - hardwired feature for talk! + // Abort if sample times out + if ((escOn && myescEvent != GetEscEvents()) + || (_ctx->myleftEvent != GetLeftEvents()) + || (_ctx->timeout <= 0)) + break; + + if (_ctx->bSample) { + // Wait for sample to end whether or not + if (!_vm->_mixer->isSoundHandleActive(_ctx->handle)) { + if (_ctx->pText == NULL || speedText == DEFTEXTSPEED) { + // No text or speed modification - just depends on sample + break; + } else { + // Talk reel stops at end of speech + FinishTalkingReel(_ctx->pActor, _ctx->actor); + _ctx->bTalkReel = false; + _ctx->bSample = false; + } + } + } else { + // No sample - just depends on time + if (_ctx->ticks-- <= 0) + break; + } + } while (1); + + /* + * The talk is over now - dump the text + * Stop the sample + * Restore the actor's film or standing reel + */ + if (_ctx->pText != NULL) + MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText); + _vm->_mixer->stopHandle(_ctx->handle); + if (_ctx->bTalkReel) + FinishTalkingReel(_ctx->pActor, _ctx->actor); + + /* + * Restore user control and tags, as appropriate + * And, finally, release the talk token. + */ + if (_ctx->bTookControl) + control(CONTROL_ON); + if (_ctx->bTookTags) + EnableTags(); + + CORO_END_CODE; +} + +/** + * talkat(actor, x, y, text) + */ +void talkat(CORO_PARAM, int actor, int x, int y, SCNHANDLE text, bool escOn, int myescEvent) { + if (!coroParam) { + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + if (!isJapanMode() && (bSubtitles || !_vm->_sound->sampleExists(text))) + setTextPal(getActorTcol(actor)); + } + + print(coroParam, x, y, text, 0, 0, escOn, myescEvent); +} + +/** + * talkats(actor, x, y, text, sustain) + */ +void talkats(CORO_PARAM, int actor, int x, int y, SCNHANDLE text, int sustain, bool escOn, int myescEvent) { + if (!coroParam) { + assert(sustain == 2); + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + if (!isJapanMode()) + setTextPal(getActorTcol(actor)); + } + + print(coroParam, x, y, text, 0, sustain, escOn, myescEvent); +} + +/** + * Set talk font's palette entry. + */ +void talkattr(int r1, int g1, int b1, bool escOn, int myescEvent) { + if (isJapanMode()) + return; + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + if (r1 > MAX_INTENSITY) r1 = MAX_INTENSITY; // } Ensure + if (g1 > MAX_INTENSITY) g1 = MAX_INTENSITY; // } within limits + if (b1 > MAX_INTENSITY) b1 = MAX_INTENSITY; // } + + setTextPal(RGB(r1, g1, b1)); +} + +/** + * Get a timer's current count. + */ +int timer(int timerno) { + return Timer(timerno); +} + +/** + * topplay(film, x, y, actor, hold, complete) + */ +void topplay(CORO_PARAM, SCNHANDLE film, int x, int y, int complete, int actorid, bool splay, int sfact, bool escOn, int myescTime) { + play(coroParam, film, x, y, complete, actorid, splay, sfact, escOn, myescTime, true); +} + +/** + * Open or close the 'top window' + */ + +void topwindow(int bpos) { + assert(bpos == TW_START || bpos == TW_END); + + switch (bpos) { + case TW_END: + KillInventory(); + break; + + case TW_START: + KillInventory(); + PopUpConf(TOPWIN); + break; + } +} + +/** + * unhookscene + */ + +void unhookscene(void) { + UnHookScene(); +} + +/** + * Un-define an actor as tagged. + */ + +void untagactor(int actor) { + UnTagActor(actor); +} + +/** + * vibrate + */ + +void vibrate(void) { +} + +/** + * waitframe(int actor, int frameNumber) + */ + +void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + while (getActorSteps(actor) < frameNumber) { + CORO_SLEEP(1); + + // Abort if escapable and ESCAPE is pressed + if (escOn && myescEvent != GetEscEvents()) + break; + } + CORO_END_CODE; +} + +/** + * Return when a key pressed or button pushed. + */ + +void waitkey(CORO_PARAM, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + int startEvent; + int startX, startY; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + while (1) { + _ctx->startEvent = getUserEvents(); + // Store cursor position + while (!GetCursorXYNoWait(&_ctx->startX, &_ctx->startY, false)) + CORO_SLEEP(1); + + while (_ctx->startEvent == getUserEvents()) { + CORO_SLEEP(1); + + // Not necessary to monitor escape as it's an event anyway + + int curX, curY; + GetCursorXY(&curX, &curY, false); // Store cursor position + if (curX != _ctx->startX || curY != _ctx->startY) + break; + + if (IsConfWindow()) + break; + } + + if (!IsConfWindow()) + return; + + do { + CORO_SLEEP(1); + } while (IsConfWindow()); + + CORO_SLEEP(ONE_SECOND / 2); // Let it die down + } + CORO_END_CODE; +} + +/** + * Pause for requested time. + */ + +void waittime(CORO_PARAM, int time, bool frame, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + int time; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + // Don't do it if it's not wanted + if (escOn && myescEvent != GetEscEvents()) + return; + + if (!frame) + time *= ONE_SECOND; + + _ctx->time = time; + do { + CORO_SLEEP(1); + + // Abort if escapable and ESCAPE is pressed + if (escOn && myescEvent != GetEscEvents()) + break; + } while (_ctx->time--); + CORO_END_CODE; +} + +/** + * Set a moving actor off on a walk. + */ +void walk(CORO_PARAM, int actor, int x, int y, SCNHANDLE film, int hold, bool igPath, bool escOn, int myescEvent) { + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + PMACTOR pActor = GetMover(actor); + assert(pActor); // Can't walk a non-moving actor + + CORO_BEGIN_CODE(_ctx); + + // Straight there if escaped + if (escOn && myescEvent != GetEscEvents()) { + stand(actor, x, y, 0); + return; + } + + assert(pActor->hCpath != NOPOLY); // moving actor not in path + + GetToken(pActor->actorToken); + SetActorDest(pActor, x, y, igPath, film); + DontScrollCursor(); + + if (hold == 2) { + ; + } else { + while (MAmoving(pActor)) { + CORO_SLEEP(1); + + // Straight there if escaped + if (escOn && myescEvent != GetEscEvents()) { + stand(actor, x, y, 0); + FreeToken(pActor->actorToken); + return; + } + } + } + FreeToken(pActor->actorToken); + CORO_END_CODE; +} + +/** + * Set a moving actor off on a walk. + * Wait to see if its aborted or completed. + */ +void walked(CORO_PARAM, int actor, int x, int y, SCNHANDLE film, bool escOn, int myescEvent, bool &retVal) { + // COROUTINE + CORO_BEGIN_CONTEXT; + int ticket; + CORO_END_CONTEXT(_ctx); + + PMACTOR pActor = GetMover(actor); + assert(pActor); // Can't walk a non-moving actor + + CORO_BEGIN_CODE(_ctx); + + // Straight there if escaped + if (escOn && myescEvent != GetEscEvents()) { + stand(actor, x, y, 0); + retVal = true; + return; + } + + CORO_SLEEP(ONE_SECOND); + + assert(pActor->hCpath != NOPOLY); // moving actor not in path + + // Briefly aquire token to kill off any other normal walk + GetToken(pActor->actorToken); + FreeToken(pActor->actorToken); + + SetActorDest(pActor, x, y, false, film); + DontScrollCursor(); + + _ctx->ticket = GetActorTicket(pActor); + + while (MAmoving(pActor)) { + CORO_SLEEP(1); + + if (_ctx->ticket != GetActorTicket(pActor)) { + retVal = false; + return; + } + + // Straight there if escaped + if (escOn && myescEvent != GetEscEvents()) { + stand(actor, x, y, 0); + retVal = true; + return; + } + } + + int endx, endy; + GetMActorPosition(pActor, &endx, &endy); + retVal = (_ctx->ticket == GetActorTicket(pActor) && endx == x && endy == y); + + CORO_END_CODE; +} + +/** + * Declare a moving actor. + */ +void walkingactor(uint32 id, SCNHANDLE *rp) { + PMACTOR pActor; // Moving actor structure + + SetMover(id); // Establish as a moving actor + pActor = GetMover(id); + assert(pActor); + + // Store all those reels + int i, j; + for (i = 0; i < 5; ++i) { + for (j = 0; j < 4; ++j) + pActor->WalkReels[i][j] = *rp++; + for (j = 0; j < 4; ++j) + pActor->StandReels[i][j] = *rp++; + } + + + for (i = NUM_MAINSCALES; i < TOTAL_SCALES; i++) { + for (j = 0; j < 4; ++j) { + pActor->WalkReels[i][j] = pActor->WalkReels[4][j]; + pActor->StandReels[i][j] = pActor->StandReels[2][j]; + } + } +} + +/** + * Walk a moving actor towards the polygon's tag, but return when the + * actor enters the polygon. + */ + +void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + PMACTOR pActor = GetMover(actor); + assert(pActor); // Can't walk a non-moving actor + + CORO_BEGIN_CODE(_ctx); + + int aniX, aniY; // cursor/actor position + int pnodex, pnodey; + + assert(hp != NOPOLY); // walkpoly() may only be called from a polygon code block + + // Straight there if escaped + if (escOn && myescEvent != GetEscEvents()) { + standtag(actor, hp); + return; + } + + GetToken(pActor->actorToken); + getPolyNode(hp, &pnodex, &pnodey); + SetActorDest(pActor, pnodex, pnodey, false, film); + DoScrollCursor(); + + do { + CORO_SLEEP(1); + + if (escOn && myescEvent != GetEscEvents()) { + // Straight there if escaped + standtag(actor, hp); + FreeToken(pActor->actorToken); + return; + } + + GetMActorPosition(pActor, &aniX, &aniY); + } while (!MActorIsInPolygon(pActor, hp) && MAmoving(pActor)); + + FreeToken(pActor->actorToken); + + CORO_END_CODE; +} + +/** + * walktag(actor, reel, hold) + */ + +void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + PMACTOR pActor = GetMover(actor); + assert(pActor); // Can't walk a non-moving actor + + CORO_BEGIN_CODE(_ctx); + + int pnodex, pnodey; + + assert(hp != NOPOLY); // walkpoly() may only be called from a polygon code block + + // Straight there if escaped + if (escOn && myescEvent != GetEscEvents()) { + standtag(actor, hp); + return; + } + + GetToken(pActor->actorToken); + getPolyNode(hp, &pnodex, &pnodey); + SetActorDest(pActor, pnodex, pnodey, false, film); + DoScrollCursor(); + + while (MAmoving(pActor)) { + CORO_SLEEP(1); + + if (escOn && myescEvent != GetEscEvents()) { + // Straight there if escaped + standtag(actor, hp); + FreeToken(pActor->actorToken); + return; + } + } + + // Adopt the tag-related reel + SCNHANDLE pfilm = getPolyFilm(hp); + + switch (pfilm) { + case TF_NONE: + break; + + case TF_UP: + SetMActorDirection(pActor, AWAY); + SetMActorStanding(pActor); + break; + case TF_DOWN: + SetMActorDirection(pActor, FORWARD); + SetMActorStanding(pActor); + break; + case TF_LEFT: + SetMActorDirection(pActor, LEFTREEL); + SetMActorStanding(pActor); + break; + case TF_RIGHT: + SetMActorDirection(pActor, RIGHTREEL); + SetMActorStanding(pActor); + break; + + default: + if (actor == LEAD_ACTOR || actor == LeadId()) + AlterMActor(pActor, pfilm, AR_NORMAL); + else + SetMActorStanding(pActor); + break; + } + + FreeToken(pActor->actorToken); + CORO_END_CODE; +} + +/** + * whichinventory + */ + +int whichinventory(void) { + return WhichInventoryOpen(); +} + + +/** + * Subtract one less that the number of parameters from pp + * pp then points to the first parameter. + * + * If the library function has no return value: + * return -(the number of parameters) to pop them from the stack + * + * If the library function has a return value: + * return -(the number of parameters - 1) to pop most of them from + * the stack, and stick the return value in pp[0] + * @param operand Library function + * @param pp Top of parameter stack + */ +int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const PINT_CONTEXT pic, RESUME_STATE *pResumeState) { + debug(7, "CallLibraryRoutine op %d (escOn %d, myescEvent %d)", operand, pic->escOn, pic->myescEvent); + switch (operand) { + case ACTORATTR: + pp -= 3; // 4 parameters + actorattr(pp[0], pp[1], pp[2], pp[3]); + return -4; + + case ACTORDIRECTION: + pp[0] = actordirection(pp[0]); + return 0; + + case ACTORREF: + error("actorref isn't a real function!"); + + case ACTORSCALE: + pp[0] = actorscale(pp[0]); + return 0; + + case ACTORSON: + actorson(); + return 0; + + case ACTORXPOS: + pp[0] = actorpos(ACTORXPOS, pp[0]); + return 0; + + case ACTORYPOS: + pp[0] = actorpos(ACTORYPOS, pp[0]); + return 0; + + case ADDICON: + addicon(pp[0]); + return -1; + + case ADDINV1: + addinv(INV_1, pp[0]); + return -1; + + case ADDINV2: + addinv(INV_2, pp[0]); + return -1; + + case ADDOPENINV: + addinv(INV_OPEN, pp[0]); + return -1; + + case AUXSCALE: + pp -= 13; // 14 parameters + auxscale(pp[0], pp[1], (SCNHANDLE *)(pp+2)); + return -14; + + case BACKGROUND: + background(pp[0]); + return -1; + + case CAMERA: + camera(pp[0]); + return -1; + + case CDLOAD: + pp -= 1; // 2 parameters + cdload(pp[0], pp[1]); + return -2; + + case CDPLAY: + error("cdplay isn't a real function!"); + + case CLEARHOOKSCENE: + clearhookscene(); + return 0; + + case CLOSEINVENTORY: + closeinventory(); + return 0; + + case CONTROL: + control(pp[0]); + return -1; + + case CONVERSATION: + conversation(pp[0], pic->hpoly, pic->escOn, pic->myescEvent); + return -1; + + case CONVICON: + convicon(pp[0]); + return -1; + + case CURSORXPOS: + pp[0] = cursorpos(CURSORXPOS); + return 0; + + case CURSORYPOS: + pp[0] = cursorpos(CURSORYPOS); + return 0; + + case CUTSCENE: + error("cutscene isn't a real function!"); + + case DEC_CONVW: + pp -= 7; // 8 parameters + dec_convw(pp[0], pp[1], pp[2], pp[3], + pp[4], pp[5], pp[6], pp[7]); + return -8; + + case DEC_CSTRINGS: + pp -= 19; // 20 parameters + dec_cstrings((SCNHANDLE *)pp); + return -20; + + case DEC_CURSOR: + dec_cursor(pp[0]); + return -1; + + case DEC_FLAGS: + dec_flags(pp[0]); + return -1; + + case DEC_INV1: + pp -= 7; // 8 parameters + dec_inv1(pp[0], pp[1], pp[2], pp[3], + pp[4], pp[5], pp[6], pp[7]); + return -8; + + case DEC_INV2: + pp -= 7; // 8 parameters + dec_inv2(pp[0], pp[1], pp[2], pp[3], + pp[4], pp[5], pp[6], pp[7]); + return -8; + + case DEC_INVW: + dec_invw(pp[0]); + return -1; + + case DEC_LEAD: + pp -= 61; // 62 parameters + dec_lead(pp[0], (SCNHANDLE *)&pp[1], pp[61]); + return -62; + + case DEC_TAGFONT: + dec_tagfont(pp[0]); + return -1; + + case DEC_TALKFONT: + dec_talkfont(pp[0]); + return -1; + + case DELICON: + delicon(pp[0]); + return -1; + + case DELINV: + delinv(pp[0]); + return -1; + + case EFFECTACTOR: + assert(pic->event == ENTER || pic->event == LEAVE); // effectactor() must be from effect poly code + + pp[0] = pic->actorid; + return 0; + + case ENABLEF1: + enablef1(); + return 0; + + case EVENT: + pp[0] = pic->event; + return 0; + + case FADEMIDI: + fademidi(coroParam, pp[0]); + return -1; + + case FRAMEGRAB: + return -1; + + case GETINVLIMIT: + pp[0] = getinvlimit(pp[0]); + return 0; + + case HASRESTARTED: + pp[0] = hasrestarted(); + return 0; + + case HELDOBJECT: + pp[0] = heldobject(); + return 0; + + case HIDE: + hide(pp[0]); + return -1; + + case HOOKSCENE: + pp -= 2; // 3 parameters + hookscene(pp[0], pp[1], pp[2]); + return -3; + + case IDLETIME: + pp[0] = idletime(); + return 0; + + case ININVENTORY: + pp[0] = ininventory(pp[0]); + return 0; // using return value + + case INVDEPICT: + pp -= 1; // 2 parameters + invdepict(pp[0], pp[1]); + return -2; + + case INVENTORY: + inventory(pp[0], pic->escOn, pic->myescEvent); + return -1; + + case INWHICHINV: + pp[0] = inwhichinv(pp[0]); + return 0; // using return value + + case KILLACTOR: + killactor(pp[0]); + return -1; + + case KILLBLOCK: + killblock(pp[0]); + return -1; + + case KILLEXIT: + killexit(pp[0]); + return -1; + + case KILLTAG: + killtag(pp[0]); + return -1; + + case LEFTOFFSET: + pp[0] = ltoffset(LEFTOFFSET); + return 0; + + case MOVECURSOR: + pp -= 1; // 2 parameters + movecursor(pp[0], pp[1]); + return -2; + + case NEWSCENE: + pp -= 2; // 3 parameters + if (*pResumeState == RES_2) + *pResumeState = RES_NOT; + else + newscene(coroParam, pp[0], pp[1], pp[2]); + return -3; + + case NOBLOCKING: + noblocking(); + return 0; + + case NOSCROLL: + pp -= 3; // 4 parameters + noscroll(pp[0], pp[1], pp[2], pp[3]); + return -4; + + case OBJECTHELD: + objectheld(pp[0]); + return -1; + + case OFFSET: + pp -= 1; // 2 parameters + offset(pp[0], pp[1]); + return -2; + + case PLAY: + pp -= 5; // 6 parameters + + if (pic->event == ENTER || pic->event == LEAVE) + play(coroParam, pp[0], pp[1], pp[2], pp[5], 0, false, 0, pic->escOn, pic->myescEvent, false); + else + play(coroParam, pp[0], pp[1], pp[2], pp[5], pic->actorid, false, 0, pic->escOn, pic->myescEvent, false); + return -6; + + case PLAYMIDI: + pp -= 2; // 3 parameters + playmidi(coroParam, pp[0], pp[1], pp[2]); + return -3; + + case PLAYRTF: + error("playrtf only applies to cdi!"); + + case PLAYSAMPLE: + pp -= 1; // 2 parameters + playsample(coroParam, pp[0], pp[1], pic->escOn, pic->myescEvent); + return -2; + + case PREPARESCENE: + preparescene(pp[0]); + return -1; + + case PRINT: + pp -= 5; // 6 parameters + /* pp[2] was intended to be attribute */ + print(coroParam, pp[0], pp[1], pp[3], pp[4], pp[5], pic->escOn, pic->myescEvent); + return -6; + + case PRINTOBJ: + printobj(coroParam, pp[0], pic->pinvo, pic->event); + return -1; + + case PRINTTAG: + printtag(pic->hpoly, pp[0]); + return -1; + + case QUITGAME: + quitgame(); + return 0; + + case RANDOM: + pp -= 2; // 3 parameters + pp[0] = dw_random(pp[0], pp[1], pp[2]); + return -2; // One holds return value + + case RESETIDLETIME: + resetidletime(); + return 0; + + case RESTARTGAME: + restartgame(); + return 0; + + case RESTORE_CUT: + restore_scene(false); + return 0; + + case RESTORE_SCENE: + restore_scene(true); + return 0; + + case RUNMODE: + pp[0] = runmode(); + return 0; + + case SAMPLEPLAYING: + pp[0] = sampleplaying(pic->escOn, pic->myescEvent); + return 0; + + case SAVE_SCENE: + if (*pResumeState == RES_1) + *pResumeState = RES_2; + else + save_scene(coroParam); + return 0; + + case SCALINGREELS: + pp -= 6; // 7 parameters + scalingreels(pp[0], pp[1], pp[2], pp[3], pp[4], pp[5], pp[6]); + return -7; + + case SCANICON: + pp[0] = scanicon(); + return 0; + + case SCROLL: + pp -= 3; // 4 parameters + scroll(coroParam, pp[0], pp[1], pp[2], pp[3], pic->escOn, pic->myescEvent); + return -4; + + case SETACTOR: + setactor(pp[0]); + return -1; + + case SETBLOCK: + setblock(pp[0]); + return -1; + + case SETEXIT: + setexit(pp[0]); + return -1; + + case SETINVLIMIT: + pp -= 1; // 2 parameters + setinvlimit(pp[0], pp[1]); + return -2; + + case SETINVSIZE: + pp -= 6; // 7 parameters + setinvsize(pp[0], pp[1], pp[2], pp[3], pp[4], pp[5], pp[6]); + return -7; + + case SETLANGUAGE: + setlanguage((LANGUAGE)pp[0]); + return -1; + + case SETPALETTE: + setpalette(pp[0], pic->escOn, pic->myescEvent); + return -1; + + case SETTAG: + settag(pp[0]); + return -1; + + case SETTIMER: + pp -= 3; // 4 parameters + settimer(pp[0], pp[1], pp[2], pp[3]); + return -4; + + case SHOWPOS: +#ifdef DEBUG + showpos(); +#endif + return 0; + + case SHOWSTRING: +#ifdef DEBUG + showstring(); +#endif + return 0; + + case SPLAY: + pp -= 6; // 7 parameters + + if (pic->event == ENTER || pic->event == LEAVE) + splay(coroParam, pp[0], pp[1], pp[2], pp[3], pp[6], 0, pic->escOn, pic->myescEvent); + else + splay(coroParam, pp[0], pp[1], pp[2], pp[3], pp[6], pic->actorid, pic->escOn, pic->myescEvent); + return -7; + + case STAND: + pp -= 3; // 4 parameters + stand(pp[0], pp[1], pp[2], pp[3]); + return -4; + + case STANDTAG: + standtag(pp[0], pic->hpoly); + return -1; + + case STOP: + stop(pp[0]); + return -1; + + case STOPMIDI: + stopmidi(); + return 0; + + case STOPSAMPLE: + stopsample(); + return 0; + + case SUBTITLES: + subtitles(pp[0]); + return -1; + + case SWALK: + pp -= 5; // 6 parameters + swalk(coroParam, pp[0], pp[1], pp[2], pp[3], pp[4], pp[5], pic->escOn, pic->myescEvent); + return -6; + + case TAGACTOR: + pp -= 2; // 3 parameters + tagactor(pp[0], pp[1], pp[2]); + return -3; + + case TALK: + pp -= 1; // 2 parameters + + if (pic->event == ENTER || pic->event == LEAVE) + talk(coroParam, pp[0], pp[1], 0, pic->escOn, pic->myescEvent); + else + talk(coroParam, pp[0], pp[1], pic->actorid, pic->escOn, pic->myescEvent); + return -2; + + case TALKAT: + pp -= 3; // 4 parameters + talkat(coroParam, pp[0], pp[1], pp[2], pp[3], pic->escOn, pic->myescEvent); + return -4; + + case TALKATS: + pp -= 4; // 5 parameters + talkats(coroParam, pp[0], pp[1], pp[2], pp[3], pp[4], pic->escOn, pic->myescEvent); + return -5; + + case TALKATTR: + pp -= 2; // 3 parameters + talkattr(pp[0], pp[1], pp[2], pic->escOn, pic->myescEvent); + return -3; + + case TIMER: + pp[0] = timer(pp[0]); + return 0; + + case TOPOFFSET: + pp[0] = ltoffset(TOPOFFSET); + return 0; + + case TOPPLAY: + pp -= 5; // 6 parameters + topplay(coroParam, pp[0], pp[1], pp[2], pp[5], pic->actorid, false, 0, pic->escOn, pic->myescEvent); + return -6; + + case TOPWINDOW: + topwindow(pp[0]); + return -1; + + case TRYPLAYSAMPLE: + pp -= 1; // 2 parameters + tryplaysample(coroParam, pp[0], pp[1], pic->escOn, pic->myescEvent); + return -2; + + case UNHOOKSCENE: + unhookscene(); + return 0; + + case UNTAGACTOR: + untagactor(pp[0]); + return -1; + + case VIBRATE: + vibrate(); + return 0; + + case WAITKEY: + waitkey(coroParam, pic->escOn, pic->myescEvent); + return 0; + + case WAITFRAME: + pp -= 1; // 2 parameters + waitframe(coroParam, pp[0], pp[1], pic->escOn, pic->myescEvent); + return -2; + + case WAITTIME: + pp -= 1; // 2 parameters + waittime(coroParam, pp[0], pp[1], pic->escOn, pic->myescEvent); + return -2; + + case WALK: + pp -= 4; // 5 parameters + walk(coroParam, pp[0], pp[1], pp[2], pp[3], pp[4], false, pic->escOn, pic->myescEvent); + return -5; + + case WALKED: { + pp -= 3; // 4 parameters + bool tmp; + walked(coroParam, pp[0], pp[1], pp[2], pp[3], pic->escOn, pic->myescEvent, tmp); + if (!coroParam) { + // Only write the result to the stack if walked actually completed running. + pp[0] = tmp; + } + } + return -3; + + case WALKINGACTOR: + pp -= 40; // 41 parameters + walkingactor(pp[0], (SCNHANDLE *)&pp[1]); + return -41; + + case WALKPOLY: + pp -= 2; // 3 parameters + walkpoly(coroParam, pp[0], pp[1], pic->hpoly, pic->escOn, pic->myescEvent); + return -3; + + case WALKTAG: + pp -= 2; // 3 parameters + walktag(coroParam, pp[0], pp[1], pic->hpoly, pic->escOn, pic->myescEvent); + return -3; + + case WHICHINVENTORY: + pp[0] = whichinventory(); + return 0; + + default: + error("Unsupported library function"); + } + + error("Can't possibly get here"); +} + + +} // end of namespace Tinsel diff --git a/engines/tinsel/tinlib.h b/engines/tinsel/tinlib.h new file mode 100644 index 0000000000..001de70896 --- /dev/null +++ b/engines/tinsel/tinlib.h @@ -0,0 +1,41 @@ +/* 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$ + * + * Text utility defines + */ + +#ifndef TINSEL_TINLIB_H // prevent multiple includes +#define TINSEL_TINLIB_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +// Library functions in TINLIB.C + +void control(int param); +void stand(int actor, int x, int y, SCNHANDLE film); + +} // end of namespace Tinsel + +#endif // TINSEL_TINLIB_H diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp new file mode 100644 index 0000000000..ec16e73294 --- /dev/null +++ b/engines/tinsel/tinsel.cpp @@ -0,0 +1,1005 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" +#include "common/stream.h" + +#include "graphics/cursorman.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "sound/mididrv.h" +#include "sound/mixer.h" +#include "sound/audiocd.h" + +#include "tinsel/actors.h" +#include "tinsel/background.h" +#include "tinsel/config.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/events.h" +#include "tinsel/faders.h" +#include "tinsel/film.h" +#include "tinsel/handle.h" +#include "tinsel/heapmem.h" // MemoryInit +#include "tinsel/inventory.h" +#include "tinsel/music.h" +#include "tinsel/object.h" +#include "tinsel/pid.h" +#include "tinsel/savescn.h" +#include "tinsel/scn.h" +#include "tinsel/serializer.h" +#include "tinsel/sound.h" +#include "tinsel/strres.h" +#include "tinsel/timers.h" +#include "tinsel/tinsel.h" + +namespace Tinsel { + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// In BG.CPP +extern void SetDoFadeIn(bool tf); +extern void DropBackground(void); + +// In CURSOR.CPP +extern void CursorProcess(CORO_PARAM); + +// In INVENTORY.CPP +extern void InventoryProcess(CORO_PARAM); + +// In SCENE.CPP +extern void PrimeBackground( void ); +extern void NewScene(SCNHANDLE scene, int entry); +extern SCNHANDLE GetSceneHandle(void); + +// In TIMER.CPP +extern void FettleTimers(void); +extern void RebootTimers(void); + +//----------------- FORWARD DECLARATIONS --------------------- +void SetNewScene(SCNHANDLE scene, int entrance, int transition); + +//----------------- GLOBAL GLOBAL DATA -------------------- + +bool bRestart = false; +bool bHasRestarted = false; + +#ifdef DEBUG +bool bFast; // set to make it go ludicrously fast +#endif + +//----------------- LOCAL GLOBAL DATA -------------------- + +struct Scene { + SCNHANDLE scene; // Memory handle for scene + int entry; // Entrance number + int trans; // Transition - not yet used +}; + +static Scene NextScene = { 0, 0, 0 }; +static Scene HookScene = { 0, 0, 0 }; +static Scene DelayedScene = { 0, 0, 0 }; + +static bool bHookSuspend = false; + +static uint32 lastLeftClick = 0, lastRightClick = 0; + +static PROCESS *pMouseProcess = 0; +static PROCESS *pKeyboardProcess = 0; + +// Stack of pending mouse button events +Common::List mouseButtons; + +// Stack of pending keypresses +Common::List keypresses; + +//----------------- LOCAL PROCEDURES -------------------- + +/** + * Process to handle keypresses + */ +void KeyboardProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + while (true) { + if (keypresses.empty()) { + // allow scheduling + CORO_SLEEP(1); + continue; + } + + // Get the next keyboard event off the stack + Common::Event evt = *keypresses.begin(); + keypresses.erase(keypresses.begin()); + + // Switch for special keys + switch (evt.kbd.keycode) { + // Drag action + case Common::KEYCODE_LALT: + case Common::KEYCODE_RALT: + if (evt.type == Common::EVENT_KEYDOWN) { + if (!bSwapButtons) + ProcessButEvent(BE_RDSTART); + else + ProcessButEvent(BE_LDSTART); + } else { + if (!bSwapButtons) + ProcessButEvent(BE_LDEND); + else + ProcessButEvent(BE_RDEND); + } + continue; + + case Common::KEYCODE_LCTRL: + case Common::KEYCODE_RCTRL: + if (evt.type == Common::EVENT_KEYDOWN) { + ProcessKeyEvent(LOOK_KEY); + } else { + // Control key release + } + continue; + + default: + break; + } + + // At this point only key down events need processing + if (evt.type == Common::EVENT_KEYUP) + continue; + + if (_vm->_keyHandler != NULL) + // Keyboard is hooked, so pass it on to that handler first + if (!_vm->_keyHandler(evt.kbd)) + continue; + + switch (evt.kbd.keycode) { + /*** SPACE = WALKTO ***/ + case Common::KEYCODE_SPACE: + ProcessKeyEvent(WALKTO_KEY); + continue; + + /*** RETURN = ACTION ***/ + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + ProcessKeyEvent(ACTION_KEY); + continue; + + /*** l = LOOK ***/ + case Common::KEYCODE_l: // LOOK + ProcessKeyEvent(LOOK_KEY); + continue; + + case Common::KEYCODE_ESCAPE: + // WORKAROUND: Check if any of the starting logo screens are active, and if so + // manually skip to the title screen, allowing them to be bypassed + { + int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0; + int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset; + if ((language == TXT_GERMAN) && + ((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) { + // Skip to title screen + // It seems the German CD version uses scenes 25,26,27,17 for the intro, + // instead of 13,14,15,11; also, the title screen is 11 instead of 10 + SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); + } else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { + // Skip to title screen + SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); + } else { + // Not on an intro screen, so process the key normally + ProcessKeyEvent(ESC_KEY); + } + } + continue; + +#ifdef SLOW_RINCE_DOWN + case '>': + AddInterlude(1); + continue; + case '<': + AddInterlude(-1); + continue; +#endif + + case Common::KEYCODE_F1: + // Options dialog + ProcessKeyEvent(OPTION_KEY); + continue; + case Common::KEYCODE_F5: + // Save game + ProcessKeyEvent(SAVE_KEY); + continue; + case Common::KEYCODE_F7: + // Load game + ProcessKeyEvent(LOAD_KEY); + continue; + case Common::KEYCODE_q: + if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT)) + ProcessKeyEvent(QUIT_KEY); + continue; + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_KP9: + ProcessKeyEvent(PGUP_KEY); + continue; + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP3: + ProcessKeyEvent(PGDN_KEY); + continue; + case Common::KEYCODE_HOME: + case Common::KEYCODE_KP7: + ProcessKeyEvent(HOME_KEY); + continue; + case Common::KEYCODE_END: + case Common::KEYCODE_KP1: + ProcessKeyEvent(END_KEY); + continue; + default: + ProcessKeyEvent(NOEVENT_KEY); + break; + } + } + CORO_END_CODE; +} + +/** + * Process to handle changes in the mouse buttons. + */ +void MouseProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + bool lastLWasDouble; + bool lastRWasDouble; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + _ctx->lastLWasDouble = false; + _ctx->lastRWasDouble = false; + + while (true) { + // FIXME: I'm still keeping the ctrl/Alt handling in the KeyProcess method. + // Need to make sure that this works correctly + //DragKeys(); + + if (mouseButtons.empty()) { + // allow scheduling + CORO_SLEEP(1); + continue; + } + + // get next mouse button event + Common::EventType type = *mouseButtons.begin(); + mouseButtons.erase(mouseButtons.begin()); + + switch (type) { + case Common::EVENT_LBUTTONDOWN: + // left button press + if (DwGetCurrentTime() - lastLeftClick < (uint32)dclickSpeed) { + // signal left drag start + ProcessButEvent(BE_LDSTART); + + // signal left double click event + ProcessButEvent(BE_DLEFT); + + _ctx->lastLWasDouble = true; + } else { + // signal left drag start + ProcessButEvent(BE_LDSTART); + + // signal left single click event + ProcessButEvent(BE_SLEFT); + + _ctx->lastLWasDouble = false; + } + break; + + case Common::EVENT_LBUTTONUP: + // left button release + + // update click timer + if (_ctx->lastLWasDouble == false) + lastLeftClick = DwGetCurrentTime(); + else + lastLeftClick -= dclickSpeed; + + // signal left drag end + ProcessButEvent(BE_LDEND); + break; + + case Common::EVENT_RBUTTONDOWN: + // right button press + + if (DwGetCurrentTime() - lastRightClick < (uint32)dclickSpeed) { + // signal right drag start + ProcessButEvent(BE_RDSTART); + + // signal right double click event + ProcessButEvent(BE_DRIGHT); + + _ctx->lastRWasDouble = true; + } else { + // signal right drag start + ProcessButEvent(BE_RDSTART); + + // signal right single click event + ProcessButEvent(BE_SRIGHT); + + _ctx->lastRWasDouble = false; + } + break; + + case Common::EVENT_RBUTTONUP: + // right button release + + // update click timer + if (_ctx->lastRWasDouble == false) + lastRightClick = DwGetCurrentTime(); + else + lastRightClick -= dclickSpeed; + + // signal right drag end + ProcessButEvent(BE_RDEND); + break; + + default: + break; + } + } + CORO_END_CODE; +} + +/** + * Installs the event driver processes + */ + +void EventsInstall(void) { + lastLeftClick = lastRightClick = DwGetCurrentTime(); + + pMouseProcess = CoroutineInstall(PID_MOUSE, MouseProcess, NULL, 0); + pKeyboardProcess = CoroutineInstall(PID_KEYBOARD, KeyboardProcess, NULL, 0); +} + +/** + * Removes the event driver processes + */ + +void EventsUninstall(void) { + ProcessKill(pMouseProcess); + ProcessKill(pKeyboardProcess); +} + +/** + * Run the master script. + * Continues between scenes, or until Interpret() returns. + */ +static void MasterScriptProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + _ctx->pic = InitInterpretContext(GS_MASTER, 0, NOEVENT, NOPOLY, 0, NULL); + CORO_INVOKE_1(Interpret, _ctx->pic); + CORO_END_CODE; +} + +/** + * Store the facts pertaining to a scene change. + */ + +void SetNewScene(SCNHANDLE scene, int entrance, int transition) { + if (HookScene.scene == 0 || bHookSuspend) { + // This scene comes next + NextScene.scene = scene; + NextScene.entry = entrance; + NextScene.trans = transition; + } else { + // This scene gets delayed + DelayedScene.scene = scene; + DelayedScene.entry = entrance; + DelayedScene.trans = transition; + + // The hooked scene comes next + NextScene.scene = HookScene.scene; + NextScene.entry = HookScene.entry; + NextScene.trans = HookScene.trans; + + HookScene.scene = 0; + } +} + +void SetHookScene(SCNHANDLE scene, int entrance, int transition) { + assert(HookScene.scene == 0); // scene already hooked + + HookScene.scene = scene; + HookScene.entry = entrance; + HookScene.trans = transition; +} + +void UnHookScene(void) { + assert(DelayedScene.scene != 0); // no scene delayed + + // The delayed scene can go now + NextScene.scene = DelayedScene.scene; + NextScene.entry = DelayedScene.entry; + NextScene.trans = DelayedScene.trans; + + DelayedScene.scene = 0; +} + +void SuspendHook(void) { + bHookSuspend = true; +} + +void UnSuspendHook(void) { + bHookSuspend = false; +} + +void syncSCdata(Serializer &s) { + s.syncAsUint32LE(HookScene.scene); + s.syncAsSint32LE(HookScene.entry); + s.syncAsSint32LE(HookScene.trans); + + s.syncAsUint32LE(DelayedScene.scene); + s.syncAsSint32LE(DelayedScene.entry); + s.syncAsSint32LE(DelayedScene.trans); +} + + +//----------------------------------------------------------------------- + +static void RestoredProcess(CORO_PARAM) { + // COROUTINE + CORO_BEGIN_CONTEXT; + PINT_CONTEXT pic; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + // get the stuff copied to process when it was created + _ctx->pic = *((PINT_CONTEXT *)ProcessGetParamsSelf()); + + _ctx->pic = RestoreInterpretContext(_ctx->pic); + CORO_INVOKE_1(Interpret, _ctx->pic); + + CORO_END_CODE; +} + +void RestoreProcess(PINT_CONTEXT pic) { + CoroutineInstall(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); +} + +void RestoreMasterProcess(PINT_CONTEXT pic) { + CoroutineInstall(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); +} + +// FIXME: CountOut is used by ChangeScene +static int CountOut = 1; // == 1 for immediate start of first scene + +/** + * If a scene restore is going on, just return (we don't update the + * screen during this time). + * If a scene change is required, 'order' the data for the new scene and + * start a fade out and a countdown. + * When the count expires, the screen will have faded. Ensure the scene | + * is loaded, clear the screen, and start the new scene. + */ +void ChangeScene() { + + if (IsRestoringScene()) + return; + + if (NextScene.scene != 0) { + if (!CountOut) { + switch (NextScene.trans) { + case TRANS_CUT: + CountOut = 1; + break; + + case TRANS_FADE: + default: + // Trigger pre-load and fade and start countdown + CountOut = COUNTOUT_COUNT; + FadeOutFast(NULL); + break; + } + } else if (--CountOut == 0) { + ClearScreen(0L); + + NewScene(NextScene.scene, NextScene.entry); + NextScene.scene = 0; + + switch (NextScene.trans) { + case TRANS_CUT: + SetDoFadeIn(false); + break; + + case TRANS_FADE: + default: + SetDoFadeIn(true); + break; + } + } + } +} + +/** + * LoadBasicChunks + */ + +void LoadBasicChunks(void) { + byte *cptr; + int numObjects; + + // Allocate RAM for savescene data + InitialiseSs(); + + // CHUNK_TOTAL_ACTORS seems to be missing in the released version, hard coding a value + // TODO: Would be nice to just change 511 to MAX_SAVED_ALIVES + cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_ACTORS); + RegisterActors((cptr != NULL) ? READ_LE_UINT32(cptr) : 511); + + // CHUNK_TOTAL_GLOBALS seems to be missing in some versions. + // So if it is missing, set a reasonably high value for the number of globals. + cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_GLOBALS); + RegisterGlobals((cptr != NULL) ? READ_LE_UINT32(cptr) : 512); + + cptr = FindChunk(INV_OBJ_SCNHANDLE, CHUNK_TOTAL_OBJECTS); + numObjects = (cptr != NULL) ? READ_LE_UINT32(cptr) : 0; + + cptr = FindChunk(INV_OBJ_SCNHANDLE, CHUNK_OBJECTS); + +#ifdef SCUMM_BIG_ENDIAN + //convert to native endianness + INV_OBJECT *io = (INV_OBJECT *)cptr; + for (int i = 0; i < numObjects; i++, io++) { + io->id = FROM_LE_32(io->id); + io->hFilm = FROM_LE_32(io->hFilm); + io->hScript = FROM_LE_32(io->hScript); + io->attribute = FROM_LE_32(io->attribute); + } +#endif + + RegisterIcons(cptr, numObjects); + + cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_POLY); + if (cptr != NULL) + MaxPolygons(*cptr); +} + +//----------------- TinselEngine -------------------- + +// Global pointer to engine +TinselEngine *_vm; + +struct GameSettings { + const char *gameid; + const char *description; + byte id; + uint32 features; + const char *detectname; +}; + +static const GameSettings tinselSettings[] = { + {"tinsel", "Tinsel game", 0, 0, 0}, + + {NULL, NULL, 0, 0, NULL} +}; + +TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) : + Engine(syst), _gameDescription(gameDesc), _screenSurface(true) { + _vm = this; + + // Setup mixer + _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 = tinselSettings; g->gameid; ++g) + if (!scumm_stricmp(g->gameid, gameid)) + _gameId = g->id; + + int cd_num = ConfMan.getInt("cdrom"); + if (cd_num >= 0) + _system->openCD(cd_num); + + int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); + bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); + //bool adlib = (midiDriver == MD_ADLIB); + + MidiDriver *driver = MidiDriver::createMidi(midiDriver); + if (native_mt32) + driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + + _music = new MusicPlayer(driver); + //_music->setNativeMT32(native_mt32); + //_music->setAdlib(adlib); + + _musicVolume = ConfMan.getInt("music_volume"); + + _sound = new SoundManager(this); + + _mousePos.x = 0; + _mousePos.y = 0; + _keyHandler = NULL; + _dosPlayerDir = 0; + quitFlag = false; +} + +TinselEngine::~TinselEngine() { + delete _sound; + delete _music; + delete _console; + FreeSs(); + FreeTextBuffer(); + FreeHandleTable(); + FreeActors(); + FreeObjectList(); + FreeGlobals(); + FreeProcessList(); +} + +int TinselEngine::init() { + // Initialize backend + _system->beginGFXTransaction(); + initCommonGFX(false); + _system->initSize(SCREEN_WIDTH, SCREEN_HEIGHT); + _system->endGFXTransaction(); + + _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, 1); + + g_system->getEventManager()->registerRandomSource(_random, "tinsel"); + + _console = new Console(); + + // init memory manager + MemoryInit(); + + // load user configuration + ReadConfig(); + +#if 1 + // FIXME: The following is taken from RestartGame(). + // It may have to be adjusted a bit + RebootCursor(); + RebootDeadTags(); + RebootMovers(); + RebootTimers(); + RebootScalingReels(); + + DelayedScene.scene = HookScene.scene = 0; +#endif + + // Init palette and object managers, scheduler, keyboard and mouse + RestartDrivers(); + + // TODO: More stuff from dos_main.c may have to be added here + + // Set language - we'll be clever here and use the ScummVM language setting + language = TXT_ENGLISH; + switch (getLanguage()) { + case Common::FR_FRA: + language = TXT_FRENCH; + break; + case Common::DE_DEU: + language = TXT_GERMAN; + break; + case Common::IT_ITA: + language = TXT_ITALIAN; + break; + case Common::ES_ESP: + language = TXT_SPANISH; + break; + default: + language = TXT_ENGLISH; + } + ChangeLanguage(language); + + // load in graphics info + SetupHandleTable(); + + // Actors, globals and inventory icons + LoadBasicChunks(); + + return 0; +} + +Common::String TinselEngine::getSavegamePattern() const { + return _targetName + ".???"; +} + +Common::String TinselEngine::getSavegameFilename(int16 saveNum) const { + char filename[256]; + snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum); + return filename; +} + +#define GAME_FRAME_DELAY (1000 / ONE_SECOND) + +int TinselEngine::go() { + uint32 timerVal = 0; + + // Continuous game processes + CreateConstProcesses(); + + // allow game to run in the background + //RestartBackgroundProcess(); // FIXME: is this still needed? + + //dumpMusic(); // dumps all of the game's music in external XMIDI files + +#if 0 + // Load game from specified slot, if any + // FIXME: Not working correctly right now + if (ConfMan.hasKey("save_slot")) { + getList(); + RestoreGame(ConfMan.getInt("save_slot")); + } +#endif + + // Foreground loop + + while (!quitFlag) { + assert(_console); + if (_console->isAttached()) + _console->onFrame(); + + // Check for time to do next game cycle + if ((g_system->getMillis() > timerVal + GAME_FRAME_DELAY)) { + timerVal = g_system->getMillis(); + AudioCD.updateCD(); + NextGameCycle(); + } + + if (bRestart) { + RestartGame(); + bRestart = false; + bHasRestarted = true; // Set restarted flag + } + + // Save/Restore scene file transfers + ProcessSRQueue(); + +#ifdef DEBUG + if (bFast) + continue; // run flat-out +#endif + // Loop processing events while there are any pending + while (pollEvent()); + + g_system->delayMillis(10); + } + + // Write configuration + WriteConfig(); + + return 0; +} + + +void TinselEngine::NextGameCycle(void) { + // + ChangeScene(); + + // Allow a user event for this schedule + ResetEcount(); + + // schedule process + Scheduler(); + + // redraw background + DrawBackgnd(); + + // Why waste resources on yet another process? + FettleTimers(); +} + + +bool TinselEngine::pollEvent() { + if (!g_system->getEventManager()->pollEvent(_event)) + return false; + + // Handle the various kind of events + switch (_event.type) { + case Common::EVENT_QUIT: + quitFlag = true; + break; + + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + // Add button to queue for the mouse process + mouseButtons.push_back(_event.type); + break; + + case Common::EVENT_MOUSEMOVE: + _mousePos = _event.mouse; + break; + + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + KeyProcess(); + break; + + default: + break; + } + + return true; +} + +/** + * Start the processes that continue between scenes. + */ + +void TinselEngine::CreateConstProcesses(void) { + // Process to run the master script + CoroutineInstall(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); + + // Processes to run the cursor and inventory, + CoroutineInstall(PID_CURSOR, CursorProcess, NULL, 0); + CoroutineInstall(PID_INVENTORY, InventoryProcess, NULL, 0); +} + +/** + * Restart the game + */ + +void TinselEngine::RestartGame(void) { + HoldItem(INV_NOICON); // Holding nothing + + DropBackground(); // No background + + // Ditches existing infrastructure background + PrimeBackground(); + + // Next scene change won't need to fade out + // -> reset the count used by ChangeScene + CountOut = 1; + + RebootCursor(); + RebootDeadTags(); + RebootMovers(); + RebootTimers(); + RebootScalingReels(); + + DelayedScene.scene = HookScene.scene = 0; + + // remove keyboard, mouse and joystick drivers + ChopDrivers(); + + // Init palette and object managers, scheduler, keyboard and mouse + RestartDrivers(); + + // Actors, globals and inventory icons + LoadBasicChunks(); + + // Continuous game processes + CreateConstProcesses(); +} + +/** + * Init palette and object managers, scheduler, keyboard and mouse. + */ + +void TinselEngine::RestartDrivers(void) { + // init the palette manager + ResetPalAllocator(); + + // init the object manager + KillAllObjects(); + + // init the process scheduler + InitScheduler(); + + // init the event handlers + EventsInstall(); + + // install sound driver + SoundInit(); + + // Set midi volume + SetMidiVolume(volMidi); +} + +/** + * Remove keyboard, mouse and joystick drivers. + */ + +void TinselEngine::ChopDrivers(void) { + // remove sound driver + SoundDeinit(); + + // remove event drivers + EventsUninstall(); +} + +/** + * Process a keyboard event + */ + +void TinselEngine::KeyProcess(void) { + + // Handle any special keys immediately + switch (_event.kbd.keycode) { + case Common::KEYCODE_d: + if ((_event.kbd.flags == Common::KBD_CTRL) && (_event.type == Common::EVENT_KEYDOWN)) { + // Activate the debugger + assert(_console); + _console->attach(); + return; + } + break; + default: + break; + } + + // Check for movement keys + int idx = 0; + switch (_event.kbd.keycode) { + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: + idx = MSK_UP; + break; + case Common::KEYCODE_DOWN: + case Common::KEYCODE_KP2: + idx = MSK_DOWN; + break; + case Common::KEYCODE_LEFT: + case Common::KEYCODE_KP4: + idx = MSK_LEFT; + break; + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP6: + idx = MSK_RIGHT; + break; + default: + break; + } + if (idx != 0) { + if (_event.type == Common::EVENT_KEYDOWN) + _dosPlayerDir |= idx; + else + _dosPlayerDir &= ~idx; + return; + } + + // All other keypresses add to the queue for processing in KeyboardProcess + keypresses.push_back(_event); +} + +} // End of namespace Tinsel diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h new file mode 100644 index 0000000000..99136e0e7b --- /dev/null +++ b/engines/tinsel/tinsel.h @@ -0,0 +1,141 @@ +/* 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 TINSEL_H +#define TINSEL_H + +#include "common/scummsys.h" +#include "common/system.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/util.h" + +#include "sound/mididrv.h" +#include "sound/mixer.h" + +#include "engines/engine.h" +#include "tinsel/debugger.h" +#include "tinsel/graphics.h" +#include "tinsel/sound.h" + +namespace Tinsel { + +class MusicPlayer; +class SoundManager; + +enum TinselGameID { + GID_DW1 = 0, + GID_DW2 = 1 +}; + +enum TinselGameFeatures { + GF_DEMO = 1 << 0, + GF_CD = 1 << 1, + GF_FLOPPY = 1 << 2, + GF_SCNFILES = 1 << 3 +}; + +enum TinselEngineVersion { + TINSEL_V1 = 1 << 0, + TINSEL_V2 = 1 << 1 +}; + +struct TinselGameDescription; + +enum TinselKeyDirection { + MSK_LEFT = 1, MSK_RIGHT = 2, MSK_UP = 4, MSK_DOWN = 8, + MSK_DIRECTION = MSK_LEFT | MSK_RIGHT | MSK_UP | MSK_DOWN +}; + +typedef bool (*KEYFPTR)(const Common::KeyState &); + +class TinselEngine : public ::Engine { + int _gameId; + Common::KeyState _keyPressed; + Common::RandomSource _random; + Surface _screenSurface; + Common::Event _event; + Common::Point _mousePos; + uint8 _dosPlayerDir; + Console *_console; +protected: + + int init(); + int go(); + +public: + TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc); + virtual ~TinselEngine(); + int getGameId() { + return _gameId; + } + + const TinselGameDescription *_gameDescription; + uint32 getGameID() const; + uint32 getFeatures() const; + Common::Language getLanguage() const; + uint16 getVersion() const; + Common::Platform getPlatform() const; + bool quitFlag; + + SoundManager *_sound; + MusicPlayer *_music; + + KEYFPTR _keyHandler; +private: + //MusicPlayer *_music; + int _musicVolume; + + void NextGameCycle(void); + void CreateConstProcesses(void); + void RestartGame(void); + void RestartDrivers(void); + void ChopDrivers(void); + void KeyProcess(void); +public: + const Common::String getTargetName() const { return _targetName; } + Common::String getSavegamePattern() const; + Common::String getSavegameFilename(int16 saveNum) const; + Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; } + Surface &screen() { return _screenSurface; } + + bool pollEvent(); + Common::Event event() { return _event; } + Common::Point getMousePosition() const { return _mousePos; } + void setMousePosition(const Common::Point &pt) { + g_system->warpMouse(pt.x, pt.y); + _mousePos = pt; + } + void divertKeyInput(KEYFPTR fptr) { _keyHandler = fptr; } + int getRandomNumber(int maxNumber) { return _random.getRandomNumber(maxNumber); } + uint8 getKeyDirection() const { return _dosPlayerDir; } +}; + +// Global reference to the TinselEngine object +extern TinselEngine *_vm; + +} // End of namespace Tinsel + +#endif /* TINSEL_H */ diff --git a/engines/tinsel/token.cpp b/engines/tinsel/token.cpp new file mode 100644 index 0000000000..e50290c3f0 --- /dev/null +++ b/engines/tinsel/token.cpp @@ -0,0 +1,129 @@ +/* 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$ + * + * To ensure exclusive use of resources and exclusive control responsibilities. + */ + +#include "common/util.h" + +#include "tinsel/sched.h" +#include "tinsel/token.h" + +namespace Tinsel { + +//----------------- LOCAL GLOBAL DATA -------------------- + +struct Token { + PROCESS *proc; +}; + +static Token tokens[NUMTOKENS]; + + +/** + * Release all tokens held by this process, and kill the process. + */ +static void TerminateProcess(PROCESS *tProc) { + + // Release tokens held by the process + for (int i = 0; i < NUMTOKENS; i++) { + if (tokens[i].proc == tProc) { + tokens[i].proc = NULL; + } + } + + // Kill the process + ProcessKill(tProc); +} + +/** + * Gain control of the CONTROL token if it is free. + */ +void GetControlToken() { + const int which = TOKEN_CONTROL; + + if (tokens[which].proc == NULL) { + tokens[which].proc = CurrentProcess(); + } +} + +/** + * Release control of the CONTROL token. + */ +void FreeControlToken() { + // Allow anyone to free TOKEN_CONTROL + tokens[TOKEN_CONTROL].proc = NULL; +} + + +/** + * Gain control of a token. If the requested token is out of range, or + * is already held by the calling process, then the calling process + * will be killed off. + * + * Otherwise, the calling process will gain the token. If the token was + * held by another process, then the previous holder is killed off. + */ +void GetToken(int which) { + assert(TOKEN_LEAD <= which && which < NUMTOKENS); + + if (tokens[which].proc != NULL) { + assert(tokens[which].proc != CurrentProcess()); + TerminateProcess(tokens[which].proc); + } + + tokens[which].proc = CurrentProcess(); +} + +/** + * Release control of a token. If the requested token is not owned by + * the calling process, then the calling process will be killed off. + */ +void FreeToken(int which) { + assert(TOKEN_LEAD <= which && which < NUMTOKENS); + + assert(tokens[which].proc == CurrentProcess()); // we'd have been killed if some other proc had taken this token + + tokens[which].proc = NULL; +} + +/** + * If it's a valid token and it's free, returns true. + */ +bool TestToken(int which) { + if (which < 0 || which >= NUMTOKENS) + return false; + + return (tokens[which].proc == NULL); +} + +/** + * Call at the start of each scene. + */ +void FreeAllTokens(void) { + for (int i = 0; i < NUMTOKENS; i++) { + tokens[i].proc = NULL; + } +} + +} // end of namespace Tinsel diff --git a/engines/tinsel/token.h b/engines/tinsel/token.h new file mode 100644 index 0000000000..4ab4775bfb --- /dev/null +++ b/engines/tinsel/token.h @@ -0,0 +1,57 @@ +/* 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 TINSEL_TOKEN_H +#define TINSEL_TOKEN_H + +#include "tinsel/dw.h" + +namespace Tinsel { + +// Fixed tokens + +enum { + TOKEN_CONTROL = 0, + TOKEN_LEAD, // = TOKEN_CONTROL + 1 + TOKEN_LEFT_BUT = TOKEN_LEAD + MAX_MOVERS, + + NUMTOKENS // = TOKEN_LEFT_BUT + 1 +}; + +// Token functions + +void GetControlToken(); +void FreeControlToken(); + +void GetToken(int which); +void FreeToken(int which); + +void FreeAllTokens(void); +bool TestToken(int which); + + +} // end of namespace Tinsel + +#endif // TINSEL_TOKEN_H -- cgit v1.2.3 From bc2ec5afdeb9be3cc35b4e45f21d783c79cf6709 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 10:27:24 +0000 Subject: Got rid of some typedefs svn-id: r33235 --- engines/tinsel/actors.cpp | 2 +- engines/tinsel/actors.h | 3 +-- engines/tinsel/anim.cpp | 8 +++---- engines/tinsel/anim.h | 1 - engines/tinsel/background.cpp | 10 ++++----- engines/tinsel/background.h | 9 -------- engines/tinsel/handle.cpp | 2 +- engines/tinsel/heapmem.cpp | 50 +++++++++++++++++++++---------------------- engines/tinsel/heapmem.h | 21 +++++++++--------- 9 files changed, 47 insertions(+), 59 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp index e0689f1374..a385c26f6f 100644 --- a/engines/tinsel/actors.cpp +++ b/engines/tinsel/actors.cpp @@ -847,7 +847,7 @@ COLORREF getActorTcol(int ano) { /** * Store relevant information pertaining to currently existing actors. */ -int SaveActors(PSAVED_ACTOR sActorInfo) { +int SaveActors(SAVED_ACTOR *sActorInfo) { int i, j; for (i = 0, j = 0; i < NumActors; i++) { diff --git a/engines/tinsel/actors.h b/engines/tinsel/actors.h index 7707dd636d..91f54519d5 100644 --- a/engines/tinsel/actors.h +++ b/engines/tinsel/actors.h @@ -111,9 +111,8 @@ struct SAVED_ACTOR { short presRnum; //!< the present reel number short presX, presY; }; -typedef SAVED_ACTOR *PSAVED_ACTOR; -int SaveActors(PSAVED_ACTOR sActorInfo); +int SaveActors(SAVED_ACTOR *sActorInfo); void RestoreActorProcess(int id, INT_CONTEXT *pic); diff --git a/engines/tinsel/anim.cpp b/engines/tinsel/anim.cpp index 266c39bca8..95d834d88a 100644 --- a/engines/tinsel/anim.cpp +++ b/engines/tinsel/anim.cpp @@ -59,7 +59,7 @@ union ANI_SCRIPT { * Advance to next frame routine. * @param pAnim Animation data structure */ -SCRIPTSTATE DoNextFrame(PANIM pAnim) { +SCRIPTSTATE DoNextFrame(ANIM *pAnim) { // get a pointer to the script const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript); @@ -227,7 +227,7 @@ SCRIPTSTATE DoNextFrame(PANIM pAnim) { * @param hNewScript Script of multipart frames * @param aniSpeed Sets speed of animation in frames */ -void InitStepAnimScript(PANIM pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) { +void InitStepAnimScript(ANIM *pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) { OBJECT *pObj; // multi-object list iterator pAnim->aniDelta = 1; // will animate on next call to NextAnimRate @@ -247,7 +247,7 @@ void InitStepAnimScript(PANIM pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int * Execute the next command in a animation script. * @param pAnim Animation data structure */ -SCRIPTSTATE StepAnimScript(PANIM pAnim) { +SCRIPTSTATE StepAnimScript(ANIM *pAnim) { SCRIPTSTATE state; if (--pAnim->aniDelta == 0) { @@ -270,7 +270,7 @@ SCRIPTSTATE StepAnimScript(PANIM pAnim) { * @param pAnim Animation data structure * @param numFrames Number of frames to skip */ -void SkipFrames(PANIM pAnim, int numFrames) { +void SkipFrames(ANIM *pAnim, int numFrames) { // get a pointer to the script const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript); diff --git a/engines/tinsel/anim.h b/engines/tinsel/anim.h index a6ac574350..5b25292a6b 100644 --- a/engines/tinsel/anim.h +++ b/engines/tinsel/anim.h @@ -41,7 +41,6 @@ struct ANIM { uint32 hScript; //!< animation script handle int scriptIndex; //!< current position in animation script }; -typedef ANIM *PANIM; /*----------------------------------------------------------------------*\ diff --git a/engines/tinsel/background.cpp b/engines/tinsel/background.cpp index 05d36e9412..6c586e11d9 100644 --- a/engines/tinsel/background.cpp +++ b/engines/tinsel/background.cpp @@ -50,7 +50,7 @@ bool bNoScroll; void InitBackground(BACKGND *pBgnd) { int i; // playfield counter - PPLAYFIELD pPlayfield; // pointer to current playfield + PLAYFIELD *pPlayfield; // pointer to current playfield // set current background pCurBgnd = pBgnd; @@ -87,7 +87,7 @@ void InitBackground(BACKGND *pBgnd) { */ void PlayfieldSetPos(int which, int newXpos, int newYpos) { - PPLAYFIELD pPlayfield; // pointer to relavent playfield + PLAYFIELD *pPlayfield; // pointer to relavent playfield // make sure there is a background assert(pCurBgnd != NULL); @@ -114,7 +114,7 @@ void PlayfieldSetPos(int which, int newXpos, int newYpos) { */ void PlayfieldGetPos(int which, int *pXpos, int *pYpos) { - PPLAYFIELD pPlayfield; // pointer to relavent playfield + PLAYFIELD *pPlayfield; // pointer to relavent playfield // make sure there is a background assert(pCurBgnd != NULL); @@ -136,7 +136,7 @@ void PlayfieldGetPos(int which, int *pXpos, int *pYpos) { */ OBJECT *GetPlayfieldList(int which) { - PPLAYFIELD pPlayfield; // pointer to relavent playfield + PLAYFIELD *pPlayfield; // pointer to relavent playfield // make sure there is a background assert(pCurBgnd != NULL); @@ -159,7 +159,7 @@ OBJECT *GetPlayfieldList(int which) { void DrawBackgnd(void) { int i; // playfield counter - PPLAYFIELD pPlay; // playfield pointer + PLAYFIELD *pPlay; // playfield pointer int prevX, prevY; // save interger part of position Common::Point ptWin; // window top left diff --git a/engines/tinsel/background.h b/engines/tinsel/background.h index 7409fd0785..f4b5c82e94 100644 --- a/engines/tinsel/background.h +++ b/engines/tinsel/background.h @@ -53,8 +53,6 @@ struct BLOCK { short blkHeight; //!< block height SCNHANDLE hBlkBits; //!< block bitmap handle }; -typedef BLOCK *PBLOCK; - /** structure to define position of blocks, which block and which palette */ struct BLK_INFO { @@ -65,8 +63,6 @@ struct BLK_INFO { uint8 byBlkPal; //!< which palette - index into "blkPals" for this block int32 blkIndex; //!< which block - index into "blocks" }; -typedef BLK_INFO *PBLK_INFO; - /** background module structure - a module is a container for blocks */ struct MODULE { @@ -78,8 +74,6 @@ struct MODULE { BLK_INFO *blkInfo; //!< pointer to array of which block goes where //!< NOTE: This array must be sorted on x position }; -typedef MODULE *PMODULE; - /** * background module node structure - links a playfields modules together @@ -92,8 +86,6 @@ struct MOD_NODE { char *onDispList; //!< pointer to modules (block on object list) flags - should alloc 1 byte per block Common::Point ptModPos; //!< module world start position }; -typedef MOD_NODE *PMOD_NODE; - /** background playfield structure - a playfield is a container for modules */ struct PLAYFIELD { @@ -106,7 +98,6 @@ struct PLAYFIELD { Common::Rect rcClip; //!< clip rectangle for this playfield bool bMoved; //!< set when playfield has moved }; -typedef PLAYFIELD *PPLAYFIELD; /** multi-playfield background structure - a backgnd is a container of playfields */ struct BACKGND { diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index 610f23012f..11623516ec 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -57,7 +57,7 @@ bool bLockedScene = 0; struct MEMHANDLE { char szName[12]; //!< 00 - file name of graphics file int32 filesize; //!< 12 - file size and flags - PMEM_NODE pNode; //!< 16 - memory node for the graphics + MEM_NODE *pNode; //!< 16 - memory node for the graphics }; diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp index f3df3d4391..aff085d003 100644 --- a/engines/tinsel/heapmem.cpp +++ b/engines/tinsel/heapmem.cpp @@ -36,7 +36,7 @@ namespace Tinsel { MEM_NODE mnodeList[NUM_MNODES]; // pointer to the linked list of free mnodes -static PMEM_NODE pFreeMemNodes; +static MEM_NODE *pFreeMemNodes; #ifdef DEBUG // diagnostic mnode counters @@ -48,14 +48,14 @@ static int maxNodes; static MEM_NODE heapSentinel; // -static PMEM_NODE AllocMemNode(void); +static MEM_NODE *AllocMemNode(void); /** * Initialises the memory manager. */ void MemoryInit(void) { - PMEM_NODE pNode; + MEM_NODE *pNode; #ifdef DEBUG // clear number of nodes in use @@ -117,9 +117,9 @@ void MemoryStats(void) { /** * Allocate a mnode from the free list. */ -static PMEM_NODE AllocMemNode(void) { +static MEM_NODE *AllocMemNode(void) { // get the first free mnode - PMEM_NODE pMemNode = pFreeMemNodes; + MEM_NODE *pMemNode = pFreeMemNodes; // make sure a mnode is available assert(pMemNode); // Out of memory nodes @@ -144,7 +144,7 @@ static PMEM_NODE AllocMemNode(void) { * Return a mnode back to the free list. * @param pMemNode Node of the memory object */ -void FreeMemNode(PMEM_NODE pMemNode) { +void FreeMemNode(MEM_NODE *pMemNode) { // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); @@ -168,8 +168,8 @@ void FreeMemNode(PMEM_NODE pMemNode) { * @param bDiscard When set - will discard blocks to fullfill the request */ bool HeapCompact(long size, bool bDiscard) { - PMEM_NODE pHeap = &heapSentinel; - PMEM_NODE pPrev, pCur, pOldest; + MEM_NODE *pHeap = &heapSentinel; + MEM_NODE *pPrev, *pCur, *pOldest; long largest; // size of largest free block uint32 oldest; // time of the oldest discardable block @@ -268,9 +268,9 @@ bool HeapCompact(long size, bool bDiscard) { * @param flags Allocation attributes * @param size Number of bytes to allocate */ -PMEM_NODE MemoryAlloc(int flags, long size) { - PMEM_NODE pHeap = &heapSentinel; - PMEM_NODE pNode; +MEM_NODE *MemoryAlloc(int flags, long size) { + MEM_NODE *pHeap = &heapSentinel; + MEM_NODE *pNode; bool bCompacted = true; // set when heap has been compacted // compact the heap if we are allocating fixed memory @@ -297,13 +297,13 @@ PMEM_NODE MemoryAlloc(int flags, long size) { if (flags & DWM_FIXED) // lock the memory - return (PMEM_NODE)MemoryLock(pNode); + return (MEM_NODE *)MemoryLock(pNode); else // just return the node return pNode; } else { // allocate a node for the remainder of the free block - PMEM_NODE pTemp = AllocMemNode(); + MEM_NODE *pTemp = AllocMemNode(); // calc size of the free block long freeSize = pNode->size - size; @@ -326,7 +326,7 @@ PMEM_NODE MemoryAlloc(int flags, long size) { if (flags & DWM_ZEROINIT) memset(pNode->pBaseAddr, 0, size); - return (PMEM_NODE)MemoryLock(pNode); + return (MEM_NODE *)MemoryLock(pNode); } else { // place the free node before pNode pTemp->pBaseAddr = pNode->pBaseAddr; @@ -375,7 +375,7 @@ PMEM_NODE MemoryAlloc(int flags, long size) { * Discards the specified memory object. * @param pMemNode Node of the memory object */ -void MemoryDiscard(PMEM_NODE pMemNode) { +void MemoryDiscard(MEM_NODE *pMemNode) { // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); @@ -387,7 +387,7 @@ void MemoryDiscard(PMEM_NODE pMemNode) { if ((pMemNode->flags & DWM_DISCARDED) == 0) { // allocate a free node to replace this node - PMEM_NODE pTemp = AllocMemNode(); + MEM_NODE *pTemp = AllocMemNode(); // copy node data memcpy(pTemp, pMemNode, sizeof(MEM_NODE)); @@ -423,8 +423,8 @@ void MemoryDiscard(PMEM_NODE pMemNode) { * Frees the specified memory object and invalidates its node. * @param pMemNode Node of the memory object */ -void MemoryFree(PMEM_NODE pMemNode) { - PMEM_NODE pPrev, pNext; +void MemoryFree(MEM_NODE *pMemNode) { + MEM_NODE *pPrev, *pNext; // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); @@ -469,7 +469,7 @@ void MemoryFree(PMEM_NODE pMemNode) { * of the objects memory block. * @param pMemNode Node of the memory object */ -void *MemoryLock(PMEM_NODE pMemNode) { +void *MemoryLock(MEM_NODE *pMemNode) { // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); @@ -493,8 +493,8 @@ void *MemoryLock(PMEM_NODE pMemNode) { * @param size New size of block * @param flags How to reallocate the object */ -PMEM_NODE MemoryReAlloc(PMEM_NODE pMemNode, long size, int flags) { - PMEM_NODE pNew; +MEM_NODE *MemoryReAlloc(MEM_NODE *pMemNode, long size, int flags) { + MEM_NODE *pNew; // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); @@ -550,7 +550,7 @@ PMEM_NODE MemoryReAlloc(PMEM_NODE pMemNode, long size, int flags) { if (flags & DWM_FIXED) // lock the memory - return (PMEM_NODE)MemoryLock(pMemNode); + return (MEM_NODE *)MemoryLock(pMemNode); else // just return the node return pMemNode; @@ -560,7 +560,7 @@ PMEM_NODE MemoryReAlloc(PMEM_NODE pMemNode, long size, int flags) { * Unlocks a memory object. * @param pMemNode Node of the memory object */ -void MemoryUnlock(PMEM_NODE pMemNode) { +void MemoryUnlock(MEM_NODE *pMemNode) { // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); @@ -578,8 +578,8 @@ void MemoryUnlock(PMEM_NODE pMemNode) { * Retrieves the mnode associated with the specified pointer to a memory object. * @param pMem Address of memory object */ -PMEM_NODE MemoryHandle(void *pMem) { - PMEM_NODE pNode; +MEM_NODE *MemoryHandle(void *pMem) { + MEM_NODE *pNode; // search the DOS heap for (pNode = heapSentinel.pNext; pNode != &heapSentinel; pNode = pNode->pNext) { if (pNode->pBaseAddr == pMem) diff --git a/engines/tinsel/heapmem.h b/engines/tinsel/heapmem.h index c5d022b7f9..7fb85985a9 100644 --- a/engines/tinsel/heapmem.h +++ b/engines/tinsel/heapmem.h @@ -41,7 +41,6 @@ struct MEM_NODE { uint32 lruTime; // time when memory object was last accessed int flags; // allocation attributes }; -typedef MEM_NODE *PMEM_NODE; // allocation flags for the MemoryAlloc function #define DWM_FIXED 0x0001 // allocates fixed memory @@ -71,35 +70,35 @@ void MemoryInit(void); // initialises the memory manager void MemoryStats(void); // Shows the maximum number of mnodes used at once #endif -PMEM_NODE MemoryAlloc( // allocates the specified number of bytes from the heap +MEM_NODE *MemoryAlloc( // allocates the specified number of bytes from the heap int flags, // allocation attributes long size); // number of bytes to allocate void MemoryDiscard( // discards the specified memory object - PMEM_NODE pMemNode); // node of the memory object + MEM_NODE *pMemNode); // node of the memory object int MemoryFlags( // returns information about the specified memory object - PMEM_NODE pMemNode); // node of the memory object + MEM_NODE *pMemNode); // node of the memory object void MemoryFree( // frees the specified memory object and invalidates its node - PMEM_NODE pMemNode); // node of the memory object + MEM_NODE *pMemNode); // node of the memory object -PMEM_NODE MemoryHandle( // Retrieves the mnode associated with the specified pointer to a memory object +MEM_NODE *MemoryHandle( // Retrieves the mnode associated with the specified pointer to a memory object void *pMem); // address of memory object void *MemoryLock( // locks a memory object and returns a pointer to the first byte of the objects memory block - PMEM_NODE pMemNode); // node of the memory object + MEM_NODE *pMemNode); // node of the memory object -PMEM_NODE MemoryReAlloc( // changes the size or attributes of a specified memory object - PMEM_NODE pMemNode, // node of the memory object +MEM_NODE *MemoryReAlloc( // changes the size or attributes of a specified memory object + MEM_NODE *pMemNode, // node of the memory object long size, // new size of block int flags); // how to reallocate the object long MemorySize( // returns the size, in bytes, of the specified memory object - PMEM_NODE pMemNode); // node of the memory object + MEM_NODE *pMemNode); // node of the memory object void MemoryUnlock( // unlocks a memory object - PMEM_NODE pMemNode); // node of the memory object + MEM_NODE *pMemNode); // node of the memory object bool HeapCompact( // Allocates the specified number of bytes from the specified heap long size, // number of bytes to free up -- cgit v1.2.3 From 3595a9b2a4e8b34c24cd740e84687d7f804f51df Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 10:29:37 +0000 Subject: Removed some dead code svn-id: r33236 --- engines/tinsel/background.h | 42 ------------------------------------------ engines/tinsel/scene.cpp | 2 -- 2 files changed, 44 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/background.h b/engines/tinsel/background.h index f4b5c82e94..e95a80581e 100644 --- a/engines/tinsel/background.h +++ b/engines/tinsel/background.h @@ -46,50 +46,8 @@ enum { /** When module BLK_INFO list is this long, switch from a binary to linear search */ #define LINEAR_SEARCH 5 - -/** structure of each individual background block */ -struct BLOCK { - short blkWidth; //!< block width - short blkHeight; //!< block height - SCNHANDLE hBlkBits; //!< block bitmap handle -}; - -/** structure to define position of blocks, which block and which palette */ -struct BLK_INFO { - uint16 wBlkX; //!< x position of this block - uint16 wBlkY; //!< y position of this block - uint16 wBlkZ; //!< z position of this block - uint8 byBlkFlags; //!< block flags used for drawing object associated with this block - uint8 byBlkPal; //!< which palette - index into "blkPals" for this block - int32 blkIndex; //!< which block - index into "blocks" -}; - -/** background module structure - a module is a container for blocks */ -struct MODULE { - int modWidth; //!< width of module - int modHeight; //!< height of module - int numBlocks; //!< number of blocks in this module - BLOCK *blocks; //!< pointer to array of all blocks used by this module - uint32 *blkPals; //!< pointer to array of all palette handles used by the blocks in this module - BLK_INFO *blkInfo; //!< pointer to array of which block goes where - //!< NOTE: This array must be sorted on x position -}; - -/** - * background module node structure - links a playfields modules together - * and specifies each module position. It is done this way so that modules - * are position independent and can be reused within a playfield - */ -struct MOD_NODE { - MOD_NODE *pNext; //!< next module node - MODULE *pModule; //!< pointer to actual module definition - char *onDispList; //!< pointer to modules (block on object list) flags - should alloc 1 byte per block - Common::Point ptModPos; //!< module world start position -}; - /** background playfield structure - a playfield is a container for modules */ struct PLAYFIELD { - MOD_NODE *pModNode; //!< head of module node chain for this playfield OBJECT *pDispList; //!< object display list for this playfield frac_t fieldX; //!< current world x position of playfield frac_t fieldY; //!< current world y position of playfield diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp index 006efd7b25..fd4dfcacea 100644 --- a/engines/tinsel/scene.cpp +++ b/engines/tinsel/scene.cpp @@ -211,7 +211,6 @@ void PrimeBackground(void) // structure for playfields static PLAYFIELD playfield[] = { { // FIELD WORLD - NULL, // no modules NULL, // display list 0, // init field x 0, // init field y @@ -221,7 +220,6 @@ void PrimeBackground(void) false // moved flag }, { // FIELD STATUS - NULL, // no modules NULL, // display list 0, // init field x 0, // init field y -- cgit v1.2.3 From 33c34f2eb474fb4ce1256c5b389b1149e6e13a60 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 10:33:36 +0000 Subject: cleanup; removed const bNoScroll variable svn-id: r33237 --- engines/tinsel/background.cpp | 28 ++++++++++------------------ engines/tinsel/background.h | 7 ------- engines/tinsel/object.cpp | 5 ++++- 3 files changed, 14 insertions(+), 26 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/background.cpp b/engines/tinsel/background.cpp index 6c586e11d9..91d21b4e0b 100644 --- a/engines/tinsel/background.cpp +++ b/engines/tinsel/background.cpp @@ -34,15 +34,9 @@ namespace Tinsel { -// screen clipping rectangle -Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - // current background BACKGND *pCurBgnd = NULL; -// scroll flag - when set scrolling and velocity additions are paused -bool bNoScroll; - /** * Called to initialise a background. * @param pBgnd Pointer to data struct for current background @@ -175,26 +169,24 @@ void DrawBackgnd(void) { prevX = fracToInt(pPlay->fieldX); prevY = fracToInt(pPlay->fieldY); - if (!bNoScroll) { - // update scrolling - pPlay->fieldX += pPlay->fieldXvel; - pPlay->fieldY += pPlay->fieldYvel; + // update scrolling + pPlay->fieldX += pPlay->fieldXvel; + pPlay->fieldY += pPlay->fieldYvel; - // convert fixed point window pos to a int - ptWin.x = fracToInt(pPlay->fieldX); - ptWin.y = fracToInt(pPlay->fieldY); + // convert fixed point window pos to a int + ptWin.x = fracToInt(pPlay->fieldX); + ptWin.y = fracToInt(pPlay->fieldY); - // set the moved flag if the playfield has moved - if (prevX != ptWin.x || prevY != ptWin.y) - pPlay->bMoved = true; - } + // set the moved flag if the playfield has moved + if (prevX != ptWin.x || prevY != ptWin.y) + pPlay->bMoved = true; // sort the display list for this background - just in case somebody has changed object Z positions SortObjectList((OBJECT *)&pPlay->pDispList); // generate clipping rects for all objects that have moved etc. FindMovingObjects((OBJECT *)&pPlay->pDispList, &ptWin, - &pPlay->rcClip, bNoScroll, pPlay->bMoved); + &pPlay->rcClip, false, pPlay->bMoved); // clear playfield moved flag pPlay->bMoved = false; diff --git a/engines/tinsel/background.h b/engines/tinsel/background.h index e95a80581e..7b8d099446 100644 --- a/engines/tinsel/background.h +++ b/engines/tinsel/background.h @@ -71,13 +71,6 @@ struct BACKGND { }; -/** screen clipping rect */ -extern Common::Rect rcScreen; - -/** scroll flag - when set scrolling and velocity additions are paused */ -extern bool bNoScroll; - - /*----------------------------------------------------------------------*\ |* Background Function Prototypes *| \*----------------------------------------------------------------------*/ diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp index 5ec0ec46e6..6996cff64e 100644 --- a/engines/tinsel/object.cpp +++ b/engines/tinsel/object.cpp @@ -25,7 +25,7 @@ */ #include "tinsel/object.h" -#include "tinsel/background.h" // for rcScreen definition +#include "tinsel/background.h" #include "tinsel/cliprect.h" // object clip rect defs #include "tinsel/graphics.h" // low level interface #include "tinsel/handle.h" @@ -34,6 +34,9 @@ namespace Tinsel { +/** screen clipping rectangle */ +static const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + // list of all objects OBJECT *objectList = 0; -- cgit v1.2.3 From 55bf215ba4b6b6fe9cfb6d1a0035c1f62d804824 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 23 Jul 2008 14:19:31 +0000 Subject: Renamed opcodes 0x49 and 0x68: - Opcode 0x49: setDefaultMenuColor2 -> setDefaultMenuBgColor - Opcode 0x68: setDefaultMenuColor -> setPlayerCommandPosY svn-id: r33240 --- engines/cine/script.h | 4 ++-- engines/cine/script_fw.cpp | 18 ++++++++++-------- engines/cine/script_os.cpp | 4 ++-- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/cine/script.h b/engines/cine/script.h index fe39272c4c..c14b7c70d1 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -198,7 +198,7 @@ protected: int o1_blitAndFade(); int o1_fadeToBlack(); int o1_transformPaletteRange(); - int o1_setDefaultMenuColor2(); + int o1_setDefaultMenuBgColor(); int o1_palRotate(); int o1_break(); int o1_endScript(); @@ -213,7 +213,7 @@ protected: int o1_initializeZoneData(); int o1_setZoneDataEntry(); int o1_getZoneDataEntry(); - int o1_setDefaultMenuColor(); + int o1_setPlayerCommandPosY(); int o1_allowPlayerInput(); int o1_disallowPlayerInput(); int o1_changeDataDisk(); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 57b1e8f7b4..08d84d480f 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -135,7 +135,7 @@ const Opcode FWScript::_opcodeTable[] = { { &FWScript::o1_transformPaletteRange, "bbwww" }, /* 48 */ { 0, 0 }, - { &FWScript::o1_setDefaultMenuColor2, "b" }, + { &FWScript::o1_setDefaultMenuBgColor, "b" }, { &FWScript::o1_palRotate, "bbb" }, { 0, 0 }, /* 4C */ @@ -174,7 +174,7 @@ const Opcode FWScript::_opcodeTable[] = { { &FWScript::o1_setZoneDataEntry, "bw" }, { &FWScript::o1_getZoneDataEntry, "bb" }, /* 68 */ - { &FWScript::o1_setDefaultMenuColor, "b" }, + { &FWScript::o1_setPlayerCommandPosY, "b" }, { &FWScript::o1_allowPlayerInput, "" }, { &FWScript::o1_disallowPlayerInput, "" }, { &FWScript::o1_changeDataDisk, "b" }, @@ -1399,10 +1399,11 @@ int FWScript::o1_transformPaletteRange() { return 0; } -int FWScript::o1_setDefaultMenuColor2() { +/** Set the default background color used for message boxes. */ +int FWScript::o1_setDefaultMenuBgColor() { byte param = getNextByte(); - debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor2(%d)", _line, param); + debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuBgColor(%d)", _line, param); renderer->_messageBg = param; return 0; @@ -1568,10 +1569,11 @@ int FWScript::o1_getZoneDataEntry() { return 0; } -int FWScript::o1_setDefaultMenuColor() { +/** Set the player command string's vertical position on-screen. */ +int FWScript::o1_setPlayerCommandPosY() { byte param = getNextByte(); - debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor(%d)", _line, param); + debugC(5, kCineDebugScript, "Line: %d: setPlayerCommandPosY(%d)", _line, param); renderer->_cmdY = param; return 0; @@ -2380,7 +2382,7 @@ void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx) param = *(localScriptPtr + position); position++; - sprintf(lineBuffer, "setDefaultMenuColor2(%d)\n", param); + sprintf(lineBuffer, "setDefaultMenuBgColor(%d)\n", param); break; } @@ -2530,7 +2532,7 @@ void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx) param = *(localScriptPtr + position); position++; - sprintf(lineBuffer, "setDefaultMenuBoxColor(%d)\n", param); + sprintf(lineBuffer, "setPlayerCommandPosY(%d)\n", param); break; } diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index 78b6c55564..a764281758 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -131,7 +131,7 @@ const Opcode OSScript::_opcodeTable[] = { { &FWScript::o1_transformPaletteRange, "bbwww" }, /* 48 */ { 0, 0 }, - { &FWScript::o1_setDefaultMenuColor2, "b" }, + { &FWScript::o1_setDefaultMenuBgColor, "b" }, { &FWScript::o1_palRotate, "bbb" }, { 0, 0 }, /* 4C */ @@ -170,7 +170,7 @@ const Opcode OSScript::_opcodeTable[] = { { &FWScript::o1_setZoneDataEntry, "bw" }, { &FWScript::o1_getZoneDataEntry, "bb" }, /* 68 */ - { &FWScript::o1_setDefaultMenuColor, "b" }, + { &FWScript::o1_setPlayerCommandPosY, "b" }, { &FWScript::o1_allowPlayerInput, "" }, { &FWScript::o1_disallowPlayerInput, "" }, { &FWScript::o1_changeDataDisk, "b" }, /* Same as opcodes 0x95 and 0xA9. */ -- cgit v1.2.3 From 4acde448f5a70d924d15cfbd385901ff4ad79dda Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 14:42:27 +0000 Subject: Moved POLYGON struct into polygon.cpp; got rid of some more typedefs svn-id: r33241 --- engines/tinsel/polygons.cpp | 118 +++++++++++++++++++++++++++++++++----------- engines/tinsel/polygons.h | 69 ++------------------------ 2 files changed, 92 insertions(+), 95 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/polygons.cpp b/engines/tinsel/polygons.cpp index 21047afcf5..fb533a7040 100644 --- a/engines/tinsel/polygons.cpp +++ b/engines/tinsel/polygons.cpp @@ -37,11 +37,71 @@ namespace Tinsel { //----------------- LOCAL DEFINES -------------------- -#define MAXONROUTE 40 -typedef POLYGON *PPOLYGON; +// Note 7/10/94, with adjacency reduction ANKHMAP max is 3, UNSEEN max is 4 +// so reduced this back to 6 (from 12) for now. +#define MAXADJ 6 // Max number of known adjacent paths + +struct POLYGON { + + PTYPE polytype; // Polygon type + + int subtype; // refer type in REFER polygons + // NODE/NORMAL in PATH polygons + + int pIndex; // Index into compiled polygon data + + /* + * Data duplicated from compiled polygon data + */ + short cx[4]; // Corners (clockwise direction) + short cy[4]; + int polyID; + + /* For TAG and EXIT (and EFFECT in future?) polygons only */ + TSTATE tagState; + PSTATE pointState; + SCNHANDLE oTagHandle; // Override tag. + + /* For Path polygons only */ + bool tried; + + /* + * Internal derived data for speed and conveniance + * set up by FiddlyBit() + */ + short ptop; // + short pbottom; // Enclosing external rectangle + short pleft; // + short pright; // + + short ltop[4]; // + short lbottom[4]; // Rectangles enclosing each side + short lleft[4]; // + short lright[4]; // + + int a[4]; // y1-y2 } + int b[4]; // x2-x1 } See IsInPolygon() + long c[4]; // y1x2 - x1y2 } + + /* + * Internal derived data for speed and conveniance + * set up by PseudoCentre() + */ + int pcentrex; // Pseudo-centre + int pcentrey; // + + /** + * List of adjacent polygons. For Path polygons only. + * set up by SetPathAdjacencies() + */ + POLYGON *adjpaths[MAXADJ]; + +}; +#define MAXONROUTE 40 + #include "common/pack-start.h" // START STRUCT PACKING /** lineinfo struct - one per (node-1) in a node path */ @@ -97,7 +157,7 @@ static int MaxPolys = MAX_POLY; static POLYGON *Polys[MAX_POLY+1]; -static PPOLYGON Polygons = 0; +static POLYGON *Polygons = 0; static SCNHANDLE pHandle = 0; // } Set at start of each scene static int noofPolys = 0; // } @@ -105,9 +165,9 @@ static int noofPolys = 0; // } static POLYGON extraBlock; // Used for dynamic blocking static int pathsOnRoute = 0; -static PPOLYGON RoutePaths[MAXONROUTE]; +static const POLYGON *RoutePaths[MAXONROUTE]; -static PPOLYGON RouteEnd = 0; +static POLYGON *RouteEnd = 0; #ifdef DEBUG int highestYet = 0; @@ -121,7 +181,7 @@ int highestYet = 0; #define CHECK_HP_OR(mvar, str) assert((mvar >= 0 && mvar <= noofPolys) || mvar == MAX_POLY); #define CHECK_HP(mvar, str) assert(mvar >= 0 && mvar <= noofPolys); -static HPOLYGON PolyIndex(PPOLYGON pp) { +static HPOLYGON PolyIndex(const POLYGON *pp) { for (int j = 0; j <= MAX_POLY; j++) { if (Polys[j] == pp) return j; @@ -159,7 +219,7 @@ static HPOLYGON PolyIndex(PPOLYGON pp) { * have two polygon corners above it and two corners to the left of it. */ bool IsInPolygon(int xt, int yt, HPOLYGON hp) { - PPOLYGON pp; + const POLYGON *pp; int i; bool BeenTested = false; int pl = 0, pa = 0; @@ -234,7 +294,7 @@ HPOLYGON InPolygon(int xt, int yt, PTYPE type) { */ void BlockingCorner(HPOLYGON hp, int *x, int *y, int tarx, int tary) { - PPOLYGON pp; + const POLYGON *pp; int i; int xd, yd; // distance per axis int ThisD, SmallestD = 1000; @@ -365,7 +425,7 @@ void BlockingCorner(HPOLYGON hp, int *x, int *y, int tarx, int tary) { * The shortest of these gives the best point in the node path. */ void FindBestPoint(HPOLYGON hp, int *x, int *y, int *pline) { - PPOLYGON pp; + const POLYGON *pp; uint8 *pps; // Compiled polygon data const POLY *ptp; // Compiled polygon data @@ -501,7 +561,7 @@ void FindBestPoint(HPOLYGON hp, int *x, int *y, int *pline) { * Returns TRUE if two paths are asdjacent. */ bool IsAdjacentPath(HPOLYGON hPath1, HPOLYGON hPath2) { - PPOLYGON pp1, pp2; + const POLYGON *pp1, *pp2; CHECK_HP(hPath1, "Out of range polygon handle (4)"); CHECK_HP(hPath2, "Out of range polygon handle (500)"); @@ -519,8 +579,8 @@ bool IsAdjacentPath(HPOLYGON hPath1, HPOLYGON hPath2) { return false; } -static POLYGON *TryPath(POLYGON *last, POLYGON *whereto, POLYGON *current) { - PPOLYGON x; +static const POLYGON *TryPath(POLYGON *last, POLYGON *whereto, POLYGON *current) { + POLYGON *x; // For each path adjacent to this one for (int j = 0; j < MAXADJ; j++) { @@ -565,7 +625,6 @@ static HPOLYGON PathOnTheWay(HPOLYGON from, HPOLYGON to) { // Also, the overhead of computing a DFS again and again could be avoided // by computing a path matrix (like we do in the SCUMM engine). int i; - PPOLYGON p; CHECK_HP(from, "Out of range polygon handle (501a)"); CHECK_HP(to, "Out of range polygon handle (501b)"); @@ -574,14 +633,14 @@ static HPOLYGON PathOnTheWay(HPOLYGON from, HPOLYGON to) { return to; for (i = 0; i < MAX_POLY; i++) { // For each polygon.. - p = Polys[i]; + POLYGON *p = Polys[i]; if (p && p->polytype == PATH) //...if it's a path p->tried = false; } Polys[from]->tried = true; pathsOnRoute = 0; - p = TryPath(Polys[from], Polys[to], Polys[from]); + const POLYGON *p = TryPath(Polys[from], Polys[to], Polys[from]); assert(p != NULL); // Trying to find route between unconnected paths @@ -622,7 +681,7 @@ HPOLYGON getPathOnTheWay(HPOLYGON hFrom, HPOLYGON hTo) { */ int NearestEndNode(HPOLYGON hPath, int x, int y) { - PPOLYGON pp; + const POLYGON *pp; int d1, d2; uint8 *pps; // Compiled polygon data @@ -654,7 +713,7 @@ int NearestEndNode(HPOLYGON hPath, int x, int y) { */ int NearEndNode(HPOLYGON hSpath, HPOLYGON hDpath) { - PPOLYGON pSpath, pDpath; + const POLYGON *pSpath, *pDpath; int ns, nd; // 'top' nodes in each path int dist, NearDist; @@ -747,7 +806,7 @@ int NearestNodeWithin(HPOLYGON hNpath, int x, int y) { * destination path which falls within the source path. */ void NearestCorner(int *x, int *y, HPOLYGON hStartPoly, HPOLYGON hDestPoly) { - PPOLYGON psp, pdp; + const POLYGON *psp, *pdp; int j; int ncorn = 0; // nearest corner HPOLYGON hNpath = NOPOLY; // path containing nearest corner @@ -976,7 +1035,6 @@ struct TAGSTATE { int tid; bool enabled; }; -typedef TAGSTATE *PTAGSTATE; #define MAX_SCENES 256 #define MAX_TAGS 2048 @@ -1087,7 +1145,7 @@ void EnableBlock(int blockno) { * Convert a TAG to an EX_TAG poly. */ void DisableTag(int tagno) { - PTAGSTATE pts; + TAGSTATE *pts; for (int i = 0; i < MAX_POLY; i++) { if (Polys[i] && Polys[i]->polytype == TAG && Polys[i]->polyID == tagno) { @@ -1116,7 +1174,7 @@ void EnableTag(int tagno) { } } - PTAGSTATE pts; + TAGSTATE *pts; pts = &TagStates[SceneTags[currentTScene].offset]; for (int j = 0; j < SceneTags[currentTScene].nooftags; j++, pts++) { if (pts->tid == tagno) { @@ -1136,7 +1194,7 @@ void EnableExit(int exitno) { } } - PTAGSTATE pts; + TAGSTATE *pts; pts = &ExitStates[SceneExits[currentEScene].offset]; for (int j = 0; j < SceneExits[currentEScene].nooftags; j++, pts++) { if (pts->tid == exitno) { @@ -1150,7 +1208,7 @@ void EnableExit(int exitno) { * Convert a EXIT to an EX_EXIT poly. */ void DisableExit(int exitno) { - PTAGSTATE pts; + TAGSTATE *pts; for (int i = 0; i < MAX_POLY; i++) { if (Polys[i] && Polys[i]->polytype == EXIT && Polys[i]->polyID == exitno) { @@ -1195,7 +1253,7 @@ HPOLYGON GetPolyHandle(int i) { * initialised, to work out which paths are adjacent to which. */ static int DistinctCorners(HPOLYGON hp1, HPOLYGON hp2) { - PPOLYGON pp1, pp2; + const POLYGON *pp1, *pp2; int i, j; int retval = 0; @@ -1223,7 +1281,7 @@ static int DistinctCorners(HPOLYGON hp1, HPOLYGON hp2) { } static void SetPathAdjacencies() { - PPOLYGON p1, p2; // Polygon pointers + POLYGON *p1, *p2; // Polygon pointers // For each polygon.. for (int i1 = 0; i1 < MAX_POLY-1; i1++) { @@ -1276,7 +1334,7 @@ static void SetPathAdjacencies() { #ifdef DEBUG void CheckNPathIntegrity() { uint8 *pps; // Compiled polygon data - PPOLYGON rp; // Run-time polygon structure + const POLYGON *rp; // Run-time polygon structure HPOLYGON hp; const POLY *cp; // Compiled polygon structure int i, j; // Loop counters @@ -1346,7 +1404,7 @@ static void SetExBlocks() { * Called at the start of a scene, nobbles TAG polygons which should be dead. */ static void SetExTags(SCNHANDLE ph) { - PTAGSTATE pts; + TAGSTATE *pts; int i, j; for (i = 0; i < numScenesT; i++) { @@ -1388,7 +1446,7 @@ void SetExExits(SCNHANDLE ph) { #else static void SetExExits(SCNHANDLE ph) { #endif - PTAGSTATE pts; + TAGSTATE *pts; int i, j; for (i = 0; i < numScenesE; i++) { @@ -1549,7 +1607,7 @@ static void InitPath(const POLY *pp, bool NodePath, int pno) { } // Clear out ajacent path pointers - memset(p->adjpaths, 0, MAXADJ*sizeof(PPOLYGON)); + memset(p->adjpaths, 0, MAXADJ*sizeof(POLYGON *)); FiddlyBit(p); PseudoCentre(p); @@ -1637,7 +1695,7 @@ void InitPolygons(SCNHANDLE ph, int numPoly, bool bRestart) { if (Polygons == NULL) { // first time - allocate memory for process list - Polygons = (PPOLYGON)calloc(MaxPolys, sizeof(POLYGON)); + Polygons = (POLYGON *)calloc(MaxPolys, sizeof(POLYGON)); // make sure memory allocated if (Polygons == NULL) { diff --git a/engines/tinsel/polygons.h b/engines/tinsel/polygons.h index 464aa4e124..c0e75ed3e7 100644 --- a/engines/tinsel/polygons.h +++ b/engines/tinsel/polygons.h @@ -32,10 +32,6 @@ namespace Tinsel { -// Note 7/10/94, with adjacency reduction ANKHMAP max is 3, UNSEEN max is 4 -// so reduced this back to 6 (from 12) for now. -#define MAXADJ 6 // Max number of known adjacent paths - // Polygon Types enum PTYPE { @@ -44,8 +40,10 @@ enum PTYPE { }; // subtype -#define NORMAL 0 -#define NODE 1 // For paths +enum { + NORMAL = 0, + NODE = 1 // For paths +}; // tagState enum TSTATE { @@ -58,65 +56,6 @@ enum PSTATE { }; - -struct POLYGON { - - PTYPE polytype; // Polygon type - - int subtype; // refer type in REFER polygons - // NODE/NORMAL in PATH polygons - - int pIndex; // Index into compiled polygon data - - /* - * Data duplicated from compiled polygon data - */ - short cx[4]; // Corners (clockwise direction) - short cy[4]; - int polyID; - - /* For TAG and EXIT (and EFFECT in future?) polygons only */ - TSTATE tagState; - PSTATE pointState; - SCNHANDLE oTagHandle; // Override tag. - - /* For Path polygons only */ - bool tried; - - /* - * Internal derived data for speed and conveniance - * set up by FiddlyBit() - */ - short ptop; // - short pbottom; // Enclosing external rectangle - short pleft; // - short pright; // - - short ltop[4]; // - short lbottom[4]; // Rectangles enclosing each side - short lleft[4]; // - short lright[4]; // - - int a[4]; // y1-y2 } - int b[4]; // x2-x1 } See IsInPolygon() - long c[4]; // y1x2 - x1y2 } - - /* - * Internal derived data for speed and conveniance - * set up by PseudoCentre() - */ - int pcentrex; // Pseudo-centre - int pcentrey; // - - /** - * List of adjacent polygons. For Path polygons only. - * set up by SetPathAdjacencies() - */ - POLYGON *adjpaths[MAXADJ]; - -}; - - enum { NOPOLY = -1 }; -- cgit v1.2.3 From 29a96430a06b415b9965f261785eb256224c8004 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 16:55:52 +0000 Subject: TINSEL: Renamed CoroutineInstall back to ProcessCreate; got rid of yet another typedef; more cleanup svn-id: r33249 --- engines/tinsel/actors.cpp | 4 ++-- engines/tinsel/bg.cpp | 2 +- engines/tinsel/effect.cpp | 2 +- engines/tinsel/events.cpp | 6 +++--- engines/tinsel/faders.cpp | 6 +++--- engines/tinsel/inventory.cpp | 4 ++-- engines/tinsel/object.cpp | 4 ++-- engines/tinsel/palette.cpp | 38 +++++++++++++++++++++++++++----------- engines/tinsel/palette.h | 25 ++++++------------------- engines/tinsel/play.cpp | 6 +++--- engines/tinsel/rince.cpp | 2 +- engines/tinsel/scene.cpp | 14 +++++++------- engines/tinsel/sched.cpp | 2 +- engines/tinsel/sched.h | 2 +- engines/tinsel/tinsel.cpp | 14 +++++++------- 15 files changed, 67 insertions(+), 64 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp index a385c26f6f..7ea2da28f6 100644 --- a/engines/tinsel/actors.cpp +++ b/engines/tinsel/actors.cpp @@ -230,7 +230,7 @@ static void ActorRestoredProcess(CORO_PARAM) { void RestoreActorProcess(int id, PINT_CONTEXT pic) { RATP_INIT r = { pic, id }; - CoroutineInstall(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); + ProcessCreate(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); } /** @@ -247,7 +247,7 @@ void actorEvent(int ano, USER_EVENT event, BUTEVENT be) { atp.id = ano; atp.event = event; atp.bev = be; - CoroutineInstall(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); + ProcessCreate(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); } } diff --git a/engines/tinsel/bg.cpp b/engines/tinsel/bg.cpp index cf7e18dc08..833c2fe37f 100644 --- a/engines/tinsel/bg.cpp +++ b/engines/tinsel/bg.cpp @@ -176,7 +176,7 @@ void startupBackground(SCNHANDLE bfilm) { // Start display process for each reel in the film assert(FROM_LE_32(pfilm->numreels) == 1); // Multi-reeled backgrounds withdrawn - CoroutineInstall(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); + ProcessCreate(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); } /** diff --git a/engines/tinsel/effect.cpp b/engines/tinsel/effect.cpp index 825825ccec..b75e186c74 100644 --- a/engines/tinsel/effect.cpp +++ b/engines/tinsel/effect.cpp @@ -102,7 +102,7 @@ static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) { epi.hEpoly = hPoly; epi.pActor = pActor; epi.index = index; - CoroutineInstall(PID_TCODE, EffectProcess, &epi, sizeof(epi)); + ProcessCreate(PID_TCODE, EffectProcess, &epi, sizeof(epi)); } } } diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp index 8064bdd3f3..311f1c0906 100644 --- a/engines/tinsel/events.cpp +++ b/engines/tinsel/events.cpp @@ -184,13 +184,13 @@ static void PolyTinselProcess(CORO_PARAM) { void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc) { TP_INIT to = { hPoly, event, be, tc, 0 }; - CoroutineInstall(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + ProcessCreate(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); } void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor) { TP_INIT to = { hPoly, event, BE_NONE, false, actor }; - CoroutineInstall(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + ProcessCreate(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); } //----------------------------------------------------------------------- @@ -233,7 +233,7 @@ static void WalkProcess(CORO_PARAM) { void walkto(int x, int y) { WP_INIT to = { x, y }; - CoroutineInstall(PID_TCODE, WalkProcess, &to, sizeof(to)); + ProcessCreate(PID_TCODE, WalkProcess, &to, sizeof(to)); } /** diff --git a/engines/tinsel/faders.cpp b/engines/tinsel/faders.cpp index 9ac742800f..3b3940fa9c 100644 --- a/engines/tinsel/faders.cpp +++ b/engines/tinsel/faders.cpp @@ -35,7 +35,7 @@ namespace Tinsel { /** structure used by the "FadeProcess" process */ struct FADE { const long *pColourMultTable; // list of fixed point colour multipliers - terminated with negative entry - PPALQ pPalQ; // palette queue entry to fade + PALQ *pPalQ; // palette queue entry to fade }; // fixed point fade multiplier tables @@ -120,7 +120,7 @@ static void FadeProcess(CORO_PARAM) { * @param noFadeTable List of palettes not to fade */ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) { - PPALQ pPal; // palette manager iterator + PALQ *pPal; // palette manager iterator // create a process for each palette in the palette queue for (pPal = GetNextPalette(NULL); pPal != NULL; pPal = GetNextPalette(pPal)) { @@ -149,7 +149,7 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) { fade.pPalQ = pPal; // create a fader process for this palette - CoroutineInstall(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); + ProcessCreate(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); } } } diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp index 96ee01edf6..9c07748ab3 100644 --- a/engines/tinsel/inventory.cpp +++ b/engines/tinsel/inventory.cpp @@ -980,7 +980,7 @@ void RunInvTinselCode(PINV_OBJECT pinvo, USER_EVENT event, BUTEVENT be, int inde return; GlitterIndex = index; - CoroutineInstall(PID_TCODE, InvTinselProcess, &to, sizeof(to)); + ProcessCreate(PID_TCODE, InvTinselProcess, &to, sizeof(to)); } /**************************************************************************/ @@ -3938,7 +3938,7 @@ void InvPickup(int index) { else if (!(invObj->attribute & IO_ONLYINV1 && ino !=INV_1) && !(invObj->attribute & IO_ONLYINV2 && ino !=INV_2)) - CoroutineInstall(PID_TCODE, InvPdProcess, &index, sizeof(index)); + ProcessCreate(PID_TCODE, InvPdProcess, &index, sizeof(index)); } } } diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp index 6996cff64e..a708cd36d7 100644 --- a/engines/tinsel/object.cpp +++ b/engines/tinsel/object.cpp @@ -365,7 +365,7 @@ OBJECT *InitObject(const OBJ_INIT *pInitTbl) { // get pointer to image if (pInitTbl->hObjImg) { int aniX, aniY; // objects animation offsets - PPALQ pPalQ; // palette queue pointer + PALQ *pPalQ; // palette queue pointer const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image // allocate a palette for this object @@ -477,7 +477,7 @@ void AnimateObject(OBJECT *pAniObj, SCNHANDLE hNewImg) { OBJECT *RectangleObject(SCNHANDLE hPal, int colour, int width, int height) { // template for initialising the rectangle object static const OBJ_INIT rectObj = {0, DMA_CONST, OID_EFFECTS, 0, 0, 0}; - PPALQ pPalQ; // palette queue pointer + PALQ *pPalQ; // palette queue pointer // allocate and init a new object OBJECT *pRect = InitObject(&rectObj); diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp index 50a908afe3..130e58ec5f 100644 --- a/engines/tinsel/palette.cpp +++ b/engines/tinsel/palette.cpp @@ -34,6 +34,22 @@ namespace Tinsel { +//----------------- LOCAL DEFINES -------------------- + +/** video DAC transfer Q structure */ +struct VIDEO_DAC_Q { + union { + SCNHANDLE hRGBarray; //!< handle of palette or + COLORREF *pRGBarray; //!< list of palette colours + } pal; + bool bHandle; //!< when set - use handle of palette + int destDACindex; //!< start index of palette in video DAC + int numColours; //!< number of colours in "hRGBarray" +}; + + +//----------------- LOCAL GLOBAL DATA -------------------- + /** background colour */ static COLORREF bgndColour = BLACK; @@ -67,8 +83,8 @@ static int maxDACQ = 0; * Transfer palettes in the palette Q to Video DAC. */ void PalettesToVideoDAC(void) { - PPALQ pPalQ; // palette Q iterator - PVIDEO_DAC_Q pDACtail = vidDACdata; // set tail pointer + PALQ *pPalQ; // palette Q iterator + VIDEO_DAC_Q *pDACtail = vidDACdata; // set tail pointer bool needUpdate = false; // while Q is not empty @@ -198,10 +214,10 @@ void UpdateDACqueue(int posInDAC, int numColours, COLORREF *pColours) { * Allocate a palette. * @param hNewPal Palette to allocate */ -PPALQ AllocPalette(SCNHANDLE hNewPal) { - PPALQ pPrev, p; // walks palAllocData +PALQ *AllocPalette(SCNHANDLE hNewPal) { + PALQ *pPrev, *p; // walks palAllocData int iDAC; // colour index in video DAC - PPALQ pNxtPal; // next PALQ struct in palette allocator + PALQ *pNxtPal; // next PALQ struct in palette allocator PALETTE *pNewPal; // get pointer to new palette @@ -274,7 +290,7 @@ PPALQ AllocPalette(SCNHANDLE hNewPal) { * Free a palette allocated with "AllocPalette". * @param pFreePal Palette queue entry to free */ -void FreePalette(PPALQ pFreePal) { +void FreePalette(PALQ *pFreePal) { // validate palette Q pointer assert(pFreePal >= palAllocData && pFreePal <= palAllocData + NUM_PALETTES - 1); @@ -299,8 +315,8 @@ void FreePalette(PPALQ pFreePal) { * Find the specified palette. * @param hSrchPal Hardware palette to search for */ -PPALQ FindPalette(SCNHANDLE hSrchPal) { - PPALQ pPal; // palette allocator iterator +PALQ *FindPalette(SCNHANDLE hSrchPal) { + PALQ *pPal; // palette allocator iterator // search all structs in palette allocator for (pPal = palAllocData; pPal < palAllocData + NUM_PALETTES; pPal++) { @@ -318,7 +334,7 @@ PPALQ FindPalette(SCNHANDLE hSrchPal) { * @param pPalQ Palette queue position * @param hNewPal New palette */ -void SwapPalette(PPALQ pPalQ, SCNHANDLE hNewPal) { +void SwapPalette(PALQ *pPalQ, SCNHANDLE hNewPal) { // convert handle to palette pointer PALETTE *pNewPal = (PALETTE *)LockMem(hNewPal); @@ -336,7 +352,7 @@ void SwapPalette(PPALQ pPalQ, SCNHANDLE hNewPal) { } else { // # colours are different - will have to update all following palette entries - PPALQ pNxtPalQ; // next palette queue position + PALQ *pNxtPalQ; // next palette queue position for (pNxtPalQ = pPalQ + 1; pNxtPalQ < palAllocData + NUM_PALETTES; pNxtPalQ++) { if (pNxtPalQ->posInDAC >= pPalQ->posInDAC + pPalQ->numColours) @@ -362,7 +378,7 @@ void SwapPalette(PPALQ pPalQ, SCNHANDLE hNewPal) { * Statless palette iterator. Returns the next palette in the list * @param pStrtPal Palette to start from - when NULL will start from beginning of list */ -PPALQ GetNextPalette(PPALQ pStrtPal) { +PALQ *GetNextPalette(PALQ *pStrtPal) { if (pStrtPal == NULL) { // start of palette iteration - return 1st palette return (palAllocData[0].objCount) ? palAllocData : NULL; diff --git a/engines/tinsel/palette.h b/engines/tinsel/palette.h index ed648950fd..fdc4826dbd 100644 --- a/engines/tinsel/palette.h +++ b/engines/tinsel/palette.h @@ -67,18 +67,6 @@ enum { #define CYAN (RGB(0, MAX_INTENSITY, MAX_INTENSITY)) -/** video DAC transfer Q structure */ -struct VIDEO_DAC_Q { - union { - SCNHANDLE hRGBarray; //!< handle of palette or - COLORREF *pRGBarray; //!< list of palette colours - } pal; - bool bHandle; //!< when set - use handle of palette - int destDACindex; //!< start index of palette in video DAC - int numColours; //!< number of colours in "hRGBarray" -}; -typedef VIDEO_DAC_Q *PVIDEO_DAC_Q; - #include "common/pack-start.h" // START STRUCT PACKING /** hardware palette structure */ @@ -97,7 +85,6 @@ struct PALQ { int posInDAC; //!< palette position in the video DAC int numColours; //!< number of colours in the palette }; -typedef PALQ *PPALQ; #define PALETTE_MOVED 0x8000 // when this bit is set in the "posInDAC" @@ -129,21 +116,21 @@ void UpdateDACqueue( // places a palette in the video DAC queue int numColours, // number of colours in palette COLORREF *pColours); // list of RGB tripples -PPALQ AllocPalette( // allocate a new palette +PALQ *AllocPalette( // allocate a new palette SCNHANDLE hNewPal); // palette to allocate void FreePalette( // free a palette allocated with "AllocPalette" - PPALQ pFreePal); // palette queue entry to free + PALQ *pFreePal); // palette queue entry to free -PPALQ FindPalette( // find a palette in the palette queue +PALQ *FindPalette( // find a palette in the palette queue SCNHANDLE hSrchPal); // palette to search for void SwapPalette( // swaps palettes at the specified palette queue position - PPALQ pPalQ, // palette queue position + PALQ *pPalQ, // palette queue position SCNHANDLE hNewPal); // new palette -PPALQ GetNextPalette( // returns the next palette in the queue - PPALQ pStrtPal); // queue position to start from - when NULL will start from beginning of queue +PALQ *GetNextPalette( // returns the next palette in the queue + PALQ *pStrtPal); // queue position to start from - when NULL will start from beginning of queue COLORREF GetBgndColour(void); // returns current background colour diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp index 6daf851fd2..9b355a6da9 100644 --- a/engines/tinsel/play.cpp +++ b/engines/tinsel/play.cpp @@ -417,7 +417,7 @@ void playFilm(SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, newestFilm(film, &pfilm->reels[i]); ppi.column = i; - CoroutineInstall(PID_REEL, playProcess, &ppi, sizeof(ppi)); + ProcessCreate(PID_REEL, playProcess, &ppi, sizeof(ppi)); } } @@ -459,7 +459,7 @@ void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay newestFilm(film, &pfilm->reels[i]); _ctx->ppi.column = i; - CoroutineInstall(PID_REEL, playProcess, &_ctx->ppi, sizeof(PPINIT)); + ProcessCreate(PID_REEL, playProcess, &_ctx->ppi, sizeof(PPINIT)); } newestFilm(film, &pfilm->reels[0]); @@ -501,7 +501,7 @@ void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y) { newestFilm(film, &pfilm->reels[reelnum]); // Start display process for the reel - CoroutineInstall(PID_REEL, playProcess, &ppi, sizeof(ppi)); + ProcessCreate(PID_REEL, playProcess, &ppi, sizeof(ppi)); } } // end of namespace Tinsel diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp index 1ecf43f821..fbae8bc6b0 100644 --- a/engines/tinsel/rince.cpp +++ b/engines/tinsel/rince.cpp @@ -633,7 +633,7 @@ void MActorProcess(CORO_PARAM) { void MActorProcessCreate(int X, int Y, int id, PMACTOR pActor) { MActorProcessHelper(X, Y, id, pActor); - pActor->pProc = CoroutineInstall(PID_MACTOR, MActorProcess, &pActor, sizeof(PMACTOR)); + pActor->pProc = ProcessCreate(PID_MACTOR, MActorProcess, &pActor, sizeof(PMACTOR)); } diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp index fd4dfcacea..a7d48e2406 100644 --- a/engines/tinsel/scene.cpp +++ b/engines/tinsel/scene.cpp @@ -154,7 +154,7 @@ static void LoadScene(SCNHANDLE scene, int entry) { for (i = 0; i < FROM_LE_32(ss->numEntrance); i++, es++) { if (FROM_LE_32(es->eNumber) == (uint)entry) { if (es->hScript) - CoroutineInstall(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript)); + ProcessCreate(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript)); break; } } @@ -163,7 +163,7 @@ static void LoadScene(SCNHANDLE scene, int entry) { error("Non-existant scene entry number"); if (ss->hSceneScript) - CoroutineInstall(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript)); + ProcessCreate(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript)); } // Default refer type @@ -257,16 +257,16 @@ void PrimeScene(void) { RestartCursor(); // Restart the cursor EnableTags(); // Next scene with tags enabled - CoroutineInstall(PID_SCROLL, ScrollProcess, NULL, 0); - CoroutineInstall(PID_SCROLL, EffectPolyProcess, NULL, 0); + ProcessCreate(PID_SCROLL, ScrollProcess, NULL, 0); + ProcessCreate(PID_SCROLL, EffectPolyProcess, NULL, 0); #ifdef DEBUG if (ShowPosition) - CoroutineInstall(PID_POSITION, CursorPositionProcess, NULL, 0); + ProcessCreate(PID_POSITION, CursorPositionProcess, NULL, 0); #endif - CoroutineInstall(PID_TAG, TagProcess, NULL, 0); - CoroutineInstall(PID_TAG, PointProcess, NULL, 0); + ProcessCreate(PID_TAG, TagProcess, NULL, 0); + ProcessCreate(PID_TAG, PointProcess, NULL, 0); // init the current background PrimeBackground(); diff --git a/engines/tinsel/sched.cpp b/engines/tinsel/sched.cpp index 9391805040..0371449eb1 100644 --- a/engines/tinsel/sched.cpp +++ b/engines/tinsel/sched.cpp @@ -147,7 +147,7 @@ void Scheduler(void) { * @param pParam process specific info * @param sizeParam size of process specific info */ -PROCESS *CoroutineInstall(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) { +PROCESS *ProcessCreate(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) { PROCESS *pProc; // get a free process diff --git a/engines/tinsel/sched.h b/engines/tinsel/sched.h index 6b89a60891..51074b5c7d 100644 --- a/engines/tinsel/sched.h +++ b/engines/tinsel/sched.h @@ -69,7 +69,7 @@ void ProcessStats(void); // Shows the maximum number of process used at once void Scheduler(void); // called to start process dispatching -PROCESS *CoroutineInstall(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam); +PROCESS *ProcessCreate(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam); void ProcessKill( // kill a process PROCESS *pKillProc); // which process to kill (must be different from current one) diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index ec16e73294..8139e9f55d 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -386,8 +386,8 @@ void MouseProcess(CORO_PARAM) { void EventsInstall(void) { lastLeftClick = lastRightClick = DwGetCurrentTime(); - pMouseProcess = CoroutineInstall(PID_MOUSE, MouseProcess, NULL, 0); - pKeyboardProcess = CoroutineInstall(PID_KEYBOARD, KeyboardProcess, NULL, 0); + pMouseProcess = ProcessCreate(PID_MOUSE, MouseProcess, NULL, 0); + pKeyboardProcess = ProcessCreate(PID_KEYBOARD, KeyboardProcess, NULL, 0); } /** @@ -498,11 +498,11 @@ static void RestoredProcess(CORO_PARAM) { } void RestoreProcess(PINT_CONTEXT pic) { - CoroutineInstall(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); + ProcessCreate(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); } void RestoreMasterProcess(PINT_CONTEXT pic) { - CoroutineInstall(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); + ProcessCreate(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); } // FIXME: CountOut is used by ChangeScene @@ -868,11 +868,11 @@ bool TinselEngine::pollEvent() { void TinselEngine::CreateConstProcesses(void) { // Process to run the master script - CoroutineInstall(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); + ProcessCreate(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); // Processes to run the cursor and inventory, - CoroutineInstall(PID_CURSOR, CursorProcess, NULL, 0); - CoroutineInstall(PID_INVENTORY, InventoryProcess, NULL, 0); + ProcessCreate(PID_CURSOR, CursorProcess, NULL, 0); + ProcessCreate(PID_INVENTORY, InventoryProcess, NULL, 0); } /** -- cgit v1.2.3 From a5f280647b5cfab615f8ef8ce00e79af0f5a696b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 23 Jul 2008 17:01:42 +0000 Subject: cleanup svn-id: r33250 --- engines/tinsel/tinsel.cpp | 26 ++++++++++++++------------ engines/tinsel/tinsel.h | 7 +++---- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 8139e9f55d..76324e8272 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -288,7 +288,7 @@ void MouseProcess(CORO_PARAM) { _ctx->lastRWasDouble = false; while (true) { - // FIXME: I'm still keeping the ctrl/Alt handling in the KeyProcess method. + // FIXME: I'm still keeping the ctrl/Alt handling in the ProcessKeyEvent method. // Need to make sure that this works correctly //DragKeys(); @@ -829,11 +829,13 @@ void TinselEngine::NextGameCycle(void) { bool TinselEngine::pollEvent() { - if (!g_system->getEventManager()->pollEvent(_event)) + Common::Event event; + + if (!g_system->getEventManager()->pollEvent(event)) return false; // Handle the various kind of events - switch (_event.type) { + switch (event.type) { case Common::EVENT_QUIT: quitFlag = true; break; @@ -843,16 +845,16 @@ bool TinselEngine::pollEvent() { case Common::EVENT_RBUTTONDOWN: case Common::EVENT_RBUTTONUP: // Add button to queue for the mouse process - mouseButtons.push_back(_event.type); + mouseButtons.push_back(event.type); break; case Common::EVENT_MOUSEMOVE: - _mousePos = _event.mouse; + _mousePos = event.mouse; break; case Common::EVENT_KEYDOWN: case Common::EVENT_KEYUP: - KeyProcess(); + ProcessKeyEvent(event); break; default: @@ -952,12 +954,12 @@ void TinselEngine::ChopDrivers(void) { * Process a keyboard event */ -void TinselEngine::KeyProcess(void) { +void TinselEngine::ProcessKeyEvent(const Common::Event &event) { // Handle any special keys immediately - switch (_event.kbd.keycode) { + switch (event.kbd.keycode) { case Common::KEYCODE_d: - if ((_event.kbd.flags == Common::KBD_CTRL) && (_event.type == Common::EVENT_KEYDOWN)) { + if ((event.kbd.flags == Common::KBD_CTRL) && (event.type == Common::EVENT_KEYDOWN)) { // Activate the debugger assert(_console); _console->attach(); @@ -970,7 +972,7 @@ void TinselEngine::KeyProcess(void) { // Check for movement keys int idx = 0; - switch (_event.kbd.keycode) { + switch (event.kbd.keycode) { case Common::KEYCODE_UP: case Common::KEYCODE_KP8: idx = MSK_UP; @@ -991,7 +993,7 @@ void TinselEngine::KeyProcess(void) { break; } if (idx != 0) { - if (_event.type == Common::EVENT_KEYDOWN) + if (event.type == Common::EVENT_KEYDOWN) _dosPlayerDir |= idx; else _dosPlayerDir &= ~idx; @@ -999,7 +1001,7 @@ void TinselEngine::KeyProcess(void) { } // All other keypresses add to the queue for processing in KeyboardProcess - keypresses.push_back(_event); + keypresses.push_back(event); } } // End of namespace Tinsel diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 99136e0e7b..9370ba6817 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -76,7 +76,6 @@ class TinselEngine : public ::Engine { Common::KeyState _keyPressed; Common::RandomSource _random; Surface _screenSurface; - Common::Event _event; Common::Point _mousePos; uint8 _dosPlayerDir; Console *_console; @@ -113,7 +112,9 @@ private: void RestartGame(void); void RestartDrivers(void); void ChopDrivers(void); - void KeyProcess(void); + void ProcessKeyEvent(const Common::Event &event); + bool pollEvent(); + public: const Common::String getTargetName() const { return _targetName; } Common::String getSavegamePattern() const; @@ -121,8 +122,6 @@ public: Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; } Surface &screen() { return _screenSurface; } - bool pollEvent(); - Common::Event event() { return _event; } Common::Point getMousePosition() const { return _mousePos; } void setMousePosition(const Common::Point &pt) { g_system->warpMouse(pt.x, pt.y); -- cgit v1.2.3 From 627e0c277426b02153b79c82616ae7f351ad5bc3 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 24 Jul 2008 08:04:17 +0000 Subject: Can't test a SharedPtr for nullity! svn-id: r33258 --- engines/parallaction/input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index c26e28b377..dbc1090a40 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -188,7 +188,7 @@ void Input::trackMouse(ZonePtr z) { return; } - if (!z) { + if (z == nullZonePtr) { return; } -- cgit v1.2.3 From 69dac1d4f22f9a63a5a9030d4405ba071e5e8b89 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 24 Jul 2008 08:59:17 +0000 Subject: Moved scheduler / process managment code into a new class Scheduler svn-id: r33259 --- engines/tinsel/actors.cpp | 12 ++--- engines/tinsel/bg.cpp | 6 +-- engines/tinsel/coroutine.h | 69 ++++++++++++++++++--------- engines/tinsel/cursor.cpp | 2 +- engines/tinsel/effect.cpp | 8 ++-- engines/tinsel/events.cpp | 14 +++--- engines/tinsel/faders.cpp | 6 +-- engines/tinsel/inventory.cpp | 14 +++--- engines/tinsel/pcode.cpp | 20 ++++---- engines/tinsel/pdisplay.cpp | 6 +-- engines/tinsel/play.cpp | 10 ++-- engines/tinsel/rince.cpp | 10 ++-- engines/tinsel/savescn.cpp | 2 +- engines/tinsel/scene.cpp | 31 ++++++------ engines/tinsel/sched.cpp | 111 ++++++++++++++++++++++--------------------- engines/tinsel/sched.h | 110 +++++++++++++++++++++++------------------- engines/tinsel/scroll.cpp | 2 +- engines/tinsel/scroll.h | 2 +- engines/tinsel/tinlib.cpp | 2 +- engines/tinsel/tinsel.cpp | 76 ++++++++++++----------------- engines/tinsel/tinsel.h | 3 ++ engines/tinsel/token.cpp | 10 ++-- 22 files changed, 271 insertions(+), 255 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp index 7ea2da28f6..5e4a17fb65 100644 --- a/engines/tinsel/actors.cpp +++ b/engines/tinsel/actors.cpp @@ -174,14 +174,14 @@ struct ATP_INIT { /** * Runs actor's glitter code. */ -static void ActorTinselProcess(CORO_PARAM) { +static void ActorTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created - ATP_INIT *atp = (ATP_INIT *)ProcessGetParamsSelf(); + ATP_INIT *atp = (ATP_INIT *)param; CORO_BEGIN_CODE(_ctx); @@ -207,14 +207,14 @@ struct RATP_INIT { int id; // Actor number }; -static void ActorRestoredProcess(CORO_PARAM) { +static void ActorRestoredProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created - RATP_INIT *r = (RATP_INIT *)ProcessGetParamsSelf(); + RATP_INIT *r = (RATP_INIT *)param; CORO_BEGIN_CODE(_ctx); @@ -230,7 +230,7 @@ static void ActorRestoredProcess(CORO_PARAM) { void RestoreActorProcess(int id, PINT_CONTEXT pic) { RATP_INIT r = { pic, id }; - ProcessCreate(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); + g_scheduler->createProcess(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); } /** @@ -247,7 +247,7 @@ void actorEvent(int ano, USER_EVENT event, BUTEVENT be) { atp.id = ano; atp.event = event; atp.bev = be; - ProcessCreate(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); + g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); } } diff --git a/engines/tinsel/bg.cpp b/engines/tinsel/bg.cpp index 833c2fe37f..922e21bd18 100644 --- a/engines/tinsel/bg.cpp +++ b/engines/tinsel/bg.cpp @@ -93,7 +93,7 @@ int BackgroundHeight(void) { /** * Run main animation that comprises the scene background. */ -static void BGmainProcess(CORO_PARAM) { +static void BGmainProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -104,7 +104,7 @@ static void BGmainProcess(CORO_PARAM) { const MULTI_INIT *pmi; // get the stuff copied to process when it was created - pfr = (const FREEL *)ProcessGetParamsSelf(); + pfr = (const FREEL *)param; if (pBG == NULL) { /*** At start of scene ***/ @@ -176,7 +176,7 @@ void startupBackground(SCNHANDLE bfilm) { // Start display process for each reel in the film assert(FROM_LE_32(pfilm->numreels) == 1); // Multi-reeled backgrounds withdrawn - ProcessCreate(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); + g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); } /** diff --git a/engines/tinsel/coroutine.h b/engines/tinsel/coroutine.h index 4a8997fe00..e0292735bb 100644 --- a/engines/tinsel/coroutine.h +++ b/engines/tinsel/coroutine.h @@ -30,15 +30,36 @@ namespace Tinsel { -// The following is loosely based on , -// Proper credit to Simon Tatham shall be given. - /* + * The following is loosely based on an article by Simon Tatham: + * . + * However, many improvements and tweaks have been made, in particular + * by taking advantage of C++ features not available in C. + * + * Why is this code here? Well, the Tinsel engine apparently used + * setjmp/longjmp based coroutines as a core tool from the start, and + * so they are deeply ingrained into the whole code base. When we + * started to get Tinsel ready for ScummVM, we had to deal with that. + * It soon got clear that we could not simply rewrite the code to work + * without some form of coroutines. While possible in principle, it + * would have meant a major restructuring of the entire code base, a + * rather daunting task. Also, it would have very likely introduced + * tons of regressons. + * + * So instead of getting rid of the coroutines, we chose to implement + * them in an alternate way, using Simon Tatham's trick as described + * above. While the trick is dirty, the result seems to be clear enough, + * we hope; plus, it allowed us to stay relatively close to the + * original structure of the code, which made it easier to avoid + * regressions, and will be helpful in the future when comparing things + * against the original code base. + */ - * `ccr' macros for re-entrant coroutines. +/** + * The core of any coroutine context which captures the 'state' of a coroutine. + * Private use only */ - struct CoroBaseContext { int _line; int _sleep; @@ -53,16 +74,28 @@ typedef CoroBaseContext *CoroContext; /** * Wrapper class which holds a pointer to a pointer to a CoroBaseContext. * The interesting part is the destructor, which kills the context being held, - * but ONLY if the _sleep val of that context is zero. + * but ONLY if the _sleep val of that context is zero. This way, a coroutine + * can just 'return' w/o having to worry about freeing the allocated context + * (in Simon Tatham's original code, one had to use a special macro to + * return from a coroutine). */ -struct CoroContextHolder { +class CoroContextHolder { CoroContext &_ctx; +public: CoroContextHolder(CoroContext &ctx) : _ctx(ctx) {} - ~CoroContextHolder() { if (_ctx && _ctx->_sleep == 0) { delete _ctx; _ctx = 0; } } + ~CoroContextHolder() { + if (_ctx && _ctx->_sleep == 0) { + delete _ctx; + _ctx = 0; + } + } }; + #define CORO_PARAM CoroContext &coroParam +#define CORO_SUBCTX coroParam->_subctx + #define CORO_BEGIN_CONTEXT struct CoroContextTag : CoroBaseContext { int DUMMY #define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam @@ -80,19 +113,18 @@ struct CoroContextHolder { #define CORO_SLEEP(delay) \ do {\ - coroParam->_line=__LINE__;\ - coroParam->_sleep=delay;\ + coroParam->_line = __LINE__;\ + coroParam->_sleep = delay;\ return; case __LINE__:;\ } while (0) -// Stop the currently running coroutine +/** Stop the currently running coroutine */ #define CORO_KILL_SELF() do { coroParam->_sleep = -1; return; } while(0) -//#define CORO_ABORT() do { delete (ctx); ctx = 0; } while (0) - +/** Invoke another coroutine */ #define CORO_INVOKE_ARGS(subCoro, ARGS) \ do {\ - coroParam->_line=__LINE__;\ + coroParam->_line = __LINE__;\ coroParam->_subctx = 0;\ do {\ subCoro ARGS;\ @@ -102,21 +134,12 @@ struct CoroContextHolder { } while(1);\ } while (0) -#define CORO_SUBCTX coroParam->_subctx - #define CORO_INVOKE_0(subCoroutine) \ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX)) #define CORO_INVOKE_1(subCoroutine, a0) \ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0)) #define CORO_INVOKE_2(subCoroutine, a0,a1) \ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1)) -#define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2)) -#define CORO_INVOKE_4(subCoroutine, a0,a1,a2,a3) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2,a3)) -#define CORO_INVOKE_5(subCoroutine, a0,a1,a2,a3,a4) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2,a3,a4)) - } // end of namespace Tinsel diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp index 087730c165..042c5b88e3 100644 --- a/engines/tinsel/cursor.cpp +++ b/engines/tinsel/cursor.cpp @@ -522,7 +522,7 @@ static void CursorStoppedCheck(CORO_PARAM) { /** * The main cursor process. */ -void CursorProcess(CORO_PARAM) { +void CursorProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); diff --git a/engines/tinsel/effect.cpp b/engines/tinsel/effect.cpp index b75e186c74..91645da71b 100644 --- a/engines/tinsel/effect.cpp +++ b/engines/tinsel/effect.cpp @@ -56,12 +56,12 @@ struct EP_INIT { * actor to leave that polygon. Then runs the polygon's Glitter code * with LEAVE event. */ -static void EffectProcess(CORO_PARAM) { +static void EffectProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); - EP_INIT *to = (EP_INIT *)ProcessGetParamsSelf(); // get the stuff copied to process when it was created + EP_INIT *to = (EP_INIT *)param; // get the stuff copied to process when it was created CORO_BEGIN_CODE(_ctx); @@ -102,7 +102,7 @@ static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) { epi.hEpoly = hPoly; epi.pActor = pActor; epi.index = index; - ProcessCreate(PID_TCODE, EffectProcess, &epi, sizeof(epi)); + g_scheduler->createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi)); } } } @@ -110,7 +110,7 @@ static void FettleEffectPolys(int x, int y, int index, PMACTOR pActor) { /** * Just calls FettleEffectPolys() every clock tick. */ -void EffectPolyProcess(CORO_PARAM) { +void EffectPolyProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp index 311f1c0906..dea699a75d 100644 --- a/engines/tinsel/events.cpp +++ b/engines/tinsel/events.cpp @@ -135,14 +135,14 @@ struct TP_INIT { /** * Runs glitter code associated with a polygon. */ -static void PolyTinselProcess(CORO_PARAM) { +static void PolyTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; bool took_control; // Set if this function takes control CORO_END_CONTEXT(_ctx); - TP_INIT *to = (TP_INIT *)ProcessGetParamsSelf(); // get the stuff copied to process when it was created + TP_INIT *to = (TP_INIT *)param; // get the stuff copied to process when it was created CORO_BEGIN_CODE(_ctx); @@ -184,13 +184,13 @@ static void PolyTinselProcess(CORO_PARAM) { void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc) { TP_INIT to = { hPoly, event, be, tc, 0 }; - ProcessCreate(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); } void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor) { TP_INIT to = { hPoly, event, BE_NONE, false, actor }; - ProcessCreate(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); } //----------------------------------------------------------------------- @@ -203,13 +203,13 @@ struct WP_INIT { /** * Perform a walk directly initiated by a click. */ -static void WalkProcess(CORO_PARAM) { +static void WalkProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PMACTOR pActor; CORO_END_CONTEXT(_ctx); - WP_INIT *to = (WP_INIT *)ProcessGetParamsSelf(); // get the co-ordinates - copied to process when it was created + WP_INIT *to = (WP_INIT *)param; // get the co-ordinates - copied to process when it was created CORO_BEGIN_CODE(_ctx); @@ -233,7 +233,7 @@ static void WalkProcess(CORO_PARAM) { void walkto(int x, int y) { WP_INIT to = { x, y }; - ProcessCreate(PID_TCODE, WalkProcess, &to, sizeof(to)); + g_scheduler->createProcess(PID_TCODE, WalkProcess, &to, sizeof(to)); } /** diff --git a/engines/tinsel/faders.cpp b/engines/tinsel/faders.cpp index 3b3940fa9c..0018727ccb 100644 --- a/engines/tinsel/faders.cpp +++ b/engines/tinsel/faders.cpp @@ -80,7 +80,7 @@ static void FadePalette(COLORREF *pNew, COLORREF *pOrig, int numColours, uint32 * A pointer to a 'FADE' structure must be passed to this process when * it is created. */ -static void FadeProcess(CORO_PARAM) { +static void FadeProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; COLORREF fadeRGB[MAX_COLOURS]; // local copy of palette @@ -89,7 +89,7 @@ static void FadeProcess(CORO_PARAM) { CORO_END_CONTEXT(_ctx); // get the fade data structure - copied to process when it was created - FADE *pFade = (FADE *)ProcessGetParamsSelf(); + FADE *pFade = (FADE *)param; CORO_BEGIN_CODE(_ctx); @@ -149,7 +149,7 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) { fade.pPalQ = pPal; // create a fader process for this palette - ProcessCreate(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); + g_scheduler->createProcess(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); } } } diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp index 9c07748ab3..aef171c2a2 100644 --- a/engines/tinsel/inventory.cpp +++ b/engines/tinsel/inventory.cpp @@ -932,7 +932,7 @@ struct ITP_INIT { /** * Run inventory item's Glitter code */ -static void InvTinselProcess(CORO_PARAM) { +static void InvTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; @@ -940,7 +940,7 @@ static void InvTinselProcess(CORO_PARAM) { CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created - ITP_INIT *to = (ITP_INIT *)ProcessGetParamsSelf(); + ITP_INIT *to = (ITP_INIT *)param; CORO_BEGIN_CODE(_ctx); @@ -980,7 +980,7 @@ void RunInvTinselCode(PINV_OBJECT pinvo, USER_EVENT event, BUTEVENT be, int inde return; GlitterIndex = index; - ProcessCreate(PID_TCODE, InvTinselProcess, &to, sizeof(to)); + g_scheduler->createProcess(PID_TCODE, InvTinselProcess, &to, sizeof(to)); } /**************************************************************************/ @@ -3005,7 +3005,7 @@ void CloseInventory(void) { /** * Redraws the icons if appropriate. Also handle button press/toggle effects */ -void InventoryProcess(CORO_PARAM) { +void InventoryProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -3901,7 +3901,7 @@ void InvPutDown(int index) { InvCursor(IC_DROP, aniX, aniY); } -void InvPdProcess(CORO_PARAM) { +void InvPdProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -3913,7 +3913,7 @@ void InvPdProcess(CORO_PARAM) { FreeToken(TOKEN_LEFT_BUT); // get the stuff copied to process when it was created - int *pindex = (int *)ProcessGetParamsSelf(); + int *pindex = (int *)param; InvPutDown(*pindex); @@ -3938,7 +3938,7 @@ void InvPickup(int index) { else if (!(invObj->attribute & IO_ONLYINV1 && ino !=INV_1) && !(invObj->attribute & IO_ONLYINV2 && ino !=INV_2)) - ProcessCreate(PID_TCODE, InvPdProcess, &index, sizeof(index)); + g_scheduler->createProcess(PID_TCODE, InvPdProcess, &index, sizeof(index)); } } } diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index 22b7ca8275..9408149ebd 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -126,13 +126,13 @@ static PINT_CONTEXT AllocateInterpretContext(GSORT gsort) { for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { if (pic->GSort == GS_NONE) { - pic->pProc = CurrentProcess(); + pic->pProc = g_scheduler->getCurrentProcess(); pic->GSort = gsort; return pic; } #ifdef DEBUG else { - if (pic->pProc == CurrentProcess()) + if (pic->pProc == g_scheduler->getCurrentProcess()) error("Found unreleased interpret context"); } #endif @@ -241,7 +241,7 @@ PINT_CONTEXT RestoreInterpretContext(PINT_CONTEXT ric) { ic = AllocateInterpretContext(GS_NONE); // Sort will soon be overridden memcpy(ic, ric, sizeof(INT_CONTEXT)); - ic->pProc = CurrentProcess(); + ic->pProc = g_scheduler->getCurrentProcess(); ic->resumeState = RES_1; LockCode(ic); @@ -268,7 +268,7 @@ void RegisterGlobals(int num) { error("Cannot allocate memory for interpret contexts"); } - SetResourceCallback(FreeInterpretContextPr); + g_scheduler->setResourceCallback(FreeInterpretContextPr); } else { // Check size is still the same assert(numGlobals == num); @@ -279,15 +279,11 @@ void RegisterGlobals(int num) { } void FreeGlobals(void) { - if (pGlobals) { - free(pGlobals); - pGlobals = NULL; - } + free(pGlobals); + pGlobals = NULL; - if (icList) { - free(icList); - icList = NULL; - } + free(icList); + icList = NULL; } /** diff --git a/engines/tinsel/pdisplay.cpp b/engines/tinsel/pdisplay.cpp index a51f13e62e..cf7f130ef6 100644 --- a/engines/tinsel/pdisplay.cpp +++ b/engines/tinsel/pdisplay.cpp @@ -92,7 +92,7 @@ static enum { TAGS_OFF, TAGS_ON } TagsActive = TAGS_ON; * This process is only started up if a Glitter showpos() call is made. * Obviously, this is for testing purposes only... */ -void CursorPositionProcess(CORO_PARAM) { +void CursorPositionProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; int prevsX, prevsY; // Last screen top left @@ -503,7 +503,7 @@ static bool PolyTag(SCNHANDLE *pTag, OBJECT **ppText) { * Handle display of tagged actor and polygon tags. * Tagged actor's get priority over polygons. */ -void TagProcess(CORO_PARAM) { +void TagProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; OBJECT *pText; // text object pointer @@ -577,7 +577,7 @@ static void leavingpoly(HPOLYGON hp) { * Maintain the polygons' pointState and tagState flags accordingly. * Also run the polygon's Glitter code when the cursor enters. */ -void PointProcess(CORO_PARAM) { +void PointProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp index 9b355a6da9..7c4f6be7e6 100644 --- a/engines/tinsel/play.cpp +++ b/engines/tinsel/play.cpp @@ -361,9 +361,9 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) { /** * Run all animations that comprise the play film. */ -static void playProcess(CORO_PARAM) { +static void playProcess(CORO_PARAM, const void *param) { // get the stuff copied to process when it was created - PPINIT *ppi = (PPINIT *)ProcessGetParamsSelf(); + PPINIT *ppi = (PPINIT *)param; PlayReel(coroParam, ppi); } @@ -417,7 +417,7 @@ void playFilm(SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, newestFilm(film, &pfilm->reels[i]); ppi.column = i; - ProcessCreate(PID_REEL, playProcess, &ppi, sizeof(ppi)); + g_scheduler->createProcess(PID_REEL, playProcess, &ppi, sizeof(ppi)); } } @@ -459,7 +459,7 @@ void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay newestFilm(film, &pfilm->reels[i]); _ctx->ppi.column = i; - ProcessCreate(PID_REEL, playProcess, &_ctx->ppi, sizeof(PPINIT)); + g_scheduler->createProcess(PID_REEL, playProcess, &_ctx->ppi, sizeof(PPINIT)); } newestFilm(film, &pfilm->reels[0]); @@ -501,7 +501,7 @@ void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y) { newestFilm(film, &pfilm->reels[reelnum]); // Start display process for the reel - ProcessCreate(PID_REEL, playProcess, &ppi, sizeof(ppi)); + g_scheduler->createProcess(PID_REEL, playProcess, &ppi, sizeof(ppi)); } } // end of namespace Tinsel diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp index fbae8bc6b0..2f8f055472 100644 --- a/engines/tinsel/rince.cpp +++ b/engines/tinsel/rince.cpp @@ -142,8 +142,8 @@ void KillMActor(PMACTOR pActor) { pActor->MActorState = NO_MACTOR; MultiDeleteObject(GetPlayfieldList(FIELD_WORLD), pActor->actorObj); pActor->actorObj = NULL; - assert(CurrentProcess() != pActor->pProc); - ProcessKill(pActor->pProc); + assert(g_scheduler->getCurrentProcess() != pActor->pProc); + g_scheduler->killProcess(pActor->pProc); } } @@ -604,12 +604,12 @@ static void MActorProcessHelper(int X, int Y, int id, PMACTOR pActor) { /** * Moving actor process - 1 per moving actor in current scene. */ -void MActorProcess(CORO_PARAM) { +void MActorProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); - PMACTOR pActor = *(PMACTOR *)ProcessGetParamsSelf(); + PMACTOR pActor = *(PMACTOR *)param; CORO_BEGIN_CODE(_ctx); @@ -633,7 +633,7 @@ void MActorProcess(CORO_PARAM) { void MActorProcessCreate(int X, int Y, int id, PMACTOR pActor) { MActorProcessHelper(X, Y, id, pActor); - pActor->pProc = ProcessCreate(PID_MACTOR, MActorProcess, &pActor, sizeof(PMACTOR)); + pActor->pProc = g_scheduler->createProcess(PID_MACTOR, MActorProcess, &pActor, sizeof(PMACTOR)); } diff --git a/engines/tinsel/savescn.cpp b/engines/tinsel/savescn.cpp index fa6e921a56..a21161e872 100644 --- a/engines/tinsel/savescn.cpp +++ b/engines/tinsel/savescn.cpp @@ -181,7 +181,7 @@ void sortActors(SAVED_DATA *rsd) { void ResumeInterprets(SAVED_DATA *rsd) { // Master script only affected on restore game, not restore scene if (rsd == &sgData) { - KillMatchingProcess(PID_MASTER_SCR, -1); + g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1); FreeMasterInterpretContext(); } diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp index a7d48e2406..ab48e26c4c 100644 --- a/engines/tinsel/scene.cpp +++ b/engines/tinsel/scene.cpp @@ -54,14 +54,14 @@ namespace Tinsel { extern void DropBackground(void); // in EFFECT.C -extern void EffectPolyProcess(CORO_PARAM); +extern void EffectPolyProcess(CORO_PARAM, const void *); // in PDISPLAY.C #ifdef DEBUG -extern void CursorPositionProcess(CORO_PARAM); +extern void CursorPositionProcess(CORO_PARAM, const void *); #endif -extern void TagProcess(CORO_PARAM); -extern void PointProcess(CORO_PARAM); +extern void TagProcess(CORO_PARAM, const void *); +extern void PointProcess(CORO_PARAM, const void *); extern void EnableTags(void); @@ -102,14 +102,14 @@ static SCNHANDLE SceneHandle = 0; // Current scene handle - stored in case of Sa /** * Started up for scene script and entrance script. */ -static void SceneTinselProcess(CORO_PARAM) { +static void SceneTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created - SCNHANDLE *ss = (SCNHANDLE *)ProcessGetParamsSelf(); + SCNHANDLE *ss = (SCNHANDLE *)param; assert(*ss); // Must have some code to run CORO_BEGIN_CODE(_ctx); @@ -154,7 +154,7 @@ static void LoadScene(SCNHANDLE scene, int entry) { for (i = 0; i < FROM_LE_32(ss->numEntrance); i++, es++) { if (FROM_LE_32(es->eNumber) == (uint)entry) { if (es->hScript) - ProcessCreate(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript)); + g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &es->hScript, sizeof(es->hScript)); break; } } @@ -163,7 +163,7 @@ static void LoadScene(SCNHANDLE scene, int entry) { error("Non-existant scene entry number"); if (ss->hSceneScript) - ProcessCreate(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript)); + g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &ss->hSceneScript, sizeof(ss->hSceneScript)); } // Default refer type @@ -200,14 +200,13 @@ void EndScene(void) { KillAllObjects(); // kill all destructable process - KillMatchingProcess(PID_DESTROY, PID_DESTROY); + g_scheduler->killMatchingProcess(PID_DESTROY, PID_DESTROY); } /** * */ -void PrimeBackground(void) -{ +void PrimeBackground(void) { // structure for playfields static PLAYFIELD playfield[] = { { // FIELD WORLD @@ -257,16 +256,16 @@ void PrimeScene(void) { RestartCursor(); // Restart the cursor EnableTags(); // Next scene with tags enabled - ProcessCreate(PID_SCROLL, ScrollProcess, NULL, 0); - ProcessCreate(PID_SCROLL, EffectPolyProcess, NULL, 0); + g_scheduler->createProcess(PID_SCROLL, ScrollProcess, NULL, 0); + g_scheduler->createProcess(PID_SCROLL, EffectPolyProcess, NULL, 0); #ifdef DEBUG if (ShowPosition) - ProcessCreate(PID_POSITION, CursorPositionProcess, NULL, 0); + g_scheduler->createProcess(PID_POSITION, CursorPositionProcess, NULL, 0); #endif - ProcessCreate(PID_TAG, TagProcess, NULL, 0); - ProcessCreate(PID_TAG, PointProcess, NULL, 0); + g_scheduler->createProcess(PID_TAG, TagProcess, NULL, 0); + g_scheduler->createProcess(PID_TAG, PointProcess, NULL, 0); // init the current background PrimeBackground(); diff --git a/engines/tinsel/sched.cpp b/engines/tinsel/sched.cpp index 0371449eb1..72cfeaf6b0 100644 --- a/engines/tinsel/sched.cpp +++ b/engines/tinsel/sched.cpp @@ -30,36 +30,51 @@ namespace Tinsel { +Scheduler *g_scheduler = 0; -/** list of all processes */ -static PROCESS *processList = 0; +/** process structure */ +struct PROCESS { + PROCESS *pNext; //!< pointer to next process in active or free list -/** active process list - also saves scheduler state */ -static PROCESS active; + CoroContext state; //!< the state of the coroutine + CORO_ADDR coroAddr; //!< the entry point of the coroutine -/** pointer to free process list */ -static PROCESS *pFreeProcesses = 0; + int sleepTime; //!< number of scheduler cycles to sleep + int pid; //!< process ID + char param[PARAM_SIZE]; //!< process specific info +}; -/** the currently active process */ -static PROCESS *pCurrent = 0; + +Scheduler::Scheduler() { + processList = 0; + pFreeProcesses = 0; + pCurrent = 0; #ifdef DEBUG -// diagnostic process counters -static int numProcs = 0; -static int maxProcs = 0; + // diagnostic process counters + numProcs = 0; + maxProcs = 0; #endif -/** - * Called from ProcessKill() to enable other resources - * a process may be allocated to be released. - */ -static VFPTRPP pRCfunction = 0; + pRCfunction = 0; + + active = new PROCESS; + + g_scheduler = this; // FIXME HACK +} +Scheduler::~Scheduler() { + free(processList); + processList = NULL; + + delete active; + active = 0; +} /** * Kills all processes and places them on the free list. */ -void InitScheduler(void) { +void Scheduler::reset() { #ifdef DEBUG // clear number of process in use @@ -80,7 +95,7 @@ void InitScheduler(void) { } // no active processes - pCurrent = active.pNext = NULL; + pCurrent = active->pNext = NULL; // place first process on free list pFreeProcesses = processList; @@ -94,19 +109,12 @@ void InitScheduler(void) { processList[NUM_PROCESS - 1].pNext = NULL; } -void FreeProcessList(void) { - if (processList) { - free(processList); - processList = NULL; - } -} - #ifdef DEBUG /** * Shows the maximum number of process used at once. */ -void ProcessStats(void) { +void Scheduler::printStats(void) { printf("%i process of %i used.\n", maxProcs, NUM_PROCESS); } #endif @@ -115,19 +123,19 @@ void ProcessStats(void) { /** * Give all active processes a chance to run */ -void Scheduler(void) { +void Scheduler::schedule(void) { // start dispatching active process list - PROCESS *pPrevProc = &active; - PROCESS *pProc = active.pNext; + PROCESS *pPrevProc = active; + PROCESS *pProc = active->pNext; while (pProc != NULL) { if (--pProc->sleepTime <= 0) { // process is ready for dispatch, activate it pCurrent = pProc; - pProc->coroAddr(pProc->state); + pProc->coroAddr(pProc->state, pProc->param); pCurrent = NULL; if (!pProc->state || pProc->state->_sleep <= 0) { // Coroutine finished - ProcessKill(pProc); + killProcess(pProc); pProc = pPrevProc; } else { pProc->sleepTime = pProc->state->_sleep; @@ -147,7 +155,7 @@ void Scheduler(void) { * @param pParam process specific info * @param sizeParam size of process specific info */ -PROCESS *ProcessCreate(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) { +PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) { PROCESS *pProc; // get a free process @@ -172,8 +180,8 @@ PROCESS *ProcessCreate(int pid, CORO_ADDR coroAddr, const void *pParam, int size // make this new process the next active process pCurrent->pNext = pProc; } else { // no active processes, place process at head of list - pProc->pNext = active.pNext; - active.pNext = pProc; + pProc->pNext = active->pNext; + active->pNext = pProc; } // set coroutine entry point @@ -206,13 +214,13 @@ PROCESS *ProcessCreate(int pid, CORO_ADDR coroAddr, const void *pParam, int size * * @param pKillProc which process to kill */ -void ProcessKill(PROCESS *pKillProc) { +void Scheduler::killProcess(PROCESS *pKillProc) { PROCESS *pProc, *pPrev; // process list pointers // make sure a valid process pointer assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1); - // can not kill the current process using ProcessKill ! + // can not kill the current process using killProcess ! assert(pCurrent != pKillProc); #ifdef DEBUG @@ -222,7 +230,7 @@ void ProcessKill(PROCESS *pKillProc) { #endif // search the active list for the process - for (pProc = active.pNext, pPrev = &active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { + for (pProc = active->pNext, pPrev = active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { if (pProc == pKillProc) { // found process in active list @@ -246,7 +254,7 @@ void ProcessKill(PROCESS *pKillProc) { } // process not found in active list if we get to here - error("ProcessKill(): tried to kill a process not in the list of active processes"); + error("killProcess(): tried to kill a process not in the list of active processes"); } @@ -254,25 +262,18 @@ void ProcessKill(PROCESS *pKillProc) { /** * Returns a pointer to the currently running process. */ -PROCESS *CurrentProcess(void) { +PROCESS *Scheduler::getCurrentProcess(void) { return pCurrent; } -char *ProcessGetParamsSelf() { - PROCESS *pProc = pCurrent; - - // make sure a valid process pointer - assert(pProc >= processList && pProc <= processList + NUM_PROCESS - 1); - - return pProc->param; -} - /** * Returns the process identifier of the specified process. * * @param pProc which process */ -int ProcessGetPID(PROCESS *pProc) { +int Scheduler::getCurrentPID() const { + PROCESS *pProc = pCurrent; + // make sure a valid process pointer assert(pProc >= processList && pProc <= processList + NUM_PROCESS - 1); @@ -288,11 +289,11 @@ int ProcessGetPID(PROCESS *pProc) { * @param pidMask mask to apply to process identifiers before comparison * @return The number of processes killed is returned. */ -int KillMatchingProcess(int pidKill, int pidMask) { +int Scheduler::killMatchingProcess(int pidKill, int pidMask) { int numKilled = 0; PROCESS *pProc, *pPrev; // process list pointers - for (pProc = active.pNext, pPrev = &active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { + for (pProc = active->pNext, pPrev = active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { if ((pProc->pid & pidMask) == pidKill) { // found a matching process @@ -329,15 +330,15 @@ int KillMatchingProcess(int pidKill, int pidMask) { /** - * Set pointer to a function to be called by ProcessKill(). + * Set pointer to a function to be called by killProcess(). * * May be called by a resource allocator, the function supplied is - * called by ProcessKill() to allow the resource allocator to free + * called by killProcess() to allow the resource allocator to free * resources allocated to the dying process. * - * @param pFunc Function to be called by ProcessKill() + * @param pFunc Function to be called by killProcess() */ -void SetResourceCallback(VFPTRPP pFunc) { +void Scheduler::setResourceCallback(VFPTRPP pFunc) { pRCfunction = pFunc; } diff --git a/engines/tinsel/sched.h b/engines/tinsel/sched.h index 51074b5c7d..0d90b3bb9f 100644 --- a/engines/tinsel/sched.h +++ b/engines/tinsel/sched.h @@ -38,62 +38,72 @@ namespace Tinsel { // the maximum number of processes #define NUM_PROCESS 64 -typedef void (*CORO_ADDR)(CoroContext &); +typedef void (*CORO_ADDR)(CoroContext &, const void *); -// process structure +struct PROCESS; -struct PROCESS { - PROCESS *pNext; // pointer to next process in active or free list - - CoroContext state; // the state of the coroutine - CORO_ADDR coroAddr; // the entry point of the coroutine - - int sleepTime; // number of scheduler cycles to sleep - int pid; // process ID - char param[PARAM_SIZE]; // process specific info -}; - - -/*----------------------------------------------------------------------*\ -|* Scheduler Function Prototypes *| -\*----------------------------------------------------------------------*/ - -void InitScheduler(void); // called to init scheduler - kills all processes and places them on free list - -void FreeProcessList(void); - -#ifdef DEBUG -void ProcessStats(void); // Shows the maximum number of process used at once +/** + * Create and manage "processes" (really coroutines). + */ +class Scheduler { +public: + /** Pointer to a function of the form "void function(PPROCESS)" */ + typedef void (*VFPTRPP)(PROCESS *); + +private: + + /** list of all processes */ + PROCESS *processList; + + /** active process list - also saves scheduler state */ + PROCESS *active; + + /** pointer to free process list */ + PROCESS *pFreeProcesses; + + /** the currently active process */ + PROCESS *pCurrent; + +#ifdef DEBUG + // diagnostic process counters + int numProcs; + int maxProcs; #endif + + /** + * Called from killProcess() to enable other resources + * a process may be allocated to be released. + */ + VFPTRPP pRCfunction; + + +public: + + Scheduler(); + ~Scheduler(); + + void reset(); + + #ifdef DEBUG + void printStats(); + #endif + + void schedule(); + + PROCESS *createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam); + void killProcess(PROCESS *pKillProc); + + PROCESS *getCurrentProcess(); + int getCurrentPID() const; + int killMatchingProcess(int pidKill, int pidMask); + + + void setResourceCallback(VFPTRPP pFunc); -void Scheduler(void); // called to start process dispatching - -PROCESS *ProcessCreate(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam); - -void ProcessKill( // kill a process - PROCESS *pKillProc); // which process to kill (must be different from current one) - -PROCESS *CurrentProcess(void); // Returns a pointer to the currently running process - -int ProcessGetPID( // Returns the process identifier of the specified process - PROCESS *pProc); // which process - -char *ProcessGetParamsSelf(); - -int KillMatchingProcess( // kill any process matching the pid parameters - int pidKill, // process identifier of process to kill - int pidMask); // mask to apply to process identifiers before comparison - - -// Pointer to a function of the form "void function(PPROCESS)" -typedef void (*VFPTRPP)(PROCESS *); - -void SetResourceCallback(VFPTRPP pFunc); // May be called by a resource allocator, - // the function supplied is called by ProcessKill() - // to allow the resource allocator to free resources - // allocated to the dying process. +}; +extern Scheduler *g_scheduler; // FIXME: Temporary global var, to be used until everything has been OOifyied } // end of namespace Tinsel diff --git a/engines/tinsel/scroll.cpp b/engines/tinsel/scroll.cpp index 7c0b12730f..aa1bc67298 100644 --- a/engines/tinsel/scroll.cpp +++ b/engines/tinsel/scroll.cpp @@ -352,7 +352,7 @@ static void MonitorScroll(void) { /** * Decide when to scroll and scroll when decided to. */ -void ScrollProcess(CORO_PARAM) { +void ScrollProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); diff --git a/engines/tinsel/scroll.h b/engines/tinsel/scroll.h index 02ce2afd5b..ac903157f2 100644 --- a/engines/tinsel/scroll.h +++ b/engines/tinsel/scroll.h @@ -62,7 +62,7 @@ void DoScrollCursor(void); void SetNoScroll(int x1, int y1, int x2, int y2); void DropNoScrolls(void); -void ScrollProcess(CORO_PARAM); +void ScrollProcess(CORO_PARAM, const void *); void ScrollFocus(int actor); void ScrollTo(int x, int y, int iter); diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index a07a16a205..84904e5138 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -768,7 +768,7 @@ void newscene(CORO_PARAM, SCNHANDLE scene, int entrance, int transition) { #endif // Prevent code subsequent to this call running before scene changes - if (ProcessGetPID(CurrentProcess()) != PID_MASTER_SCR) + if (g_scheduler->getCurrentPID() != PID_MASTER_SCR) CORO_KILL_SELF(); CORO_END_CODE; } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 76324e8272..8cfc6d7d4d 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -71,13 +71,13 @@ extern void SetDoFadeIn(bool tf); extern void DropBackground(void); // In CURSOR.CPP -extern void CursorProcess(CORO_PARAM); +extern void CursorProcess(CORO_PARAM, const void *); // In INVENTORY.CPP -extern void InventoryProcess(CORO_PARAM); +extern void InventoryProcess(CORO_PARAM, const void *); // In SCENE.CPP -extern void PrimeBackground( void ); +extern void PrimeBackground(); extern void NewScene(SCNHANDLE scene, int entry); extern SCNHANDLE GetSceneHandle(void); @@ -111,8 +111,6 @@ static Scene DelayedScene = { 0, 0, 0 }; static bool bHookSuspend = false; -static uint32 lastLeftClick = 0, lastRightClick = 0; - static PROCESS *pMouseProcess = 0; static PROCESS *pKeyboardProcess = 0; @@ -127,7 +125,7 @@ Common::List keypresses; /** * Process to handle keypresses */ -void KeyboardProcess(CORO_PARAM) { +void KeyboardProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -275,17 +273,19 @@ void KeyboardProcess(CORO_PARAM) { /** * Process to handle changes in the mouse buttons. */ -void MouseProcess(CORO_PARAM) { +void MouseProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; bool lastLWasDouble; bool lastRWasDouble; + uint32 lastLeftClick, lastRightClick; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); _ctx->lastLWasDouble = false; _ctx->lastRWasDouble = false; + _ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime(); while (true) { // FIXME: I'm still keeping the ctrl/Alt handling in the ProcessKeyEvent method. @@ -305,7 +305,7 @@ void MouseProcess(CORO_PARAM) { switch (type) { case Common::EVENT_LBUTTONDOWN: // left button press - if (DwGetCurrentTime() - lastLeftClick < (uint32)dclickSpeed) { + if (DwGetCurrentTime() - _ctx->lastLeftClick < (uint32)dclickSpeed) { // signal left drag start ProcessButEvent(BE_LDSTART); @@ -329,9 +329,9 @@ void MouseProcess(CORO_PARAM) { // update click timer if (_ctx->lastLWasDouble == false) - lastLeftClick = DwGetCurrentTime(); + _ctx->lastLeftClick = DwGetCurrentTime(); else - lastLeftClick -= dclickSpeed; + _ctx->lastLeftClick -= dclickSpeed; // signal left drag end ProcessButEvent(BE_LDEND); @@ -340,7 +340,7 @@ void MouseProcess(CORO_PARAM) { case Common::EVENT_RBUTTONDOWN: // right button press - if (DwGetCurrentTime() - lastRightClick < (uint32)dclickSpeed) { + if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) { // signal right drag start ProcessButEvent(BE_RDSTART); @@ -364,9 +364,9 @@ void MouseProcess(CORO_PARAM) { // update click timer if (_ctx->lastRWasDouble == false) - lastRightClick = DwGetCurrentTime(); + _ctx->lastRightClick = DwGetCurrentTime(); else - lastRightClick -= dclickSpeed; + _ctx->lastRightClick -= dclickSpeed; // signal right drag end ProcessButEvent(BE_RDEND); @@ -379,31 +379,11 @@ void MouseProcess(CORO_PARAM) { CORO_END_CODE; } -/** - * Installs the event driver processes - */ - -void EventsInstall(void) { - lastLeftClick = lastRightClick = DwGetCurrentTime(); - - pMouseProcess = ProcessCreate(PID_MOUSE, MouseProcess, NULL, 0); - pKeyboardProcess = ProcessCreate(PID_KEYBOARD, KeyboardProcess, NULL, 0); -} - -/** - * Removes the event driver processes - */ - -void EventsUninstall(void) { - ProcessKill(pMouseProcess); - ProcessKill(pKeyboardProcess); -} - /** * Run the master script. * Continues between scenes, or until Interpret() returns. */ -static void MasterScriptProcess(CORO_PARAM) { +static void MasterScriptProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; @@ -480,7 +460,7 @@ void syncSCdata(Serializer &s) { //----------------------------------------------------------------------- -static void RestoredProcess(CORO_PARAM) { +static void RestoredProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; @@ -489,7 +469,7 @@ static void RestoredProcess(CORO_PARAM) { CORO_BEGIN_CODE(_ctx); // get the stuff copied to process when it was created - _ctx->pic = *((PINT_CONTEXT *)ProcessGetParamsSelf()); + _ctx->pic = *((PINT_CONTEXT *)param); _ctx->pic = RestoreInterpretContext(_ctx->pic); CORO_INVOKE_1(Interpret, _ctx->pic); @@ -498,11 +478,11 @@ static void RestoredProcess(CORO_PARAM) { } void RestoreProcess(PINT_CONTEXT pic) { - ProcessCreate(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); + g_scheduler->createProcess(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); } void RestoreMasterProcess(PINT_CONTEXT pic) { - ProcessCreate(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); + g_scheduler->createProcess(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); } // FIXME: CountOut is used by ChangeScene @@ -670,7 +650,7 @@ TinselEngine::~TinselEngine() { FreeActors(); FreeObjectList(); FreeGlobals(); - FreeProcessList(); + delete _scheduler; } int TinselEngine::init() { @@ -685,6 +665,8 @@ int TinselEngine::init() { g_system->getEventManager()->registerRandomSource(_random, "tinsel"); _console = new Console(); + + _scheduler = new Scheduler(); // init memory manager MemoryInit(); @@ -818,7 +800,7 @@ void TinselEngine::NextGameCycle(void) { ResetEcount(); // schedule process - Scheduler(); + _scheduler->schedule(); // redraw background DrawBackgnd(); @@ -870,11 +852,11 @@ bool TinselEngine::pollEvent() { void TinselEngine::CreateConstProcesses(void) { // Process to run the master script - ProcessCreate(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); + _scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); // Processes to run the cursor and inventory, - ProcessCreate(PID_CURSOR, CursorProcess, NULL, 0); - ProcessCreate(PID_INVENTORY, InventoryProcess, NULL, 0); + _scheduler->createProcess(PID_CURSOR, CursorProcess, NULL, 0); + _scheduler->createProcess(PID_INVENTORY, InventoryProcess, NULL, 0); } /** @@ -926,10 +908,11 @@ void TinselEngine::RestartDrivers(void) { KillAllObjects(); // init the process scheduler - InitScheduler(); + _scheduler->reset(); // init the event handlers - EventsInstall(); + pMouseProcess = _scheduler->createProcess(PID_MOUSE, MouseProcess, NULL, 0); + pKeyboardProcess = _scheduler->createProcess(PID_KEYBOARD, KeyboardProcess, NULL, 0); // install sound driver SoundInit(); @@ -947,7 +930,8 @@ void TinselEngine::ChopDrivers(void) { SoundDeinit(); // remove event drivers - EventsUninstall(); + _scheduler->killProcess(pMouseProcess); + _scheduler->killProcess(pKeyboardProcess); } /** diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 9370ba6817..6b838924e8 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -43,6 +43,7 @@ namespace Tinsel { class MusicPlayer; +class Scheduler; class SoundManager; enum TinselGameID { @@ -79,6 +80,8 @@ class TinselEngine : public ::Engine { Common::Point _mousePos; uint8 _dosPlayerDir; Console *_console; + Scheduler *_scheduler; + protected: int init(); diff --git a/engines/tinsel/token.cpp b/engines/tinsel/token.cpp index e50290c3f0..0bdac0d6eb 100644 --- a/engines/tinsel/token.cpp +++ b/engines/tinsel/token.cpp @@ -53,7 +53,7 @@ static void TerminateProcess(PROCESS *tProc) { } // Kill the process - ProcessKill(tProc); + g_scheduler->killProcess(tProc); } /** @@ -63,7 +63,7 @@ void GetControlToken() { const int which = TOKEN_CONTROL; if (tokens[which].proc == NULL) { - tokens[which].proc = CurrentProcess(); + tokens[which].proc = g_scheduler->getCurrentProcess(); } } @@ -88,11 +88,11 @@ void GetToken(int which) { assert(TOKEN_LEAD <= which && which < NUMTOKENS); if (tokens[which].proc != NULL) { - assert(tokens[which].proc != CurrentProcess()); + assert(tokens[which].proc != g_scheduler->getCurrentProcess()); TerminateProcess(tokens[which].proc); } - tokens[which].proc = CurrentProcess(); + tokens[which].proc = g_scheduler->getCurrentProcess(); } /** @@ -102,7 +102,7 @@ void GetToken(int which) { void FreeToken(int which) { assert(TOKEN_LEAD <= which && which < NUMTOKENS); - assert(tokens[which].proc == CurrentProcess()); // we'd have been killed if some other proc had taken this token + assert(tokens[which].proc == g_scheduler->getCurrentProcess()); // we'd have been killed if some other proc had taken this token tokens[which].proc = NULL; } -- cgit v1.2.3 From 4936e5f7df8e2257b1af4ee3ab2fdcd8cb88e91b Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 24 Jul 2008 09:24:32 +0000 Subject: * Moved end intro and end game sequences code to gui. * Rewrote all gui code to be run inside the main loop * Added code to avoid crashes when a scene with no standard background is drawn svn-id: r33260 --- engines/parallaction/callables_ns.cpp | 95 +-- engines/parallaction/graphics.cpp | 72 ++- engines/parallaction/graphics.h | 2 + engines/parallaction/gui_ns.cpp | 1037 +++++++++++++++++++++--------- engines/parallaction/input.cpp | 1 + engines/parallaction/input.h | 3 +- engines/parallaction/parallaction.cpp | 5 + engines/parallaction/parallaction.h | 33 +- engines/parallaction/parallaction_ns.cpp | 11 +- 9 files changed, 798 insertions(+), 461 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 558d6fdc33..0a39698850 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -37,18 +37,6 @@ namespace Parallaction { -// part completion messages -static const char *endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; -static const char *endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"}; -static const char *endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"}; -static const char *endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"}; -// game completion messages -static const char *endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; -static const char *endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"}; -static const char *endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"}; -static const char *endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"}; - - /* intro callables data members */ @@ -143,18 +131,6 @@ static uint16 _rightHandPositions[684] = { 0x00e0, 0x007b, 0x00e0, 0x0077 }; -struct Credit { - const char *_role; - const char *_name; -} _credits[] = { - {"Music and Sound Effects", "MARCO CAPRELLI"}, - {"PC Version", "RICCARDO BALLARINO"}, - {"Project Manager", "LOVRANO CANEPA"}, - {"Production", "BRUNO BOZ"}, - {"Special Thanks to", "LUIGI BENEDICENTI - GILDA and DANILO"}, - {"Copyright 1992 Euclidea s.r.l ITALY", "All rights reserved"} -}; - /* game callables */ @@ -376,39 +352,12 @@ void Parallaction_ns::_c_finito(void *parm) { setPartComplete(_char); cleanInventory(); - _gfx->setPalette(_gfx->_palette); - - uint id[4]; - - if (allPartsComplete()) { - id[0] = _gfx->createLabel(_menuFont, endMsg4[_language], 1); - id[1] = _gfx->createLabel(_menuFont, endMsg5[_language], 1); - id[2] = _gfx->createLabel(_menuFont, endMsg6[_language], 1); - id[3] = _gfx->createLabel(_menuFont, endMsg7[_language], 1); - } else { - id[0] = _gfx->createLabel(_menuFont, endMsg0[_language], 1); - id[1] = _gfx->createLabel(_menuFont, endMsg1[_language], 1); - id[2] = _gfx->createLabel(_menuFont, endMsg2[_language], 1); - id[3] = _gfx->createLabel(_menuFont, endMsg3[_language], 1); - } - - _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70); - _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100); - _gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 130); - _gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 160); - - _gfx->updateScreen(); - _input->waitForButtonEvent(kMouseLeftUp); + cleanupGame(); - _gfx->freeLabels(); + _gfx->setPalette(_gfx->_palette); - if (allPartsComplete()) { - scheduleLocationSwitch("estgrotta.drki"); - } else { - selectStartLocation(); - } + startEndPartSequence(); - cleanupGame(); return; } @@ -475,43 +424,7 @@ void Parallaction_ns::_c_startIntro(void *parm) { } void Parallaction_ns::_c_endIntro(void *parm) { - - debugC(1, kDebugExec, "endIntro()"); - - uint id[2]; - for (uint16 _si = 0; _si < 6; _si++) { - id[0] = _gfx->createLabel(_menuFont, _credits[_si]._role, 1); - id[1] = _gfx->createLabel(_menuFont, _credits[_si]._name, 1); - - _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80); - _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100); - - _gfx->updateScreen(); - - _input->waitForButtonEvent(kMouseLeftUp, 5500); - - _gfx->freeLabels(); - } - debugC(1, kDebugExec, "endIntro(): done showing credits"); - - _soundMan->stopMusic(); - - if ((getFeatures() & GF_DEMO) == 0) { - - id[0] = _gfx->createLabel(_menuFont, "CLICK MOUSE BUTTON TO START", 1); - _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80); - _gfx->updateScreen(); - _input->waitForButtonEvent(kMouseLeftUp); - _gfx->freeLabels(); - _engineFlags &= ~kEngineBlockInput; - selectStartLocation(); - cleanupGame(); - } else { - _gfx->updateScreen(); - _input->waitForButtonEvent(kMouseLeftUp); - } - - return; + startCreditSequence(); } void Parallaction_ns::_c_moveSheet(void *parm) { diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 6f29a6cf3f..3afc05bdc1 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -352,29 +352,30 @@ void Gfx::clearScreen() { } void Gfx::beginFrame() { - - int32 oldBackgroundMode = _varBackgroundMode; - _varBackgroundMode = getVar("background_mode"); - - if (oldBackgroundMode != _varBackgroundMode) { - switch (_varBackgroundMode) { - case 1: - _bitmapMask.free(); - break; - case 2: - _bitmapMask.create(_backgroundInfo.width, _backgroundInfo.height, 1); - byte *data = (byte*)_bitmapMask.pixels; - for (uint y = 0; y < _bitmapMask.h; y++) { - for (uint x = 0; x < _bitmapMask.w; x++) { - *data++ = _backgroundInfo.mask.getValue(x, y); + _skipBackground = (_backgroundInfo.bg.pixels == 0); // don't render frame if background is missing + + if (!_skipBackground) { + int32 oldBackgroundMode = _varBackgroundMode; + _varBackgroundMode = getVar("background_mode"); + if (oldBackgroundMode != _varBackgroundMode) { + switch (_varBackgroundMode) { + case 1: + _bitmapMask.free(); + break; + case 2: + _bitmapMask.create(_backgroundInfo.width, _backgroundInfo.height, 1); + byte *data = (byte*)_bitmapMask.pixels; + for (uint y = 0; y < _bitmapMask.h; y++) { + for (uint x = 0; x < _bitmapMask.w; x++) { + *data++ = _backgroundInfo.mask.getValue(x, y); + } } + break; } - break; } } - - if (_vm->_screenWidth >= _backgroundInfo.width) { + if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo.width)) { _varScrollX = 0; } else { _varScrollX = getVar("scroll_x"); @@ -399,24 +400,25 @@ int32 Gfx::getRenderMode(const char *type) { void Gfx::updateScreen() { - // background may not cover the whole screen, so adjust bulk update size - uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo.width); - uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo.height); + if (!_skipBackground) { + // background may not cover the whole screen, so adjust bulk update size + uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo.width); + uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo.height); - byte *backgroundData = 0; - uint16 backgroundPitch = 0; - switch (_varBackgroundMode) { - case 1: - backgroundData = (byte*)_backgroundInfo.bg.getBasePtr(_varScrollX, 0); - backgroundPitch = _backgroundInfo.bg.pitch; - break; - case 2: - backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0); - backgroundPitch = _bitmapMask.pitch; - break; + byte *backgroundData = 0; + uint16 backgroundPitch = 0; + switch (_varBackgroundMode) { + case 1: + backgroundData = (byte*)_backgroundInfo.bg.getBasePtr(_varScrollX, 0); + backgroundPitch = _backgroundInfo.bg.pitch; + break; + case 2: + backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0); + backgroundPitch = _bitmapMask.pitch; + break; + } + g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h); } - g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h); - _varRenderMode = _varAnimRenderMode; @@ -847,6 +849,8 @@ void Gfx::setBackground(uint type, const char* name, const char* mask, const cha _palette.clone(_backgroundInfo.palette); } else { _disk->loadSlide(_backgroundInfo, name); + for (uint i = 0; i < 6; i++) + _backgroundInfo.ranges[i]._flags = 0; // disable palette cycling for slides setPalette(_backgroundInfo.palette); } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index a7242ba6f4..b3745098c2 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -553,6 +553,8 @@ protected: Parallaction* _vm; bool _halfbrite; + bool _skipBackground; + Common::Point _hbCirclePos; int _hbCircleRadius; diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 6068a6a0dd..258463bbbe 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -24,6 +24,7 @@ */ #include "common/system.h" +#include "common/hashmap.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" @@ -32,318 +33,633 @@ namespace Parallaction { -const char *introMsg1[] = { - "INSERISCI IL CODICE", - "ENTREZ CODE", - "ENTER CODE", - "GIB DEN KODE EIN" -}; -const char *introMsg2[] = { - "CODICE ERRATO", - "CODE ERRONE", - "WRONG CODE", - "GIB DEN KODE EIN" -}; +class MenuInputState; -const char *introMsg3[] = { - "PRESS LEFT MOUSE BUTTON", - "TO SEE INTRO", - "PRESS RIGHT MOUSE BUTTON", - "TO START" -}; +class MenuInputHelper { + typedef Common::HashMap StateMap; -const char *newGameMsg[] = { - "NUOVO GIOCO", - "NEUF JEU", - "NEW GAME", - "NEUES SPIEL" -}; + StateMap _map; + MenuInputState *_state; + MenuInputState *_newState; -const char *loadGameMsg[] = { - "GIOCO SALVATO", - "JEU SAUVE'", - "SAVED GAME", - "SPIEL GESPEICHERT" -}; +public: + MenuInputHelper() : _state(0) { + } + ~MenuInputHelper(); -#define BLOCK_WIDTH 16 -#define BLOCK_HEIGHT 24 + void setState(const Common::String &name) { + // bootstrap routine + _newState = getState(name); + assert(_newState); + } -#define BLOCK_X 112 -#define BLOCK_Y 130 + void addState(const Common::String &name, MenuInputState *state) { + _map.setVal(name, state); + } -#define BLOCK_SELECTION_X (BLOCK_X-1) -#define BLOCK_SELECTION_Y (BLOCK_Y-1) + MenuInputState *getState(const Common::String &name) { + return _map[name]; + } -#define BLOCK_X_OFFSET (BLOCK_WIDTH+1) -#define BLOCK_Y_OFFSET 9 + bool run(); +}; -// destination slots for code blocks -// -#define SLOT_X 61 -#define SLOT_Y 64 -#define SLOT_WIDTH (BLOCK_WIDTH+2) +class MenuInputState { -#define PASSWORD_LEN 6 +protected: + MenuInputHelper *_helper; -#define CHAR_DINO 0 -#define CHAR_DONNA 1 -#define CHAR_DOUGH 2 +public: + MenuInputState(const Common::String &name, MenuInputHelper *helper) : _helper(helper), _name(name) { + debugC(3, kDebugExec, "MenuInputState(%s)", name.c_str()); + _helper->addState(name, this); + } -static const uint16 _amigaKeys[][PASSWORD_LEN] = { - { 5, 3, 6, 2, 2, 7 }, // dino - { 0, 3, 6, 2, 2, 6 }, // donna - { 1, 3 ,7, 2, 4, 6 } // dough -}; + Common::String _name; -static const uint16 _pcKeys[][PASSWORD_LEN] = { - { 5, 3, 6, 1, 4, 7 }, // dino - { 0, 2, 8, 5, 5, 1 }, // donna - { 1, 7 ,7, 2, 2, 6 } // dough -}; + virtual ~MenuInputState() { } -static const char *_charStartLocation[] = { - "test.dino", - "test.donna", - "test.dough" + virtual MenuInputState* run() = 0; + virtual void enter() = 0; }; -enum { - NEW_GAME, - LOAD_GAME -}; +bool MenuInputHelper::run() { + if (_newState == 0) { + debugC(3, kDebugExec, "MenuInputHelper has set NULL state"); + return false; + } -enum { - START_DEMO, - START_INTRO, - GAME_LOADED, - SELECT_CHARACTER -}; + if (_newState != _state) { + debugC(3, kDebugExec, "MenuInputHelper changing state to '%s'", _newState->_name.c_str()); -void Parallaction_ns::guiStart() { + _newState->enter(); + _state = _newState; + } - _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); + _newState = _state->run(); - guiSplash(); + return true; +} - _language = guiChooseLanguage(); - _disk->setLanguage(_language); +MenuInputHelper::~MenuInputHelper() { + StateMap::iterator b = _map.begin(); + for ( ; b != _map.end(); b++) { + delete b->_value; + } + _map.clear(); +} - int event; - if (getFeatures() & GF_DEMO) { - event = START_DEMO; - } else { - if (guiSelectGame() == NEW_GAME) { - event = guiNewGame(); - } else { - event = loadGame() ? GAME_LOADED : START_INTRO; +class SplashInputState : public MenuInputState { +protected: + Common::String _slideName; + uint32 _timeOut; + Common::String _nextState; + uint32 _startTime; + + Parallaction_ns *_vm; + +public: + SplashInputState(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + } + + virtual MenuInputState* run() { + uint32 curTime = g_system->getMillis(); + if (curTime - _startTime > _timeOut) { + _vm->freeBackground(); + return _helper->getState(_nextState); } + return this; } - switch (event) { - case START_DEMO: - strcpy(_location._name, "fognedemo.dough"); - break; + virtual void enter() { + _vm->showSlide(_slideName.c_str()); + _startTime = g_system->getMillis(); + } +}; - case START_INTRO: - strcpy(_location._name, "fogne.dough"); - break; +class SplashInputState0 : public SplashInputState { - case GAME_LOADED: - // nothing to do here - return; +public: + SplashInputState0(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState(vm, "intro0", helper) { + _slideName = "intro"; + _timeOut = 2000; + _nextState = "intro1"; + } +}; - case SELECT_CHARACTER: - selectStartLocation(); - break; +class SplashInputState1 : public SplashInputState { +public: + SplashInputState1(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState(vm, "intro1", helper) { + _slideName = "minintro"; + _timeOut = 2000; + _nextState = "chooselanguage"; } +}; - return; -} -void Parallaction_ns::selectStartLocation() { - _inTestResult = false; +class ChooseLanguageInputState : public MenuInputState { + #define BLOCK_WIDTH 16 + #define BLOCK_HEIGHT 24 - int character = guiSelectCharacter(); - if (character == -1) - error("invalid character selected from menu screen"); + #define BLOCK_X 112 + #define BLOCK_Y 130 - scheduleLocationSwitch(_charStartLocation[character]); -} + #define BLOCK_SELECTION_X (BLOCK_X-1) + #define BLOCK_SELECTION_Y (BLOCK_Y-1) + #define BLOCK_X_OFFSET (BLOCK_WIDTH+1) + #define BLOCK_Y_OFFSET 9 -void Parallaction_ns::guiSplash() { + // destination slots for code blocks + // + #define SLOT_X 61 + #define SLOT_Y 64 + #define SLOT_WIDTH (BLOCK_WIDTH+2) - showSlide("intro"); - _gfx->updateScreen(); - g_system->delayMillis(2000); - freeBackground(); + int _language; + bool _allowChoice; + Common::String _nextState; - showSlide("minintro"); - _gfx->updateScreen(); - g_system->delayMillis(2000); - freeBackground(); -} + static const Common::Rect _dosLanguageSelectBlocks[4]; + static const Common::Rect _amigaLanguageSelectBlocks[4]; + const Common::Rect *_blocks; -int Parallaction_ns::guiNewGame() { + Parallaction_ns *_vm; + +public: + ChooseLanguageInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { + _allowChoice = false; + _nextState = "selectgame"; + + if (_vm->getPlatform() == Common::kPlatformAmiga) { + if (!(_vm->getFeatures() & GF_LANG_MULT)) { + if (_vm->getFeatures() & GF_DEMO) { + _language = 1; // Amiga Demo supports English + _nextState = "startdemo"; + return; + } else { + _language = 0; // The only other non multi-lingual version just supports Italian + return; + } + } - const char **v14 = introMsg3; + _blocks = _amigaLanguageSelectBlocks; + } else { + _blocks = _dosLanguageSelectBlocks; + } - _disk->selectArchive("disk1"); + _language = -1; + _allowChoice = true; + } - setBackground("test", NULL, NULL); + virtual MenuInputState* run() { + if (!_allowChoice) { + _vm->setInternLanguage(_language); + return _helper->getState(_nextState); + } - _gfx->updateScreen(); + int event = _vm->_input->getLastButtonEvent(); + if (event != kMouseLeftUp) { + return this; + } - uint id[4]; - id[0] = _gfx->createLabel(_menuFont, v14[0], 1); - id[1] = _gfx->createLabel(_menuFont, v14[1], 1); - id[2] = _gfx->createLabel(_menuFont, v14[2], 1); - id[3] = _gfx->createLabel(_menuFont, v14[3], 1); - _gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 50); - _gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 70); - _gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 100); - _gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 120); + Common::Point p; + _vm->_input->getCursorPos(p); - _input->showCursor(false); + for (uint16 i = 0; i < 4; i++) { + if (_blocks[i].contains(p)) { + _vm->setInternLanguage(i); + _vm->beep(); + _vm->_gfx->freeLabels(); + return _helper->getState(_nextState); + } + } - _gfx->updateScreen(); + return this; + } - _input->waitForButtonEvent(kMouseLeftUp | kMouseRightUp); - uint32 event = _input->getLastButtonEvent(); + virtual void enter() { + if (!_allowChoice) { + return; + } - _input->showCursor(true); + // user can choose language in this version + _vm->showSlide("lingua"); - _gfx->freeLabels(); + uint id = _vm->_gfx->createLabel(_vm->_introFont, "SELECT LANGUAGE", 1); + _vm->_gfx->showLabel(id, 60, 30); - if (event != kMouseRightUp) { - return START_INTRO; + _vm->setArrowCursor(); } +}; - return SELECT_CHARACTER; -} - -static const Common::Rect _dosLanguageSelectBlocks[4] = { +const Common::Rect ChooseLanguageInputState::_dosLanguageSelectBlocks[4] = { Common::Rect( 80, 110, 128, 180 ), // Italian Common::Rect( 129, 85, 177, 155 ), // French Common::Rect( 178, 60, 226, 130 ), // English Common::Rect( 227, 35, 275, 105 ) // German }; -static const Common::Rect _amigaLanguageSelectBlocks[4] = { +const Common::Rect ChooseLanguageInputState::_amigaLanguageSelectBlocks[4] = { Common::Rect( -1, -1, -1, -1 ), // Italian: not supported by Amiga multi-lingual version Common::Rect( 129, 85, 177, 155 ), // French Common::Rect( 178, 60, 226, 130 ), // English Common::Rect( 227, 35, 275, 105 ) // German }; +class SelectGameInputState : public MenuInputState { + + int _choice, _oldChoice; + Common::String _nextState[2]; + + uint _labels[2]; + + Parallaction_ns *_vm; + + static const char *newGameMsg[4]; + static const char *loadGameMsg[4]; + +public: + SelectGameInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { + _choice = 0; + _oldChoice = -1; + + _nextState[0] = "newgame"; + _nextState[1] = "loadgame"; + } + + + virtual MenuInputState *run() { + int event = _vm->_input->getLastButtonEvent(); + + if (event == kMouseLeftUp) { + _vm->_gfx->freeLabels(); + return _helper->getState(_nextState[_choice]); + } + + Common::Point p; + _vm->_input->getCursorPos(p); + _choice = (p.x > 160) ? 1 : 0; + + if (_choice != _oldChoice) { + if (_oldChoice != -1) + _vm->_gfx->hideLabel(_labels[_oldChoice]); + + if (_choice != -1) + _vm->_gfx->showLabel(_labels[_choice], 60, 30); + + _oldChoice = _choice; + } + + return this; + } + + virtual void enter() { + _vm->showSlide("restore"); + + _labels[0] = _vm->_gfx->createLabel(_vm->_introFont, newGameMsg[_vm->getInternLanguage()], 1); + _labels[1] = _vm->_gfx->createLabel(_vm->_introFont, loadGameMsg[_vm->getInternLanguage()], 1); + } + +}; + +const char *SelectGameInputState::newGameMsg[4] = { + "NUOVO GIOCO", + "NEUF JEU", + "NEW GAME", + "NEUES SPIEL" +}; + +const char *SelectGameInputState::loadGameMsg[4] = { + "GIOCO SALVATO", + "JEU SAUVE'", + "SAVED GAME", + "SPIEL GESPEICHERT" +}; + + + +class LoadGameInputState : public MenuInputState { + bool _result; + Parallaction_ns *_vm; + +public: + LoadGameInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } + + virtual MenuInputState* run() { + if (!_result) { + _vm->scheduleLocationSwitch("fogne.dough"); + } + return 0; + } + + virtual void enter() { + _result = _vm->loadGame(); + } +}; + + -uint16 Parallaction_ns::guiChooseLanguage() { +class NewGameInputState : public MenuInputState { + Parallaction_ns *_vm; - const Common::Rect *blocks; + static const char *introMsg3[4]; - if (getPlatform() == Common::kPlatformAmiga) { - if (!(getFeatures() & GF_LANG_MULT)) { - if (getFeatures() & GF_DEMO) { - return 1; // Amiga Demo supports English - } else { - return 0; // The only other non multi-lingual version just supports Italian +public: + NewGameInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { + } + + virtual MenuInputState* run() { + int event = _vm->_input->getLastButtonEvent(); + + if (event == kMouseLeftUp || event == kMouseRightUp) { + _vm->_input->showCursor(true); + _vm->_gfx->freeLabels(); + + if (event == kMouseLeftUp) { + _vm->scheduleLocationSwitch("fogne.dough"); + return 0; } + + return _helper->getState("selectcharacter"); } - blocks = _amigaLanguageSelectBlocks; - } else { - blocks = _dosLanguageSelectBlocks; + return this; + } + + virtual void enter() { + _vm->_disk->selectArchive("disk1"); + _vm->setBackground("test", NULL, NULL); + _vm->_input->showCursor(false); + + uint id[4]; + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[0], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[1], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[2], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[3], 1); + _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 50); + _vm->_gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 70); + _vm->_gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 100); + _vm->_gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 120); } +}; - // user can choose language in dos version - showSlide("lingua"); +const char *NewGameInputState::introMsg3[4] = { + "PRESS LEFT MOUSE BUTTON", + "TO SEE INTRO", + "PRESS RIGHT MOUSE BUTTON", + "TO START" +}; - uint id = _gfx->createLabel(_introFont, "SELECT LANGUAGE", 1); - _gfx->showLabel(id, 60, 30); - setArrowCursor(); - Common::Point p; +class StartDemoInputState : public MenuInputState { + Parallaction_ns *_vm; - int selection = -1; - int event; - while (selection == -1) { - _input->readInput(); - event = _input->getLastButtonEvent(); +public: + StartDemoInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { + } - if (event == kMouseLeftUp) { - _input->getCursorPos(p); - for (uint16 i = 0; i < 4; i++) { - if (blocks[i].contains(p)) { - selection = i; - break; - } + virtual MenuInputState* run() { + _vm->scheduleLocationSwitch("fognedemo.dough"); + return 0; + } + + virtual void enter() { } +}; + +class SelectCharacterInputState : public MenuInputState { + + #define PASSWORD_LEN 6 + + #define CHAR_DINO 0 + #define CHAR_DONNA 1 + #define CHAR_DOUGH 2 + + static const Common::Rect codeSelectBlocks[9]; + static const Common::Rect codeTrueBlocks[9]; + + Parallaction_ns *_vm; + + int guiGetSelectedBlock(const Common::Point &p) { + + int selection = -1; + + for (uint16 i = 0; i < 9; i++) { + if (codeSelectBlocks[i].contains(p)) { + selection = i; + break; } } - _gfx->updateScreen(); + if ((selection != -1) && (_vm->getPlatform() == Common::kPlatformAmiga)) { + _vm->_gfx->invertBackground(codeTrueBlocks[selection]); + _vm->_gfx->updateScreen(); + _vm->beep(); + g_system->delayMillis(100); + _vm->_gfx->invertBackground(codeTrueBlocks[selection]); + _vm->_gfx->updateScreen(); + } + + return selection; } - beep(); + byte _points[3]; + bool _fail; + const uint16 (*_keys)[PASSWORD_LEN]; + Graphics::Surface _block; + Graphics::Surface _emptySlots; - _gfx->freeLabels(); + uint _labels[2]; + uint _len; + uint32 _startTime; - return selection; -} + enum { + CHOICE, + FAIL, + SUCCESS, + DELAY + }; + uint _state; + static const char *introMsg1[4]; + static const char *introMsg2[4]; -uint16 Parallaction_ns::guiSelectGame() { -// printf("selectGame()\n"); + static const uint16 _amigaKeys[3][PASSWORD_LEN]; + static const uint16 _pcKeys[3][PASSWORD_LEN]; + static const char *_charStartLocation[3]; - showSlide("restore"); - uint16 _si = 0; - uint16 _di = 3; +public: + SelectCharacterInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { + _keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys; + _block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); + } - uint id0, id1; - id0 = _gfx->createLabel(_introFont, loadGameMsg[_language], 1); - id1 = _gfx->createLabel(_introFont, newGameMsg[_language], 1); + void cleanup() { + _points[0] = _points[1] = _points[2] = 0; + _vm->_gfx->hideLabel(_labels[1]); + _vm->_gfx->showLabel(_labels[0], 60, 30); + _fail = false; + _len = 0; + } - Common::Point p; + void delay() { + if (g_system->getMillis() - _startTime < 2000) { + return; + } + cleanup(); + _state = CHOICE; + } - uint32 event = kMouseNone; - while (event != kMouseLeftUp) { + void choice() { + int event = _vm->_input->getLastButtonEvent(); + if (event != kMouseLeftUp) { + return; + } - _input->readInput(); - _input->getCursorPos(p); - event = _input->getLastButtonEvent(); + Common::Point p; + _vm->_input->getCursorPos(p); + int _si = guiGetSelectedBlock(p); - _si = (p.x > 160) ? 1 : 0; + if (_si != -1) { + _vm->_gfx->grabBackground(codeTrueBlocks[_si], _block); + _vm->_gfx->patchBackground(_block, _len * SLOT_WIDTH + SLOT_X, SLOT_Y, false); - if (_si != _di) { - if (_si != 0) { - // load a game - _gfx->hideLabel(id1); - _gfx->showLabel(id0, 60, 30); - } else { - // new game - _gfx->hideLabel(id0); - _gfx->showLabel(id1, 60, 30); + if (_keys[0][_len] != _si && _keys[1][_len] != _si && _keys[2][_len] != _si) { + _fail = true; } - _di = _si; + + // build user preference + _points[0] += (_keys[0][_len] == _si); + _points[1] += (_keys[1][_len] == _si); + _points[2] += (_keys[2][_len] == _si); + + _len++; } - _gfx->updateScreen(); - g_system->delayMillis(30); + if (_len == PASSWORD_LEN) { + _state = _fail ? FAIL : SUCCESS; + } } - _gfx->freeLabels(); + void fail() { + _vm->_gfx->patchBackground(_emptySlots, SLOT_X, SLOT_Y, false); + _vm->_gfx->hideLabel(_labels[0]); + _vm->_gfx->showLabel(_labels[1], 60, 30); + _startTime = g_system->getMillis(); + _state = DELAY; + } - return _si ? LOAD_GAME : NEW_GAME; -} + void success() { + _vm->_gfx->freeLabels(); + _vm->_gfx->setBlackPalette(); + _emptySlots.free(); + + // actually select character + int character = -1; + if (_points[0] >= _points[1] && _points[0] >= _points[2]) { + character = CHAR_DINO; + } else + if (_points[1] >= _points[0] && _points[1] >= _points[2]) { + character = CHAR_DONNA; + } else + if (_points[2] >= _points[0] && _points[2] >= _points[1]) { + character = CHAR_DOUGH; + } else { + error("If you read this, either your CPU or transivity is broken (we believe the former)."); + } + + _vm->_inTestResult = false; + _vm->cleanupGame(); + _vm->scheduleLocationSwitch(_charStartLocation[character]); + } + + virtual MenuInputState* run() { + MenuInputState* nextState = this; + + switch (_state) { + case DELAY: + delay(); + break; + + case CHOICE: + choice(); + break; + + case FAIL: + fail(); + break; + + case SUCCESS: + success(); + nextState = 0; + break; + + default: + error("unknown state in SelectCharacterInputState"); + } + + return nextState; + } + + virtual void enter() { + _vm->setArrowCursor(); + _vm->_soundMan->stopMusic(); + _vm->_disk->selectArchive((_vm->getFeatures() & GF_DEMO) ? "disk0" : "disk1"); + _vm->showSlide("password"); + + _emptySlots.create(BLOCK_WIDTH * 8, BLOCK_HEIGHT, 1); + Common::Rect rect(SLOT_X, SLOT_Y, SLOT_X + BLOCK_WIDTH * 8, SLOT_Y + BLOCK_HEIGHT); + _vm->_gfx->grabBackground(rect, _emptySlots); + + _labels[0] = _vm->_gfx->createLabel(_vm->_introFont, introMsg1[_vm->getInternLanguage()], 1); + _labels[1] = _vm->_gfx->createLabel(_vm->_introFont, introMsg2[_vm->getInternLanguage()], 1); + + cleanup(); + _state = CHOICE; + } +}; + +const char *SelectCharacterInputState::introMsg1[4] = { + "INSERISCI IL CODICE", + "ENTREZ CODE", + "ENTER CODE", + "GIB DEN KODE EIN" +}; + +const char *SelectCharacterInputState::introMsg2[4] = { + "CODICE ERRATO", + "CODE ERRONE", + "WRONG CODE", + "GIB DEN KODE EIN" +}; -static const Common::Rect codeSelectBlocks[9] = { +const uint16 SelectCharacterInputState::_amigaKeys[][PASSWORD_LEN] = { + { 5, 3, 6, 2, 2, 7 }, // dino + { 0, 3, 6, 2, 2, 6 }, // donna + { 1, 3 ,7, 2, 4, 6 } // dough +}; + +const uint16 SelectCharacterInputState::_pcKeys[][PASSWORD_LEN] = { + { 5, 3, 6, 1, 4, 7 }, // dino + { 0, 2, 8, 5, 5, 1 }, // donna + { 1, 7 ,7, 2, 2, 6 } // dough +}; + +const char *SelectCharacterInputState::_charStartLocation[] = { + "test.dino", + "test.donna", + "test.dough" +}; + + +const Common::Rect SelectCharacterInputState::codeSelectBlocks[9] = { Common::Rect( 111, 129, 127, 153 ), // na Common::Rect( 128, 120, 144, 144 ), // wa Common::Rect( 145, 111, 161, 135 ), // ra @@ -355,7 +671,7 @@ static const Common::Rect codeSelectBlocks[9] = { Common::Rect( 247, 57, 263, 81 ) // ka }; -static const Common::Rect codeTrueBlocks[9] = { +const Common::Rect SelectCharacterInputState::codeTrueBlocks[9] = { Common::Rect( 112, 130, 128, 154 ), Common::Rect( 129, 121, 145, 145 ), Common::Rect( 146, 112, 162, 136 ), @@ -368,151 +684,252 @@ static const Common::Rect codeTrueBlocks[9] = { }; -int Parallaction_ns::guiGetSelectedBlock(const Common::Point &p) { +class ShowCreditsInputState : public MenuInputState { + Parallaction_ns *_vm; + int _current; + uint32 _startTime; - int selection = -1; + struct Credit { + const char *_role; + const char *_name; + }; - for (uint16 i = 0; i < 9; i++) { - if (codeSelectBlocks[i].contains(p)) { - selection = i; - break; - } - } + static const Credit _credits[6]; - if ((selection != -1) && (getPlatform() == Common::kPlatformAmiga)) { - _gfx->invertBackground(codeTrueBlocks[selection]); - _gfx->updateScreen(); - beep(); - g_system->delayMillis(100); - _gfx->invertBackground(codeTrueBlocks[selection]); - _gfx->updateScreen(); +public: + ShowCreditsInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { } - return selection; -} + void drawCurrentLabel() { + uint id[2]; + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, _credits[_current]._role, 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, _credits[_current]._name, 1); + _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 80); + _vm->_gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100); + } -// -// character selection and protection -// -int Parallaction_ns::guiSelectCharacter() { - debugC(1, kDebugMenu, "Parallaction_ns::guiselectCharacter()"); + virtual MenuInputState* run() { + if (_current == -1) { + _startTime = g_system->getMillis(); + _current = 0; + drawCurrentLabel(); + return this; + } - setArrowCursor(); - _soundMan->stopMusic(); + int event = _vm->_input->getLastButtonEvent(); + uint32 curTime = g_system->getMillis(); + if ((event == kMouseLeftUp) || (curTime - _startTime > 5500)) { + _current++; + _startTime = curTime; + _vm->_gfx->freeLabels(); - _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); + if (_current == 6) { + return _helper->getState("endintro"); + } - showSlide("password"); + drawCurrentLabel(); + } + return this; + } - const uint16 (*keys)[PASSWORD_LEN] = (getPlatform() == Common::kPlatformAmiga && (getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys; - uint16 _di = 0; - byte points[3] = { 0, 0, 0 }; + virtual void enter() { + _current = -1; + } +}; - bool fail; +const ShowCreditsInputState::Credit ShowCreditsInputState::_credits[6] = { + {"Music and Sound Effects", "MARCO CAPRELLI"}, + {"PC Version", "RICCARDO BALLARINO"}, + {"Project Manager", "LOVRANO CANEPA"}, + {"Production", "BRUNO BOZ"}, + {"Special Thanks to", "LUIGI BENEDICENTI - GILDA and DANILO"}, + {"Copyright 1992 Euclidea s.r.l ITALY", "All rights reserved"} +}; - uint id[2]; - id[0] = _gfx->createLabel(_introFont, introMsg1[_language], 1); - id[1] = _gfx->createLabel(_introFont, introMsg2[_language], 1); +class EndIntroInputState : public MenuInputState { + Parallaction_ns *_vm; + bool _isDemo; - Graphics::Surface v14; - v14.create(BLOCK_WIDTH * 8, BLOCK_HEIGHT, 1); - Common::Rect rect(SLOT_X, SLOT_Y, SLOT_X + BLOCK_WIDTH * 8, SLOT_Y + BLOCK_HEIGHT); - _gfx->grabBackground(rect, v14); +public: + EndIntroInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { + _isDemo = (_vm->getFeatures() & GF_DEMO) != 0; + } - Graphics::Surface block; - block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); + virtual MenuInputState* run() { - Common::Point p; + int event = _vm->_input->getLastButtonEvent(); + if (event != kMouseLeftUp) { + return this; + } - while (true) { + if (_isDemo) { + _engineFlags |= kEngineQuit; + return 0; + } - points[0] = 0; - points[1] = 0; - points[2] = 0; - fail = false; + _vm->_gfx->freeLabels(); + _engineFlags &= ~kEngineBlockInput; + return _helper->getState("selectcharacter"); + } - _gfx->hideLabel(id[1]); - _gfx->showLabel(id[0], 60, 30); + virtual void enter() { + _vm->_soundMan->stopMusic(); - _di = 0; - int event; - while (_di < PASSWORD_LEN) { - _input->readInput(); - event = _input->getLastButtonEvent(); - if (event == kMouseLeftUp) { + if (!_isDemo) { + int label = _vm->_gfx->createLabel(_vm->_menuFont, "CLICK MOUSE BUTTON TO START", 1); + _vm->_gfx->showLabel(label, CENTER_LABEL_HORIZONTAL, 80); + } + } +}; - _input->getCursorPos(p); - int _si = guiGetSelectedBlock(p); +class EndPartInputState : public MenuInputState { + Parallaction_ns *_vm; + bool _allPartsComplete; - if (_si != -1) { - _gfx->grabBackground(codeTrueBlocks[_si], block); - _gfx->patchBackground(block, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, false); + // part completion messages + static const char *endMsg0[4]; + static const char *endMsg1[4]; + static const char *endMsg2[4]; + static const char *endMsg3[4]; + // game completion messages + static const char *endMsg4[4]; + static const char *endMsg5[4]; + static const char *endMsg6[4]; + static const char *endMsg7[4]; - if (keys[0][_di] == _si) { - points[0]++; - } else - if (keys[1][_di] == _si) { - points[1]++; - } else - if (keys[2][_di] == _si) { - points[2]++; - } else { - fail = true; - } - // build user preference - points[0] += (keys[0][_di] == _si); - points[1] += (keys[1][_di] == _si); - points[2] += (keys[2][_di] == _si); +public: + EndPartInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { + } - _di++; - } - } - _gfx->updateScreen(); + virtual MenuInputState* run() { + int event = _vm->_input->getLastButtonEvent(); + if (event != kMouseLeftUp) { + return this; } - if (!fail) { - break; + _vm->_gfx->freeLabels(); + + if (_allPartsComplete) { + _vm->scheduleLocationSwitch("estgrotta.drki"); + return 0; } - _gfx->patchBackground(v14, SLOT_X, SLOT_Y, false); + return _helper->getState("selectcharacter"); + } - _gfx->hideLabel(id[0]); - _gfx->showLabel(id[1], 60, 30); + virtual void enter() { + _allPartsComplete = _vm->allPartsComplete(); - _gfx->updateScreen(); + uint id[4]; + if (_allPartsComplete) { + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[_language], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[_language], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[_language], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[_language], 1); + } else { + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[_language], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[_language], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[_language], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[_language], 1); + } - g_system->delayMillis(2000); + _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70); + _vm->_gfx->showLabel(id[1], CENTER_LABEL_HORIZONTAL, 100); + _vm->_gfx->showLabel(id[2], CENTER_LABEL_HORIZONTAL, 130); + _vm->_gfx->showLabel(id[3], CENTER_LABEL_HORIZONTAL, 160); } +}; + +// part completion messages +const char *EndPartInputState::endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; +const char *EndPartInputState::endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"}; +const char *EndPartInputState::endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"}; +const char *EndPartInputState::endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"}; +// game completion messages +const char *EndPartInputState::endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; +const char *EndPartInputState::endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"}; +const char *EndPartInputState::endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"}; +const char *EndPartInputState::endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"}; + +void Parallaction_ns::startGui() { + _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); + + _menuHelper = new MenuInputHelper; + assert(_menuHelper); + + new SelectGameInputState(this, _menuHelper); + new LoadGameInputState(this, _menuHelper); + new NewGameInputState(this, _menuHelper); + new StartDemoInputState(this, _menuHelper); + new SelectCharacterInputState(this, _menuHelper); + new ChooseLanguageInputState(this, _menuHelper); + new SplashInputState1(this, _menuHelper); + new SplashInputState0(this, _menuHelper); + _menuHelper->setState("intro0"); + + _input->_inputMode = Input::kInputModeMenu; +} + +void Parallaction_ns::startCreditSequence() { + _menuHelper = new MenuInputHelper; + assert(_menuHelper); - _gfx->freeLabels(); + new ShowCreditsInputState(this, _menuHelper); + new EndIntroInputState(this, _menuHelper); + new SelectCharacterInputState(this, _menuHelper); + _menuHelper->setState("showcredits"); - _gfx->setBlackPalette(); - _gfx->updateScreen(); + _input->_inputMode = Input::kInputModeMenu; +} - v14.free(); +void Parallaction_ns::startEndPartSequence() { + _menuHelper = new MenuInputHelper; + assert(_menuHelper); + new EndPartInputState(this, _menuHelper); + new SelectCharacterInputState(this, _menuHelper); + _menuHelper->setState("endpart"); + + _input->_inputMode = Input::kInputModeMenu; +} - // actually select character - int character = -1; - if (points[0] >= points[1] && points[0] >= points[2]) { - character = CHAR_DINO; - } else - if (points[1] >= points[0] && points[1] >= points[2]) { - character = CHAR_DONNA; - } else - if (points[2] >= points[0] && points[2] >= points[1]) { - character = CHAR_DOUGH; - } else { - error("If you read this, either your CPU or transivity is broken (we believe the former)."); +void Parallaction::runGuiFrame() { + if (_input->_inputMode != Input::kInputModeMenu) { + return; + } + + if (!_menuHelper) { + error("No menu helper defined!"); } - return character; + bool res = _menuHelper->run(); + + if (!res) { + cleanupGui(); + _input->_inputMode = Input::kInputModeGame; + } + +} + +void Parallaction::cleanupGui() { + delete _menuHelper; + _menuHelper = 0; } +void Parallaction::setInternLanguage(uint id) { + //TODO: assert id! + + _language = id; + _disk->setLanguage(id); +} + +uint Parallaction::getInternLanguage() { + return _language; +} } // namespace Parallaction diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index dbc1090a40..2919bc61fd 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -166,6 +166,7 @@ InputData* Input::updateInput() { switch (_inputMode) { case kInputModeComment: case kInputModeDialogue: + case kInputModeMenu: readInput(); break; diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 68acce6554..89a98541bb 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -85,7 +85,8 @@ public: kInputModeGame = 0, kInputModeComment = 1, kInputModeDialogue = 2, - kInputModeInventory = 3 + kInputModeInventory = 3, + kInputModeMenu = 4 }; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index e7455220ec..163f3009e1 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -98,6 +98,8 @@ Parallaction::~Parallaction() { freeCharacter(); destroyInventory(); + cleanupGui(); + delete _localFlagNames; delete _gfx; delete _soundMan; @@ -136,6 +138,8 @@ int Parallaction::init() { _debugger = new Debugger(this); + _menuHelper = 0; + setupBalloonManager(); return 0; @@ -325,6 +329,7 @@ void Parallaction::runGame() { if (_engineFlags & kEngineQuit) return; + runGuiFrame(); runDialogueFrame(); runCommentFrame(); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index d8ab93e257..47bbda0b4a 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -158,6 +158,7 @@ class Gfx; class SoundMan; class Input; class DialogueManager; +class MenuInputHelper; struct Location { @@ -416,11 +417,18 @@ public: void exitDialogueMode(); void runDialogueFrame(); + MenuInputHelper *_menuHelper; + void runGuiFrame(); + void cleanupGui(); + ZonePtr _commentZone; void enterCommentMode(ZonePtr z); void exitCommentMode(); void runCommentFrame(); + void setInternLanguage(uint id); + uint getInternLanguage(); + }; @@ -485,6 +493,13 @@ public: bool saveGame(); void switchBackground(const char* background, const char* mask); + void showSlide(const char *name); + void setArrowCursor(); + + // TODO: this should be private!!!!!!! + bool _inTestResult; + void cleanupGame(); + bool allPartsComplete(); private: LocationParser_ns *_locationParser; @@ -496,16 +511,13 @@ private: Common::String genSaveFileName(uint slot, bool oldStyle = false); Common::InSaveFile *getInSaveFile(uint slot); Common::OutSaveFile *getOutSaveFile(uint slot); - bool allPartsComplete(); void setPartComplete(const Character& character); private: void changeLocation(char *location); void changeCharacter(const char *name); void runPendingZones(); - void cleanupGame(); - void setArrowCursor(); void setInventoryCursor(int pos); @@ -539,9 +551,6 @@ private: ZonePtr _moveSarcExaZones[5]; AnimationPtr _rightHandAnim; - bool _inTestResult; - - // common callables void _c_play_boogie(void*); void _c_startIntro(void*); @@ -586,15 +595,9 @@ protected: void selectStartLocation(); - void guiStart(); - int guiSelectCharacter(); - void guiSplash(); - int guiNewGame(); - uint16 guiChooseLanguage(); - uint16 guiSelectGame(); - int guiGetSelectedBlock(const Common::Point &p); - - void showSlide(const char *name); + void startGui(); + void startCreditSequence(); + void startEndPartSequence(); }; diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index b2e60c5851..cf5cf2cd73 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -240,17 +240,8 @@ int Parallaction_ns::go() { _globalTable = _disk->loadTable("global"); - guiStart(); + startGui(); - if (_engineFlags & kEngineQuit) - return 0; - - changeLocation(_location._name); - - if (_engineFlags & kEngineQuit) - return 0; - - _input->_inputMode = Input::kInputModeGame; while ((_engineFlags & kEngineQuit) == 0) { runGame(); } -- cgit v1.2.3 From ba1f91eba80dd6f65101d4461fdd4b8612a12c7b Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 24 Jul 2008 09:42:44 +0000 Subject: Fixed leak in new gui code. svn-id: r33261 --- engines/parallaction/gui_ns.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'engines') diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 258463bbbe..2428c4b989 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -501,6 +501,11 @@ public: _block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); } + ~SelectCharacterInputState() { + _block.free(); + _emptySlots.free(); + } + void cleanup() { _points[0] = _points[1] = _points[2] = 0; _vm->_gfx->hideLabel(_labels[1]); -- cgit v1.2.3 From 728a045308e62579262bcf50d11fd5c37b6e26e0 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 24 Jul 2008 10:31:37 +0000 Subject: cleanup svn-id: r33263 --- engines/tinsel/music.cpp | 7 ++----- engines/tinsel/sound.cpp | 46 ---------------------------------------------- engines/tinsel/sound.h | 3 --- engines/tinsel/tinsel.cpp | 13 ++++++++++--- 4 files changed, 12 insertions(+), 57 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 8af905b0c8..060eba10d4 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -58,8 +58,8 @@ static uint32 dwMidiIndex = 0; // MIDI buffer static SOUND_BUFFER midiBuffer = { 0, 0 }; -static SCNHANDLE currentMidi; -static bool currentLoop; +static SCNHANDLE currentMidi = 0; +static bool currentLoop = false; const SCNHANDLE midiOffsetsGRAVersion[] = { 4, 4534, 14298, 18828, 23358, 38888, 54418, 57172, 59926, 62450, @@ -149,7 +149,6 @@ SCNHANDLE GetTrackOffset(int trackNumber) { * @param dwFileOffset File offset of MIDI sequence data * @param bLoop Whether to loop the sequence */ - bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { currentMidi = dwFileOffset; currentLoop = bLoop; @@ -234,7 +233,6 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { /** * Returns TRUE if a Midi tune is currently playing. */ - bool MidiPlaying(void) { if (AudioCD.isPlaying()) return true; return _vm->_music->isPlaying(); @@ -243,7 +241,6 @@ bool MidiPlaying(void) { /** * Stops any currently playing midi. */ - bool StopMidi(void) { currentMidi = 0; currentLoop = false; diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp index 0a3b01089f..e2a24dbd47 100644 --- a/engines/tinsel/sound.cpp +++ b/engines/tinsel/sound.cpp @@ -43,9 +43,6 @@ namespace Tinsel { //--------------------------- General data ---------------------------------- -// get set when music/sample driver is installed -static bool bInstalled = false; - SoundManager::SoundManager(TinselEngine *vm) : //_vm(vm), // TODO: Enable this once global _vm var is gone _sampleIndex(0), _sampleIndexLen(0) { @@ -211,47 +208,4 @@ void SoundManager::openSampleFiles(void) { */ } -/** - * Initialises the sound driver. - */ - -bool SoundInit(void) { - if (!bInstalled) { -// if (mDriver != NULL) { - if (true) { // TODO: Check that a MIDI music output device is available - // open MIDI files - OpenMidiFiles(); - } - - if (_vm->_mixer->isReady()) { - // open sample files - _vm->_sound->openSampleFiles(); - } - bInstalled = true; - return true; - } else { - // already installed - return false; - } -} - - -/** - * De-initialises the sound driver. - */ - -bool SoundDeinit(void) { - if (bInstalled) { - bInstalled = false; - AudioCD.stop(); - StopMidi(); - _vm->_sound->stopAllSamples(); - DeleteMidiBuffer(); - return true; - } else { - // not installed - return false; - } -} - } // end of namespace Tinsel diff --git a/engines/tinsel/sound.h b/engines/tinsel/sound.h index c80e7589ec..56618eeb8e 100644 --- a/engines/tinsel/sound.h +++ b/engines/tinsel/sound.h @@ -75,9 +75,6 @@ public: void openSampleFiles(void); }; -bool SoundInit(void); // Initialises the sound driver -bool SoundDeinit(void); // De-initialises the sound driver - } // end of namespace Tinsel #endif // TINSEL_SOUND_H diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 8cfc6d7d4d..946c9338ba 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -914,8 +914,13 @@ void TinselEngine::RestartDrivers(void) { pMouseProcess = _scheduler->createProcess(PID_MOUSE, MouseProcess, NULL, 0); pKeyboardProcess = _scheduler->createProcess(PID_KEYBOARD, KeyboardProcess, NULL, 0); - // install sound driver - SoundInit(); + // open MIDI files + OpenMidiFiles(); + + // open sample files (only if mixer is ready) + if (_mixer->isReady()) { + _sound->openSampleFiles(); + } // Set midi volume SetMidiVolume(volMidi); @@ -927,7 +932,9 @@ void TinselEngine::RestartDrivers(void) { void TinselEngine::ChopDrivers(void) { // remove sound driver - SoundDeinit(); + StopMidi(); + _sound->stopAllSamples(); + DeleteMidiBuffer(); // remove event drivers _scheduler->killProcess(pMouseProcess); -- cgit v1.2.3 From 6b2337740ecdce2bcc7053568c5b232845be75ff Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Thu, 24 Jul 2008 22:12:48 +0000 Subject: Make sure _musicVolume and _sfxVolume are clipped to fit in a byte. svn-id: r33266 --- engines/kyra/sound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 5068268d99..c8749dc06b 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -202,8 +202,8 @@ bool SoundMidiPC::init() { } void SoundMidiPC::updateVolumeSettings() { - _musicVolume = ConfMan.getInt("music_volume"); - _sfxVolume = ConfMan.getInt("sfx_volume"); + _musicVolume = CLIP(ConfMan.getInt("music_volume"), 0, 255); + _sfxVolume = CLIP(ConfMan.getInt("sfx_volume"), 0, 255); updateChannelVolume(_musicVolume); } -- cgit v1.2.3 From d1a6b175f5ef7f64435477775015730657195a11 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 25 Jul 2008 02:37:55 +0000 Subject: * Merged old input management flags into a single mouse status variable. * Mouse is now displayed when it is needed, and hidden when it is not ;) svn-id: r33270 --- engines/parallaction/callables_ns.cpp | 12 +++------- engines/parallaction/exec_br.cpp | 4 ++-- engines/parallaction/gui_ns.cpp | 22 +++++++++++++----- engines/parallaction/input.cpp | 40 ++++++++++++++++++++++---------- engines/parallaction/input.h | 16 ++++++++++--- engines/parallaction/parallaction.h | 3 --- engines/parallaction/parallaction_ns.cpp | 14 +++++------ 7 files changed, 68 insertions(+), 43 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 0a39698850..9cd6b610ff 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -280,15 +280,11 @@ void Parallaction_ns::_c_trasformata(void *parm) { } void Parallaction_ns::_c_offMouse(void *parm) { - _input->showCursor(false); - _engineFlags |= kEngineBlockInput; - return; + _input->setMouseState(MOUSE_DISABLED); } void Parallaction_ns::_c_onMouse(void *parm) { - _engineFlags &= ~kEngineBlockInput; - _input->showCursor(true); - return; + _input->setMouseState(MOUSE_ENABLED_SHOW); } @@ -418,9 +414,7 @@ void Parallaction_ns::_c_startIntro(void *parm) { _soundMan->playMusic(); } - _engineFlags |= kEngineBlockInput; - - return; + _input->setMouseState(MOUSE_DISABLED); } void Parallaction_ns::_c_endIntro(void *parm) { diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index edb832cffc..ef671b1e0e 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -194,12 +194,12 @@ DECLARE_COMMAND_OPCODE(followme) { DECLARE_COMMAND_OPCODE(onmouse) { - _vm->_input->showCursor(true); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); } DECLARE_COMMAND_OPCODE(offmouse) { - _vm->_input->showCursor(false); + _vm->_input->setMouseState(MOUSE_DISABLED); } diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 2428c4b989..ce68df46e2 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -135,6 +135,7 @@ public: } virtual void enter() { + _vm->_input->setMouseState(MOUSE_DISABLED); _vm->showSlide(_slideName.c_str()); _startTime = g_system->getMillis(); } @@ -247,6 +248,8 @@ public: return; } + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); + // user can choose language in this version _vm->showSlide("lingua"); @@ -320,6 +323,7 @@ public: virtual void enter() { _vm->showSlide("restore"); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); _labels[0] = _vm->_gfx->createLabel(_vm->_introFont, newGameMsg[_vm->getInternLanguage()], 1); _labels[1] = _vm->_gfx->createLabel(_vm->_introFont, loadGameMsg[_vm->getInternLanguage()], 1); @@ -377,7 +381,7 @@ public: int event = _vm->_input->getLastButtonEvent(); if (event == kMouseLeftUp || event == kMouseRightUp) { - _vm->_input->showCursor(true); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); _vm->_gfx->freeLabels(); if (event == kMouseLeftUp) { @@ -394,7 +398,7 @@ public: virtual void enter() { _vm->_disk->selectArchive("disk1"); _vm->setBackground("test", NULL, NULL); - _vm->_input->showCursor(false); + _vm->_input->setMouseState(MOUSE_ENABLED_HIDE); uint id[4]; id[0] = _vm->_gfx->createLabel(_vm->_menuFont, introMsg3[0], 1); @@ -429,7 +433,9 @@ public: return 0; } - virtual void enter() { } + virtual void enter() { + _vm->_input->setMouseState(MOUSE_DISABLED); + } }; class SelectCharacterInputState : public MenuInputState { @@ -504,7 +510,7 @@ public: ~SelectCharacterInputState() { _block.free(); _emptySlots.free(); - } + } void cleanup() { _points[0] = _points[1] = _points[2] = 0; @@ -614,7 +620,6 @@ public: } virtual void enter() { - _vm->setArrowCursor(); _vm->_soundMan->stopMusic(); _vm->_disk->selectArchive((_vm->getFeatures() & GF_DEMO) ? "disk0" : "disk1"); _vm->showSlide("password"); @@ -627,6 +632,9 @@ public: _labels[1] = _vm->_gfx->createLabel(_vm->_introFont, introMsg2[_vm->getInternLanguage()], 1); cleanup(); + + _vm->setArrowCursor(); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); _state = CHOICE; } }; @@ -741,6 +749,7 @@ public: virtual void enter() { _current = -1; + _vm->_input->setMouseState(MOUSE_DISABLED); } }; @@ -775,12 +784,12 @@ public: } _vm->_gfx->freeLabels(); - _engineFlags &= ~kEngineBlockInput; return _helper->getState("selectcharacter"); } virtual void enter() { _vm->_soundMan->stopMusic(); + _vm->_input->setMouseState(MOUSE_DISABLED); if (!_isDemo) { int label = _vm->_gfx->createLabel(_vm->_menuFont, "CLICK MOUSE BUTTON TO START", 1); @@ -828,6 +837,7 @@ public: virtual void enter() { _allPartsComplete = _vm->allPartsComplete(); + _vm->_input->setMouseState(MOUSE_DISABLED); uint id[4]; if (_allPartsComplete) { diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 2919bc61fd..380f766fe0 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -131,18 +131,16 @@ void Input::updateGameInput() { readInput(); - debugC(3, kDebugInput, "translateInput: input flags (%i, %i, %i, %i)", - !_mouseHidden, - (_engineFlags & kEngineBlockInput) == 0, - (_engineFlags & kEngineWalking) == 0, - (_engineFlags & kEngineChangeLocation) == 0 - ); - - if ((_mouseHidden) || - (_engineFlags & kEngineBlockInput) || + if (!isMouseEnabled() || (_engineFlags & kEngineWalking) || (_engineFlags & kEngineChangeLocation)) { + debugC(3, kDebugInput, "updateGameInput: input flags (mouse: %i, walking: %i, changeloc: %i)", + isMouseEnabled(), + (_engineFlags & kEngineWalking) == 0, + (_engineFlags & kEngineChangeLocation) == 0 + ); + return; } @@ -347,10 +345,28 @@ bool Input::updateInventoryInput() { } -void Input::showCursor(bool visible) { - _mouseHidden = !visible; - _vm->_system->showMouse(visible); +void Input::setMouseState(MouseTriState state) { + assert(state == MOUSE_ENABLED_SHOW || state == MOUSE_ENABLED_HIDE || state == MOUSE_DISABLED); + _mouseState = state; + + switch (_mouseState) { + case MOUSE_ENABLED_HIDE: + case MOUSE_DISABLED: + _vm->_system->showMouse(false); + break; + + case MOUSE_ENABLED_SHOW: + _vm->_system->showMouse(true); + break; + } +} + +MouseTriState Input::getMouseState() { + return _mouseState; } +bool Input::isMouseEnabled() { + return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE); +} } // namespace Parallaction diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index 89a98541bb..c1e912db74 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -49,6 +49,12 @@ struct InputData { uint _label; }; +enum MouseTriState { + MOUSE_ENABLED_SHOW, + MOUSE_ENABLED_HIDE, + MOUSE_DISABLED +}; + class Input { void updateGameInput(); @@ -74,7 +80,6 @@ class Input { Common::Point _mousePos; uint16 _mouseButtons; - bool _mouseHidden; ZonePtr _hoverZone; void enterInventoryMode(); @@ -93,7 +98,7 @@ public: Input(Parallaction *vm) : _vm(vm) { _transCurrentHoverItem = 0; _hasDelayedAction = false; // actived when the character needs to move before taking an action - _mouseHidden = false; + _mouseState = MOUSE_DISABLED; _activeItem._index = 0; _activeItem._id = 0; _mouseButtons = 0; @@ -103,7 +108,6 @@ public: virtual ~Input() { } - void showCursor(bool visible); void getCursorPos(Common::Point& p) { p = _mousePos; } @@ -119,6 +123,12 @@ public: bool getLastKeyDown(uint16 &ascii); void stopHovering(); + + MouseTriState _mouseState; + + void setMouseState(MouseTriState state); + MouseTriState getMouseState(); + bool isMouseEnabled(); }; } // namespace Parallaction diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 47bbda0b4a..0b1fa53e67 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -101,10 +101,8 @@ enum { enum EngineFlags { kEngineQuit = (1 << 0), kEnginePauseJobs = (1 << 1), -// kEngineInventory = (1 << 2), kEngineWalking = (1 << 3), kEngineChangeLocation = (1 << 4), - kEngineBlockInput = (1 << 5), kEngineDragging = (1 << 6), kEngineTransformedDonna = (1 << 7), @@ -428,7 +426,6 @@ public: void setInternLanguage(uint id); uint getInternLanguage(); - }; diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index cf5cf2cd73..e8aa32dea7 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -195,8 +195,6 @@ void Parallaction_ns::setArrowCursor() { _input->_activeItem._id = 0; _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); - _system->showMouse(true); - } void Parallaction_ns::setInventoryCursor(int pos) { @@ -291,6 +289,9 @@ void Parallaction_ns::runPendingZones() { void Parallaction_ns::changeLocation(char *location) { debugC(1, kDebugExec, "changeLocation(%s)", location); + MouseTriState oldMouseState = _input->getMouseState(); + _input->setMouseState(MOUSE_DISABLED); + _soundMan->playLocationMusic(location); _input->stopHovering(); @@ -298,9 +299,7 @@ void Parallaction_ns::changeLocation(char *location) { _zoneTrap = nullZonePtr; - if (_engineFlags & kEngineBlockInput) { - setArrowCursor(); - } + setArrowCursor(); _gfx->showGfxObj(_char._ani->gfxobj, false); _location._animations.remove(_char._ani); @@ -360,10 +359,9 @@ void Parallaction_ns::changeLocation(char *location) { if (_location._hasSound) _soundMan->playSfx(_location._soundFile, 0, true); - debugC(1, kDebugExec, "changeLocation() done"); - - return; + _input->setMouseState(oldMouseState); + debugC(1, kDebugExec, "changeLocation() done"); } -- cgit v1.2.3 From 884a6b1dfb465990757c9ea3619d874a0c8c208c Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 25 Jul 2008 06:35:02 +0000 Subject: Converted BRA to work with the new menu approach. It is not yet well plugged-in as in NS, but it suffices for the moment. svn-id: r33272 --- engines/parallaction/gui.cpp | 92 +++++++++ engines/parallaction/gui.h | 93 +++++++++ engines/parallaction/gui_br.cpp | 333 +++++++++++++++++++------------ engines/parallaction/gui_ns.cpp | 232 ++++++--------------- engines/parallaction/module.mk | 1 + engines/parallaction/parallaction.h | 10 +- engines/parallaction/parallaction_br.cpp | 18 +- 7 files changed, 464 insertions(+), 315 deletions(-) create mode 100644 engines/parallaction/gui.cpp create mode 100644 engines/parallaction/gui.h (limited to 'engines') diff --git a/engines/parallaction/gui.cpp b/engines/parallaction/gui.cpp new file mode 100644 index 0000000000..2dbe64fcf6 --- /dev/null +++ b/engines/parallaction/gui.cpp @@ -0,0 +1,92 @@ +/* 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 "parallaction/gui.h" + +namespace Parallaction { + +bool MenuInputHelper::run() { + if (_newState == 0) { + debugC(3, kDebugExec, "MenuInputHelper has set NULL state"); + return false; + } + + if (_newState != _state) { + debugC(3, kDebugExec, "MenuInputHelper changing state to '%s'", _newState->_name.c_str()); + + _newState->enter(); + _state = _newState; + } + + _newState = _state->run(); + + return true; +} + +MenuInputHelper::~MenuInputHelper() { + StateMap::iterator b = _map.begin(); + for ( ; b != _map.end(); b++) { + delete b->_value; + } + _map.clear(); +} + + +void Parallaction::runGuiFrame() { + if (_input->_inputMode != Input::kInputModeMenu) { + return; + } + + if (!_menuHelper) { + error("No menu helper defined!"); + } + + bool res = _menuHelper->run(); + + if (!res) { + cleanupGui(); + _input->_inputMode = Input::kInputModeGame; + } + +} + +void Parallaction::cleanupGui() { + delete _menuHelper; + _menuHelper = 0; +} + +void Parallaction::setInternLanguage(uint id) { + //TODO: assert id! + + _language = id; + _disk->setLanguage(id); +} + +uint Parallaction::getInternLanguage() { + return _language; +} + + +} // namespace Parallaction diff --git a/engines/parallaction/gui.h b/engines/parallaction/gui.h new file mode 100644 index 0000000000..dc6d1bc71b --- /dev/null +++ b/engines/parallaction/gui.h @@ -0,0 +1,93 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef PARALLACTION_GUI_H +#define PARALLACTION_GUI_H + +#include "common/system.h" +#include "common/hashmap.h" + +#include "parallaction/input.h" +#include "parallaction/parallaction.h" +#include "parallaction/sound.h" + + +namespace Parallaction { + +class MenuInputState; + +class MenuInputHelper { + typedef Common::HashMap StateMap; + + StateMap _map; + MenuInputState *_state; + MenuInputState *_newState; + +public: + MenuInputHelper() : _state(0) { + } + + ~MenuInputHelper(); + + void setState(const Common::String &name) { + // bootstrap routine + _newState = getState(name); + assert(_newState); + } + + void addState(const Common::String &name, MenuInputState *state) { + _map.setVal(name, state); + } + + MenuInputState *getState(const Common::String &name) { + return _map[name]; + } + + bool run(); +}; + +class MenuInputState { + +protected: + MenuInputHelper *_helper; + +public: + MenuInputState(const Common::String &name, MenuInputHelper *helper) : _helper(helper), _name(name) { + debugC(3, kDebugExec, "MenuInputState(%s)", name.c_str()); + _helper->addState(name, this); + } + + Common::String _name; + + virtual ~MenuInputState() { } + + virtual MenuInputState* run() = 0; + virtual void enter() = 0; +}; + + +} // namespace Parallaction + +#endif diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 0be070e345..2a82eca041 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -25,184 +25,267 @@ #include "common/system.h" - +#include "parallaction/gui.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" namespace Parallaction { -enum MenuOptions { - kMenuPart0 = 0, - kMenuPart1 = 1, - kMenuPart2 = 2, - kMenuPart3 = 3, - kMenuPart4 = 4, - kMenuLoadGame = 5, - kMenuQuit = 6 -}; - +class SplashInputState_BR : public MenuInputState { +protected: + Common::String _slideName; + uint32 _timeOut; + Common::String _nextState; + uint32 _startTime; + Palette blackPal; + Palette pal; -void Parallaction_br::guiStart() { + Parallaction_br *_vm; + int _fadeSteps; - // TODO: load progress value from special save game - _progress = 3; +public: + SplashInputState_BR(Parallaction_br *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + } - int option = guiShowMenu(); - switch (option) { - case kMenuQuit: - _engineFlags |= kEngineQuit; - break; + virtual MenuInputState* run() { + if (_fadeSteps > 0) { + pal.fadeTo(blackPal, 1); + _vm->_gfx->setPalette(pal); + _fadeSteps--; + // TODO: properly implement timers to avoid delay calls + _vm->_system->delayMillis(20); + return this; + } - case kMenuLoadGame: - warning("loadgame not yet implemented"); - break; + if (_fadeSteps == 0) { + _vm->freeBackground(); + return _helper->getState(_nextState); + } - default: - _part = option; - _disk->selectArchive(_partNames[_part]); - startPart(); + uint32 curTime = _vm->_system->getMillis(); + if (curTime - _startTime > _timeOut) { + _fadeSteps = 64; + pal.clone(_vm->_gfx->_backgroundInfo.palette); + } + return this; } -} -void Parallaction_br::guiSplash(const char *name) { + virtual void enter() { + _vm->_gfx->clearScreen(); + _vm->_gfx->setBackground(kBackgroundSlide, _slideName.c_str(), 0, 0); + _vm->_gfx->_backgroundInfo.x = (_vm->_screenWidth - _vm->_gfx->_backgroundInfo.width) >> 1; + _vm->_gfx->_backgroundInfo.y = (_vm->_screenHeight - _vm->_gfx->_backgroundInfo.height) >> 1; + _vm->_input->setMouseState(MOUSE_DISABLED); - _gfx->clearScreen(); - _gfx->setBackground(kBackgroundSlide, name, 0, 0); - _gfx->_backgroundInfo.x = (_screenWidth - _gfx->_backgroundInfo.width) >> 1; - _gfx->_backgroundInfo.y = (_screenHeight - _gfx->_backgroundInfo.height) >> 1; - _gfx->updateScreen(); - _system->delayMillis(600); + _startTime = g_system->getMillis(); + _fadeSteps = -1; + } +}; - Palette blackPal; - Palette pal(_gfx->_backgroundInfo.palette); - for (uint i = 0; i < 64; i++) { - pal.fadeTo(blackPal, 1); - _gfx->setPalette(pal); - _gfx->updateScreen(); - _system->delayMillis(20); +class SplashInputState0_BR : public SplashInputState_BR { + +public: + SplashInputState0_BR(Parallaction_br *vm, MenuInputHelper *helper) : SplashInputState_BR(vm, "intro0", helper) { + _slideName = "dyna"; + _timeOut = 600; + _nextState = "intro1"; } +}; -} +class SplashInputState1_BR : public SplashInputState_BR { -#define MENUITEMS_X 250 -#define MENUITEMS_Y 200 +public: + SplashInputState1_BR(Parallaction_br *vm, MenuInputHelper *helper) : SplashInputState_BR(vm, "intro1", helper) { + _slideName = "core"; + _timeOut = 600; + _nextState = "mainmenu"; + } +}; -#define MENUITEM_WIDTH 190 -#define MENUITEM_HEIGHT 18 +class MainMenuInputState_BR : public MenuInputState { + Parallaction_br *_vm; -Frames* Parallaction_br::guiRenderMenuItem(const char *text) { - // this builds a surface containing two copies of the text. - // one is in normal color, the other is inverted. - // the two 'frames' are used to display selected/unselected menu items + #define MENUITEMS_X 250 + #define MENUITEMS_Y 200 - Graphics::Surface *surf = new Graphics::Surface; - surf->create(MENUITEM_WIDTH, MENUITEM_HEIGHT*2, 1); + #define MENUITEM_WIDTH 190 + #define MENUITEM_HEIGHT 18 - // build first frame to be displayed when item is not selected - if (getPlatform() == Common::kPlatformPC) { - _menuFont->setColor(0); - } else { - _menuFont->setColor(7); - } - _menuFont->drawString((byte*)surf->getBasePtr(5, 2), MENUITEM_WIDTH, text); + Frames* renderMenuItem(const char *text) { + // this builds a surface containing two copies of the text. + // one is in normal color, the other is inverted. + // the two 'frames' are used to display selected/unselected menu items - // build second frame to be displayed when item is selected - _menuFont->drawString((byte*)surf->getBasePtr(5, 2 + MENUITEM_HEIGHT), MENUITEM_WIDTH, text); - byte *s = (byte*)surf->getBasePtr(0, MENUITEM_HEIGHT); - for (int i = 0; i < surf->w * MENUITEM_HEIGHT; i++) { - *s++ ^= 0xD; - } + Graphics::Surface *surf = new Graphics::Surface; + surf->create(MENUITEM_WIDTH, MENUITEM_HEIGHT*2, 1); - // wrap the surface into the suitable Frames adapter - return new SurfaceToMultiFrames(2, MENUITEM_WIDTH, MENUITEM_HEIGHT, surf); -} + // build first frame to be displayed when item is not selected + if (_vm->getPlatform() == Common::kPlatformPC) { + _vm->_menuFont->setColor(0); + } else { + _vm->_menuFont->setColor(7); + } + _vm->_menuFont->drawString((byte*)surf->getBasePtr(5, 2), MENUITEM_WIDTH, text); + + // build second frame to be displayed when item is selected + _vm->_menuFont->drawString((byte*)surf->getBasePtr(5, 2 + MENUITEM_HEIGHT), MENUITEM_WIDTH, text); + byte *s = (byte*)surf->getBasePtr(0, MENUITEM_HEIGHT); + for (int i = 0; i < surf->w * MENUITEM_HEIGHT; i++) { + *s++ ^= 0xD; + } + // wrap the surface into the suitable Frames adapter + return new SurfaceToMultiFrames(2, MENUITEM_WIDTH, MENUITEM_HEIGHT, surf); + } -int Parallaction_br::guiShowMenu() { - // TODO: filter menu entries according to progress in game + enum MenuOptions { + kMenuPart0 = 0, + kMenuPart1 = 1, + kMenuPart2 = 2, + kMenuPart3 = 3, + kMenuPart4 = 4, + kMenuLoadGame = 5, + kMenuQuit = 6 + }; #define NUM_MENULINES 7 GfxObj *_lines[NUM_MENULINES]; - const char *menuStrings[NUM_MENULINES] = { - "SEE INTRO", - "NEW GAME", - "SAVED GAME", - "EXIT TO DOS", - "PART 2", - "PART 3", - "PART 4" - }; + static const char *_menuStrings[NUM_MENULINES]; + static const MenuOptions _options[NUM_MENULINES]; - MenuOptions options[NUM_MENULINES] = { - kMenuPart0, - kMenuPart1, - kMenuLoadGame, - kMenuQuit, - kMenuPart2, - kMenuPart3, - kMenuPart4 - }; + int _availItems; + int _selection; - _gfx->clearScreen(); - _gfx->setBackground(kBackgroundSlide, "tbra", 0, 0); - if (getPlatform() == Common::kPlatformPC) { - _gfx->_backgroundInfo.x = 20; - _gfx->_backgroundInfo.y = 50; + void cleanup() { + _vm->_system->showMouse(false); + _vm->hideDialogueStuff(); + + for (int i = 0; i < _availItems; i++) { + delete _lines[i]; + } } - int availItems = 4 + _progress; + void performChoice(int selectedItem) { + switch (selectedItem) { + case kMenuQuit: + _engineFlags |= kEngineQuit; + break; - // TODO: keep track of and destroy menu item frames/surfaces + case kMenuLoadGame: + warning("loadgame not yet implemented"); + break; - int i; - for (i = 0; i < availItems; i++) { - _lines[i] = new GfxObj(0, guiRenderMenuItem(menuStrings[i]), "MenuItem"); - uint id = _gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF); - _gfx->setItemFrame(id, 0); + default: + _vm->startPart(selectedItem); + } } - int selectedItem = -1; - - setMousePointer(0); - - uint32 event; - Common::Point p; - while (true) { +public: + MainMenuInputState_BR(Parallaction_br *vm, MenuInputHelper *helper) : MenuInputState("mainmenu", helper), _vm(vm) { + } - _input->readInput(); + virtual MenuInputState* run() { - event = _input->getLastButtonEvent(); - if ((event == kMouseLeftUp) && selectedItem >= 0) - break; + int event = _vm->_input->getLastButtonEvent(); + if ((event == kMouseLeftUp) && _selection >= 0) { + cleanup(); + performChoice(_options[_selection]); + return 0; + } - _input->getCursorPos(p); + Common::Point p; + _vm->_input->getCursorPos(p); if ((p.x > MENUITEMS_X) && (p.x < (MENUITEMS_X+MENUITEM_WIDTH)) && (p.y > MENUITEMS_Y)) { - selectedItem = (p.y - MENUITEMS_Y) / MENUITEM_HEIGHT; + _selection = (p.y - MENUITEMS_Y) / MENUITEM_HEIGHT; - if (!(selectedItem < availItems)) - selectedItem = -1; + if (!(_selection < _availItems)) + _selection = -1; } else - selectedItem = -1; + _selection = -1; - for (i = 0; i < availItems; i++) { - _gfx->setItemFrame(i, selectedItem == i ? 1 : 0); + for (int i = 0; i < _availItems; i++) { + _vm->_gfx->setItemFrame(i, _selection == i ? 1 : 0); } - _gfx->updateScreen(); - _system->delayMillis(20); + + return this; } - _system->showMouse(false); - hideDialogueStuff(); + virtual void enter() { + _vm->_gfx->clearScreen(); + _vm->_gfx->setBackground(kBackgroundSlide, "tbra", 0, 0); + if (_vm->getPlatform() == Common::kPlatformPC) { + _vm->_gfx->_backgroundInfo.x = 20; + _vm->_gfx->_backgroundInfo.y = 50; + } + + // TODO: load progress from savefile + int progress = 3; + _availItems = 4 + progress; - for (i = 0; i < availItems; i++) { - delete _lines[i]; + // TODO: keep track of and destroy menu item frames/surfaces + int i; + for (i = 0; i < _availItems; i++) { + _lines[i] = new GfxObj(0, renderMenuItem(_menuStrings[i]), "MenuItem"); + uint id = _vm->_gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF); + _vm->_gfx->setItemFrame(id, 0); + } + _selection = -1; + _vm->setArrowCursor(); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); } - return options[selectedItem]; +}; + +const char *MainMenuInputState_BR::_menuStrings[NUM_MENULINES] = { + "SEE INTRO", + "NEW GAME", + "SAVED GAME", + "EXIT TO DOS", + "PART 2", + "PART 3", + "PART 4" +}; + +const MainMenuInputState_BR::MenuOptions MainMenuInputState_BR::_options[NUM_MENULINES] = { + kMenuPart0, + kMenuPart1, + kMenuLoadGame, + kMenuQuit, + kMenuPart2, + kMenuPart3, + kMenuPart4 +}; + + + + + + + +void Parallaction_br::startGui() { + _menuHelper = new MenuInputHelper; + new SplashInputState0_BR(this, _menuHelper); + new SplashInputState1_BR(this, _menuHelper); + new MainMenuInputState_BR(this, _menuHelper); + + _menuHelper->setState("intro0"); + _input->_inputMode = Input::kInputModeMenu; + + do { + _input->readInput(); + if (!_menuHelper->run()) break; + _gfx->beginFrame(); + _gfx->updateScreen(); + } while (true); + + delete _menuHelper; + _menuHelper = 0; } + + } // namespace Parallaction diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index ce68df46e2..815c27bd1c 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -26,6 +26,7 @@ #include "common/system.h" #include "common/hashmap.h" +#include "parallaction/gui.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" #include "parallaction/sound.h" @@ -33,86 +34,7 @@ namespace Parallaction { - -class MenuInputState; - -class MenuInputHelper { - typedef Common::HashMap StateMap; - - StateMap _map; - MenuInputState *_state; - MenuInputState *_newState; - -public: - MenuInputHelper() : _state(0) { - } - - ~MenuInputHelper(); - - void setState(const Common::String &name) { - // bootstrap routine - _newState = getState(name); - assert(_newState); - } - - void addState(const Common::String &name, MenuInputState *state) { - _map.setVal(name, state); - } - - MenuInputState *getState(const Common::String &name) { - return _map[name]; - } - - bool run(); -}; - -class MenuInputState { - -protected: - MenuInputHelper *_helper; - -public: - MenuInputState(const Common::String &name, MenuInputHelper *helper) : _helper(helper), _name(name) { - debugC(3, kDebugExec, "MenuInputState(%s)", name.c_str()); - _helper->addState(name, this); - } - - Common::String _name; - - virtual ~MenuInputState() { } - - virtual MenuInputState* run() = 0; - virtual void enter() = 0; -}; - -bool MenuInputHelper::run() { - if (_newState == 0) { - debugC(3, kDebugExec, "MenuInputHelper has set NULL state"); - return false; - } - - if (_newState != _state) { - debugC(3, kDebugExec, "MenuInputHelper changing state to '%s'", _newState->_name.c_str()); - - _newState->enter(); - _state = _newState; - } - - _newState = _state->run(); - - return true; -} - -MenuInputHelper::~MenuInputHelper() { - StateMap::iterator b = _map.begin(); - for ( ; b != _map.end(); b++) { - delete b->_value; - } - _map.clear(); -} - - -class SplashInputState : public MenuInputState { +class SplashInputState_NS : public MenuInputState { protected: Common::String _slideName; uint32 _timeOut; @@ -122,7 +44,7 @@ protected: Parallaction_ns *_vm; public: - SplashInputState(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + SplashInputState_NS(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { } virtual MenuInputState* run() { @@ -141,20 +63,20 @@ public: } }; -class SplashInputState0 : public SplashInputState { +class SplashInputState0_NS : public SplashInputState_NS { public: - SplashInputState0(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState(vm, "intro0", helper) { + SplashInputState0_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) { _slideName = "intro"; _timeOut = 2000; _nextState = "intro1"; } }; -class SplashInputState1 : public SplashInputState { +class SplashInputState1_NS : public SplashInputState_NS { public: - SplashInputState1(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState(vm, "intro1", helper) { + SplashInputState1_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) { _slideName = "minintro"; _timeOut = 2000; _nextState = "chooselanguage"; @@ -162,7 +84,7 @@ public: }; -class ChooseLanguageInputState : public MenuInputState { +class ChooseLanguageInputState_NS : public MenuInputState { #define BLOCK_WIDTH 16 #define BLOCK_HEIGHT 24 @@ -192,7 +114,7 @@ class ChooseLanguageInputState : public MenuInputState { Parallaction_ns *_vm; public: - ChooseLanguageInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { + ChooseLanguageInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { _allowChoice = false; _nextState = "selectgame"; @@ -260,21 +182,21 @@ public: } }; -const Common::Rect ChooseLanguageInputState::_dosLanguageSelectBlocks[4] = { +const Common::Rect ChooseLanguageInputState_NS::_dosLanguageSelectBlocks[4] = { Common::Rect( 80, 110, 128, 180 ), // Italian Common::Rect( 129, 85, 177, 155 ), // French Common::Rect( 178, 60, 226, 130 ), // English Common::Rect( 227, 35, 275, 105 ) // German }; -const Common::Rect ChooseLanguageInputState::_amigaLanguageSelectBlocks[4] = { +const Common::Rect ChooseLanguageInputState_NS::_amigaLanguageSelectBlocks[4] = { Common::Rect( -1, -1, -1, -1 ), // Italian: not supported by Amiga multi-lingual version Common::Rect( 129, 85, 177, 155 ), // French Common::Rect( 178, 60, 226, 130 ), // English Common::Rect( 227, 35, 275, 105 ) // German }; -class SelectGameInputState : public MenuInputState { +class SelectGameInputState_NS : public MenuInputState { int _choice, _oldChoice; Common::String _nextState[2]; @@ -287,7 +209,7 @@ class SelectGameInputState : public MenuInputState { static const char *loadGameMsg[4]; public: - SelectGameInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { + SelectGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { _choice = 0; _oldChoice = -1; @@ -331,14 +253,14 @@ public: }; -const char *SelectGameInputState::newGameMsg[4] = { +const char *SelectGameInputState_NS::newGameMsg[4] = { "NUOVO GIOCO", "NEUF JEU", "NEW GAME", "NEUES SPIEL" }; -const char *SelectGameInputState::loadGameMsg[4] = { +const char *SelectGameInputState_NS::loadGameMsg[4] = { "GIOCO SALVATO", "JEU SAUVE'", "SAVED GAME", @@ -347,12 +269,12 @@ const char *SelectGameInputState::loadGameMsg[4] = { -class LoadGameInputState : public MenuInputState { +class LoadGameInputState_NS : public MenuInputState { bool _result; Parallaction_ns *_vm; public: - LoadGameInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } + LoadGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } virtual MenuInputState* run() { if (!_result) { @@ -368,13 +290,13 @@ public: -class NewGameInputState : public MenuInputState { +class NewGameInputState_NS : public MenuInputState { Parallaction_ns *_vm; static const char *introMsg3[4]; public: - NewGameInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { + NewGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -412,7 +334,7 @@ public: } }; -const char *NewGameInputState::introMsg3[4] = { +const char *NewGameInputState_NS::introMsg3[4] = { "PRESS LEFT MOUSE BUTTON", "TO SEE INTRO", "PRESS RIGHT MOUSE BUTTON", @@ -421,11 +343,11 @@ const char *NewGameInputState::introMsg3[4] = { -class StartDemoInputState : public MenuInputState { +class StartDemoInputState_NS : public MenuInputState { Parallaction_ns *_vm; public: - StartDemoInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { + StartDemoInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -438,7 +360,7 @@ public: } }; -class SelectCharacterInputState : public MenuInputState { +class SelectCharacterInputState_NS : public MenuInputState { #define PASSWORD_LEN 6 @@ -502,12 +424,12 @@ class SelectCharacterInputState : public MenuInputState { public: - SelectCharacterInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { + SelectCharacterInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { _keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys; _block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); } - ~SelectCharacterInputState() { + ~SelectCharacterInputState_NS() { _block.free(); _emptySlots.free(); } @@ -639,40 +561,40 @@ public: } }; -const char *SelectCharacterInputState::introMsg1[4] = { +const char *SelectCharacterInputState_NS::introMsg1[4] = { "INSERISCI IL CODICE", "ENTREZ CODE", "ENTER CODE", "GIB DEN KODE EIN" }; -const char *SelectCharacterInputState::introMsg2[4] = { +const char *SelectCharacterInputState_NS::introMsg2[4] = { "CODICE ERRATO", "CODE ERRONE", "WRONG CODE", "GIB DEN KODE EIN" }; -const uint16 SelectCharacterInputState::_amigaKeys[][PASSWORD_LEN] = { +const uint16 SelectCharacterInputState_NS::_amigaKeys[][PASSWORD_LEN] = { { 5, 3, 6, 2, 2, 7 }, // dino { 0, 3, 6, 2, 2, 6 }, // donna { 1, 3 ,7, 2, 4, 6 } // dough }; -const uint16 SelectCharacterInputState::_pcKeys[][PASSWORD_LEN] = { +const uint16 SelectCharacterInputState_NS::_pcKeys[][PASSWORD_LEN] = { { 5, 3, 6, 1, 4, 7 }, // dino { 0, 2, 8, 5, 5, 1 }, // donna { 1, 7 ,7, 2, 2, 6 } // dough }; -const char *SelectCharacterInputState::_charStartLocation[] = { +const char *SelectCharacterInputState_NS::_charStartLocation[] = { "test.dino", "test.donna", "test.dough" }; -const Common::Rect SelectCharacterInputState::codeSelectBlocks[9] = { +const Common::Rect SelectCharacterInputState_NS::codeSelectBlocks[9] = { Common::Rect( 111, 129, 127, 153 ), // na Common::Rect( 128, 120, 144, 144 ), // wa Common::Rect( 145, 111, 161, 135 ), // ra @@ -684,7 +606,7 @@ const Common::Rect SelectCharacterInputState::codeSelectBlocks[9] = { Common::Rect( 247, 57, 263, 81 ) // ka }; -const Common::Rect SelectCharacterInputState::codeTrueBlocks[9] = { +const Common::Rect SelectCharacterInputState_NS::codeTrueBlocks[9] = { Common::Rect( 112, 130, 128, 154 ), Common::Rect( 129, 121, 145, 145 ), Common::Rect( 146, 112, 162, 136 ), @@ -697,7 +619,7 @@ const Common::Rect SelectCharacterInputState::codeTrueBlocks[9] = { }; -class ShowCreditsInputState : public MenuInputState { +class ShowCreditsInputState_NS : public MenuInputState { Parallaction_ns *_vm; int _current; uint32 _startTime; @@ -710,7 +632,7 @@ class ShowCreditsInputState : public MenuInputState { static const Credit _credits[6]; public: - ShowCreditsInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { + ShowCreditsInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { } void drawCurrentLabel() { @@ -753,7 +675,7 @@ public: } }; -const ShowCreditsInputState::Credit ShowCreditsInputState::_credits[6] = { +const ShowCreditsInputState_NS::Credit ShowCreditsInputState_NS::_credits[6] = { {"Music and Sound Effects", "MARCO CAPRELLI"}, {"PC Version", "RICCARDO BALLARINO"}, {"Project Manager", "LOVRANO CANEPA"}, @@ -762,12 +684,12 @@ const ShowCreditsInputState::Credit ShowCreditsInputState::_credits[6] = { {"Copyright 1992 Euclidea s.r.l ITALY", "All rights reserved"} }; -class EndIntroInputState : public MenuInputState { +class EndIntroInputState_NS : public MenuInputState { Parallaction_ns *_vm; bool _isDemo; public: - EndIntroInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { + EndIntroInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { _isDemo = (_vm->getFeatures() & GF_DEMO) != 0; } @@ -799,7 +721,7 @@ public: }; -class EndPartInputState : public MenuInputState { +class EndPartInputState_NS : public MenuInputState { Parallaction_ns *_vm; bool _allPartsComplete; @@ -816,7 +738,7 @@ class EndPartInputState : public MenuInputState { public: - EndPartInputState(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { + EndPartInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -860,15 +782,15 @@ public: }; // part completion messages -const char *EndPartInputState::endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; -const char *EndPartInputState::endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"}; -const char *EndPartInputState::endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"}; -const char *EndPartInputState::endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"}; +const char *EndPartInputState_NS::endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; +const char *EndPartInputState_NS::endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"}; +const char *EndPartInputState_NS::endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"}; +const char *EndPartInputState_NS::endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"}; // game completion messages -const char *EndPartInputState::endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; -const char *EndPartInputState::endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"}; -const char *EndPartInputState::endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"}; -const char *EndPartInputState::endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"}; +const char *EndPartInputState_NS::endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"}; +const char *EndPartInputState_NS::endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"}; +const char *EndPartInputState_NS::endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"}; +const char *EndPartInputState_NS::endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"}; void Parallaction_ns::startGui() { _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); @@ -876,14 +798,14 @@ void Parallaction_ns::startGui() { _menuHelper = new MenuInputHelper; assert(_menuHelper); - new SelectGameInputState(this, _menuHelper); - new LoadGameInputState(this, _menuHelper); - new NewGameInputState(this, _menuHelper); - new StartDemoInputState(this, _menuHelper); - new SelectCharacterInputState(this, _menuHelper); - new ChooseLanguageInputState(this, _menuHelper); - new SplashInputState1(this, _menuHelper); - new SplashInputState0(this, _menuHelper); + new SelectGameInputState_NS(this, _menuHelper); + new LoadGameInputState_NS(this, _menuHelper); + new NewGameInputState_NS(this, _menuHelper); + new StartDemoInputState_NS(this, _menuHelper); + new SelectCharacterInputState_NS(this, _menuHelper); + new ChooseLanguageInputState_NS(this, _menuHelper); + new SplashInputState1_NS(this, _menuHelper); + new SplashInputState0_NS(this, _menuHelper); _menuHelper->setState("intro0"); _input->_inputMode = Input::kInputModeMenu; @@ -893,9 +815,9 @@ void Parallaction_ns::startCreditSequence() { _menuHelper = new MenuInputHelper; assert(_menuHelper); - new ShowCreditsInputState(this, _menuHelper); - new EndIntroInputState(this, _menuHelper); - new SelectCharacterInputState(this, _menuHelper); + new ShowCreditsInputState_NS(this, _menuHelper); + new EndIntroInputState_NS(this, _menuHelper); + new SelectCharacterInputState_NS(this, _menuHelper); _menuHelper->setState("showcredits"); _input->_inputMode = Input::kInputModeMenu; @@ -905,46 +827,12 @@ void Parallaction_ns::startEndPartSequence() { _menuHelper = new MenuInputHelper; assert(_menuHelper); - new EndPartInputState(this, _menuHelper); - new SelectCharacterInputState(this, _menuHelper); + new EndPartInputState_NS(this, _menuHelper); + new SelectCharacterInputState_NS(this, _menuHelper); _menuHelper->setState("endpart"); _input->_inputMode = Input::kInputModeMenu; } -void Parallaction::runGuiFrame() { - if (_input->_inputMode != Input::kInputModeMenu) { - return; - } - - if (!_menuHelper) { - error("No menu helper defined!"); - } - - bool res = _menuHelper->run(); - - if (!res) { - cleanupGui(); - _input->_inputMode = Input::kInputModeGame; - } - -} - -void Parallaction::cleanupGui() { - delete _menuHelper; - _menuHelper = 0; -} - -void Parallaction::setInternLanguage(uint id) { - //TODO: assert id! - - _language = id; - _disk->setLanguage(id); -} - -uint Parallaction::getInternLanguage() { - return _language; -} - } // namespace Parallaction diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index fb867f5285..9d44422541 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -14,6 +14,7 @@ MODULE_OBJS := \ font.o \ gfxbase.o \ graphics.o \ + gui.o \ gui_br.o \ gui_ns.o \ input.o \ diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 0b1fa53e67..523ec06a61 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -638,7 +638,8 @@ public: int32 _counters[32]; uint32 _zoneFlags[NUM_LOCATIONS][NUM_ZONES]; - + void startPart(uint part); + void setArrowCursor(); private: LocationParser_br *_locationParser; ProgramParser_br *_programParser; @@ -647,7 +648,6 @@ private: void initFonts(); void freeFonts(); - void setArrowCursor(); void setInventoryCursor(int pos); void changeLocation(char *location); @@ -655,7 +655,6 @@ private: void initPart(); void freePart(); - void startPart(); void setMousePointer(int16 index); void initCursors(); @@ -668,10 +667,7 @@ private: static const char *_partNames[]; - void guiStart(); - int guiShowMenu(); - void guiSplash(const char *name); - Frames* guiRenderMenuItem(const char *text); + void startGui(); static const Callable _dosCallables[6]; diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 9e2a0f10f1..494544fb03 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -109,16 +109,10 @@ void Parallaction_br::callFunction(uint index, void* parm) { int Parallaction_br::go() { - guiSplash("dyna"); - guiSplash("core"); + startGui(); while ((_engineFlags & kEngineQuit) == 0) { - guiStart(); - - if (_engineFlags & kEngineQuit) - return 0; - // initCharacter(); _input->_inputMode = Input::kInputModeGame; @@ -195,7 +189,9 @@ void Parallaction_br::freePart() { _countersNames = 0; } -void Parallaction_br::startPart() { +void Parallaction_br::startPart(uint part) { + _part = part; + _disk->selectArchive(_partNames[_part]); initPart(); @@ -320,9 +316,9 @@ void Parallaction_br::changeCharacter(const char *name) { void Parallaction_br::setArrowCursor() { - - - + // TODO: choose the pointer depending on the active character + // For now, defaults to 0, that corresponds to the default in the original + setMousePointer(0); } void Parallaction_br::setInventoryCursor(int pos) { -- cgit v1.2.3 From a27f0faeef4e09b9625d8183207323dc0d780b17 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 25 Jul 2008 08:27:44 +0000 Subject: Made character visible in BRA. svn-id: r33273 --- engines/parallaction/gui_br.cpp | 2 ++ engines/parallaction/parallaction_br.cpp | 31 +++++++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 2a82eca041..b10237046e 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -283,6 +283,8 @@ void Parallaction_br::startGui() { delete _menuHelper; _menuHelper = 0; + + _input->_inputMode = Input::kInputModeGame; } diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 494544fb03..04036eb4aa 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -232,7 +232,7 @@ void Parallaction_br::changeLocation(char *location) { // free open location stuff clearSubtitles(); freeBackground(); - _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter); + _gfx->clearGfxObjects(kGfxObjNormal); _location._programs.clear(); _location._animations.remove(_char._ani); @@ -244,12 +244,17 @@ void Parallaction_br::changeLocation(char *location) { // free(_location._comment); // _location._comment = 0; -// _location._commands.clear(); -// _location._aCommands.clear(); - + _location._commands.clear(); + _location._aCommands.clear(); // load new location parseLocation(location); + + // kFlagsRemove is cleared because the character defaults to visible on new locations + // script command can hide the character, anyway, so that's why the flag is cleared + // before _location._commands are executed + _char._ani->_flags &= ~kFlagsRemove; + _cmdExec->run(_location._commands); // doLocationEnterTransition(); _cmdExec->run(_location._aCommands); @@ -301,17 +306,19 @@ void Parallaction_br::loadProgram(AnimationPtr a, const char *filename) { void Parallaction_br::changeCharacter(const char *name) { - printf("changeCharacter(%s)\n", name); - const char *charName = _char.getName(); - if (!scumm_stricmp(charName, name)) { - return; + + if (scumm_stricmp(charName, name)) { + debugC(1, kDebugExec, "changeCharacter(%s)", name); + + _char.setName(name); + _char._ani->gfxobj = _gfx->loadAnim(name); + _char._ani->gfxobj->setFlags(kGfxObjCharacter); + _char._ani->gfxobj->clearFlags(kGfxObjNormal); + _char._talk = _disk->loadTalk(name); } - _char.setName(name); - _char._ani->gfxobj = _gfx->loadAnim(name); - _char._ani->gfxobj->setFlags(kGfxObjCharacter); - _char._talk = _disk->loadTalk(name); + _char._ani->_flags |= kFlagsActive; } -- cgit v1.2.3 From 2fc0c3e85933ccbee0b3e0373b45c49d932f5159 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:05:04 +0000 Subject: TINSEL: Updating the palette should only require a call to OSystem::updateScreen and not a blit svn-id: r33274 --- engines/tinsel/palette.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp index 130e58ec5f..3bc2b514b5 100644 --- a/engines/tinsel/palette.cpp +++ b/engines/tinsel/palette.cpp @@ -133,7 +133,7 @@ void PalettesToVideoDAC(void) { pPalQ->posInDAC &= ~PALETTE_MOVED; if (needUpdate) - _vm->screen().update(); + g_system->updateScreen(); } /** -- cgit v1.2.3 From 52a3dd758128ed442900ef57925c16e90c4c6316 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:12:03 +0000 Subject: TINSEL: Get rid of Graphics::Surface class svn-id: r33275 --- engines/tinsel/graphics.cpp | 15 +++++++++------ engines/tinsel/graphics.h | 27 +-------------------------- engines/tinsel/tinsel.cpp | 15 ++++++++------- engines/tinsel/tinsel.h | 4 ++-- 4 files changed, 20 insertions(+), 41 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp index 751b8929ef..cd0937d944 100644 --- a/engines/tinsel/graphics.cpp +++ b/engines/tinsel/graphics.cpp @@ -369,17 +369,20 @@ static void DemoWrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool app /** * Clears both the screen surface buffer and screen to the specified value */ -void ClearScreen(uint32 val) { - uint32 *pDest = (uint32 *)_vm->screen().getData(); - Common::set_to(pDest, (uint32 *)((byte *)pDest + SCREEN_WIDTH * SCREEN_HEIGHT), val); - _vm->screen().update(); +void ClearScreen() { + void *pDest = _vm->screen().getBasePtr(0, 0); + memset(pDest, 0, SCREEN_WIDTH * SCREEN_HEIGHT); + g_system->clearScreen(); + g_system->updateScreen(); } /** * Updates the screen surface within the following rectangle */ void UpdateScreenRect(const Common::Rect &pClip) { - _vm->screen().updateRect(pClip); + byte *pDest = (byte *)_vm->screen().getBasePtr(pClip.left, pClip.top); + g_system->copyRectToScreen(pDest, _vm->screen().pitch, pClip.left, pClip.top, pClip.width(), pClip.height()); + g_system->updateScreen(); } /** @@ -403,7 +406,7 @@ void DrawObject(DRAWOBJECT *pObj) { } // Get destination starting point - destPtr = _vm->screen().getBasePtr(pObj->xPos, pObj->yPos); + destPtr = (byte *)_vm->screen().getBasePtr(pObj->xPos, pObj->yPos); // Handle various draw types uint8 typeId = pObj->flags & 0xff; diff --git a/engines/tinsel/graphics.h b/engines/tinsel/graphics.h index e080e08f58..85299d4873 100644 --- a/engines/tinsel/graphics.h +++ b/engines/tinsel/graphics.h @@ -43,31 +43,6 @@ struct PALQ; #define SCRN_CENTRE_X ((SCREEN_WIDTH - 1) / 2) // screen centre x #define SCRN_CENTRE_Y ((SCREEN_HEIGHT - 1) / 2) // screen centre y -/** Class representing either a buffered surface or the physical screen. */ -class Surface : public Graphics::Surface { -private: - bool _isScreen; -public: - Surface(bool isScreen = false) { _isScreen = isScreen; } - Surface(int Width, int Height) { create(Width, Height, 1); _isScreen = false; } - - // Surface methods - byte *getData() { return (byte *)pixels; } - byte *getBasePtr(int x, int y) { return (byte *)Graphics::Surface::getBasePtr(x, y); } - - void update() { - if (_isScreen) { - g_system->copyRectToScreen((const byte *)pixels, pitch, 0, 0, w, h); - g_system->updateScreen(); - } - } - void updateRect(const Common::Rect &r) { - g_system->copyRectToScreen(getBasePtr(r.left, r.top), pitch, r.left, r.top, r.width(), r.height()); - g_system->updateScreen(); - } - -}; - /** draw object structure - only used when drawing objects */ struct DRAWOBJECT { char *charBase; // character set base address @@ -92,7 +67,7 @@ struct DRAWOBJECT { |* Function Prototypes *| \*----------------------------------------------------------------------*/ -void ClearScreen(uint32 val); +void ClearScreen(); void DrawObject(DRAWOBJECT *pObj); // called to update a rectangle on the video screen from a video page diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 946c9338ba..1f56385283 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -54,6 +54,7 @@ #include "tinsel/music.h" #include "tinsel/object.h" #include "tinsel/pid.h" +#include "tinsel/polygons.h" #include "tinsel/savescn.h" #include "tinsel/scn.h" #include "tinsel/serializer.h" @@ -386,7 +387,7 @@ void MouseProcess(CORO_PARAM, const void *) { static void MasterScriptProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); @@ -463,13 +464,13 @@ void syncSCdata(Serializer &s) { static void RestoredProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); // get the stuff copied to process when it was created - _ctx->pic = *((PINT_CONTEXT *)param); + _ctx->pic = *((INT_CONTEXT **)param); _ctx->pic = RestoreInterpretContext(_ctx->pic); CORO_INVOKE_1(Interpret, _ctx->pic); @@ -477,11 +478,11 @@ static void RestoredProcess(CORO_PARAM, const void *param) { CORO_END_CODE; } -void RestoreProcess(PINT_CONTEXT pic) { +void RestoreProcess(INT_CONTEXT *pic) { g_scheduler->createProcess(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); } -void RestoreMasterProcess(PINT_CONTEXT pic) { +void RestoreMasterProcess(INT_CONTEXT *pic) { g_scheduler->createProcess(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); } @@ -516,7 +517,7 @@ void ChangeScene() { break; } } else if (--CountOut == 0) { - ClearScreen(0L); + ClearScreen(); NewScene(NextScene.scene, NextScene.entry); NextScene.scene = 0; @@ -599,7 +600,7 @@ static const GameSettings tinselSettings[] = { }; TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) : - Engine(syst), _gameDescription(gameDesc), _screenSurface(true) { + Engine(syst), _gameDescription(gameDesc) { _vm = this; // Setup mixer diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 6b838924e8..9ffadfe8c1 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -76,7 +76,7 @@ class TinselEngine : public ::Engine { int _gameId; Common::KeyState _keyPressed; Common::RandomSource _random; - Surface _screenSurface; + Graphics::Surface _screenSurface; Common::Point _mousePos; uint8 _dosPlayerDir; Console *_console; @@ -123,7 +123,7 @@ public: Common::String getSavegamePattern() const; Common::String getSavegameFilename(int16 saveNum) const; Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; } - Surface &screen() { return _screenSurface; } + Graphics::Surface &screen() { return _screenSurface; } Common::Point getMousePosition() const { return _mousePos; } void setMousePosition(const Common::Point &pt) { -- cgit v1.2.3 From 3d6badc476fa12f228702d15c1395da376aa7be9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:13:08 +0000 Subject: TINSEL: ActorTag & PolyTag abused a SCNHANDLE and some global enums to keep a trinary state -- fixed that by introducing a new enum HotSpotTag svn-id: r33276 --- engines/tinsel/pdisplay.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/pdisplay.cpp b/engines/tinsel/pdisplay.cpp index cf7f130ef6..b5488da3e8 100644 --- a/engines/tinsel/pdisplay.cpp +++ b/engines/tinsel/pdisplay.cpp @@ -70,8 +70,11 @@ extern int BackgroundHeight(void); #define POSY 0 // Y-co-ord of these position displays -#define ACTOR_TAG 0xffffffff - +enum HotSpotTag { + NO_HOTSPOT_TAG, + POLY_HOTSPOT_TAG, + ACTOR_HOTSPOT_TAG +}; //----------------- LOCAL GLOBAL DATA -------------------- @@ -337,7 +340,7 @@ static bool InHotSpot(int ano, int aniX, int aniY, int *pxtext, int *pytext) { * the tag or, if tag already displayed, maintain the tag's position on * the screen. */ -static bool ActorTag(int curX, int curY, SCNHANDLE *pTag, OBJECT **ppText) { +static bool ActorTag(int curX, int curY, HotSpotTag *pTag, OBJECT **ppText) { static int Loffset = 0, Toffset = 0; // Values when tag was displayed int nLoff, nToff; // new values, to keep tag in place int ano; @@ -349,7 +352,7 @@ static bool ActorTag(int curX, int curY, SCNHANDLE *pTag, OBJECT **ppText) { while ((ano = NextTaggedActor()) != 0) { if (InHotSpot(ano, curX, curY, &xtext, &ytext)) { // Put up or maintain actor tag - if (*pTag != ACTOR_TAG) + if (*pTag != ACTOR_HOTSPOT_TAG) newActor = true; else if (ano != GetTaggedActor()) newActor = true; // Different actor @@ -362,7 +365,7 @@ static bool ActorTag(int curX, int curY, SCNHANDLE *pTag, OBJECT **ppText) { if (*ppText) MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText); - *pTag = ACTOR_TAG; + *pTag = ACTOR_HOTSPOT_TAG; SaveTaggedActor(ano); // This actor tagged SaveTaggedPoly(NOPOLY); // No tagged polygon @@ -387,8 +390,8 @@ static bool ActorTag(int curX, int curY, SCNHANDLE *pTag, OBJECT **ppText) { } // No tagged actor - if (*pTag == ACTOR_TAG) { - *pTag = 0; + if (*pTag == ACTOR_HOTSPOT_TAG) { + *pTag = NO_HOTSPOT_TAG; SaveTaggedActor(0); } return false; @@ -401,7 +404,7 @@ static bool ActorTag(int curX, int curY, SCNHANDLE *pTag, OBJECT **ppText) { * EXIT polygon, its pointState flag is set to POINTING. If its Glitter * code contains a printtag() call, its tagState flag gets set to TAG_ON. */ -static bool PolyTag(SCNHANDLE *pTag, OBJECT **ppText) { +static bool PolyTag(HotSpotTag *pTag, OBJECT **ppText) { static int Loffset = 0, Toffset = 0; // Values when tag was displayed int nLoff, nToff; // new values, to keep tag in place HPOLYGON hp; @@ -423,14 +426,14 @@ static bool PolyTag(SCNHANDLE *pTag, OBJECT **ppText) { MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText); *ppText = NULL; } - *pTag = POLY_TAG; + *pTag = POLY_HOTSPOT_TAG; SaveTaggedActor(0); // No tagged actor SaveTaggedPoly(hp); // This polygon tagged } return true; } else if (hp != NOPOLY && PolyTagState(hp) == TAG_ON) { // Put up or maintain polygon tag - if (*pTag != POLY_TAG) + if (*pTag != POLY_HOTSPOT_TAG) newPoly = true; // A new polygon (no current) else if (hp != GetTaggedPoly()) newPoly = true; // Different polygon @@ -441,7 +444,7 @@ static bool PolyTag(SCNHANDLE *pTag, OBJECT **ppText) { if (*ppText) MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), *ppText); - *pTag = POLY_TAG; + *pTag = POLY_HOTSPOT_TAG; SaveTaggedActor(0); // No tagged actor SaveTaggedPoly(hp); // This polygon tagged @@ -492,8 +495,8 @@ static bool PolyTag(SCNHANDLE *pTag, OBJECT **ppText) { } // No tagged polygon - if (*pTag == POLY_TAG) { - *pTag = 0; + if (*pTag == POLY_HOTSPOT_TAG) { + *pTag = NO_HOTSPOT_TAG; SaveTaggedPoly(NOPOLY); } return false; @@ -507,13 +510,13 @@ void TagProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; OBJECT *pText; // text object pointer - SCNHANDLE Tag; + HotSpotTag Tag; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); _ctx->pText = NULL; - _ctx->Tag = 0; + _ctx->Tag = NO_HOTSPOT_TAG; SaveTaggedActor(0); // No tagged actor yet SaveTaggedPoly(NOPOLY); // No tagged polygon yet @@ -541,7 +544,7 @@ void TagProcess(CORO_PARAM, const void *) { // kill current text objects MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pText); _ctx->pText = NULL; - _ctx->Tag = 0; + _ctx->Tag = NO_HOTSPOT_TAG; } } -- cgit v1.2.3 From 75ff7a1b0e87a016fbc545ed06de98e56720c0f8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:15:03 +0000 Subject: cleanup svn-id: r33277 --- engines/tinsel/cliprect.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/cliprect.h b/engines/tinsel/cliprect.h index 96b4b3314e..28a66c312c 100644 --- a/engines/tinsel/cliprect.h +++ b/engines/tinsel/cliprect.h @@ -40,7 +40,7 @@ typedef Common::List RectList; |* Clip Rect Function Prototypes *| \*----------------------------------------------------------------------*/ -void ResetClipRect(void); // Resets the clipping rectangle allocator +void ResetClipRect(); // Resets the clipping rectangle allocator void AddClipRect( // Allocate a clipping rectangle from the free list const Common::Rect &pClip); // clip rectangle dimensions to allocate @@ -64,7 +64,7 @@ void FindMovingObjects( // Creates clipping rectangles for all the objects that bool bVelocity, // when set, objects pos is updated with velocity bool bScrolled); // when set, playfield has scrolled -void MergeClipRect(void); // Merges any clipping rectangles that overlap +void MergeClipRect(); // Merges any clipping rectangles that overlap void UpdateClipRect( // Redraws all objects within this clipping rectangle OBJECT *pObjList, // object list to draw -- cgit v1.2.3 From f96faab2ba530375dbd32f31761430535473dd60 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:15:32 +0000 Subject: TINSEL: Got rid of NO_TAG (not used) svn-id: r33278 --- engines/tinsel/polygons.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/tinsel/polygons.h b/engines/tinsel/polygons.h index c0e75ed3e7..90c57d5f99 100644 --- a/engines/tinsel/polygons.h +++ b/engines/tinsel/polygons.h @@ -47,7 +47,7 @@ enum { // tagState enum TSTATE { - NO_TAG, TAG_OFF, TAG_ON + TAG_OFF, TAG_ON }; // pointState -- cgit v1.2.3 From bfcc4339c1792a33386a6b3b584e9bb839375c36 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:17:47 +0000 Subject: More tinsel cleanup svn-id: r33280 --- engines/tinsel/cliprect.cpp | 65 +++++++++++++++---------------- engines/tinsel/polygons.cpp | 93 ++++++++++++++++++++++----------------------- engines/tinsel/rince.h | 4 +- engines/tinsel/scene.h | 6 --- 4 files changed, 81 insertions(+), 87 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/cliprect.cpp b/engines/tinsel/cliprect.cpp index 632a84f723..b67ae7b17f 100644 --- a/engines/tinsel/cliprect.cpp +++ b/engines/tinsel/cliprect.cpp @@ -61,12 +61,12 @@ const RectList &GetClipRects() { * @param pSrc2 Pointer to a source rectangle */ bool IntersectRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) { - pDest.left = (pSrc1.left > pSrc2.left) ? pSrc1.left : pSrc2.left; - pDest.top = (pSrc1.top > pSrc2.top) ? pSrc1.top : pSrc2.top; - pDest.right = (pSrc1.right < pSrc2.right) ? pSrc1.right : pSrc2.right; - pDest.bottom = (pSrc1.bottom < pSrc2.bottom) ? pSrc1.bottom : pSrc2.bottom; + pDest.left = MAX(pSrc1.left, pSrc2.left); + pDest.top = MAX(pSrc1.top, pSrc2.top); + pDest.right = MIN(pSrc1.right, pSrc2.right); + pDest.bottom = MIN(pSrc1.bottom, pSrc2.bottom); - return (pDest.right > pDest.left && pDest.bottom > pDest.top); + return !pDest.isEmpty(); } /** @@ -77,12 +77,12 @@ bool IntersectRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Co * @param pSrc2 a source rectangle */ bool UnionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) { - pDest.left = (pSrc1.left < pSrc2.left) ? pSrc1.left : pSrc2.left; - pDest.top = (pSrc1.top < pSrc2.top) ? pSrc1.top : pSrc2.top; - pDest.right = (pSrc1.right > pSrc2.right) ? pSrc1.right : pSrc2.right; - pDest.bottom = (pSrc1.bottom > pSrc2.bottom) ? pSrc1.bottom : pSrc2.bottom; + pDest.left = MIN(pSrc1.left, pSrc2.left); + pDest.top = MIN(pSrc1.top, pSrc2.top); + pDest.right = MAX(pSrc1.right, pSrc2.right); + pDest.bottom = MAX(pSrc1.bottom, pSrc2.bottom); - return (pDest.right > pDest.left && pDest.bottom > pDest.top); + return !pDest.isEmpty(); } /** @@ -93,12 +93,12 @@ bool UnionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common static bool LooseIntersectRectangle(const Common::Rect &pSrc1, const Common::Rect &pSrc2) { Common::Rect pDest; - pDest.left = (pSrc1.left > pSrc2.left) ? pSrc1.left : pSrc2.left; - pDest.top = (pSrc1.top > pSrc2.top) ? pSrc1.top : pSrc2.top; - pDest.right = (pSrc1.right < pSrc2.right) ? pSrc1.right : pSrc2.right; - pDest.bottom = (pSrc1.bottom < pSrc2.bottom) ? pSrc1.bottom : pSrc2.bottom; + pDest.left = MAX(pSrc1.left, pSrc2.left); + pDest.top = MAX(pSrc1.top, pSrc2.top); + pDest.right = MIN(pSrc1.right, pSrc2.right); + pDest.bottom = MIN(pSrc1.bottom, pSrc2.bottom); - return (pDest.right >= pDest.left && pDest.bottom >= pDest.top); + return pDest.isValidRect(); } /** @@ -174,26 +174,27 @@ void FindMovingObjects(OBJECT *pObjList, Common::Point *pWin, Common::Rect *pCli * Merges any clipping rectangles that overlap to try and reduce * the total number of clip rectangles. */ -void MergeClipRect(void) { - if (s_rectList.size() > 1) { - RectList::iterator rOuter, rInner; +void MergeClipRect() { + if (s_rectList.size() <= 1) + return; - for (rOuter = s_rectList.begin(); rOuter != s_rectList.end(); ++rOuter) { - rInner = rOuter; - while (++rInner != s_rectList.end()) { + RectList::iterator rOuter, rInner; - if (LooseIntersectRectangle(*rOuter, *rInner)) { - // these two rectangles overlap or - // are next to each other - merge them + for (rOuter = s_rectList.begin(); rOuter != s_rectList.end(); ++rOuter) { + rInner = rOuter; + while (++rInner != s_rectList.end()) { - UnionRectangle(*rOuter, *rOuter, *rInner); + if (LooseIntersectRectangle(*rOuter, *rInner)) { + // these two rectangles overlap or + // are next to each other - merge them - // remove the inner rect from the list - s_rectList.erase(rInner); + UnionRectangle(*rOuter, *rOuter, *rInner); - // move back to beginning of list - rInner = rOuter; - } + // remove the inner rect from the list + s_rectList.erase(rInner); + + // move back to beginning of list + rInner = rOuter; } } } @@ -298,8 +299,8 @@ void UpdateClipRect(OBJECT *pObjList, Common::Point *pWin, Common::Rect *pClip) // copy objects properties to local object currentObj.width = pObj->width; currentObj.height = pObj->height; - currentObj.xPos = (short) x; - currentObj.yPos = (short) y; + currentObj.xPos = (short)x; + currentObj.yPos = (short)y; currentObj.pPal = pObj->pPal; currentObj.constant = pObj->constant; currentObj.hBits = pObj->hBits; diff --git a/engines/tinsel/polygons.cpp b/engines/tinsel/polygons.cpp index fb533a7040..d73e290277 100644 --- a/engines/tinsel/polygons.cpp +++ b/engines/tinsel/polygons.cpp @@ -37,6 +37,12 @@ namespace Tinsel { //----------------- LOCAL DEFINES -------------------- +/** different types of polygon */ +enum POLY_TYPE { + POLY_PATH, POLY_NPATH, POLY_BLOCK, POLY_REFER, POLY_EFFECT, + POLY_EXIT, POLY_TAG +}; + // Note 7/10/94, with adjacency reduction ANKHMAP max is 3, UNSEEN max is 4 // so reduced this back to 6 (from 12) for now. @@ -1141,29 +1147,6 @@ void EnableBlock(int blockno) { } } -/** - * Convert a TAG to an EX_TAG poly. - */ -void DisableTag(int tagno) { - TAGSTATE *pts; - - for (int i = 0; i < MAX_POLY; i++) { - if (Polys[i] && Polys[i]->polytype == TAG && Polys[i]->polyID == tagno) { - Polys[i]->polytype = EX_TAG; - Polys[i]->tagState = TAG_OFF; - Polys[i]->pointState = NOT_POINTING; - } - } - - pts = &TagStates[SceneTags[currentTScene].offset]; - for (int j = 0; j < SceneTags[currentTScene].nooftags; j++, pts++) { - if (pts->tid == tagno) { - pts->enabled = false; - break; - } - } -} - /** * Convert an EX_TAG to a TAG poly. */ @@ -1204,6 +1187,29 @@ void EnableExit(int exitno) { } } +/** + * Convert a TAG to an EX_TAG poly. + */ +void DisableTag(int tagno) { + TAGSTATE *pts; + + for (int i = 0; i < MAX_POLY; i++) { + if (Polys[i] && Polys[i]->polytype == TAG && Polys[i]->polyID == tagno) { + Polys[i]->polytype = EX_TAG; + Polys[i]->tagState = TAG_OFF; + Polys[i]->pointState = NOT_POINTING; + } + } + + pts = &TagStates[SceneTags[currentTScene].offset]; + for (int j = 0; j < SceneTags[currentTScene].nooftags; j++, pts++) { + if (pts->tid == tagno) { + pts->enabled = false; + break; + } + } +} + /** * Convert a EXIT to an EX_EXIT poly. */ @@ -1419,6 +1425,7 @@ static void SetExTags(SCNHANDLE ph) { return; } } + i = numScenesT++; currentTScene = i; assert(numScenesT < MAX_SCENES); // Dead tag remembering: scene limit @@ -1441,11 +1448,7 @@ static void SetExTags(SCNHANDLE ph) { /** * Called at the start of a scene, nobbles EXIT polygons which should be dead. */ -#ifdef DEBUG -void SetExExits(SCNHANDLE ph) { -#else static void SetExExits(SCNHANDLE ph) { -#endif TAGSTATE *pts; int i, j; @@ -1488,29 +1491,29 @@ static void FiddlyBit(POLYGON *p) { int t1, t2; // General purpose temp. variables // Enclosing external rectangle - t1 = p->cx[0] > p->cx[1] ? p->cx[0] : p->cx[1]; - t2 = p->cx[2] > p->cx[3] ? p->cx[2] : p->cx[3]; - p->pright = (short)(t1 > t2 ? t1 : t2); + t1 = MAX(p->cx[0], p->cx[1]); + t2 = MAX(p->cx[2], p->cx[3]); + p->pright = MAX(t1, t2); - t1 = p->cx[0] < p->cx[1] ? p->cx[0] : p->cx[1]; - t2 = p->cx[2] < p->cx[3] ? p->cx[2] : p->cx[3]; - p->pleft = (short)(t1 < t2 ? t1 : t2); + t1 = MIN(p->cx[0], p->cx[1]); + t2 = MIN(p->cx[2], p->cx[3]); + p->pleft = MIN(t1, t2); - t1 = p->cy[0] > p->cy[1] ? p->cy[0] : p->cy[1]; - t2 = p->cy[2] > p->cy[3] ? p->cy[2] : p->cy[3]; - p->pbottom = (short)(t1 > t2 ? t1 : t2); + t1 = MAX(p->cy[0], p->cy[1]); + t2 = MAX(p->cy[2], p->cy[3]); + p->pbottom = MAX(t1, t2); - t1 = p->cy[0] < p->cy[1] ? p->cy[0] : p->cy[1]; - t2 = p->cy[2] < p->cy[3] ? p->cy[2] : p->cy[3]; - p->ptop = (short)(t1 < t2 ? t1 : t2); + t1 = MIN(p->cy[0], p->cy[1]); + t2 = MIN(p->cy[2], p->cy[3]); + p->ptop = MIN(t1, t2); // Rectangles enclosing each side and each side's magic numbers for (t1 = 0; t1 < 4; t1++) { - p->lright[t1] = p->cx[t1] > p->cx[(t1+1)%4] ? p->cx[t1] : p->cx[(t1+1)%4]; - p->lleft[t1] = p->cx[t1] < p->cx[(t1+1)%4] ? p->cx[t1] : p->cx[(t1+1)%4]; + p->lright[t1] = MAX(p->cx[t1], p->cx[(t1+1)%4]); + p->lleft[t1] = MIN(p->cx[t1], p->cx[(t1+1)%4]); - p->ltop[t1] = p->cy[t1] < p->cy[(t1+1)%4] ? p->cy[t1] : p->cy[(t1+1)%4]; - p->lbottom[t1] = p->cy[t1] > p->cy[(t1+1)%4] ? p->cy[t1] : p->cy[(t1+1)%4]; + p->ltop[t1] = MIN(p->cy[t1], p->cy[(t1+1)%4]); + p->lbottom[t1] = MAX(p->cy[t1], p->cy[(t1+1)%4]); p->a[t1] = p->cy[t1] - p->cy[(t1+1)%4]; p->b[t1] = p->cx[(t1+1)%4] - p->cx[t1]; @@ -1522,11 +1525,7 @@ static void FiddlyBit(POLYGON *p) { * Calculate a point approximating to the centre of a polygon. * Not very sophisticated. */ -#ifdef DEBUG -void PseudoCentre(POLYGON *p) { -#else static void PseudoCentre(POLYGON *p) { -#endif p->pcentrex = (p->cx[0] + p->cx[1] + p->cx[2] + p->cx[3])/4; p->pcentrey = (p->cy[0] + p->cy[1] + p->cy[2] + p->cy[3])/4; diff --git a/engines/tinsel/rince.h b/engines/tinsel/rince.h index a3ed5bd845..7ccf017c65 100644 --- a/engines/tinsel/rince.h +++ b/engines/tinsel/rince.h @@ -67,7 +67,7 @@ struct MACTOR { IND InDifficulty; -/* For use in 'follow nodes' polygons */ + /* For use in 'follow nodes' polygons */ HPOLYGON hFnpath; NPS npstatus; int line; @@ -77,7 +77,7 @@ struct MACTOR { bool TagReelRunning; - /* Used internally */ + /* Used internally */ DIRREEL dirn; // Current reel int scale; // Current scale int scount; // Step count for walking reel synchronisation diff --git a/engines/tinsel/scene.h b/engines/tinsel/scene.h index baecac40b9..d0fc6e1ae3 100644 --- a/engines/tinsel/scene.h +++ b/engines/tinsel/scene.h @@ -55,12 +55,6 @@ enum MASK_TYPE{ ACT_ALWAYS = -2 }; -/** different types of polygon */ -enum POLY_TYPE { - POLY_PATH, POLY_NPATH, POLY_BLOCK, POLY_REFER, POLY_EFFECT, - POLY_EXIT, POLY_TAG -}; - /** different scales */ enum SCALE { SCALE_DEFAULT, SCALE_LARGE, SCALE_MEDIUM, SCALE_SMALL, -- cgit v1.2.3 From 054fe75422167ecc30757f944cb16c2fc6a56416 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:18:39 +0000 Subject: TINSEL: Fixed forgotten ClearScreen(0) call svn-id: r33281 --- engines/tinsel/savescn.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/savescn.cpp b/engines/tinsel/savescn.cpp index a21161e872..9f0d7b9039 100644 --- a/engines/tinsel/savescn.cpp +++ b/engines/tinsel/savescn.cpp @@ -35,6 +35,7 @@ #include "tinsel/inventory.h" #include "tinsel/music.h" #include "tinsel/pid.h" +#include "tinsel/polygons.h" #include "tinsel/rince.h" #include "tinsel/savescn.h" #include "tinsel/sched.h" @@ -53,10 +54,10 @@ extern SCNHANDLE GetBgroundHandle(void); extern void SetDoFadeIn(bool tf); // In DOS_DW.C -void RestoreMasterProcess(PINT_CONTEXT pic); +void RestoreMasterProcess(INT_CONTEXT *pic); // in EVENTS.C (declared here and not in events.h because of strange goings-on) -void RestoreProcess(PINT_CONTEXT pic); +void RestoreProcess(INT_CONTEXT *pic); // in PLAY.C extern void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y); @@ -227,7 +228,7 @@ static int DoRestoreScene(SAVED_DATA *rsd, int n) { case RS_COUNT: _vm->_sound->stopAllSamples(); - ClearScreen(0L); + ClearScreen(); RestoreDeadPolys(rsd->SavedDeadPolys); NewScene(rsd->SavedSceneHandle, NO_ENTRY_NUM); SetDoFadeIn(!bNoFade); -- cgit v1.2.3 From 04985c8ac94027fd05351866f243bbb6d590c4f9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 25 Jul 2008 09:19:06 +0000 Subject: TINSEL: Got rid of PIMAGE, PINT_CONTEXT, PINV_OBJECT, PINV_DEF, PCONFBOX, PCONFINIT svn-id: r33282 --- engines/tinsel/actors.cpp | 9 ++-- engines/tinsel/bg.cpp | 2 +- engines/tinsel/cursor.cpp | 6 +-- engines/tinsel/events.cpp | 2 +- engines/tinsel/font.cpp | 6 +-- engines/tinsel/inventory.cpp | 110 ++++++++++++++++++++++--------------------- engines/tinsel/inventory.h | 1 - engines/tinsel/object.h | 1 - engines/tinsel/pcode.cpp | 34 ++++++------- engines/tinsel/pcode.h | 5 +- engines/tinsel/play.cpp | 4 +- engines/tinsel/rince.cpp | 5 +- engines/tinsel/scene.cpp | 3 +- engines/tinsel/tinlib.cpp | 8 ++-- 14 files changed, 98 insertions(+), 98 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp index 5e4a17fb65..c2f01added 100644 --- a/engines/tinsel/actors.cpp +++ b/engines/tinsel/actors.cpp @@ -34,6 +34,7 @@ #include "tinsel/object.h" // for POBJECT #include "tinsel/pcode.h" #include "tinsel/pid.h" +#include "tinsel/polygons.h" #include "tinsel/rince.h" #include "tinsel/sched.h" #include "tinsel/serializer.h" @@ -177,7 +178,7 @@ struct ATP_INIT { static void ActorTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created @@ -203,14 +204,14 @@ static void ActorTinselProcess(CORO_PARAM, const void *param) { //--------------------------------------------------------------------------- struct RATP_INIT { - PINT_CONTEXT pic; + INT_CONTEXT *pic; int id; // Actor number }; static void ActorRestoredProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created @@ -227,7 +228,7 @@ static void ActorRestoredProcess(CORO_PARAM, const void *param) { CORO_END_CODE; } -void RestoreActorProcess(int id, PINT_CONTEXT pic) { +void RestoreActorProcess(int id, INT_CONTEXT *pic) { RATP_INIT r = { pic, id }; g_scheduler->createProcess(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); diff --git a/engines/tinsel/bg.cpp b/engines/tinsel/bg.cpp index 922e21bd18..9c1e5f1540 100644 --- a/engines/tinsel/bg.cpp +++ b/engines/tinsel/bg.cpp @@ -161,7 +161,7 @@ void ChangePalette(SCNHANDLE hPal) { */ void startupBackground(SCNHANDLE bfilm) { const FILM *pfilm; - PIMAGE pim; + IMAGE *pim; BgroundHandle = bfilm; // Save handle in case of Save_Scene() diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp index 042c5b88e3..4eb6b98da3 100644 --- a/engines/tinsel/cursor.cpp +++ b/engines/tinsel/cursor.cpp @@ -105,7 +105,7 @@ static void MoveCursor(void); */ static void InitCurTrailObj(int i, int x, int y) { const FREEL *pfr; // pointer to reel - PIMAGE pim; // pointer to image + IMAGE *pim; // pointer to image const MULTI_INIT *pmi; // MULTI_INIT structure const FILM *pfilm; @@ -354,7 +354,7 @@ void DelAuxCursor(void) { * Save animation offsets from the image if required. */ void SetAuxCursor(SCNHANDLE hFilm) { - PIMAGE pim; // Pointer to auxillary cursor's image + IMAGE *pim; // Pointer to auxillary cursor's image const FREEL *pfr; const MULTI_INIT *pmi; const FILM *pfilm; @@ -461,7 +461,7 @@ static void InitCurObj(void) { const FILM *pfilm; const FREEL *pfr; const MULTI_INIT *pmi; - PIMAGE pim; + IMAGE *pim; pim = GetImageFromFilm(CursorHandle, 0, &pfr, &pmi, &pfilm);// Get pointer to image assert(BackPal()); // no background palette diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp index dea699a75d..bf9f428fd4 100644 --- a/engines/tinsel/events.cpp +++ b/engines/tinsel/events.cpp @@ -138,7 +138,7 @@ struct TP_INIT { static void PolyTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; bool took_control; // Set if this function takes control CORO_END_CONTEXT(_ctx); diff --git a/engines/tinsel/font.cpp b/engines/tinsel/font.cpp index 335ba031fe..620298867e 100644 --- a/engines/tinsel/font.cpp +++ b/engines/tinsel/font.cpp @@ -78,18 +78,18 @@ void TalkFontHandle(SCNHANDLE hf) { */ void fettleFontPal(SCNHANDLE fontPal) { const FONT *pFont; - PIMAGE pImg; + IMAGE *pImg; assert(fontPal); assert(hTagFont); // Tag font not declared assert(hTalkFont); // Talk font not declared pFont = (const FONT *)LockMem(hTagFont); - pImg = (PIMAGE)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0 + pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0 pImg->hImgPal = TO_LE_32(fontPal); pFont = (const FONT *)LockMem(hTalkFont); - pImg = (PIMAGE)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0 + pImg = (IMAGE *)LockMem(FROM_LE_32(pFont->fontInit.hObjImg)); // get image for char 0 pImg->hImgPal = TO_LE_32(fontPal); } diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp index aef171c2a2..2a0f3695c0 100644 --- a/engines/tinsel/inventory.cpp +++ b/engines/tinsel/inventory.cpp @@ -224,7 +224,7 @@ static SCNHANDLE winPartsf = 0; // Window members and cursors' graphic data static SCNHANDLE flagFilm = 0; // Window members and cursors' graphic data static SCNHANDLE configStrings[20]; -static PINV_OBJECT pio = 0; // Inventory objects' data +static INV_OBJECT *pio = 0; // Inventory objects' data static int numObjects = 0; // Number of inventory objects @@ -267,7 +267,6 @@ struct INV_DEF { bool bMax; // Maximised last time open? }; -typedef INV_DEF *PINV_DEF; static INV_DEF InvD[NUM_INV]; // Conversation + 2 inventories + ... @@ -362,24 +361,27 @@ static int lX = 0; // used by SlideMSlider() - last x-coordinate // AATBUT Action always, text box // AAGBUT Action always, graphic button // SLIDER Not a button at all -typedef enum {RGROUP, ARSBUT, AABUT, AATBUT, ARSGBUT, AAGBUT, SLIDER, - TOGGLE, DCTEST, FLIP, FRGROUP, NOTHING} BTYPE; +enum BTYPE { + RGROUP, ARSBUT, AABUT, AATBUT, ARSGBUT, AAGBUT, SLIDER, + TOGGLE, DCTEST, FLIP, FRGROUP, NOTHING +}; -typedef enum {NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN, - OPENLOAD, OPENSAVE, OPENREST, - OPENSOUND, OPENCONT, +enum BFUNC { + NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN, + OPENLOAD, OPENSAVE, OPENREST, + OPENSOUND, OPENCONT, #ifndef JAPAN - OPENSUBT, + OPENSUBT, #endif - OPENQUIT, - INITGAME, MIDIVOL, - CLANG, RLANG + OPENQUIT, + INITGAME, MIDIVOL, + CLANG, RLANG #ifdef MAC_OPTIONS - , MASTERVOL, SAMPVOL + , MASTERVOL, SAMPVOL #endif - } BFUNC; +}; -typedef struct { +struct CONFBOX { BTYPE boxType; BFUNC boxFunc; char *boxText; @@ -390,7 +392,7 @@ typedef struct { int h; // Doubles as iteration size for SLIDERs int *ival; int bi; // Base index for AAGBUTs -} CONFBOX, *PCONFBOX; +}; #define NO_HEADING (-1) @@ -624,40 +626,40 @@ CONFBOX topwinBox[] = { -typedef struct { +struct CONFINIT { int h; int v; int x; int y; bool bExtraWin; - PCONFBOX Box; + CONFBOX *Box; int NumBoxes; int ixHeading; -} CONFINIT, *PCONFINIT; +}; -CONFINIT ciOption = { 6, 5, 72, 23, false, optionBox, sizeof(optionBox)/sizeof(CONFBOX), NO_HEADING }; +CONFINIT ciOption = { 6, 5, 72, 23, false, optionBox, ARRAYSIZE(optionBox), NO_HEADING }; -CONFINIT ciLoad = { 10, 6, 20, 16, true, loadBox, sizeof(loadBox)/sizeof(CONFBOX), SIX_LOAD_HEADING }; -CONFINIT ciSave = { 10, 6, 20, 16, true, saveBox, sizeof(saveBox)/sizeof(CONFBOX), SIX_SAVE_HEADING }; +CONFINIT ciLoad = { 10, 6, 20, 16, true, loadBox, ARRAYSIZE(loadBox), SIX_LOAD_HEADING }; +CONFINIT ciSave = { 10, 6, 20, 16, true, saveBox, ARRAYSIZE(saveBox), SIX_SAVE_HEADING }; #ifdef JAPAN -CONFINIT ciRestart = { 6, 2, 72, 53, false, restartBox, sizeof(restartBox)/sizeof(CONFBOX), SIX_RESTART_HEADING }; +CONFINIT ciRestart = { 6, 2, 72, 53, false, restartBox, ARRAYSIZE(restartBox), SIX_RESTART_HEADING }; #else -CONFINIT ciRestart = { 4, 2, 98, 53, false, restartBox, sizeof(restartBox)/sizeof(CONFBOX), SIX_RESTART_HEADING }; +CONFINIT ciRestart = { 4, 2, 98, 53, false, restartBox, ARRAYSIZE(restartBox), SIX_RESTART_HEADING }; #endif -CONFINIT ciSound = { 10, 5, 20, 16, false, soundBox, sizeof(soundBox)/sizeof(CONFBOX), NO_HEADING }; +CONFINIT ciSound = { 10, 5, 20, 16, false, soundBox, ARRAYSIZE(soundBox), NO_HEADING }; #ifdef MAC_OPTIONS - CONFINIT ciControl = { 10, 3, 20, 40, false, controlBox, sizeof(controlBox)/sizeof(CONFBOX), NO_HEADING }; + CONFINIT ciControl = { 10, 3, 20, 40, false, controlBox, ARRAYSIZE(controlBox), NO_HEADING }; #else - CONFINIT ciControl = { 10, 5, 20, 16, false, controlBox, sizeof(controlBox)/sizeof(CONFBOX), NO_HEADING }; + CONFINIT ciControl = { 10, 5, 20, 16, false, controlBox, ARRAYSIZE(controlBox), NO_HEADING }; #endif #ifndef JAPAN #if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) -CONFINIT ciSubtitles = { 10, 6, 20, 16, false, subtitlesBox, sizeof(subtitlesBox)/sizeof(CONFBOX), NO_HEADING }; +CONFINIT ciSubtitles = { 10, 6, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING }; #else -CONFINIT ciSubtitles = { 10, 3, 20, 16, false, subtitlesBox, sizeof(subtitlesBox)/sizeof(CONFBOX), NO_HEADING }; +CONFINIT ciSubtitles = { 10, 3, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING }; #endif #endif -CONFINIT ciQuit = { 4, 2, 98, 53, false, quitBox, sizeof(quitBox)/sizeof(CONFBOX), SIX_QUIT_HEADING }; +CONFINIT ciQuit = { 4, 2, 98, 53, false, quitBox, ARRAYSIZE(quitBox), SIX_QUIT_HEADING }; CONFINIT ciTopWin = { 6, 5, 72, 23, false, topwinBox, 0, NO_HEADING }; @@ -665,7 +667,7 @@ CONFINIT ciTopWin = { 6, 5, 72, 23, false, topwinBox, 0, NO_HEADING }; // Conf window globals static struct { - PCONFBOX Box; + CONFBOX *Box; int NumBoxes; bool bExtraWin; int ixHeading; @@ -693,7 +695,7 @@ char sedit[SG_DESC_LEN+2]; // Data for button press/toggle effects static struct { bool bButAnim; - PCONFBOX box; + CONFBOX *box; bool press; // true = button press; false = button toggle } g_buttonEffect = { false, 0, false }; @@ -838,8 +840,8 @@ static void DumpObjArray(void) { * Convert item ID number to pointer to item's compiled data * i.e. Image data and Glitter code. */ -PINV_OBJECT findInvObject(int num) { - PINV_OBJECT retval = pio; +INV_OBJECT *findInvObject(int num) { + INV_OBJECT *retval = pio; for (int i = 0; i < numObjects; i++, retval++) { if (retval->id == num) @@ -895,7 +897,7 @@ int WhichItemHeld(void) { */ void InventoryIconCursor(void) { - PINV_OBJECT invObj; + INV_OBJECT *invObj; if (HeldItem != INV_NOICON) { invObj = findInvObject(HeldItem); @@ -924,7 +926,7 @@ int WhichInventoryOpen(void) { /**************************************************************************/ struct ITP_INIT { - PINV_OBJECT pinvo; + INV_OBJECT *pinvo; USER_EVENT event; BUTEVENT bev; }; @@ -935,7 +937,7 @@ struct ITP_INIT { static void InvTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; int ThisPointedWait; // Fix the 'repeated pressing bug' CORO_END_CONTEXT(_ctx); @@ -973,7 +975,7 @@ static void InvTinselProcess(CORO_PARAM, const void *param) { /** * Run inventory item's Glitter code */ -void RunInvTinselCode(PINV_OBJECT pinvo, USER_EVENT event, BUTEVENT be, int index) { +void RunInvTinselCode(INV_OBJECT *pinvo, USER_EVENT event, BUTEVENT be, int index) { ITP_INIT to = { pinvo, event, be }; if (InventoryHidden) @@ -1238,7 +1240,7 @@ void Select(int i, bool force) { */ void HoldItem(int item) { - PINV_OBJECT invObj; + INV_OBJECT *invObj; if (HeldItem != item) { if (item == INV_NOICON && HeldItem != INV_NOICON) @@ -1279,7 +1281,7 @@ void AddToInventory(int invno, int icon, bool hold) { int i; bool bOpen; #ifdef DEBUG - PINV_OBJECT invObj; + INV_OBJECT *invObj; #endif assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_OPEN)); // Trying to add to illegal inventory @@ -1674,7 +1676,7 @@ void InvBoxes(bool InBody, int curX, int curY) { } } -static void ButtonPress(CORO_PARAM, PCONFBOX box) { +static void ButtonPress(CORO_PARAM, CONFBOX *box) { CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -1722,7 +1724,7 @@ static void ButtonPress(CORO_PARAM, PCONFBOX box) { CORO_END_CODE; } -static void ButtonToggle(CORO_PARAM, PCONFBOX box) { +static void ButtonToggle(CORO_PARAM, CONFBOX *box) { CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -1801,7 +1803,7 @@ static void ButtonToggle(CORO_PARAM, PCONFBOX box) { void InvLabels(bool InBody, int aniX, int aniY) { int index; // Icon pointed to on this call - PINV_OBJECT invObj; + INV_OBJECT *invObj; // Find out which icon is currently pointed to if (!InBody) @@ -1904,10 +1906,10 @@ void AdjustTop(void) { */ OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) { - PINV_OBJECT invObj; // Icon data + INV_OBJECT *invObj; // Icon data const MULTI_INIT *pmi; // Its INIT structure - from the reel - PIMAGE pim; // ... you get the picture - OBJECT * pPlayObj; // The object we insert + IMAGE *pim; // ... you get the picture + OBJECT *pPlayObj; // The object we insert invObj = findInvObject(num); @@ -2011,8 +2013,8 @@ void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int te static OBJECT *AddObject(const FREEL *pfreel, int num) { const MULTI_INIT *pmi; // Get the MULTI_INIT structure - PIMAGE pim; - OBJECT * pPlayObj; + IMAGE *pim; + OBJECT *pPlayObj; // Get pointer to image pim = GetImageFromReel(pfreel, &pmi); @@ -2564,7 +2566,7 @@ bool RePosition(void) { */ void AlterCursor(int num) { const FREEL *pfreel; - PIMAGE pim; + IMAGE *pim; // Get pointer to image pim = GetImageFromFilm(winPartsf, num, &pfreel); @@ -2833,7 +2835,7 @@ void PopUpInventory(int invno) { } } -void SetConfGlobals(PCONFINIT ci) { +void SetConfGlobals(CONFINIT *ci) { InvD[INV_CONF].MinHicons = InvD[INV_CONF].MaxHicons = InvD[INV_CONF].NoofHicons = ci->h; InvD[INV_CONF].MaxVicons = InvD[INV_CONF].MinVicons = InvD[INV_CONF].NoofVicons = ci->v; InvD[INV_CONF].inventoryX = ci->x; @@ -3921,7 +3923,7 @@ void InvPdProcess(CORO_PARAM, const void *param) { } void InvPickup(int index) { - PINV_OBJECT invObj; + INV_OBJECT *invObj; if (index != INV_NOICON) { if (HeldItem == INV_NOICON && InvD[ino].ItemOrder[index] && InvD[ino].ItemOrder[index] != HeldItem) { @@ -4028,7 +4030,7 @@ void InvSLClick(void) { void InvAction(void) { int index; - PINV_OBJECT invObj; + INV_OBJECT *invObj; int aniX, aniY; int i; @@ -4109,7 +4111,7 @@ void InvAction(void) { void InvLook(void) { int index; - PINV_OBJECT invObj; + INV_OBJECT *invObj; int aniX, aniY; GetCursorXY(&aniX, &aniY, false); @@ -4283,7 +4285,7 @@ void KeyToInventory(KEYEVENT ke) { */ void invObjectFilm(int object, SCNHANDLE hFilm) { - PINV_OBJECT invObj; + INV_OBJECT *invObj; invObj = findInvObject(object); invObj->hFilm = hFilm; @@ -4334,7 +4336,7 @@ void syncInvInfo(Serializer &s) { // Note: the SCHANDLE type here has been changed to a void* void RegisterIcons(void *cptr, int num) { numObjects = num; - pio = (PINV_OBJECT) cptr; + pio = (INV_OBJECT *) cptr; } /** diff --git a/engines/tinsel/inventory.h b/engines/tinsel/inventory.h index 6b0c10e3de..d83439c68f 100644 --- a/engines/tinsel/inventory.h +++ b/engines/tinsel/inventory.h @@ -52,7 +52,6 @@ struct INV_OBJECT { SCNHANDLE hScript; // inventory objects event handling script int32 attribute; // inventory object's attribute }; -typedef INV_OBJECT *PINV_OBJECT; void PopUpInventory(int invno); diff --git a/engines/tinsel/object.h b/engines/tinsel/object.h index 01c56737e4..8b61571a3e 100644 --- a/engines/tinsel/object.h +++ b/engines/tinsel/object.h @@ -65,7 +65,6 @@ struct IMAGE { SCNHANDLE hImgBits; //!< image bitmap handle SCNHANDLE hImgPal; //!< image palette handle }; -typedef IMAGE *PIMAGE; /** a multi-object animation frame is a list of multi-image handles */ diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index 9408149ebd..023417fe3c 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -39,7 +39,7 @@ namespace Tinsel { //----------------- EXTERN FUNCTIONS -------------------- -extern int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const PINT_CONTEXT pic, RESUME_STATE *pResumeState); +extern int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pic, RESUME_STATE *pResumeState); //----------------- LOCAL DEFINES -------------------- @@ -105,12 +105,12 @@ static int32 *pGlobals = 0; // global vars static int numGlobals = 0; // How many global variables to save/restore -static PINT_CONTEXT icList = 0; +static INT_CONTEXT *icList = 0; /** * Keeps the code array pointer up to date. */ -void LockCode(PINT_CONTEXT ic) { +void LockCode(INT_CONTEXT *ic) { if (ic->GSort == GS_MASTER) ic->code = (byte *)FindChunk(MASTER_SCNHANDLE, CHUNK_PCODE); else @@ -120,8 +120,8 @@ void LockCode(PINT_CONTEXT ic) { /** * Find a free interpret context and allocate it to the calling process. */ -static PINT_CONTEXT AllocateInterpretContext(GSORT gsort) { - PINT_CONTEXT pic; +static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) { + INT_CONTEXT *pic; int i; for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { @@ -145,7 +145,7 @@ static PINT_CONTEXT AllocateInterpretContext(GSORT gsort) { * Normal release of an interpret context. * Called from the end of Interpret(). */ -static void FreeInterpretContextPi(PINT_CONTEXT pic) { +static void FreeInterpretContextPi(INT_CONTEXT *pic) { pic->GSort = GS_NONE; } @@ -155,7 +155,7 @@ static void FreeInterpretContextPi(PINT_CONTEXT pic) { * call doesn't complete. */ void FreeInterpretContextPr(PROCESS *pProc) { - PINT_CONTEXT pic; + INT_CONTEXT *pic; int i; for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { @@ -170,7 +170,7 @@ void FreeInterpretContextPr(PROCESS *pProc) { * Free all interpret contexts except for the master script's */ void FreeMostInterpretContexts(void) { - PINT_CONTEXT pic; + INT_CONTEXT *pic; int i; for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { @@ -184,7 +184,7 @@ void FreeMostInterpretContexts(void) { * Free the master script's interpret context. */ void FreeMasterInterpretContext(void) { - PINT_CONTEXT pic; + INT_CONTEXT *pic; int i; for (i = 0, pic = icList; i < MAX_INTERPRET; i++, pic++) { @@ -205,9 +205,9 @@ void FreeMasterInterpretContext(void) { * @param actorId Associated actor (if any) * @param pinvo Associated inventory object */ -PINT_CONTEXT InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event, - HPOLYGON hpoly, int actorid, PINV_OBJECT pinvo) { - PINT_CONTEXT ic; +INT_CONTEXT *InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event, + HPOLYGON hpoly, int actorid, INV_OBJECT *pinvo) { + INT_CONTEXT *ic; ic = AllocateInterpretContext(gsort); @@ -235,8 +235,8 @@ PINT_CONTEXT InitInterpretContext(GSORT gsort, SCNHANDLE hCode, USER_EVENT event /** * Allocate and initialise an interpret context with restored data. */ -PINT_CONTEXT RestoreInterpretContext(PINT_CONTEXT ric) { - PINT_CONTEXT ic; +INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric) { + INT_CONTEXT *ic; ic = AllocateInterpretContext(GS_NONE); // Sort will soon be overridden @@ -263,7 +263,7 @@ void RegisterGlobals(int num) { } // Allocate RAM for interpret contexts and make sure it's allocated - icList = (PINT_CONTEXT)calloc(MAX_INTERPRET, sizeof(INT_CONTEXT)); + icList = (INT_CONTEXT *)calloc(MAX_INTERPRET, sizeof(INT_CONTEXT)); if (icList == NULL) { error("Cannot allocate memory for interpret contexts"); } @@ -326,7 +326,7 @@ void INT_CONTEXT::syncWithSerializer(Serializer &s) { /** * Return pointer to and size of global data for save/restore game. */ -void SaveInterpretContexts(PINT_CONTEXT sICInfo) { +void SaveInterpretContexts(INT_CONTEXT *sICInfo) { memcpy(sICInfo, icList, MAX_INTERPRET * sizeof(INT_CONTEXT)); } @@ -355,7 +355,7 @@ static int32 Fetch(byte opcode, byte *code, int &ip) { /** * Interprets the PCODE instructions in the code array. */ -void Interpret(CORO_PARAM, PINT_CONTEXT ic) { +void Interpret(CORO_PARAM, INT_CONTEXT *ic) { do { int tmp, tmp2; int ip = ic->ip; diff --git a/engines/tinsel/pcode.h b/engines/tinsel/pcode.h index 1fc87e6e50..1c7e0a942c 100644 --- a/engines/tinsel/pcode.h +++ b/engines/tinsel/pcode.h @@ -28,8 +28,6 @@ #define TINSEL_PCODE_H #include "tinsel/events.h" // for USER_EVENT -//#include "tinsel/inventory.h" // for PINV_OBJECT -#include "tinsel/polygons.h" // for PPOLYGON #include "tinsel/sched.h" // for PROCESS namespace Tinsel { @@ -77,7 +75,6 @@ struct INT_CONTEXT { void syncWithSerializer(Serializer &s); }; -typedef INT_CONTEXT *PINT_CONTEXT; /*----------------------------------------------------------------------*\ @@ -86,7 +83,7 @@ typedef INT_CONTEXT *PINT_CONTEXT; void Interpret(CORO_PARAM, INT_CONTEXT *ic); // Interprets the PCODE instructions in the code array -PINT_CONTEXT InitInterpretContext( +INT_CONTEXT *InitInterpretContext( GSORT gsort, SCNHANDLE hCode, // code to execute USER_EVENT event, // causal event diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp index 7c4f6be7e6..90fa51d6fc 100644 --- a/engines/tinsel/play.cpp +++ b/engines/tinsel/play.cpp @@ -45,14 +45,14 @@ namespace Tinsel { */ static void PokeInPalette(SCNHANDLE hMulFrame) { const FRAME *pFrame; // Pointer to frame - PIMAGE pim; // Pointer to image + IMAGE *pim; // Pointer to image // Could be an empty column if (hMulFrame) { pFrame = (const FRAME *)LockMem(hMulFrame); // get pointer to image - pim = (PIMAGE)LockMem(READ_LE_UINT32(pFrame)); // handle to image + pim = (IMAGE *)LockMem(READ_LE_UINT32(pFrame)); // handle to image pim->hImgPal = TO_LE_32(BackPal()); } diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp index 2f8f055472..a9b24bcac9 100644 --- a/engines/tinsel/rince.cpp +++ b/engines/tinsel/rince.cpp @@ -37,6 +37,7 @@ #include "tinsel/object.h" #include "tinsel/pcode.h" #include "tinsel/pid.h" +#include "tinsel/polygons.h" #include "tinsel/rince.h" #include "tinsel/sched.h" #include "tinsel/timers.h" @@ -550,7 +551,7 @@ static void MActorProcessHelper(int X, int Y, int id, PMACTOR pActor) { const FILM *pfilm; const MULTI_INIT *pmi; const FRAME *pFrame; - PIMAGE pim; + IMAGE *pim; assert(BackPal()); // Can't start actor without a background palette @@ -566,7 +567,7 @@ static void MActorProcessHelper(int X, int Y, int id, PMACTOR pActor) { pFrame = (const FRAME *)LockMem(FROM_LE_32(pmi->hMulFrame)); // get pointer to image - pim = (PIMAGE)LockMem(READ_LE_UINT32(pFrame)); // handle to image + pim = (IMAGE *)LockMem(READ_LE_UINT32(pFrame)); // handle to image pim->hImgPal = TO_LE_32(BackPal()); //--- pActor->actorObj = MultiInitObject(pmi); diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp index ab48e26c4c..70700c16a3 100644 --- a/engines/tinsel/scene.cpp +++ b/engines/tinsel/scene.cpp @@ -43,6 +43,7 @@ #include "tinsel/object.h" #include "tinsel/pcode.h" #include "tinsel/pid.h" // process IDs +#include "tinsel/polygons.h" #include "tinsel/token.h" @@ -105,7 +106,7 @@ static SCNHANDLE SceneHandle = 0; // Current scene handle - stored in case of Sa static void SceneTinselProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; - PINT_CONTEXT pic; + INT_CONTEXT *pic; CORO_END_CONTEXT(_ctx); // get the stuff copied to process when it was created diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index 84904e5138..e8364e20dd 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -1065,13 +1065,13 @@ void print(CORO_PARAM, int x, int y, SCNHANDLE text, int time, int hold, bool es } -static void printobjPointed(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, OBJECT *&pText, const int textx, const int texty, const int item); +static void printobjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *pinvo, OBJECT *&pText, const int textx, const int texty, const int item); static void printobjNonPointed(CORO_PARAM, const SCNHANDLE text, const OBJECT *pText); /** * Print the given inventory object's name or whatever. */ -void printobj(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, const int event) { +void printobj(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *pinvo, const int event) { CORO_BEGIN_CONTEXT; OBJECT *pText; // text object pointer int textx, texty; @@ -1142,7 +1142,7 @@ void printobj(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, const i CORO_END_CODE; } -static void printobjPointed(CORO_PARAM, const SCNHANDLE text, const PINV_OBJECT pinvo, OBJECT *&pText, const int textx, const int texty, const int item) { +static void printobjPointed(CORO_PARAM, const SCNHANDLE text, const INV_OBJECT *pinvo, OBJECT *&pText, const int textx, const int texty, const int item) { CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -2404,7 +2404,7 @@ int whichinventory(void) { * @param operand Library function * @param pp Top of parameter stack */ -int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const PINT_CONTEXT pic, RESUME_STATE *pResumeState) { +int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pic, RESUME_STATE *pResumeState) { debug(7, "CallLibraryRoutine op %d (escOn %d, myescEvent %d)", operand, pic->escOn, pic->myescEvent); switch (operand) { case ACTORATTR: -- cgit v1.2.3 From ba351015cbbdbfd75235996cfa4f177442448bba Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 25 Jul 2008 09:36:18 +0000 Subject: Fix to prevent attempt to delete a non-initialised object during game exit svn-id: r33283 --- engines/agos/agos.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index 365f9fcde7..a9fd204d73 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -578,6 +578,8 @@ int AGOSEngine::init() { _midiEnabled = true; + } else { + _driver = NULL; } // allocate buffers @@ -881,7 +883,8 @@ AGOSEngine::~AGOSEngine() { delete _gameFile; _midi.close(); - delete _driver; + if (_driver) + delete _driver; AudioCD.destroy(); -- cgit v1.2.3 From 71d40e23f5fff8557283726fb0563a79e6ba7a9c Mon Sep 17 00:00:00 2001 From: Joost Peters Date: Fri, 25 Jul 2008 10:20:05 +0000 Subject: change PPINIT struct to use ScummVM datatypes, so sizeof(PPINIT) is 28 on ppc/OSX as well. svn-id: r33285 --- engines/tinsel/play.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp index 90fa51d6fc..e32fc88d3d 100644 --- a/engines/tinsel/play.cpp +++ b/engines/tinsel/play.cpp @@ -93,18 +93,18 @@ int32 NoNameFunc(int actorID, bool bNewMover) { struct PPINIT { SCNHANDLE hFilm; // The 'film' - short x; // } Co-ordinates from the play() - short y; // } - set to (-1, -1) if none. - short z; // normally 0, set if from restore - short speed; // Film speed - short actorid; // Set if called from an actor code block - bool splay; // Set if called from splay() - bool bTop; // Set if called from topplay() - short sf; // SlowFactor - only used for moving actors - short column; // Column number, first column = 0 - - bool escOn; - int myescEvent; + int16 x; // } Co-ordinates from the play() + int16 y; // } - set to (-1, -1) if none. + int16 z; // normally 0, set if from restore + int16 speed; // Film speed + int16 actorid; // Set if called from an actor code block + uint8 splay; // Set if called from splay() + uint8 bTop; // Set if called from topplay() + int16 sf; // SlowFactor - only used for moving actors + int16 column; // Column number, first column = 0 + + uint8 escOn; + int32 myescEvent; }; @@ -417,7 +417,7 @@ void playFilm(SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, newestFilm(film, &pfilm->reels[i]); ppi.column = i; - g_scheduler->createProcess(PID_REEL, playProcess, &ppi, sizeof(ppi)); + g_scheduler->createProcess(PID_REEL, playProcess, &ppi, sizeof(PPINIT)); } } -- cgit v1.2.3 From 84505d6374e0eb7134f1201050b84c45c29580fe Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Fri, 25 Jul 2008 12:59:46 +0000 Subject: Fixed the inventory bug that's been reported in the forums svn-id: r33288 --- engines/tinsel/cursor.cpp | 4 ++-- engines/tinsel/object.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp index 4eb6b98da3..b95662cbfe 100644 --- a/engines/tinsel/cursor.cpp +++ b/engines/tinsel/cursor.cpp @@ -368,8 +368,8 @@ void SetAuxCursor(SCNHANDLE hFilm) { assert(BackPal()); // no background palette pim->hImgPal = TO_LE_32(BackPal()); // Poke in the background palette - ACoX = (short)(FROM_LE_16(pim->imgWidth)/2 - FROM_LE_16(pim->anioffX)); - ACoY = (short)(FROM_LE_16(pim->imgHeight)/2 - FROM_LE_16(pim->anioffY)); + ACoX = (short)(FROM_LE_16(pim->imgWidth)/2 - ((int16) FROM_LE_16(pim->anioffX))); + ACoY = (short)(FROM_LE_16(pim->imgHeight)/2 - ((int16) FROM_LE_16(pim->anioffY))); // Initialise and insert the auxillary cursor object AcurObj = MultiInitObject(pmi); diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp index a708cd36d7..709fa4fad9 100644 --- a/engines/tinsel/object.cpp +++ b/engines/tinsel/object.cpp @@ -297,10 +297,10 @@ void GetAniOffset(SCNHANDLE hImg, int flags, int *pAniX, int *pAniY) { const IMAGE *pImg = (const IMAGE *)LockMem(hImg); // set ani X - *pAniX = FROM_LE_16(pImg->anioffX); + *pAniX = (int16) FROM_LE_16(pImg->anioffX); // set ani Y - *pAniY = FROM_LE_16(pImg->anioffY); + *pAniY = (int16) FROM_LE_16(pImg->anioffY); if (flags & DMA_FLIPH) { // we are flipped horizontally -- cgit v1.2.3 From 3e08d36363c1f761807ad012de4dd3f6aa3589b0 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 25 Jul 2008 16:01:25 +0000 Subject: * Changed walk code to use Common::Point instead of the clumsy WalkNode. * Changed walk code to use object copy instead of managing pointers. svn-id: r33289 --- engines/parallaction/parallaction.h | 5 ++-- engines/parallaction/parser.h | 2 +- engines/parallaction/parser_ns.cpp | 12 ++------ engines/parallaction/walk.cpp | 58 +++++++++++++------------------------ engines/parallaction/walk.h | 23 ++++----------- 5 files changed, 31 insertions(+), 69 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 523ec06a61..5bbd6ea8c7 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -177,7 +177,7 @@ struct Location { char _soundFile[50]; // NS specific - WalkNodeList _walkNodes; + PointList _walkNodes; char _slideText[2][MAX_TOKEN_LEN]; // BRA specific @@ -199,7 +199,7 @@ struct Character { GfxObj *_talk; GfxObj *_objs; PathBuilder _builder; - WalkNodeList *_walkPath; + PointList *_walkPath; Character(Parallaction *vm); void getFoot(Common::Point &foot); @@ -259,7 +259,6 @@ public: void resumeJobs(); void finalizeWalk(Character &character); - int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to); void clipMove(Common::Point& pos, const Common::Point& to); ZonePtr findZone(const char *name); diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index 1541fb89b2..a31be2ccb0 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -193,7 +193,7 @@ protected: void parseZone(ZoneList &list, char *name); void parseZoneTypeBlock(ZonePtr z); - void parseWalkNodes(WalkNodeList &list); + void parseWalkNodes(PointList &list); void parseAnimation(AnimationList &list, char *name); void parseCommands(CommandList&); void parseCommandFlags(); diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 2f4d2df776..3595fa5696 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1124,20 +1124,14 @@ void LocationParser_ns::parse(Script *script) { resolveCommandForwards(); } -void LocationParser_ns::parseWalkNodes(WalkNodeList &list) { +void LocationParser_ns::parseWalkNodes(PointList &list) { debugC(5, kDebugParser, "parseWalkNodes()"); _script->readLineToken(true); while (scumm_stricmp(_tokens[0], "ENDNODES")) { if (!scumm_stricmp(_tokens[0], "COORD")) { - - WalkNodePtr v4(new WalkNode( - atoi(_tokens[1]), - atoi(_tokens[2]) - )); - - list.push_front(v4); + list.push_front(Common::Point(atoi(_tokens[1]), atoi(_tokens[2]))); } _script->readLineToken(true); @@ -1397,7 +1391,7 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) { list.push_front(z); _parser->pushTables(&_locationZoneParsers, _locationZoneStmt); - + return; } diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index a717b615e6..1914117915 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -97,16 +97,15 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& while (true) { - WalkNodeList::iterator nearest = _vm->_location._walkNodes.end(); - WalkNodeList::iterator locNode = _vm->_location._walkNodes.begin(); + PointList::iterator nearest = _vm->_location._walkNodes.end(); + PointList::iterator locNode = _vm->_location._walkNodes.begin(); // scans location path nodes searching for the nearest Node // which can't be farther than the target position // otherwise no _closest_node is selected while (locNode != _vm->_location._walkNodes.end()) { - Common::Point v8; - (*locNode)->getPoint(v8); + Common::Point v8 = *locNode; v2C = v8.sqrDist(stop); v28 = v8.sqrDist(v20); @@ -120,10 +119,10 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& if (nearest == _vm->_location._walkNodes.end()) break; - (*nearest)->getPoint(v20); + v20 = *nearest; v34 = v30 = v20.sqrDist(stop); - _subPath.push_back(WalkNodePtr(new WalkNode(**nearest))); + _subPath.push_back(*nearest); } return v34; @@ -141,34 +140,34 @@ void printNodes(WalkNodeList *list, const char* text) { // // x, y: mouse click (foot) coordinates // -WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) { +PointList *PathBuilder::buildPath(uint16 x, uint16 y) { debugC(1, kDebugWalk, "PathBuilder::buildPath to (%i, %i)", x, y); Common::Point to(x, y); correctPathPoint(to); debugC(1, kDebugWalk, "found closest path point at (%i, %i)", to.x, to.y); - WalkNodePtr v48(new WalkNode(to.x, to.y)); - WalkNodePtr v44 = v48; + Common::Point v48(to); + Common::Point v44(to); uint16 v38 = walkFunc1(to.x, to.y, v44); if (v38 == 1) { // destination directly reachable debugC(1, kDebugWalk, "direct move to (%i, %i)", to.x, to.y); - _list = new WalkNodeList; + _list = new PointList; _list->push_back(v48); return _list; } // path is obstructed: look for alternative - _list = new WalkNodeList; + _list = new PointList; _list->push_back(v48); #if 0 printNodes(_list, "start"); #endif - Common::Point stop(v48->_x, v48->_y); + Common::Point stop(v48.x, v48.y); Common::Point pos; _vm->_char.getFoot(pos); @@ -184,7 +183,7 @@ WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) { printNodes(_list, "first segment"); #endif - (*_list->begin())->getPoint(stop); + stop = *_list->begin(); buildSubPath(pos, stop); _list->insert(_list->begin(), _subPath.begin(), _subPath.end()); #if 0 @@ -202,7 +201,7 @@ WalkNodeList *PathBuilder::buildPath(uint16 x, uint16 y) { // 1 : Point reachable in a straight line // other values: square distance to target (point not reachable in a straight line) // -uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) { +uint16 PathBuilder::walkFunc1(int16 x, int16 y, Common::Point& node) { Common::Point arg(x, y); @@ -239,9 +238,7 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) { v8 = foot; } - Node->_x = v4.x; - Node->_y = v4.y; - + node = v4; return (x - v4.x) * (x - v4.x) + (y - v4.y) * (y - v4.y); } @@ -326,10 +323,10 @@ void Parallaction_ns::walk(Character &character) { character.getFoot(curPos); // update target, if previous was reached - WalkNodeList::iterator it = character._walkPath->begin(); + PointList::iterator it = character._walkPath->begin(); if (it != character._walkPath->end()) { - if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) { - debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y); + if ((*it).x == curPos.x && (*it).y == curPos.y) { + debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it).x, (*it).y); it = character._walkPath->erase(it); } } @@ -341,11 +338,9 @@ void Parallaction_ns::walk(Character &character) { finalizeWalk(character); targetPos = curPos; } else { - if (*it) { - // targetPos is saved to help setting character direction - targetPos.x = (*it)->_x; - targetPos.y = (*it)->_y; - } + // targetPos is saved to help setting character direction + targetPos.x = (*it).x; + targetPos.y = (*it).y; Common::Point newPos(curPos); clipMove(newPos, targetPos); @@ -368,19 +363,6 @@ void Parallaction_ns::walk(Character &character) { } -WalkNode::WalkNode() : _x(0), _y(0) { -} - -WalkNode::WalkNode(int16 x, int16 y) : _x(x), _y(y) { -} - -WalkNode::WalkNode(const WalkNode& w) : _x(w._x), _y(w._y) { -} - -void WalkNode::getPoint(Common::Point &p) const { - p.x = _x; - p.y = _y; -} PathBuilder::PathBuilder(AnimationPtr anim) : _anim(anim), _list(0) { } diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index 788a6e1375..c2114c5988 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -33,36 +33,23 @@ namespace Parallaction { struct Animation; -struct WalkNode { - int16 _x; - int16 _y; - -public: - WalkNode(); - WalkNode(int16 x, int16 y); - WalkNode(const WalkNode& w); - - void getPoint(Common::Point &p) const; -}; - -typedef Common::SharedPtr WalkNodePtr; -typedef Common::List WalkNodeList; +typedef Common::List PointList; class PathBuilder { AnimationPtr _anim; - WalkNodeList *_list; - WalkNodeList _subPath; + PointList *_list; + PointList _subPath; void correctPathPoint(Common::Point &to); uint32 buildSubPath(const Common::Point& pos, const Common::Point& stop); - uint16 walkFunc1(int16 x, int16 y, WalkNodePtr Node); + uint16 walkFunc1(int16 x, int16 y, Common::Point& Node); public: PathBuilder(AnimationPtr anim); - WalkNodeList* buildPath(uint16 x, uint16 y); + PointList* buildPath(uint16 x, uint16 y); }; -- cgit v1.2.3 From 1174296a664a7e796cf178297b4e65d6a56bb158 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 25 Jul 2008 16:08:10 +0000 Subject: Changed the remaining references to Nodes into Points. svn-id: r33290 --- engines/parallaction/parallaction.cpp | 2 +- engines/parallaction/parallaction.h | 2 +- engines/parallaction/parser.h | 2 +- engines/parallaction/parser_ns.cpp | 8 ++++---- engines/parallaction/walk.cpp | 8 ++++---- engines/parallaction/walk.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 163f3009e1..b5f2de851b 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -259,7 +259,7 @@ void Parallaction::freeLocation() { _localFlagNames->clear(); - _location._walkNodes.clear(); + _location._walkPoints.clear(); _gfx->clearGfxObjects(kGfxObjNormal); freeBackground(); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 5bbd6ea8c7..24e9b18ba9 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -177,7 +177,7 @@ struct Location { char _soundFile[50]; // NS specific - PointList _walkNodes; + PointList _walkPoints; char _slideText[2][MAX_TOKEN_LEN]; // BRA specific diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index a31be2ccb0..67515627d0 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -193,7 +193,7 @@ protected: void parseZone(ZoneList &list, char *name); void parseZoneTypeBlock(ZonePtr z); - void parseWalkNodes(PointList &list); + void parsePointList(PointList &list); void parseAnimation(AnimationList &list, char *name); void parseCommands(CommandList&); void parseCommandFlags(); diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 3595fa5696..b06eccc81c 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -1011,7 +1011,7 @@ DECLARE_LOCATION_PARSER(disk) { DECLARE_LOCATION_PARSER(nodes) { debugC(7, kDebugParser, "LOCATION_PARSER(nodes) "); - parseWalkNodes(_vm->_location._walkNodes); + parsePointList(_vm->_location._walkPoints); } @@ -1124,8 +1124,8 @@ void LocationParser_ns::parse(Script *script) { resolveCommandForwards(); } -void LocationParser_ns::parseWalkNodes(PointList &list) { - debugC(5, kDebugParser, "parseWalkNodes()"); +void LocationParser_ns::parsePointList(PointList &list) { + debugC(5, kDebugParser, "parsePointList()"); _script->readLineToken(true); while (scumm_stricmp(_tokens[0], "ENDNODES")) { @@ -1137,7 +1137,7 @@ void LocationParser_ns::parseWalkNodes(PointList &list) { _script->readLineToken(true); } - debugC(5, kDebugParser, "parseWalkNodes() done"); + debugC(5, kDebugParser, "parsePointList() done"); return; } diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 1914117915..98557bf22c 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -97,13 +97,13 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& while (true) { - PointList::iterator nearest = _vm->_location._walkNodes.end(); - PointList::iterator locNode = _vm->_location._walkNodes.begin(); + PointList::iterator nearest = _vm->_location._walkPoints.end(); + PointList::iterator locNode = _vm->_location._walkPoints.begin(); // scans location path nodes searching for the nearest Node // which can't be farther than the target position // otherwise no _closest_node is selected - while (locNode != _vm->_location._walkNodes.end()) { + while (locNode != _vm->_location._walkPoints.end()) { Common::Point v8 = *locNode; v2C = v8.sqrDist(stop); @@ -117,7 +117,7 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& locNode++; } - if (nearest == _vm->_location._walkNodes.end()) break; + if (nearest == _vm->_location._walkPoints.end()) break; v20 = *nearest; v34 = v30 = v20.sqrDist(stop); diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index c2114c5988..b68a7f585f 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -45,7 +45,7 @@ class PathBuilder { void correctPathPoint(Common::Point &to); uint32 buildSubPath(const Common::Point& pos, const Common::Point& stop); - uint16 walkFunc1(int16 x, int16 y, Common::Point& Node); + uint16 walkFunc1(int16 x, int16 y, Common::Point& node); public: PathBuilder(AnimationPtr anim); -- cgit v1.2.3 From aee128467893daa3e3482ad3c9a90b66cbc1bcdf Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sat, 26 Jul 2008 02:09:50 +0000 Subject: BRA now parses path data from the scripts. svn-id: r33295 --- engines/parallaction/graphics.cpp | 22 ++++++++++++++ engines/parallaction/graphics.h | 1 + engines/parallaction/objects.h | 18 ++++++++++- engines/parallaction/parser.h | 6 +++- engines/parallaction/parser_br.cpp | 61 ++++++++++++++++++++++++++++++++++++++ engines/parallaction/walk.h | 7 ++--- 6 files changed, 108 insertions(+), 7 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 3afc05bdc1..7195d1c126 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -375,6 +375,13 @@ void Gfx::beginFrame() { } } + _varDrawPathZones = getVar("draw_path_zones"); + if (_varDrawPathZones == 1 && _vm->getGameType() != GType_BRA) { + setVar("draw_path_zones", 0); + _varDrawPathZones = 0; + warning("Path zones are supported only in Big Red Adventure"); + } + if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo.width)) { _varScrollX = 0; } else { @@ -420,6 +427,19 @@ void Gfx::updateScreen() { g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h); } + if (_varDrawPathZones == 1) { + Graphics::Surface *surf = g_system->lockScreen(); + ZoneList::iterator b = _vm->_location._zones.begin(); + ZoneList::iterator e = _vm->_location._zones.end(); + for (; b != e; b++) { + ZonePtr z = *b; + if (z->_type & kZonePath) { + surf->frameRect(Common::Rect(z->_left, z->_top, z->_right, z->_bottom), 2); + } + } + g_system->unlockScreen(); + } + _varRenderMode = _varAnimRenderMode; // TODO: transform objects coordinates to be drawn with scrolling @@ -775,6 +795,8 @@ Gfx::Gfx(Parallaction* vm) : registerVar("anim_render_mode", 1); registerVar("misc_render_mode", 1); + registerVar("draw_path_zones", 0); + return; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index b3745098c2..bba2d01d8a 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -564,6 +564,7 @@ protected: int32 _varAnimRenderMode; // 1 = normal, 2 = flat int32 _varMiscRenderMode; // 1 = normal, 2 = flat int32 _varRenderMode; + int32 _varDrawPathZones; // 0 = don't draw, 1 = draw Graphics::Surface _bitmapMask; int32 getRenderMode(const char *type); diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index 19835da9d0..fd855f9dca 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -54,6 +54,7 @@ typedef Common::SharedPtr InstructionPtr; typedef Common::List InstructionList; extern InstructionPtr nullInstructionPtr; +typedef Common::List PointList; enum ZoneTypes { kZoneExamine = 1, // zone displays comment if activated @@ -67,7 +68,10 @@ enum ZoneTypes { kZoneNone = 0x100, // used to prevent parsing on peculiar Animations kZoneTrap = 0x200, // zone activated when character enters kZoneYou = 0x400, // marks the character - kZoneCommand = 0x800 + kZoneCommand = 0x800, + + // BRA specific + kZonePath = 0x1000 // defines nodes for assisting walk calculation routines }; @@ -256,6 +260,15 @@ struct MergeData { // size = 12 _obj1 = _obj2 = _obj3 = 0; } }; +#define MAX_WALKPOINT_LISTS 20 +struct PathData { + int _numLists; + PointList _lists[MAX_WALKPOINT_LISTS]; + + PathData() { + _numLists = 0; + } +}; struct TypeData { GetData *get; @@ -264,6 +277,8 @@ struct TypeData { DoorData *door; HearData *hear; MergeData *merge; + // BRA specific field + PathData *path; TypeData() { get = NULL; @@ -272,6 +287,7 @@ struct TypeData { door = NULL; hear = NULL; merge = NULL; + path = NULL; } }; diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index 67515627d0..290a0815c8 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -192,7 +192,7 @@ protected: Question *parseQuestion(); void parseZone(ZoneList &list, char *name); - void parseZoneTypeBlock(ZonePtr z); + virtual void parseZoneTypeBlock(ZonePtr z); void parsePointList(PointList &list); void parseAnimation(AnimationList &list, char *name); void parseCommands(CommandList&); @@ -284,6 +284,9 @@ protected: DECLARE_UNQUALIFIED_ANIM_PARSER(moveto); DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); + virtual void parseZoneTypeBlock(ZonePtr z); + void parsePathData(ZonePtr z); + public: LocationParser_br(Parallaction_br *vm) : LocationParser_ns((Parallaction_ns*)vm), _vm(vm) { } @@ -307,6 +310,7 @@ protected: Parser *_parser; Parallaction_ns *_vm; + Script *_script; ProgramPtr _program; diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index defc917a72..7ed826d9f8 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -750,6 +750,67 @@ DECLARE_ZONE_PARSER(type) { _parser->popTables(); } +void LocationParser_br::parsePathData(ZonePtr z) { + + PathData *data = new PathData; + + do { + + if (!scumm_stricmp("zone", _tokens[0])) { + int id = atoi(_tokens[1]); + parsePointList(data->_lists[id]); + data->_numLists++; + } + + _script->readLineToken(true); + } while (scumm_stricmp("endzone", _tokens[0])); + + z->u.path = data; +} + +void LocationParser_br::parseZoneTypeBlock(ZonePtr z) { + debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type); + + switch (z->_type & 0xFFFF) { + case kZoneExamine: // examine Zone alloc + parseExamineData(z); + break; + + case kZoneDoor: // door Zone alloc + parseDoorData(z); + break; + + case kZoneGet: // get Zone alloc + parseGetData(z); + break; + + case kZoneMerge: // merge Zone alloc + parseMergeData(z); + break; + + case kZoneHear: // hear Zone alloc + parseHearData(z); + break; + + case kZoneSpeak: // speak Zone alloc + parseSpeakData(z); + break; + + // BRA specific zone + case kZonePath: + parsePathData(z); + break; + + default: + // eats up 'ENDZONE' line for unprocessed zone types + _script->readLineToken(true); + break; + } + + debugC(7, kDebugParser, "parseZoneTypeBlock() done"); + + return; +} DECLARE_ANIM_PARSER(file) { debugC(7, kDebugParser, "ANIM_PARSER(file) "); diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index b68a7f585f..dddf2857be 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -29,12 +29,9 @@ #include "common/ptr.h" #include "common/list.h" -namespace Parallaction { - -struct Animation; - -typedef Common::List PointList; +#include "parallaction/objects.h" +namespace Parallaction { class PathBuilder { -- cgit v1.2.3 From 7950a9183b34fe60f979576c6f4d5b6f9d56a3dc Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sat, 26 Jul 2008 04:01:11 +0000 Subject: * Added walk calculations to BRA (doesn't walk yet, though). * Adapted Character and Animation to handle both versions of the engine. svn-id: r33296 --- engines/parallaction/objects.cpp | 4 +- engines/parallaction/parallaction.cpp | 52 +++++++++++++-- engines/parallaction/parallaction.h | 5 +- engines/parallaction/walk.cpp | 117 +++++++++++++++++++++++++++++----- engines/parallaction/walk.h | 27 +++++++- 5 files changed, 176 insertions(+), 29 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index 66025cf0f7..e04a7d5342 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -60,14 +60,14 @@ Animation::~Animation() { uint16 Animation::width() const { if (!gfxobj) return 0; Common::Rect r; - gfxobj->getRect(0, r); + gfxobj->getRect(_frame, r); return r.width(); } uint16 Animation::height() const { if (!gfxobj) return 0; Common::Rect r; - gfxobj->getRect(0, r); + gfxobj->getRect(_frame, r); return r.height(); } diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index b5f2de851b..78e7af6343 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -497,7 +497,7 @@ const char Character::_suffixTras[] = "tras"; const char Character::_empty[] = "\0"; -Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder(_ani) { +Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) { _talk = NULL; _head = NULL; _objs = NULL; @@ -516,25 +516,63 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder( _ani->_flags = kFlagsActive | kFlagsNoName; _ani->_type = kZoneYou; strncpy(_ani->_name, "yourself", ZONENAME_LENGTH); + + // TODO: move creation into Parallaction. Needs to make Character a pointer first. + if (_vm->getGameType() == GType_Nippon) + _builder = new PathBuilder_NS(this); + else + _builder = new PathBuilder_BR(this); +} + +Character::~Character() { + delete _builder; + _builder = 0; + + free(); } void Character::getFoot(Common::Point &foot) { - foot.x = _ani->_left + _ani->width() / 2; - foot.y = _ani->_top + _ani->height(); + Common::Rect rect; + _ani->gfxobj->getRect(_ani->_frame, rect); + + foot.x = _ani->_left + (rect.left + rect.width() / 2); + foot.y = _ani->_top + (rect.top + rect.height()); } void Character::setFoot(const Common::Point &foot) { - _ani->_left = foot.x - _ani->width() / 2; - _ani->_top = foot.y - _ani->height(); + Common::Rect rect; + _ani->gfxobj->getRect(_ani->_frame, rect); + + _ani->_left = foot.x - (rect.left + rect.width() / 2); + _ani->_top = foot.y - (rect.top + rect.height()); } +#if 0 +void dumpPath(PointList *list, const char* text) { + for (PointList::iterator it = list->begin(); it != list->end(); it++) + printf("node (%i, %i)\n", it->x, it->y); + + return; +} +#endif + void Character::scheduleWalk(int16 x, int16 y) { if ((_ani->_flags & kFlagsRemove) || (_ani->_flags & kFlagsActive) == 0) { return; } - _walkPath = _builder.buildPath(x, y); - _engineFlags |= kEngineWalking; + _walkPath = _builder->buildPath(x, y); +#if 0 + dumpPath(_walkPath, _name); +#endif + + if (_vm->getGameType() == GType_Nippon) { + _engineFlags |= kEngineWalking; + } else { + // BRA can't walk yet! + delete _walkPath; + _walkPath = 0; + } } void Character::free() { diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 24e9b18ba9..03bff44981 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -198,10 +198,12 @@ struct Character { GfxObj *_head; GfxObj *_talk; GfxObj *_objs; - PathBuilder _builder; + PathBuilder *_builder; PointList *_walkPath; Character(Parallaction *vm); + ~Character(); + void getFoot(Common::Point &foot); void setFoot(const Common::Point &foot); void scheduleWalk(int16 x, int16 y); @@ -379,6 +381,7 @@ public: void beep(); ZonePtr _zoneTrap; + PathBuilder* getPathBuilder(Character *ch); public: // const char **_zoneFlagNamesRes; diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 98557bf22c..fa6c7d5ede 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -28,15 +28,29 @@ namespace Parallaction { + 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; + uint bit = 0; + switch (_vm->getGameType()) { + case GType_Nippon: + bit = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7)); + break; + + case GType_BRA: + // Amiga and PC versions pack the path bits the same way in BRA + bit = 7 - (x & 7); + break; + + default: + error("path mask not yet implemented for this game type"); + } + return ((1 << bit) & m) >> bit; } // adjusts position towards nearest walkable point // -void PathBuilder::correctPathPoint(Common::Point &to) { +void PathBuilder_NS::correctPathPoint(Common::Point &to) { if (_vm->_pathBuffer->getValue(to.x, to.y)) return; @@ -84,7 +98,7 @@ void PathBuilder::correctPathPoint(Common::Point &to) { } -uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& stop) { +uint32 PathBuilder_NS::buildSubPath(const Common::Point& pos, const Common::Point& stop) { uint32 v28 = 0; uint32 v2C = 0; @@ -128,19 +142,11 @@ uint32 PathBuilder::buildSubPath(const Common::Point& pos, const Common::Point& return v34; } -#if 0 -void printNodes(WalkNodeList *list, const char* text) { - printf("%s\n-------------------\n", text); - for (WalkNodeList::iterator it = list->begin(); it != list->end(); it++) - printf("node [%p] (%i, %i)\n", *it, (*it)->_x, (*it)->_y); - return; -} -#endif // // x, y: mouse click (foot) coordinates // -PointList *PathBuilder::buildPath(uint16 x, uint16 y) { +PointList *PathBuilder_NS::buildPath(uint16 x, uint16 y) { debugC(1, kDebugWalk, "PathBuilder::buildPath to (%i, %i)", x, y); Common::Point to(x, y); @@ -169,7 +175,7 @@ PointList *PathBuilder::buildPath(uint16 x, uint16 y) { Common::Point stop(v48.x, v48.y); Common::Point pos; - _vm->_char.getFoot(pos); + _ch->getFoot(pos); uint32 v34 = buildSubPath(pos, stop); if (v38 != 0 && v34 > v38) { @@ -201,14 +207,14 @@ PointList *PathBuilder::buildPath(uint16 x, uint16 y) { // 1 : Point reachable in a straight line // other values: square distance to target (point not reachable in a straight line) // -uint16 PathBuilder::walkFunc1(int16 x, int16 y, Common::Point& node) { +uint16 PathBuilder_NS::walkFunc1(int16 x, int16 y, Common::Point& node) { Common::Point arg(x, y); Common::Point v4(0, 0); Common::Point foot; - _vm->_char.getFoot(foot); + _ch->getFoot(foot); Common::Point v8(foot); @@ -364,8 +370,85 @@ void Parallaction_ns::walk(Character &character) { -PathBuilder::PathBuilder(AnimationPtr anim) : _anim(anim), _list(0) { +PathBuilder_NS::PathBuilder_NS(Character *ch) : PathBuilder(ch), _list(0) { +} + +#define isPositionOnPath(x,y) _vm->_pathBuffer->getValue((x), (y)) + + +bool PathBuilder_BR::directPathExists(const Common::Point &from, const Common::Point &to) { + + Common::Point copy(from); + Common::Point p(copy); + + while (p != to) { + + if (p.x < to.x && isPositionOnPath(p.x + 1, p.y)) p.x++; + if (p.x > to.x && isPositionOnPath(p.x - 1, p.y)) p.x--; + if (p.y < to.y && isPositionOnPath(p.x, p.y + 1)) p.y++; + if (p.y > to.y && isPositionOnPath(p.x, p.y - 1)) p.y--; + + if (p == copy && p != to) { + return false; + } + + copy = p; + } + + return true; } +PointList* PathBuilder_BR::buildPath(uint16 x, uint16 y) { + Common::Point foot; + _ch->getFoot(foot); + + debugC(1, kDebugWalk, "buildPath: from (%i, %i) to (%i, %i)", foot.x, foot.y, x, y); + + PointList *list = new PointList; + + // look for easy path first + Common::Point dest(x, y); + if (directPathExists(foot, dest)) { + list->push_back(dest); + debugC(3, kDebugWalk, "buildPath: direct path found"); + return list; + } + + // look for short circuit cases + ZonePtr z0 = _vm->hitZone(kZonePath, x, y); + if (z0 == nullZonePtr) { + list->push_back(dest); + debugC(3, kDebugWalk, "buildPath: corner case 0"); + return list; + } + ZonePtr z1 = _vm->hitZone(kZonePath, foot.x, foot.y); + if (z1 == nullZonePtr || z1 == z0) { + list->push_back(dest); + debugC(3, kDebugWalk, "buildPath: corner case 1"); + return list; + } + + // build complex path + int id = atoi(z0->_name); + + if (z1->u.path->_lists[id].empty()) { + list->clear(); + debugC(3, kDebugWalk, "buildPath: no path"); + return list; + } + + PointList::iterator b = z1->u.path->_lists[id].begin(); + PointList::iterator e = z1->u.path->_lists[id].end(); + for ( ; b != e; b++) { + list->push_front(*b); + } + list->push_back(dest); + debugC(3, kDebugWalk, "buildPath: complex path"); + + return list; +} + +PathBuilder_BR::PathBuilder_BR(Character *ch) : PathBuilder(ch) { +} } // namespace Parallaction diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index dddf2857be..4df89faec1 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -31,11 +31,25 @@ #include "parallaction/objects.h" + namespace Parallaction { +struct Character; + class PathBuilder { - AnimationPtr _anim; +protected: + Character *_ch; + +public: + PathBuilder(Character *ch) : _ch(ch) { } + virtual ~PathBuilder() { } + + virtual PointList* buildPath(uint16 x, uint16 y) = 0; +}; + + +class PathBuilder_NS : public PathBuilder { PointList *_list; PointList _subPath; @@ -45,9 +59,18 @@ class PathBuilder { uint16 walkFunc1(int16 x, int16 y, Common::Point& node); public: - PathBuilder(AnimationPtr anim); + PathBuilder_NS(Character *ch); PointList* buildPath(uint16 x, uint16 y); +}; + + +class PathBuilder_BR : public PathBuilder { + bool directPathExists(const Common::Point &from, const Common::Point &to); + +public: + PathBuilder_BR(Character *ch); + PointList* buildPath(uint16 x, uint16 y); }; -- cgit v1.2.3 From 34ff51d1c6331e3654877da17cd689351edd86f1 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sat, 26 Jul 2008 05:37:52 +0000 Subject: Cleanup. svn-id: r33297 --- engines/parallaction/walk.cpp | 61 +++++++++++++++++++++---------------------- engines/parallaction/walk.h | 2 +- 2 files changed, 31 insertions(+), 32 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index fa6c7d5ede..2adbfb3bac 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -29,6 +29,8 @@ namespace Parallaction { +#define IS_PATH_CLEAR(x,y) _vm->_pathBuffer->getValue((x), (y)) + inline byte PathBuffer::getValue(uint16 x, uint16 y) { byte m = data[(x >> 3) + y * internalWidth]; uint bit = 0; @@ -52,16 +54,16 @@ inline byte PathBuffer::getValue(uint16 x, uint16 y) { // void PathBuilder_NS::correctPathPoint(Common::Point &to) { - if (_vm->_pathBuffer->getValue(to.x, to.y)) return; + if (IS_PATH_CLEAR(to.x, to.y)) return; int16 right = to.x; int16 left = to.x; do { right++; - } while ((_vm->_pathBuffer->getValue(right, to.y) == 0) && (right < _vm->_pathBuffer->w)); + } while (!IS_PATH_CLEAR(right, to.y) && (right < _vm->_pathBuffer->w)); do { left--; - } while ((_vm->_pathBuffer->getValue(left, to.y) == 0) && (left > 0)); + } while (!IS_PATH_CLEAR(left, to.y) && (left > 0)); right = (right == _vm->_pathBuffer->w) ? 1000 : right - to.x; left = (left == 0) ? 1000 : to.x - left; @@ -70,10 +72,10 @@ void PathBuilder_NS::correctPathPoint(Common::Point &to) { int16 bottom = to.y; do { top--; - } while ((_vm->_pathBuffer->getValue(to.x, top) == 0) && (top > 0)); + } while (!IS_PATH_CLEAR(to.x, top) && (top > 0)); do { bottom++; - } while ((_vm->_pathBuffer->getValue(to.x, bottom) == 0) && (bottom < _vm->_pathBuffer->h)); + } while (!IS_PATH_CLEAR(to.x, bottom) && (bottom < _vm->_pathBuffer->h)); top = (top == 0) ? 1000 : to.y - top; bottom = (bottom == _vm->_pathBuffer->h) ? 1000 : bottom - to.y; @@ -156,7 +158,7 @@ PointList *PathBuilder_NS::buildPath(uint16 x, uint16 y) { Common::Point v48(to); Common::Point v44(to); - uint16 v38 = walkFunc1(to.x, to.y, v44); + uint16 v38 = walkFunc1(to, v44); if (v38 == 1) { // destination directly reachable debugC(1, kDebugWalk, "direct move to (%i, %i)", to.x, to.y); @@ -207,11 +209,11 @@ PointList *PathBuilder_NS::buildPath(uint16 x, uint16 y) { // 1 : Point reachable in a straight line // other values: square distance to target (point not reachable in a straight line) // -uint16 PathBuilder_NS::walkFunc1(int16 x, int16 y, Common::Point& node) { +uint16 PathBuilder_NS::walkFunc1(const Common::Point &to, Common::Point& node) { - Common::Point arg(x, y); + Common::Point arg(to); - Common::Point v4(0, 0); + Common::Point v4; Common::Point foot; _ch->getFoot(foot); @@ -220,10 +222,10 @@ uint16 PathBuilder_NS::walkFunc1(int16 x, int16 y, Common::Point& node) { while (foot != arg) { - 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.x < to.x && IS_PATH_CLEAR(foot.x + 1, foot.y)) foot.x++; + if (foot.x > to.x && IS_PATH_CLEAR(foot.x - 1, foot.y)) foot.x--; + if (foot.y < to.y && IS_PATH_CLEAR(foot.x, foot.y + 1)) foot.y++; + if (foot.y > to.y && IS_PATH_CLEAR(foot.x, foot.y - 1)) foot.y--; if (foot == v8 && foot != arg) { @@ -233,10 +235,10 @@ uint16 PathBuilder_NS::walkFunc1(int16 x, int16 y, Common::Point& node) { while (foot != arg) { - 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.x < to.x && !IS_PATH_CLEAR(foot.x + 1, foot.y)) foot.x++; + if (foot.x > to.x && !IS_PATH_CLEAR(foot.x - 1, foot.y)) foot.x--; + if (foot.y < to.y && !IS_PATH_CLEAR(foot.x, foot.y + 1)) foot.y++; + if (foot.y > to.y && !IS_PATH_CLEAR(foot.x, foot.y - 1)) foot.y--; if (foot == v8 && foot != arg) return 0; @@ -245,7 +247,7 @@ uint16 PathBuilder_NS::walkFunc1(int16 x, int16 y, Common::Point& node) { } node = v4; - return (x - v4.x) * (x - v4.x) + (y - v4.y) * (y - v4.y); + return v4.sqrDist(to); } v8 = foot; @@ -258,19 +260,19 @@ uint16 PathBuilder_NS::walkFunc1(int16 x, int16 y, Common::Point& node) { void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { - if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { + if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && IS_PATH_CLEAR(pos.x + 2, pos.y)) { pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x; } - if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { + if ((pos.x > to.x) && (pos.x > 0) && IS_PATH_CLEAR(pos.x - 2, pos.y)) { pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x; } - if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { + if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && IS_PATH_CLEAR(pos.x, pos.y + 2)) { pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y; } - if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { + if ((pos.y > to.y) && (pos.y > 0) && IS_PATH_CLEAR(pos.x, pos.y - 2)) { pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y; } @@ -331,7 +333,7 @@ void Parallaction_ns::walk(Character &character) { // update target, if previous was reached PointList::iterator it = character._walkPath->begin(); if (it != character._walkPath->end()) { - if ((*it).x == curPos.x && (*it).y == curPos.y) { + if (*it == curPos) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it).x, (*it).y); it = character._walkPath->erase(it); } @@ -345,8 +347,7 @@ void Parallaction_ns::walk(Character &character) { targetPos = curPos; } else { // targetPos is saved to help setting character direction - targetPos.x = (*it).x; - targetPos.y = (*it).y; + targetPos = *it; Common::Point newPos(curPos); clipMove(newPos, targetPos); @@ -373,8 +374,6 @@ void Parallaction_ns::walk(Character &character) { PathBuilder_NS::PathBuilder_NS(Character *ch) : PathBuilder(ch), _list(0) { } -#define isPositionOnPath(x,y) _vm->_pathBuffer->getValue((x), (y)) - bool PathBuilder_BR::directPathExists(const Common::Point &from, const Common::Point &to) { @@ -383,10 +382,10 @@ bool PathBuilder_BR::directPathExists(const Common::Point &from, const Common::P while (p != to) { - if (p.x < to.x && isPositionOnPath(p.x + 1, p.y)) p.x++; - if (p.x > to.x && isPositionOnPath(p.x - 1, p.y)) p.x--; - if (p.y < to.y && isPositionOnPath(p.x, p.y + 1)) p.y++; - if (p.y > to.y && isPositionOnPath(p.x, p.y - 1)) p.y--; + if (p.x < to.x && IS_PATH_CLEAR(p.x + 1, p.y)) p.x++; + if (p.x > to.x && IS_PATH_CLEAR(p.x - 1, p.y)) p.x--; + if (p.y < to.y && IS_PATH_CLEAR(p.x, p.y + 1)) p.y++; + if (p.y > to.y && IS_PATH_CLEAR(p.x, p.y - 1)) p.y--; if (p == copy && p != to) { return false; diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index 4df89faec1..680fd3f93f 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -56,7 +56,7 @@ class PathBuilder_NS : public PathBuilder { void correctPathPoint(Common::Point &to); uint32 buildSubPath(const Common::Point& pos, const Common::Point& stop); - uint16 walkFunc1(int16 x, int16 y, Common::Point& node); + uint16 walkFunc1(const Common::Point &to, Common::Point& node); public: PathBuilder_NS(Character *ch); -- cgit v1.2.3 From 8245aa42b5892b92aafe0f0c9c891cabfd7f91ef Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sat, 26 Jul 2008 05:56:39 +0000 Subject: More cleanup. svn-id: r33298 --- engines/parallaction/parallaction.cpp | 9 ++--- engines/parallaction/parallaction.h | 2 +- engines/parallaction/walk.cpp | 75 +++++++++++++++-------------------- engines/parallaction/walk.h | 6 +-- 4 files changed, 40 insertions(+), 52 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 78e7af6343..0c053f35f2 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -548,8 +548,8 @@ void Character::setFoot(const Common::Point &foot) { } #if 0 -void dumpPath(PointList *list, const char* text) { - for (PointList::iterator it = list->begin(); it != list->end(); it++) +void dumpPath(const PointList &list, const char* text) { + for (PointList::iterator it = list.begin(); it != list.end(); it++) printf("node (%i, %i)\n", it->x, it->y); return; @@ -561,7 +561,7 @@ void Character::scheduleWalk(int16 x, int16 y) { return; } - _walkPath = _builder->buildPath(x, y); + _builder->buildPath(x, y); #if 0 dumpPath(_walkPath, _name); #endif @@ -570,8 +570,7 @@ void Character::scheduleWalk(int16 x, int16 y) { _engineFlags |= kEngineWalking; } else { // BRA can't walk yet! - delete _walkPath; - _walkPath = 0; + _walkPath.clear(); } } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 03bff44981..d7786e0633 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -199,7 +199,7 @@ struct Character { GfxObj *_talk; GfxObj *_objs; PathBuilder *_builder; - PointList *_walkPath; + PointList _walkPath; Character(Parallaction *vm); ~Character(); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 2adbfb3bac..bede804f45 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -148,9 +148,11 @@ uint32 PathBuilder_NS::buildSubPath(const Common::Point& pos, const Common::Poin // // x, y: mouse click (foot) coordinates // -PointList *PathBuilder_NS::buildPath(uint16 x, uint16 y) { +void PathBuilder_NS::buildPath(uint16 x, uint16 y) { debugC(1, kDebugWalk, "PathBuilder::buildPath to (%i, %i)", x, y); + _ch->_walkPath.clear(); + Common::Point to(x, y); correctPathPoint(to); debugC(1, kDebugWalk, "found closest path point at (%i, %i)", to.x, to.y); @@ -162,43 +164,32 @@ PointList *PathBuilder_NS::buildPath(uint16 x, uint16 y) { if (v38 == 1) { // destination directly reachable debugC(1, kDebugWalk, "direct move to (%i, %i)", to.x, to.y); - - _list = new PointList; - _list->push_back(v48); - return _list; + _ch->_walkPath.push_back(v48); + return; } // path is obstructed: look for alternative - _list = new PointList; - _list->push_back(v48); + _ch->_walkPath.push_back(v48); #if 0 printNodes(_list, "start"); #endif - Common::Point stop(v48.x, v48.y); Common::Point pos; _ch->getFoot(pos); - uint32 v34 = buildSubPath(pos, stop); + uint32 v34 = buildSubPath(pos, v48); if (v38 != 0 && v34 > v38) { // no alternative path (gap?) - _list->clear(); - _list->push_back(v44); - return _list; + _ch->_walkPath.clear(); + _ch->_walkPath.push_back(v44); + return; } - _list->insert(_list->begin(), _subPath.begin(), _subPath.end()); -#if 0 - printNodes(_list, "first segment"); -#endif + _ch->_walkPath.insert(_ch->_walkPath.begin(), _subPath.begin(), _subPath.end()); - stop = *_list->begin(); - buildSubPath(pos, stop); - _list->insert(_list->begin(), _subPath.begin(), _subPath.end()); -#if 0 - printNodes(_list, "complete"); -#endif + buildSubPath(pos, *_ch->_walkPath.begin()); + _ch->_walkPath.insert(_ch->_walkPath.begin(), _subPath.begin(), _subPath.end()); - return _list; + return; } @@ -318,8 +309,7 @@ void Parallaction::finalizeWalk(Character &character) { character.getFoot(foot); checkDoor(foot); - delete character._walkPath; - character._walkPath = 0; + character._walkPath.clear(); } void Parallaction_ns::walk(Character &character) { @@ -331,17 +321,17 @@ void Parallaction_ns::walk(Character &character) { character.getFoot(curPos); // update target, if previous was reached - PointList::iterator it = character._walkPath->begin(); - if (it != character._walkPath->end()) { + PointList::iterator it = character._walkPath.begin(); + if (it != character._walkPath.end()) { if (*it == curPos) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it).x, (*it).y); - it = character._walkPath->erase(it); + it = character._walkPath.erase(it); } } // advance character towards the target Common::Point targetPos; - if (it == character._walkPath->end()) { + if (it == character._walkPath.end()) { debugC(1, kDebugWalk, "walk reached last node"); finalizeWalk(character); targetPos = curPos; @@ -397,54 +387,53 @@ bool PathBuilder_BR::directPathExists(const Common::Point &from, const Common::P return true; } -PointList* PathBuilder_BR::buildPath(uint16 x, uint16 y) { +void PathBuilder_BR::buildPath(uint16 x, uint16 y) { Common::Point foot; _ch->getFoot(foot); debugC(1, kDebugWalk, "buildPath: from (%i, %i) to (%i, %i)", foot.x, foot.y, x, y); - - PointList *list = new PointList; + _ch->_walkPath.clear(); // look for easy path first Common::Point dest(x, y); if (directPathExists(foot, dest)) { - list->push_back(dest); + _ch->_walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: direct path found"); - return list; + return; } // look for short circuit cases ZonePtr z0 = _vm->hitZone(kZonePath, x, y); if (z0 == nullZonePtr) { - list->push_back(dest); + _ch->_walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: corner case 0"); - return list; + return; } ZonePtr z1 = _vm->hitZone(kZonePath, foot.x, foot.y); if (z1 == nullZonePtr || z1 == z0) { - list->push_back(dest); + _ch->_walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: corner case 1"); - return list; + return; } // build complex path int id = atoi(z0->_name); if (z1->u.path->_lists[id].empty()) { - list->clear(); + _ch->_walkPath.clear(); debugC(3, kDebugWalk, "buildPath: no path"); - return list; + return; } PointList::iterator b = z1->u.path->_lists[id].begin(); PointList::iterator e = z1->u.path->_lists[id].end(); for ( ; b != e; b++) { - list->push_front(*b); + _ch->_walkPath.push_front(*b); } - list->push_back(dest); + _ch->_walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: complex path"); - return list; + return; } PathBuilder_BR::PathBuilder_BR(Character *ch) : PathBuilder(ch) { diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index 680fd3f93f..e6ad8e5c16 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -45,7 +45,7 @@ public: PathBuilder(Character *ch) : _ch(ch) { } virtual ~PathBuilder() { } - virtual PointList* buildPath(uint16 x, uint16 y) = 0; + virtual void buildPath(uint16 x, uint16 y) = 0; }; @@ -60,7 +60,7 @@ class PathBuilder_NS : public PathBuilder { public: PathBuilder_NS(Character *ch); - PointList* buildPath(uint16 x, uint16 y); + void buildPath(uint16 x, uint16 y); }; @@ -70,7 +70,7 @@ class PathBuilder_BR : public PathBuilder { public: PathBuilder_BR(Character *ch); - PointList* buildPath(uint16 x, uint16 y); + void buildPath(uint16 x, uint16 y); }; -- cgit v1.2.3 From 4f445e3deb2e468393a26166d46ed34e758ef316 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Sun, 27 Jul 2008 01:54:40 +0000 Subject: Fix buffer overflow in error message. svn-id: r33321 --- engines/agos/saveload.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 34e5f2cfeb..284c7979c0 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -75,7 +75,7 @@ int AGOSEngine::countSaveGames() { } char *AGOSEngine::genSaveName(int slot) { - static char buf[15]; + static char buf[20]; if (getGameId() == GID_DIMP) { sprintf(buf, "dimp.sav"); @@ -111,7 +111,7 @@ void AGOSEngine::quickLoadOrSave() { } bool success; - char buf[50]; + char buf[60]; char *filename = genSaveName(_saveLoadSlot); if (_saveLoadType == 2) { -- cgit v1.2.3 From b9d0e4dafb82a6481dc6a16d834edb9f017e4e26 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 27 Jul 2008 08:35:00 +0000 Subject: Doug from BRA can now walk in his hotel room. He still stops in bizarre poses, though. svn-id: r33325 --- engines/parallaction/parallaction.cpp | 20 ++-- engines/parallaction/parallaction.h | 8 +- engines/parallaction/walk.cpp | 220 ++++++++++++++++++++++++++++------ engines/parallaction/walk.h | 37 ++++++ 4 files changed, 231 insertions(+), 54 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 0c053f35f2..436cad4ca4 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -353,7 +353,7 @@ void Parallaction::runGame() { if (_char._ani->gfxobj) { _char._ani->gfxobj->z = _char._ani->_z; } - walk(_char); + _char._walker->walk(); drawAnimations(); } @@ -518,16 +518,22 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) { strncpy(_ani->_name, "yourself", ZONENAME_LENGTH); // TODO: move creation into Parallaction. Needs to make Character a pointer first. - if (_vm->getGameType() == GType_Nippon) + if (_vm->getGameType() == GType_Nippon) { _builder = new PathBuilder_NS(this); - else + _walker = new PathWalker_NS(this); + } else { _builder = new PathBuilder_BR(this); + _walker = new PathWalker_BR(this); + } } Character::~Character() { delete _builder; _builder = 0; + delete _walker; + _walker = 0; + free(); } @@ -565,13 +571,7 @@ void Character::scheduleWalk(int16 x, int16 y) { #if 0 dumpPath(_walkPath, _name); #endif - - if (_vm->getGameType() == GType_Nippon) { - _engineFlags |= kEngineWalking; - } else { - // BRA can't walk yet! - _walkPath.clear(); - } + _engineFlags |= kEngineWalking; } void Character::free() { diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index d7786e0633..8d4bb93c97 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -199,6 +199,7 @@ struct Character { GfxObj *_talk; GfxObj *_objs; PathBuilder *_builder; + PathWalker *_walker; PointList _walkPath; Character(Parallaction *vm); @@ -260,9 +261,6 @@ public: void pauseJobs(); void resumeJobs(); - void finalizeWalk(Character &character); - void clipMove(Common::Point& pos, const Common::Point& to); - ZonePtr findZone(const char *name); ZonePtr hitZone(uint32 type, uint16 x, uint16 y); uint16 runZone(ZonePtr z); @@ -353,8 +351,6 @@ protected: // members void displayComment(ExamineData *data); - void checkDoor(const Common::Point &foot); - void freeCharacter(); int16 pickupItem(ZonePtr z); @@ -375,7 +371,6 @@ public: void updateDoor(ZonePtr z); - virtual void walk(Character &character) = 0; virtual void drawAnimations() = 0; void beep(); @@ -586,7 +581,6 @@ private: const Callable *_callables; protected: - void walk(Character &character); void drawAnimations(); void parseLocation(const char *filename); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index bede804f45..feb2029f5a 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -170,10 +170,6 @@ void PathBuilder_NS::buildPath(uint16 x, uint16 y) { // path is obstructed: look for alternative _ch->_walkPath.push_back(v48); -#if 0 - printNodes(_list, "start"); -#endif - Common::Point pos; _ch->getFoot(pos); @@ -249,9 +245,9 @@ uint16 PathBuilder_NS::walkFunc1(const Common::Point &to, Common::Point& node) { return 1; } -void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { +void PathWalker_NS::clipMove(Common::Point& pos, const Common::Point& to) { - if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && IS_PATH_CLEAR(pos.x + 2, pos.y)) { + if ((pos.x < to.x) && (pos.x < _vm->_pathBuffer->w) && IS_PATH_CLEAR(pos.x + 2, pos.y)) { pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x; } @@ -259,7 +255,7 @@ void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x; } - if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && IS_PATH_CLEAR(pos.x, pos.y + 2)) { + if ((pos.y < to.y) && (pos.y < _vm->_pathBuffer->h) && IS_PATH_CLEAR(pos.x, pos.y + 2)) { pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y; } @@ -271,69 +267,69 @@ void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { } -void Parallaction::checkDoor(const Common::Point &foot) { +void PathWalker_NS::checkDoor(const Common::Point &foot) { - ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y); + ZonePtr z = _vm->hitZone(kZoneDoor, foot.x, foot.y); if (z) { if ((z->_flags & kFlagsClosed) == 0) { - _location._startPosition = z->u.door->_startPos; - _location._startFrame = z->u.door->_startFrame; - scheduleLocationSwitch(z->u.door->_location); - _zoneTrap = nullZonePtr; + _vm->_location._startPosition = z->u.door->_startPos; + _vm->_location._startFrame = z->u.door->_startFrame; + _vm->scheduleLocationSwitch(z->u.door->_location); + _vm->_zoneTrap = nullZonePtr; } else { - _cmdExec->run(z->_commands, z); + _vm->_cmdExec->run(z->_commands, z); } } - z = hitZone(kZoneTrap, foot.x, foot.y); + z = _vm->hitZone(kZoneTrap, foot.x, foot.y); if (z) { - setLocationFlags(kFlagsEnter); - _cmdExec->run(z->_commands, z); - clearLocationFlags(kFlagsEnter); - _zoneTrap = z; + _vm->setLocationFlags(kFlagsEnter); + _vm->_cmdExec->run(z->_commands, z); + _vm->clearLocationFlags(kFlagsEnter); + _vm->_zoneTrap = z; } else - if (_zoneTrap) { - setLocationFlags(kFlagsExit); - _cmdExec->run(_zoneTrap->_commands, _zoneTrap); - clearLocationFlags(kFlagsExit); - _zoneTrap = nullZonePtr; + if (_vm->_zoneTrap) { + _vm->setLocationFlags(kFlagsExit); + _vm->_cmdExec->run(_vm->_zoneTrap->_commands, _vm->_zoneTrap); + _vm->clearLocationFlags(kFlagsExit); + _vm->_zoneTrap = nullZonePtr; } } -void Parallaction::finalizeWalk(Character &character) { +void PathWalker_NS::finalizeWalk() { _engineFlags &= ~kEngineWalking; Common::Point foot; - character.getFoot(foot); + _ch->getFoot(foot); checkDoor(foot); - character._walkPath.clear(); + _ch->_walkPath.clear(); } -void Parallaction_ns::walk(Character &character) { +void PathWalker_NS::walk() { if ((_engineFlags & kEngineWalking) == 0) { return; } Common::Point curPos; - character.getFoot(curPos); + _ch->getFoot(curPos); // update target, if previous was reached - PointList::iterator it = character._walkPath.begin(); - if (it != character._walkPath.end()) { + PointList::iterator it = _ch->_walkPath.begin(); + if (it != _ch->_walkPath.end()) { if (*it == curPos) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it).x, (*it).y); - it = character._walkPath.erase(it); + it = _ch->_walkPath.erase(it); } } // advance character towards the target Common::Point targetPos; - if (it == character._walkPath.end()) { + if (it == _ch->_walkPath.end()) { debugC(1, kDebugWalk, "walk reached last node"); - finalizeWalk(character); + finalizeWalk(); targetPos = curPos; } else { // targetPos is saved to help setting character direction @@ -341,11 +337,11 @@ void Parallaction_ns::walk(Character &character) { Common::Point newPos(curPos); clipMove(newPos, targetPos); - character.setFoot(newPos); + _ch->setFoot(newPos); if (newPos == curPos) { debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); - finalizeWalk(character); + finalizeWalk(); targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected } } @@ -356,7 +352,7 @@ void Parallaction_ns::walk(Character &character) { // from curPos to newPos is prone to abrutply change in direction, thus making the // code select 'too different' frames when walking diagonally against obstacles, // and yielding an annoying shaking effect in the character. - character.updateDirection(curPos, targetPos); + _ch->updateDirection(curPos, targetPos); } @@ -439,4 +435,154 @@ void PathBuilder_BR::buildPath(uint16 x, uint16 y) { PathBuilder_BR::PathBuilder_BR(Character *ch) : PathBuilder(ch) { } +void PathWalker_BR::finalizeWalk() { + _engineFlags &= ~kEngineWalking; + _first = true; + _fieldC = 1; +} + + +void PathWalker_BR::walk() { + if ((_engineFlags & kEngineWalking) == 0) { + return; + } + +/* + if (ch._walkDelay > 0) { + ch._walkDelay--; + if (ch._walkDelay == 0 && _ch._ani->_scriptName) { + // stop script and reset + _ch._ani->_flags &= ~kFlagsActing; + Script *script = findScript(_ch._ani->_scriptName); + script->_nextCommand = script->firstCommand; + } + return; + } +*/ + GfxObj *obj = _ch->_ani->gfxobj; + + Common::Rect rect; + obj->getRect(_ch->_ani->_frame, rect); + + uint scale; + if (rect.bottom > _vm->_location._zeta0) { + scale = 100; + } else + if (rect.bottom < _vm->_location._zeta1) { + scale = _vm->_location._zeta2; + } else { + scale = _vm->_location._zeta2 + ((rect.bottom - _vm->_location._zeta1) * (100 - _vm->_location._zeta2)) / (_vm->_location._zeta0 - _vm->_location._zeta1); + } + int xStep = (scale * 16) / 100 + 1; + int yStep = (scale * 10) / 100 + 1; + + debugC(9, kDebugWalk, "calculated step: (%i, %i)\n", xStep, yStep); +/* + if (_first) { + _ch->getFoot(_startFoot); + _first = false; + } +*/ + if (_fieldC == 0) { + _ch->_walkPath.erase(_ch->_walkPath.begin()); + + if (_ch->_walkPath.empty()) { + finalizeWalk(); + debugC(3, kDebugWalk, "PathWalker_BR::walk, case 0\n"); + return; + } else { +// _ch->getFoot(_startFoot); + debugC(3, kDebugWalk, "PathWalker_BR::walk, moving to next node\n"); + } + } + + _ch->getFoot(_startFoot); + + _fieldC = 0; + _step++; + _step %= 8; + + int walkFrame = _step; + int dirFrame = 0; + Common::Point newpos(_startFoot), delta; + + Common::Point p(*_ch->_walkPath.begin()); + + if (_startFoot.y < p.y && _startFoot.y < 400 && IS_PATH_CLEAR(_startFoot.x, yStep + _startFoot.y)) { + if (yStep + _startFoot.y <= p.y) { + _fieldC = 1; + delta.y = yStep; + newpos.y = yStep + _startFoot.y; + } else { + delta.y = p.y - _startFoot.y; + newpos.y = p.y; + } + dirFrame = 9; + } else + if (_startFoot.y > p.y && _startFoot.y > 0 && IS_PATH_CLEAR(_startFoot.x, _startFoot.y - yStep)) { + if (_startFoot.y - yStep >= p.y) { + _fieldC = 1; + delta.y = yStep; + newpos.y = _startFoot.y - yStep; + } else { + delta.y = _startFoot.y - p.y; + newpos.y = p.y; + } + dirFrame = 0; + } + + if (_startFoot.x < p.x && _startFoot.x < 640 && IS_PATH_CLEAR(_startFoot.x + xStep, _startFoot.y)) { + if (_startFoot.x + xStep <= p.x) { + _fieldC = 1; + delta.x = xStep; + newpos.x = xStep + _startFoot.x; + } else { + delta.x = p.x - _startFoot.x; + newpos.x = p.x; + } + if (delta.y < delta.x) { + dirFrame = 18; // right + } + } else + if (_startFoot.x > p.x && _startFoot.x > 0 && IS_PATH_CLEAR(_startFoot.x - xStep, _startFoot.y)) { + if (_startFoot.x - xStep >= p.x) { + _fieldC = 1; + delta.x = xStep; + newpos.x = _startFoot.x - xStep; + } else { + delta.x = _startFoot.x - p.x; + newpos.x = p.x; + } + if (delta.y < delta.x) { + dirFrame = 27; // left + } + } + + debugC(9, kDebugWalk, "foot (%i, %i) dest (%i, %i) deltas = %i/%i \n", _startFoot.x, _startFoot.y, p.x, p.y, delta.x, delta.y); + + if (_fieldC) { + debugC(9, kDebugWalk, "PathWalker_BR::walk, foot moved from (%i, %i) to (%i, %i)\n", _startFoot.x, _startFoot.y, newpos.x, newpos.y); + _ch->_ani->_frame = walkFrame + dirFrame + 1; + _startFoot.x = newpos.x; + _startFoot.y = newpos.y; + _ch->setFoot(_startFoot); + // _ch->_z = ch._startFoot.y; + } + + if (_fieldC || !_ch->_walkPath.empty()) { +// checkTrap(); + debugC(3, kDebugWalk, "PathWalker_BR::walk, case 1\n"); + return; + } + + debugC(3, kDebugWalk, "PathWalker_BR::walk, case 2\n"); + finalizeWalk(); + return; +} + +PathWalker_BR::PathWalker_BR(Character *ch) : PathWalker(ch), _fieldC(1), _first(true) { + +} + + } // namespace Parallaction diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index e6ad8e5c16..f1afa078fd 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -73,6 +73,43 @@ public: void buildPath(uint16 x, uint16 y); }; +class PathWalker { +protected: + Character *_ch; +public: + PathWalker(Character *ch) : _ch(ch) { } + virtual ~PathWalker() { } + virtual void walk() = 0; +}; + +class PathWalker_NS : public PathWalker { + + + void finalizeWalk(); + void clipMove(Common::Point& pos, const Common::Point& to); + void checkDoor(const Common::Point &foot); + +public: + PathWalker_NS(Character *ch) : PathWalker(ch) { } + void walk(); +}; + + +class PathWalker_BR : public PathWalker { + + + int _walkDelay; + int _fieldC; + Common::Point _startFoot; + bool _first; + int _step; + + void finalizeWalk(); + +public: + PathWalker_BR(Character *ch); + void walk(); +}; } -- cgit v1.2.3 From e0503bc5499614399bf5778c66ff0b7f4e5e4b07 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Sun, 27 Jul 2008 10:36:26 +0000 Subject: Search common directory, when loading frames and talks in Amiga verison of BRA. svn-id: r33327 --- engines/parallaction/disk.h | 2 +- engines/parallaction/disk_br.cpp | 42 ++++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 11 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 694d4efa6d..5b00baeb04 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -239,7 +239,7 @@ class AmigaDisk_br : public DosDisk_br { protected: BackgroundInfo _backgroundTemp; - Sprites* createSprites(const char *name); + Sprites* createSprites(Common::ReadStream &stream); Font *createFont(const char *name, Common::SeekableReadStream &stream); void loadMask(BackgroundInfo& info, const char *name); void loadBackground(BackgroundInfo& info, const char *name); diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index ee1e111139..035d0d13c5 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -576,13 +576,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) { return new GfxObj(0, new SurfaceToFrames(surf)); } -Sprites* AmigaDisk_br::createSprites(const char *path) { - - Common::File stream; - if (!stream.open(path)) { - errorFileNotFound(path); - } - +Sprites* AmigaDisk_br::createSprites(Common::ReadStream &stream) { uint16 num = stream.readUint16BE(); Sprites *sprites = new Sprites(num); @@ -609,16 +603,44 @@ Frames* AmigaDisk_br::loadFrames(const char* name) { char path[PATH_LEN]; sprintf(path, "%s/anims/%s", _partPath, name); - return createSprites(path); + Common::File stream; + if (!stream.open(path)) { + sprintf(path, "%s/anims/%s.ani", _partPath, name); + if (!stream.open(path)) { + sprintf(path, "common/anims/%s", name); + if (!stream.open(path)) { + sprintf(path, "common/anims/%s.ani", name); + if (!stream.open(path)) { + errorFileNotFound(path); + } + } + } + } + + return createSprites(stream); } GfxObj* AmigaDisk_br::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name); + Common::File stream; + char path[PATH_LEN]; - sprintf(path, "%s/talks/%s.tal", _partPath, name); + sprintf(path, "%s/talks/%s", _partPath, name); + if (!stream.open(path)) { + sprintf(path, "%s/talks/%s.tal", _partPath, name); + if (!stream.open(path)) { + sprintf(path, "common/talks/%s", name); + if (!stream.open(path)) { + sprintf(path, "common/talks/%s.tal", name); + if (!stream.open(path)) { + errorFileNotFound(path); + } + } + } + } - return new GfxObj(0, createSprites(path)); + return new GfxObj(0, createSprites(stream)); } Font* AmigaDisk_br::loadFont(const char* name) { -- cgit v1.2.3 From 6e4d26fb70566846c1d8e559db9e1c4b39e3324d Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 27 Jul 2008 10:37:54 +0000 Subject: Added rudimental support for location changes when walking through doors. The best part of this commit is that Doug now stops in a normal position. svn-id: r33328 --- engines/parallaction/walk.cpp | 79 ++++++++++++++++++++++++++++++++++--------- engines/parallaction/walk.h | 2 ++ 2 files changed, 65 insertions(+), 16 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index feb2029f5a..14d8d080bd 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -439,6 +439,57 @@ void PathWalker_BR::finalizeWalk() { _engineFlags &= ~kEngineWalking; _first = true; _fieldC = 1; + + Common::Point foot; + _ch->getFoot(foot); + + ZonePtr z = _vm->hitZone(kZoneDoor, foot.x, foot.y); + if (z != nullZonePtr && (z->_flags & kFlagsClosed) == 0) { + _vm->_location._startPosition = z->u.door->_startPos; // foot pos + _vm->_location._startFrame = z->u.door->_startFrame; + +#if 0 + // TODO: implement working follower. Must find out a location in which the code is + // used and which is stable enough. + _followerFootInit.x = -1; + if (_follower && z->u.door->startPos2.x != -1) { + _followerFootInit.x = z->u.door->startPos2.x; // foot pos + _followerFootInit.y = z->u.door->startPos2.y; // foot pos + } + _followerFootInit.z = -1; + if (_follower && z->u.door->startPos2.z != -1) { + _followerFootInit.z = z->u.door->startPos2.z; // foot pos + } +#endif + + _vm->scheduleLocationSwitch(z->u.door->_location); + _vm->_cmdExec->run(z->_commands, z); + } + +#if 0 + // TODO: Input::walkTo must be extended to support destination frame in addition to coordinates + // TODO: the frame argument must be passed to PathWalker through PathBuilder, so probably + // a merge between the two Path managers is the right solution + if (_engineFlags & FINAL_WALK_FRAME) { // this flag is set in readInput() + _engineFlags &= ~FINAL_WALK_FRAME; + _char.ani->_frame = _moveToF; // from readInput()... + } else { + _char.ani->_frame = _dirFrame; // from walk() + } + _char.setFoot(foot); +#endif + + _ch->_ani->_frame = _dirFrame; // temporary solution + +#if 0 + // TODO: support scrolling ;) + if (foot.x > _gfx->hscroll + 600) _gfx->scrollRight(78); + if (foot.x < _gfx->hscroll + 40) _gfx->scrollLeft(78); + if (foot.y > 350) _gfx->scrollDown(100); + if (foot.y < 80) _gfx->scrollUp(100); +#endif + + return; } @@ -447,7 +498,8 @@ void PathWalker_BR::walk() { return; } -/* +#if 0 + // TODO: support delays in walking. This requires extending Input::walkIo(). if (ch._walkDelay > 0) { ch._walkDelay--; if (ch._walkDelay == 0 && _ch._ani->_scriptName) { @@ -458,7 +510,8 @@ void PathWalker_BR::walk() { } return; } -*/ +#endif + GfxObj *obj = _ch->_ani->gfxobj; Common::Rect rect; @@ -477,12 +530,7 @@ void PathWalker_BR::walk() { int yStep = (scale * 10) / 100 + 1; debugC(9, kDebugWalk, "calculated step: (%i, %i)\n", xStep, yStep); -/* - if (_first) { - _ch->getFoot(_startFoot); - _first = false; - } -*/ + if (_fieldC == 0) { _ch->_walkPath.erase(_ch->_walkPath.begin()); @@ -491,7 +539,6 @@ void PathWalker_BR::walk() { debugC(3, kDebugWalk, "PathWalker_BR::walk, case 0\n"); return; } else { -// _ch->getFoot(_startFoot); debugC(3, kDebugWalk, "PathWalker_BR::walk, moving to next node\n"); } } @@ -503,7 +550,7 @@ void PathWalker_BR::walk() { _step %= 8; int walkFrame = _step; - int dirFrame = 0; + _dirFrame = 0; Common::Point newpos(_startFoot), delta; Common::Point p(*_ch->_walkPath.begin()); @@ -517,7 +564,7 @@ void PathWalker_BR::walk() { delta.y = p.y - _startFoot.y; newpos.y = p.y; } - dirFrame = 9; + _dirFrame = 9; } else if (_startFoot.y > p.y && _startFoot.y > 0 && IS_PATH_CLEAR(_startFoot.x, _startFoot.y - yStep)) { if (_startFoot.y - yStep >= p.y) { @@ -528,7 +575,7 @@ void PathWalker_BR::walk() { delta.y = _startFoot.y - p.y; newpos.y = p.y; } - dirFrame = 0; + _dirFrame = 0; } if (_startFoot.x < p.x && _startFoot.x < 640 && IS_PATH_CLEAR(_startFoot.x + xStep, _startFoot.y)) { @@ -541,7 +588,7 @@ void PathWalker_BR::walk() { newpos.x = p.x; } if (delta.y < delta.x) { - dirFrame = 18; // right + _dirFrame = 18; // right } } else if (_startFoot.x > p.x && _startFoot.x > 0 && IS_PATH_CLEAR(_startFoot.x - xStep, _startFoot.y)) { @@ -554,7 +601,7 @@ void PathWalker_BR::walk() { newpos.x = p.x; } if (delta.y < delta.x) { - dirFrame = 27; // left + _dirFrame = 27; // left } } @@ -562,11 +609,11 @@ void PathWalker_BR::walk() { if (_fieldC) { debugC(9, kDebugWalk, "PathWalker_BR::walk, foot moved from (%i, %i) to (%i, %i)\n", _startFoot.x, _startFoot.y, newpos.x, newpos.y); - _ch->_ani->_frame = walkFrame + dirFrame + 1; + _ch->_ani->_frame = walkFrame + _dirFrame + 1; _startFoot.x = newpos.x; _startFoot.y = newpos.y; _ch->setFoot(_startFoot); - // _ch->_z = ch._startFoot.y; + _ch->_ani->_z = newpos.y; } if (_fieldC || !_ch->_walkPath.empty()) { diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index f1afa078fd..8d21e5ebbd 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -104,6 +104,8 @@ class PathWalker_BR : public PathWalker { bool _first; int _step; + int _dirFrame; + void finalizeWalk(); public: -- cgit v1.2.3 From 4c7420125ec5b1549953e137176a5e6109459a5f Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Sun, 27 Jul 2008 10:43:15 +0000 Subject: Add music/sound loading in Amiga version of BRA. svn-id: r33329 --- engines/parallaction/disk.h | 2 ++ engines/parallaction/disk_br.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 5b00baeb04..24f80e1a44 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -254,6 +254,8 @@ public: Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); + Common::SeekableReadStream* loadMusic(const char* name); + Common::ReadStream* loadSound(const char* name); }; } // namespace Parallaction diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 035d0d13c5..aec605dbcd 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -656,4 +656,31 @@ Font* AmigaDisk_br::loadFont(const char* name) { return createFont(name, stream); } +Common::SeekableReadStream* AmigaDisk_br::loadMusic(const char* name) { + debugC(5, kDebugDisk, "AmigaDisk_br::loadMusic"); + + char path[PATH_LEN]; + sprintf(path, "%s/msc/%s", _partPath, name); + + Common::File *stream = new Common::File; + if (!stream->open(path)) + return 0; + + return stream; +} + + +Common::ReadStream* AmigaDisk_br::loadSound(const char* name) { + debugC(5, kDebugDisk, "AmigaDisk_br::loadSound"); + + char path[PATH_LEN]; + sprintf(path, "%s/sfx/%s", _partPath, name); + + Common::File *stream = new Common::File; + if (!stream->open(path)) + errorFileNotFound(path); + + return stream; +} + } // namespace Parallaction -- cgit v1.2.3 From bd5cac4e2efb75f67235222a8ea2ce01247429ae Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 27 Jul 2008 12:05:40 +0000 Subject: Fixed macro. svn-id: r33332 --- engines/kyra/script_hof.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index 94f160d11f..e3a8bf95bc 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -1492,7 +1492,7 @@ typedef Common::Functor1Mem OpcodeV2; typedef Common::Functor2Mem TIMOpcodeV2; #define OpcodeTim(x) _timOpcodes.push_back(new TIMOpcodeV2(this, &KyraEngine_HoF::x)) -#define OpcodeTimUnImpl() _timOpcodes.push_back(TIMOpcodeV2(this, 0)) +#define OpcodeTimUnImpl() _timOpcodes.push_back(new TIMOpcodeV2(this, 0)) void KyraEngine_HoF::setupOpcodeTable() { Common::Array *table = 0; -- cgit v1.2.3 From b95c05c384fd99e1deb75245aa295a5de64b9091 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 27 Jul 2008 12:09:10 +0000 Subject: Fixed typo. svn-id: r33333 --- engines/kyra/wsamovie.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/kyra/wsamovie.h b/engines/kyra/wsamovie.h index 36cd75b1ab..1db8ee8474 100644 --- a/engines/kyra/wsamovie.h +++ b/engines/kyra/wsamovie.h @@ -109,7 +109,7 @@ private: class WSAMovie_v2 : public WSAMovie_v1 { public: - WSAMovie_v2(KyraEngine_v1 *vm, Screen_v2 *scren); + WSAMovie_v2(KyraEngine_v1 *vm, Screen_v2 *screen); int open(const char *filename, int unk1, uint8 *palette); -- cgit v1.2.3 From 7e7468b322d928a28243a3e03bc64e87dda4fadc Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 27 Jul 2008 12:12:40 +0000 Subject: - Fixed fadePalette for HoF and Kyra3 - Fixed bug in wsaFrameAnimationStep svn-id: r33334 --- engines/kyra/screen.cpp | 109 ++++++++++++++++++++++++++------------------- engines/kyra/screen.h | 6 ++- engines/kyra/screen_v2.cpp | 26 ++++++++++- engines/kyra/screen_v2.h | 2 + 4 files changed, 95 insertions(+), 48 deletions(-) (limited to 'engines') diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 6e7a88b1a3..74f7bc6de9 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -380,61 +380,23 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u debugC(9, kDebugLevelScreen, "Screen::fadePalette(%p, %d, %p)", (const void *)palData, delay, (const void*)upFunc); updateScreen(); - uint8 fadePal[768]; - memcpy(fadePal, _screenPalette, 768); - uint8 diff, maxDiff = 0; - for (int i = 0; i < 768; ++i) { - diff = ABS(palData[i] - fadePal[i]); - if (diff > maxDiff) { - maxDiff = diff; - } - } - - int16 delayInc = delay << 8; - if (maxDiff != 0) - delayInc /= maxDiff; - - delay = delayInc; - for (diff = 1; diff <= maxDiff; ++diff) { - if (delayInc >= 512) - break; - delayInc += delay; - } + int diff = 0, delayInc = 0; + getFadeParams(palData, delay, delayInc, diff); int delayAcc = 0; while (!_vm->quit()) { delayAcc += delayInc; - bool needRefresh = false; - for (int i = 0; i < 768; ++i) { - int c1 = palData[i]; - int c2 = fadePal[i]; - if (c1 != c2) { - needRefresh = true; - if (c1 > c2) { - c2 += diff; - if (c1 < c2) - c2 = c1; - } - - if (c1 < c2) { - c2 -= diff; - if (c1 > c2) - c2 = c1; - } - - fadePal[i] = (uint8)c2; - } - } - if (!needRefresh) - break; + int refreshed = fadePalStep(palData, diff); - setScreenPalette(fadePal); if (upFunc && upFunc->isValid()) (*upFunc)(); else _system->updateScreen(); - //_system->delayMillis((delayAcc >> 8) * 1000 / 60); + + if (!refreshed) + break; + _vm->delay((delayAcc >> 8) * 1000 / 60); delayAcc &= 0xFF; } @@ -448,6 +410,61 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u } } +void Screen::getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff) { + debugC(9, kDebugLevelScreen, "Screen::getFadeParams(%p, %d, %p, %p)", (const void *)palette, delay, (const void *)&delayInc, (const void *)&diff); + uint8 maxDiff = 0; + for (int i = 0; i < 768; ++i) { + diff = ABS(palette[i] - _screenPalette[i]); + maxDiff = MAX(maxDiff, diff); + } + + delayInc = delay << 8; + if (maxDiff != 0) + delayInc /= maxDiff; + delayInc &= 0x7FFF; + + delay = delayInc; + for (diff = 1; diff <= maxDiff; ++diff) { + if (delayInc >= 512) + break; + delayInc += delay; + } +} + +int Screen::fadePalStep(const uint8 *palette, int diff) { + debugC(9, kDebugLevelScreen, "Screen::fadePalStep(%p, %d)", (const void *)palette, diff); + + uint8 fadePal[768]; + memcpy(fadePal, _screenPalette, 768); + + bool needRefresh = false; + for (int i = 0; i < 768; ++i) { + int c1 = palette[i]; + int c2 = fadePal[i]; + if (c1 != c2) { + needRefresh = true; + if (c1 > c2) { + c2 += diff; + if (c1 < c2) + c2 = c1; + } + + if (c1 < c2) { + c2 -= diff; + if (c1 > c2) + c2 = c1; + } + + fadePal[i] = (uint8)c2; + } + } + + if (needRefresh) + setScreenPalette(fadePal); + + return needRefresh ? 1 : 0; +} + void Screen::setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue) { debugC(9, kDebugLevelScreen, "Screen::setPaletteIndex(%u, %u, %u, %u)", index, red, green, blue); _currentPalette[index * 3 + 0] = red; @@ -2442,7 +2459,7 @@ void Screen::setShapePages(int page1, int page2, int minY, int maxY) { _maskMaxY = maxY; } -void Screen::setMouseCursor(int x, int y, byte *shape) { +void Screen::setMouseCursor(int x, int y, const byte *shape) { debugC(9, kDebugLevelScreen, "Screen::setMouseCursor(%d, %d, %p)", x, y, (const void *)shape); if (!shape) return; diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index f8c85a2bac..99ba2d7c5f 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -89,10 +89,12 @@ public: enum FontId { FID_6_FNT = 0, FID_8_FNT, + FID_9_FNT, FID_CRED6_FNT, FID_CRED8_FNT, FID_BOOKFONT_FNT, FID_GOLDFONT_FNT, + FID_INTRO_FNT, FID_NUM }; @@ -145,6 +147,8 @@ public: void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0); void fadePalette(const uint8 *palData, int delay, const UpdateFunctor *upFunc = 0); + virtual void getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff); + int fadePalStep(const uint8 *palette, int diff); void setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue); void setScreenPalette(const uint8 *palData); @@ -189,7 +193,7 @@ public: void hideMouse(); void showMouse(); bool isMouseVisible() const; - void setMouseCursor(int x, int y, byte *shape); + void setMouseCursor(int x, int y, const byte *shape); // rect handling virtual int getRectSize(int w, int h) = 0; diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp index e26ef87bad..e5d851aeab 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -111,6 +111,30 @@ int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *p return r; } +void Screen_v2::getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff) { + debugC(9, kDebugLevelScreen, "Screen_v2::getFadeParams(%p, %d, %p, %p)", (const void *)palette, delay, (const void *)&delayInc, (const void *)&diff); + + int maxDiff = 0; + diff = 0; + for (int i = 0; i < 768; ++i) { + diff = ABS(palette[i] - _screenPalette[i]); + maxDiff = MAX(maxDiff, diff); + } + + delayInc = delay << 8; + if (maxDiff != 0) { + delayInc /= maxDiff; + delayInc = MIN(delayInc, 0x7FFF); + } + + delay = delayInc; + for (diff = 1; diff <= maxDiff; ++diff) { + if (delayInc >= 256) + break; + delayInc += delay; + } +} + void Screen_v2::copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src, int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2) { uint8 *dstPtr = getPagePtr(_curPage); @@ -369,7 +393,7 @@ void Screen_v2::wsaFrameAnimationStep(int x1, int y1, int x2, int y2, int t = (nb * h1) / h2; if (t != u) { u = t; - const uint8 *s = src + (x1 + t) * 320; + const uint8 *s = src + x1 + t * 320; uint8 *dt = (uint8 *)_wsaFrameAnimBuffer; t = w2 - w1; diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h index f624228445..3283526ee3 100644 --- a/engines/kyra/screen_v2.h +++ b/engines/kyra/screen_v2.h @@ -44,6 +44,8 @@ public: uint8 *generateOverlay(const uint8 *palette, uint8 *buffer, int color, uint16 factor); void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay); int findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors); + + virtual void getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff); // shape handling uint8 *getPtrToShape(uint8 *shpFile, int shape); -- cgit v1.2.3 From d223e90002d5e95c1dccd14aa81c7090138abbd1 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 27 Jul 2008 13:43:40 +0000 Subject: Inventory icons are now loaded correctly (not yet displayed). BRA doesn't crash anymore when pressing the right button. :) svn-id: r33335 --- engines/parallaction/disk.h | 1 + engines/parallaction/disk_br.cpp | 10 +++++++- engines/parallaction/font.cpp | 43 ++++++++++++++++++++++++++++++++ engines/parallaction/parallaction_br.cpp | 2 +- 4 files changed, 54 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 24f80e1a44..b98e5d0cae 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -211,6 +211,7 @@ protected: Font *createFont(const char *name, Common::ReadStream &stream); Sprites* createSprites(Common::ReadStream &stream); void loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette); + GfxObj* createInventoryObjects(Common::SeekableReadStream &stream); public: DosDisk_br(Parallaction *vm); diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index aec605dbcd..54a1261936 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -237,7 +237,15 @@ Font* DosDisk_br::loadFont(const char* name) { GfxObj* DosDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); - return 0; + + char path[PATH_LEN]; + sprintf(path, "%s/%s", _partPath, name); + + Common::File stream; + if (!stream.open(path)) + errorFileNotFound(path); + + return createInventoryObjects(stream); } void genSlidePath(char *path, const char* name) { diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index 91848b30a4..6b65f19298 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -35,6 +35,7 @@ extern byte _amigaTopazFont[]; class BraFont : public Font { +protected: byte *_cp; uint _bufPitch; @@ -173,6 +174,42 @@ byte BraFont::_charMap[] = { }; +class BraInventoryObjects : public BraFont, public Frames { + +public: + BraInventoryObjects(Common::ReadStream &stream) : BraFont(stream) { + } + + // Frames implementation + uint16 getNum() { + return _numGlyphs; + } + + byte* getData(uint16 index) { + assert(index < _numGlyphs); + return _data + _height * index + _widths[index]; + } + + void getRect(uint16 index, Common::Rect &r) { + assert(index < _numGlyphs); + r.left = 0; + r.top = 0; + r.setWidth(_widths[index]); + r.setHeight(_height); + } + + uint getRawSize(uint16 index) { + assert(index < _numGlyphs); + return _widths[index] * _height; + } + + uint getSize(uint16 index) { + assert(index < _numGlyphs); + return _widths[index] * _height; + } + +}; + class DosFont : public Font { protected: @@ -545,6 +582,12 @@ Font *AmigaDisk_br::createFont(const char *name, Common::SeekableReadStream &str return new AmigaFont(stream); } +GfxObj* DosDisk_br::createInventoryObjects(Common::SeekableReadStream &stream) { + Frames *frames = new BraInventoryObjects(stream); + return new GfxObj(0, frames, "inventoryobjects"); +} + + void Parallaction_ns::initFonts() { if (getPlatform() == Common::kPlatformPC) { diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 04036eb4aa..020dfa6df5 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -174,7 +174,7 @@ void Parallaction_br::initPart() { _objectsNames = _disk->loadTable("objects"); _countersNames = _disk->loadTable("counters"); -// _disk->loadObjects("icone.ico"); + _char._objs = _disk->loadObjects("icone.ico"); } -- cgit v1.2.3 From 387134a16a144df3c9512e8c61901e7b7142e540 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Sun, 27 Jul 2008 14:21:16 +0000 Subject: Moved inventory cursor drawing code to InventoryRenderer. svn-id: r33337 --- engines/parallaction/inventory.cpp | 14 ++++++++++++++ engines/parallaction/inventory.h | 5 +---- engines/parallaction/parallaction_ns.cpp | 12 +----------- 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index 71c336bbab..42db5e50c1 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -38,6 +38,10 @@ namespace Parallaction { // but only 24x24 pixels are actually copied to graphic memory // +#define INVENTORYITEM_PITCH 32 +#define INVENTORYITEM_WIDTH 24 +#define INVENTORYITEM_HEIGHT 24 + #define INVENTORY_MAX_ITEMS 30 #define INVENTORY_FIRST_ITEM 4 // first four entries are used up by verbs @@ -220,6 +224,16 @@ void InventoryRenderer::getItemRect(ItemPosition pos, Common::Rect &r) { } +void InventoryRenderer::drawItem(ItemName name, byte *buffer, uint pitch) { + byte* s = _vm->_char._objs->getData(name); + byte* d = buffer; + for (uint i = 0; i < INVENTORYITEM_HEIGHT; i++) { + memcpy(d, s, INVENTORYITEM_WIDTH); + + s += INVENTORYITEM_PITCH; + d += pitch; + } +} Inventory::Inventory(uint16 maxItems) : _maxItems(maxItems), _numItems(0) { diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h index 8c32c09219..eb96735c91 100644 --- a/engines/parallaction/inventory.h +++ b/engines/parallaction/inventory.h @@ -38,10 +38,6 @@ struct InventoryItem { uint16 _index; // index to frame in objs file }; -#define INVENTORYITEM_PITCH 32 -#define INVENTORYITEM_WIDTH 24 -#define INVENTORYITEM_HEIGHT 24 - #define MAKE_INVENTORY_ID(x) (((x) & 0xFFFF) << 16) typedef int16 ItemPosition; @@ -97,6 +93,7 @@ public: ItemPosition hitTest(const Common::Point &p) const; void highlightItem(ItemPosition pos, byte color); + void drawItem(ItemName name, byte *buffer, uint pitch); byte* getData() const { return (byte*)_surf.pixels; } diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index e8aa32dea7..5b5c9f6871 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -211,18 +211,8 @@ void Parallaction_ns::setInventoryCursor(int pos) { byte *v8 = _mouseComposedArrow->getData(0); // FIXME: destination offseting is not clear - byte* s = _char._objs->getData(item->_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; - } - + _inventoryRenderer->drawItem(item->_index, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH); _system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); - } -- cgit v1.2.3 From 955d0700f55b21e6e70668170869f72ad9746bd7 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Sun, 27 Jul 2008 14:33:37 +0000 Subject: Cut savegame loading into smaller functional parts (resetEngine, loadPlainSave etc). svn-id: r33338 --- engines/cine/cine.h | 2 + engines/cine/various.cpp | 237 ++++++++++++++++++++++++----------------------- 2 files changed, 125 insertions(+), 114 deletions(-) (limited to 'engines') diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 06f2dfd982..20e32b0df7 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -98,6 +98,8 @@ public: private: void initialize(void); + void resetEngine(); + bool loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat); bool makeLoad(char *saveName); void mainLoop(int bootScriptIdx); void readVolCnf(); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index f3b8cc2582..383cda1875 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -408,70 +408,13 @@ void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { overlayList.push_back(tmp); } -/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only - * \todo Add support for loading the zoneQuery table (Operation Stealth specific) - */ -bool CineEngine::makeLoad(char *saveName) { - int16 i; - int16 size; - char bgName[13]; - - Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); - - if (!saveFile) { - drawString(otherMessages[0], 0); - waitPlayerInput(); - // restoreScreen(); - checkDataDisk(-1); - return false; - } - - uint32 saveSize = saveFile->size(); - if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it - // Can't get information about the savefile's size so let's try - // reading as much as we can from the file up to a predefined upper limit. - // - // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each): - // With 256 global scripts, object scripts, overlays and background incrusts: - // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB - // With 512 global scripts, object scripts, overlays and background incrusts: - // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB - // - // I think it extremely unlikely that there would be over 512 global scripts, object scripts, - // overlays and background incrusts so 256kB seems like quite a safe upper limit. - // NOTE: If the savegame format is changed then this value might have to be re-evaluated! - // Hopefully devices with more limited memory can also cope with this memory allocation. - saveSize = 256 * 1024; - } - Common::SharedPtr fHandle(saveFile->readStream(saveSize)); - - // Try to detect the used savegame format - enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*fHandle); - - // Handle problematic savegame formats - if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { - // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but - // that's not implemented here because it was never used in a stable - // release of ScummVM but only during development (From revision 31453, - // which introduced the problem, until revision 32073, which fixed it). - // Therefore be bail out if we detect this particular savegame format. - warning("Detected a known broken savegame format, not loading savegame"); - return false; - } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { - // If we can't detect the savegame format - // then let's try the default format and hope for the best. - warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); - saveGameFormat = ANIMSIZE_30_PTRS_INTACT; - } - // Now we should have either of these formats - assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); - +void CineEngine::resetEngine() { g_sound->stopMusic(); freeAnimDataTable(); overlayList.clear(); - // if (g_cine->getGameType() == Cine::GType_OS) { - // freeUnkList(); - // } + if (g_cine->getGameType() == Cine::GType_OS) { + seqList.clear(); + } bgIncrustList.clear(); closePart(); @@ -481,7 +424,7 @@ bool CineEngine::makeLoad(char *saveName) { scriptTable.clear(); messageTable.clear(); - for (i = 0; i < NUM_MAX_OBJECT; i++) { + for (int i = 0; i < NUM_MAX_OBJECT; i++) { objectTable[i].part = 0; objectTable[i].name[0] = 0; objectTable[i].frame = 0; @@ -514,29 +457,34 @@ bool CineEngine::makeLoad(char *saveName) { renderer->clear(); checkForPendingDataLoadSwitch = 0; +} +bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { + int16 i; + int16 size; + char bgName[13]; // At savefile position 0x0000: - currentDisk = fHandle->readUint16BE(); + currentDisk = in.readUint16BE(); // At 0x0002: - fHandle->read(currentPartName, 13); + in.read(currentPartName, 13); // At 0x000F: - fHandle->read(currentDatName, 13); + in.read(currentDatName, 13); // At 0x001C: - saveVar2 = fHandle->readSint16BE(); + saveVar2 = in.readSint16BE(); // At 0x001E: - fHandle->read(currentPrcName, 13); + in.read(currentPrcName, 13); // At 0x002B: - fHandle->read(currentRelName, 13); + in.read(currentRelName, 13); // At 0x0038: - fHandle->read(currentMsgName, 13); + in.read(currentMsgName, 13); // At 0x0045: - fHandle->read(bgName, 13); + in.read(bgName, 13); // At 0x0052: - fHandle->read(currentCtName, 13); + in.read(currentCtName, 13); checkDataDisk(currentDisk); @@ -561,109 +509,109 @@ bool CineEngine::makeLoad(char *saveName) { } // At 0x005F: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x0061: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x0063: for (i = 0; i < 255; i++) { // At 0x0063 + i * 32 + 0: - objectTable[i].x = fHandle->readSint16BE(); + objectTable[i].x = in.readSint16BE(); // At 0x0063 + i * 32 + 2: - objectTable[i].y = fHandle->readSint16BE(); + objectTable[i].y = in.readSint16BE(); // At 0x0063 + i * 32 + 4: - objectTable[i].mask = fHandle->readUint16BE(); + objectTable[i].mask = in.readUint16BE(); // At 0x0063 + i * 32 + 6: - objectTable[i].frame = fHandle->readSint16BE(); + objectTable[i].frame = in.readSint16BE(); // At 0x0063 + i * 32 + 8: - objectTable[i].costume = fHandle->readSint16BE(); + objectTable[i].costume = in.readSint16BE(); // At 0x0063 + i * 32 + 10: - fHandle->read(objectTable[i].name, 20); + in.read(objectTable[i].name, 20); // At 0x0063 + i * 32 + 30: - objectTable[i].part = fHandle->readUint16BE(); + objectTable[i].part = in.readUint16BE(); } // At 0x2043 (i.e. 0x0063 + 255 * 32): - renderer->restorePalette(*fHandle); + renderer->restorePalette(in); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): - globalVars.load(*fHandle, NUM_MAX_VAR - 1); + globalVars.load(in, NUM_MAX_VAR - 1); // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { // At 0x2281 + i * 2: - zoneData[i] = fHandle->readUint16BE(); + zoneData[i] = in.readUint16BE(); } // At 0x22A1 (i.e. 0x2281 + 16 * 2): for (i = 0; i < 4; i++) { // At 0x22A1 + i * 2: - commandVar3[i] = fHandle->readUint16BE(); + commandVar3[i] = in.readUint16BE(); } // At 0x22A9 (i.e. 0x22A1 + 4 * 2): - fHandle->read(commandBuffer, 0x50); + in.read(commandBuffer, 0x50); renderer->setCommand(commandBuffer); // At 0x22F9 (i.e. 0x22A9 + 0x50): - renderer->_cmdY = fHandle->readUint16BE(); + renderer->_cmdY = in.readUint16BE(); // At 0x22FB: - bgVar0 = fHandle->readUint16BE(); + bgVar0 = in.readUint16BE(); // At 0x22FD: - allowPlayerInput = fHandle->readUint16BE(); + allowPlayerInput = in.readUint16BE(); // At 0x22FF: - playerCommand = fHandle->readSint16BE(); + playerCommand = in.readSint16BE(); // At 0x2301: - commandVar1 = fHandle->readSint16BE(); + commandVar1 = in.readSint16BE(); // At 0x2303: - isDrawCommandEnabled = fHandle->readUint16BE(); + isDrawCommandEnabled = in.readUint16BE(); // At 0x2305: - var5 = fHandle->readUint16BE(); + var5 = in.readUint16BE(); // At 0x2307: - var4 = fHandle->readUint16BE(); + var4 = in.readUint16BE(); // At 0x2309: - var3 = fHandle->readUint16BE(); + var3 = in.readUint16BE(); // At 0x230B: - var2 = fHandle->readUint16BE(); + var2 = in.readUint16BE(); // At 0x230D: - commandVar2 = fHandle->readSint16BE(); + commandVar2 = in.readSint16BE(); // At 0x230F: - renderer->_messageBg = fHandle->readUint16BE(); + renderer->_messageBg = in.readUint16BE(); // At 0x2311: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x2313: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x2315: - loadResourcesFromSave(*fHandle, saveGameFormat); + loadResourcesFromSave(in, saveGameFormat); // TODO: handle screen params (really required ?) - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - - size = fHandle->readSint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + + size = in.readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(*fHandle, true); + loadScriptFromSave(in, true); } - size = fHandle->readSint16BE(); + size = in.readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(*fHandle, false); + loadScriptFromSave(in, false); } - size = fHandle->readSint16BE(); + size = in.readSint16BE(); for (i = 0; i < size; i++) { - loadOverlayFromSave(*fHandle); + loadOverlayFromSave(in); } - loadBgIncrustFromSave(*fHandle); + loadBgIncrustFromSave(in); if (strlen(currentMsgName)) { loadMsg(currentMsgName); @@ -683,6 +631,67 @@ bool CineEngine::makeLoad(char *saveName) { return true; } +/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only + * \todo Add support for loading the zoneQuery table (Operation Stealth specific) + */ +bool CineEngine::makeLoad(char *saveName) { + Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); + + if (!saveFile) { + drawString(otherMessages[0], 0); + waitPlayerInput(); + // restoreScreen(); + checkDataDisk(-1); + return false; + } + + uint32 saveSize = saveFile->size(); + if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it + // Can't get information about the savefile's size so let's try + // reading as much as we can from the file up to a predefined upper limit. + // + // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each): + // With 256 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB + // With 512 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB + // + // I think it extremely unlikely that there would be over 512 global scripts, object scripts, + // overlays and background incrusts so 256kB seems like quite a safe upper limit. + // NOTE: If the savegame format is changed then this value might have to be re-evaluated! + // Hopefully devices with more limited memory can also cope with this memory allocation. + saveSize = 256 * 1024; + } + Common::SharedPtr in(saveFile->readStream(saveSize)); + + // Try to detect the used savegame format + enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*in); + + // Handle problematic savegame formats + if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { + // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but + // that's not implemented here because it was never used in a stable + // release of ScummVM but only during development (From revision 31453, + // which introduced the problem, until revision 32073, which fixed it). + // Therefore be bail out if we detect this particular savegame format. + warning("Detected a known broken savegame format, not loading savegame"); + return false; + } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { + // If we can't detect the savegame format + // then let's try the default format and hope for the best. + warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); + saveGameFormat = ANIMSIZE_30_PTRS_INTACT; + } + // Now we should have either of these formats + assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); + + // Reset the engine's state + resetEngine(); + + // Load the plain Future Wars savegame format + return loadPlainSaveFW(*in, saveGameFormat); +} + /*! \todo Add support for saving the zoneQuery table (Operation Stealth specific) */ void makeSave(char *saveFileName) { -- cgit v1.2.3 From cedbb6b2b23ef5d55c26022b7535cf3d248c5df7 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Sun, 27 Jul 2008 14:36:53 +0000 Subject: Clear the confusing usage of NUM_MAX_VAR (It's 255 actually, not 256). svn-id: r33339 --- engines/cine/object.h | 2 +- engines/cine/various.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/cine/object.h b/engines/cine/object.h index 103b2f50ba..7ad65eb75f 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -50,7 +50,7 @@ struct overlay { }; #define NUM_MAX_OBJECT 255 -#define NUM_MAX_VAR 256 +#define NUM_MAX_VAR 255 extern objectStruct objectTable[NUM_MAX_OBJECT]; diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 383cda1875..4ac4c4a590 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -535,7 +535,7 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor renderer->restorePalette(in); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): - globalVars.load(in, NUM_MAX_VAR - 1); + globalVars.load(in, NUM_MAX_VAR); // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { @@ -733,7 +733,7 @@ void makeSave(char *saveFileName) { renderer->savePalette(*fHandle); - globalVars.save(*fHandle, NUM_MAX_VAR - 1); + globalVars.save(*fHandle, NUM_MAX_VAR); for (i = 0; i < 16; i++) { fHandle->writeUint16BE(zoneData[i]); -- cgit v1.2.3 From 4a245208c093f9587163a9df283d91a440e21379 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 27 Jul 2008 21:14:31 +0000 Subject: Patch from bugreport #2020561: "MMNES : Incorrect detection (US/GB)" svn-id: r33342 --- engines/scumm/scumm-md5.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 62d777aa33..ce8f0a4d9a 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Mon Jun 02 08:37:50 2008 + This file was generated by the md5table tool on Mon Jul 28 00:13:01 2008 DO NOT EDIT MANUALLY! */ @@ -75,7 +75,7 @@ static const MD5Table md5table[] = { { "16effd200aa6b8abe9c569c3e578814d", "freddi4", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "179879b6e35c1ead0d93aab26db0951b", "fbear", "HE 70", "", 13381, Common::EN_ANY, Common::kPlatformWindows }, { "17b5d5e6af4ae89d62631641d66d5a05", "indy3", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformPC }, - { "17f7296f63c78642724f057fd8e736a7", "maniac", "NES", "extracted", -1, Common::EN_USA, Common::kPlatformNES }, + { "17f7296f63c78642724f057fd8e736a7", "maniac", "NES", "extracted", -1, Common::EN_GRB, Common::kPlatformNES }, { "17fa250eb72dae2dad511ba79c0b6b0a", "tentacle", "", "Demo", -1, Common::FR_FRA, Common::kPlatformPC }, { "182344899c2e2998fca0bebcd82aa81a", "atlantis", "", "CD", 12035, Common::EN_ANY, Common::kPlatformPC }, { "183d7464902d40d00800e8ee1f04117c", "maniac", "V2", "V2", 1988, Common::DE_DEU, Common::kPlatformPC }, @@ -149,7 +149,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", "", 262144, Common::EN_GRB, Common::kPlatformNES }, + { "3905799e081b80a61d4460b7b733c206", "maniac", "NES", "", 262144, Common::EN_USA, 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 }, @@ -357,7 +357,7 @@ static const MD5Table md5table[] = { { "90e2f0af4f779629695c6394a65bb702", "spyfox2", "", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "910e31cffb28226bd68c569668a0d6b4", "monkey", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformPC }, { "91469353f7be1b122fa88d23480a1320", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformAmiga }, - { "91d5db93187fab54d823f73bd6441cb6", "maniac", "NES", "extracted", -1, Common::EN_GRB, Common::kPlatformNES }, + { "91d5db93187fab54d823f73bd6441cb6", "maniac", "NES", "extracted", -1, Common::EN_USA, Common::kPlatformNES }, { "927a764615c7fcdd72f591355e089d8c", "monkey", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "92e7727e67f5cd979d8a1070e4eb8cb3", "puttzoo", "HE 98.5", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -503,7 +503,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", "", 262144, Common::EN_USA, Common::kPlatformNES }, + { "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", 262144, Common::EN_GRB, 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 }, -- cgit v1.2.3 From 06a45c49c79056ef6ae81cc9f846ebddf07d03bc Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Sun, 27 Jul 2008 22:50:36 +0000 Subject: Added a preliminary saving routine for Operation Stealth (Disabled by default, needs more work still. WIP!). Added backgrounds' name saving (8 names in Operation Stealth instead of just 1 like in Future Wars). Added 256 color palette saving and restoring (One of the palettes isn't properly handled yet though). svn-id: r33349 --- engines/cine/bg.h | 3 + engines/cine/cine.h | 3 + engines/cine/gfx.cpp | 51 ++++++- engines/cine/gfx.h | 10 +- engines/cine/various.cpp | 371 ++++++++++++++++++++++++++++++++--------------- engines/cine/various.h | 2 +- 6 files changed, 317 insertions(+), 123 deletions(-) (limited to 'engines') diff --git a/engines/cine/bg.h b/engines/cine/bg.h index 5fa8209131..ba3548fa4f 100644 --- a/engines/cine/bg.h +++ b/engines/cine/bg.h @@ -35,6 +35,9 @@ void addBackground(const char *bgName, uint16 bgIdx); extern uint16 bgVar0; +extern byte currentAdditionalBgIdx; +extern byte currentAdditionalBgIdx2; + } // End of namespace Cine #endif diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 20e32b0df7..884520d65f 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -101,6 +101,9 @@ private: void resetEngine(); bool loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat); bool makeLoad(char *saveName); + void makeSaveFW(Common::OutSaveFile &out); + void makeSaveOS(Common::OutSaveFile &out); + void makeSave(char *saveFileName); void mainLoop(int bootScriptIdx); void readVolCnf(); diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index f95794a409..dfff47e969 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -607,7 +607,7 @@ void FWRenderer::removeBg(unsigned int idx) { error("Future Wars renderer doesn't support multiple backgrounds"); } -void FWRenderer::saveBg(Common::OutSaveFile &fHandle) { +void FWRenderer::saveBgNames(Common::OutSaveFile &fHandle) { fHandle.write(_bgName, 13); } @@ -655,6 +655,49 @@ void FWRenderer::savePalette(Common::OutSaveFile &fHandle) { } } +/*! \brief Write active and backup palette to save + * \param fHandle Savefile open for writing + */ +void OSRenderer::savePalette(Common::OutSaveFile &fHandle) { + int i; + + assert(_activeHiPal); + + // Write the active 256 color palette. + for (i = 0; i < _hiPalSize; i++) { + fHandle.writeByte(_activeHiPal[i]); + } + + // Write the active 256 color palette a second time. + // FIXME: The backup 256 color palette should be saved here instead of the active one. + for (i = 0; i < _hiPalSize; i++) { + fHandle.writeByte(_activeHiPal[i]); + } +} + +/*! \brief Restore active and backup palette from save + * \param fHandle Savefile open for reading + */ +void OSRenderer::restorePalette(Common::SeekableReadStream &fHandle) { + int i; + + if (!_activeHiPal) { + _activeHiPal = new byte[_hiPalSize]; + } + + assert(_activeHiPal); + + for (i = 0; i < _hiPalSize; i++) { + _activeHiPal[i] = fHandle.readByte(); + } + + // Jump over the backup 256 color palette. + // FIXME: Load the backup 256 color palette and use it properly. + fHandle.seek(_hiPalSize, SEEK_CUR); + + _changePal = 1; +} + /*! \brief Rotate active palette * \param a First color to rotate * \param b Last color to rotate @@ -1270,6 +1313,12 @@ void OSRenderer::removeBg(unsigned int idx) { memset(_bgTable[idx].name, 0, sizeof (_bgTable[idx].name)); } +void OSRenderer::saveBgNames(Common::OutSaveFile &fHandle) { + for (int i = 0; i < 8; i++) { + fHandle.write(_bgTable[i].name, 13); + } +} + /*! \brief Fade to black * \bug Operation Stealth sometimes seems to fade to black using * transformPalette resulting in double fadeout diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 910a4326e9..d2cdd2ddf6 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -109,12 +109,12 @@ public: virtual void selectScrollBg(unsigned int idx); virtual void setScroll(unsigned int shift); virtual void removeBg(unsigned int idx); - void saveBg(Common::OutSaveFile &fHandle); + virtual void saveBgNames(Common::OutSaveFile &fHandle); virtual void refreshPalette(); virtual void reloadPalette(); - void restorePalette(Common::SeekableReadStream &fHandle); - void savePalette(Common::OutSaveFile &fHandle); + virtual void restorePalette(Common::SeekableReadStream &fHandle); + virtual void savePalette(Common::OutSaveFile &fHandle); virtual void rotatePalette(int a, int b, int c); virtual void transformPalette(int first, int last, int r, int g, int b); @@ -128,6 +128,7 @@ public: */ class OSRenderer : public FWRenderer { private: + // FIXME: Background table's size is probably 8 instead of 9. Check to make sure and correct if necessary. palBg _bgTable[9]; ///< Table of backgrounds loaded into renderer byte *_activeHiPal; ///< Active 256 color palette unsigned int _currentBg; ///< Current background @@ -164,9 +165,12 @@ public: void selectScrollBg(unsigned int idx); void setScroll(unsigned int shift); void removeBg(unsigned int idx); + void saveBgNames(Common::OutSaveFile &fHandle); void refreshPalette(); void reloadPalette(); + void restorePalette(Common::SeekableReadStream &fHandle); + void savePalette(Common::OutSaveFile &fHandle); void rotatePalette(int a, int b, int c); void transformPalette(int first, int last, int r, int g, int b); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 4ac4c4a590..b4bbcc2bb9 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -229,6 +229,129 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { return -1; } +void saveObjectTable(Common::OutSaveFile &out) { + out.writeUint16BE(NUM_MAX_OBJECT); // Entry count + out.writeUint16BE(0x20); // Entry size + + for (int i = 0; i < NUM_MAX_OBJECT; i++) { + out.writeUint16BE(objectTable[i].x); + out.writeUint16BE(objectTable[i].y); + out.writeUint16BE(objectTable[i].mask); + out.writeUint16BE(objectTable[i].frame); + out.writeUint16BE(objectTable[i].costume); + out.write(objectTable[i].name, 20); + out.writeUint16BE(objectTable[i].part); + } +} + +void saveZoneData(Common::OutSaveFile &out) { + for (int i = 0; i < 16; i++) { + out.writeUint16BE(zoneData[i]); + } +} + +void saveCommandVariables(Common::OutSaveFile &out) { + for (int i = 0; i < 4; i++) { + out.writeUint16BE(commandVar3[i]); + } +} + +void saveAnimDataTable(Common::OutSaveFile &out) { + out.writeUint16BE(NUM_MAX_ANIMDATA); // Entry count + out.writeUint16BE(0x1E); // Entry size + + for (int i = 0; i < NUM_MAX_ANIMDATA; i++) { + animDataTable[i].save(out); + } +} + +void saveScreenParams(Common::OutSaveFile &out) { + // Screen parameters, unhandled + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); +} + +void saveGlobalScripts(Common::OutSaveFile &out) { + ScriptList::const_iterator it; + out.writeUint16BE(globalScripts.size()); + for (it = globalScripts.begin(); it != globalScripts.end(); ++it) { + (*it)->save(out); + } +} + +void saveObjectScripts(Common::OutSaveFile &out) { + ScriptList::const_iterator it; + out.writeUint16BE(objectScripts.size()); + for (it = objectScripts.begin(); it != objectScripts.end(); ++it) { + (*it)->save(out); + } +} + +void saveOverlayList(Common::OutSaveFile &out) { + Common::List::const_iterator it; + + out.writeUint16BE(overlayList.size()); + + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + out.writeUint32BE(0); // next + out.writeUint32BE(0); // previous? + out.writeUint16BE(it->objIdx); + out.writeUint16BE(it->type); + out.writeSint16BE(it->x); + out.writeSint16BE(it->y); + out.writeSint16BE(it->width); + out.writeSint16BE(it->color); + } +} + +void saveBgIncrustList(Common::OutSaveFile &out) { + Common::List::const_iterator it; + out.writeUint16BE(bgIncrustList.size()); + + for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { + out.writeUint32BE(0); // next + out.writeUint32BE(0); // previous? + out.writeUint16BE(it->objIdx); + out.writeUint16BE(it->param); + out.writeUint16BE(it->x); + out.writeUint16BE(it->y); + out.writeUint16BE(it->frame); + out.writeUint16BE(it->part); + } +} + +void saveZoneQuery(Common::OutSaveFile &out) { + for (int i = 0; i < 16; i++) { + out.writeUint16BE(zoneQuery[i]); + } +} + +void saveSeqList(Common::OutSaveFile &out) { + Common::List::const_iterator it; + out.writeUint16BE(seqList.size()); + + for (it = seqList.begin(); it != seqList.end(); ++it) { + out.writeSint16BE(it->var4); + out.writeUint16BE(it->objIdx); + out.writeSint16BE(it->var8); + out.writeSint16BE(it->frame); + out.writeSint16BE(it->varC); + out.writeSint16BE(it->varE); + out.writeSint16BE(it->var10); + out.writeSint16BE(it->var12); + out.writeSint16BE(it->var14); + out.writeSint16BE(it->var16); + out.writeSint16BE(it->var18); + out.writeSint16BE(it->var1A); + out.writeSint16BE(it->var1C); + out.writeSint16BE(it->var1E); + } +} + bool CineEngine::loadSaveDirectory(void) { Common::InSaveFile *fHandle; char tmp[80]; @@ -692,134 +815,64 @@ bool CineEngine::makeLoad(char *saveName) { return loadPlainSaveFW(*in, saveGameFormat); } -/*! \todo Add support for saving the zoneQuery table (Operation Stealth specific) - */ -void makeSave(char *saveFileName) { - int16 i; - Common::OutSaveFile *fHandle; +void CineEngine::makeSaveFW(Common::OutSaveFile &out) { + out.writeUint16BE(currentDisk); + out.write(currentPartName, 13); + out.write(currentDatName, 13); + out.writeUint16BE(saveVar2); + out.write(currentPrcName, 13); + out.write(currentRelName, 13); + out.write(currentMsgName, 13); + renderer->saveBgNames(out); + out.write(currentCtName, 13); + + saveObjectTable(out); + renderer->savePalette(out); + globalVars.save(out, NUM_MAX_VAR); + saveZoneData(out); + saveCommandVariables(out); + out.write(commandBuffer, 0x50); + + out.writeUint16BE(renderer->_cmdY); + out.writeUint16BE(bgVar0); + out.writeUint16BE(allowPlayerInput); + out.writeUint16BE(playerCommand); + out.writeUint16BE(commandVar1); + out.writeUint16BE(isDrawCommandEnabled); + out.writeUint16BE(var5); + out.writeUint16BE(var4); + out.writeUint16BE(var3); + out.writeUint16BE(var2); + out.writeUint16BE(commandVar2); + out.writeUint16BE(renderer->_messageBg); + + saveAnimDataTable(out); + saveScreenParams(out); + + saveGlobalScripts(out); + saveObjectScripts(out); + saveOverlayList(out); + saveBgIncrustList(out); +} - fHandle = g_saveFileMan->openForSaving(saveFileName); +void CineEngine::makeSave(char *saveFileName) { + Common::SharedPtr fHandle(g_saveFileMan->openForSaving(saveFileName)); + + setMouseCursor(MOUSE_CURSOR_DISK); if (!fHandle) { drawString(otherMessages[1], 0); waitPlayerInput(); // restoreScreen(); checkDataDisk(-1); - return; - } - - fHandle->writeUint16BE(currentDisk); - fHandle->write(currentPartName, 13); - fHandle->write(currentDatName, 13); - fHandle->writeUint16BE(saveVar2); - fHandle->write(currentPrcName, 13); - fHandle->write(currentRelName, 13); - fHandle->write(currentMsgName, 13); - renderer->saveBg(*fHandle); - fHandle->write(currentCtName, 13); - - fHandle->writeUint16BE(0xFF); - fHandle->writeUint16BE(0x20); - - for (i = 0; i < 255; i++) { - fHandle->writeUint16BE(objectTable[i].x); - fHandle->writeUint16BE(objectTable[i].y); - fHandle->writeUint16BE(objectTable[i].mask); - fHandle->writeUint16BE(objectTable[i].frame); - fHandle->writeUint16BE(objectTable[i].costume); - fHandle->write(objectTable[i].name, 20); - fHandle->writeUint16BE(objectTable[i].part); - } - - renderer->savePalette(*fHandle); - - globalVars.save(*fHandle, NUM_MAX_VAR); - - for (i = 0; i < 16; i++) { - fHandle->writeUint16BE(zoneData[i]); - } - - for (i = 0; i < 4; i++) { - fHandle->writeUint16BE(commandVar3[i]); - } - - fHandle->write(commandBuffer, 0x50); - - fHandle->writeUint16BE(renderer->_cmdY); - - fHandle->writeUint16BE(bgVar0); - fHandle->writeUint16BE(allowPlayerInput); - fHandle->writeUint16BE(playerCommand); - fHandle->writeUint16BE(commandVar1); - fHandle->writeUint16BE(isDrawCommandEnabled); - fHandle->writeUint16BE(var5); - fHandle->writeUint16BE(var4); - fHandle->writeUint16BE(var3); - fHandle->writeUint16BE(var2); - fHandle->writeUint16BE(commandVar2); - - fHandle->writeUint16BE(renderer->_messageBg); - - fHandle->writeUint16BE(0xFF); - fHandle->writeUint16BE(0x1E); - - for (i = 0; i < NUM_MAX_ANIMDATA; i++) { - animDataTable[i].save(*fHandle); - } - - fHandle->writeUint16BE(0); // Screen params, unhandled - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - - { - ScriptList::iterator it; - fHandle->writeUint16BE(globalScripts.size()); - for (it = globalScripts.begin(); it != globalScripts.end(); ++it) { - (*it)->save(*fHandle); - } - - fHandle->writeUint16BE(objectScripts.size()); - for (it = objectScripts.begin(); it != objectScripts.end(); ++it) { - (*it)->save(*fHandle); - } - } - - { - Common::List::iterator it; - - fHandle->writeUint16BE(overlayList.size()); - - for (it = overlayList.begin(); it != overlayList.end(); ++it) { - fHandle->writeUint32BE(0); - fHandle->writeUint32BE(0); - fHandle->writeUint16BE(it->objIdx); - fHandle->writeUint16BE(it->type); - fHandle->writeSint16BE(it->x); - fHandle->writeSint16BE(it->y); - fHandle->writeSint16BE(it->width); - fHandle->writeSint16BE(it->color); + } else { + if (g_cine->getGameType() == GType_FW) { + makeSaveFW(*fHandle); + } else { + makeSaveOS(*fHandle); } } - Common::List::iterator it; - fHandle->writeUint16BE(bgIncrustList.size()); - - for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { - fHandle->writeUint32BE(0); // next - fHandle->writeUint32BE(0); // unkPtr - fHandle->writeUint16BE(it->objIdx); - fHandle->writeUint16BE(it->param); - fHandle->writeUint16BE(it->x); - fHandle->writeUint16BE(it->y); - fHandle->writeUint16BE(it->frame); - fHandle->writeUint16BE(it->part); - } - - delete fHandle; - setMouseCursor(MOUSE_CURSOR_NORMAL); } @@ -960,6 +1013,88 @@ void CineEngine::makeSystemMenu(void) { } } +/** + * Save an Operation Stealth type savegame. WIP! Not yet enabled by default! + * + * TODO: Add some kind of a header to the Operation Stealth's savegame file + * that differentiates it from any of the plain data savegame formats used by + * the already officially supported Future Wars. + * NOTE: This is going to be very much a work in progress so the Operation Stealth's + * savegame formats that are going to be tried are extremely probably not going + * to be supported at all after Operation Stealth becomes officially supported. + * This means that the savegame format will hopefully change to something nicer + * when official support for Operation Stealth begins. + */ +void CineEngine::makeSaveOS(Common::OutSaveFile &out) { + int i; + + // TODO: Enable saving in Operation Stealth after adding a header and possibly some testing + warning("makeSaveOS: Saving in Operation Stealth not yet enabled. Not saving game"); + return; + + out.writeUint16BE(currentDisk); + out.write(currentPartName, 13); + out.write(currentPrcName, 13); + out.write(currentRelName, 13); + out.write(currentMsgName, 13); + renderer->saveBgNames(out); + out.write(currentCtName, 13); + + saveObjectTable(out); + renderer->savePalette(out); + globalVars.save(out, NUM_MAX_VAR); + saveZoneData(out); + saveCommandVariables(out); + out.write(commandBuffer, 0x50); + saveZoneQuery(out); + + // FIXME: Save a proper name here, saving an empty string currently. + // 0x2925: Current music name (String, 13 bytes). + for (i = 0; i < 13; i++) { + out.writeByte(0); + } + // FIXME: Save proper value for this variable, currently writing zero + // 0x2932: Is music loaded? (Uint16BE, Boolean). + out.writeUint16BE(0); + // FIXME: Save proper value for this variable, currently writing zero + // 0x2934: Is music playing? (Uint16BE, Boolean). + out.writeUint16BE(0); + + out.writeUint16BE(renderer->_cmdY); + out.writeUint16BE(0); // Some unknown variable that seems to always be zero + out.writeUint16BE(allowPlayerInput); + out.writeUint16BE(playerCommand); + out.writeUint16BE(commandVar1); + out.writeUint16BE(isDrawCommandEnabled); + out.writeUint16BE(var5); + out.writeUint16BE(var4); + out.writeUint16BE(var3); + out.writeUint16BE(var2); + out.writeUint16BE(commandVar2); + out.writeUint16BE(renderer->_messageBg); + + // FIXME: Save proper value for this variable, currently writing zero. + // An unknown variable at 0x295E: adBgVar1 (Uint16BE). + out.writeUint16BE(0); + out.writeUint16BE(currentAdditionalBgIdx); + out.writeUint16BE(currentAdditionalBgIdx2); + // FIXME: Save proper value for this variable, currently writing zero. + // 0x2954: additionalBgVScroll (Uint16BE). This probably means renderer->_bgShift. + out.writeUint16BE(0); + // FIXME: Save proper value for this variable, currently writing zero. + // An unknown variable at 0x2956: adBgVar0 (Uint16BE). Maybe this means bgVar0? + out.writeUint16BE(0); + out.writeUint16BE(disableSystemMenu); + + saveAnimDataTable(out); + saveScreenParams(out); + saveGlobalScripts(out); + saveObjectScripts(out); + saveSeqList(out); + saveOverlayList(out); + saveBgIncrustList(out); +} + void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte* page) { gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page); // top gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page); // bottom diff --git a/engines/cine/various.h b/engines/cine/various.h index 840f1674a2..d87679ca08 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -44,7 +44,7 @@ extern bool inMenu; struct SeqListElement { int16 var4; - uint16 objIdx; + uint16 objIdx; ///< Is this really unsigned? int16 var8; int16 frame; int16 varC; -- cgit v1.2.3 From 03ffd60054141dfee971232e935cf6d75c737700 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 05:18:23 +0000 Subject: * Changed Disk code in BRA to use FilesystemNode (duplication has become truly visible!). * Fixed Inventory items loading. svn-id: r33352 --- engines/parallaction/disk.h | 37 ++- engines/parallaction/disk_br.cpp | 481 +++++++++++++++++++------------ engines/parallaction/disk_ns.cpp | 3 + engines/parallaction/font.cpp | 6 +- engines/parallaction/parallaction_br.cpp | 7 +- 5 files changed, 343 insertions(+), 191 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index b98e5d0cae..451781d6f1 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -28,6 +28,8 @@ #define PATH_LEN 200 +#include "common/fs.h" + #include "common/file.h" #include "graphics/surface.h" @@ -202,12 +204,25 @@ public: class DosDisk_br : public Disk { protected: + uint16 _language; + Parallaction *_vm; - char _partPath[PATH_LEN]; - char _languageDir[2]; + + FilesystemNode _baseDir; + FilesystemNode _partDir; + + FilesystemNode _aniDir; + FilesystemNode _bkgDir; + FilesystemNode _mscDir; + FilesystemNode _mskDir; + FilesystemNode _pthDir; + FilesystemNode _rasDir; + FilesystemNode _scrDir; + FilesystemNode _sfxDir; + FilesystemNode _talDir; protected: - void errorFileNotFound(const char *s); + void errorFileNotFound(const FilesystemNode &dir, const Common::String &filename); Font *createFont(const char *name, Common::ReadStream &stream); Sprites* createSprites(Common::ReadStream &stream); void loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette); @@ -242,8 +257,17 @@ protected: Sprites* createSprites(Common::ReadStream &stream); Font *createFont(const char *name, Common::SeekableReadStream &stream); - void loadMask(BackgroundInfo& info, const char *name); - void loadBackground(BackgroundInfo& info, const char *name); + void loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream); + void loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream); + + FilesystemNode _baseBkgDir; + FilesystemNode _fntDir; + FilesystemNode _commonAniDir; + FilesystemNode _commonBkgDir; + FilesystemNode _commonMscDir; + FilesystemNode _commonMskDir; + FilesystemNode _commonPthDir; + FilesystemNode _commonTalDir; public: AmigaDisk_br(Parallaction *vm); @@ -255,8 +279,11 @@ public: Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); + GfxObj* AmigaDisk_br::loadObjects(const char *name); Common::SeekableReadStream* loadMusic(const char* name); Common::ReadStream* loadSound(const char* name); + Common::String selectArchive(const Common::String& name); + }; } // namespace Parallaction diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 54a1261936..e354c1cecc 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -25,6 +25,7 @@ #include "graphics/iff.h" +#include "common/config-manager.h" #include "parallaction/parallaction.h" @@ -90,49 +91,40 @@ struct Sprites : public Frames { -void DosDisk_br::errorFileNotFound(const char *s) { - error("File '%s' not found", s); +void DosDisk_br::errorFileNotFound(const FilesystemNode &dir, const Common::String &filename) { + error("File '%s' not found in directory '%s'", filename.c_str(), dir.getDisplayName().c_str()); } Common::String DosDisk_br::selectArchive(const Common::String& name) { debugC(5, kDebugDisk, "DosDisk_br::selectArchive"); - Common::String oldPath(_partPath); - strcpy(_partPath, name.c_str()); + Common::String oldPath; + if (_partDir.exists()) { + oldPath = _partDir.getDisplayName(); + } + + _partDir = _baseDir.getChild(name); + + _aniDir = _partDir.getChild("ani"); + _bkgDir = _partDir.getChild("bkg"); + _mscDir = _partDir.getChild("msc"); + _mskDir = _partDir.getChild("msk"); + _pthDir = _partDir.getChild("pth"); + _rasDir = _partDir.getChild("ras"); + _scrDir = _partDir.getChild("scripts"); + _sfxDir = _partDir.getChild("sfx"); + _talDir = _partDir.getChild("tal"); 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; + assert(language < 4); + _language = language; } -DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) { - +DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm), _baseDir(ConfMan.get("path")) { } DosDisk_br::~DosDisk_br() { @@ -141,45 +133,54 @@ DosDisk_br::~DosDisk_br() { GfxObj* DosDisk_br::loadTalk(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name); - Common::File stream; - - char path[PATH_LEN]; - sprintf(path, "%s/tal/%s", _partPath, name); - if (!stream.open(path)) { - sprintf(path, "%s/tal/%s.tal", _partPath, name); - if (!stream.open(path)) - errorFileNotFound(path); + Common::String path(name); + FilesystemNode node = _talDir.getChild(path); + if (!node.exists()) { + path += ".tal"; + node = _talDir.getChild(path); + if (!node.exists()) + errorFileNotFound(_talDir, path); } + Common::File stream; + stream.open(node); return new GfxObj(0, createSprites(stream), name); } Script* DosDisk_br::loadLocation(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadLocation"); - 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); + Common::String langs[4] = { "it", "fr", "en", "ge" }; + FilesystemNode locDir = _partDir.getChild(langs[_language]); + + Common::String path(name); + path += ".slf"; + FilesystemNode node = locDir.getChild(path); + if (!node.exists()) { + path = Common::String(name) + ".loc"; + node = locDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(locDir, path); + } } + Common::File *stream = new Common::File; + stream->open(node); return new Script(stream, true); } Script* DosDisk_br::loadScript(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadScript"); - Common::File *stream = new Common::File; - - char path[PATH_LEN]; - sprintf(path, "%s/scripts/%s.scr", _partPath, name); - if (!stream->open(path)) - errorFileNotFound(path); + Common::String path(name); + path += ".scr"; + FilesystemNode node = _scrDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_scrDir, path); + } + Common::File *stream = new Common::File; + stream->open(node); return new Script(stream, true); } @@ -208,12 +209,15 @@ void DosDisk_br::loadBitmap(Common::SeekableReadStream &stream, Graphics::Surfac Frames* DosDisk_br::loadPointer(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadPointer"); - char path[PATH_LEN]; - sprintf(path, "%s.ras", name); + Common::String path(name); + path += ".ras"; + FilesystemNode node = _baseDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_baseDir, path); + } Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); + stream.open(node); Graphics::Surface *surf = new Graphics::Surface; loadBitmap(stream, *surf, 0); @@ -224,13 +228,15 @@ Frames* DosDisk_br::loadPointer(const char *name) { Font* DosDisk_br::loadFont(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFont"); - char path[PATH_LEN]; - sprintf(path, "%s.fnt", name); + Common::String path(name); + path += ".fnt"; + FilesystemNode node = _baseDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_baseDir, path); + } Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); - + stream.open(node); return createFont(name, stream); } @@ -238,12 +244,14 @@ Font* DosDisk_br::loadFont(const char* name) { GfxObj* DosDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); - char path[PATH_LEN]; - sprintf(path, "%s/%s", _partPath, name); + Common::String path(name); + FilesystemNode node = _partDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_partDir, path); + } Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); + stream.open(node); return createInventoryObjects(stream); } @@ -255,13 +263,15 @@ void genSlidePath(char *path, const char* name) { GfxObj* DosDisk_br::loadStatic(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadStatic"); - char path[PATH_LEN]; - sprintf(path, "%s/ras/%s", _partPath, name); - Common::File stream; - if (!stream.open(path)) { - errorFileNotFound(path); + Common::String path(name); + FilesystemNode node = _rasDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_rasDir, path); } + Common::File stream; + stream.open(node); + Graphics::Surface *surf = new Graphics::Surface; loadBitmap(stream, *surf, 0); return new GfxObj(0, new SurfaceToFrames(surf), name); @@ -291,17 +301,18 @@ Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) { Frames* DosDisk_br::loadFrames(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); - char path[PATH_LEN]; - sprintf(path, "%s/ani/%s", _partPath, name); - - Common::File stream; - if (!stream.open(path)) { - sprintf(path, "%s/ani/%s.ani", _partPath, name); - if (!stream.open(path)) { - errorFileNotFound(path); + Common::String path(name); + FilesystemNode node = _aniDir.getChild(path); + if (!node.exists()) { + path += ".ani"; + node = _aniDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_aniDir, path); } } + Common::File stream; + stream.open(node); return createSprites(stream); } @@ -313,12 +324,15 @@ Frames* DosDisk_br::loadFrames(const char* name) { void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadSlide"); - char path[PATH_LEN]; - genSlidePath(path, name); + Common::String path(name); + path += ".bmp"; + FilesystemNode node = _baseDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_baseDir, path); + } Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); + stream.open(node); byte rgb[768]; @@ -336,13 +350,17 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) { 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::String filepath; + FilesystemNode node; Common::File stream; if (name) { - sprintf(filename, "%s/bkg/%s.bkg", _partPath, name); - if (!stream.open(filename)) - errorFileNotFound(filename); + filepath = Common::String(name) + ".bkg"; + node = _bkgDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_bkgDir, filepath); + } + stream.open(node); byte rgb[768]; @@ -358,9 +376,12 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char } if (mask) { - sprintf(filename, "%s/msk/%s.msk", _partPath, mask); - if (!stream.open(filename)) - errorFileNotFound(filename); + filepath = Common::String(mask) + ".msk"; + node = _mskDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_mskDir, filepath); + } + stream.open(node); // NOTE: info.width and info.height are only valid if the background graphics // have already been loaded @@ -371,9 +392,12 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char } if (path) { - sprintf(filename, "%s/pth/%s.pth", _partPath, path); - if (!stream.open(filename)) - errorFileNotFound(filename); + filepath = Common::String(path) + ".pth"; + node = _pthDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_pthDir, filepath); + } + stream.open(node); // NOTE: info.width and info.height are only valid if the background graphics // have already been loaded @@ -388,15 +412,16 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char Table* DosDisk_br::loadTable(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadTable"); - char path[PATH_LEN]; - sprintf(path, "%s/%s.tab", _partPath, name); - - Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); + Common::String path(name); + path += ".tab"; + FilesystemNode node = _partDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_partDir, path); + } + Common::File stream; + stream.open(node); Table *t = createTableFromStream(100, stream); - stream.close(); return t; @@ -419,7 +444,17 @@ Common::ReadStream* DosDisk_br::loadSound(const char* name) { AmigaDisk_br::AmigaDisk_br(Parallaction *vm) : DosDisk_br(vm) { + _fntDir = _baseDir.getChild("fonts"); + _baseBkgDir = _baseDir.getChild("backs"); + + FilesystemNode commonDir = _baseDir.getChild("common"); + _commonAniDir = commonDir.getChild("anims"); + _commonBkgDir = commonDir.getChild("backs"); + _commonMscDir = commonDir.getChild("msc"); + _commonMskDir = commonDir.getChild("msk"); + _commonPthDir = commonDir.getChild("pth"); + _commonTalDir = commonDir.getChild("talks"); } @@ -455,19 +490,11 @@ void buildMask2(byte* buf) { } } -void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *name) { - - char path[PATH_LEN]; - sprintf(path, "%s", name); - - Common::File s; - - if (!s.open(path)) - errorFileNotFound(path); +void AmigaDisk_br::loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream) { byte *pal; - Graphics::ILBMDecoder decoder(s, info.bg, pal); + Graphics::ILBMDecoder decoder(stream, info.bg, pal); decoder.decode(); uint i; @@ -491,30 +518,23 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *name) { return; } -void AmigaDisk_br::loadMask(BackgroundInfo& info, const char *name) { - debugC(5, kDebugDisk, "AmigaDisk_br::loadMask(%s)", name); - - Common::File s; - - if (!s.open(name)) - return; - - s.seek(0x30, SEEK_SET); +void AmigaDisk_br::loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream) { + stream.seek(0x30, SEEK_SET); byte r, g, b; for (uint i = 0; i < 4; i++) { - r = s.readByte(); - g = s.readByte(); - b = s.readByte(); + r = stream.readByte(); + g = stream.readByte(); + b = stream.readByte(); info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF; } - s.seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic - Graphics::PackBitsReadStream stream(s); + stream.seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic + Graphics::PackBitsReadStream unpackedStream(stream); info.mask.create(info.width, info.height); - stream.read(info.mask.data, info.mask.size); + unpackedStream.read(info.mask.data, info.mask.size); buildMask2(info.mask.data); return; @@ -523,26 +543,39 @@ void AmigaDisk_br::loadMask(BackgroundInfo& info, const char *name) { void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) { debugC(1, kDebugDisk, "AmigaDisk_br::loadScenery '%s', '%s' '%s'", name, mask, path); - char filename[PATH_LEN]; + Common::String filepath; + FilesystemNode node; Common::File stream; if (name) { - sprintf(filename, "%s/backs/%s.bkg", _partPath, name); - - loadBackground(info, filename); + filepath = Common::String(name) + ".bkg"; + node = _bkgDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_bkgDir, filepath); + } + stream.open(node); + loadBackground(info, stream); + stream.close(); } if (mask) { - sprintf(filename, "%s/msk/%s.msk", _partPath, name); - - loadMask(info, filename); + filepath = Common::String(name) + ".msk"; + node = _mskDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_mskDir, filepath); + } + stream.open(node); + loadMask(info, stream); + stream.close(); } if (path) { - sprintf(filename, "%s/pth/%s.pth", _partPath, path); - if (!stream.open(filename)) - errorFileNotFound(filename); - + filepath = Common::String(name) + ".pth"; + node = _pthDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_pthDir, filepath); + } + stream.open(node); // NOTE: info.width and info.height are only valid if the background graphics // have already been loaded info.path.create(info.width, info.height); @@ -556,22 +589,28 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadSlide '%s'", name); - char path[PATH_LEN]; - sprintf(path, "backs/%s.bkg", name); - - loadBackground(info, path); + Common::String path(name); + path += ".bkg"; + FilesystemNode node = _baseBkgDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_baseBkgDir, path); + } + Common::File stream; + stream.open(node); + loadBackground(info, stream); return; } GfxObj* AmigaDisk_br::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name); - char path[PATH_LEN]; - sprintf(path, "%s/ras/%s", _partPath, name); - Common::File stream; - if (!stream.open(path)) { - errorFileNotFound(path); + Common::String path(name); + FilesystemNode node = _rasDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_rasDir, path); } + Common::File stream; + stream.open(node); byte *pal = 0; Graphics::Surface* surf = new Graphics::Surface; @@ -608,72 +647,103 @@ Sprites* AmigaDisk_br::createSprites(Common::ReadStream &stream) { Frames* AmigaDisk_br::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name); - char path[PATH_LEN]; - sprintf(path, "%s/anims/%s", _partPath, name); - - Common::File stream; - if (!stream.open(path)) { - sprintf(path, "%s/anims/%s.ani", _partPath, name); - if (!stream.open(path)) { - sprintf(path, "common/anims/%s", name); - if (!stream.open(path)) { - sprintf(path, "common/anims/%s.ani", name); - if (!stream.open(path)) { - errorFileNotFound(path); + Common::String path(name); + FilesystemNode node = _aniDir.getChild(path); + if (!node.exists()) { + path += ".ani"; + node = _aniDir.getChild(path); + if (!node.exists()) { + path = Common::String(name); + node = _commonAniDir.getChild(path); + if (!node.exists()) { + path += ".ani"; + node = _commonAniDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_aniDir, path); } } } } + Common::File stream; + stream.open(node); return createSprites(stream); } GfxObj* AmigaDisk_br::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name); - Common::File stream; - - char path[PATH_LEN]; - sprintf(path, "%s/talks/%s", _partPath, name); - if (!stream.open(path)) { - sprintf(path, "%s/talks/%s.tal", _partPath, name); - if (!stream.open(path)) { - sprintf(path, "common/talks/%s", name); - if (!stream.open(path)) { - sprintf(path, "common/talks/%s.tal", name); - if (!stream.open(path)) { - errorFileNotFound(path); + Common::String path(name); + FilesystemNode node = _talDir.getChild(path); + if (!node.exists()) { + path += ".tal"; + node = _talDir.getChild(path); + if (!node.exists()) { + path = Common::String(name); + node = _commonTalDir.getChild(path); + if (!node.exists()) { + path += ".tal"; + node = _commonTalDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_talDir, path); } } } } + Common::File stream; + stream.open(node); return new GfxObj(0, createSprites(stream)); } Font* AmigaDisk_br::loadFont(const char* name) { debugC(1, kDebugDisk, "AmigaFullDisk::loadFont '%s'", name); - char path[PATH_LEN]; - sprintf(path, "%s", name); + Common::String path(name); + path += ".font"; + FilesystemNode node = _fntDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_fntDir, path); + } + + Common::String fontDir; + Common::String fontFile; + byte ch; Common::File stream; - if (!stream.open(path)) - errorFileNotFound(path); + stream.open(node); + stream.seek(4, SEEK_SET); + while ((ch = stream.readByte()) != 0x2F) fontDir += ch; + while ((ch = stream.readByte()) != 0) fontFile += ch; + stream.close(); + + printf("fontDir = %s, fontFile = %s\n", fontDir.c_str(), fontFile.c_str()); + node = _fntDir.getChild(fontDir); + if (!node.exists()) { + errorFileNotFound(_fntDir, fontDir); + } + node = node.getChild(fontFile); + if (!node.exists()) { + errorFileNotFound(node, fontFile); + } + + stream.open(node); return createFont(name, stream); } Common::SeekableReadStream* AmigaDisk_br::loadMusic(const char* name) { debugC(5, kDebugDisk, "AmigaDisk_br::loadMusic"); - char path[PATH_LEN]; - sprintf(path, "%s/msc/%s", _partPath, name); - - Common::File *stream = new Common::File; - if (!stream->open(path)) + Common::String path(name); + FilesystemNode node = _mscDir.getChild(path); + if (!node.exists()) { + // TODO (Kirben): error out when music file is not found? return 0; + } + Common::File *stream = new Common::File; + stream->open(node); return stream; } @@ -681,14 +751,61 @@ Common::SeekableReadStream* AmigaDisk_br::loadMusic(const char* name) { Common::ReadStream* AmigaDisk_br::loadSound(const char* name) { debugC(5, kDebugDisk, "AmigaDisk_br::loadSound"); - char path[PATH_LEN]; - sprintf(path, "%s/sfx/%s", _partPath, name); + Common::String path(name); + FilesystemNode node = _sfxDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_sfxDir, path); + } Common::File *stream = new Common::File; - if (!stream->open(path)) - errorFileNotFound(path); - + stream->open(node); return stream; } +GfxObj* AmigaDisk_br::loadObjects(const char *name) { + debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects"); + + Common::String path(name); + FilesystemNode node = _partDir.getChild(path); + if (!node.exists()) { + errorFileNotFound(_partDir, path); + } + + Common::File stream; + stream.open(node); + + byte *pal = 0; + Graphics::Surface* surf = new Graphics::Surface; + + Graphics::ILBMDecoder decoder(stream, *surf, pal); + decoder.decode(); + + free(pal); + + return new GfxObj(0, new SurfaceToFrames(surf)); +} + +Common::String AmigaDisk_br::selectArchive(const Common::String& name) { + debugC(5, kDebugDisk, "AmigaDisk_br::selectArchive"); + + Common::String oldPath; + if (_partDir.exists()) { + oldPath = _partDir.getDisplayName(); + } + + _partDir = _baseDir.getChild(name); + + _aniDir = _partDir.getChild("anims"); + _bkgDir = _partDir.getChild("backs"); + _mscDir = _partDir.getChild("msc"); + _mskDir = _partDir.getChild("msk"); + _pthDir = _partDir.getChild("pth"); + _rasDir = _partDir.getChild("ras"); + _scrDir = _partDir.getChild("scripts"); + _sfxDir = _partDir.getChild("sfx"); + _talDir = _partDir.getChild("talks"); + + return oldPath; +} + } // namespace Parallaction diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 55e6fc5e77..3c13538c32 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -25,6 +25,9 @@ #include "graphics/iff.h" +#include "common/fs.h" +#include "common/config-manager.h" + #include "parallaction/parallaction.h" diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index 6b65f19298..41fa862400 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -187,7 +187,7 @@ public: byte* getData(uint16 index) { assert(index < _numGlyphs); - return _data + _height * index + _widths[index]; + return _data + (_height * _widths[index]) * index;; } void getRect(uint16 index, Common::Rect &r) { @@ -616,8 +616,8 @@ void Parallaction_br::initFonts() { // fonts/sonya/18 // fonts/vanya/16 - _menuFont = _disk->loadFont("fonts/natasha/16"); - _dialogueFont = _disk->loadFont("fonts/sonya/18"); + _menuFont = _disk->loadFont("natasha"); + _dialogueFont = _disk->loadFont("sonya"); Common::MemoryReadStream stream(_amigaTopazFont, 2600, false); _labelFont = new AmigaFont(stream); } diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 020dfa6df5..18b697fdae 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -174,7 +174,12 @@ void Parallaction_br::initPart() { _objectsNames = _disk->loadTable("objects"); _countersNames = _disk->loadTable("counters"); - _char._objs = _disk->loadObjects("icone.ico"); + // TODO: maybe handle this into Disk + if (getPlatform() == Common::kPlatformPC) { + _char._objs = _disk->loadObjects("icone.ico"); + } else { + _char._objs = _disk->loadObjects("icons.ico"); + } } -- cgit v1.2.3 From 7173aa2e3a564fa36bb84eb73afb4d12e721d924 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 05:21:11 +0000 Subject: Some unneeded references slipped in with the last commit. svn-id: r33353 --- engines/parallaction/disk_ns.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 3c13538c32..55e6fc5e77 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -25,9 +25,6 @@ #include "graphics/iff.h" -#include "common/fs.h" -#include "common/config-manager.h" - #include "parallaction/parallaction.h" -- cgit v1.2.3 From 1d1fc64c663060888347fa4c4efc4402c3f755d2 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Mon, 28 Jul 2008 05:38:24 +0000 Subject: Fix compile. svn-id: r33354 --- engines/parallaction/disk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 451781d6f1..a2a4086a51 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -279,7 +279,7 @@ public: Frames* loadFrames(const char* name); void loadSlide(BackgroundInfo& info, const char *filename); void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path); - GfxObj* AmigaDisk_br::loadObjects(const char *name); + GfxObj* loadObjects(const char *name); Common::SeekableReadStream* loadMusic(const char* name); Common::ReadStream* loadSound(const char* name); Common::String selectArchive(const Common::String& name); -- cgit v1.2.3 From df50b8ee68fd24afcdf4c882d653fbd9d78a3e0e Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 06:06:35 +0000 Subject: Inventory is now properly rendered. Item selection is not yet working. svn-id: r33355 --- engines/parallaction/graphics.cpp | 27 +++++++++ engines/parallaction/graphics.h | 4 ++ engines/parallaction/inventory.cpp | 113 ++++++++++++++++++++++--------------- engines/parallaction/inventory.h | 23 +++++++- 4 files changed, 117 insertions(+), 50 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 7195d1c126..50bf059145 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -153,6 +153,13 @@ void Palette::setEntry(uint index, int red, int green, int blue) { _data[index*3+2] = blue & 0xFF; } +void Palette::getEntry(uint index, int &red, int &green, int &blue) { + assert(index < _colors); + red = _data[index*3]; + green = _data[index*3+1]; + blue = _data[index*3+2]; +} + void Palette::makeGrayscale() { byte v; for (uint16 i = 0; i < _colors; i++) { @@ -797,6 +804,14 @@ Gfx::Gfx(Parallaction* vm) : registerVar("draw_path_zones", 0); + if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) { + // this loads the backup palette needed by the PC version of BRA (see setBackground()). + BackgroundInfo paletteInfo; + _disk->loadSlide(paletteInfo, "pointer"); + _backupPal.clone(paletteInfo.palette); + paletteInfo.free(); + } + return; } @@ -867,6 +882,18 @@ void Gfx::setBackground(uint type, const char* name, const char* mask, const cha if (type == kBackgroundLocation) { _disk->loadScenery(_backgroundInfo, name, mask, path); + + // The PC version of BRA needs the entries 20-31 of the palette to be constant, but + // the background resource files are screwed up. The right colors come from an unused + // bitmap (pointer.bmp). Nothing is known about the Amiga version so far. + if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) { + int r, g, b; + for (uint i = 16; i < 32; i++) { + _backupPal.getEntry(i, r, g, b); + _backgroundInfo.palette.setEntry(i, r, g, b); + } + } + setPalette(_backgroundInfo.palette); _palette.clone(_backgroundInfo.palette); } else { diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index bba2d01d8a..8b00b49ece 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -261,6 +261,7 @@ public: void makeBlack(); void setEntries(byte* data, uint first, uint num); + void getEntry(uint index, int &red, int &green, int &blue); void setEntry(uint index, int red, int green, int blue); void makeGrayscale(); void fadeTo(const Palette& target, uint step); @@ -558,6 +559,9 @@ protected: Common::Point _hbCirclePos; int _hbCircleRadius; + // BRA specific + Palette _backupPal; + // frame data stored in programmable variables int32 _varBackgroundMode; // 1 = normal, 2 = only mask int32 _varScrollX; diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index 42db5e50c1..fc2c9fc3eb 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -37,7 +37,7 @@ namespace Parallaction { // inventory items are stored in cnv files in a 32x24 grid // but only 24x24 pixels are actually copied to graphic memory // - +/* #define INVENTORYITEM_PITCH 32 #define INVENTORYITEM_WIDTH 24 #define INVENTORYITEM_HEIGHT 24 @@ -50,7 +50,31 @@ namespace Parallaction { #define INVENTORY_WIDTH (INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH) #define INVENTORY_HEIGHT (INVENTORY_LINES*INVENTORYITEM_HEIGHT) - +*/ + +InventoryProperties _invProps_NS = { + 32, // INVENTORYITEM_PITCH + 24, // INVENTORYITEM_WIDTH + 24, // INVENTORYITEM_HEIGHT + 30, // INVENTORY_MAX_ITEMS + 4, // INVENTORY_FIRST_ITEM // first four entries are used up by verbs + 5, // INVENTORY_ITEMS_PER_LINE + 6, // INVENTORY_LINES + 5 * 24, // INVENTORY_WIDTH =(INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH) + 6 * 24 // INVENTORY_HEIGHT = (INVENTORY_LINES*INVENTORYITEM_HEIGHT) +}; + +InventoryProperties _invProps_BR = { + 51, // INVENTORYITEM_PITCH + 51, // INVENTORYITEM_WIDTH + 51, // INVENTORYITEM_HEIGHT + 48, // INVENTORY_MAX_ITEMS + 4, // INVENTORY_FIRST_ITEM // first four entries are used up by verbs + 6, // INVENTORY_ITEMS_PER_LINE + 8, // INVENTORY_LINES + 6 * 51, // INVENTORY_WIDTH =(INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH) + 8 * 51 // INVENTORY_HEIGHT = (INVENTORY_LINES*INVENTORYITEM_HEIGHT) +}; int16 Parallaction::getHoverInventoryItem(int16 x, int16 y) { return _inventoryRenderer->hitTest(Common::Point(x,y)); @@ -95,8 +119,16 @@ int16 Parallaction::getInventoryItemIndex(int16 pos) { } void Parallaction::initInventory() { - _inventory = new Inventory(INVENTORY_MAX_ITEMS); - _inventoryRenderer = new InventoryRenderer(this); + InventoryProperties *props; + + if (getGameType() == GType_Nippon) { + props = &_invProps_NS; + } else { + props = &_invProps_BR; + } + + _inventory = new Inventory(props); + _inventoryRenderer = new InventoryRenderer(this, props); _inventoryRenderer->bindInventory(_inventory); } @@ -123,8 +155,8 @@ void Parallaction::closeInventory() { -InventoryRenderer::InventoryRenderer(Parallaction *vm) : _vm(vm) { - _surf.create(INVENTORY_WIDTH, INVENTORY_HEIGHT, 1); +InventoryRenderer::InventoryRenderer(Parallaction *vm, InventoryProperties *props) : _vm(vm), _props(props) { + _surf.create(_props->_width, _props->_height, 1); } InventoryRenderer::~InventoryRenderer() { @@ -135,15 +167,13 @@ void InventoryRenderer::showInventory() { if (!_inv) error("InventoryRenderer not bound to inventory"); -// _engineFlags |= kEngineInventory; - uint16 lines = getNumLines(); Common::Point p; _vm->_input->getCursorPos(p); - _pos.x = CLIP(p.x - (INVENTORY_WIDTH / 2), 0, (int)(_vm->_screenWidth - INVENTORY_WIDTH)); - _pos.y = CLIP(p.y - 2 - (lines * INVENTORYITEM_HEIGHT), 0, (int)(_vm->_screenHeight - lines * INVENTORYITEM_HEIGHT)); + _pos.x = CLIP((int)(p.x - (_props->_width / 2)), 0, (int)(_vm->_screenWidth - _props->_width)); + _pos.y = CLIP((int)(p.y - 2 - (lines * _props->_itemHeight)), 0, (int)(_vm->_screenHeight - lines * _props->_itemHeight)); refresh(); } @@ -154,8 +184,8 @@ void InventoryRenderer::hideInventory() { } void InventoryRenderer::getRect(Common::Rect& r) const { - r.setWidth(INVENTORY_WIDTH); - r.setHeight(INVENTORYITEM_HEIGHT * getNumLines()); + r.setWidth(_props->_width); + r.setHeight(_props->_itemHeight * getNumLines()); r.moveTo(_pos); } @@ -165,35 +195,36 @@ ItemPosition InventoryRenderer::hitTest(const Common::Point &p) const { if (!r.contains(p)) return -1; - return ((p.x - _pos.x) / INVENTORYITEM_WIDTH) + (INVENTORY_ITEMS_PER_LINE * ((p.y - _pos.y) / INVENTORYITEM_HEIGHT)); + return ((p.x - _pos.x) / _props->_itemWidth) + (_props->_itemsPerLine * ((p.y - _pos.y) / _props->_itemHeight)); } - void InventoryRenderer::drawItem(ItemPosition pos, ItemName name) { - Common::Rect r; getItemRect(pos, r); + byte* d = (byte*)_surf.getBasePtr(r.left, r.top); + drawItem(name, d, _surf.pitch); +} - // FIXME: this will end up in a general blit function - +void InventoryRenderer::drawItem(ItemName name, byte *buffer, uint pitch) { byte* s = _vm->_char._objs->getData(name); - byte* d = (byte*)_surf.getBasePtr(r.left, r.top); - for (uint32 i = 0; i < INVENTORYITEM_HEIGHT; i++) { - memcpy(d, s, INVENTORYITEM_WIDTH); + byte* d = buffer; + for (uint i = 0; i < _props->_itemHeight; i++) { + memcpy(d, s, _props->_itemWidth); - d += INVENTORY_WIDTH; - s += INVENTORYITEM_PITCH; + s += _props->_itemPitch; + d += pitch; } } + int16 InventoryRenderer::getNumLines() const { int16 num = _inv->getNumItems(); - return (num / INVENTORY_ITEMS_PER_LINE) + ((num % INVENTORY_ITEMS_PER_LINE) > 0 ? 1 : 0); + return (num / _props->_itemsPerLine) + ((num % _props->_itemsPerLine) > 0 ? 1 : 0); } void InventoryRenderer::refresh() { - for (uint16 i = 0; i < INVENTORY_MAX_ITEMS; i++) { + for (uint16 i = 0; i < _props->_maxItems; i++) { ItemName name = _inv->getItemName(i); drawItem(i, name); } @@ -214,30 +245,18 @@ void InventoryRenderer::highlightItem(ItemPosition pos, byte color) { void InventoryRenderer::getItemRect(ItemPosition pos, Common::Rect &r) { - r.setHeight(INVENTORYITEM_HEIGHT); - r.setWidth(INVENTORYITEM_WIDTH); + r.setHeight(_props->_itemHeight); + r.setWidth(_props->_itemWidth); - uint16 line = pos / INVENTORY_ITEMS_PER_LINE; - uint16 col = pos % INVENTORY_ITEMS_PER_LINE; - - r.moveTo(col * INVENTORYITEM_WIDTH, line * INVENTORYITEM_HEIGHT); - -} + uint16 line = pos / _props->_itemsPerLine; + uint16 col = pos % _props->_itemsPerLine; -void InventoryRenderer::drawItem(ItemName name, byte *buffer, uint pitch) { - byte* s = _vm->_char._objs->getData(name); - byte* d = buffer; - for (uint i = 0; i < INVENTORYITEM_HEIGHT; i++) { - memcpy(d, s, INVENTORYITEM_WIDTH); + r.moveTo(col * _props->_itemWidth, line * _props->_itemHeight); - s += INVENTORYITEM_PITCH; - d += pitch; - } } - -Inventory::Inventory(uint16 maxItems) : _maxItems(maxItems), _numItems(0) { - _items = (InventoryItem*)calloc(_maxItems, sizeof(InventoryItem)); +Inventory::Inventory(InventoryProperties *props) : _numItems(0), _props(props) { + _items = (InventoryItem*)calloc(_props->_maxItems, sizeof(InventoryItem)); addItem(1, kZoneDoor); addItem(3, kZoneExamine); @@ -253,7 +272,7 @@ Inventory::~Inventory() { ItemPosition Inventory::addItem(ItemName name, uint32 value) { debugC(1, kDebugInventory, "addItem(%i, %i)", name, value); - if (_numItems == INVENTORY_MAX_ITEMS) { + if (_numItems == _props->_maxItems) { debugC(3, kDebugInventory, "addItem: inventory is full"); return -1; } @@ -312,9 +331,9 @@ void Inventory::removeItem(ItemName name) { void Inventory::clear(bool keepVerbs) { debugC(1, kDebugInventory, "clearInventory()"); - uint first = (keepVerbs ? INVENTORY_FIRST_ITEM : 0); + uint first = (keepVerbs ? _props->_firstItem : 0); - for (uint16 slot = first; slot < _maxItems; slot++) { + for (uint16 slot = first; slot < _props->_maxItems; slot++) { _items[slot]._id = 0; _items[slot]._index = 0; } @@ -324,7 +343,7 @@ void Inventory::clear(bool keepVerbs) { ItemName Inventory::getItemName(ItemPosition pos) const { - return (pos >= 0 && pos < INVENTORY_MAX_ITEMS) ? _items[pos]._index : 0; + return (pos >= 0 && pos < _props->_maxItems) ? _items[pos]._index : 0; } const InventoryItem* Inventory::getItem(ItemPosition pos) const { diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h index eb96735c91..faa6c24f24 100644 --- a/engines/parallaction/inventory.h +++ b/engines/parallaction/inventory.h @@ -38,6 +38,21 @@ struct InventoryItem { uint16 _index; // index to frame in objs file }; +struct InventoryProperties { + uint _itemPitch; + uint _itemWidth; + uint _itemHeight; + + int _maxItems; + int _firstItem; + + int _itemsPerLine; + int _maxLines; + + int _width; + int _height; +}; + #define MAKE_INVENTORY_ID(x) (((x) & 0xFFFF) << 16) typedef int16 ItemPosition; @@ -47,11 +62,11 @@ class Inventory { protected: InventoryItem *_items; - uint16 _maxItems; uint16 _numItems; + InventoryProperties *_props; public: - Inventory(uint16 maxItems); + Inventory(InventoryProperties *props); virtual ~Inventory(); ItemPosition addItem(ItemName name, uint32 value); @@ -71,6 +86,8 @@ public: class InventoryRenderer { Parallaction *_vm; + InventoryProperties *_props; + Inventory *_inv; Common::Point _pos; @@ -83,7 +100,7 @@ protected: void refresh(); public: - InventoryRenderer(Parallaction *vm); + InventoryRenderer(Parallaction *vm, InventoryProperties *props); virtual ~InventoryRenderer(); void bindInventory(Inventory *inv) { _inv = inv; } -- cgit v1.2.3 From 258f1e8fe630e4323c93c03bbf993307ef652fb5 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Mon, 28 Jul 2008 06:18:39 +0000 Subject: There is no mask or path directories for part0 of BRA (Amiga), so always check whether they exist. svn-id: r33356 --- engines/parallaction/disk_br.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index e354c1cecc..8f2fabf926 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -558,8 +558,8 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha stream.close(); } - if (mask) { - filepath = Common::String(name) + ".msk"; + if (mask && _mskDir.exists()) { + filepath = Common::String(mask) + ".msk"; node = _mskDir.getChild(filepath); if (!node.exists()) { errorFileNotFound(_mskDir, filepath); @@ -569,8 +569,8 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha stream.close(); } - if (path) { - filepath = Common::String(name) + ".pth"; + if (path && _pthDir.exists()) { + filepath = Common::String(path) + ".pth"; node = _pthDir.getChild(filepath); if (!node.exists()) { errorFileNotFound(_pthDir, filepath); -- cgit v1.2.3 From 533dbfd756f744234fdc2942472a61b542530193 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Mon, 28 Jul 2008 07:20:55 +0000 Subject: Add basic support for running Amiga and PC demos of BRA. svn-id: r33357 --- engines/parallaction/detection.cpp | 36 +++++++++++++++++++++++++++++-- engines/parallaction/disk.h | 10 +++++++++ engines/parallaction/disk_br.cpp | 37 ++++++++++++++++++++++++++++++++ engines/parallaction/gfxbase.cpp | 4 ++++ engines/parallaction/parallaction_br.cpp | 18 +++++++++++++--- 5 files changed, 100 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 8841b9ca40..0476b01454 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -154,7 +154,23 @@ static const PARALLACTIONGameDescription gameDescriptions[] = { Common::ADGF_NO_FLAGS }, GType_BRA, - GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT + GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT, + }, + + { + { + "bra", + "Demo", + { + { "russia.fnt", 0, "0dd55251d2886d6783718df2b184bf97", 10649 }, + { NULL, 0, NULL, 0} + }, + Common::UNK_LANG, + Common::kPlatformPC, + Common::ADGF_DEMO + }, + GType_BRA, + GF_LANG_EN | GF_DEMO, }, // TODO: Base the detection of Amiga BRA on actual data file, not executable file. @@ -171,9 +187,25 @@ static const PARALLACTIONGameDescription gameDescriptions[] = { Common::ADGF_NO_FLAGS }, GType_BRA, - GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT + GF_LANG_EN | GF_LANG_FR | GF_LANG_DE | GF_LANG_IT | GF_LANG_MULT, }, + // TODO: Base the detection of Amiga BRA demo on actual data file, not executable file. + { + { + "bra", + "Demo", + { + { "bigred", 0, "b62a7b589fb5e9071f021227640893bf", 97004 }, + { NULL, 0, NULL, 0} + }, + Common::UNK_LANG, + Common::kPlatformAmiga, + Common::ADGF_DEMO + }, + GType_BRA, + GF_LANG_EN | GF_DEMO, + }, { AD_TABLE_END_MARKER, 0, 0 } }; diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index a2a4086a51..ee393afd6a 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -250,6 +250,16 @@ public: Common::ReadStream* loadSound(const char* name); }; +class DosDemo_br : public DosDisk_br { + +public: + DosDemo_br(Parallaction *vm); + virtual ~DosDemo_br(); + + Common::String selectArchive(const Common::String& name); + +}; + class AmigaDisk_br : public DosDisk_br { protected: diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 8f2fabf926..1f77c338c0 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -443,6 +443,43 @@ Common::ReadStream* DosDisk_br::loadSound(const char* name) { +DosDemo_br::DosDemo_br(Parallaction *vm) : DosDisk_br(vm) { + +} + + +DosDemo_br::~DosDemo_br() { + +} + +Common::String DosDemo_br::selectArchive(const Common::String& name) { + debugC(5, kDebugDisk, "DosDemo_br::selectArchive"); + + Common::String oldPath; + if (_partDir.exists()) { + oldPath = _partDir.getDisplayName(); + } + + _partDir = _baseDir; + + _aniDir = _partDir.getChild("ani"); + _bkgDir = _partDir.getChild("bkg"); + _mscDir = _partDir.getChild("msc"); + _mskDir = _partDir.getChild("msk"); + _pthDir = _partDir.getChild("pth"); + _rasDir = _partDir.getChild("ras"); + _scrDir = _partDir.getChild("scripts"); + _sfxDir = _partDir.getChild("sfx"); + _talDir = _partDir.getChild("tal"); + + return oldPath; +} + + + + + + AmigaDisk_br::AmigaDisk_br(Parallaction *vm) : DosDisk_br(vm) { _fntDir = _baseDir.getChild("fonts"); diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index e8250ac8fd..c9892ce2f3 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -204,6 +204,10 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) { void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) { + // TODO: Add support for difference in font data + if (_vm->getGameType() == GType_BRA && _vm->getPlatform() == Common::kPlatformPC && (_vm->getFeatures() & GF_DEMO)) + return; + byte *dst = (byte*)surf->getBasePtr(x, y); font->setColor(color); font->drawString(dst, surf->w, text); diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 18b697fdae..6482329c5e 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -56,7 +56,11 @@ int Parallaction_br::init() { if (getGameType() == GType_BRA) { if (getPlatform() == Common::kPlatformPC) { - _disk = new DosDisk_br(this); + if (getFeatures() & GF_DEMO) { + _disk = new DosDemo_br(this); + } else { + _disk = new DosDisk_br(this); + } _disk->setLanguage(2); // NOTE: language is now hardcoded to English. Original used command-line parameters. _soundMan = new DummySoundMan(this); } else { @@ -109,7 +113,11 @@ void Parallaction_br::callFunction(uint index, void* parm) { int Parallaction_br::go() { - startGui(); + if (getFeatures() & GF_DEMO) { + startPart(1); + } else { + startGui(); + } while ((_engineFlags & kEngineQuit) == 0) { @@ -200,7 +208,11 @@ void Parallaction_br::startPart(uint part) { initPart(); - strcpy(_location._name, partFirstLocation[_part]); + if (getFeatures() & GF_DEMO) { + strcpy(_location._name, "camalb"); + } else { + strcpy(_location._name, partFirstLocation[_part]); + } parseLocation("common"); changeLocation(_location._name); -- cgit v1.2.3 From 8d59006bd7ed3ea00e84649d316139da4fa37408 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 08:25:06 +0000 Subject: Some instrumentation for script debugging. svn-id: r33359 --- engines/parallaction/exec.h | 6 ++---- engines/parallaction/exec_br.cpp | 5 +++-- engines/parallaction/exec_ns.cpp | 5 +++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h index 887d6be526..9ac343dc62 100644 --- a/engines/parallaction/exec.h +++ b/engines/parallaction/exec.h @@ -143,10 +143,6 @@ public: ~CommandExec_br(); }; - - - - class ProgramExec { protected: struct ParallactionStruct2 { @@ -157,6 +153,8 @@ protected: bool suspend; } _ctxt; + const char **_instructionNames; + OpcodeSet _opcodes; uint16 _modCounter; diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index ef671b1e0e..9376aa57ef 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -61,8 +61,6 @@ namespace Parallaction { #define INST_STOP 30 #define INST_ENDSCRIPT 31 - - #define SetOpcodeTable(x) table = &x; typedef Common::Functor0Mem OpcodeV1; @@ -73,6 +71,8 @@ typedef Common::Functor0Mem OpcodeV2; #define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_br::instOp_##op)) #define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_br::instOp_##op() +extern const char *_instructionNamesRes_br[]; + void Parallaction_br::setupSubtitles(char *s, char *s2, int y) { debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y); @@ -602,6 +602,7 @@ void ProgramExec_br::init() { } ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm) { + _instructionNames = _instructionNamesRes_br; } ProgramExec_br::~ProgramExec_br() { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index e596f2e971..fee215289b 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -61,7 +61,7 @@ typedef Common::Functor0Mem OpcodeV2; #define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_ns::instOp_##op)) #define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_ns::instOp_##op() - +extern const char *_instructionNamesRes_ns[]; DECLARE_INSTRUCTION_OPCODE(on) { @@ -394,7 +394,7 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator (*it)->_status = kProgramRunning; - debugC(9, kDebugExec, "Animation: %s, instruction: %i", a->_name, (*inst)->_index); //_instructionNamesRes[(*inst)->_index - 1]); + debugC(9, kDebugExec, "anim: %s, inst[%02i]: %s", a->_name, (*inst)->_index, _instructionNames[(*inst)->_index - 1]); _ctxt.inst = inst; _ctxt.anim = AnimationPtr(a); @@ -755,6 +755,7 @@ void ProgramExec_ns::init() { } ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) { + _instructionNames = _instructionNamesRes_ns; } ProgramExec_ns::~ProgramExec_ns() { -- cgit v1.2.3 From 356adc5e0908e50f8982fb727375d9a08cd01919 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 08:25:52 +0000 Subject: Added support for text in BRA DOS demo. svn-id: r33360 --- engines/parallaction/font.cpp | 93 +++++++++++++++++++++++++++++++++++++--- engines/parallaction/gfxbase.cpp | 4 -- 2 files changed, 87 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index 41fa862400..2a379828ae 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -46,15 +46,15 @@ protected: uint *_offsets; byte *_data; - - static byte _charMap[]; + const byte *_charMap; byte mapChar(byte c) { - return _charMap[c]; + return (_charMap == 0) ? c : _charMap[c]; } public: - BraFont(Common::ReadStream &stream) { + BraFont(Common::ReadStream &stream, const byte *charMap = 0) { + _charMap = charMap; _numGlyphs = stream.readByte(); _height = stream.readUint32BE(); @@ -138,7 +138,7 @@ public: }; -byte BraFont::_charMap[] = { +const byte _braDosFullCharMap[256] = { // 0 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, // 1 @@ -173,6 +173,75 @@ byte BraFont::_charMap[] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; +const byte _braDosDemoComicCharMap[] = { +// 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 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// 9 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// A + 0x34, 0x34, 0x34, 0x34, 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, 0x34, 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 +}; + +const byte _braDosDemoRussiaCharMap[] = { +// 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, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// 3 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// 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 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// 9 + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, +// A + 0x34, 0x34, 0x34, 0x34, 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, 0x34, 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 BraInventoryObjects : public BraFont, public Frames { @@ -574,7 +643,19 @@ Font *AmigaDisk_ns::createFont(const char *name, Common::SeekableReadStream &str Font *DosDisk_br::createFont(const char *name, Common::ReadStream &stream) { // printf("DosDisk_br::createFont(%s)\n", name); - return new BraFont(stream); + Font *font; + + if (_vm->getFeatures() & GF_DEMO) { + if (!scumm_stricmp(name, "russia")) { + font = new BraFont(stream, _braDosDemoRussiaCharMap); + } else { + font = new BraFont(stream, _braDosDemoComicCharMap); + } + } else { + font = new BraFont(stream, _braDosFullCharMap); + } + + return font; } Font *AmigaDisk_br::createFont(const char *name, Common::SeekableReadStream &stream) { diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index c9892ce2f3..e8250ac8fd 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -204,10 +204,6 @@ void Gfx::drawGfxObjects(Graphics::Surface &surf) { void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) { - // TODO: Add support for difference in font data - if (_vm->getGameType() == GType_BRA && _vm->getPlatform() == Common::kPlatformPC && (_vm->getFeatures() & GF_DEMO)) - return; - byte *dst = (byte*)surf->getBasePtr(x, y); font->setColor(color); font->drawString(dst, surf->w, text); -- cgit v1.2.3 From b5a7735ffcad29c533edf22944262c1339d5bf82 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Mon, 28 Jul 2008 08:44:14 +0000 Subject: Correct character name set by character location parser. svn-id: r33361 --- engines/parallaction/parser_br.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 7ed826d9f8..5fc59fcbb9 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -442,7 +442,7 @@ DECLARE_LOCATION_PARSER(redundant) { DECLARE_LOCATION_PARSER(character) { debugC(7, kDebugParser, "LOCATION_PARSER(character) "); - ctxt.characterName = strdup(_tokens[0]); + ctxt.characterName = strdup(_tokens[1]); } -- cgit v1.2.3 From 16fe053ab4535865b7f52a274cc886a682caf7d4 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 08:44:49 +0000 Subject: Made the savegame loading routine choose between loading a Future Wars or an Operation Stealth savegame format. Added a stub for loading the Operation Stealth's temporary savegame format (Not yet implemented). Made mouse cursor change to a disk icon when loading a savegame and back to normal after its done. svn-id: r33362 --- engines/cine/anim.h | 9 ++++++++- engines/cine/cine.h | 1 + engines/cine/various.cpp | 34 +++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 10 deletions(-) (limited to 'engines') diff --git a/engines/cine/anim.h b/engines/cine/anim.h index c04513149c..c3665bf4ce 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -53,12 +53,19 @@ namespace Cine { * but don't try using them for anything else, it won't work. * - Introduced in revision 31444, got broken in revision 31453, * got fixed in revision 32073 and used after that. + * + * TEMP_OS_FORMAT: + * - Temporary Operation Stealth savegame format. + * - NOT backward compatible and NOT to be supported in the future. + * This format should ONLY be used during development and abandoned + * later in favor of a better format! */ enum CineSaveGameFormat { ANIMSIZE_UNKNOWN, ANIMSIZE_23, ANIMSIZE_30_PTRS_BROKEN, - ANIMSIZE_30_PTRS_INTACT + ANIMSIZE_30_PTRS_INTACT, + TEMP_OS_FORMAT }; struct AnimHeaderStruct { diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 884520d65f..eaae555812 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -100,6 +100,7 @@ private: void initialize(void); void resetEngine(); bool loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat); + bool loadTempSaveOS(Common::SeekableReadStream &in); bool makeLoad(char *saveName); void makeSaveFW(Common::OutSaveFile &out); void makeSaveOS(Common::OutSaveFile &out); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index b4bbcc2bb9..6efb441049 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -582,6 +582,11 @@ void CineEngine::resetEngine() { checkForPendingDataLoadSwitch = 0; } +bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { + warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); + return false; +} + bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { int16 i; int16 size; @@ -740,8 +745,6 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor loadMsg(currentMsgName); } - setMouseCursor(MOUSE_CURSOR_NORMAL); - if (strlen(currentDatName)) { /* i = saveVar2; saveVar2 = 0; @@ -768,6 +771,8 @@ bool CineEngine::makeLoad(char *saveName) { return false; } + setMouseCursor(MOUSE_CURSOR_DISK); + uint32 saveSize = saveFile->size(); if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it // Can't get information about the savefile's size so let's try @@ -791,6 +796,8 @@ bool CineEngine::makeLoad(char *saveName) { enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*in); // Handle problematic savegame formats + bool load = true; // Should we try to load the savegame? + bool result = false; if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but // that's not implemented here because it was never used in a stable @@ -798,21 +805,30 @@ bool CineEngine::makeLoad(char *saveName) { // which introduced the problem, until revision 32073, which fixed it). // Therefore be bail out if we detect this particular savegame format. warning("Detected a known broken savegame format, not loading savegame"); - return false; + load = false; // Don't load the savegame } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { // If we can't detect the savegame format // then let's try the default format and hope for the best. warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); saveGameFormat = ANIMSIZE_30_PTRS_INTACT; } - // Now we should have either of these formats - assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); - // Reset the engine's state - resetEngine(); + if (load) { + // Reset the engine's state + resetEngine(); + + if (saveGameFormat == TEMP_OS_FORMAT) { + // Load the temporary Operation Stealth savegame format + result = loadTempSaveOS(*in); + } else { + // Load the plain Future Wars savegame format + result = loadPlainSaveFW(*in, saveGameFormat); + } + } - // Load the plain Future Wars savegame format - return loadPlainSaveFW(*in, saveGameFormat); + setMouseCursor(MOUSE_CURSOR_NORMAL); + + return result; } void CineEngine::makeSaveFW(Common::OutSaveFile &out) { -- cgit v1.2.3 From c6cbf1f144110ab2d754e42032036018768ef9ff Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 08:56:37 +0000 Subject: Added a post processing step to runScripts, so that Animation can be validated after buggy scripts have been executed. svn-id: r33363 --- engines/parallaction/exec_ns.cpp | 33 +++++++++++++++++---------------- engines/parallaction/objects.cpp | 6 ++++++ engines/parallaction/objects.h | 2 ++ 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index fee215289b..11ee829662 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -331,35 +331,34 @@ void Parallaction_ns::drawAnimations() { for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { - AnimationPtr v18 = *it; - GfxObj *obj = v18->gfxobj; + AnimationPtr anim = *it; + GfxObj *obj = anim->gfxobj; - if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) { + if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) { - int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1); - if (v18->_flags & kFlagsNoMasked) + if (anim->_flags & kFlagsNoMasked) layer = 3; else - layer = _gfx->_backgroundInfo.getLayer(v18->_top + v18->height()); + layer = _gfx->_backgroundInfo.getLayer(anim->_top + anim->height()); if (obj) { _gfx->showGfxObj(obj, true); - obj->frame = frame; - obj->x = v18->_left; - obj->y = v18->_top; - obj->z = v18->_z; + obj->frame = anim->_frame; + obj->x = anim->_left; + obj->y = anim->_top; + obj->z = anim->_z; obj->layer = layer; } } - if (((v18->_flags & kFlagsActive) == 0) && (v18->_flags & kFlagsRemove)) { - v18->_flags &= ~kFlagsRemove; - v18->_oldPos.x = -1000; + if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) { + anim->_flags &= ~kFlagsRemove; + anim->_oldPos.x = -1000; } - if ((v18->_flags & kFlagsActive) && (v18->_flags & kFlagsRemove)) { - v18->_flags &= ~kFlagsActive; - v18->_flags |= kFlagsRemove; + if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) { + anim->_flags &= ~kFlagsActive; + anim->_flags |= kFlagsRemove; if (obj) { _gfx->showGfxObj(obj, false); } @@ -416,6 +415,8 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator label1: if (a->_flags & kFlagsCharacter) a->_z = a->_top + a->height(); + + a->validateScriptVars(); } _modCounter++; diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index e04a7d5342..c387484de7 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -81,6 +81,12 @@ byte* Animation::getFrameData(uint32 index) const { return gfxobj->getData(index); } +void Animation::validateScriptVars() { + // this is used to clip values of _frame, _left and _top + // which can be screwed up by buggy scripts. + + _frame = CLIP(_frame, (int16)0, (int16)(getFrameNum() - 1)); +} #define NUM_LOCALS 10 char _localNames[NUM_LOCALS][10]; diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index fd855f9dca..813f83d183 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -448,6 +448,8 @@ struct Animation : public Zone { virtual uint16 height() const; uint16 getFrameNum() const; byte* getFrameData(uint32 index) const; + + void validateScriptVars(); }; class Table { -- cgit v1.2.3 From 5d2e25ee11f15fd36173ce548f4ea06a80054680 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 09:00:00 +0000 Subject: Preliminary code for traps. svn-id: r33364 --- engines/parallaction/objects.h | 1 + engines/parallaction/parser_ns.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'engines') diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index 813f83d183..de740a631e 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -93,6 +93,7 @@ enum ZoneFlags { kFlagsYourself = 0x1000, kFlagsScaled = 0x2000, kFlagsSelfuse = 0x4000, + kFlagsIsAnimation = 0x1000000, // BRA: used in walk code (trap check), to tell is a Zone is an Animation kFlagsAnimLinked = 0x2000000 }; diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index b06eccc81c..88de7bc5f1 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -299,6 +299,7 @@ void LocationParser_ns::parseAnimation(AnimationList &list, char *name) { AnimationPtr a(new Animation); strncpy(a->_name, name, ZONENAME_LENGTH); + a->_flags |= kFlagsIsAnimation; list.push_front(AnimationPtr(a)); -- cgit v1.2.3 From 50088df80fb3fbc421e252f667faab88f73bc6f9 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 10:09:00 +0000 Subject: Now detects temporary Operation Stealth savegame format and saves it. No loading yet. svn-id: r33365 --- engines/cine/anim.h | 15 +++++++++++++++ engines/cine/various.cpp | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/cine/anim.h b/engines/cine/anim.h index c3665bf4ce..b0ce55f7ee 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -26,6 +26,8 @@ #ifndef CINE_ANIM_H #define CINE_ANIM_H +#include "common/endian.h" + namespace Cine { /** @@ -68,6 +70,19 @@ enum CineSaveGameFormat { TEMP_OS_FORMAT }; +/** Identifier for the temporary Operation Stealth savegame format. */ +static const uint32 TEMP_OS_FORMAT_ID = MKID_BE('TEMP'); + +/** The current version number of Operation Stealth's savegame format. */ +static const uint32 CURRENT_OS_SAVE_VER = 0; + +/** Chunk header used by the temporary Operation Stealth savegame format. */ +struct ChunkHeader { + uint32 id; ///< Identifier (e.g. MKID_BE('TEMP')) + uint32 version; ///< Version number + uint32 size; ///< Size of the chunk after this header in bytes +}; + struct AnimHeaderStruct { byte field_0; byte field_1; diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 6efb441049..48155f7d90 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -229,6 +229,20 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { return -1; } +bool writeChunkHeader(Common::OutSaveFile &out, const ChunkHeader &header) { + out.writeUint32BE(header.id); + out.writeUint32BE(header.version); + out.writeUint32BE(header.size); + return !out.ioFailed(); +} + +bool loadChunkHeader(Common::SeekableReadStream &in, ChunkHeader &header) { + header.id = in.readUint32BE(); + header.version = in.readUint32BE(); + header.size = in.readUint32BE(); + return !in.ioFailed(); +} + void saveObjectTable(Common::OutSaveFile &out) { out.writeUint16BE(NUM_MAX_OBJECT); // Entry count out.writeUint16BE(0x20); // Entry size @@ -378,8 +392,23 @@ bool CineEngine::loadSaveDirectory(void) { * algorithm could get confused and think that the file uses both the older * and the newer format but that is such a remote possibility that I wouldn't * worry about it at all. + * + * Also detects the temporary Operation Stealth savegame format now. */ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) { + const uint32 prevStreamPos = fHandle.pos(); + + // First check for the temporary Operation Stealth savegame format. + fHandle.seek(0); + ChunkHeader hdr; + loadChunkHeader(fHandle, hdr); + fHandle.seek(prevStreamPos); + if (hdr.id == TEMP_OS_FORMAT_ID) { + return TEMP_OS_FORMAT; + } + + // Ok, so the savegame isn't using the temporary Operation Stealth savegame format. + // Let's check for the plain Future Wars savegame format and its different versions then. // The animDataTable begins at savefile position 0x2315. // Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443) // and 30 bytes in the save format after that (Revision 31444 and onwards). @@ -388,10 +417,8 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle static const uint animEntriesCount = 255; static const uint oldAnimEntrySize = 23; static const uint newAnimEntrySize = 30; -// static const uint defaultAnimEntrySize = newAnimEntrySize; static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; Common::Array animEntrySizeMatches; - const uint32 prevStreamPos = fHandle.pos(); // Try to walk through the savefile using different animDataTable entry sizes // and make a list of all the successful entry sizes. @@ -774,6 +801,7 @@ bool CineEngine::makeLoad(char *saveName) { setMouseCursor(MOUSE_CURSOR_DISK); uint32 saveSize = saveFile->size(); + // TODO: Evaluate the maximum savegame size for the temporary Operation Stealth savegame format. if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it // Can't get information about the savefile's size so let's try // reading as much as we can from the file up to a predefined upper limit. @@ -1044,10 +1072,14 @@ void CineEngine::makeSystemMenu(void) { void CineEngine::makeSaveOS(Common::OutSaveFile &out) { int i; - // TODO: Enable saving in Operation Stealth after adding a header and possibly some testing - warning("makeSaveOS: Saving in Operation Stealth not yet enabled. Not saving game"); - return; + // Make a temporary Operation Stealth savegame format chunk header and save it. + ChunkHeader header; + header.id = TEMP_OS_FORMAT_ID; + header.version = CURRENT_OS_SAVE_VER; + header.size = 0; // No data is currently put inside the chunk, all the plain data comes right after it. + writeChunkHeader(out, header); + // Start outputting the plain savegame data right after the chunk header. out.writeUint16BE(currentDisk); out.write(currentPartName, 13); out.write(currentPrcName, 13); -- cgit v1.2.3 From c23f805a7fb3870fcf2695d889a09954a010d959 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 10:44:54 +0000 Subject: Cut Future Wars savegame loading routine into parts that can be reused when loading the Operation Stealth savegame format. svn-id: r33366 --- engines/cine/various.cpp | 129 +++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 55 deletions(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 48155f7d90..6dbff06a58 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -609,14 +609,78 @@ void CineEngine::resetEngine() { checkForPendingDataLoadSwitch = 0; } +bool loadObjectTable(Common::SeekableReadStream &in) { + in.readUint16BE(); // Entry count + in.readUint16BE(); // Entry size + + for (int i = 0; i < NUM_MAX_OBJECT; i++) { + objectTable[i].x = in.readSint16BE(); + objectTable[i].y = in.readSint16BE(); + objectTable[i].mask = in.readUint16BE(); + objectTable[i].frame = in.readSint16BE(); + objectTable[i].costume = in.readSint16BE(); + in.read(objectTable[i].name, 20); + objectTable[i].part = in.readUint16BE(); + } + return !in.ioFailed(); +} + +bool loadZoneData(Common::SeekableReadStream &in) { + for (int i = 0; i < 16; i++) { + zoneData[i] = in.readUint16BE(); + } + return !in.ioFailed(); +} + +bool loadCommandVariables(Common::SeekableReadStream &in) { + for (int i = 0; i < 4; i++) { + commandVar3[i] = in.readUint16BE(); + } + return !in.ioFailed(); +} + +bool loadScreenParams(Common::SeekableReadStream &in) { + // TODO: handle screen params (really required ?) + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + return !in.ioFailed(); +} + +bool loadGlobalScripts(Common::SeekableReadStream &in) { + int size = in.readSint16BE(); + for (int i = 0; i < size; i++) { + loadScriptFromSave(in, true); + } + return !in.ioFailed(); +} + +bool loadObjectScripts(Common::SeekableReadStream &in) { + int size = in.readSint16BE(); + for (int i = 0; i < size; i++) { + loadScriptFromSave(in, false); + } + return !in.ioFailed(); +} + +bool loadOverlayList(Common::SeekableReadStream &in) { + int size = in.readSint16BE(); + for (int i = 0; i < size; i++) { + loadOverlayFromSave(in); + } + return !in.ioFailed(); +} + +// TODO: Implement this function bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); return false; } bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { - int16 i; - int16 size; char bgName[13]; // At savefile position 0x0000: @@ -664,45 +728,19 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor } // At 0x005F: - in.readUint16BE(); - // At 0x0061: - in.readUint16BE(); - - // At 0x0063: - for (i = 0; i < 255; i++) { - // At 0x0063 + i * 32 + 0: - objectTable[i].x = in.readSint16BE(); - // At 0x0063 + i * 32 + 2: - objectTable[i].y = in.readSint16BE(); - // At 0x0063 + i * 32 + 4: - objectTable[i].mask = in.readUint16BE(); - // At 0x0063 + i * 32 + 6: - objectTable[i].frame = in.readSint16BE(); - // At 0x0063 + i * 32 + 8: - objectTable[i].costume = in.readSint16BE(); - // At 0x0063 + i * 32 + 10: - in.read(objectTable[i].name, 20); - // At 0x0063 + i * 32 + 30: - objectTable[i].part = in.readUint16BE(); - } + loadObjectTable(in); - // At 0x2043 (i.e. 0x0063 + 255 * 32): + // At 0x2043 (i.e. 0x005F + 2 * 2 + 255 * 32): renderer->restorePalette(in); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): globalVars.load(in, NUM_MAX_VAR); // At 0x2281 (i.e. 0x2083 + 255 * 2): - for (i = 0; i < 16; i++) { - // At 0x2281 + i * 2: - zoneData[i] = in.readUint16BE(); - } + loadZoneData(in); // At 0x22A1 (i.e. 0x2281 + 16 * 2): - for (i = 0; i < 4; i++) { - // At 0x22A1 + i * 2: - commandVar3[i] = in.readUint16BE(); - } + loadCommandVariables(in); // At 0x22A9 (i.e. 0x22A1 + 4 * 2): in.read(commandBuffer, 0x50); @@ -743,29 +781,10 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor // At 0x2315: loadResourcesFromSave(in, saveGameFormat); - // TODO: handle screen params (really required ?) - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - - size = in.readSint16BE(); - for (i = 0; i < size; i++) { - loadScriptFromSave(in, true); - } - - size = in.readSint16BE(); - for (i = 0; i < size; i++) { - loadScriptFromSave(in, false); - } - - size = in.readSint16BE(); - for (i = 0; i < size; i++) { - loadOverlayFromSave(in); - } - + loadScreenParams(in); + loadGlobalScripts(in); + loadObjectScripts(in); + loadOverlayList(in); loadBgIncrustFromSave(in); if (strlen(currentMsgName)) { -- cgit v1.2.3 From b08288c1cd816105636aa628526dba758e886236 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 10:54:53 +0000 Subject: Added remaining load functions needed for the Operation Stealth savegame format loading (loadSeqList and loadZoneQuery). Not used yet. svn-id: r33367 --- engines/cine/various.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 6dbff06a58..02e09be88a 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -674,6 +674,36 @@ bool loadOverlayList(Common::SeekableReadStream &in) { return !in.ioFailed(); } +bool loadSeqList(Common::SeekableReadStream &in) { + uint size = in.readUint16BE(); + SeqListElement tmp; + for (uint i = 0; i < size; i++) { + tmp.var4 = in.readSint16BE(); + tmp.objIdx = in.readUint16BE(); + tmp.var8 = in.readSint16BE(); + tmp.frame = in.readSint16BE(); + tmp.varC = in.readSint16BE(); + tmp.varE = in.readSint16BE(); + tmp.var10 = in.readSint16BE(); + tmp.var12 = in.readSint16BE(); + tmp.var14 = in.readSint16BE(); + tmp.var16 = in.readSint16BE(); + tmp.var18 = in.readSint16BE(); + tmp.var1A = in.readSint16BE(); + tmp.var1C = in.readSint16BE(); + tmp.var1E = in.readSint16BE(); + seqList.push_back(tmp); + } + return !in.ioFailed(); +} + +bool loadZoneQuery(Common::SeekableReadStream &in) { + for (int i = 0; i < 16; i++) { + zoneQuery[i] = in.readUint16BE(); + } + return !in.ioFailed(); +} + // TODO: Implement this function bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); -- cgit v1.2.3 From f4ef55a2e5d3bbbd561c927f6a77e5d21123768a Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 11:47:03 +0000 Subject: Tiny readability aid for parser code. svn-id: r33369 --- engines/parallaction/parser.h | 2 +- engines/parallaction/parser_br.cpp | 4 ++-- engines/parallaction/parser_ns.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index 290a0815c8..488d437deb 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -171,7 +171,7 @@ protected: DECLARE_UNQUALIFIED_COMMAND_PARSER(animation); DECLARE_UNQUALIFIED_COMMAND_PARSER(zone); DECLARE_UNQUALIFIED_COMMAND_PARSER(location); - DECLARE_UNQUALIFIED_COMMAND_PARSER(drop); + DECLARE_UNQUALIFIED_COMMAND_PARSER(invObject); DECLARE_UNQUALIFIED_COMMAND_PARSER(call); DECLARE_UNQUALIFIED_COMMAND_PARSER(simple); DECLARE_UNQUALIFIED_COMMAND_PARSER(move); diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 5fc59fcbb9..3ba2beb288 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -1044,7 +1044,7 @@ void LocationParser_br::init() { COMMAND_PARSER(zone); // off COMMAND_PARSER(call); COMMAND_PARSER(flags); // toggle - COMMAND_PARSER(drop); + COMMAND_PARSER(invObject); // drop COMMAND_PARSER(simple); // quit COMMAND_PARSER(move); COMMAND_PARSER(zone); // stop @@ -1052,7 +1052,7 @@ void LocationParser_br::init() { COMMAND_PARSER(string); // followme COMMAND_PARSER(simple); // onmouse COMMAND_PARSER(simple); // offmouse - COMMAND_PARSER(drop); // add + COMMAND_PARSER(invObject); // add COMMAND_PARSER(zone); // leave COMMAND_PARSER(math); // inc COMMAND_PARSER(math); // dec diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 88de7bc5f1..ad0f714fdc 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -659,7 +659,7 @@ DECLARE_COMMAND_PARSER(location) { } -DECLARE_COMMAND_PARSER(drop) { +DECLARE_COMMAND_PARSER(invObject) { debugC(7, kDebugParser, "COMMAND_PARSER(drop) "); createCommand(_parser->_lookup); @@ -1198,7 +1198,7 @@ void LocationParser_ns::init() { COMMAND_PARSER(zone); // off COMMAND_PARSER(call); // call COMMAND_PARSER(flags); // toggle - COMMAND_PARSER(drop); // drop + COMMAND_PARSER(invObject); // drop COMMAND_PARSER(simple); // quit COMMAND_PARSER(move); // move COMMAND_PARSER(zone); // stop -- cgit v1.2.3 From fb388deb99be4c1457dd052382c32a05dfc4b528 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 11:48:04 +0000 Subject: Implemented opcodes for picking up/dropping/opening/closing items. svn-id: r33370 --- engines/parallaction/exec_br.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 9376aa57ef..69d963dafd 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -122,11 +122,19 @@ DECLARE_COMMAND_OPCODE(location) { DECLARE_COMMAND_OPCODE(open) { warning("Parallaction_br::cmdOp_open command not yet implemented"); + _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed; + if (_ctxt.cmd->u._zone->u.door->gfxobj) { + _vm->updateDoor(_ctxt.cmd->u._zone); + } } DECLARE_COMMAND_OPCODE(close) { warning("Parallaction_br::cmdOp_close not yet implemented"); + _ctxt.cmd->u._zone->_flags |= kFlagsClosed; + if (_ctxt.cmd->u._zone->u.door->gfxobj) { + _vm->updateDoor(_ctxt.cmd->u._zone); + } } @@ -165,7 +173,7 @@ DECLARE_COMMAND_OPCODE(call) { DECLARE_COMMAND_OPCODE(drop) { - warning("Parallaction_br::cmdOp_drop not yet implemented"); + _vm->dropItem(_ctxt.cmd->u._object); } @@ -204,7 +212,7 @@ DECLARE_COMMAND_OPCODE(offmouse) { DECLARE_COMMAND_OPCODE(add) { - warning("Parallaction_br::cmdOp_add not yet implemented"); + _vm->addInventoryItem(_ctxt.cmd->u._object); } -- cgit v1.2.3 From a1557bd776c9335b36313860d437bc8b1ef2a936 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 11:50:36 +0000 Subject: Pick up/drop/open/close actions are now available in game. svn-id: r33371 --- engines/parallaction/input.cpp | 12 ++++-- engines/parallaction/parallaction.cpp | 2 + engines/parallaction/parallaction.h | 10 ++--- engines/parallaction/parallaction_br.cpp | 65 +++++++++++++++++++++++--------- engines/parallaction/parallaction_ns.cpp | 20 +++------- 5 files changed, 67 insertions(+), 42 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 380f766fe0..0e6e135cc3 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -301,13 +301,13 @@ void Input::enterInventoryMode() { void Input::exitInventoryMode() { // right up hides inventory - int item = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + int pos = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); _vm->highlightInventoryItem(-1); // disable if ((_engineFlags & kEngineDragging)) { _engineFlags &= ~kEngineDragging; - ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(item)); + ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(pos)); if (z) { _vm->dropItem(z->u.merge->_obj1); @@ -319,10 +319,14 @@ void Input::exitInventoryMode() { } _vm->closeInventory(); - if (item == -1) { + if (pos == -1) { _vm->setArrowCursor(); } else { - _vm->setInventoryCursor(item); + const InventoryItem *item = _vm->getInventoryItem(pos); + if (item->_index != 0) { + _activeItem._id = item->_id; + _vm->setInventoryCursor(item->_index); + } } _vm->resumeJobs(); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 436cad4ca4..54cb175e46 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -100,6 +100,8 @@ Parallaction::~Parallaction() { cleanupGui(); + delete _comboArrow; + delete _localFlagNames; delete _gfx; delete _soundMan; diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 8d4bb93c97..d8e4da5baf 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -325,6 +325,7 @@ public: Common::RandomSource _rnd; Debugger *_debugger; + Frames *_comboArrow; protected: // data @@ -365,7 +366,7 @@ public: virtual void callFunction(uint index, void* parm) { } virtual void setArrowCursor() = 0; - virtual void setInventoryCursor(int pos) = 0; + virtual void setInventoryCursor(ItemName name) = 0; virtual void parseLocation(const char* name) = 0; @@ -481,7 +482,6 @@ public: typedef void (Parallaction_ns::*Callable)(void*); virtual void callFunction(uint index, void* parm); - void setMousePointer(uint32 value); bool loadGame(); bool saveGame(); @@ -512,7 +512,7 @@ private: void changeCharacter(const char *name); void runPendingZones(); - void setInventoryCursor(int pos); + void setInventoryCursor(ItemName name); void doLoadGame(uint16 slot); @@ -525,7 +525,6 @@ private: static byte _resMouseArrow[256]; byte *_mouseArrow; - Frames *_mouseComposedArrow; static const Callable _dosCallables[25]; static const Callable _amigaCallables[25]; @@ -644,7 +643,7 @@ private: void initFonts(); void freeFonts(); - void setInventoryCursor(int pos); + void setInventoryCursor(ItemName name); void changeLocation(char *location); void runPendingZones(); @@ -652,7 +651,6 @@ private: void initPart(); void freePart(); - void setMousePointer(int16 index); void initCursors(); Frames *_dinoCursor; diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 6482329c5e..efdf0d06b4 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -32,6 +32,27 @@ namespace Parallaction { +struct MouseComboProperties { + int _xOffset; + int _yOffset; + int _width; + int _height; +}; +/* +// TODO: improve NS's handling of normal cursor before merging cursor code. +MouseComboProperties _mouseComboProps_NS = { + 7, // combo x offset (the icon from the inventory will be rendered from here) + 7, // combo y offset (ditto) + 32, // combo (arrow + icon) width + 32 // combo (arrow + icon) height +}; +*/ +MouseComboProperties _mouseComboProps_BR = { + 8, // combo x offset (the icon from the inventory will be rendered from here) + 8, // combo y offset (ditto) + 68, // combo (arrow + icon) width + 68 // combo (arrow + icon) height +}; const char *Parallaction_br::_partNames[] = { "PART0", @@ -103,6 +124,7 @@ Parallaction_br::~Parallaction_br() { delete _dougCursor; delete _donnaCursor; + delete _mouseArrow; } void Parallaction_br::callFunction(uint index, void* parm) { @@ -154,6 +176,12 @@ void Parallaction_br::initCursors() { _dougCursor = _disk->loadPointer("pointer2"); _donnaCursor = _disk->loadPointer("pointer3"); + Graphics::Surface *surf = new Graphics::Surface; + surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); + _comboArrow = new SurfaceToFrames(surf); + + // TODO: choose the pointer depending on the active character + // For now, we pick Donna's _mouseArrow = _donnaCursor; } else { // TODO: Where are the Amiga cursors? @@ -161,19 +189,6 @@ void Parallaction_br::initCursors() { } -void Parallaction_br::setMousePointer(int16 index) { - // FIXME: Where are the Amiga cursors? - if (getPlatform() == Common::kPlatformAmiga) - return; - - Common::Rect r; - _mouseArrow->getRect(0, r); - - _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); - _system->showMouse(true); - -} - void Parallaction_br::initPart() { memset(_counters, 0, ARRAYSIZE(_counters)); @@ -340,15 +355,29 @@ void Parallaction_br::changeCharacter(const char *name) { void Parallaction_br::setArrowCursor() { - // TODO: choose the pointer depending on the active character - // For now, defaults to 0, that corresponds to the default in the original - setMousePointer(0); -} + // FIXME: Where are the Amiga cursors? + if (getPlatform() == Common::kPlatformAmiga) + return; -void Parallaction_br::setInventoryCursor(int pos) { + Common::Rect r; + _mouseArrow->getRect(0, r); + + _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); + _system->showMouse(true); + + _input->_activeItem._id = 0; +} +void Parallaction_br::setInventoryCursor(ItemName name) { + assert(name > 0); + byte *src = _mouseArrow->getData(0); + byte *dst = _comboArrow->getData(0); + memcpy(dst, src, _comboArrow->getSize(0)); + // FIXME: destination offseting is not clear + _inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); + _system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); } } // namespace Parallaction diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 5b5c9f6871..851fe38138 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -34,6 +34,7 @@ namespace Parallaction { + #define MOUSEARROW_WIDTH 16 #define MOUSEARROW_HEIGHT 16 @@ -165,7 +166,6 @@ Parallaction_ns::~Parallaction_ns() { delete _locationParser; delete _programParser; - delete _mouseComposedArrow; _location._animations.remove(_char._ani); @@ -182,7 +182,7 @@ void Parallaction_ns::freeFonts() { } void Parallaction_ns::initCursors() { - _mouseComposedArrow = _disk->loadPointer("pointer"); + _comboArrow = _disk->loadPointer("pointer"); _mouseArrow = _resMouseArrow; } @@ -197,21 +197,13 @@ void Parallaction_ns::setArrowCursor() { _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); } -void Parallaction_ns::setInventoryCursor(int pos) { - - if (pos == -1) - return; - - const InventoryItem *item = getInventoryItem(pos); - if (item->_index == 0) - return; - - _input->_activeItem._id = item->_id; +void Parallaction_ns::setInventoryCursor(ItemName name) { + assert(name > 0); - byte *v8 = _mouseComposedArrow->getData(0); + byte *v8 = _comboArrow->getData(0); // FIXME: destination offseting is not clear - _inventoryRenderer->drawItem(item->_index, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH); + _inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH); _system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); } -- cgit v1.2.3 From b67db7baf5fae6ad24174a4eafd3e5a76566b462 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 28 Jul 2008 12:46:30 +0000 Subject: Cleanup svn-id: r33373 --- engines/saga/font.cpp | 13 +++-- engines/saga/font.h | 3 +- engines/saga/font_map.cpp | 131 +--------------------------------------------- 3 files changed, 14 insertions(+), 133 deletions(-) (limited to 'engines') diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp index 7789949393..482b3a4c82 100644 --- a/engines/saga/font.cpp +++ b/engines/saga/font.cpp @@ -240,6 +240,13 @@ void Font::createOutline(FontData *font) { } } +int Font::translateChar(int charId) { + if (charId <= 127) + return charId; // normal character + else + return _charMap[charId - 128]; // extended character +} + // Returns the horizontal length in pixels of the graphical representation // of at most 'count' characters of the string 'text', taking // into account any formatting options specified by 'flags'. @@ -259,7 +266,7 @@ int Font::getStringWidth(FontId fontId, const char *text, size_t count, FontEffe for (ct = count; *txt && (!count || ct > 0); txt++, ct--) { ch = *txt & 0xFFU; // Translate character - ch = _charMap[ch]; + ch = translateChar(ch); assert(ch < FONT_CHARCOUNT); width += font->normal.fontCharEntry[ch].tracking; } @@ -338,11 +345,11 @@ void Font::outFont(const FontStyle &drawFont, Surface *ds, const char *text, siz // Don't do any special font mapping for the Italian fan // translation of ITE if (_vm->getLanguage() != Common::IT_ITA) - c_code = _charMap[c_code]; + c_code = translateChar(c_code); } } else if (_fontMapping == 1) { // Force font mapping - c_code = _charMap[c_code]; + c_code = translateChar(c_code); } else { // In all other cases, ignore font mapping } diff --git a/engines/saga/font.h b/engines/saga/font.h index 6b930ddca0..76c0f06725 100644 --- a/engines/saga/font.h +++ b/engines/saga/font.h @@ -158,6 +158,7 @@ class Font { }; Font::FontId knownFont2FontIdx(KnownFont font); + int translateChar(int charId); int getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags); int getHeight(FontId fontId, const char *text, int width, FontEffectFlags flags); @@ -196,7 +197,7 @@ class Font { return byteLength; } - static const int _charMap[256]; + static const int _charMap[128]; SagaEngine *_vm; bool _initialized; diff --git a/engines/saga/font_map.cpp b/engines/saga/font_map.cpp index 6246cb71da..6abaeea151 100644 --- a/engines/saga/font_map.cpp +++ b/engines/saga/font_map.cpp @@ -32,135 +32,8 @@ namespace Saga { -const int Font::_charMap[256] = { - 0, // 0 - 1, // 1 - 2, // 2 - 3, // 3 - 4, // 4 - 5, // 5 - 6, // 6 - 7, // 7 - 8, // 8 - 9, // 9 - 10, // 10 - 11, // 11 - 12, // 12 - 13, // 13 - 14, // 14 - 15, // 15 - 16, // 16 - 17, // 17 - 18, // 18 - 19, // 19 - 20, // 20 - 21, // 21 - 22, // 22 - 23, // 23 - 24, // 24 - 25, // 25 - 26, // 26 - 27, // 27 - 28, // 28 - 29, // 29 - 30, // 30 - 31, // 31 - 32, // 32 - 33, // 33 - 34, // 34 - 35, // 35 - 36, // 36 - 37, // 37 - 38, // 38 - 39, // 39 - 40, // 40 - 41, // 41 - 42, // 42 - 43, // 43 - 44, // 44 - 45, // 45 - 46, // 46 - 47, // 47 - 48, // 48 - 49, // 49 - 50, // 50 - 51, // 51 - 52, // 52 - 53, // 53 - 54, // 54 - 55, // 55 - 56, // 56 - 57, // 57 - 58, // 58 - 59, // 59 - 60, // 60 - 61, // 61 - 62, // 62 - 63, // 63 - 64, // 64 - 65, // 65 - 66, // 66 - 67, // 67 - 68, // 68 - 69, // 69 - 70, // 70 - 71, // 71 - 72, // 72 - 73, // 73 - 74, // 74 - 75, // 75 - 76, // 76 - 77, // 77 - 78, // 78 - 79, // 79 - 80, // 80 - 81, // 81 - 82, // 82 - 83, // 83 - 84, // 84 - 85, // 85 - 86, // 86 - 87, // 87 - 88, // 88 - 89, // 89 - 90, // 90 - 91, // 91 - 92, // 92 - 93, // 93 - 94, // 94 - 95, // 95 - 96, // 96 - 97, // 97 - 98, // 98 - 99, // 99 - 100, // 100 - 101, // 101 - 102, // 102 - 103, // 103 - 104, // 104 - 105, // 105 - 106, // 106 - 107, // 107 - 108, // 108 - 109, // 109 - 110, // 110 - 111, // 111 - 112, // 112 - 113, // 113 - 114, // 114 - 115, // 115 - 116, // 116 - 117, // 117 - 118, // 118 - 119, // 119 - 120, // 120 - 121, // 121 - 122, // 122 - 123, // 123 - 124, // 124 - 125, // 125 - 126, // 126 - 127, // 127 +const int Font::_charMap[128] = { + // Characters 0 - 127 are mapped directly to ISO 8859-1 199, // 128 LATIN CAPITAL LETTER C WITH CEDILLA 252, // 129 LATIN SMALL LETTER U WITH DIAERESIS 233, // 130 LATIN SMALL LETTER E WITH ACUTE -- cgit v1.2.3 From a5d225d438d86ab5ccada755773f131e1007f0f5 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 14:02:46 +0000 Subject: Fixed loading of static items. svn-id: r33375 --- engines/parallaction/disk_br.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines') diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 1f77c338c0..34186f52c2 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -193,6 +193,7 @@ GfxObj* DosDisk_br::loadHead(const char* name) { void DosDisk_br::loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette) { stream.skip(4); uint width = stream.readUint32BE(); + if (width & 1) width++; uint height = stream.readUint32BE(); stream.skip(20); -- cgit v1.2.3 From 30d943fe2f18df9677225ab7a92ddc6b2a42062b Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 14:22:44 +0000 Subject: Moved validation step from revision 33363, so that it is executed for all animations. svn-id: r33376 --- engines/parallaction/exec_ns.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 11ee829662..fbfb462f9a 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -334,6 +334,12 @@ void Parallaction_ns::drawAnimations() { AnimationPtr anim = *it; GfxObj *obj = anim->gfxobj; + // Validation is performed here, so that every animation is affected, instead that only the ones + // who *own* a script. In fact, some scripts can change values in other animations. + // The right way to do this would be to enforce validation when any variable is modified from + // a script. + anim->validateScriptVars(); + if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) { if (anim->_flags & kFlagsNoMasked) @@ -415,8 +421,6 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator label1: if (a->_flags & kFlagsCharacter) a->_z = a->_top + a->height(); - - a->validateScriptVars(); } _modCounter++; -- cgit v1.2.3 From ec04a81e81615fed1b10f1887ada097365a97a84 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 14:23:49 +0000 Subject: Yet another hack to deal with labels... Must rethink this crap from scratch. svn-id: r33377 --- engines/parallaction/parallaction_br.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'engines') diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index efdf0d06b4..b5fb2fa3bb 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -265,6 +265,9 @@ void Parallaction_br::changeLocation(char *location) { clearSubtitles(); freeBackground(); _gfx->clearGfxObjects(kGfxObjNormal); + _gfx->freeLabels(); + _subtitle[0] = _subtitle[1] = -1; + _location._programs.clear(); _location._animations.remove(_char._ani); -- cgit v1.2.3 From add07fceaaa2cbbc9e286c420d4bc66c4d17dc36 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 16:02:40 +0000 Subject: Added loading of temporary Operation Stealth savegames. Needs testing! - Music related settings and adBgVar0 & adBgVar1 aren't loaded currently. Modified resetEngine to also reset more of the Operation Stealth specific variables. Added getter for background scrolling value. Changed additional background indices 1 & 2 from byte to uint16. Made savegame loading functions return !in.ioFailed() as return value instead of true as previously. svn-id: r33379 --- engines/cine/bg.cpp | 2 +- engines/cine/bg.h | 4 +- engines/cine/gfx.cpp | 13 ++++ engines/cine/gfx.h | 2 + engines/cine/various.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 162 insertions(+), 19 deletions(-) (limited to 'engines') diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp index c5b7fb4e3d..2a4e7f0ab1 100644 --- a/engines/cine/bg.cpp +++ b/engines/cine/bg.cpp @@ -35,7 +35,7 @@ namespace Cine { uint16 bgVar0; byte *additionalBgTable[9]; -byte currentAdditionalBgIdx = 0, currentAdditionalBgIdx2 = 0; +int16 currentAdditionalBgIdx = 0, currentAdditionalBgIdx2 = 0; byte loadCtFW(const char *ctName) { uint16 header[32]; diff --git a/engines/cine/bg.h b/engines/cine/bg.h index ba3548fa4f..9f97bc467d 100644 --- a/engines/cine/bg.h +++ b/engines/cine/bg.h @@ -35,8 +35,8 @@ void addBackground(const char *bgName, uint16 bgIdx); extern uint16 bgVar0; -extern byte currentAdditionalBgIdx; -extern byte currentAdditionalBgIdx2; +extern int16 currentAdditionalBgIdx; +extern int16 currentAdditionalBgIdx2; } // End of namespace Cine diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index dfff47e969..cbddf0fc59 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -601,6 +601,12 @@ void FWRenderer::setScroll(unsigned int shift) { error("Future Wars renderer doesn't support multiple backgrounds"); } +/*! \brief Future Wars has no scrolling backgrounds so scroll value is always zero. + */ +uint FWRenderer::getScroll() const { + return 0; +} + /*! \brief Placeholder for Operation Stealth implementation */ void FWRenderer::removeBg(unsigned int idx) { @@ -1290,6 +1296,13 @@ void OSRenderer::setScroll(unsigned int shift) { _bgShift = shift; } +/*! \brief Get background scroll + * \return Background scroll in pixels + */ +uint OSRenderer::getScroll() const { + return _bgShift; +} + /*! \brief Unload background from renderer * \param idx Background to unload */ diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index d2cdd2ddf6..6a3aa1ef89 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -108,6 +108,7 @@ public: virtual void selectBg(unsigned int idx); virtual void selectScrollBg(unsigned int idx); virtual void setScroll(unsigned int shift); + virtual uint getScroll() const; virtual void removeBg(unsigned int idx); virtual void saveBgNames(Common::OutSaveFile &fHandle); @@ -164,6 +165,7 @@ public: void selectBg(unsigned int idx); void selectScrollBg(unsigned int idx); void setScroll(unsigned int shift); + uint getScroll() const; void removeBg(unsigned int idx); void saveBgNames(Common::OutSaveFile &fHandle); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 02e09be88a..379b723d2c 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -562,9 +562,6 @@ void CineEngine::resetEngine() { g_sound->stopMusic(); freeAnimDataTable(); overlayList.clear(); - if (g_cine->getGameType() == Cine::GType_OS) { - seqList.clear(); - } bgIncrustList.clear(); closePart(); @@ -607,6 +604,16 @@ void CineEngine::resetEngine() { renderer->clear(); checkForPendingDataLoadSwitch = 0; + + if (g_cine->getGameType() == Cine::GType_OS) { + seqList.clear(); + currentAdditionalBgIdx = 0; + currentAdditionalBgIdx2 = 0; + // TODO: Add resetting of the following variables + // adBgVar1 = 0; + // adBgVar0 = 0; + // gfxFadeOutCompleted = 0; + } } bool loadObjectTable(Common::SeekableReadStream &in) { @@ -704,10 +711,137 @@ bool loadZoneQuery(Common::SeekableReadStream &in) { return !in.ioFailed(); } -// TODO: Implement this function bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { - warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); - return false; + char musicName[13]; + char bgNames[8][13]; + + // First check the temporary Operation Stealth savegame format header. + ChunkHeader hdr; + loadChunkHeader(in, hdr); + if (hdr.id != TEMP_OS_FORMAT_ID) { + warning("loadTempSaveOS: File has incorrect identifier. Not loading savegame"); + return false; + } else if (hdr.version > CURRENT_OS_SAVE_VER) { + warning("loadTempSaveOS: Detected newer format version. Not loading savegame"); + return false; + } else if (hdr.version < CURRENT_OS_SAVE_VER) { + warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break"); + } else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER + debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match)."); + } + + // There shouldn't be any data in the header's chunk currently so it's an error if there is. + if (hdr.size > 0) { + warning("loadTempSaveOS: Format header's chunk seems to contain data so format is incorrect. Not loading savegame"); + return false; + } + + // Ok, so we've got a correct header for a temporary Operation Stealth savegame. + // Let's start loading the plain savegame data then. + currentDisk = in.readUint16BE(); + in.read(currentPartName, 13); + in.read(currentPrcName, 13); + in.read(currentRelName, 13); + in.read(currentMsgName, 13); + + // Load the 8 background names. + for (uint i = 0; i < 8; i++) { + in.read(bgNames[i], 13); + } + + in.read(currentCtName, 13); + + loadObjectTable(in); + renderer->restorePalette(in); + globalVars.load(in, NUM_MAX_VAR); + loadZoneData(in); + loadCommandVariables(in); + in.read(commandBuffer, 0x50); + loadZoneQuery(in); + + // TODO: Use the loaded string (Current music name (String, 13 bytes)). + in.read(musicName, 13); + + // TODO: Use the loaded value (Is music loaded? (Uint16BE, Boolean)). + in.readUint16BE(); + + // TODO: Use the loaded value (Is music playing? (Uint16BE, Boolean)). + in.readUint16BE(); + + renderer->_cmdY = in.readUint16BE(); + in.readUint16BE(); // Some unknown variable that seems to always be zero + allowPlayerInput = in.readUint16BE(); + playerCommand = in.readUint16BE(); + commandVar1 = in.readUint16BE(); + isDrawCommandEnabled = in.readUint16BE(); + var5 = in.readUint16BE(); + var4 = in.readUint16BE(); + var3 = in.readUint16BE(); + var2 = in.readUint16BE(); + commandVar2 = in.readUint16BE(); + renderer->_messageBg = in.readUint16BE(); + + // TODO: Use the loaded value (adBgVar1 (Uint16BE)). + in.readUint16BE(); + + currentAdditionalBgIdx = in.readSint16BE(); + currentAdditionalBgIdx2 = in.readSint16BE(); + + // TODO: Check whether the scroll value really gets used correctly after this. + // Note that the backgrounds are loaded only later than this value is set. + renderer->setScroll(in.readUint16BE()); + + // TODO: Use the loaded value (adBgVar0 (Uint16BE). Maybe this means bgVar0?). + in.readUint16BE(); + + disableSystemMenu = in.readUint16BE(); + + // TODO: adBgVar1 = 1 here + + // Load the animDataTable entries + in.readUint16BE(); // Entry count (255 in the PC version of Operation Stealth). + in.readUint16BE(); // Entry size (36 in the PC version of Operation Stealth). + loadResourcesFromSave(in, ANIMSIZE_30_PTRS_INTACT); + + loadScreenParams(in); + loadGlobalScripts(in); + loadObjectScripts(in); + loadSeqList(in); + loadOverlayList(in); + loadBgIncrustFromSave(in); + + if (strlen(currentPrcName)) { + loadPrc(currentPrcName); + } + + if (strlen(currentRelName)) { + loadRel(currentRelName); + } + + if (strlen(currentMsgName)) { + loadMsg(currentMsgName); + } + + // Load first background (Uses loadBg) + if (strlen(bgNames[0])) { + loadBg(bgNames[0]); + } + + // Add backgrounds 1-7 (Uses addBackground) + for (int i = 1; i < 8; i++) { + if (strlen(bgNames[i])) { + addBackground(bgNames[i], i); + } + } + + if (strlen(currentCtName)) { + loadCtOS(currentCtName); + } + + // TODO: Add current music loading and playing here + // TODO: Palette handling? + + return !in.ioFailed(); } bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { @@ -830,12 +964,9 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor }*/ } - return true; + return !in.ioFailed(); } -/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only - * \todo Add support for loading the zoneQuery table (Operation Stealth specific) - */ bool CineEngine::makeLoad(char *saveName) { Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); @@ -1107,11 +1238,8 @@ void CineEngine::makeSystemMenu(void) { } /** - * Save an Operation Stealth type savegame. WIP! Not yet enabled by default! + * Save an Operation Stealth type savegame. WIP! * - * TODO: Add some kind of a header to the Operation Stealth's savegame file - * that differentiates it from any of the plain data savegame formats used by - * the already officially supported Future Wars. * NOTE: This is going to be very much a work in progress so the Operation Stealth's * savegame formats that are going to be tried are extremely probably not going * to be supported at all after Operation Stealth becomes officially supported. @@ -1173,8 +1301,8 @@ void CineEngine::makeSaveOS(Common::OutSaveFile &out) { // FIXME: Save proper value for this variable, currently writing zero. // An unknown variable at 0x295E: adBgVar1 (Uint16BE). out.writeUint16BE(0); - out.writeUint16BE(currentAdditionalBgIdx); - out.writeUint16BE(currentAdditionalBgIdx2); + out.writeSint16BE(currentAdditionalBgIdx); + out.writeSint16BE(currentAdditionalBgIdx2); // FIXME: Save proper value for this variable, currently writing zero. // 0x2954: additionalBgVScroll (Uint16BE). This probably means renderer->_bgShift. out.writeUint16BE(0); -- cgit v1.2.3 From d2639f0c845b8b1f07a3545868e61c29c067cbca Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 16:46:20 +0000 Subject: Fixed crash when running Operation Stealth introduced in r33339 (There are actually 256 global variables although only 255 of them are saved and loaded from savegames. The last one is VAR_BYPASS_PROTECTION and it is written to in the mainLoop so that's why there was a crash). svn-id: r33380 --- engines/cine/script_fw.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 08d84d480f..6b4ec2790f 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -38,7 +38,13 @@ namespace Cine { -ScriptVars globalVars(NUM_MAX_VAR); +/** + * Global variables. + * 255 of these are saved, but there's one more that's used for bypassing the copy protection. + * In CineEngine::mainLoop(int bootScriptIdx) there's this code: globalVars[VAR_BYPASS_PROTECTION] = 0; + * And as VAR_BYPASS_PROTECTION is 255 that's why we're allocating one more than we otherwise would. + */ +ScriptVars globalVars(NUM_MAX_VAR + 1); uint16 compareVars(int16 a, int16 b); -- cgit v1.2.3 From 09f70b640897b4b36185acd7359e908eb0e3ae7b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 28 Jul 2008 22:21:11 +0000 Subject: Fixing 'warning: comparison of unsigned expression < 0 is always false' svn-id: r33383 --- engines/cine/various.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 379b723d2c..ab181743db 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -724,7 +724,7 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { } else if (hdr.version > CURRENT_OS_SAVE_VER) { warning("loadTempSaveOS: Detected newer format version. Not loading savegame"); return false; - } else if (hdr.version < CURRENT_OS_SAVE_VER) { + } else if ((int)hdr.version < (int)CURRENT_OS_SAVE_VER) { warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break"); } else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match)."); -- cgit v1.2.3 From 7baf727790f0bd9879ae60bb52d703c113875238 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 28 Jul 2008 23:21:03 +0000 Subject: Enforcing use of nullZonePtr only for nulling out pointers, as it is useless for comparisons. svn-id: r33384 --- engines/parallaction/exec_ns.cpp | 2 +- engines/parallaction/input.cpp | 2 +- engines/parallaction/walk.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index fbfb462f9a..e01fdd9d0b 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -487,7 +487,7 @@ CommandExec_ns::~CommandExec_ns() { // void Parallaction::enterCommentMode(ZonePtr z) { - if (z == nullZonePtr) { + if (!z) { return; } diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 0e6e135cc3..287618e803 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -187,7 +187,7 @@ void Input::trackMouse(ZonePtr z) { return; } - if (z == nullZonePtr) { + if (!z) { return; } diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 14d8d080bd..bf8f423fd5 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -400,13 +400,13 @@ void PathBuilder_BR::buildPath(uint16 x, uint16 y) { // look for short circuit cases ZonePtr z0 = _vm->hitZone(kZonePath, x, y); - if (z0 == nullZonePtr) { + if (!z0) { _ch->_walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: corner case 0"); return; } ZonePtr z1 = _vm->hitZone(kZonePath, foot.x, foot.y); - if (z1 == nullZonePtr || z1 == z0) { + if (!z1 || z1 == z0) { _ch->_walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: corner case 1"); return; @@ -444,7 +444,7 @@ void PathWalker_BR::finalizeWalk() { _ch->getFoot(foot); ZonePtr z = _vm->hitZone(kZoneDoor, foot.x, foot.y); - if (z != nullZonePtr && (z->_flags & kFlagsClosed) == 0) { + if (z && ((z->_flags & kFlagsClosed) == 0)) { _vm->_location._startPosition = z->u.door->_startPos; // foot pos _vm->_location._startFrame = z->u.door->_startFrame; -- cgit v1.2.3 From c8400e97251ce8d494bb102f9dd4706ac1dc6b7d Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 29 Jul 2008 03:14:35 +0000 Subject: * Fixed positioning of balloons and faces in BRA (dos, at least). * Adapted loading of faces. svn-id: r33392 --- engines/parallaction/balloons.cpp | 18 +++++++++-------- engines/parallaction/dialogue.cpp | 41 +++++++++++++++++++++++++++++++++------ engines/parallaction/disk_br.cpp | 11 ++++++++++- engines/parallaction/exec_ns.cpp | 39 ++++++++++++++++++++++--------------- 4 files changed, 78 insertions(+), 31 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp index fab92dada9..bda1957e40 100644 --- a/engines/parallaction/balloons.cpp +++ b/engines/parallaction/balloons.cpp @@ -315,11 +315,11 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w Balloon *balloon = &_intBalloons[id]; if (winding == 0) { - src = _leftBalloon; + src = _rightBalloon; srcFrame = 0; } else if (winding == 1) { - src = _rightBalloon; + src = _leftBalloon; srcFrame = 0; } @@ -332,10 +332,12 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); - balloon->obj->x = x; - balloon->obj->y = y; + balloon->obj->x = x + balloon->box.left; + balloon->obj->y = y + balloon->box.top; balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; + printf("balloon (%i, %i)\n", balloon->obj->x, balloon->obj->y); + _numBalloons++; return id; @@ -351,11 +353,11 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC Balloon *balloon = &_intBalloons[id]; if (winding == 0) { - src = _leftBalloon; + src = _rightBalloon; srcFrame = id; } else if (winding == 1) { - src = _rightBalloon; + src = _leftBalloon; srcFrame = 0; } @@ -368,8 +370,8 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); - balloon->obj->x = 0; - balloon->obj->y = 10; + balloon->obj->x = balloon->box.left; + balloon->obj->y = balloon->box.top; balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; if (id > 0) { diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 0d8b933907..21584a0525 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -33,7 +33,7 @@ namespace Parallaction { #define MAX_PASSWORD_LENGTH 7 - +/* #define QUESTION_BALLOON_X 140 #define QUESTION_BALLOON_Y 10 #define QUESTION_CHARACTER_X 190 @@ -41,6 +41,25 @@ namespace Parallaction { #define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_Y 80 +*/ +struct BalloonPositions { + Common::Point _questionBalloon; + Common::Point _questionChar; + + Common::Point _answerChar; +}; + +BalloonPositions _balloonPositions_NS = { + Common::Point(140, 10), + Common::Point(190, 80), + Common::Point(10, 80) +}; + +BalloonPositions _balloonPositions_BR = { + Common::Point(0, 0), + Common::Point(380, 80), + Common::Point(10, 80) +}; class DialogueManager { @@ -78,6 +97,7 @@ class DialogueManager { bool _isKeyDown; uint16 _downKey; + BalloonPositions _ballonPos; public: DialogueManager(Parallaction *vm, ZonePtr z); @@ -112,6 +132,15 @@ protected: }; DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) { + int gtype = vm->getGameType(); + if (gtype == GType_Nippon) { + _ballonPos = _balloonPositions_NS; + } else + if (gtype == GType_BRA) { + _ballonPos = _balloonPositions_BR; + } else + error("unsupported game in DialogueManager"); + _dialogue = _z->u.speak->_dialogue; isNpc = scumm_stricmp(_z->u.speak->_name, "yourself") && _z->u.speak->_name[0] != '\0'; _questioner = isNpc ? _vm->_disk->loadTalk(_z->u.speak->_name) : _vm->_char._talk; @@ -168,16 +197,16 @@ bool DialogueManager::displayAnswers() { if (_askPassword) { resetPassword(); // _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); _vm->_gfx->setItemFrame(id, 0); } else if (_numVisAnswers == 1) { - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); } else if (_numVisAnswers > 1) { - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); _vm->_gfx->setItemFrame(id, _q->_answers[_visAnswers[0]]->_mood & 0xF); _oldSelection = -1; _selection = 0; @@ -189,8 +218,8 @@ bool DialogueManager::displayAnswers() { bool DialogueManager::displayQuestion() { if (!scumm_stricmp(_q->_text, "NULL")) return false; - _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); - int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y); + _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, 0); + int id = _vm->_gfx->setItem(_questioner, _ballonPos._questionChar.x, _ballonPos._questionChar.y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); return true; diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 34186f52c2..4de3048a1f 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -144,7 +144,16 @@ GfxObj* DosDisk_br::loadTalk(const char *name) { Common::File stream; stream.open(node); - return new GfxObj(0, createSprites(stream), name); + + // talk position is set to (0,0), because talks are always displayed at + // absolute coordinates, set in the dialogue manager. The original used + // to null out coordinates every time they were needed. We do it better! + Sprites *spr = createSprites(stream); + for (int i = 0; i < spr->getNum(); i++) { + spr->_sprites[i].x = 0; + spr->_sprites[i].y = 0; + } + return new GfxObj(0, spr, name); } Script* DosDisk_br::loadLocation(const char *name) { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index e01fdd9d0b..60cc2b13f1 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -499,24 +499,31 @@ void Parallaction::enterCommentMode(ZonePtr z) { return; } - int id; + // TODO: move this balloons stuff into DialogueManager and BalloonManager + if (getGameType() == GType_Nippon) { + int id; + if (data->_filename) { + if (data->_cnv == 0) { + data->_cnv = _disk->loadStatic(data->_filename); + } - if (data->_filename) { - if (data->_cnv == 0) { - data->_cnv = _disk->loadStatic(data->_filename); + _gfx->setHalfbriteMode(true); + _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); + Common::Rect r; + data->_cnv->getRect(0, r); + id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); + _gfx->setItemFrame(id, 0); + id = _gfx->setItem(_char._head, 100, 152); + _gfx->setItemFrame(id, 0); + } else { + _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); + id = _gfx->setItem(_char._talk, 190, 80); + _gfx->setItemFrame(id, 0); } - - _gfx->setHalfbriteMode(true); - _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); - Common::Rect r; - data->_cnv->getRect(0, r); - id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); - _gfx->setItemFrame(id, 0); - id = _gfx->setItem(_char._head, 100, 152); - _gfx->setItemFrame(id, 0); - } else { - _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); - id = _gfx->setItem(_char._talk, 190, 80); + } else + if (getGameType() == GType_BRA) { + _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, 0); + int id = _gfx->setItem(_char._talk, 10, 80); _gfx->setItemFrame(id, 0); } -- cgit v1.2.3 From fd40cb43427ea26836e967a866124d74aa854e9a Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Tue, 29 Jul 2008 04:00:07 +0000 Subject: Add check common directories, in loadScenery() for Amiga version of BRA. svn-id: r33393 --- engines/parallaction/disk_br.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 4de3048a1f..a5c5a51306 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -598,7 +598,11 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha filepath = Common::String(name) + ".bkg"; node = _bkgDir.getChild(filepath); if (!node.exists()) { - errorFileNotFound(_bkgDir, filepath); + filepath = Common::String(name) + ".bkg"; + node = _commonBkgDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_bkgDir, filepath); + } } stream.open(node); loadBackground(info, stream); @@ -609,7 +613,11 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha filepath = Common::String(mask) + ".msk"; node = _mskDir.getChild(filepath); if (!node.exists()) { - errorFileNotFound(_mskDir, filepath); + filepath = Common::String(mask) + ".msk"; + node = _commonMskDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_mskDir, filepath); + } } stream.open(node); loadMask(info, stream); @@ -620,7 +628,11 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha filepath = Common::String(path) + ".pth"; node = _pthDir.getChild(filepath); if (!node.exists()) { - errorFileNotFound(_pthDir, filepath); + filepath = Common::String(path) + ".pth"; + node = _commonPthDir.getChild(filepath); + if (!node.exists()) { + errorFileNotFound(_pthDir, filepath); + } } stream.open(node); // NOTE: info.width and info.height are only valid if the background graphics -- cgit v1.2.3 From 598394e5b88f8513b9f5d9ee841e5bc2882f5d6c Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Tue, 29 Jul 2008 04:06:10 +0000 Subject: Mask files don't always exist in Amiga version of BRA, in paricular NULL.msk. svn-id: r33394 --- engines/parallaction/disk_br.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index a5c5a51306..2285c5608e 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -615,13 +615,13 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha if (!node.exists()) { filepath = Common::String(mask) + ".msk"; node = _commonMskDir.getChild(filepath); - if (!node.exists()) { - errorFileNotFound(_mskDir, filepath); - } } - stream.open(node); - loadMask(info, stream); - stream.close(); + + if (node.exists()) { + stream.open(node); + loadMask(info, stream); + stream.close(); + } } if (path && _pthDir.exists()) { -- cgit v1.2.3 From 884b753c7362b25356f427f4f15abe90bf411032 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 29 Jul 2008 09:44:05 +0000 Subject: Added dialogue text rendering for BRA. svn-id: r33402 --- engines/parallaction/balloons.cpp | 287 ++++++++++++++++++++++++++++++++++++-- engines/parallaction/gfxbase.cpp | 57 -------- engines/parallaction/graphics.cpp | 43 ------ engines/parallaction/graphics.h | 2 - 4 files changed, 278 insertions(+), 111 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp index bda1957e40..c7a5fee919 100644 --- a/engines/parallaction/balloons.cpp +++ b/engines/parallaction/balloons.cpp @@ -23,6 +23,8 @@ * */ +#include "common/util.h" + #include "parallaction/graphics.h" #include "parallaction/parallaction.h" @@ -76,6 +78,7 @@ class BalloonManager_ns : public BalloonManager { uint _numBalloons; + void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); Balloon *getBalloon(uint id); @@ -149,12 +152,12 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w int16 w, h; - _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); int id = createBalloon(w+5, h, winding, 1); Balloon *balloon = &_intBalloons[id]; - _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -169,12 +172,12 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC int16 w, h; - _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); int id = createBalloon(w+5, h, winding, 1); Balloon *balloon = &_intBalloons[id]; - _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -193,7 +196,7 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) { Balloon *balloon = getBalloon(id); balloon->surface->fillRect(balloon->innerBox, 1); - _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); } @@ -201,11 +204,11 @@ int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) { int16 w, h; - _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS); Balloon *balloon = &_intBalloons[id]; - _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -242,8 +245,105 @@ void BalloonManager_ns::freeBalloons() { _numBalloons = 0; } +void BalloonManager_ns::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) { + + uint16 lines = 0; + uint16 linewidth = 0; + + uint16 rx = 10; + uint16 ry = 4; + + uint16 blankWidth = font->getStringWidth(" "); + uint16 tokenWidth = 0; + + char token[MAX_TOKEN_LEN]; + + if (wrapwidth == -1) + wrapwidth = _vm->_screenWidth; + while (strlen(text) > 0) { + text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); + + if (!scumm_stricmp(token, "%p")) { + lines++; + rx = 10; + ry = 4 + lines*10; // y + + strcpy(token, "> ......."); + strncpy(token+2, _password, strlen(_password)); + tokenWidth = font->getStringWidth(token); + } else { + tokenWidth = font->getStringWidth(token); + + linewidth += tokenWidth; + + if (linewidth > wrapwidth) { + // wrap line + lines++; + rx = 10; // x + ry = 4 + lines*10; // y + linewidth = tokenWidth; + } + + if (!scumm_stricmp(token, "%s")) { + sprintf(token, "%d", _score); + } + + } + + _gfx->drawText(font, surf, rx, ry, token, color); + + rx += tokenWidth + blankWidth; + linewidth += blankWidth; + + text = Common::ltrim(text); + } + +} + +void BalloonManager_ns::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) { + + uint16 lines = 0; + uint16 w = 0; + *width = 0; + + uint16 blankWidth = font->getStringWidth(" "); + uint16 tokenWidth = 0; + + char token[MAX_TOKEN_LEN]; + + while (strlen(text) != 0) { + + text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); + tokenWidth = font->getStringWidth(token); + + w += tokenWidth; + + if (!scumm_stricmp(token, "%p")) { + lines++; + } else { + if (w > maxwidth) { + w -= tokenWidth; + lines++; + if (w > *width) + *width = w; + + w = tokenWidth; + } + } + + w += blankWidth; + text = Common::ltrim(text); + } + + if (*width < w) *width = w; + *width += 10; + + *height = lines * 10 + 20; + + return; +} @@ -265,11 +365,29 @@ class BalloonManager_br : public BalloonManager { Gfx *_gfx; void cacheAnims(); + void getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); Balloon *getBalloon(uint id); Graphics::Surface *expandBalloon(Frames *data, int frameNum); + void textSetupRendering(const Common::String &text, Graphics::Surface *dest, Font *font, byte color); + void textEmitCenteredLine(); + void textAccum(const Common::String &token, uint16 width); + void textNewLine(); + + Common::String _textLine; + Graphics::Surface *_textSurf; + Font *_textFont; + uint16 _textX, _textY; + byte _textColor; + uint16 _textLines, _textWidth; + + void extentSetup(Font *font, int16 *width, int16 *height); + void extentAction(); + + int16 *_extentWidth, *_extentHeight; + public: BalloonManager_br(Disk *disk, Gfx *gfx); @@ -328,7 +446,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w balloon->surface = expandBalloon(src, srcFrame); src->getRect(srcFrame, balloon->box); -// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -366,7 +484,7 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC balloon->surface = expandBalloon(src, srcFrame); src->getRect(srcFrame, balloon->box); -// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); + drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -436,6 +554,155 @@ void BalloonManager_br::cacheAnims() { } } + +void BalloonManager_br::extentSetup(Font *font, int16 *width, int16 *height) { + _extentWidth = width; + _extentHeight = height; + + _textLine.clear(); + _textLines = 0; + _textWidth = 0; + _textFont = font; +} + +void BalloonManager_br::extentAction() { + if (_textWidth > *_extentWidth) { + *_extentWidth = _textWidth; + } + *_extentHeight = _textLines * _textFont->height(); +} + +void BalloonManager_br::textSetupRendering(const Common::String &text, Graphics::Surface *dest, Font *font, byte color) { + uint16 maxWidth = 216; + + int16 w, h; + getStringExtent(font, text.c_str(), maxWidth, &w, &h); + + w += 10; + h += 12; + + _textLine.clear(); + _textSurf = dest; + _textFont = font; + _textX = 0; + _textY = (_textSurf->h - h) / 2; + _textColor = color; + _textLines = 0; + _textWidth = 0; +} + +void BalloonManager_br::textEmitCenteredLine() { + if (_textLine.empty()) { + return; + } + uint16 rx = _textX + (_textSurf->w - _textWidth) / 2; + uint16 ry = _textY + _textLines * _textFont->height(); // y + _gfx->drawText(_textFont, _textSurf, rx, ry, _textLine.c_str(), _textColor); +} + +void BalloonManager_br::textAccum(const Common::String &token, uint16 width) { + if (token.empty()) { + return; + } + + _textWidth += width; + _textLine += token; +} + +void BalloonManager_br::textNewLine() { + _textLines++; + _textWidth = 0; + _textLine.clear(); +} + + +// TODO: really, base this and getStringExtent on some kind of LineTokenizer, instead of +// repeating the algorithm and changing a couple of lines. +void BalloonManager_br::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapWidth) { + textSetupRendering(text, surf, font, color); + + wrapWidth = 216; + + Common::StringTokenizer tokenizer(text, " "); + Common::String token; + Common::String blank(" "); + + uint16 blankWidth = font->getStringWidth(" "); + uint16 tokenWidth = 0; + + while (!tokenizer.empty()) { + token = tokenizer.nextToken(); + + if (token == '/') { + tokenWidth = 0; + textEmitCenteredLine(); + textNewLine(); + } else { + // todo: expand '%' + tokenWidth = font->getStringWidth(token.c_str()); + + if (_textWidth == 0) { + textAccum(token, tokenWidth); + } else { + if (_textWidth + blankWidth + tokenWidth <= wrapWidth) { + textAccum(blank, blankWidth); + textAccum(token, tokenWidth); + } else { + textEmitCenteredLine(); + textNewLine(); + textAccum(token, tokenWidth); + } + } + } + } + + textEmitCenteredLine(); +} + + + +void BalloonManager_br::getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height) { + extentSetup(font, width, height); + + Common::StringTokenizer tokenizer(text, " "); + Common::String token; + Common::String blank(" "); + + uint16 blankWidth = font->getStringWidth(" "); + uint16 tokenWidth = 0; + + while (!tokenizer.empty()) { + token = tokenizer.nextToken(); + + if (token == '/') { + tokenWidth = 0; + extentAction(); + textNewLine(); + } else { + // todo: expand '%' + tokenWidth = font->getStringWidth(token.c_str()); + + if (_textWidth == 0) { + textAccum(token, tokenWidth); + } else { + if (_textWidth + blankWidth + tokenWidth <= maxwidth) { + textAccum(blank, blankWidth); + textAccum(token, tokenWidth); + } else { + extentAction(); + textNewLine(); + textAccum(token, tokenWidth); + } + } + } + } + + extentAction(); +} + + + + BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) { } @@ -455,4 +722,6 @@ void Parallaction::setupBalloonManager() { } } + + } // namespace Parallaction diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index e8250ac8fd..7c02205e69 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -209,63 +209,6 @@ void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, cons font->drawString(dst, surf->w, text); } -void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) { - - uint16 lines = 0; - uint16 linewidth = 0; - - uint16 rx = 10; - uint16 ry = 4; - - uint16 blankWidth = font->getStringWidth(" "); - uint16 tokenWidth = 0; - - char token[MAX_TOKEN_LEN]; - - if (wrapwidth == -1) - wrapwidth = _vm->_screenWidth; - - while (strlen(text) > 0) { - - text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); - - if (!scumm_stricmp(token, "%p")) { - lines++; - rx = 10; - ry = 4 + lines*10; // y - - strcpy(token, "> ......."); - strncpy(token+2, _password, strlen(_password)); - tokenWidth = font->getStringWidth(token); - } else { - tokenWidth = font->getStringWidth(token); - - linewidth += tokenWidth; - - if (linewidth > wrapwidth) { - // wrap line - lines++; - rx = 10; // x - ry = 4 + lines*10; // y - linewidth = tokenWidth; - } - - if (!scumm_stricmp(token, "%s")) { - sprintf(token, "%d", _score); - } - - } - - drawText(font, surf, rx, ry, token, color); - - rx += tokenWidth + blankWidth; - linewidth += blankWidth; - - text = Common::ltrim(text); - } - -} - #if 0 void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 50bf059145..a31b7f4994 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -707,49 +707,6 @@ void Gfx::drawLabels() { } -void Gfx::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) { - - uint16 lines = 0; - uint16 w = 0; - *width = 0; - - uint16 blankWidth = font->getStringWidth(" "); - uint16 tokenWidth = 0; - - char token[MAX_TOKEN_LEN]; - - while (strlen(text) != 0) { - - text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true); - tokenWidth = font->getStringWidth(token); - - w += tokenWidth; - - if (!scumm_stricmp(token, "%p")) { - lines++; - } else { - if (w > maxwidth) { - w -= tokenWidth; - lines++; - if (w > *width) - *width = w; - - w = tokenWidth; - } - } - - w += blankWidth; - text = Common::ltrim(text); - } - - if (*width < w) *width = w; - *width += 10; - - *height = lines * 10 + 20; - - return; -} - void Gfx::copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst) { diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 8b00b49ece..90669daab8 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -497,7 +497,6 @@ public: void freeLabels(); // dialogue balloons - void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height); GfxObj* registerBalloon(Frames *frames, const char *text); void destroyBalloons(); @@ -599,7 +598,6 @@ public: // low level text and patches void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); - void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene); void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); -- cgit v1.2.3 From 0365c45b8c613eb9a84e656b5a4f0eb2be33e5e0 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 10:13:53 +0000 Subject: Rearranged parts of the Operation Stealth savegame loading routine. - Emulating the Future Wars savegame loading routine and hoping for the best. - Fixes an array out of bounds access when loading the global scripts. Now the loading crashes in the mainloop in processSeqList! But at least we got a bit farther this time. More fixing to come... svn-id: r33404 --- engines/cine/various.cpp | 67 +++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index ab181743db..9a9393cc92 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -751,6 +751,45 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { in.read(currentCtName, 13); + // Moved the loading of current procedure, relation, + // backgrounds and Ct here because if they were at the + // end of this function then the global scripts loading + // made an array out of bounds access. In the original + // game's disassembly these aren't here but at the end. + // The difference is probably in how we handle loading + // the global scripts and some other things (i.e. the + // loading routines aren't exactly the same and subtle + // semantic differences result in having to do things + // in a different order). + { + // Not sure if this is needed with Operation Stealth... + checkDataDisk(currentDisk); + + if (strlen(currentPrcName)) { + loadPrc(currentPrcName); + } + + if (strlen(currentRelName)) { + loadRel(currentRelName); + } + + // Load first background (Uses loadBg) + if (strlen(bgNames[0])) { + loadBg(bgNames[0]); + } + + // Add backgrounds 1-7 (Uses addBackground) + for (int i = 1; i < 8; i++) { + if (strlen(bgNames[i])) { + addBackground(bgNames[i], i); + } + } + + if (strlen(currentCtName)) { + loadCtOS(currentCtName); + } + } + loadObjectTable(in); renderer->restorePalette(in); globalVars.load(in, NUM_MAX_VAR); @@ -810,34 +849,14 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { loadOverlayList(in); loadBgIncrustFromSave(in); - if (strlen(currentPrcName)) { - loadPrc(currentPrcName); - } - - if (strlen(currentRelName)) { - loadRel(currentRelName); - } - + // Left this here instead of moving it earlier in this function with + // the other current value loadings (e.g. loading of current procedure, + // current backgrounds etc). Mostly emulating the way we've handled + // Future Wars savegames and hoping that things work out. if (strlen(currentMsgName)) { loadMsg(currentMsgName); } - // Load first background (Uses loadBg) - if (strlen(bgNames[0])) { - loadBg(bgNames[0]); - } - - // Add backgrounds 1-7 (Uses addBackground) - for (int i = 1; i < 8; i++) { - if (strlen(bgNames[i])) { - addBackground(bgNames[i], i); - } - } - - if (strlen(currentCtName)) { - loadCtOS(currentCtName); - } - // TODO: Add current music loading and playing here // TODO: Palette handling? -- cgit v1.2.3 From f31cf5d94cb949d02a6ef42dcbadd48cc807ce40 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 29 Jul 2008 10:22:50 +0000 Subject: * Added flexible verb configuration for both NS and BRA. * Objects can now be really opened and closed in BRA. svn-id: r33405 --- engines/parallaction/inventory.cpp | 47 +++++++++++++++++++++++--------------- engines/parallaction/inventory.h | 5 ++-- engines/parallaction/objects.h | 3 ++- 3 files changed, 34 insertions(+), 21 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index fc2c9fc3eb..7b92974205 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -30,20 +30,13 @@ namespace Parallaction { -// -// inventory is a grid made of (at most) 30 cells, 24x24 pixels each, -// arranged in 6 lines -// -// inventory items are stored in cnv files in a 32x24 grid -// but only 24x24 pixels are actually copied to graphic memory -// + /* #define INVENTORYITEM_PITCH 32 #define INVENTORYITEM_WIDTH 24 #define INVENTORYITEM_HEIGHT 24 #define INVENTORY_MAX_ITEMS 30 -#define INVENTORY_FIRST_ITEM 4 // first four entries are used up by verbs #define INVENTORY_ITEMS_PER_LINE 5 #define INVENTORY_LINES 6 @@ -52,12 +45,27 @@ namespace Parallaction { #define INVENTORY_HEIGHT (INVENTORY_LINES*INVENTORYITEM_HEIGHT) */ +InventoryItem _verbs_NS[] = { + { 1, kZoneDoor }, + { 3, kZoneExamine }, + { 2, kZoneGet }, + { 4, kZoneSpeak }, + { 0, 0 } +}; + +InventoryItem _verbs_BR[] = { + { 1, kZoneBox }, + { 2, kZoneGet }, + { 3, kZoneExamine }, + { 4, kZoneSpeak }, + { 0, 0 } +}; + InventoryProperties _invProps_NS = { 32, // INVENTORYITEM_PITCH 24, // INVENTORYITEM_WIDTH 24, // INVENTORYITEM_HEIGHT 30, // INVENTORY_MAX_ITEMS - 4, // INVENTORY_FIRST_ITEM // first four entries are used up by verbs 5, // INVENTORY_ITEMS_PER_LINE 6, // INVENTORY_LINES 5 * 24, // INVENTORY_WIDTH =(INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH) @@ -69,7 +77,6 @@ InventoryProperties _invProps_BR = { 51, // INVENTORYITEM_WIDTH 51, // INVENTORYITEM_HEIGHT 48, // INVENTORY_MAX_ITEMS - 4, // INVENTORY_FIRST_ITEM // first four entries are used up by verbs 6, // INVENTORY_ITEMS_PER_LINE 8, // INVENTORY_LINES 6 * 51, // INVENTORY_WIDTH =(INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH) @@ -120,14 +127,17 @@ int16 Parallaction::getInventoryItemIndex(int16 pos) { void Parallaction::initInventory() { InventoryProperties *props; + InventoryItem *verbs; if (getGameType() == GType_Nippon) { props = &_invProps_NS; + verbs = _verbs_NS; } else { props = &_invProps_BR; + verbs = _verbs_BR; } - _inventory = new Inventory(props); + _inventory = new Inventory(props, verbs); _inventoryRenderer = new InventoryRenderer(this, props); _inventoryRenderer->bindInventory(_inventory); } @@ -255,13 +265,14 @@ void InventoryRenderer::getItemRect(ItemPosition pos, Common::Rect &r) { } -Inventory::Inventory(InventoryProperties *props) : _numItems(0), _props(props) { +Inventory::Inventory(InventoryProperties *props, InventoryItem *verbs) : _numItems(0), _props(props) { _items = (InventoryItem*)calloc(_props->_maxItems, sizeof(InventoryItem)); - addItem(1, kZoneDoor); - addItem(3, kZoneExamine); - addItem(2, kZoneGet); - addItem(4, kZoneSpeak); + int i = 0; + for ( ; verbs[i]._id; i++) { + addItem(verbs[i]._id, verbs[i]._index); + } + _numVerbs = i; } @@ -331,9 +342,9 @@ void Inventory::removeItem(ItemName name) { void Inventory::clear(bool keepVerbs) { debugC(1, kDebugInventory, "clearInventory()"); - uint first = (keepVerbs ? _props->_firstItem : 0); + uint first = (keepVerbs ? _numVerbs : 0); - for (uint16 slot = first; slot < _props->_maxItems; slot++) { + for (uint16 slot = first; slot < _numVerbs; slot++) { _items[slot]._id = 0; _items[slot]._index = 0; } diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h index faa6c24f24..f041627810 100644 --- a/engines/parallaction/inventory.h +++ b/engines/parallaction/inventory.h @@ -44,7 +44,6 @@ struct InventoryProperties { uint _itemHeight; int _maxItems; - int _firstItem; int _itemsPerLine; int _maxLines; @@ -61,12 +60,14 @@ typedef uint16 ItemName; class Inventory { protected: + uint16 _numVerbs; + InventoryItem *_items; uint16 _numItems; InventoryProperties *_props; public: - Inventory(InventoryProperties *props); + Inventory(InventoryProperties *props, InventoryItem *verbs); virtual ~Inventory(); ItemPosition addItem(ItemName name, uint32 value); diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index de740a631e..7e7a811ba6 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -71,7 +71,8 @@ enum ZoneTypes { kZoneCommand = 0x800, // BRA specific - kZonePath = 0x1000 // defines nodes for assisting walk calculation routines + kZonePath = 0x1000, // defines nodes for assisting walk calculation routines + kZoneBox = 0x2000 }; -- cgit v1.2.3 From 52700d59fdba83f549a23569c058e1cccac7f510 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 12:56:32 +0000 Subject: Added a debug message to loadTempSaveOS's to check whether we loaded the whole savefile. Made objectStruct's clearing also clear x and y member variables in resetEngine. svn-id: r33407 --- engines/cine/various.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9a9393cc92..9ff0d54f67 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -572,6 +572,8 @@ void CineEngine::resetEngine() { messageTable.clear(); for (int i = 0; i < NUM_MAX_OBJECT; i++) { + objectTable[i].x = 0; + objectTable[i].y = 0; objectTable[i].part = 0; objectTable[i].name[0] = 0; objectTable[i].frame = 0; @@ -860,6 +862,12 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { // TODO: Add current music loading and playing here // TODO: Palette handling? + if (in.pos() == in.size()) { + debug(3, "loadTempSaveOS: Loaded the whole savefile."); + } else { + warning("loadTempSaveOS: Loaded the savefile but didn't exhaust it completely. Something was left over"); + } + return !in.ioFailed(); } -- cgit v1.2.3 From f46ee2b70c3722b59e8a95e89e9cba649d87d58b Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 29 Jul 2008 12:59:55 +0000 Subject: * Implemented pause/resume of command execution * Implemented command opcode MOVE (not the script instruction). svn-id: r33408 --- engines/parallaction/exec.h | 16 ++++++++ engines/parallaction/exec_br.cpp | 3 +- engines/parallaction/exec_ns.cpp | 68 ++++++++++++++++++++++++++------ engines/parallaction/parallaction_br.cpp | 2 + 4 files changed, 76 insertions(+), 13 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h index 9ac343dc62..03526617c6 100644 --- a/engines/parallaction/exec.h +++ b/engines/parallaction/exec.h @@ -47,14 +47,30 @@ protected: struct ParallactionStruct1 { CommandPtr cmd; ZonePtr z; + bool suspend; } _ctxt; OpcodeSet _opcodes; + struct SuspendedContext { + bool valid; + CommandList::iterator first; + CommandList::iterator last; + ZonePtr zone; + } _suspendedCtxt; + + ZonePtr _execZone; + void runList(CommandList::iterator first, CommandList::iterator last); + void createSuspendList(CommandList::iterator first, CommandList::iterator last); + void cleanSuspendedList(); + public: virtual void init() = 0; virtual void run(CommandList &list, ZonePtr z = nullZonePtr); + void runSuspended(); + CommandExec() { + _suspendedCtxt.valid = false; } virtual ~CommandExec() { for (Common::Array::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i) diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 69d963dafd..a2efe8b90c 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -178,7 +178,8 @@ DECLARE_COMMAND_OPCODE(drop) { DECLARE_COMMAND_OPCODE(move) { - warning("Parallaction_br::cmdOp_move not yet implemented"); + _vm->_char.scheduleWalk(_ctxt.cmd->u._move.x, _ctxt.cmd->u._move.y); + _ctxt.suspend = true; } DECLARE_COMMAND_OPCODE(start) { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 60cc2b13f1..32dafef92b 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -428,23 +428,18 @@ label1: return; } -void CommandExec::run(CommandList& list, ZonePtr z) { - if (list.size() == 0) { - debugC(3, kDebugExec, "runCommands: nothing to do"); - return; - } - - debugC(3, kDebugExec, "runCommands starting"); +void CommandExec::runList(CommandList::iterator first, CommandList::iterator last) { uint32 useFlags = 0; bool useLocalFlags; - CommandList::iterator it = list.begin(); - for ( ; it != list.end(); it++) { + _ctxt.suspend = false; + + for ( ; first != last; first++) { if (_engineFlags & kEngineQuit) break; - CommandPtr cmd = *it; + CommandPtr cmd = *first; if (cmd->_flagsOn & kFlagsGlobal) { useFlags = _commandFlags | kFlagsGlobal; @@ -462,16 +457,65 @@ void CommandExec::run(CommandList& list, ZonePtr z) { if (!onMatch || !offMatch) continue; - _ctxt.z = z; + _ctxt.z = _execZone; _ctxt.cmd = cmd; (*_opcodes[cmd->_id])(); + + if (_ctxt.suspend) { + createSuspendList(++first, last); + return; + } + } + +} + +void CommandExec::run(CommandList& list, ZonePtr z) { + if (list.size() == 0) { + debugC(3, kDebugExec, "runCommands: nothing to do"); + return; } + _execZone = z; + + debugC(3, kDebugExec, "runCommands starting"); + runList(list.begin(), list.end()); debugC(3, kDebugExec, "runCommands completed"); +} - return; +void CommandExec::createSuspendList(CommandList::iterator first, CommandList::iterator last) { + if (first == last) { + return; + } + + debugC(3, kDebugExec, "CommandExec::createSuspendList()"); + + _suspendedCtxt.valid = true; + _suspendedCtxt.first = first; + _suspendedCtxt.last = last; + _suspendedCtxt.zone = _execZone; +} +void CommandExec::cleanSuspendedList() { + debugC(3, kDebugExec, "CommandExec::cleanSuspended()"); + + _suspendedCtxt.valid = false; + _suspendedCtxt.first = _suspendedCtxt.last; + _suspendedCtxt.zone = nullZonePtr; +} + +void CommandExec::runSuspended() { + if (_engineFlags & kEngineWalking) { + return; + } + + if (_suspendedCtxt.valid) { + debugC(3, kDebugExec, "CommandExec::runSuspended()"); + + _execZone = _suspendedCtxt.zone; + runList(_suspendedCtxt.first, _suspendedCtxt.last); + cleanSuspendedList(); + } } CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) { diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index b5fb2fa3bb..761c8d1b74 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -237,6 +237,8 @@ void Parallaction_br::startPart(uint part) { void Parallaction_br::runPendingZones() { ZonePtr z; + _cmdExec->runSuspended(); + if (_activeZone) { z = _activeZone; // speak Zone or sound _activeZone = nullZonePtr; -- cgit v1.2.3 From d83c6d7d68027d3a174ad305720ed3c5de7cb0c7 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 13:44:14 +0000 Subject: Added purgeSeqList function (Used in mainloop now). Let's see if this helps any... Renamed functions: * addScriptToList0 -> addScriptToGlobalScripts * executeList0 -> executeGlobalScripts * executeList1 -> executeObjectScripts * purgeList1 -> purgeObjectScripts (Also added a clarifying TODO to this function) * purgeList0 -> purgeGlobalScripts (Also added a clarifying TODO to this function) svn-id: r33409 --- engines/cine/main_loop.cpp | 25 ++++++++++++++++++++----- engines/cine/script.h | 10 +++++----- engines/cine/script_fw.cpp | 18 +++++++++++------- engines/cine/various.cpp | 2 +- 4 files changed, 37 insertions(+), 18 deletions(-) (limited to 'engines') diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 6aa1ec1737..ffaa1b49b4 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -179,6 +179,20 @@ int getKeyData() { return k; } +/** Removes elements from seqList that have their member variable var4 set to value -1. */ +void purgeSeqList() { + Common::List::iterator it = seqList.begin(); + while (it != seqList.end()) { + if (it->var4 == -1) { + // Erase the element and jump to the next element + it = seqList.erase(it); + } else { + // Let the element be and jump to the next element + it++; + } + } +} + void CineEngine::mainLoop(int bootScriptIdx) { bool playerAction; uint16 quitFlag; @@ -195,7 +209,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { errorVar = 0; - addScriptToList0(bootScriptIdx); + addScriptToGlobalScripts(bootScriptIdx); menuVar = 0; @@ -244,11 +258,12 @@ void CineEngine::mainLoop(int bootScriptIdx) { } processSeqList(); - executeList1(); - executeList0(); + executeObjectScripts(); + executeGlobalScripts(); - purgeList1(); - purgeList0(); + purgeObjectScripts(); + purgeGlobalScripts(); + purgeSeqList(); if (playerCommand == -1) { setMouseCursor(MOUSE_CURSOR_NORMAL); diff --git a/engines/cine/script.h b/engines/cine/script.h index c14b7c70d1..19576e4c1a 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -371,16 +371,16 @@ void dumpScript(char *dumpName); #define OP_requestCheckPendingDataLoad 0x42 #define OP_endScript 0x50 -void addScriptToList0(uint16 idx); +void addScriptToGlobalScripts(uint16 idx); int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx); void runObjectScript(int16 entryIdx); -void executeList1(void); -void executeList0(void); +void executeObjectScripts(void); +void executeGlobalScripts(void); -void purgeList1(void); -void purgeList0(void); +void purgeObjectScripts(void); +void purgeGlobalScripts(void); } // End of namespace Cine diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 6b4ec2790f..84dde264d9 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1279,7 +1279,7 @@ int FWScript::o1_startGlobalScript() { assert(param < NUM_MAX_SCRIPT); debugC(5, kCineDebugScript, "Line: %d: startScript(%d)", _line, param); - addScriptToList0(param); + addScriptToGlobalScripts(param); return 0; } @@ -1754,7 +1754,7 @@ int FWScript::o1_unloadMask5() { //----------------------------------------------------------------------- -void addScriptToList0(uint16 idx) { +void addScriptToGlobalScripts(uint16 idx) { ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx)); assert(tmp); globalScripts.push_back(tmp); @@ -1828,7 +1828,7 @@ uint16 compareVars(int16 a, int16 b) { return flag; } -void executeList1(void) { +void executeObjectScripts(void) { ScriptList::iterator it = objectScripts.begin(); for (; it != objectScripts.end();) { if ((*it)->_index < 0 || (*it)->execute() < 0) { @@ -1839,7 +1839,7 @@ void executeList1(void) { } } -void executeList0(void) { +void executeGlobalScripts(void) { ScriptList::iterator it = globalScripts.begin(); for (; it != globalScripts.end();) { if ((*it)->_index < 0 || (*it)->execute() < 0) { @@ -1850,12 +1850,16 @@ void executeList0(void) { } } -/*! \todo objectScripts.clear()? +/*! \todo Remove object scripts with script index of -1 (Not script position, but script index!). + * This would seem to be valid for both Future Wars and Operation Stealth. */ -void purgeList1(void) { +void purgeObjectScripts(void) { } -void purgeList0(void) { +/*! \todo Remove global scripts with script index of -1 (Not script position, but script index!). + * This would seem to be valid for both Future Wars and Operation Stealth. + */ +void purgeGlobalScripts(void) { } //////////////////////////////////// diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9ff0d54f67..14f75efe29 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2013,7 +2013,7 @@ void checkForPendingDataLoad(void) { // fixes a crash when failing copy protection in Amiga or Atari ST // versions of Future Wars. if (loadPrcOk) { - addScriptToList0(1); + addScriptToGlobalScripts(1); } else if (scumm_stricmp(currentPrcName, COPY_PROT_FAIL_PRC_NAME)) { // We only show an error here for other files than the file that // is loaded if copy protection fails (i.e. L201.ANI). -- cgit v1.2.3 From c9051fcfbd9b1f227bf5bddd81aac478d139e358 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 13:46:42 +0000 Subject: Make sure processSeqList and purgeSeqList are only called in the main loop when running Operation Stealth. Mostly a precaution as the seqList should be totally empty when running Future Wars as it doesn't use it. svn-id: r33410 --- engines/cine/main_loop.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index ffaa1b49b4..e5e670c973 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -257,13 +257,17 @@ void CineEngine::mainLoop(int bootScriptIdx) { } } - processSeqList(); + if (g_cine->getGameType() == Cine::GType_OS) { + processSeqList(); + } executeObjectScripts(); executeGlobalScripts(); purgeObjectScripts(); purgeGlobalScripts(); - purgeSeqList(); + if (g_cine->getGameType() == Cine::GType_OS) { + purgeSeqList(); + } if (playerCommand == -1) { setMouseCursor(MOUSE_CURSOR_NORMAL); -- cgit v1.2.3 From 0be985ce833d03e4458bb4512d5bed377c13d9c7 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 29 Jul 2008 16:09:10 +0000 Subject: Changed class File (and derived classes) to only support read-only access; added a new class DumpFile for writing svn-id: r33412 --- engines/agos/debug.cpp | 4 ++-- engines/agos/saveload.cpp | 4 ++-- engines/cine/part.cpp | 4 ++-- engines/cine/script_fw.cpp | 4 ++-- engines/cruise/volume.cpp | 4 ++-- engines/gob/dataio.cpp | 11 ++++------- engines/gob/dataio.h | 6 ++---- engines/scumm/charset.cpp | 2 +- engines/scumm/debugger.cpp | 2 +- engines/scumm/file.cpp | 16 +++------------- engines/scumm/file.h | 9 +++------ engines/scumm/file_nes.cpp | 15 ++++----------- engines/scumm/file_nes.h | 3 +-- engines/scumm/he/script_v60he.cpp | 2 +- engines/scumm/he/script_v72he.cpp | 2 +- engines/scumm/he/script_v80he.cpp | 2 +- engines/scumm/he/wiz_he.cpp | 6 +++--- engines/scumm/resource.cpp | 4 ++-- engines/sky/disk.cpp | 4 ++-- engines/sword1/resman.cpp | 4 ++-- engines/sword2/resman.cpp | 5 ++--- engines/tinsel/music.cpp | 4 ++-- 22 files changed, 45 insertions(+), 72 deletions(-) (limited to 'engines') diff --git a/engines/agos/debug.cpp b/engines/agos/debug.cpp index 76a0b8e76f..2cf285d56a 100644 --- a/engines/agos/debug.cpp +++ b/engines/agos/debug.cpp @@ -393,11 +393,11 @@ static const byte bmp_hdr[] = { }; void dumpBMP(const char *filename, int w, int h, const byte *bytes, const uint32 *palette) { - Common::File out; + Common::DumpFile out; byte my_hdr[sizeof(bmp_hdr)]; int i; - out.open(filename, Common::File::kFileWriteMode); + out.open(filename); if (!out.isOpen()) return; diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 284c7979c0..4a5c43e706 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -978,7 +978,7 @@ bool AGOSEngine::loadGame(const char *filename, bool restartMode) { if (restartMode) { // Load restart state Common::File *file = new Common::File(); - file->open(filename, Common::File::kFileReadMode); + file->open(filename); f = file; } else { f = _saveFileMan->openForLoading(filename); @@ -1154,7 +1154,7 @@ bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) { if (restartMode) { // Load restart state Common::File *file = new Common::File(); - file->open(filename, Common::File::kFileReadMode); + file->open(filename); f = file; } else { f = _saveFileMan->openForLoading(filename); diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp index b39f1eff7d..88f2dcef52 100644 --- a/engines/cine/part.cpp +++ b/engines/cine/part.cpp @@ -289,8 +289,8 @@ void dumpBundle(const char *fileName) { debug(0, "%s", partBuffer[i].partName); - Common::File out; - if (out.open(Common::String("dumps/") + partBuffer[i].partName, Common::File::kFileWriteMode)) { + Common::DumpFile out; + if (out.open(Common::String("dumps/") + partBuffer[i].partName)) { out.write(data, partBuffer[i].unpackedSize); out.close(); } diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 84dde264d9..e761a0c8e4 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -2957,10 +2957,10 @@ void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx) } void dumpScript(char *dumpName) { - Common::File fHandle; + Common::DumpFile fHandle; uint16 i; - fHandle.open(dumpName, Common::File::kFileWriteMode); + fHandle.open(dumpName); for (i = 0; i < decompileBufferPosition; i++) { fHandle.writeString(Common::String(decompileBuffer[i])); diff --git a/engines/cruise/volume.cpp b/engines/cruise/volume.cpp index e4a3dde78f..b2ff2631c0 100644 --- a/engines/cruise/volume.cpp +++ b/engines/cruise/volume.cpp @@ -456,8 +456,8 @@ int16 readVolCnf(void) { sprintf(nameBuffer, "%s", buffer[j].name); if (buffer[j].size == buffer[j].extSize) { - Common::File fout; - fout.open(nameBuffer, Common::File::kFileWriteMode); + Common::DumpFile fout; + fout.open(nameBuffer); if(fout.isOpen()) fout.write(bufferLocal, buffer[j].size); } else { diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 8ae11b8755..bcf566d134 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -202,7 +202,7 @@ const Common::File *DataIO::file_getHandle(int16 handle) const { return &_filesHandles[handle]; } -int16 DataIO::file_open(const char *path, Common::File::AccessMode mode) { +int16 DataIO::file_open(const char *path) { int16 i; for (i = 0; i < MAX_FILES; i++) { @@ -212,7 +212,7 @@ int16 DataIO::file_open(const char *path, Common::File::AccessMode mode) { if (i == MAX_FILES) return -1; - file_getHandle(i)->open(path, mode); + file_getHandle(i)->open(path); if (file_getHandle(i)->isOpen()) return i; @@ -467,17 +467,14 @@ void DataIO::closeData(int16 handle) { file_getHandle(handle)->close(); } -int16 DataIO::openData(const char *path, Common::File::AccessMode mode) { +int16 DataIO::openData(const char *path) { int16 handle; - if (mode != Common::File::kFileReadMode) - return file_open(path, mode); - handle = getChunk(path); if (handle >= 0) return handle; - return file_open(path, mode); + return file_open(path); } DataStream *DataIO::openAsStream(int16 handle, bool dispose) { diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index a990dbeda5..4b4c79d1eb 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -79,8 +79,7 @@ public: void closeDataFile(bool itk = 0); byte *getUnpackedData(const char *name); void closeData(int16 handle); - int16 openData(const char *path, - Common::File::AccessMode mode = Common::File::kFileReadMode); + int16 openData(const char *path); DataStream *openAsStream(int16 handle, bool dispose = false); int32 getDataSize(const char *name); @@ -104,8 +103,7 @@ protected: class GobEngine *_vm; - int16 file_open(const char *path, - Common::File::AccessMode mode = Common::File::kFileReadMode); + int16 file_open(const char *path); Common::File *file_getHandle(int16 handle); const Common::File *file_getHandle(int16 handle) const; diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 8f3175f098..5a45fb7da9 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -56,7 +56,7 @@ void ScummEngine::loadCJKFont() { _2byteWidth = 16; _2byteHeight = 16; // use FM-TOWNS font rom, since game files don't have kanji font resources - if (fp.open("fmt_fnt.rom", Common::File::kFileReadMode)) { + if (fp.open("fmt_fnt.rom")) { _useCJKMode = true; debug(2, "Loading FM-TOWNS Kanji rom"); _2byteFontPtr = new byte[((_2byteWidth + 7) / 8) * _2byteHeight * numChar]; diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp index 9f9115e207..23af1f9672 100644 --- a/engines/scumm/debugger.cpp +++ b/engines/scumm/debugger.cpp @@ -298,7 +298,7 @@ bool ScummDebugger::Cmd_ImportRes(int argc, const char** argv) { // FIXME add bounds check if (!strncmp(argv[1], "scr", 3)) { - file.open(argv[2], Common::File::kFileReadMode); + file.open(argv[2]); if (file.isOpen() == false) { DebugPrintf("Could not open file %s\n", argv[2]); return true; diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index bc5fc38225..bf13308a0c 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -58,8 +58,8 @@ void ScummFile::resetSubfile() { seek(0, SEEK_SET); } -bool ScummFile::open(const Common::String &filename, AccessMode mode) { - if (File::open(filename, mode)) { +bool ScummFile::open(const Common::String &filename) { + if (File::open(filename)) { resetSubfile(); return true; } else { @@ -187,11 +187,6 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { return realLen; } -uint32 ScummFile::write(const void *, uint32) { - error("ScummFile does not support writing!"); - return 0; -} - #pragma mark - #pragma mark --- ScummDiskImage --- #pragma mark - @@ -250,11 +245,6 @@ ScummDiskImage::ScummDiskImage(const char *disk1, const char *disk2, GameSetting } } -uint32 ScummDiskImage::write(const void *, uint32) { - error("ScummDiskImage does not support writing!"); - return 0; -} - void ScummDiskImage::setEnc(byte enc) { _stream->setEnc(enc); } @@ -300,7 +290,7 @@ bool ScummDiskImage::openDisk(char num) { return true; } -bool ScummDiskImage::open(const Common::String &filename, AccessMode mode) { +bool ScummDiskImage::open(const Common::String &filename) { uint16 signature; // check signature diff --git a/engines/scumm/file.h b/engines/scumm/file.h index 7064654f89..a2695cac59 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -36,7 +36,7 @@ class BaseScummFile : public Common::File { public: virtual void setEnc(byte value) = 0; - virtual bool open(const Common::String &filename, AccessMode mode = kFileReadMode) = 0; + virtual bool open(const Common::String &filename) = 0; virtual bool openSubFile(const Common::String &filename) = 0; virtual bool eof() = 0; @@ -44,7 +44,6 @@ public: virtual uint32 size() = 0; virtual void seek(int32 offs, int whence = SEEK_SET) = 0; virtual uint32 read(void *dataPtr, uint32 dataSize) = 0; - virtual uint32 write(const void *dataPtr, uint32 dataSize) = 0; }; class ScummFile : public BaseScummFile { @@ -59,7 +58,7 @@ public: void setSubfileRange(uint32 start, uint32 len); void resetSubfile(); - bool open(const Common::String &filename, AccessMode mode = kFileReadMode); + bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); bool eof(); @@ -67,7 +66,6 @@ public: uint32 size(); void seek(int32 offs, int whence = SEEK_SET); uint32 read(void *dataPtr, uint32 dataSize); - uint32 write(const void *dataPtr, uint32 dataSize); }; class ScummDiskImage : public BaseScummFile { @@ -104,7 +102,7 @@ public: ScummDiskImage(const char *disk1, const char *disk2, GameSettings game); void setEnc(byte value); - bool open(const Common::String &filename, AccessMode mode = kFileReadMode); + bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); void close(); @@ -113,7 +111,6 @@ public: 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 diff --git a/engines/scumm/file_nes.cpp b/engines/scumm/file_nes.cpp index 95f5eec4ea..8325436f87 100644 --- a/engines/scumm/file_nes.cpp +++ b/engines/scumm/file_nes.cpp @@ -62,11 +62,6 @@ struct ScummNESFile::Resource { 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); } @@ -1234,7 +1229,7 @@ bool ScummNESFile::generateIndex() { return true; } -bool ScummNESFile::open(const Common::String &filename, AccessMode mode) { +bool ScummNESFile::open(const Common::String &filename) { if (_ROMset == kROMsetNum) { char md5str[32+1]; @@ -1267,9 +1262,8 @@ bool ScummNESFile::open(const Common::String &filename, AccessMode mode) { } } - if (File::open(filename, mode)) { - if (_stream) - delete _stream; + if (File::open(filename)) { + delete _stream; _stream = 0; free(_buf); @@ -1282,8 +1276,7 @@ bool ScummNESFile::open(const Common::String &filename, AccessMode mode) { } void ScummNESFile::close() { - if (_stream) - delete _stream; + delete _stream; _stream = 0; free(_buf); diff --git a/engines/scumm/file_nes.h b/engines/scumm/file_nes.h index d601c2c496..4d2d6de275 100644 --- a/engines/scumm/file_nes.h +++ b/engines/scumm/file_nes.h @@ -64,7 +64,7 @@ public: ScummNESFile(); void setEnc(byte value); - bool open(const Common::String &filename, AccessMode mode = kFileReadMode); + bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); void close(); @@ -73,7 +73,6 @@ public: 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 diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp index 4d5ec668a0..9429f8d086 100644 --- a/engines/scumm/he/script_v60he.cpp +++ b/engines/scumm/he/script_v60he.cpp @@ -1012,7 +1012,7 @@ void ScummEngine_v60he::o60_openFile() { _hInFileTable[slot] = _saveFileMan->openForLoading(filename); if (_hInFileTable[slot] == 0) { Common::File *f = new Common::File(); - f->open(filename, Common::File::kFileReadMode); + f->open(filename); if (!f->isOpen()) delete f; else diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index df3d857642..6c3d0023d8 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -1692,7 +1692,7 @@ void ScummEngine_v72he::o72_openFile() { _hInFileTable[slot] = _saveFileMan->openForLoading(filename); if (_hInFileTable[slot] == 0) { Common::File *f = new Common::File(); - f->open(filename, Common::File::kFileReadMode); + f->open(filename); if (!f->isOpen()) delete f; else diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp index 393e1d3a8f..39ec715d94 100644 --- a/engines/scumm/he/script_v80he.cpp +++ b/engines/scumm/he/script_v80he.cpp @@ -409,7 +409,7 @@ void ScummEngine_v80he::o80_getFileSize() { Common::SeekableReadStream *f = _saveFileMan->openForLoading((const char *)filename); if (!f) { Common::File *file = new Common::File(); - file->open((const char *)filename, Common::File::kFileReadMode); + file->open((const char *)filename); if (!file->isOpen()) delete f; else diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index df472307eb..f514449bff 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -1881,7 +1881,7 @@ void Wiz::processWizImage(const WizParameters *params) { memcpy(filename, params->filename, 260); _vm->convertFilePath(filename); - if (f.open((const char *)filename, Common::File::kFileReadMode)) { + if (f.open((const char *)filename)) { uint32 id = f.readUint32BE(); if (id == MKID_BE('AWIZ') || id == MKID_BE('MULT')) { uint32 size = f.readUint32BE(); @@ -1911,7 +1911,7 @@ void Wiz::processWizImage(const WizParameters *params) { break; case 4: if (params->processFlags & kWPFUseFile) { - Common::File f; + Common::DumpFile f; switch (params->fileWriteMode) { case 2: @@ -1924,7 +1924,7 @@ void Wiz::processWizImage(const WizParameters *params) { memcpy(filename, params->filename, 260); _vm->convertFilePath(filename); - if (!f.open((const char *)filename, Common::File::kFileWriteMode)) { + if (!f.open((const char *)filename)) { debug(0, "Unable to open for write '%s'", filename); _vm->VAR(119) = -3; } else { diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index acdc2bc222..6bd62c1761 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -1299,7 +1299,7 @@ void ScummEngine::allocateArrays() { void ScummEngine::dumpResource(const char *tag, int idx, const byte *ptr, int length) { char buf[256]; - Common::File out; + Common::DumpFile out; uint32 size; if (length >= 0) @@ -1313,7 +1313,7 @@ void ScummEngine::dumpResource(const char *tag, int idx, const byte *ptr, int le sprintf(buf, "dumps/%s%d.dmp", tag, idx); - out.open(buf, Common::File::kFileWriteMode); + out.open(buf); if (out.isOpen() == false) return; out.write(ptr, size); diff --git a/engines/sky/disk.cpp b/engines/sky/disk.cpp index a2f7d57cb0..a30276f8be 100644 --- a/engines/sky/disk.cpp +++ b/engines/sky/disk.cpp @@ -326,14 +326,14 @@ void Disk::fnFlushBuffers(void) { void Disk::dumpFile(uint16 fileNr) { char buf[128]; - Common::File out; + Common::DumpFile out; byte* filePtr; filePtr = loadFile(fileNr); sprintf(buf, "dumps/file-%d.dmp", fileNr); if (!Common::File::exists(buf)) { - if (out.open(buf, Common::File::kFileWriteMode)) + if (out.open(buf)) out.write(filePtr, _lastLoadedFileSize); } free(filePtr); diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp index d54e290b09..adb84eee83 100644 --- a/engines/sword1/resman.cpp +++ b/engines/sword1/resman.cpp @@ -212,8 +212,8 @@ void *ResMan::openFetchRes(uint32 id) { void ResMan::dumpRes(uint32 id) { char outn[30]; sprintf(outn, "DUMP%08X.BIN", id); - Common::File outf; - if (outf.open(outn, Common::File::kFileWriteMode)) { + Common::DumpFile outf; + if (outf.open(outn)) { resOpen(id); MemHandle *memHandle = resHandle(id); outf.write(memHandle->data, memHandle->size); diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp index d6b8025cda..8cddddff78 100644 --- a/engines/sword2/resman.cpp +++ b/engines/sword2/resman.cpp @@ -234,7 +234,6 @@ bool ResourceManager::init() { /** * Returns the address of a resource. Loads if not in memory. Retains a count. */ - byte *ResourceManager::openResource(uint32 res, bool dump) { assert(res < _totalResFiles); @@ -287,7 +286,6 @@ byte *ResourceManager::openResource(uint32 res, bool dump) { if (dump) { char buf[256]; const char *tag; - Common::File out; switch (fetchType(_resList[res].ptr)) { case ANIMATION_FILE: @@ -337,7 +335,8 @@ byte *ResourceManager::openResource(uint32 res, bool dump) { sprintf(buf, "dumps/%s-%d.dmp", tag, res); if (!Common::File::exists(buf)) { - if (out.open(buf, Common::File::kFileWriteMode)) + Common::DumpFile out; + if (out.open(buf)) out.write(_resList[res].ptr, len); } } diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 060eba10d4..7d4efd8079 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -507,7 +507,7 @@ void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) { // Dumps all of the game's music in external XMIDI *.xmi files void dumpMusic() { Common::File midiFile; - Common::File outFile; + Common::DumpFile outFile; char outName[20]; midiFile.open(MIDI_FILE); int outFileSize = 0; @@ -519,7 +519,7 @@ void dumpMusic() { for (int i = 0; i < total; i++) { sprintf(outName, "track%03d.xmi", i + 1); - outFile.open(outName, Common::File::kFileWriteMode); + outFile.open(outName); if (_vm->getFeatures() & GF_SCNFILES) { if (i < total - 1) -- cgit v1.2.3 From 8bdbbaf413d61cacbe62d11195842c93be786a18 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Wed, 30 Jul 2008 06:25:17 +0000 Subject: Reordered initialization lists to silence warning. svn-id: r33432 --- engines/parallaction/balloons.cpp | 5 +++-- engines/parallaction/gfxbase.cpp | 2 +- engines/parallaction/graphics.h | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp index c7a5fee919..81b32adb15 100644 --- a/engines/parallaction/balloons.cpp +++ b/engines/parallaction/balloons.cpp @@ -359,11 +359,12 @@ class BalloonManager_br : public BalloonManager { uint _numBalloons; - Frames *_leftBalloon; - Frames *_rightBalloon; Disk *_disk; Gfx *_gfx; + Frames *_leftBalloon; + Frames *_rightBalloon; + void cacheAnims(); void getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 7c02205e69..aa02253cb1 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -32,7 +32,7 @@ namespace Parallaction { -GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(kGfxObjNormal), _keep(true) { +GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3) { if (name) { _name = strdup(name); } else { diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 90669daab8..52b7a4b870 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -472,6 +472,9 @@ typedef Common::HashMap_loopCounter = inst->_opB.getRValue(); - _ctxt.program->_loopStart = _ctxt.inst; -} - DECLARE_INSTRUCTION_OPCODE(inc) { InstructionPtr inst = *_ctxt.inst; @@ -504,16 +497,6 @@ DECLARE_INSTRUCTION_OPCODE(stop) { warning("Parallaction_br::instOp_stop not yet implemented"); } -DECLARE_INSTRUCTION_OPCODE(endscript) { - if ((_ctxt.anim->_flags & kFlagsLooping) == 0) { - _ctxt.anim->_flags &= ~kFlagsActing; - _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim); - _ctxt.program->_status = kProgramDone; - } - _ctxt.program->_ip = _ctxt.program->_instructions.begin(); - - _ctxt.suspend = true; -} void CommandExec_br::init() { Common::Array *table = 0; @@ -585,7 +568,7 @@ void ProgramExec_br::init() { INSTRUCTION_OPCODE(set); // f INSTRUCTION_OPCODE(loop); INSTRUCTION_OPCODE(endloop); - INSTRUCTION_OPCODE(null); // show + INSTRUCTION_OPCODE(show); // show INSTRUCTION_OPCODE(inc); INSTRUCTION_OPCODE(inc); // dec INSTRUCTION_OPCODE(set); diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 32dafef92b..3e3ee19a03 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -81,13 +81,13 @@ DECLARE_INSTRUCTION_OPCODE(loop) { InstructionPtr inst = *_ctxt.inst; _ctxt.program->_loopCounter = inst->_opB.getRValue(); - _ctxt.program->_loopStart = _ctxt.inst; + _ctxt.program->_loopStart = _ctxt.ip; } DECLARE_INSTRUCTION_OPCODE(endloop) { if (--_ctxt.program->_loopCounter > 0) { - _ctxt.inst = _ctxt.program->_loopStart; + _ctxt.ip = _ctxt.program->_loopStart; } } @@ -97,7 +97,7 @@ DECLARE_INSTRUCTION_OPCODE(inc) { if (inst->_flags & kInstMod) { // mod int16 _bx = (_si > 0 ? _si : -_si); - if (_modCounter % _bx != 0) return; + if (_ctxt.modCounter % _bx != 0) return; _si = (_si > 0 ? 1 : -1); } @@ -142,8 +142,8 @@ DECLARE_INSTRUCTION_OPCODE(put) { _vm->_gfx->patchBackground(v18, x, y, mask); } -DECLARE_INSTRUCTION_OPCODE(null) { - +DECLARE_INSTRUCTION_OPCODE(show) { + _ctxt.suspend = true; } DECLARE_INSTRUCTION_OPCODE(invalid) { @@ -156,8 +156,10 @@ DECLARE_INSTRUCTION_OPCODE(call) { DECLARE_INSTRUCTION_OPCODE(wait) { - if (_engineFlags & kEngineWalking) + if (_engineFlags & kEngineWalking) { + _ctxt.ip--; _ctxt.suspend = true; + } } @@ -186,8 +188,8 @@ DECLARE_INSTRUCTION_OPCODE(endscript) { _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim); _ctxt.program->_status = kProgramDone; } - _ctxt.program->_ip = _ctxt.program->_instructions.begin(); + _ctxt.ip = _ctxt.program->_instructions.begin(); _ctxt.suspend = true; } @@ -376,14 +378,41 @@ void Parallaction_ns::drawAnimations() { return; } +void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) { + debugC(9, kDebugExec, "runScript(Animation = %s)", a->_name); + + _ctxt.ip = script->_ip; + _ctxt.anim = a; + _ctxt.program = script; + _ctxt.suspend = false; + _ctxt.modCounter = _modCounter; + + InstructionList::iterator inst; + for ( ; (a->_flags & kFlagsActing) ; ) { + + inst = _ctxt.ip; + _ctxt.inst = inst; + _ctxt.ip++; + + debugC(9, kDebugExec, "inst [%02i] %s\n", (*inst)->_index, _instructionNames[(*inst)->_index - 1]); + + script->_status = kProgramRunning; + + (*_opcodes[(*inst)->_index])(); + + if (_ctxt.suspend) + break; + + } + script->_ip = _ctxt.ip; + +} void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) { if (_engineFlags & kEnginePauseJobs) { return; } - debugC(9, kDebugExec, "runScripts"); - for (ProgramList::iterator it = first; it != last; it++) { AnimationPtr a = (*it)->_anim; @@ -394,31 +423,8 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator if ((a->_flags & kFlagsActing) == 0) continue; - InstructionList::iterator inst = (*it)->_ip; - while (((*inst)->_index != INST_SHOW) && (a->_flags & kFlagsActing)) { - - (*it)->_status = kProgramRunning; - - debugC(9, kDebugExec, "anim: %s, inst[%02i]: %s", a->_name, (*inst)->_index, _instructionNames[(*inst)->_index - 1]); - - _ctxt.inst = inst; - _ctxt.anim = AnimationPtr(a); - _ctxt.program = *it; - _ctxt.suspend = false; - - (*_opcodes[(*inst)->_index])(); - - inst = _ctxt.inst; // handles endloop correctly - - if (_ctxt.suspend) - goto label1; - - inst++; - } - - (*it)->_ip = ++inst; + runScript(*it, a); -label1: if (a->_flags & kFlagsCharacter) a->_z = a->_top + a->height(); } @@ -796,7 +802,7 @@ void ProgramExec_ns::init() { INSTRUCTION_OPCODE(set); // f INSTRUCTION_OPCODE(loop); INSTRUCTION_OPCODE(endloop); - INSTRUCTION_OPCODE(null); + INSTRUCTION_OPCODE(show); INSTRUCTION_OPCODE(inc); INSTRUCTION_OPCODE(inc); // dec INSTRUCTION_OPCODE(set); -- cgit v1.2.3 From 8941a96bf0742b35e04741d9841d4c1430201baa Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 30 Jul 2008 08:23:04 +0000 Subject: Make sure that save game descriptions are 0-terminated svn-id: r33438 --- engines/tinsel/saveload.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'engines') diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index 5cb149eb37..1a6cc1202a 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -136,6 +136,7 @@ static bool syncSaveGameHeader(Serializer &s, SaveGameHeader &hdr) { s.syncAsUint32LE(hdr.ver); s.syncBytes((byte *)hdr.desc, SG_DESC_LEN); + hdr.desc[SG_DESC_LEN - 1] = 0; syncTime(s, hdr.dateTime); @@ -291,6 +292,7 @@ int getList(void) { strncpy(savedFiles[i].name, fname.c_str(), FNAMELEN); strncpy(savedFiles[i].desc, hdr.desc, SG_DESC_LEN); + savedFiles[i].desc[SG_DESC_LEN - 1] = 0; savedFiles[i].dateTime = hdr.dateTime; ++numSfiles; @@ -405,6 +407,7 @@ static void DoSave(void) { hdr.size = SAVEGAME_HEADER_SIZE; hdr.ver = CURRENT_VER; memcpy(hdr.desc, SaveSceneDesc, SG_DESC_LEN); + hdr.desc[SG_DESC_LEN - 1] = 0; g_system->getTimeAndDate(hdr.dateTime); if (!syncSaveGameHeader(s, hdr) || f->ioFailed()) { goto save_failure; -- cgit v1.2.3 From 4210defa2980092822bd8e931b7ca37bbae020ad Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 30 Jul 2008 11:03:52 +0000 Subject: Added some debug aids related to addAni and the processSeqList crashing. svn-id: r33444 --- engines/cine/various.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 14f75efe29..1af807c867 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2186,6 +2186,8 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele const int8 *ptr2; int16 di; + debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, param3 = %d", param1, objIdx, ptr, param3); + // In the original an error string is set and 0 is returned if the following doesn't hold assert(ptr); @@ -2291,6 +2293,19 @@ void processSeqListElement(SeqListElement &element) { int16 var_10; int16 var_4; int16 var_2; + + // Initial interpretations for variables addressed through ptr1 (8-bit addressing): + // These may be inaccurate! + // 0: ? + // 1: xRadius + // 2: yRadius + // 3: ? + // 4: xAdd + // 5: yAdd + // 6: ? + // 7: ? + // After this come (At least at positions 0, 1 and 3 in 16-bit addressing) + // 16-bit big-endian values used for addressing through ptr1. if (element.var12 < element.var10) { element.var12++; -- cgit v1.2.3 From 81cb4931582f5839cca2958a634525ffb81a1714 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 30 Jul 2008 11:36:14 +0000 Subject: Debug printing a couple more relevant variables in addAni. svn-id: r33446 --- engines/cine/various.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 1af807c867..2fcb015fcd 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2186,7 +2186,8 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele const int8 *ptr2; int16 di; - debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, param3 = %d", param1, objIdx, ptr, param3); + debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, element.var8 = %d, element.var14 = %d param3 = %d", + param1, objIdx, ptr, element.var8, element.var14, param3); // In the original an error string is set and 0 is returned if the following doesn't hold assert(ptr); -- cgit v1.2.3 From 5e0df8ad8e9755e1fcf11d8433052dc11c74e988 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 31 Jul 2008 10:47:15 +0000 Subject: Committed slightly modified patch #2029395 "KYRA: Lands of Lore Intro + Character selection". svn-id: r33463 --- engines/kyra/detection.cpp | 57 +++ engines/kyra/kyra_hof.cpp | 2 +- engines/kyra/kyra_v1.h | 3 +- engines/kyra/lol.cpp | 806 +++++++++++++++++++++++++++++++++++++++++++ engines/kyra/lol.h | 155 +++++++++ engines/kyra/module.mk | 2 + engines/kyra/resource.cpp | 16 +- engines/kyra/screen_lol.cpp | 69 ++++ engines/kyra/screen_lol.h | 53 +++ engines/kyra/screen_v2.cpp | 22 ++ engines/kyra/screen_v2.h | 2 + engines/kyra/script_tim.cpp | 401 ++++++++++++++++++++- engines/kyra/script_tim.h | 63 +++- engines/kyra/sound_adlib.cpp | 9 +- engines/kyra/staticres.cpp | 107 +++++- 15 files changed, 1736 insertions(+), 31 deletions(-) create mode 100644 engines/kyra/lol.cpp create mode 100644 engines/kyra/lol.h create mode 100644 engines/kyra/screen_lol.cpp create mode 100644 engines/kyra/screen_lol.h (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index fce1e93bc2..2d592069d2 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -26,6 +26,7 @@ #include "kyra/kyra_lok.h" #include "kyra/kyra_hof.h" #include "kyra/kyra_mr.h" +#include "kyra/lol.h" #include "common/config-manager.h" #include "common/advancedDetector.h" @@ -64,6 +65,8 @@ namespace { #define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3) #define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3) +#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_LOL) + const KYRAGameDescription adGameDescs[] = { { { @@ -700,6 +703,56 @@ const KYRAGameDescription adGameDescs[] = { }, KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA) }, + + // Lands of Lore CD + { + { + "lol", + "CD", + { + { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 }, + { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + LOL_CD_FLAGS + }, + + { + { + "lol", + "CD", + { + { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 }, + { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 }, + { 0, 0, 0, 0 } + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + LOL_CD_FLAGS + }, + + { + { + "lol", + "CD", + { + { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 }, + { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + LOL_CD_FLAGS + }, + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } }; @@ -707,6 +760,7 @@ const PlainGameDescriptor gameList[] = { { "kyra1", "The Legend of Kyrandia" }, { "kyra2", "The Legend of Kyrandia: The Hand of Fate" }, { "kyra3", "The Legend of Kyrandia: Malcolm's Revenge" }, + { "lol", "Lands of Lore: The Throne of Chaos" }, { 0, 0 } }; @@ -779,6 +833,9 @@ bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common case Kyra::GI_KYRA3: *engine = new Kyra::KyraEngine_MR(syst, flags); break; + case Kyra::GI_LOL: + *engine = new Kyra::LoLEngine(syst, flags); + break; default: res = false; warning("Kyra engine: unknown gameID"); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 879efab86e..d3de621707 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -230,7 +230,7 @@ int KyraEngine_HoF::init() { _gui = new GUI_HoF(this); assert(_gui); _gui->initStaticData(); - _tim = new TIMInterpreter(this, _system); + _tim = new TIMInterpreter(this, _screen, _system); assert(_tim); if (_flags.isDemo && !_flags.isTalkie) { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 09efc8cc97..50cabc421e 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -64,7 +64,8 @@ struct GameFlags { enum { GI_KYRA1 = 0, GI_KYRA2 = 1, - GI_KYRA3 = 2 + GI_KYRA3 = 2, + GI_LOL = 4 }; struct AudioDataStruct { diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp new file mode 100644 index 0000000000..ef1121baa0 --- /dev/null +++ b/engines/kyra/lol.cpp @@ -0,0 +1,806 @@ +/* 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 "kyra/lol.h" +#include "kyra/screen_lol.h" +#include "kyra/resource.h" +#include "kyra/sound.h" + +#include "common/endian.h" + +namespace Kyra { + +LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags) { + _screen = 0; + + switch (_flags.lang) { + case Common::EN_ANY: + case Common::EN_USA: + case Common::EN_GRB: + _lang = 0; + break; + + case Common::FR_FRA: + _lang = 1; + break; + + case Common::DE_DEU: + _lang = 2; + break; + + default: + warning("unsupported language, switching back to English"); + _lang = 0; + break; + } + + _chargenWSA = 0; +} + +LoLEngine::~LoLEngine() { + setupPrologueData(false); + + delete _screen; + delete _tim; + + for (Common::Array::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i) + delete *i; + _timIntroOpcodes.clear(); +} + +Screen *LoLEngine::screen() { + return _screen; +} + +int LoLEngine::init() { + _screen = new Screen_LoL(this, _system); + assert(_screen); + _screen->setResolution(); + + KyraEngine_v1::init(); + + _tim = new TIMInterpreter(this, _screen, _system); + assert(_tim); + + _screen->setAnimBlockPtr(10000); + _screen->setScreenDim(0); + + return 0; +} + +int LoLEngine::go() { + setupPrologueData(true); + showIntro(); + _sound->playTrack(6); + /*int character = */chooseCharacter(); + _sound->playTrack(1); + _screen->fadeToBlack(); + setupPrologueData(false); + + return 0; +} + +#pragma mark - Input + +int LoLEngine::checkInput(Button *buttonList, bool mainLoop) { + debugC(9, kDebugLevelMain, "LoLEngine::checkInput(%p, %d)", (const void*)buttonList, mainLoop); + updateInput(); + + int keys = 0; + int8 mouseWheel = 0; + + while (_eventList.size()) { + Common::Event event = *_eventList.begin(); + bool breakLoop = false; + + switch (event.type) { + case Common::EVENT_KEYDOWN: + /*if (event.kbd.keycode >= '1' && event.kbd.keycode <= '9' && + (event.kbd.flags == Common::KBD_CTRL || event.kbd.flags == Common::KBD_ALT) && mainLoop) { + const char *saveLoadSlot = getSavegameFilename(9 - (event.kbd.keycode - '0') + 990); + + if (event.kbd.flags == Common::KBD_CTRL) { + loadGame(saveLoadSlot); + _eventList.clear(); + breakLoop = true; + } else { + char savegameName[14]; + sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); + saveGame(saveLoadSlot, savegameName); + } + } else if (event.kbd.flags == Common::KBD_CTRL) { + if (event.kbd.keycode == 'd') + _debugger->attach(); + }*/ + break; + + case Common::EVENT_MOUSEMOVE: { + Common::Point pos = getMousePos(); + _mouseX = pos.x; + _mouseY = pos.y; + } break; + + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: { + Common::Point pos = getMousePos(); + _mouseX = pos.x; + _mouseY = pos.y; + keys = (event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800)); + breakLoop = true; + } break; + + case Common::EVENT_WHEELUP: + mouseWheel = -1; + break; + + case Common::EVENT_WHEELDOWN: + mouseWheel = 1; + break; + + default: + break; + } + + //if (_debugger->isAttached()) + // _debugger->onFrame(); + + if (breakLoop) + break; + + _eventList.erase(_eventList.begin()); + } + + return /*gui_v2()->processButtonList(buttonList, keys | 0x8000, mouseWheel)*/keys; +} + +void LoLEngine::updateInput() { + Common::Event event; + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + _quitFlag = true; + break; + + case Common::EVENT_KEYDOWN: + if (event.kbd.keycode == '.' || event.kbd.keycode == Common::KEYCODE_ESCAPE) + _eventList.push_back(Event(event, true)); + else if (event.kbd.keycode == 'q' && event.kbd.flags == Common::KBD_CTRL) + _quitFlag = true; + else + _eventList.push_back(event); + break; + + case Common::EVENT_LBUTTONDOWN: + _eventList.push_back(Event(event, true)); + break; + + case Common::EVENT_MOUSEMOVE: + _screen->updateScreen(); + // fall through + + case Common::EVENT_LBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + _eventList.push_back(event); + break; + + default: + break; + } + } +} + +void LoLEngine::removeInputTop() { + if (!_eventList.empty()) + _eventList.erase(_eventList.begin()); +} + +bool LoLEngine::skipFlag() const { + for (Common::List::const_iterator i = _eventList.begin(); i != _eventList.end(); ++i) { + if (i->causedSkip) + return true; + } + return false; +} + +void LoLEngine::resetSkipFlag(bool removeEvent) { + for (Common::List::iterator i = _eventList.begin(); i != _eventList.end(); ++i) { + if (i->causedSkip) { + if (removeEvent) + _eventList.erase(i); + else + i->causedSkip = false; + return; + } + } +} + +#pragma mark - Intro + +void LoLEngine::setupPrologueData(bool load) { + static const char * const fileList[] = { + "xxx/general.pak", + "xxx/introvoc.pak", + "xxx/startup.pak", + "xxx/intro1.pak", + "xxx/intro2.pak", + "xxx/intro3.pak", + "xxx/intro4.pak", + "xxx/intro5.pak", + "xxx/intro6.pak", + "xxx/intro7.pak", + "xxx/intro8.pak", + "xxx/intro9.pak" + }; + + char filename[32]; + for (uint i = 0; i < ARRAYSIZE(fileList); ++i) { + strcpy(filename, fileList[i]); + memcpy(filename, _languageExt[_lang], 3); + + if (load) { + if (!_res->loadPakFile(filename)) + error("Couldn't load file: '%s'", filename); + } else { + _res->unloadPakFile(filename); + } + } + + if (load) { + _chargenWSA = new WSAMovie_v2(this, _screen); + assert(_chargenWSA); + + _charSelection = -1; + _charSelectionInfoResult = -1; + + _selectionAnimFrames[0] = _selectionAnimFrames[2] = 0; + _selectionAnimFrames[1] = _selectionAnimFrames[3] = 1; + + memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers)); + memset(_screen->getPalette(1), 0, 768); + } else { + delete _chargenWSA; _chargenWSA = 0; + } +} + +void LoLEngine::showIntro() { + debugC(9, kDebugLevelMain, "LoLEngine::showIntro()"); + + TIM *intro = _tim->load("LOLINTRO.TIM", &_timIntroOpcodes); + + _screen->loadFont(Screen::FID_8_FNT, "NEW8P.FNT"); + _screen->loadFont(Screen::FID_INTRO_FNT, "INTRO.FNT"); + _screen->setFont(Screen::FID_8_FNT); + + _tim->resetFinishedFlag(); + _tim->setLangData("LOLINTRO.DIP"); + + _screen->hideMouse(); + + uint32 palNextFadeStep = 0; + while (!_tim->finished() && !_quitFlag && !skipFlag()) { + updateInput(); + _tim->exec(intro, false); + _screen->checkedPageUpdate(8, 4); + + if (_tim->_palDiff) { + if (palNextFadeStep < _system->getMillis()) { + _tim->_palDelayAcc += _tim->_palDelayInc; + palNextFadeStep = _system->getMillis() + ((_tim->_palDelayAcc >> 8) * _tickLength); + _tim->_palDelayAcc &= 0xFF; + + if (!_screen->fadePalStep(_screen->getPalette(0), _tim->_palDiff)) { + _screen->setScreenPalette(_screen->getPalette(0)); + _tim->_palDiff = 0; + } + } + } + + _system->delayMillis(10); + _screen->updateScreen(); + } + _screen->showMouse(); + _sound->voiceStop(); + + // HACK: Remove all input events + _eventList.clear(); + + _tim->unload(intro); + _tim->clearLangData(); + + _screen->fadePalette(_screen->getPalette(1), 30, 0); +} + +int LoLEngine::chooseCharacter() { + debugC(9, kDebugLevelMain, "LoLEngine::chooseCharacter()"); + + _tim->setLangData("LOLINTRO.DIP"); + + _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT"); + + _screen->loadBitmap("ITEMICN.SHP", 3, 3, 0); + _screen->setMouseCursor(0, 0, _screen->getPtrToShape(_screen->getCPagePtr(3), 0)); + + while (!_screen->isMouseVisible()) + _screen->showMouse(); + + _screen->loadBitmap("CHAR.CPS", 2, 2, _screen->getPalette(0)); + _screen->loadBitmap("BACKGRND.CPS", 4, 4, _screen->getPalette(0)); + + if (!_chargenWSA->open("CHARGEN.WSA", 1, 0)) + error("Couldn't load CHARGEN.WSA"); + _chargenWSA->setX(113); + _chargenWSA->setY(0); + _chargenWSA->setDrawPage(2); + _chargenWSA->displayFrame(0, 0, 0, 0); + + _screen->setFont(Screen::FID_9_FNT); + _screen->_curPage = 2; + + for (int i = 0; i < 4; ++i) + _screen->fprintStringIntro(_charPreviews[i].name, _charPreviews[i].x + 16, _charPreviews[i].y + 36, 0xC0, 0x00, 0x9C, 0x120); + + for (int i = 0; i < 4; ++i) { + _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 48, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[0]); + _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 56, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[1]); + _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 64, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[2]); + } + + _screen->fprintStringIntro(_tim->getCTableEntry(51), 36, 173, 0x98, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(53), 36, 181, 0x98, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(55), 36, 189, 0x98, 0x00, 0x9C, 0x20); + + _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); + _screen->_curPage = 0; + + _screen->fadePalette(_screen->getPalette(0), 30, 0); + + bool kingIntro = true; + while (!_quitFlag) { + if (kingIntro) + kingSelectionIntro(); + + if (_charSelection < 0) + processCharacterSelection(); + + if (_quitFlag) + break; + + if (_charSelection == 100) { + kingIntro = true; + _charSelection = -1; + continue; + } + + _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + _screen->showMouse(); + + if (selectionCharInfo(_charSelection) == -1) { + _charSelection = -1; + kingIntro = false; + } else { + break; + } + } + + if (_quitFlag) + return -1; + + uint32 waitTime = _system->getMillis() + 420 * _tickLength; + while (waitTime > _system->getMillis() && !skipFlag() && !_quitFlag) { + updateInput(); + _system->delayMillis(10); + } + + // HACK: Remove all input events + _eventList.clear(); + + _tim->clearLangData(); + + return _charSelection; +} + +void LoLEngine::kingSelectionIntro() { + debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionIntro()"); + + _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK); + int y = 38; + + _screen->fprintStringIntro(_tim->getCTableEntry(57), 8, y, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(58), 8, y + 10, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(59), 8, y + 20, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(60), 8, y + 30, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(61), 8, y + 40, 0x32, 0x00, 0x9C, 0x20); + + _sound->voicePlay("KING01"); + + _chargenWSA->setX(113); + _chargenWSA->setY(0); + _chargenWSA->setDrawPage(0); + + int index = 4; + while (_sound->voiceIsPlaying("KING01") && _charSelection == -1 && !_quitFlag && !skipFlag()) { + index = MAX(index, 4); + + _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 0, 0); + _screen->copyRegion(_selectionPosTable[_selectionChar1IdxTable[index]*2+0], _selectionPosTable[_selectionChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0); + _screen->copyRegion(_selectionPosTable[_selectionChar2IdxTable[index]*2+0], _selectionPosTable[_selectionChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0); + _screen->copyRegion(_selectionPosTable[_selectionChar3IdxTable[index]*2+0], _selectionPosTable[_selectionChar3IdxTable[index]*2+1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0); + _screen->copyRegion(_selectionPosTable[_selectionChar4IdxTable[index]*2+0], _selectionPosTable[_selectionChar4IdxTable[index]*2+1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0); + _screen->updateScreen(); + + uint32 waitEnd = _system->getMillis() + 7 * _tickLength; + while (waitEnd > _system->getMillis() && _charSelection == -1 && !_quitFlag && !skipFlag()) { + _charSelection = getCharSelection(); + _system->delayMillis(10); + } + + index = (index + 1) % 22; + } + + resetSkipFlag(); + + _chargenWSA->displayFrame(0x10, 0, 0, 0); + _screen->updateScreen(); + _sound->voiceStop("KING01"); +} + +void LoLEngine::kingSelectionReminder() { + debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionReminder()"); + + _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK); + int y = 48; + + _screen->fprintStringIntro(_tim->getCTableEntry(62), 8, y, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(63), 8, y + 10, 0x32, 0x00, 0x9C, 0x20); + + _sound->voicePlay("KING02"); + + _chargenWSA->setX(113); + _chargenWSA->setY(0); + _chargenWSA->setDrawPage(0); + + int index = 0; + while (_sound->voiceIsPlaying("KING02") && _charSelection == -1 && !_quitFlag && index < 15) { + _chargenWSA->displayFrame(_chargenFrameTable[index+9], 0, 0, 0); + _screen->copyRegion(_selectionPosTable[_reminderChar1IdxTable[index]*2+0], _selectionPosTable[_reminderChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0); + _screen->copyRegion(_selectionPosTable[_reminderChar2IdxTable[index]*2+0], _selectionPosTable[_reminderChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0); + _screen->copyRegion(_selectionPosTable[_reminderChar3IdxTable[index]*2+0], _selectionPosTable[_reminderChar3IdxTable[index]*2+1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0); + _screen->copyRegion(_selectionPosTable[_reminderChar4IdxTable[index]*2+0], _selectionPosTable[_reminderChar4IdxTable[index]*2+1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0); + _screen->updateScreen(); + + uint32 waitEnd = _system->getMillis() + 8 * _tickLength; + while (waitEnd > _system->getMillis() && !_quitFlag) { + _charSelection = getCharSelection(); + _system->delayMillis(10); + } + + index = (index + 1) % 22; + } + + _sound->voiceStop("KING02"); +} + +void LoLEngine::kingSelectionOutro() { + debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionOutro()"); + + _sound->voicePlay("KING03"); + + _chargenWSA->setX(113); + _chargenWSA->setY(0); + _chargenWSA->setDrawPage(0); + + int index = 0; + while (_sound->voiceIsPlaying("KING03") && !_quitFlag && !skipFlag()) { + index = MAX(index, 4); + + _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 0, 0); + _screen->updateScreen(); + + uint32 waitEnd = _system->getMillis() + 8 * _tickLength; + while (waitEnd > _system->getMillis() && !_quitFlag && !skipFlag()) { + updateInput(); + _system->delayMillis(10); + } + + index = (index + 1) % 22; + } + + resetSkipFlag(); + + _chargenWSA->displayFrame(0x10, 0, 0, 0); + _screen->updateScreen(); + _sound->voiceStop("KING03"); +} + +void LoLEngine::processCharacterSelection() { + debugC(9, kDebugLevelMain, "LoLEngine::processCharacterSelection()"); + + _charSelection = -1; + while (!_quitFlag && _charSelection == -1) { + uint32 nextKingMessage = _system->getMillis() + 900 * _tickLength; + + while (nextKingMessage > _system->getMillis() && _charSelection == -1 && !_quitFlag) { + updateSelectionAnims(); + _charSelection = getCharSelection(); + _system->delayMillis(10); + } + + if (_charSelection == -1) + kingSelectionReminder(); + } +} + +void LoLEngine::updateSelectionAnims() { + debugC(9, kDebugLevelMain, "LoLEngine::updateSelectionAnims()"); + + for (int i = 0; i < 4; ++i) { + if (_system->getMillis() < _selectionAnimTimers[i]) + continue; + + const int index = _selectionAnimIndexTable[_selectionAnimFrames[i] + i * 2]; + _screen->copyRegion(_selectionPosTable[index*2+0], _selectionPosTable[index*2+1], _charPreviews[i].x, _charPreviews[i].y, 32, 32, 4, 0); + + int delayTime = 0; + if (_selectionAnimFrames[i] == 1) + delayTime = _rnd.getRandomNumberRng(0, 31) + 80; + else + delayTime = _rnd.getRandomNumberRng(0, 3) + 10; + + _selectionAnimTimers[i] = _system->getMillis() + delayTime * _tickLength; + _selectionAnimFrames[i] = (_selectionAnimFrames[i] + 1) % 2; + } + + _screen->updateScreen(); +} + +int LoLEngine::selectionCharInfo(int character) { + debugC(9, kDebugLevelMain, "LoLEngine::selectionCharInfo(%d)", character); + if (character < 0) + return -1; + + char filename[16]; + char vocFilename[6]; + strcpy(vocFilename, "000X0"); + + switch (character) { + case 0: + strcpy(filename, "face09.shp"); + vocFilename[3] = 'A'; + break; + + case 1: + strcpy(filename, "face01.shp"); + vocFilename[3] = 'M'; + break; + + case 2: + strcpy(filename, "face08.shp"); + vocFilename[3] = 'K'; + break; + + case 3: + strcpy(filename, "face05.shp"); + vocFilename[3] = 'C'; + break; + + default: + break; + }; + + _screen->loadBitmap(filename, 9, 9, 0); + _screen->copyRegion(0, 122, 0, 122, 320, 78, 4, 0, Screen::CR_NO_P_CHECK); + _screen->copyRegion(_charPreviews[character].x - 3, _charPreviews[character].y - 3, 8, 127, 38, 38, 2, 0); + + static const uint8 charSelectInfoIdx[] = { 0x1D, 0x22, 0x27, 0x2C }; + const int idx = charSelectInfoIdx[character]; + + _screen->fprintStringIntro(_tim->getCTableEntry(idx+0), 50, 127, 0x53, 0x00, 0xCF, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(idx+1), 50, 137, 0x53, 0x00, 0xCF, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(idx+2), 50, 147, 0x53, 0x00, 0xCF, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(idx+3), 50, 157, 0x53, 0x00, 0xCF, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(idx+4), 50, 167, 0x53, 0x00, 0xCF, 0x20); + + _screen->fprintStringIntro(_tim->getCTableEntry(69), 100, 168, 0x32, 0x00, 0xCF, 0x20); + + selectionCharInfoIntro(vocFilename); + if (_charSelectionInfoResult == -1) { + while (_charSelectionInfoResult == -1) { + _charSelectionInfoResult = selectionCharAccept(); + _system->delayMillis(10); + } + } + + if (_charSelectionInfoResult != 1) { + _charSelectionInfoResult = -1; + _screen->copyRegion(0, 122, 0, 122, 320, 78, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + return -1; + } + + _screen->copyRegion(48, 127, 48, 127, 272, 60, 4, 0, Screen::CR_NO_P_CHECK); + _screen->hideMouse(); + _screen->copyRegion(48, 127, 48, 160, 272, 35, 4, 0, Screen::CR_NO_P_CHECK); + _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK); + + _screen->fprintStringIntro(_tim->getCTableEntry(64), 3, 28, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(65), 3, 38, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(66), 3, 48, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(67), 3, 58, 0x32, 0x00, 0x9C, 0x20); + _screen->fprintStringIntro(_tim->getCTableEntry(68), 3, 68, 0x32, 0x00, 0x9C, 0x20); + + resetSkipFlag(); + kingSelectionOutro(); + return character; +} + +void LoLEngine::selectionCharInfoIntro(char *file) { + debugC(9, kDebugLevelMain, "LoLEngine::selectionCharInfoIntro(%p)", (const void *)file); + int index = 0; + file[4] = '0'; + + while (_charSelectionInfoResult == -1 && !_quitFlag) { + if (!_sound->voicePlay(file)) + break; + + int i = 0; + while (_sound->voiceIsPlaying(file) && _charSelectionInfoResult == -1 && !_quitFlag) { + _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), _charInfoFrameTable[i]), 11, 130, 0, 0); + _screen->updateScreen(); + + uint32 nextFrame = _system->getMillis() + 8 * _tickLength; + while (nextFrame > _system->getMillis() && _charSelectionInfoResult == -1) { + _charSelectionInfoResult = selectionCharAccept(); + _system->delayMillis(10); + } + + i = (i + 1) % 32; + } + + _sound->voiceStop(file); + file[4] = ++index + '0'; + } + + _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), 0), 11, 130, 0, 0); + _screen->updateScreen(); +} + +int LoLEngine::getCharSelection() { + int inputFlag = checkInput() & 0xCF; + removeInputTop(); + + if (inputFlag == 200) { + for (int i = 0; i < 4; ++i) { + if (_charPreviews[i].x <= _mouseX && _mouseX <= _charPreviews[i].x + 31 && + _charPreviews[i].y <= _mouseY && _mouseY <= _charPreviews[i].y + 31) + return i; + } + } + + return -1; +} + +int LoLEngine::selectionCharAccept() { + int inputFlag = checkInput() & 0xCF; + removeInputTop(); + + if (inputFlag == 200) { + if (88 <= _mouseX && _mouseX <= 128 && 180 <= _mouseY && _mouseY <= 194) + return 1; + if (196 <= _mouseX && _mouseX <= 236 && 180 <= _mouseY && _mouseY <= 194) + return 0; + } + + return -1; +} + +#pragma mark - Opcodes + +typedef Common::Functor2Mem TIMOpcodeLoL; +#define SetTimOpcodeTable(x) timTable = &x; +#define OpcodeTim(x) timTable->push_back(new TIMOpcodeLoL(this, &LoLEngine::x)) +#define OpcodeTimUnImpl() timTable->push_back(new TIMOpcodeLoL(this, 0)) + +void LoLEngine::setupOpcodeTable() { + Common::Array *timTable = 0; + + SetTimOpcodeTable(_timIntroOpcodes); + + // 0x00 + OpcodeTim(tlol_setupPaletteFade); + OpcodeTimUnImpl(); + OpcodeTim(tlol_loadPalette); + OpcodeTim(tlol_setupPaletteFadeEx); + + // 0x04 + OpcodeTim(tlol_processWsaFrame); + OpcodeTim(tlol_displayText); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); +} + +#pragma mark - + +int LoLEngine::tlol_setupPaletteFade(const TIM *tim, const uint16 *param) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::t2_playSoundEffect(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]); + _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff); + _tim->_palDelayAcc = 0; + return 1; +} + +int LoLEngine::tlol_loadPalette(const TIM *tim, const uint16 *param) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_loadPalette(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]); + const char *palFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1))); + _res->loadFileToBuf(palFile, _screen->getPalette(0), 768); + return 1; +} + +int LoLEngine::tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_setupPaletteFadeEx(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]); + memcpy(_screen->getPalette(0), _screen->getPalette(1), 768); + + _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff); + _tim->_palDelayAcc = 0; + return 1; +} + +int LoLEngine::tlol_processWsaFrame(const TIM *tim, const uint16 *param) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_processWsaFrame(%p, %p) (%d, %d, %d, %d, %d)", + (const void*)tim, (const void*)param, param[0], param[1], param[2], param[3], param[4]); + TIMInterpreter::Animation *anim = (TIMInterpreter::Animation *)tim->wsa[param[0]].anim; + const int frame = param[1]; + const int x2 = param[2]; + const int y2 = param[3]; + const int factor = MAX(0, (int16)param[4]); + + const int x1 = anim->x; + const int y1 = anim->y; + + int w1 = anim->wsa->width(); + int h1 = anim->wsa->height(); + int w2 = (w1 * factor) / 100; + int h2 = (h1 * factor) / 100; + + anim->wsa->setDrawPage(2); + anim->wsa->setX(x1); + anim->wsa->setY(y1); + anim->wsa->displayFrame(frame, anim->wsaCopyParams & 0xF0FF, 0, 0); + _screen->wsaFrameAnimationStep(x1, y1, x2, y2, w1, h1, w2, h2, 2, 8, 0); + _screen->checkedPageUpdate(8, 4); + _screen->updateScreen(); + + return 1; +} + +int LoLEngine::tlol_displayText(const TIM *tim, const uint16 *param) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_displayText(%p, %p) (%d, %d)", (const void*)tim, (const void*)param, param[0], (int16)param[1]); + _tim->displayText(param[0], param[1]); + return 1; +} + +} // end of namespace Kyra + diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h new file mode 100644 index 0000000000..ee54f8abbb --- /dev/null +++ b/engines/kyra/lol.h @@ -0,0 +1,155 @@ +/* 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 KYRA_LOL_H +#define KYRA_LOL_H + +#include "kyra/kyra_v1.h" +#include "kyra/script_tim.h" + +#include "common/list.h" + +namespace Kyra { + +class Screen_LoL; +class WSAMovie_v2; +struct Button; + +class LoLEngine : public KyraEngine_v1 { +public: + LoLEngine(OSystem *system, const GameFlags &flags); + ~LoLEngine(); + + Screen *screen(); +private: + Screen_LoL *_screen; + TIMInterpreter *_tim; + + int init(); + int go(); + + // input + void updateInput(); + int checkInput(Button *buttonList = 0, bool mainLoop = false); + void removeInputTop(); + + int _mouseX, _mouseY; + + struct Event { + Common::Event event; + bool causedSkip; + + Event() : event(), causedSkip(false) {} + Event(Common::Event e) : event(e), causedSkip(false) {} + Event(Common::Event e, bool skip) : event(e), causedSkip(skip) {} + + operator Common::Event() const { return event; } + }; + Common::List _eventList; + + virtual bool skipFlag() const; + virtual void resetSkipFlag(bool removeEvent = true); + + // intro + void setupPrologueData(bool load); + + void showIntro(); + + struct CharacterPrev { + const char *name; + int x, y; + int attrib[3]; + }; + + static const CharacterPrev _charPreviews[]; + + WSAMovie_v2 *_chargenWSA; + static const uint8 _chargenFrameTable[]; + int chooseCharacter(); + + void kingSelectionIntro(); + void kingSelectionReminder(); + void kingSelectionOutro(); + void processCharacterSelection(); + void updateSelectionAnims(); + int selectionCharInfo(int character); + void selectionCharInfoIntro(char *file); + + int getCharSelection(); + int selectionCharAccept(); + + int _charSelection; + int _charSelectionInfoResult; + + uint32 _selectionAnimTimers[4]; + uint8 _selectionAnimFrames[4]; + static const uint8 _selectionAnimIndexTable[]; + + static const uint16 _selectionPosTable[]; + + static const uint8 _selectionChar1IdxTable[]; + static const uint8 _selectionChar2IdxTable[]; + static const uint8 _selectionChar3IdxTable[]; + static const uint8 _selectionChar4IdxTable[]; + + static const uint8 _reminderChar1IdxTable[]; + static const uint8 _reminderChar2IdxTable[]; + static const uint8 _reminderChar3IdxTable[]; + static const uint8 _reminderChar4IdxTable[]; + + static const uint8 _charInfoFrameTable[]; + + // timer + void setupTimers() {} + + // sound + void snd_playVoiceFile(int) { /* XXX */ } + + // opcode + void setupOpcodeTable(); + + Common::Array _timIntroOpcodes; + int tlol_setupPaletteFade(const TIM *tim, const uint16 *param); + int tlol_loadPalette(const TIM *tim, const uint16 *param); + int tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param); + int tlol_processWsaFrame(const TIM *tim, const uint16 *param); + int tlol_displayText(const TIM *tim, const uint16 *param); + + // translation + int _lang; + + static const char * const _languageExt[]; + + // unneeded + void setWalkspeed(uint8) {} + void setHandItem(uint16) {} + void removeHandItem() {} + bool lineIsPassable(int, int) { return false; } +}; + +} // end of namespace Kyra + +#endif + diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index ebb63b4b4e..e059a8ce4b 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -21,6 +21,7 @@ MODULE_OBJS := \ kyra_v2.o \ kyra_hof.o \ kyra_mr.o \ + lol.o \ resource.o \ saveload.o \ saveload_lok.o \ @@ -33,6 +34,7 @@ MODULE_OBJS := \ scene_mr.o \ screen.o \ screen_lok.o \ + screen_lol.o \ screen_v2.o \ screen_hof.o \ screen_mr.o \ diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index afd7eacfda..92818aafe1 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -55,10 +55,12 @@ bool Resource::reset() { if (!dir.exists() || !dir.isDirectory()) error("invalid game path '%s'", dir.getPath().c_str()); - if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) { - Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website"; - _vm->GUIErrorMessage(errorMessage); - error(errorMessage.c_str()); + if (_vm->game() != GI_LOL) { + if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) { + Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website"; + _vm->GUIErrorMessage(errorMessage); + error(errorMessage.c_str()); + } } if (_vm->game() == GI_KYRA1) { @@ -98,6 +100,8 @@ bool Resource::reset() { loadFileList("FILEDATA.FDT"); + return true; + } else if (_vm->game() == GI_LOL) { return true; } @@ -1120,7 +1124,7 @@ bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) { const uint8 *tbl1 = _tables[srcIndex]; - const uint8 *tbl2 = _tables[dstIndex]; + uint8 *tbl2 = _tables[dstIndex]; const uint8 *tbl3 = dstIndex2 == 0xff ? 0 : _tables[dstIndex2]; if (!cnt) @@ -1185,7 +1189,7 @@ void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex } } - memset((void*) tbl2, 0, 512); + memset(tbl2, 0, 512); cnt--; s = tbl1 + cnt; diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp new file mode 100644 index 0000000000..c6b47a9ca9 --- /dev/null +++ b/engines/kyra/screen_lol.cpp @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "kyra/screen_lol.h" +#include "kyra/lol.h" + +namespace Kyra { + +Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _vm(vm) { +} + +void Screen_LoL::setScreenDim(int dim) { + debugC(9, kDebugLevelScreen, "Screen_LoL::setScreenDim(%d)", dim); + assert(dim < _screenDimTableCount); + _curDim = &_screenDimTable[dim]; +} + +const ScreenDim *Screen_LoL::getScreenDim(int dim) { + debugC(9, kDebugLevelScreen, "Screen_LoL::getScreenDim(%d)", dim); + assert(dim < _screenDimTableCount); + return &_screenDimTable[dim]; +} + +void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...) { + debugC(9, kDebugLevelScreen, "Screen_LoL::fprintStringIntro('%s', %d, %d, %d, %d, %d, %d, ...)", format, x, y, c1, c2, c3, flags); + char buffer[400]; + + va_list args; + va_start(args, flags); + vsprintf(buffer, format, args); + va_end(args); + + if ((flags & 0x0F00) == 0x100) + x -= getTextWidth(buffer) >> 1; + if ((flags & 0x0F00) == 0x200) + x -= getTextWidth(buffer); + + if ((flags & 0x00F0) == 0x20) { + printText(buffer, x-1, y, c3, c2); + printText(buffer, x, y+1, c3, c2); + } + + printText(buffer, x, y, c1, c2); +} + +} // end of namespace Kyra + diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h new file mode 100644 index 0000000000..38df3ca897 --- /dev/null +++ b/engines/kyra/screen_lol.h @@ -0,0 +1,53 @@ +/* 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 KYRA_SCREEN_LOL_H +#define KYRA_SCREEN_LOL_H + +#include "kyra/screen_v2.h" + +namespace Kyra { + +class LoLEngine; + +class Screen_LoL : public Screen_v2 { +public: + Screen_LoL(LoLEngine *vm, OSystem *system); + + void setScreenDim(int dim); + const ScreenDim *getScreenDim(int dim); + + void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...); +private: + LoLEngine *_vm; + + static const ScreenDim _screenDimTable[]; + static const int _screenDimTableCount; +}; + +} // end of namespace Kyra + +#endif + diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp index e5d851aeab..c6ea6a93e8 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -485,5 +485,27 @@ bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, i return (w1 == -1) ? false : true; } +void Screen_v2::checkedPageUpdate(int srcPage, int dstPage) { + debugC(9, kDebugLevelScreen, "Screen_v2::checkedPageUpdate(%d, %d)", srcPage, dstPage); + + const uint32 *src = (const uint32 *)getPagePtr(srcPage); + uint32 *dst = (uint32 *)getPagePtr(dstPage); + uint32 *page0 = (uint32 *)getPagePtr(0); + + bool updated = false; + + for (int y = 0; y < 200; ++y) { + for (int x = 0; x < 80; ++x, ++src, ++dst, ++page0) { + if (*src != *dst) { + updated = true; + *dst = *page0 = *src; + } + } + } + + if (updated) + addDirtyRect(0, 0, 320, 200); +} + } // end of namespace Kyra diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h index 3283526ee3..7bbdc4b6c3 100644 --- a/engines/kyra/screen_v2.h +++ b/engines/kyra/screen_v2.h @@ -40,6 +40,8 @@ public: void copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src, int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2); + void checkedPageUpdate(int srcPage, int dstPage); + // palette handling uint8 *generateOverlay(const uint8 *palette, uint8 *buffer, int color, uint16 factor); void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay); diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 4b82232049..b8fc6713a6 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -26,12 +26,14 @@ #include "kyra/script_tim.h" #include "kyra/script.h" #include "kyra/resource.h" +#include "kyra/sound.h" +#include "kyra/wsamovie.h" #include "common/endian.h" namespace Kyra { -TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) { +TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system) : _vm(vm), _screen(screen), _system(system), _currentTim(0) { #define COMMAND(x) { &TIMInterpreter::x, #x } #define COMMAND_UNIMPL() { 0, 0 } #define cmd_return(n) cmd_return_##n @@ -39,32 +41,32 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s // 0x00 COMMAND(cmd_initFunc0), COMMAND(cmd_stopCurFunc), - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), + COMMAND(cmd_initWSA), + COMMAND(cmd_uninitWSA), // 0x04 COMMAND(cmd_initFunc), COMMAND(cmd_stopFunc), - COMMAND_UNIMPL(), + COMMAND(cmd_wsaDisplayFrame), COMMAND_UNIMPL(), // 0x08 - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), + COMMAND(cmd_loadVocFile), + COMMAND(cmd_unloadVocFile), + COMMAND(cmd_playVocFile), COMMAND_UNIMPL(), // 0x0C - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), + COMMAND(cmd_loadSoundFile), + COMMAND(cmd_return(1)), + COMMAND(cmd_playMusicTrack), COMMAND_UNIMPL(), // 0x10 - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), + COMMAND(cmd_return(1)), + COMMAND(cmd_return(1)), COMMAND_UNIMPL(), COMMAND_UNIMPL(), // 0x14 - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), - COMMAND_UNIMPL(), + COMMAND(cmd_setLoopIp), + COMMAND(cmd_continueLoop), + COMMAND(cmd_resetLoopIp), COMMAND(cmd_resetAllRuntimes), // 0x18 COMMAND(cmd_return(1)), @@ -80,6 +82,19 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s _commands = commandProcs; _commandsSize = ARRAYSIZE(commandProcs); + + memset(&_animations, 0, sizeof(_animations)); + _langData = 0; + _textDisplayed = false; + _textAreaBuffer = new uint8[320*40]; + assert(_textAreaBuffer); + + _palDelayInc = _palDiff = _palDelayAcc = 0; +} + +TIMInterpreter::~TIMInterpreter() { + delete[] _langData; + delete[] _textAreaBuffer; } TIM *TIMInterpreter::load(const char *filename, const Common::Array *opcodes) { @@ -139,6 +154,11 @@ void TIMInterpreter::unload(TIM *&tim) const { tim = 0; } +void TIMInterpreter::setLangData(const char *filename) { + delete[] _langData; + _langData = _vm->resource()->fileData(filename, 0); +} + void TIMInterpreter::exec(TIM *tim, bool loop) { if (!tim) return; @@ -175,6 +195,10 @@ void TIMInterpreter::exec(TIM *tim, bool loop) { _currentTim->procFunc = _currentFunc; break; + case 22: + cur.loopIp = 0; + break; + default: break; } @@ -201,6 +225,205 @@ void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) { } } +void TIMInterpreter::displayText(uint16 textId, int16 flags) { + char *text = getTableEntry(textId); + + if (_textDisplayed) { + _screen->copyBlockToPage(0, 0, 160, 320, 40, _textAreaBuffer); + _textDisplayed = false; + } + + if (!text) + return; + if (!text[0]) + return; + + char filename[16]; + memset(filename, 0, sizeof(filename)); + + if (text[0] == '$') { + const char *end = strchr(text+1, '$'); + if (end) + memcpy(filename, text+1, end-1-text); + } + + if (filename[0]) + _vm->sound()->voicePlay(filename); + + if (text[0] == '$') + text = strchr(text + 1, '$') + 1; + + setupTextPalette((flags < 0) ? 1 : flags, 0); + + if (flags < 0) { + static const uint8 colorMap[] = { 0x00, 0xF0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + _screen->setFont(Screen::FID_8_FNT); + _screen->setTextColorMap(colorMap); + _screen->_charWidth = -2; + } + + _screen->_charOffset = -4; + _screen->copyRegionToBuffer(0, 0, 160, 320, 40, _textAreaBuffer); + _textDisplayed = true; + + char backupChar = 0; + char *str = text; + int heightAdd = 0; + + while (str[0]) { + char *nextLine = strchr(str, '\r'); + + backupChar = 0; + if (nextLine) { + backupChar = nextLine[0]; + nextLine[0] = '\0'; + } + + int width = _screen->getTextWidth(str); + + if (flags >= 0) + _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, 0xF0, 0x00); + else + _screen->printText(str, (320 - width) >> 1, 188, 0xF0, 0x00); + + heightAdd += _screen->getFontHeight(); + str += strlen(str); + + if (backupChar) { + nextLine[0] = backupChar; + ++str; + } + } + + _screen->_charOffset = 0; + + if (flags < 0) { + static const uint8 colorMap[] = { 0x00, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00 }; + + _screen->setFont(Screen::FID_INTRO_FNT); + _screen->setTextColorMap(colorMap); + _screen->_charWidth = 0; + } +} + +void TIMInterpreter::setupTextPalette(uint index, int fadePalette) { + static const uint16 palTable[] = { + 0x00, 0x00, 0x00, + 0x64, 0x64, 0x64, + 0x61, 0x51, 0x30, + 0x29, 0x48, 0x64, + 0x00, 0x4B, 0x3B, + 0x64, 0x1E, 0x1E, + }; + + for (int i = 0; i < 15; ++i) { + uint8 *palette = _screen->getPalette(0) + (240 + i) * 3; + + uint8 c1 = (((15 - i) << 2) * palTable[index*3+0]) / 100; + uint8 c2 = (((15 - i) << 2) * palTable[index*3+1]) / 100; + uint8 c3 = (((15 - i) << 2) * palTable[index*3+2]) / 100; + + palette[0] = c1; + palette[1] = c2; + palette[2] = c3; + } + + if (!fadePalette && !_palDiff) { + _screen->setScreenPalette(_screen->getPalette(0)); + } else { + _screen->getFadeParams(_screen->getPalette(0), fadePalette, _palDelayInc, _palDiff); + _palDelayAcc = 0; + } +} + +TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags) { + Animation *anim = &_animations[index]; + anim->x = x; + anim->y = y; + anim->wsaCopyParams = wsaFlags; + + uint16 wsaOpenFlags = ((wsaFlags & 0x10) != 0) ? 2 : 0; + + char file[32]; + snprintf(file, 32, "%s.WSA", filename); + + if (_vm->resource()->exists(file)) { + anim->wsa = new WSAMovie_v2(_vm, _screen); + assert(anim->wsa); + + anim->wsa->open(file, wsaOpenFlags, (index == 1) ? _screen->getPalette(0) : 0); + } + + if (anim->wsa && anim->wsa->opened()) { + if (x == -1) + anim->x = x = 0; + if (y == -1) + anim->y = y = 0; + + if (wsaFlags & 2) { + _screen->fadePalette(_screen->getPalette(1), 15, 0); + _screen->clearPage(8); + _screen->checkedPageUpdate(8, 4); + _screen->updateScreen(); + } + + if (wsaFlags & 4) { + snprintf(file, 32, "%s.CPS", filename); + + if (_vm->resource()->exists(file)) { + _screen->loadBitmap(file, 3, 3, _screen->getPalette(0)); + _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 8, Screen::CR_NO_P_CHECK); + _screen->checkedPageUpdate(8, 4); + _screen->updateScreen(); + } + + anim->wsa->setX(x); + anim->wsa->setY(y); + anim->wsa->setDrawPage(0); + anim->wsa->displayFrame(0, 0, 0, 0); + } + + if (wsaFlags & 2) + _screen->fadePalette(_screen->getPalette(0), 30, 0); + } else { + if (wsaFlags & 2) { + _screen->fadePalette(_screen->getPalette(1), 15, 0); + _screen->clearPage(8); + _screen->checkedPageUpdate(8, 4); + _screen->updateScreen(); + } + + snprintf(file, 32, "%s.CPS", filename); + + if (_vm->resource()->exists(file)) { + _screen->loadBitmap(file, 3, 3, _screen->getPalette(0)); + _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 8, Screen::CR_NO_P_CHECK); + _screen->checkedPageUpdate(8, 4); + _screen->updateScreen(); + } + + if (wsaFlags & 2) + _screen->fadePalette(_screen->getPalette(0), 30, 0); + } + + return anim; +} + +char *TIMInterpreter::getTableEntry(uint idx) { + if (!_langData) + return 0; + else + return (char *)(_langData + READ_LE_UINT16(_langData + (idx<<1))); +} + +const char *TIMInterpreter::getCTableEntry(uint idx) const { + if (!_langData) + return 0; + else + return (const char *)(_langData + READ_LE_UINT16(_langData + (idx<<1))); +} + int TIMInterpreter::execCommand(int cmd, const uint16 *param) { if (cmd < 0 || cmd >= _commandsSize) { warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename); @@ -212,11 +435,14 @@ int TIMInterpreter::execCommand(int cmd, const uint16 *param) { return 0; } - debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void*)param); + debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void* )param); return (this->*_commands[cmd].proc)(param); } int TIMInterpreter::cmd_initFunc0(const uint16 *param) { + for (int i = 0; i < TIM::kWSASlots; ++i) + memset(&_currentTim->wsa[i], 0, sizeof(TIM::WSASlot)); + _currentTim->func[0].ip = _currentTim->func[0].avtl; _currentTim->func[0].lastTime = _system->getMillis(); return 1; @@ -230,6 +456,46 @@ int TIMInterpreter::cmd_stopCurFunc(const uint16 *param) { return -2; } +int TIMInterpreter::cmd_initWSA(const uint16 *param) { + const int index = param[0]; + + TIM::WSASlot &slot = _currentTim->wsa[index]; + + slot.x = int16(param[2]); + slot.y = int16(param[3]); + slot.offscreen = param[4]; + slot.wsaFlags = param[5]; + const char *filename = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[1]<<1))); + + slot.anim = initAnimStruct(index, filename, slot.x, slot.y, 10, slot.offscreen, slot.wsaFlags); + return 1; +} + +int TIMInterpreter::cmd_uninitWSA(const uint16 *param) { + const int index = param[0]; + + TIM::WSASlot &slot = _currentTim->wsa[index]; + + if (!slot.anim) + return 0; + + Animation &anim = _animations[index]; + + if (slot.offscreen) { + delete anim.wsa; + anim.wsa = 0; + slot.anim = 0; + } else { + //XXX + + delete anim.wsa; + memset(&anim, 0, sizeof(Animation)); + memset(&slot, 0, sizeof(TIM::WSASlot)); + } + + return 1; +} + int TIMInterpreter::cmd_initFunc(const uint16 *param) { uint16 func = *param; assert(func < TIM::kCountFuncs); @@ -247,6 +513,97 @@ int TIMInterpreter::cmd_stopFunc(const uint16 *param) { return 1; } +int TIMInterpreter::cmd_wsaDisplayFrame(const uint16 *param) { + Animation &anim = _animations[param[0]]; + const int frame = param[1]; + + anim.wsa->setX(anim.x); + anim.wsa->setY(anim.y); + anim.wsa->setDrawPage((anim.wsaCopyParams & 0x4000) != 0 ? 2 : 8); + anim.wsa->displayFrame(frame, anim.wsaCopyParams & 0xF0FF, 0, 0); + return 1; +} + +int TIMInterpreter::cmd_displayText(const uint16 *param) { + displayText(param[0], param[1]); + return 1; +} + +int TIMInterpreter::cmd_loadVocFile(const uint16 *param) { + const int stringId = param[0]; + const int index = param[1]; + + _vocFiles[index] = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (stringId << 1))); + for (int i = 0; i < 4; ++i) + _vocFiles[index].deleteLastChar(); + return 1; +} + +int TIMInterpreter::cmd_unloadVocFile(const uint16 *param) { + const int index = param[0]; + _vocFiles[index].clear(); + return 1; +} + +int TIMInterpreter::cmd_playVocFile(const uint16 *param) { + const int index = param[0]; + const int volume = (param[1] * 255) / 100; + + if (index < ARRAYSIZE(_vocFiles) && !_vocFiles[index].empty()) + _vm->sound()->voicePlay(_vocFiles[index].c_str()/*, volume*/, true); + else + _vm->snd_playSoundEffect(index, volume); + + return 1; +} + +int TIMInterpreter::cmd_loadSoundFile(const uint16 *param) { + const char *file = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[0]<<1))); + + static char * fileList[] = { 0 }; + fileList[0] = _audioFilename; + static AudioDataStruct audioList = { fileList, 1, 0, 0 }; + + strncpy(_audioFilename, file, sizeof(_audioFilename)); + + _vm->sound()->setSoundList(&audioList); + _vm->sound()->loadSoundFile(0); + return 1; +} + +int TIMInterpreter::cmd_playMusicTrack(const uint16 *param) { + _vm->sound()->playTrack(param[0]); + return 1; +} + +int TIMInterpreter::cmd_setLoopIp(const uint16 *param) { + _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip; + return 1; +} + +int TIMInterpreter::cmd_continueLoop(const uint16 *param) { + TIM::Function &func = _currentTim->func[_currentFunc]; + + if (!func.loopIp) + return -2; + + func.ip = func.loopIp; + + uint16 factor = param[0]; + if (factor) { + const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000); + uint32 waitTime = (random * factor) / 0x8000; + func.nextTime += waitTime * _vm->tickLength(); + } + + return 1; +} + +int TIMInterpreter::cmd_resetLoopIp(const uint16 *param) { + _currentTim->func[_currentFunc].loopIp = 0; + return 1; +} + int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) { for (int i = 0; i < TIM::kCountFuncs; ++i) { if (_currentTim->func[i].ip) @@ -256,17 +613,25 @@ int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) { } int TIMInterpreter::cmd_execOpcode(const uint16 *param) { + const uint16 opcode = *param++; + if (!_currentTim->opcodes) { - warning("Trying to execute TIM opcode without opcode list"); + warning("Trying to execute TIM opcode %d without opcode list (file '%s')", opcode, _currentTim->filename); + fflush(stderr); fflush(stdout); return 0; } - uint16 opcode = *param++; if (opcode > _currentTim->opcodes->size()) { warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename); return 0; } + if (!(*_currentTim->opcodes)[opcode]->isValid()) { + warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename); + fflush(stderr); + return 0; + } + return (*(*_currentTim->opcodes)[opcode])(_currentTim, param); } diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index 39a1d90a44..68ef23fd6c 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -30,9 +30,12 @@ #include "common/array.h" #include "common/func.h" +#include "common/str.h" namespace Kyra { +class WSAMovie_v2; +class Screen_v2; struct TIM; typedef Common::Functor2 TIMOpcode; @@ -52,9 +55,23 @@ struct TIM { uint32 lastTime; uint32 nextTime; + const uint16 *loopIp; + const uint16 *avtl; } func[kCountFuncs]; + enum { + kWSASlots = 10 + }; + + struct WSASlot { + void *anim; + + int16 x, y; + uint16 wsaFlags; + uint16 offscreen; + } wsa[kWSASlots]; + uint16 *avtl; uint8 *text; @@ -63,10 +80,22 @@ struct TIM { class TIMInterpreter { public: - TIMInterpreter(KyraEngine_v1 *vm, OSystem *system); + struct Animation { + WSAMovie_v2 *wsa; + int16 x, y; + uint16 wsaCopyParams; + }; + + TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system); + ~TIMInterpreter(); TIM *load(const char *filename, const Common::Array *opcodes); void unload(TIM *&tim) const; + + void setLangData(const char *filename); + void clearLangData() { delete[] _langData; _langData = 0; } + + const char *getCTableEntry(uint idx) const; void resetFinishedFlag() { _finished = false; } bool finished() const { return _finished; } @@ -74,10 +103,15 @@ public: void exec(TIM *tim, bool loop); void stopCurFunc() { if (_currentTim) cmd_stopCurFunc(0); } - void play(const char *filename); void refreshTimersAfterPause(uint32 elapsedTime); + + void displayText(uint16 textId, int16 flags); + void setupTextPalette(uint index, int fadePalette); + + int _palDelayInc, _palDiff, _palDelayAcc; private: KyraEngine_v1 *_vm; + Screen_v2 *_screen; OSystem *_system; TIM *_currentTim; @@ -85,6 +119,19 @@ private: bool _finished; + Common::String _vocFiles[120]; + + Animation _animations[TIM::kWSASlots]; + + Animation *initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags); + + char _audioFilename[32]; + + uint8 *_langData; + char *getTableEntry(uint idx); + bool _textDisplayed; + uint8 *_textAreaBuffer; + int execCommand(int cmd, const uint16 *param); typedef int (TIMInterpreter::*CommandProc)(const uint16 *); @@ -98,8 +145,20 @@ private: int cmd_initFunc0(const uint16 *param); int cmd_stopCurFunc(const uint16 *param); + int cmd_initWSA(const uint16 *param); + int cmd_uninitWSA(const uint16 *param); int cmd_initFunc(const uint16 *param); int cmd_stopFunc(const uint16 *param); + int cmd_wsaDisplayFrame(const uint16 *param); + int cmd_displayText(const uint16 *param); + int cmd_loadVocFile(const uint16 *param); + int cmd_unloadVocFile(const uint16 *param); + int cmd_playVocFile(const uint16 *param); + int cmd_loadSoundFile(const uint16 *param); + int cmd_playMusicTrack(const uint16 *param); + int cmd_setLoopIp(const uint16 *param); + int cmd_continueLoop(const uint16 *param); + int cmd_resetLoopIp(const uint16 *param); int cmd_resetAllRuntimes(const uint16 *param); int cmd_execOpcode(const uint16 *param); int cmd_initFuncNow(const uint16 *param); diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 68a2f0be9c..0ceb288b8a 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -235,6 +235,10 @@ private: // * One for instruments, starting at offset 500. uint8 *getProgram(int progId) { + uint16 offset = READ_LE_UINT16(_soundData + 2 * progId); + //TODO: Check in LoL CD Adlib driver + if (offset == 0xFFFF) + return 0; return _soundData + READ_LE_UINT16(_soundData + 2 * progId); } @@ -1282,6 +1286,9 @@ int AdlibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va return 0; uint8 *ptr = getProgram(value); + //TODO: Check in LoL CD Adlib driver + if (!ptr) + return 0; uint8 chan = *ptr++; uint8 priority = *ptr++; @@ -2213,7 +2220,7 @@ const int SoundAdlibPC::_kyra1NumSoundTriggers = ARRAYSIZE(SoundAdlibPC::_kyra1S SoundAdlibPC::SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) { memset(_trackEntries, 0, sizeof(_trackEntries)); - _v2 = (_vm->gameFlags().gameID == GI_KYRA2); + _v2 = (_vm->gameFlags().gameID == GI_KYRA2) || (_vm->gameFlags().gameID == GI_LOL); _driver = new AdlibDriver(mixer, _v2); assert(_driver); diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index c05795dacd..9a4b40902e 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -23,16 +23,17 @@ * */ - #include "common/endian.h" #include "common/md5.h" #include "kyra/kyra_v1.h" #include "kyra/kyra_lok.h" +#include "kyra/lol.h" #include "kyra/kyra_v2.h" #include "kyra/kyra_hof.h" #include "kyra/kyra_mr.h" #include "kyra/screen.h" #include "kyra/screen_lok.h" +#include "kyra/screen_lol.h" #include "kyra/screen_hof.h" #include "kyra/screen_mr.h" #include "kyra/resource.h" @@ -287,8 +288,10 @@ bool StaticResource::init() { } else if (_vm->game() == GI_KYRA3) { _builtIn = 0; _filenameTable = kyra3StaticRes; + } else if (_vm->game() == GI_LOL) { + return true; } else { - error("unknown game ID"); + error("StaticResource: Unknown game ID"); } char errorBuffer[100]; @@ -2236,5 +2239,105 @@ const int8 KyraEngine_MR::_albumWSAY[] = { -1, -2, 2, 2, -6, -6, -6, 0 }; +// lands of lore static res + +const ScreenDim Screen_LoL::_screenDimTable[] = { + { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 } +}; + +const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable); + +const char * const LoLEngine::_languageExt[] = { + "ENG", + "FRE", + "GER" +}; + +const LoLEngine::CharacterPrev LoLEngine::_charPreviews[] = { + { "Ak\'shel", 0x060, 0x7F, { 0x0F, 0x08, 0x05 } }, + { "Michael", 0x09A, 0x7F, { 0x06, 0x0A, 0x0F } }, + { "Kieran", 0x0D4, 0x7F, { 0x08, 0x06, 0x08 } }, + { "Conrad", 0x10F, 0x7F, { 0x0A, 0x0C, 0x0A } } +}; + +const uint8 LoLEngine::_chargenFrameTable[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x04, 0x03, 0x02, 0x01, + 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12 +}; + +const uint16 LoLEngine::_selectionPosTable[] = { + 0x6F, 0x00, 0x8F, 0x00, 0xAF, 0x00, 0xCF, 0x00, + 0xEF, 0x00, 0x6F, 0x20, 0x8F, 0x20, 0xAF, 0x20, + 0xCF, 0x20, 0xEF, 0x20, 0x6F, 0x40, 0x8F, 0x40, + 0xAF, 0x40, 0xCF, 0x40, 0xEF, 0x40, 0x10F, 0x00 +}; + +const uint8 LoLEngine::_selectionChar1IdxTable[] = { + 0, 0, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 5, 5, 5, + 5, 5, 5, 5, 0, 0, 5, 5, + 5, 5, 5 +}; + +const uint8 LoLEngine::_selectionChar2IdxTable[] = { + 1, 1, 6, 6, 1, 1, 6, 6, + 6, 6, 6, 6, 6, 1, 1, 6, + 6, 6, 1, 1, 6, 6, 6, 6, + 6, 6, 6 +}; + +const uint8 LoLEngine::_selectionChar3IdxTable[] = { + 2, 2, 7, 7, 7, 7, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 2, + 2, 7, 7, 7, 7, 2, 2, 7, + 7, 7, 7 +}; + +const uint8 LoLEngine::_selectionChar4IdxTable[] = { + 3, 3, 8, 8, 8, 8, 3, 3, + 8, 8, 3, 3, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 3, 3, 8, + 8, 8, 8 +}; + +const uint8 LoLEngine::_reminderChar1IdxTable[] = { + 4, 4, 4, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5 +}; + +const uint8 LoLEngine::_reminderChar2IdxTable[] = { + 9, 9, 9, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6 +}; + +const uint8 LoLEngine::_reminderChar3IdxTable[] = { + 0xE, 0xE, 0xE, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7 +}; + +const uint8 LoLEngine::_reminderChar4IdxTable[] = { + 0xF, 0xF, 0xF, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8 +}; + +const uint8 LoLEngine::_selectionAnimIndexTable[] = { + 0, 5, 1, 6, 2, 7, 3, 8 +}; + +const uint8 LoLEngine::_charInfoFrameTable[] = { + 0x0, 0x7, 0x8, 0x9, 0xA, 0xB, 0xA, 0x9, + 0x8, 0x7, 0x0, 0x0, 0x7, 0x8, 0x9, 0xA, + 0xB, 0xA, 0x9, 0x8, 0x7, 0x0, 0x0, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xA, 0x9, 0x8, 0x7 +}; + } // End of namespace Kyra -- cgit v1.2.3 From eb9462c1a096a9abad8494b8446721a3e82f8bad Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 31 Jul 2008 10:52:29 +0000 Subject: Removed debugging leftover. svn-id: r33464 --- engines/kyra/script_tim.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'engines') diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index b8fc6713a6..7993fb8de6 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -617,7 +617,6 @@ int TIMInterpreter::cmd_execOpcode(const uint16 *param) { if (!_currentTim->opcodes) { warning("Trying to execute TIM opcode %d without opcode list (file '%s')", opcode, _currentTim->filename); - fflush(stderr); fflush(stdout); return 0; } @@ -628,7 +627,6 @@ int TIMInterpreter::cmd_execOpcode(const uint16 *param) { if (!(*_currentTim->opcodes)[opcode]->isValid()) { warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename); - fflush(stderr); return 0; } -- cgit v1.2.3 From 538fdcc61a801573f9f42bf928efe720c5f6bbd9 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 31 Jul 2008 11:29:37 +0000 Subject: Set correct font for dialogues in BRA Amiga. svn-id: r33467 --- engines/parallaction/font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index 2a379828ae..e84dad34aa 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -698,7 +698,7 @@ void Parallaction_br::initFonts() { // fonts/vanya/16 _menuFont = _disk->loadFont("natasha"); - _dialogueFont = _disk->loadFont("sonya"); + _dialogueFont = _disk->loadFont("vanya"); Common::MemoryReadStream stream(_amigaTopazFont, 2600, false); _labelFont = new AmigaFont(stream); } -- cgit v1.2.3 From 591973c827c60648b6d94e2bca44fd1df49ed2f5 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 31 Jul 2008 12:26:12 +0000 Subject: Changed Gfx::_backgroundInfo to be a pointer. This temporarily kills all z-buffering. svn-id: r33468 --- engines/parallaction/callables_ns.cpp | 10 +++--- engines/parallaction/exec_ns.cpp | 2 +- engines/parallaction/gfxbase.cpp | 8 ++--- engines/parallaction/graphics.cpp | 58 +++++++++++++++++------------------ engines/parallaction/graphics.h | 4 +-- engines/parallaction/gui_br.cpp | 10 +++--- engines/parallaction/parallaction.cpp | 4 +-- engines/parallaction/parser_br.cpp | 8 ++--- 8 files changed, 51 insertions(+), 53 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 9cd6b610ff..761e11dc7d 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -291,8 +291,8 @@ void Parallaction_ns::_c_onMouse(void *parm) { void Parallaction_ns::_c_setMask(void *parm) { - memset(_gfx->_backgroundInfo.mask.data + 3600, 0, 3600); - _gfx->_backgroundInfo.layers[1] = 500; + memset(_gfx->_backgroundInfo->mask.data + 3600, 0, 3600); + _gfx->_backgroundInfo->layers[1] = 500; return; } @@ -502,11 +502,11 @@ void Parallaction_ns::_c_shade(void *parm) { _rightHandAnim->_top ); - uint16 _di = r.left/4 + r.top * _gfx->_backgroundInfo.mask.internalWidth; + uint16 _di = r.left/4 + r.top * _gfx->_backgroundInfo->mask.internalWidth; for (uint16 _si = r.top; _si < r.bottom; _si++) { - memset(_gfx->_backgroundInfo.mask.data + _di, 0, r.width()/4+1); - _di += _gfx->_backgroundInfo.mask.internalWidth; + memset(_gfx->_backgroundInfo->mask.data + _di, 0, r.width()/4+1); + _di += _gfx->_backgroundInfo->mask.internalWidth; } return; diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 3e3ee19a03..99a492863b 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -347,7 +347,7 @@ void Parallaction_ns::drawAnimations() { if (anim->_flags & kFlagsNoMasked) layer = 3; else - layer = _gfx->_backgroundInfo.getLayer(anim->_top + anim->height()); + layer = _gfx->_backgroundInfo->getLayer(anim->_top + anim->height()); if (obj) { _gfx->showGfxObj(obj, true); diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index aa02253cb1..1c373dda44 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -291,8 +291,8 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 for (uint16 j = 0; j < q.width(); j++) { if (*s != transparentColor) { - if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { - byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); + if (_backgroundInfo->mask.data && (z < LAYER_FOREGROUND)) { + byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); if (z >= v) *d = 5; } else { *d = 5; @@ -308,13 +308,13 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 } } else { - if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) { + if (_backgroundInfo->mask.data && (z < LAYER_FOREGROUND)) { for (uint16 i = 0; i < q.height(); i++) { for (uint16 j = 0; j < q.width(); j++) { if (*s != transparentColor) { - byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i); + byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); if (z >= v) *d = *s; } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index a31b7f4994..7aa284e82c 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -269,7 +269,7 @@ void Gfx::animatePalette() { PaletteFxRange *range; for (uint16 i = 0; i < 4; i++) { - range = &_backgroundInfo.ranges[i]; + range = &_backgroundInfo->ranges[i]; if ((range->_flags & 1) == 0) continue; // animated palette range->_timer += range->_step * 2; // update timer @@ -359,7 +359,7 @@ void Gfx::clearScreen() { } void Gfx::beginFrame() { - _skipBackground = (_backgroundInfo.bg.pixels == 0); // don't render frame if background is missing + _skipBackground = (_backgroundInfo->bg.pixels == 0); // don't render frame if background is missing if (!_skipBackground) { int32 oldBackgroundMode = _varBackgroundMode; @@ -370,11 +370,11 @@ void Gfx::beginFrame() { _bitmapMask.free(); break; case 2: - _bitmapMask.create(_backgroundInfo.width, _backgroundInfo.height, 1); + _bitmapMask.create(_backgroundInfo->width, _backgroundInfo->height, 1); byte *data = (byte*)_bitmapMask.pixels; for (uint y = 0; y < _bitmapMask.h; y++) { for (uint x = 0; x < _bitmapMask.w; x++) { - *data++ = _backgroundInfo.mask.getValue(x, y); + *data++ = _backgroundInfo->mask.getValue(x, y); } } break; @@ -389,7 +389,7 @@ void Gfx::beginFrame() { warning("Path zones are supported only in Big Red Adventure"); } - if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo.width)) { + if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo->width)) { _varScrollX = 0; } else { _varScrollX = getVar("scroll_x"); @@ -416,22 +416,22 @@ void Gfx::updateScreen() { if (!_skipBackground) { // background may not cover the whole screen, so adjust bulk update size - uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo.width); - uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo.height); + uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo->width); + uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo->height); byte *backgroundData = 0; uint16 backgroundPitch = 0; switch (_varBackgroundMode) { case 1: - backgroundData = (byte*)_backgroundInfo.bg.getBasePtr(_varScrollX, 0); - backgroundPitch = _backgroundInfo.bg.pitch; + backgroundData = (byte*)_backgroundInfo->bg.getBasePtr(_varScrollX, 0); + backgroundPitch = _backgroundInfo->bg.pitch; break; case 2: backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0); backgroundPitch = _bitmapMask.pitch; break; } - g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h); + g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); } if (_varDrawPathZones == 1) { @@ -499,17 +499,17 @@ void Gfx::patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask) Common::Rect r(surf.w, surf.h); r.moveTo(x, y); - uint16 z = (mask) ? _backgroundInfo.getLayer(y) : LAYER_FOREGROUND; - blt(r, (byte*)surf.pixels, &_backgroundInfo.bg, z, 0); + uint16 z = (mask) ? _backgroundInfo->getLayer(y) : LAYER_FOREGROUND; + blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 0); } void Gfx::fillBackground(const Common::Rect& r, byte color) { - _backgroundInfo.bg.fillRect(r, color); + _backgroundInfo->bg.fillRect(r, color); } void Gfx::invertBackground(const Common::Rect& r) { - byte *d = (byte*)_backgroundInfo.bg.getBasePtr(r.left, r.top); + byte *d = (byte*)_backgroundInfo->bg.getBasePtr(r.left, r.top); for (int i = 0; i < r.height(); i++) { for (int j = 0; j < r.width(); j++) { @@ -517,7 +517,7 @@ void Gfx::invertBackground(const Common::Rect& r) { d++; } - d += (_backgroundInfo.bg.pitch - r.width()); + d += (_backgroundInfo->bg.pitch - r.width()); } } @@ -724,7 +724,7 @@ void Gfx::copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surf } void Gfx::grabBackground(const Common::Rect& r, Graphics::Surface &dst) { - copyRect(r, _backgroundInfo.bg, dst); + copyRect(r, _backgroundInfo->bg, dst); } @@ -744,6 +744,8 @@ Gfx::Gfx(Parallaction* vm) : _screenX = 0; _screenY = 0; + _backgroundInfo = 0; + _halfbrite = false; _hbCircleRadius = 0; @@ -766,7 +768,6 @@ Gfx::Gfx(Parallaction* vm) : BackgroundInfo paletteInfo; _disk->loadSlide(paletteInfo, "pointer"); _backupPal.clone(paletteInfo.palette); - paletteInfo.free(); } return; @@ -774,7 +775,8 @@ Gfx::Gfx(Parallaction* vm) : Gfx::~Gfx() { - freeBackground(); + delete _backgroundInfo; + freeLabels(); delete []_unpackedBitmap; @@ -829,16 +831,14 @@ void Gfx::freeItems() { _numItems = 0; } -void Gfx::freeBackground() { - _backgroundInfo.free(); -} void Gfx::setBackground(uint type, const char* name, const char* mask, const char* path) { - freeBackground(); + delete _backgroundInfo; + _backgroundInfo = new BackgroundInfo; if (type == kBackgroundLocation) { - _disk->loadScenery(_backgroundInfo, name, mask, path); + _disk->loadScenery(*_backgroundInfo, name, mask, path); // The PC version of BRA needs the entries 20-31 of the palette to be constant, but // the background resource files are screwed up. The right colors come from an unused @@ -847,17 +847,17 @@ void Gfx::setBackground(uint type, const char* name, const char* mask, const cha int r, g, b; for (uint i = 16; i < 32; i++) { _backupPal.getEntry(i, r, g, b); - _backgroundInfo.palette.setEntry(i, r, g, b); + _backgroundInfo->palette.setEntry(i, r, g, b); } } - setPalette(_backgroundInfo.palette); - _palette.clone(_backgroundInfo.palette); + setPalette(_backgroundInfo->palette); + _palette.clone(_backgroundInfo->palette); } else { - _disk->loadSlide(_backgroundInfo, name); + _disk->loadSlide(*_backgroundInfo, name); for (uint i = 0; i < 6; i++) - _backgroundInfo.ranges[i]._flags = 0; // disable palette cycling for slides - setPalette(_backgroundInfo.palette); + _backgroundInfo->ranges[i]._flags = 0; // disable palette cycling for slides + setPalette(_backgroundInfo->palette); } } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 52b7a4b870..71eaa3724f 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -436,7 +436,7 @@ struct BackgroundInfo { return LAYER_FOREGROUND; } - void free() { + ~BackgroundInfo() { bg.free(); mask.free(); path.free(); @@ -511,7 +511,7 @@ public: void freeItems(); // background surface - BackgroundInfo _backgroundInfo; + BackgroundInfo *_backgroundInfo; void setBackground(uint type, const char* name, const char* mask, const char* path); void patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask = false); void grabBackground(const Common::Rect& r, Graphics::Surface &dst); diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index b10237046e..89226bc9ac 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -65,7 +65,7 @@ public: uint32 curTime = _vm->_system->getMillis(); if (curTime - _startTime > _timeOut) { _fadeSteps = 64; - pal.clone(_vm->_gfx->_backgroundInfo.palette); + pal.clone(_vm->_gfx->_backgroundInfo->palette); } return this; } @@ -73,8 +73,8 @@ public: virtual void enter() { _vm->_gfx->clearScreen(); _vm->_gfx->setBackground(kBackgroundSlide, _slideName.c_str(), 0, 0); - _vm->_gfx->_backgroundInfo.x = (_vm->_screenWidth - _vm->_gfx->_backgroundInfo.width) >> 1; - _vm->_gfx->_backgroundInfo.y = (_vm->_screenHeight - _vm->_gfx->_backgroundInfo.height) >> 1; + _vm->_gfx->_backgroundInfo->x = (_vm->_screenWidth - _vm->_gfx->_backgroundInfo->width) >> 1; + _vm->_gfx->_backgroundInfo->y = (_vm->_screenHeight - _vm->_gfx->_backgroundInfo->height) >> 1; _vm->_input->setMouseState(MOUSE_DISABLED); _startTime = g_system->getMillis(); @@ -217,8 +217,8 @@ public: _vm->_gfx->clearScreen(); _vm->_gfx->setBackground(kBackgroundSlide, "tbra", 0, 0); if (_vm->getPlatform() == Common::kPlatformPC) { - _vm->_gfx->_backgroundInfo.x = 20; - _vm->_gfx->_backgroundInfo.y = 50; + _vm->_gfx->_backgroundInfo->x = 20; + _vm->_gfx->_backgroundInfo->y = 50; } // TODO: load progress from savefile diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 54cb175e46..e13d2f9aa4 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -264,7 +264,6 @@ void Parallaction::freeLocation() { _location._walkPoints.clear(); _gfx->clearGfxObjects(kGfxObjNormal); - freeBackground(); _location._programs.clear(); freeZones(); @@ -284,7 +283,6 @@ void Parallaction::freeLocation() { void Parallaction::freeBackground() { - _gfx->freeBackground(); _pathBuffer = 0; } @@ -292,7 +290,7 @@ void Parallaction::freeBackground() { void Parallaction::setBackground(const char* name, const char* mask, const char* path) { _gfx->setBackground(kBackgroundLocation, name, mask, path); - _pathBuffer = &_gfx->_backgroundInfo.path; + _pathBuffer = &_gfx->_backgroundInfo->path; return; } diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 3ba2beb288..df992b9a20 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -464,9 +464,9 @@ DECLARE_LOCATION_PARSER(mask) { debugC(7, kDebugParser, "LOCATION_PARSER(mask) "); ctxt.maskName = strdup(_tokens[1]); - _vm->_gfx->_backgroundInfo.layers[0] = atoi(_tokens[2]); - _vm->_gfx->_backgroundInfo.layers[1] = atoi(_tokens[3]); - _vm->_gfx->_backgroundInfo.layers[2] = atoi(_tokens[4]); + _vm->_gfx->_backgroundInfo->layers[0] = atoi(_tokens[2]); + _vm->_gfx->_backgroundInfo->layers[1] = atoi(_tokens[3]); + _vm->_gfx->_backgroundInfo->layers[2] = atoi(_tokens[4]); } @@ -1179,7 +1179,7 @@ void LocationParser_br::parse(Script *script) { LocationParser_ns::parse(script); _vm->_gfx->setBackground(kBackgroundLocation, ctxt.bgName, ctxt.maskName, ctxt.pathName); - _vm->_pathBuffer = &_vm->_gfx->_backgroundInfo.path; + _vm->_pathBuffer = &_vm->_gfx->_backgroundInfo->path; if (ctxt.characterName) { _vm->changeCharacter(ctxt.characterName); -- cgit v1.2.3 From 6ed4beb1bfc1ffe7a2ca9f99dbd63eaf9c245bea Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 31 Jul 2008 12:50:43 +0000 Subject: Made changing of background more flexible, in that the engine can now configure its BackgroundInfo before passing it to Gfx. svn-id: r33469 --- engines/parallaction/graphics.cpp | 10 ++-------- engines/parallaction/graphics.h | 2 +- engines/parallaction/gui_br.cpp | 11 +++++------ engines/parallaction/parallaction.cpp | 5 ++++- engines/parallaction/parallaction.h | 2 +- engines/parallaction/parallaction_ns.cpp | 10 ++++++++-- engines/parallaction/parser_br.cpp | 3 +-- 7 files changed, 22 insertions(+), 21 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 7aa284e82c..c19d6ae5e5 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -831,15 +831,11 @@ void Gfx::freeItems() { _numItems = 0; } - -void Gfx::setBackground(uint type, const char* name, const char* mask, const char* path) { - +void Gfx::setBackground(uint type, BackgroundInfo *info) { delete _backgroundInfo; - _backgroundInfo = new BackgroundInfo; + _backgroundInfo = info; if (type == kBackgroundLocation) { - _disk->loadScenery(*_backgroundInfo, name, mask, path); - // The PC version of BRA needs the entries 20-31 of the palette to be constant, but // the background resource files are screwed up. The right colors come from an unused // bitmap (pointer.bmp). Nothing is known about the Amiga version so far. @@ -854,12 +850,10 @@ void Gfx::setBackground(uint type, const char* name, const char* mask, const cha setPalette(_backgroundInfo->palette); _palette.clone(_backgroundInfo->palette); } else { - _disk->loadSlide(*_backgroundInfo, name); for (uint i = 0; i < 6; i++) _backgroundInfo->ranges[i]._flags = 0; // disable palette cycling for slides setPalette(_backgroundInfo->palette); } - } } // namespace Parallaction diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 71eaa3724f..23b4569c6a 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -512,7 +512,7 @@ public: // background surface BackgroundInfo *_backgroundInfo; - void setBackground(uint type, const char* name, const char* mask, const char* path); + void setBackground(uint type, BackgroundInfo *info); void patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask = false); void grabBackground(const Common::Rect& r, Graphics::Surface &dst); void fillBackground(const Common::Rect& r, byte color); diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 89226bc9ac..3315433762 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -72,9 +72,7 @@ public: virtual void enter() { _vm->_gfx->clearScreen(); - _vm->_gfx->setBackground(kBackgroundSlide, _slideName.c_str(), 0, 0); - _vm->_gfx->_backgroundInfo->x = (_vm->_screenWidth - _vm->_gfx->_backgroundInfo->width) >> 1; - _vm->_gfx->_backgroundInfo->y = (_vm->_screenHeight - _vm->_gfx->_backgroundInfo->height) >> 1; + _vm->showSlide(_slideName.c_str(), CENTER_LABEL_HORIZONTAL, CENTER_LABEL_VERTICAL); _vm->_input->setMouseState(MOUSE_DISABLED); _startTime = g_system->getMillis(); @@ -215,11 +213,12 @@ public: virtual void enter() { _vm->_gfx->clearScreen(); - _vm->_gfx->setBackground(kBackgroundSlide, "tbra", 0, 0); + int x = 0, y = 0; if (_vm->getPlatform() == Common::kPlatformPC) { - _vm->_gfx->_backgroundInfo->x = 20; - _vm->_gfx->_backgroundInfo->y = 50; + x = 20; + y = 50; } + _vm->showSlide("tbra", x, y); // TODO: load progress from savefile int progress = 3; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index e13d2f9aa4..e4a5f55894 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -289,7 +289,10 @@ void Parallaction::freeBackground() { void Parallaction::setBackground(const char* name, const char* mask, const char* path) { - _gfx->setBackground(kBackgroundLocation, name, mask, path); + BackgroundInfo *info = new BackgroundInfo; + _disk->loadScenery(*info, name, mask, path); + + _gfx->setBackground(kBackgroundLocation, info); _pathBuffer = &_gfx->_backgroundInfo->path; return; diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index d8e4da5baf..e5c5221414 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -487,7 +487,7 @@ public: bool saveGame(); void switchBackground(const char* background, const char* mask); - void showSlide(const char *name); + void showSlide(const char *name, int x = 0, int y = 0); void setArrowCursor(); // TODO: this should be private!!!!!!! diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 851fe38138..e81492e655 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -253,8 +253,14 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask) } -void Parallaction_ns::showSlide(const char *name) { - _gfx->setBackground(kBackgroundSlide, name, 0, 0); +void Parallaction_ns::showSlide(const char *name, int x, int y) { + BackgroundInfo *info = new BackgroundInfo; + _disk->loadSlide(*info, name); + + info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; + info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; + + _gfx->setBackground(kBackgroundSlide, info); } void Parallaction_ns::runPendingZones() { diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index df992b9a20..ff7a34f95f 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -1178,8 +1178,7 @@ void LocationParser_br::parse(Script *script) { LocationParser_ns::parse(script); - _vm->_gfx->setBackground(kBackgroundLocation, ctxt.bgName, ctxt.maskName, ctxt.pathName); - _vm->_pathBuffer = &_vm->_gfx->_backgroundInfo->path; + _vm->setBackground(ctxt.bgName, ctxt.maskName, ctxt.pathName); if (ctxt.characterName) { _vm->changeCharacter(ctxt.characterName); -- cgit v1.2.3 From b79f069c58fb8f90562b1ddacd52046b0d1d24be Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Thu, 31 Jul 2008 13:45:58 +0000 Subject: Applied my patch #2030058 ("Workaround for incorrectly compressed FotAQ"), and made a mention in NEWS that speech is played correctly now. Of course, we should still provide a correctly compressed version at some point. svn-id: r33471 --- engines/queen/sound.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index f4e0116cf1..27cf1bf6a2 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -35,6 +35,7 @@ #include "queen/queen.h" #include "queen/resource.h" +#include "sound/audiostream.h" #include "sound/flac.h" #include "sound/mididrv.h" #include "sound/mp3.h" @@ -45,6 +46,42 @@ namespace Queen { +// The sounds in the PC versions are all played at 11840 Hz. Unfortunately, we +// did not know that at the time, so there are plenty of compressed versions +// which claim that they should be played at 11025 Hz. This "wrapper" class +// works around that. + +class AudioStreamWrapper : public Audio::AudioStream { +protected: + Audio::AudioStream *_stream; + +public: + AudioStreamWrapper(Audio::AudioStream *stream) { + _stream = stream; + } + ~AudioStreamWrapper() { + delete _stream; + } + int readBuffer(int16 *buffer, const int numSamples) { + return _stream->readBuffer(buffer, numSamples); + } + bool isStereo() const { + return _stream->isStereo(); + } + bool endOfData() const { + return _stream->endOfData(); + } + bool endOfStream() { + return _stream->endOfStream(); + } + int getRate() const { + return 11840; + } + int32 getTotalPlayTime() { + return _stream->getTotalPlayTime(); + } +}; + class SilentSound : public PCSound { public: SilentSound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {} @@ -69,7 +106,7 @@ protected: void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { Common::MemoryReadStream *tmp = f->readStream(size); assert(tmp); - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, Audio::makeMP3Stream(tmp, true)); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeMP3Stream(tmp, true))); } }; #endif @@ -82,7 +119,7 @@ protected: void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { Common::MemoryReadStream *tmp = f->readStream(size); assert(tmp); - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, Audio::makeVorbisStream(tmp, true)); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeVorbisStream(tmp, true))); } }; #endif @@ -95,7 +132,7 @@ protected: void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { Common::MemoryReadStream *tmp = f->readStream(size); assert(tmp); - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, Audio::makeFlacStream(tmp, true)); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeFlacStream(tmp, true))); } }; #endif // #ifdef USE_FLAC -- cgit v1.2.3 From 0679889d98ef00275c7c726147b3bc54cbefdca6 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 31 Jul 2008 14:20:51 +0000 Subject: Disabled masks in BRA Amiga, because the decoding is not known yet. svn-id: r33473 --- engines/parallaction/disk.h | 1 - engines/parallaction/disk_br.cpp | 57 +++++----------------------------------- 2 files changed, 7 insertions(+), 51 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index ee393afd6a..341229a649 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -267,7 +267,6 @@ protected: Sprites* createSprites(Common::ReadStream &stream); Font *createFont(const char *name, Common::SeekableReadStream &stream); - void loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream); void loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream); FilesystemNode _baseBkgDir; diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 2285c5608e..cd57ec8822 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -510,33 +510,6 @@ AmigaDisk_br::~AmigaDisk_br() { } -/* - FIXME: mask values are not computed correctly for level 1 and 2 - - NOTE: this routine is only able to build masks for Nippon Safes, since mask widths are hardcoded - into the main loop. -*/ -void buildMask2(byte* buf) { - - byte mask1[16] = { 0, 0x80, 0x20, 0xA0, 8, 0x88, 0x28, 0xA8, 2, 0x82, 0x22, 0xA2, 0xA, 0x8A, 0x2A, 0xAA }; - byte mask0[16] = { 0, 0x40, 0x10, 0x50, 4, 0x44, 0x14, 0x54, 1, 0x41, 0x11, 0x51, 0x5, 0x45, 0x15, 0x55 }; - - byte plane0[40]; - byte plane1[40]; - - for (int32 i = 0; i < _vm->_screenHeight; i++) { - - memcpy(plane0, buf, 40); - memcpy(plane1, buf+40, 40); - - for (uint32 j = 0; j < 40; j++) { - *buf++ = mask0[(plane0[j] & 0xF0) >> 4] | mask1[(plane1[j] & 0xF0) >> 4]; - *buf++ = mask0[plane0[j] & 0xF] | mask1[plane1[j] & 0xF]; - } - - } -} - void AmigaDisk_br::loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream) { byte *pal; @@ -565,27 +538,6 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, Common::SeekableReadStre return; } -void AmigaDisk_br::loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream) { - stream.seek(0x30, SEEK_SET); - - byte r, g, b; - for (uint i = 0; i < 4; i++) { - r = stream.readByte(); - g = stream.readByte(); - b = stream.readByte(); - - info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF; - } - - stream.seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic - Graphics::PackBitsReadStream unpackedStream(stream); - - info.mask.create(info.width, info.height); - unpackedStream.read(info.mask.data, info.mask.size); - buildMask2(info.mask.data); - - return; -} void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) { debugC(1, kDebugDisk, "AmigaDisk_br::loadScenery '%s', '%s' '%s'", name, mask, path); @@ -608,7 +560,7 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha loadBackground(info, stream); stream.close(); } - +#if 0 if (mask && _mskDir.exists()) { filepath = Common::String(mask) + ".msk"; node = _mskDir.getChild(filepath); @@ -619,11 +571,16 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha if (node.exists()) { stream.open(node); + stream.seek(0x30, SEEK_SET); + Graphics::PackBitsReadStream unpackedStream(stream); + info.mask.create(info.width, info.height); + unpackedStream.read(info.mask.data, info.mask.size); + // TODO: there is another step to do after decompression... loadMask(info, stream); stream.close(); } } - +#endif if (path && _pthDir.exists()) { filepath = Common::String(path) + ".pth"; node = _pthDir.getChild(filepath); -- cgit v1.2.3 From f5b7004faed0d64bf24e0080d7312eeb40c16a10 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Thu, 31 Jul 2008 15:15:42 +0000 Subject: * Removed references to the current _backgroundInfo from parser code. * Re-enabled masks (in BRA DOS). svn-id: r33474 --- engines/parallaction/parallaction.cpp | 2 +- engines/parallaction/parser.h | 1 + engines/parallaction/parser_br.cpp | 12 ++++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'engines') diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index e4a5f55894..bb306c3299 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -293,7 +293,7 @@ void Parallaction::setBackground(const char* name, const char* mask, const char* _disk->loadScenery(*info, name, mask, path); _gfx->setBackground(kBackgroundLocation, info); - _pathBuffer = &_gfx->_backgroundInfo->path; + _pathBuffer = &info->path; return; } diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index 488d437deb..79e6cf6640 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -128,6 +128,7 @@ protected: // BRA specific int numZones; + BackgroundInfo *info; char *bgName; char *maskName; char *pathName; diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index ff7a34f95f..3b446805d7 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -464,9 +464,9 @@ DECLARE_LOCATION_PARSER(mask) { debugC(7, kDebugParser, "LOCATION_PARSER(mask) "); ctxt.maskName = strdup(_tokens[1]); - _vm->_gfx->_backgroundInfo->layers[0] = atoi(_tokens[2]); - _vm->_gfx->_backgroundInfo->layers[1] = atoi(_tokens[3]); - _vm->_gfx->_backgroundInfo->layers[2] = atoi(_tokens[4]); + ctxt.info->layers[0] = atoi(_tokens[2]); + ctxt.info->layers[1] = atoi(_tokens[3]); + ctxt.info->layers[2] = atoi(_tokens[4]); } @@ -1175,10 +1175,14 @@ void LocationParser_br::parse(Script *script) { ctxt.maskName = 0; ctxt.pathName = 0; ctxt.characterName = 0; + ctxt.info = new BackgroundInfo; LocationParser_ns::parse(script); - _vm->setBackground(ctxt.bgName, ctxt.maskName, ctxt.pathName); + _vm->_disk->loadScenery(*ctxt.info, ctxt.bgName, ctxt.maskName, ctxt.pathName); + _vm->_gfx->setBackground(kBackgroundLocation, ctxt.info); + _vm->_pathBuffer = &ctxt.info->path; + if (ctxt.characterName) { _vm->changeCharacter(ctxt.characterName); -- cgit v1.2.3