diff options
Diffstat (limited to 'engines/zvision/scripting')
19 files changed, 713 insertions, 431 deletions
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp index f60fdbb973..e1380b0eb2 100644 --- a/engines/zvision/scripting/actions.cpp +++ b/engines/zvision/scripting/actions.cpp @@ -23,11 +23,12 @@ #include "common/scummsys.h" #include "video/video_decoder.h" +#include "zvision/scripting/actions.h" + #include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" #include "zvision/graphics/render_manager.h" #include "zvision/file/save_manager.h" -#include "zvision/scripting/actions.h" #include "zvision/scripting/menu.h" #include "zvision/scripting/effects/timer_effect.h" #include "zvision/scripting/effects/music_effect.h" @@ -46,12 +47,18 @@ namespace ZVision { +ResultAction::ResultAction(ZVision *engine, int32 slotKey) : + _engine(engine), + _slotKey(slotKey), + _scriptManager(engine->getScriptManager()) { +} + ////////////////////////////////////////////////////////////////////////////// // ActionAdd ////////////////////////////////////////////////////////////////////////////// -ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionAdd::ActionAdd(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; _value = 0; @@ -59,7 +66,7 @@ ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line) } bool ActionAdd::execute() { - _engine->getScriptManager()->setStateValue(_key, _engine->getScriptManager()->getStateValue(_key) + _value); + _scriptManager->setStateValue(_key, _scriptManager->getStateValue(_key) + _value); return true; } @@ -67,23 +74,22 @@ bool ActionAdd::execute() { // ActionAssign ////////////////////////////////////////////////////////////////////////////// -ActionAssign::ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionAssign::ActionAssign(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; char buf[64]; memset(buf, 0, 64); sscanf(line.c_str(), "%u, %s", &_key, buf); - _value = new ValueSlot(_engine->getScriptManager(), buf); + _value = new ValueSlot(_scriptManager, buf); } ActionAssign::~ActionAssign() { - if (_value) - delete _value; + delete _value; } bool ActionAssign::execute() { - _engine->getScriptManager()->setStateValue(_key, _value->getValue()); + _scriptManager->setStateValue(_key, _value->getValue()); return true; } @@ -91,8 +97,8 @@ bool ActionAssign::execute() { // ActionAttenuate ////////////////////////////////////////////////////////////////////////////// -ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; _attenuation = 0; @@ -100,10 +106,10 @@ ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::S } bool ActionAttenuate::execute() { - ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_key); + ScriptingEffect *fx = _scriptManager->getSideFX(_key); if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) { - MusicNode *mus = (MusicNode *)fx; - mus->setVolume(255 - (abs(_attenuation) >> 7)); + MusicNodeBASE *mus = (MusicNodeBASE *)fx; + mus->setVolume(255 * (10000 - abs(_attenuation)) / 10000 ); } return true; } @@ -112,8 +118,8 @@ bool ActionAttenuate::execute() { // ActionChangeLocation ////////////////////////////////////////////////////////////////////////////// -ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _world = 'g'; _room = 'a'; _node = 'r'; @@ -125,7 +131,7 @@ ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const bool ActionChangeLocation::execute() { // We can't directly call ScriptManager::ChangeLocationIntern() because doing so clears all the Puzzles, and thus would corrupt the current puzzle checking - _engine->getScriptManager()->changeLocation(_world, _room, _node, _view, _offset); + _scriptManager->changeLocation(_world, _room, _node, _view, _offset); // Tell the puzzle system to stop checking any more puzzles return false; } @@ -134,8 +140,8 @@ bool ActionChangeLocation::execute() { // ActionCrossfade ////////////////////////////////////////////////////////////////////////////// -ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _keyOne = 0; _keyTwo = 0; _oneStartVolume = 0; @@ -151,9 +157,9 @@ ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::S bool ActionCrossfade::execute() { if (_keyOne) { - ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_keyOne); + ScriptingEffect *fx = _scriptManager->getSideFX(_keyOne); if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) { - MusicNode *mus = (MusicNode *)fx; + MusicNodeBASE *mus = (MusicNodeBASE *)fx; if (_oneStartVolume >= 0) mus->setVolume((_oneStartVolume * 255) / 100); @@ -162,9 +168,9 @@ bool ActionCrossfade::execute() { } if (_keyTwo) { - ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_keyTwo); + ScriptingEffect *fx = _scriptManager->getSideFX(_keyTwo); if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) { - MusicNode *mus = (MusicNode *)fx; + MusicNodeBASE *mus = (MusicNodeBASE *)fx; if (_twoStartVolume >= 0) mus->setVolume((_twoStartVolume * 255) / 100); @@ -178,8 +184,8 @@ bool ActionCrossfade::execute() { // ActionCursor ////////////////////////////////////////////////////////////////////////////// -ActionCursor::ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionCursor::ActionCursor(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { Common::String up = line; up.toUppercase(); _action = 0; @@ -210,10 +216,13 @@ bool ActionCursor::execute() { // ActionDelayRender ////////////////////////////////////////////////////////////////////////////// -ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _framesToDelay = 0; sscanf(line.c_str(), "%u", &_framesToDelay); + // Limit to 10 frames maximum. This fixes the script bug in ZGI scene px10 + // (outside Frobozz Electric building), where this is set to 100 (bug #6791). + _framesToDelay = MIN<uint32>(_framesToDelay, 10); } bool ActionDelayRender::execute() { @@ -225,15 +234,15 @@ bool ActionDelayRender::execute() { // ActionDisableControl ////////////////////////////////////////////////////////////////////////////// -ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; sscanf(line.c_str(), "%u", &_key); } bool ActionDisableControl::execute() { - _engine->getScriptManager()->setStateFlag(_key, Puzzle::DISABLED); + _scriptManager->setStateFlag(_key, Puzzle::DISABLED); return true; } @@ -241,8 +250,8 @@ bool ActionDisableControl::execute() { // ActionDisplayMessage ////////////////////////////////////////////////////////////////////////////// -ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _control = 0; _msgid = 0; @@ -250,7 +259,7 @@ ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const } bool ActionDisplayMessage::execute() { - Control *ctrl = _engine->getScriptManager()->getControl(_control); + Control *ctrl = _scriptManager->getControl(_control); if (ctrl && ctrl->getType() == Control::CONTROL_TITLER) { TitlerControl *titler = (TitlerControl *)ctrl; titler->setString(_msgid); @@ -276,8 +285,8 @@ bool ActionDissolve::execute() { // ActionDistort - only used by Zork: Nemesis for the "treatment" puzzle in the Sanitarium (aj30) ////////////////////////////////////////////////////////////////////////////// -ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionDistort::ActionDistort(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _distSlot = 0; _speed = 0; _startAngle = 60.0; @@ -289,14 +298,14 @@ ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::Strin } ActionDistort::~ActionDistort() { - _engine->getScriptManager()->killSideFx(_distSlot); + _scriptManager->killSideFx(_distSlot); } bool ActionDistort::execute() { - if (_engine->getScriptManager()->getSideFX(_distSlot)) + if (_scriptManager->getSideFX(_distSlot)) return true; - _engine->getScriptManager()->addSideFX(new DistortNode(_engine, _distSlot, _speed, _startAngle, _endAngle, _startLineScale, _endLineScale)); + _scriptManager->addSideFX(new DistortNode(_engine, _distSlot, _speed, _startAngle, _endAngle, _startLineScale, _endLineScale)); return true; } @@ -305,15 +314,15 @@ bool ActionDistort::execute() { // ActionEnableControl ////////////////////////////////////////////////////////////////////////////// -ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; sscanf(line.c_str(), "%u", &_key); } bool ActionEnableControl::execute() { - _engine->getScriptManager()->unsetStateFlag(_key, Puzzle::DISABLED); + _scriptManager->unsetStateFlag(_key, Puzzle::DISABLED); return true; } @@ -321,13 +330,13 @@ bool ActionEnableControl::execute() { // ActionFlushMouseEvents ////////////////////////////////////////////////////////////////////////////// -ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotkey) : - ResultAction(engine, slotkey) { +ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotKey) : + ResultAction(engine, slotKey) { } bool ActionFlushMouseEvents::execute() { - _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONUP); - _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONDOWN); + _scriptManager->flushEvent(Common::EVENT_LBUTTONUP); + _scriptManager->flushEvent(Common::EVENT_LBUTTONDOWN); return true; } @@ -335,8 +344,8 @@ bool ActionFlushMouseEvents::execute() { // ActionInventory ////////////////////////////////////////////////////////////////////////////// -ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionInventory::ActionInventory(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _type = -1; _key = 0; @@ -360,22 +369,22 @@ ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::S bool ActionInventory::execute() { switch (_type) { case 0: // add - _engine->getScriptManager()->inventoryAdd(_key); + _scriptManager->inventoryAdd(_key); break; case 1: // addi - _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(_key)); + _scriptManager->inventoryAdd(_scriptManager->getStateValue(_key)); break; case 2: // drop if (_key >= 0) - _engine->getScriptManager()->inventoryDrop(_key); + _scriptManager->inventoryDrop(_key); else - _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(StateKey_InventoryItem)); + _scriptManager->inventoryDrop(_scriptManager->getStateValue(StateKey_InventoryItem)); break; case 3: // dropi - _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(_key)); + _scriptManager->inventoryDrop(_scriptManager->getStateValue(_key)); break; case 4: // cycle - _engine->getScriptManager()->inventoryCycle(); + _scriptManager->inventoryCycle(); break; default: break; @@ -387,8 +396,8 @@ bool ActionInventory::execute() { // ActionKill - only used by ZGI ////////////////////////////////////////////////////////////////////////////// -ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionKill::ActionKill(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; _type = 0; char keytype[25]; @@ -416,9 +425,9 @@ ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &lin bool ActionKill::execute() { if (_type) - _engine->getScriptManager()->killSideFxType((ScriptingEffect::ScriptingEffectType)_type); + _scriptManager->killSideFxType((ScriptingEffect::ScriptingEffectType)_type); else - _engine->getScriptManager()->killSideFx(_key); + _scriptManager->killSideFx(_key); return true; } @@ -426,8 +435,8 @@ bool ActionKill::execute() { // ActionMenuBarEnable ////////////////////////////////////////////////////////////////////////////// -ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _menus = 0xFFFF; sscanf(line.c_str(), "%hu", &_menus); @@ -442,18 +451,20 @@ bool ActionMenuBarEnable::execute() { // ActionMusic ////////////////////////////////////////////////////////////////////////////// -ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global) : - ResultAction(engine, slotkey), - _volume(255), +ActionMusic::ActionMusic(ZVision *engine, int32 slotKey, const Common::String &line, bool global) : + ResultAction(engine, slotKey), _note(0), _prog(0), _universe(global) { uint type = 0; char fileNameBuffer[25]; uint loop = 0; - uint volume = 255; + char volumeBuffer[15]; + + // Volume is optional. If it doesn't appear, assume full volume + strcpy(volumeBuffer, "100"); - sscanf(line.c_str(), "%u %24s %u %u", &type, fileNameBuffer, &loop, &volume); + sscanf(line.c_str(), "%u %24s %u %14s", &type, fileNameBuffer, &loop, volumeBuffer); // Type 4 actions are MIDI commands, not files. These are only used by // Zork: Nemesis, for the flute and piano puzzles (tj4e and ve6f, as well @@ -462,39 +473,54 @@ ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &l _midi = true; int note; int prog; - sscanf(line.c_str(), "%u %d %d %u", &type, &prog, ¬e, &volume); - _volume = volume; + sscanf(line.c_str(), "%u %d %d %14s", &type, &prog, ¬e, volumeBuffer); + _volume = new ValueSlot(_scriptManager, volumeBuffer); _note = note; _prog = prog; } else { _midi = false; _fileName = Common::String(fileNameBuffer); _loop = loop == 1 ? true : false; - - // Volume is optional. If it doesn't appear, assume full volume - if (volume != 255) { - // Volume in the script files is mapped to [0, 100], but the ScummVM mixer uses [0, 255] - _volume = volume * 255 / 100; + if (volumeBuffer[0] != '[' && atoi(volumeBuffer) > 100) { + // I thought I saw a case like this in Zork Nemesis, so + // let's guard against it. + warning("ActionMusic: Adjusting volume for %s from %s to 100", _fileName.c_str(), volumeBuffer); + strcpy(volumeBuffer, "100"); } + _volume = new ValueSlot(_scriptManager, volumeBuffer); } + + // WORKAROUND for a script bug in Zork Nemesis, rooms mq70/mq80. + // Fixes an edge case where the player goes to the dark room with the grue + // without holding a torch, and then quickly runs away before the grue's + // sound effect finishes. Fixes script bug #6794. + if (engine->getGameId() == GID_NEMESIS && _slotKey == 14822 && _scriptManager->getStateValue(_slotKey) == 2) + _scriptManager->setStateValue(_slotKey, 0); + } ActionMusic::~ActionMusic() { if (!_universe) - _engine->getScriptManager()->killSideFx(_slotKey); + _scriptManager->killSideFx(_slotKey); + delete _volume; } bool ActionMusic::execute() { - if (_engine->getScriptManager()->getSideFX(_slotKey)) - return true; + if (_scriptManager->getSideFX(_slotKey)) { + _scriptManager->killSideFx(_slotKey); + _scriptManager->setStateValue(_slotKey, 2); + } + + uint volume = _volume->getValue(); if (_midi) { - _engine->getScriptManager()->addSideFX(new MusicMidiNode(_engine, _slotKey, _prog, _note, _volume)); + _scriptManager->addSideFX(new MusicMidiNode(_engine, _slotKey, _prog, _note, volume)); } else { if (!_engine->getSearchManager()->hasFile(_fileName)) return true; - _engine->getScriptManager()->addSideFX(new MusicNode(_engine, _slotKey, _fileName, _loop, _volume)); + // Volume in the script files is mapped to [0, 100], but the ScummVM mixer uses [0, 255] + _scriptManager->addSideFX(new MusicNode(_engine, _slotKey, _fileName, _loop, volume * 255 / 100)); } return true; @@ -504,8 +530,8 @@ bool ActionMusic::execute() { // ActionPanTrack ////////////////////////////////////////////////////////////////////////////// -ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey), +ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey), _pos(0), _musicSlot(0) { @@ -513,14 +539,14 @@ ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::Str } ActionPanTrack::~ActionPanTrack() { - _engine->getScriptManager()->killSideFx(_slotKey); + _scriptManager->killSideFx(_slotKey); } bool ActionPanTrack::execute() { - if (_engine->getScriptManager()->getSideFX(_slotKey)) + if (_scriptManager->getSideFX(_slotKey)) return true; - _engine->getScriptManager()->addSideFX(new PanTrackNode(_engine, _slotKey, _musicSlot, _pos)); + _scriptManager->addSideFX(new PanTrackNode(_engine, _slotKey, _musicSlot, _pos)); return true; } @@ -529,8 +555,8 @@ bool ActionPanTrack::execute() { // ActionPreferences ////////////////////////////////////////////////////////////////////////////// -ActionPreferences::ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionPreferences::ActionPreferences(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { if (line.compareToIgnoreCase("save") == 0) _save = true; else @@ -550,8 +576,8 @@ bool ActionPreferences::execute() { // ActionPreloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _mask = 0; _framerate = 0; @@ -570,18 +596,18 @@ ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, c } ActionPreloadAnimation::~ActionPreloadAnimation() { - _engine->getScriptManager()->deleteSideFx(_slotKey); + _scriptManager->deleteSideFx(_slotKey); } bool ActionPreloadAnimation::execute() { - AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_slotKey); + AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_slotKey); if (!nod) { nod = new AnimationEffect(_engine, _slotKey, _fileName, _mask, _framerate, false); - _engine->getScriptManager()->addSideFX(nod); + _scriptManager->addSideFX(nod); } else nod->stop(); - _engine->getScriptManager()->setStateValue(_slotKey, 2); + _scriptManager->setStateValue(_slotKey, 2); return true; } @@ -589,18 +615,18 @@ bool ActionPreloadAnimation::execute() { // ActionUnloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; sscanf(line.c_str(), "%u", &_key); } bool ActionUnloadAnimation::execute() { - AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_key); + AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_key); if (nod && nod->getType() == ScriptingEffect::SCRIPTING_EFFECT_ANIM) - _engine->getScriptManager()->deleteSideFx(_key); + _scriptManager->deleteSideFx(_key); return true; } @@ -609,8 +635,8 @@ bool ActionUnloadAnimation::execute() { // ActionPlayAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _x = 0; _y = 0; _x2 = 0; @@ -635,18 +661,25 @@ ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const C _mask = -1; _fileName = Common::String(fileName); + + // WORKAROUND for bug #6769, location me1g.scr (the "Alchemical debacle" + // video in ZGI). We only scale up by 2x, in AnimationEffect::process(), + // but the dimensions of the target frame are off by 2 pixels. We fix that + // here, so that the video can be scaled. + if (_fileName == "me1ga011.avi" && _y2 == 213) + _y2 = 215; } ActionPlayAnimation::~ActionPlayAnimation() { - _engine->getScriptManager()->deleteSideFx(_slotKey); + _scriptManager->deleteSideFx(_slotKey); } bool ActionPlayAnimation::execute() { - AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_slotKey); + AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_slotKey); if (!nod) { nod = new AnimationEffect(_engine, _slotKey, _fileName, _mask, _framerate); - _engine->getScriptManager()->addSideFX(nod); + _scriptManager->addSideFX(nod); } else nod->stop(); @@ -660,8 +693,8 @@ bool ActionPlayAnimation::execute() { // ActionPlayPreloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _controlKey = 0; _x1 = 0; _y1 = 0; @@ -677,7 +710,7 @@ ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 sl } bool ActionPlayPreloadAnimation::execute() { - AnimationEffect *nod = (AnimationEffect *)_engine->getScriptManager()->getSideFX(_controlKey); + AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_controlKey); if (nod) nod->addPlayNode(_slotKey, _x1, _y1, _x2, _y2, _startFrame, _endFrame, _loopCount); @@ -699,8 +732,8 @@ bool ActionQuit::execute() { // ActionRegion - only used by Zork: Nemesis ////////////////////////////////////////////////////////////////////////////// -ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionRegion::ActionRegion(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _delay = 0; _type = 0; _unk1 = 0; @@ -718,11 +751,11 @@ ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String } ActionRegion::~ActionRegion() { - _engine->getScriptManager()->killSideFx(_slotKey); + _scriptManager->killSideFx(_slotKey); } bool ActionRegion::execute() { - if (_engine->getScriptManager()->getSideFX(_slotKey)) + if (_scriptManager->getSideFX(_slotKey)) return true; GraphicsEffect *effect = NULL; @@ -767,7 +800,7 @@ bool ActionRegion::execute() { } if (effect) { - _engine->getScriptManager()->addSideFX(new RegionNode(_engine, _slotKey, effect, _delay)); + _scriptManager->addSideFX(new RegionNode(_engine, _slotKey, effect, _delay)); _engine->getRenderManager()->addEffect(effect); } @@ -778,31 +811,46 @@ bool ActionRegion::execute() { // ActionRandom ////////////////////////////////////////////////////////////////////////////// -ActionRandom::ActionRandom(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionRandom::ActionRandom(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { char maxBuffer[64]; memset(maxBuffer, 0, 64); sscanf(line.c_str(), "%s", maxBuffer); - _max = new ValueSlot(_engine->getScriptManager(), maxBuffer); + _max = new ValueSlot(_scriptManager, maxBuffer); } ActionRandom::~ActionRandom() { - if (_max) - delete _max; + delete _max; } bool ActionRandom::execute() { uint randNumber = _engine->getRandomSource()->getRandomNumber(_max->getValue()); - _engine->getScriptManager()->setStateValue(_slotKey, randNumber); + _scriptManager->setStateValue(_slotKey, randNumber); return true; } ////////////////////////////////////////////////////////////////////////////// +// ActionRestoreGame +////////////////////////////////////////////////////////////////////////////// + +ActionRestoreGame::ActionRestoreGame(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { + char buf[128]; + sscanf(line.c_str(), "%s", buf); + _fileName = Common::String(buf); +} + +bool ActionRestoreGame::execute() { + _engine->getSaveManager()->loadGame(-1); + return false; +} + +////////////////////////////////////////////////////////////////////////////// // ActionRotateTo ////////////////////////////////////////////////////////////////////////////// -ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _time = 0; _toPos = 0; @@ -819,8 +867,8 @@ bool ActionRotateTo::execute() { // ActionSetPartialScreen ////////////////////////////////////////////////////////////////////////////// -ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _x = 0; _y = 0; @@ -859,8 +907,8 @@ bool ActionSetPartialScreen::execute() { // ActionSetScreen ////////////////////////////////////////////////////////////////////////////// -ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { char fileName[25]; sscanf(line.c_str(), "%24s", fileName); @@ -877,14 +925,14 @@ bool ActionSetScreen::execute() { // ActionStop ////////////////////////////////////////////////////////////////////////////// -ActionStop::ActionStop(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionStop::ActionStop(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _key = 0; sscanf(line.c_str(), "%u", &_key); } bool ActionStop::execute() { - _engine->getScriptManager()->stopSideFx(_key); + _scriptManager->stopSideFx(_key); return true; } @@ -892,8 +940,8 @@ bool ActionStop::execute() { // ActionStreamVideo ////////////////////////////////////////////////////////////////////////////// -ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _x1 = 0; _x2 = 0; _y1 = 0; @@ -912,7 +960,15 @@ ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Commo bool ActionStreamVideo::execute() { Video::VideoDecoder *decoder; Common::Rect destRect = Common::Rect(_x1, _y1, _x2 + 1, _y2 + 1); + Common::String subname = _fileName; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + bool subtitleExists = _engine->getSearchManager()->hasFile(subname); + bool switchToHires = false; +// NOTE: We only show the hires MPEG2 videos when libmpeg2 is compiled in, +// otherwise we fall back to the lowres ones #ifdef USE_MPEG2 Common::String hiresFileName = _fileName; hiresFileName.setChar('d', hiresFileName.size() - 8); @@ -920,36 +976,44 @@ bool ActionStreamVideo::execute() { hiresFileName.setChar('o', hiresFileName.size() - 2); hiresFileName.setChar('b', hiresFileName.size() - 1); - if (_engine->getScriptManager()->getStateValue(StateKey_MPEGMovies) == 1 &&_engine->getSearchManager()->hasFile(hiresFileName)) - // TODO: Enable once VOB + AC3 support is implemented - //_fileName = hiresFileName; + if (_scriptManager->getStateValue(StateKey_MPEGMovies) == 1 &&_engine->getSearchManager()->hasFile(hiresFileName)) { + // TODO: Enable once AC3 support is implemented + if (!_engine->getSearchManager()->hasFile(_fileName)) // Check for the regular video + return true; warning("The hires videos of the DVD version of ZGI aren't supported yet, using lowres"); -#endif - - Common::String subname = _fileName; - subname.setChar('s', subname.size() - 3); - subname.setChar('u', subname.size() - 2); - subname.setChar('b', subname.size() - 1); - + //_fileName = hiresFileName; + //switchToHires = true; + } else if (!_engine->getSearchManager()->hasFile(_fileName)) + return true; +#else if (!_engine->getSearchManager()->hasFile(_fileName)) return true; +#endif decoder = _engine->loadAnimation(_fileName); + Subtitle *sub = (subtitleExists) ? new Subtitle(_engine, subname, switchToHires) : NULL; _engine->getCursorManager()->showMouse(false); - Subtitle *sub = NULL; - - if (_engine->getSearchManager()->hasFile(subname)) - sub = new Subtitle(_engine, subname); + if (switchToHires) { + _engine->initHiresScreen(); + destRect = Common::Rect(40, -40, 760, 440); + Common::Rect workingWindow = _engine->_workingWindow; + workingWindow.translate(0, -40); + _engine->getRenderManager()->initSubArea(HIRES_WINDOW_WIDTH, HIRES_WINDOW_HEIGHT, workingWindow); + } _engine->playVideo(*decoder, destRect, _skippable, sub); - delete decoder; + + if (switchToHires) { + _engine->initScreen(); + _engine->getRenderManager()->initSubArea(WINDOW_WIDTH, WINDOW_HEIGHT, _engine->_workingWindow); + } _engine->getCursorManager()->showMouse(true); - if (sub) - delete sub; + delete decoder; + delete sub; return true; } @@ -958,8 +1022,8 @@ bool ActionStreamVideo::execute() { // ActionSyncSound ////////////////////////////////////////////////////////////////////////////// -ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _syncto = 0; char fileName[25]; @@ -971,14 +1035,14 @@ ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::S } bool ActionSyncSound::execute() { - ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_syncto); + ScriptingEffect *fx = _scriptManager->getSideFX(_syncto); if (!fx) return true; if (!(fx->getType() & ScriptingEffect::SCRIPTING_EFFECT_ANIM)) return true; - _engine->getScriptManager()->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto)); + _scriptManager->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto)); return true; } @@ -986,24 +1050,23 @@ bool ActionSyncSound::execute() { // ActionTimer ////////////////////////////////////////////////////////////////////////////// -ActionTimer::ActionTimer(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionTimer::ActionTimer(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { char timeBuffer[64]; memset(timeBuffer, 0, 64); sscanf(line.c_str(), "%s", timeBuffer); - _time = new ValueSlot(_engine->getScriptManager(), timeBuffer); + _time = new ValueSlot(_scriptManager, timeBuffer); } ActionTimer::~ActionTimer() { - if (_time) - delete _time; - _engine->getScriptManager()->killSideFx(_slotKey); + delete _time; + _scriptManager->killSideFx(_slotKey); } bool ActionTimer::execute() { - if (_engine->getScriptManager()->getSideFX(_slotKey)) + if (_scriptManager->getSideFX(_slotKey)) return true; - _engine->getScriptManager()->addSideFX(new TimerNode(_engine, _slotKey, _time->getValue())); + _scriptManager->addSideFX(new TimerNode(_engine, _slotKey, _time->getValue())); return true; } @@ -1011,25 +1074,25 @@ bool ActionTimer::execute() { // ActionTtyText ////////////////////////////////////////////////////////////////////////////// -ActionTtyText::ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line) : - ResultAction(engine, slotkey) { +ActionTtyText::ActionTtyText(ZVision *engine, int32 slotKey, const Common::String &line) : + ResultAction(engine, slotKey) { _delay = 0; char filename[64]; int32 x1 = 0, y1 = 0, x2 = 0, y2 = 0; - sscanf(line.c_str(), "%d %d %d %d %64s %u", &x1, &y1, &x2, &y2, filename, &_delay); + sscanf(line.c_str(), "%d %d %d %d %63s %u", &x1, &y1, &x2, &y2, filename, &_delay); _r = Common::Rect(x1, y1, x2, y2); _filename = Common::String(filename); } ActionTtyText::~ActionTtyText() { - _engine->getScriptManager()->killSideFx(_slotKey); + _scriptManager->killSideFx(_slotKey); } bool ActionTtyText::execute() { - if (_engine->getScriptManager()->getSideFX(_slotKey)) + if (_scriptManager->getSideFX(_slotKey)) return true; - _engine->getScriptManager()->addSideFX(new ttyTextNode(_engine, _slotKey, _filename, _r, _delay)); + _scriptManager->addSideFX(new ttyTextNode(_engine, _slotKey, _filename, _r, _delay)); return true; } diff --git a/engines/zvision/scripting/actions.h b/engines/zvision/scripting/actions.h index c2350bc83a..bde1baa291 100644 --- a/engines/zvision/scripting/actions.h +++ b/engines/zvision/scripting/actions.h @@ -32,6 +32,7 @@ namespace ZVision { // Forward declaration of ZVision. This file is included before ZVision is declared class ZVision; +class ScriptManager; class ValueSlot; /** @@ -40,7 +41,7 @@ class ValueSlot; */ class ResultAction { public: - ResultAction(ZVision *engine, int32 slotkey) : _engine(engine), _slotKey(slotkey) {} + ResultAction(ZVision *engine, int32 slotkey); virtual ~ResultAction() {} /** * This is called by the script system whenever a Puzzle's criteria are found to be true. @@ -53,6 +54,7 @@ public: virtual bool execute() = 0; protected: ZVision *_engine; + ScriptManager *_scriptManager; int32 _slotKey; }; @@ -224,7 +226,7 @@ public: private: Common::String _fileName; bool _loop; - byte _volume; + ValueSlot *_volume; bool _universe; bool _midi; int8 _note; @@ -267,7 +269,6 @@ public: bool execute(); private: - uint32 _animationKey; uint32 _controlKey; uint32 _x1; uint32 _y1; @@ -340,6 +341,15 @@ private: ValueSlot *_max; }; +class ActionRestoreGame : public ResultAction { +public: + ActionRestoreGame(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + Common::String _fileName; +}; + class ActionRotateTo : public ResultAction { public: ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line); diff --git a/engines/zvision/scripting/controls/fist_control.cpp b/engines/zvision/scripting/controls/fist_control.cpp index 4a8e8b1bbd..f79c82dc79 100644 --- a/engines/zvision/scripting/controls/fist_control.cpp +++ b/engines/zvision/scripting/controls/fist_control.cpp @@ -105,7 +105,12 @@ bool FistControl::process(uint32 deltaTimeInMillis) { if (_animation->needsUpdate()) { const Graphics::Surface *frameData = _animation->decodeNextFrame(); if (frameData) - _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _anmRect); + // WORKAROUND: Ignore the target frame dimensions for the finger animations. + // The target dimensions specify an area smaller than expected, thus if we + // scale the finger videos to fit these dimensions, they are not aligned + // correctly. Not scaling these videos yields a result identical to the + // original. Fixes bug #6784. + _engine->getRenderManager()->blitSurfaceToBkg(*frameData, _anmRect.left, _anmRect.top); } } diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp index 47da27fa08..9525333ef0 100644 --- a/engines/zvision/scripting/controls/input_control.cpp +++ b/engines/zvision/scripting/controls/input_control.cpp @@ -39,10 +39,10 @@ namespace ZVision { InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) : Control(engine, key, CONTROL_INPUT), + _background(0), _nextTabstop(0), _focused(false), _textChanged(false), - _cursorOffset(0), _enterPressed(false), _readOnly(false), _txtWidth(0), @@ -78,13 +78,13 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre sscanf(values.c_str(), "%u", &fontFormatNumber); - _stringInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); + _stringInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber)); } else if (param.matchString("chooser_init_string", true)) { uint fontFormatNumber; sscanf(values.c_str(), "%u", &fontFormatNumber); - _stringChooserInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); + _stringChooserInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber)); } else if (param.matchString("next_tabstop", true)) { sscanf(values.c_str(), "%u", &_nextTabstop); } else if (param.matchString("cursor_dimensions", true)) { @@ -109,6 +109,15 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); getParams(line, param, values); } + + _maxTxtWidth = _textRectangle.width(); + if (_animation) + _maxTxtWidth -= _animation->getWidth(); +} + +InputControl::~InputControl() { + _background->free(); + delete _background; } bool InputControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { @@ -191,19 +200,31 @@ bool InputControl::process(uint32 deltaTimeInMillis) { if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; + if (!_background) { + _background = _engine->getRenderManager()->getBkgRect(_textRectangle); + } + // First see if we need to render the text if (_textChanged) { // Blit the text using the RenderManager Graphics::Surface txt; - txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_resourcePixelFormat); + txt.copyFrom(*_background); + + int32 oldTxtWidth = _txtWidth; if (!_readOnly || !_focused) - _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt); + _txtWidth = _engine->getTextRenderer()->drawText(_currentInputText, _stringInit, txt); else - _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringChooserInit, txt); + _txtWidth = _engine->getTextRenderer()->drawText(_currentInputText, _stringChooserInit, txt); - _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top); + if (_readOnly || _txtWidth <= _maxTxtWidth) + _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top); + else { + // Assume the last character caused the overflow. + _currentInputText.deleteLastChar(); + _txtWidth = oldTxtWidth; + } txt.free(); } diff --git a/engines/zvision/scripting/controls/input_control.h b/engines/zvision/scripting/controls/input_control.h index 99f7f5287d..6abdb3c692 100644 --- a/engines/zvision/scripting/controls/input_control.h +++ b/engines/zvision/scripting/controls/input_control.h @@ -38,25 +38,25 @@ namespace ZVision { class InputControl : public Control { public: InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~InputControl(); private: + Graphics::Surface *_background; Common::Rect _textRectangle; Common::Rect _headerRectangle; - cTxtStyle _stringInit; - cTxtStyle _stringChooserInit; + TextStyleState _stringInit; + TextStyleState _stringChooserInit; uint32 _nextTabstop; bool _focused; Common::String _currentInputText; bool _textChanged; - uint _cursorOffset; bool _enterPressed; bool _readOnly; int16 _txtWidth; + int16 _maxTxtWidth; Video::VideoDecoder *_animation; - int32 _frameDelay; - int16 _frame; public: void focus() { diff --git a/engines/zvision/scripting/controls/lever_control.cpp b/engines/zvision/scripting/controls/lever_control.cpp index bef51f0e91..0f105b424c 100644 --- a/engines/zvision/scripting/controls/lever_control.cpp +++ b/engines/zvision/scripting/controls/lever_control.cpp @@ -232,10 +232,13 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common if (angle >= (int)iter->angle - ANGLE_DELTA && angle <= (int)iter->angle + ANGLE_DELTA) { _currentFrame = iter->toFrame; renderFrame(_currentFrame); + _engine->getScriptManager()->setStateValue(_key, _currentFrame); break; } } } + _engine->getCursorManager()->changeCursor(_cursor); + cursorWasChanged = true; } else if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) { _engine->getCursorManager()->changeCursor(_cursor); cursorWasChanged = true; diff --git a/engines/zvision/scripting/controls/safe_control.cpp b/engines/zvision/scripting/controls/safe_control.cpp index 6ba34106d0..4d2a91a1ad 100644 --- a/engines/zvision/scripting/controls/safe_control.cpp +++ b/engines/zvision/scripting/controls/safe_control.cpp @@ -123,6 +123,8 @@ bool SafeControl::process(uint32 deltaTimeInMillis) { _animation->seekToFrame(_animation->getCurFrame() - 1); const Graphics::Surface *frameData = _animation->decodeNextFrame(); + if (_animation->getCurFrame() == _targetFrame) + _engine->getScriptManager()->setStateValue(_key, _curState); if (frameData) _engine->getRenderManager()->blitSurfaceToBkg(*frameData, _rectangle.left, _rectangle.top); } @@ -169,8 +171,6 @@ bool SafeControl::onMouseUp(const Common::Point &screenSpacePos, const Common::P _curState = (_statesCount * 2 + tmp2) % _statesCount; _targetFrame = (_curState + _statesCount - _startPointer) % _statesCount; - - _engine->getScriptManager()->setStateValue(_key, _curState); return true; } } diff --git a/engines/zvision/scripting/controls/titler_control.cpp b/engines/zvision/scripting/controls/titler_control.cpp index 542e0a0b67..683d6660af 100644 --- a/engines/zvision/scripting/controls/titler_control.cpp +++ b/engines/zvision/scripting/controls/titler_control.cpp @@ -82,7 +82,7 @@ TitlerControl::~TitlerControl() { void TitlerControl::setString(int strLine) { if (strLine != _curString && strLine >= 0 && strLine < (int)_strings.size()) { _surface->fillRect(Common::Rect(_surface->w, _surface->h), 0); - _engine->getTextRenderer()->drawTxtInOneLine(_strings[strLine], *_surface); + _engine->getTextRenderer()->drawTextWithWordWrapping(_strings[strLine], *_surface); _engine->getRenderManager()->blitSurfaceToBkg(*_surface, _rectangle.left, _rectangle.top); _curString = strLine; } diff --git a/engines/zvision/scripting/effects/distort_effect.cpp b/engines/zvision/scripting/effects/distort_effect.cpp index 78c4a1b9a8..113b5d048d 100644 --- a/engines/zvision/scripting/effects/distort_effect.cpp +++ b/engines/zvision/scripting/effects/distort_effect.cpp @@ -52,7 +52,7 @@ DistortNode::DistortNode(ZVision *engine, uint32 key, int16 speed, float startAn _diffLinScale = endLineScale - startLineScale; _frmSpeed = (float)speed / 15.0; - _frames = ceil((5.0 - _frmSpeed * 2.0) / _frmSpeed); + _frames = (int)ceil((5.0 - _frmSpeed * 2.0) / _frmSpeed); if (_frames <= 0) _frames = 1; diff --git a/engines/zvision/scripting/effects/music_effect.cpp b/engines/zvision/scripting/effects/music_effect.cpp index 102f330305..e3fdc96dba 100644 --- a/engines/zvision/scripting/effects/music_effect.cpp +++ b/engines/zvision/scripting/effects/music_effect.cpp @@ -36,16 +36,33 @@ namespace ZVision { -MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, int8 volume) +static const uint8 dbMapLinear[256] = +{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, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, +2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, +4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, +8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, +14, 15, 15, 16, 16, 17, 18, 18, 19, 20, 21, 21, 22, 23, 24, 25, +26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 40, 41, 43, 45, +46, 48, 50, 52, 53, 55, 57, 60, 62, 64, 67, 69, 72, 74, 77, 80, +83, 86, 89, 92, 96, 99, 103, 107, 111, 115, 119, 123, 128, 133, 137, 143, +148, 153, 159, 165, 171, 177, 184, 191, 198, 205, 212, 220, 228, 237, 245, 255}; + +MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, uint8 volume) : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) { _loop = loop; _volume = volume; + _deltaVolume = 0; + _balance = 0; _crossfade = false; _crossfadeTarget = 0; _crossfadeTime = 0; - _attenuate = 0; - _pantrack = false; - _pantrackPosition = 0; _sub = NULL; _stereo = false; _loaded = false; @@ -66,9 +83,9 @@ MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool if (_loop) { Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); - _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, _volume); + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, dbMapLinear[_volume]); } else { - _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, _volume); + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, dbMapLinear[_volume]); } if (_key != StateKey_NotSet) @@ -94,20 +111,17 @@ MusicNode::~MusicNode() { _engine->getScriptManager()->setStateValue(_key, 2); if (_sub) delete _sub; - debug(1, "MusicNode: %d destroyed\n", _key); + debug(1, "MusicNode: %d destroyed", _key); } -void MusicNode::setPanTrack(int16 pos) { - if (!_stereo) { - _pantrack = true; - _pantrackPosition = pos; - setVolume(_volume); - } +void MusicNode::setDeltaVolume(uint8 volume) { + _deltaVolume = volume; + setVolume(_volume); } -void MusicNode::unsetPanTrack() { - _pantrack = false; - setVolume(_volume); +void MusicNode::setBalance(int8 balance) { + _balance = balance; + _engine->_mixer->setChannelBalance(_handle, _balance); } void MusicNode::setFade(int32 time, uint8 target) { @@ -126,7 +140,7 @@ bool MusicNode::process(uint32 deltaTimeInMillis) { if (_crossfadeTime > 0) { if ((int32)deltaTimeInMillis > _crossfadeTime) deltaTimeInMillis = _crossfadeTime; - _newvol += floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis; + _newvol += (int)(floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis); _crossfadeTime -= deltaTimeInMillis; } else { _crossfade = false; @@ -134,7 +148,7 @@ bool MusicNode::process(uint32 deltaTimeInMillis) { } } - if (_pantrack || _volume != _newvol) + if (_volume != _newvol) setVolume(_newvol); if (_sub && _engine->getScriptManager()->getStateValue(StateKey_Subtitles) == 1) @@ -146,55 +160,85 @@ bool MusicNode::process(uint32 deltaTimeInMillis) { void MusicNode::setVolume(uint8 newVolume) { if (!_loaded) return; - if (_pantrack) { - int curX = _engine->getScriptManager()->getStateValue(StateKey_ViewPos); - curX -= _pantrackPosition; - int32 _width = _engine->getRenderManager()->getBkgSize().x; - if (curX < (-_width) / 2) - curX += _width; - else if (curX >= _width / 2) - curX -= _width; - - float norm = (float)curX / ((float)_width / 2.0); - float lvl = fabs(norm); - if (lvl > 0.5) - lvl = (lvl - 0.5) * 1.7; - else - lvl = 1.0; - float bal = sin(-norm * 3.1415926) * 127.0; + _volume = newVolume; - if (_engine->_mixer->isSoundHandleActive(_handle)) { - _engine->_mixer->setChannelBalance(_handle, bal); - _engine->_mixer->setChannelVolume(_handle, newVolume * lvl); - } - } else { - if (_engine->_mixer->isSoundHandleActive(_handle)) { - _engine->_mixer->setChannelBalance(_handle, 0); - _engine->_mixer->setChannelVolume(_handle, newVolume); - } - } + if (_deltaVolume >= _volume) + _engine->_mixer->setChannelVolume(_handle, 0); + else + _engine->_mixer->setChannelVolume(_handle, dbMapLinear[_volume - _deltaVolume]); +} - _volume = newVolume; +uint8 MusicNode::getVolume() { + return _volume; } PanTrackNode::PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos) : ScriptingEffect(engine, key, SCRIPTING_EFFECT_PANTRACK) { _slot = slot; + _position = pos; - ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(slot); - if (fx && fx->getType() == SCRIPTING_EFFECT_AUDIO) { - MusicNodeBASE *mus = (MusicNodeBASE *)fx; - mus->setPanTrack(pos); - } + // Try to set pan value for music node immediately + process(0); } PanTrackNode::~PanTrackNode() { - ScriptingEffect *fx = _engine->getScriptManager()->getSideFX(_slot); +} + +bool PanTrackNode::process(uint32 deltaTimeInMillis) { + ScriptManager * scriptManager = _engine->getScriptManager(); + ScriptingEffect *fx = scriptManager->getSideFX(_slot); if (fx && fx->getType() == SCRIPTING_EFFECT_AUDIO) { MusicNodeBASE *mus = (MusicNodeBASE *)fx; - mus->unsetPanTrack(); + + int curPos = scriptManager->getStateValue(StateKey_ViewPos); + int16 _width = _engine->getRenderManager()->getBkgSize().x; + int16 _halfWidth = _width / 2; + int16 _quarterWidth = _width / 4; + + int tmp = 0; + if (curPos <= _position) + tmp = _position - curPos; + else + tmp = _position - curPos + _width; + + int balance = 0; + + if (tmp > _halfWidth) + tmp -= _width; + + if (tmp > _quarterWidth) { + balance = 1; + tmp = _halfWidth - tmp; + } else if (tmp < -_quarterWidth) { + balance = -1; + tmp = -_halfWidth - tmp; + } + + // Originally it's value -90...90 but we use -127...127 and therefore 360 replaced by 508 + mus->setBalance( (508 * tmp) / _width ); + + tmp = (360 * tmp) / _width; + + int deltaVol = balance; + + // This value sets how fast volume goes off than sound source back of you + // By this value we can hack some "bugs" have place in originall game engine like beat sound in ZGI-dc10 + int volumeCorrection = 2; + + if (_engine->getGameId() == GID_GRANDINQUISITOR) { + if (scriptManager->getCurrentLocation() == "dc10") + volumeCorrection = 5; + } + + if (deltaVol != 0) + deltaVol = (mus->getVolume() * volumeCorrection) * (90 - tmp * balance) / 90; + if (deltaVol > 255) + deltaVol = 255; + + mus->setDeltaVolume(deltaVol); } + return false; } MusicMidiNode::MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume) @@ -225,10 +269,10 @@ MusicMidiNode::~MusicMidiNode() { _engine->getScriptManager()->setStateValue(_key, 2); } -void MusicMidiNode::setPanTrack(int16 pos) { +void MusicMidiNode::setDeltaVolume(uint8 volume) { } -void MusicMidiNode::unsetPanTrack() { +void MusicMidiNode::setBalance(int8 balance) { } void MusicMidiNode::setFade(int32 time, uint8 target) { @@ -245,4 +289,8 @@ void MusicMidiNode::setVolume(uint8 newVolume) { _volume = newVolume; } +uint8 MusicMidiNode::getVolume() { + return _volume; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/effects/music_effect.h b/engines/zvision/scripting/effects/music_effect.h index 31d538f668..7657be8e09 100644 --- a/engines/zvision/scripting/effects/music_effect.h +++ b/engines/zvision/scripting/effects/music_effect.h @@ -48,16 +48,16 @@ public: virtual bool process(uint32 deltaTimeInMillis) = 0; virtual void setVolume(uint8 volume) = 0; - - virtual void setPanTrack(int16 pos) = 0; - virtual void unsetPanTrack() = 0; + virtual uint8 getVolume() = 0; + virtual void setDeltaVolume(uint8 volume) = 0; + virtual void setBalance(int8 balance) = 0; virtual void setFade(int32 time, uint8 target) = 0; }; class MusicNode : public MusicNodeBASE { public: - MusicNode(ZVision *engine, uint32 key, Common::String &file, bool loop, int8 volume); + MusicNode(ZVision *engine, uint32 key, Common::String &file, bool loop, uint8 volume); ~MusicNode(); /** @@ -70,17 +70,16 @@ public: bool process(uint32 deltaTimeInMillis); void setVolume(uint8 volume); - - void setPanTrack(int16 pos); - void unsetPanTrack(); + uint8 getVolume(); + void setDeltaVolume(uint8 volume); + void setBalance(int8 balance); void setFade(int32 time, uint8 target); private: - bool _pantrack; - int32 _pantrackPosition; - int32 _attenuate; uint8 _volume; + uint8 _deltaVolume; + int8 _balance; bool _loop; bool _crossfade; uint8 _crossfadeTarget; @@ -107,9 +106,9 @@ public: bool process(uint32 deltaTimeInMillis); void setVolume(uint8 volume); - - void setPanTrack(int16 pos); - void unsetPanTrack(); + uint8 getVolume(); + void setDeltaVolume(uint8 volume); + void setBalance(int8 balance); void setFade(int32 time, uint8 target); @@ -126,8 +125,11 @@ public: PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos); ~PanTrackNode(); + bool process(uint32 deltaTimeInMillis); + private: uint32 _slot; + int16 _position; }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/effects/ttytext_effect.cpp b/engines/zvision/scripting/effects/ttytext_effect.cpp index c60b3aa8c5..8d340dae39 100644 --- a/engines/zvision/scripting/effects/ttytext_effect.cpp +++ b/engines/zvision/scripting/effects/ttytext_effect.cpp @@ -57,9 +57,9 @@ ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file delete infile; } _img.create(_r.width(), _r.height(), _engine->_resourcePixelFormat); - _style._sharp = true; - _style.readAllStyle(_txtbuf); - _style.setFont(_fnt); + _state._sharp = true; + _state.readAllStyles(_txtbuf); + _state.updateFontWithTextState(_fnt); _engine->getScriptManager()->setStateValue(_key, 1); } @@ -74,29 +74,27 @@ bool ttyTextNode::process(uint32 deltaTimeInMillis) { if (_nexttime < 0) { if (_txtpos < _txtbuf.size()) { if (_txtbuf[_txtpos] == '<') { - int32 strt = _txtpos; - int32 endt = 0; + int32 start = _txtpos; + int32 end = 0; int16 ret = 0; while (_txtbuf[_txtpos] != '>' && _txtpos < _txtbuf.size()) _txtpos++; - endt = _txtpos; - if (strt != -1) - if ((endt - strt - 1) > 0) - ret = _style.parseStyle(_txtbuf.c_str() + strt + 1, endt - strt - 1); - - if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) { - if (ret & TXT_RET_FNTCHG) - _style.setFont(_fnt); - if (ret & TXT_RET_FNTSTL) - _style.setFontStyle(_fnt); - - if (ret & TXT_RET_NEWLN) - newline(); + end = _txtpos; + if (start != -1) { + if ((end - start - 1) > 0) { + ret = _state.parseStyle(_txtbuf.c_str() + start + 1, end - start - 1); + } + } + + if (ret & (TEXT_CHANGE_FONT_TYPE | TEXT_CHANGE_FONT_STYLE)) { + _state.updateFontWithTextState(_fnt); + } else if (ret & TEXT_CHANGE_NEWLINE) { + newline(); } - if (ret & TXT_RET_HASSTBOX) { + if (ret & TEXT_CHANGE_HAS_STATE_BOX) { Common::String buf; - buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_style._statebox)); + buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_state._statebox)); for (uint8 j = 0; j < buf.size(); j++) outchar(buf[j]); @@ -158,7 +156,7 @@ void ttyTextNode::newline() { } void ttyTextNode::outchar(uint16 chr) { - uint32 clr = _engine->_resourcePixelFormat.RGBToColor(_style._red, _style._green, _style._blue); + uint32 clr = _engine->_resourcePixelFormat.RGBToColor(_state._red, _state._green, _state._blue); if (_dx + _fnt.getCharWidth(chr) > _r.width()) newline(); diff --git a/engines/zvision/scripting/effects/ttytext_effect.h b/engines/zvision/scripting/effects/ttytext_effect.h index 8d8a2518c7..18cbbbaee3 100644 --- a/engines/zvision/scripting/effects/ttytext_effect.h +++ b/engines/zvision/scripting/effects/ttytext_effect.h @@ -51,7 +51,7 @@ public: private: Common::Rect _r; - cTxtStyle _style; + TextStyleState _state; StyledTTFont _fnt; Common::String _txtbuf; uint32 _txtpos; diff --git a/engines/zvision/scripting/menu.cpp b/engines/zvision/scripting/menu.cpp index 16aa57e3ae..064bd1b57d 100644 --- a/engines/zvision/scripting/menu.cpp +++ b/engines/zvision/scripting/menu.cpp @@ -46,13 +46,13 @@ MenuHandler::MenuHandler(ZVision *engine) { MenuZGI::MenuZGI(ZVision *engine) : MenuHandler(engine) { menuMouseFocus = -1; - inmenu = false; + inMenu = false; scrolled[0] = false; scrolled[1] = false; scrolled[2] = false; - scrollPos[0] = 0.0; - scrollPos[1] = 0.0; - scrollPos[2] = 0.0; + scrollPos[0] = 0; + scrollPos[1] = 0; + scrollPos[2] = 0; mouseOnItem = -1; redraw = false; clean = false; @@ -60,15 +60,15 @@ MenuZGI::MenuZGI(ZVision *engine) : char buf[24]; for (int i = 1; i < 4; i++) { sprintf(buf, "gmzau%2.2x1.tga", i); - _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][0], false); + _engine->getRenderManager()->readImageToSurface(buf, menuBack[i - 1][0], false); sprintf(buf, "gmzau%2.2x1.tga", i + 0x10); - _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][1], false); + _engine->getRenderManager()->readImageToSurface(buf, menuBack[i - 1][1], false); } for (int i = 0; i < 4; i++) { sprintf(buf, "gmzmu%2.2x1.tga", i); - _engine->getRenderManager()->readImageToSurface(buf, menubar[i][0], false); + _engine->getRenderManager()->readImageToSurface(buf, menuBar[i][0], false); sprintf(buf, "gmznu%2.2x1.tga", i); - _engine->getRenderManager()->readImageToSurface(buf, menubar[i][1], false); + _engine->getRenderManager()->readImageToSurface(buf, menuBar[i][1], false); } for (int i = 0; i < 50; i++) { @@ -86,12 +86,12 @@ MenuZGI::MenuZGI(ZVision *engine) : MenuZGI::~MenuZGI() { for (int i = 0; i < 3; i++) { - menuback[i][0].free(); - menuback[i][1].free(); + menuBack[i][0].free(); + menuBack[i][1].free(); } for (int i = 0; i < 4; i++) { - menubar[i][0].free(); - menubar[i][1].free(); + menuBar[i][0].free(); + menuBar[i][1].free(); } for (int i = 0; i < 50; i++) { if (items[i][0]) { @@ -208,9 +208,9 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) { void MenuZGI::onMouseMove(const Common::Point &Pos) { if (Pos.y < 40) { - if (!inmenu) + if (!inMenu) redraw = true; - inmenu = true; + inMenu = true; switch (menuMouseFocus) { case kMenuItem: if (menuBarFlag & kMenubarItems) { @@ -311,7 +311,7 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) { if (Common::Rect(64, 0, 64 + 512, 8).contains(Pos)) { // Main menuMouseFocus = kMenuMain; scrolled[kMenuMain] = false; - scrollPos[kMenuMain] = menuback[kMenuMain][1].h - menuback[kMenuMain][0].h; + scrollPos[kMenuMain] = menuBack[kMenuMain][1].h - menuBack[kMenuMain][0].h; _engine->getScriptManager()->setStateValue(StateKey_MenuState, 2); } @@ -337,9 +337,9 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) { break; } } else { - if (inmenu) + if (inMenu) clean = true; - inmenu = false; + inMenu = false; if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0) _engine->getScriptManager()->setStateValue(StateKey_MenuState, 0); menuMouseFocus = -1; @@ -361,15 +361,15 @@ void MenuZGI::process(uint32 deltatime) { if (scrl == 0) scrl = 1.0; - scrollPos [kMenuItem] += scrl; + scrollPos[kMenuItem] += (int)scrl; if (scrollPos[kMenuItem] >= 0) { scrolled[kMenuItem] = true; - scrollPos [kMenuItem] = 0; + scrollPos[kMenuItem] = 0; } } if (redraw) { - _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuItem][0], scrollPos[kMenuItem], 0); + _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuItem][0], scrollPos[kMenuItem], 0); int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots); if (itemCount == 0) @@ -430,15 +430,15 @@ void MenuZGI::process(uint32 deltatime) { if (scrl == 0) scrl = 1.0; - scrollPos [kMenuMagic] += scrl; + scrollPos[kMenuMagic] += (int)scrl; if (scrollPos[kMenuMagic] >= 600) { scrolled[kMenuMagic] = true; - scrollPos [kMenuMagic] = 600; + scrollPos[kMenuMagic] = 600; } } if (redraw) { - _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMagic][0], 640 - scrollPos[kMenuMagic], 0); + _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMagic][0], 640 - scrollPos[kMenuMagic], 0); for (int i = 0; i < 12; i++) { bool inrect = false; @@ -495,53 +495,53 @@ void MenuZGI::process(uint32 deltatime) { if (scrl == 0) scrl = 1.0; - scrollPos [kMenuMain] += scrl; + scrollPos[kMenuMain] += (int)scrl; if (scrollPos[kMenuMain] >= 0) { scrolled[kMenuMain] = true; - scrollPos [kMenuMain] = 0; + scrollPos[kMenuMain] = 0; } } if (redraw) { - _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMain][0], 30, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMain][0], 30, scrollPos[kMenuMain]); if (menuBarFlag & kMenubarExit) { if (mouseOnItem == kMainMenuExit) - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuExit][1], 320 + 135, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuExit][1], 320 + 135, scrollPos[kMenuMain]); else - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuExit][0], 320 + 135, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuExit][0], 320 + 135, scrollPos[kMenuMain]); } if (menuBarFlag & kMenubarSettings) { if (mouseOnItem == kMainMenuPrefs) - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuPrefs][1], 320, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuPrefs][1], 320, scrollPos[kMenuMain]); else - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuPrefs][0], 320, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuPrefs][0], 320, scrollPos[kMenuMain]); } if (menuBarFlag & kMenubarRestore) { if (mouseOnItem == kMainMenuLoad) - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuLoad][1], 320 - 135, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuLoad][1], 320 - 135, scrollPos[kMenuMain]); else - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuLoad][0], 320 - 135, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuLoad][0], 320 - 135, scrollPos[kMenuMain]); } if (menuBarFlag & kMenubarSave) { if (mouseOnItem == kMainMenuSave) - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuSave][1], 320 - 135 * 2, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuSave][1], 320 - 135 * 2, scrollPos[kMenuMain]); else - _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuSave][0], 320 - 135 * 2, scrollPos[kMenuMain]); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuSave][0], 320 - 135 * 2, scrollPos[kMenuMain]); } redraw = false; } break; default: if (redraw) { - if (inmenu) { - _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMain][1], 30, 0); + if (inMenu) { + _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMain][1], 30, 0); if (menuBarFlag & kMenubarItems) - _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuItem][1], 0, 0); + _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuItem][1], 0, 0); if (menuBarFlag & kMenubarMagic) - _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMagic][1], 640 - 28, 0); + _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMagic][1], 640 - 28, 0); } redraw = false; } @@ -551,9 +551,9 @@ void MenuZGI::process(uint32 deltatime) { MenuNemesis::MenuNemesis(ZVision *engine) : MenuHandler(engine) { - inmenu = false; + inMenu = false; scrolled = false; - scrollPos = 0.0; + scrollPos = 0; mouseOnItem = -1; redraw = false; delay = 0; @@ -565,7 +565,7 @@ MenuNemesis::MenuNemesis(ZVision *engine) : _engine->getRenderManager()->readImageToSurface(buf, but[i][j], false); } - _engine->getRenderManager()->readImageToSurface("bar.tga", menubar, false); + _engine->getRenderManager()->readImageToSurface("bar.tga", menuBar, false); frm = 0; } @@ -575,7 +575,7 @@ MenuNemesis::~MenuNemesis() { for (int j = 0; j < 6; j++) but[i][j].free(); - menubar.free(); + menuBar.free(); } static const int16 buts[4][2] = { {120 , 64}, {144, 184}, {128, 328}, {120, 456} }; @@ -631,7 +631,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) { void MenuNemesis::onMouseMove(const Common::Point &Pos) { if (Pos.y < 40) { - inmenu = true; + inMenu = true; if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 2) _engine->getScriptManager()->setStateValue(StateKey_MenuState, 2); @@ -681,7 +681,7 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) { delay = 200; } } else { - inmenu = false; + inMenu = false; if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0) _engine->getScriptManager()->setStateValue(StateKey_MenuState, 0); mouseOnItem = -1; @@ -689,14 +689,14 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) { } void MenuNemesis::process(uint32 deltatime) { - if (inmenu) { + if (inMenu) { if (!scrolled) { float scrl = 32.0 * 2.0 * (deltatime / 1000.0); if (scrl == 0) scrl = 1.0; - scrollPos += scrl; + scrollPos += (int)scrl; redraw = true; } @@ -715,7 +715,7 @@ void MenuNemesis::process(uint32 deltatime) { } if (redraw) { - _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar, 64, scrollPos); if (menuBarFlag & kMenubarExit) if (mouseOnItem == kMainMenuExit) @@ -743,16 +743,16 @@ void MenuNemesis::process(uint32 deltatime) { if (scrl == 0) scrl = 1.0; - Common::Rect cl(64, 32 + scrollPos - scrl, 64 + 512, 32 + scrollPos + 1); + Common::Rect cl(64, (int16)(32 + scrollPos - scrl), 64 + 512, 32 + scrollPos + 1); _engine->getRenderManager()->clearMenuSurface(cl); - scrollPos -= scrl; + scrollPos -= (int)scrl; redraw = true; } else scrollPos = -32; if (redraw) { - _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos); + _engine->getRenderManager()->blitSurfaceToMenu(menuBar, 64, scrollPos); redraw = false; } } diff --git a/engines/zvision/scripting/menu.h b/engines/zvision/scripting/menu.h index a88587966f..f6b21b9c97 100644 --- a/engines/zvision/scripting/menu.h +++ b/engines/zvision/scripting/menu.h @@ -68,8 +68,8 @@ public: void onMouseUp(const Common::Point &Pos); void process(uint32 deltaTimeInMillis); private: - Graphics::Surface menuback[3][2]; - Graphics::Surface menubar[4][2]; + Graphics::Surface menuBack[3][2]; + Graphics::Surface menuBar[4][2]; Graphics::Surface *items[50][2]; uint itemId[50]; @@ -77,11 +77,11 @@ private: uint magicId[12]; int menuMouseFocus; - bool inmenu; + bool inMenu; int mouseOnItem; - bool scrolled[3]; + bool scrolled[3]; int16 scrollPos[3]; bool clean; @@ -98,13 +98,13 @@ public: void process(uint32 deltaTimeInMillis); private: Graphics::Surface but[4][6]; - Graphics::Surface menubar; + Graphics::Surface menuBar; - bool inmenu; + bool inMenu; int mouseOnItem; - bool scrolled; + bool scrolled; int16 scrollPos; bool redraw; @@ -114,6 +114,6 @@ private: }; -} +} // End of namespace ZVision #endif diff --git a/engines/zvision/scripting/scr_file_handling.cpp b/engines/zvision/scripting/scr_file_handling.cpp index 7856bf7b2e..edc1b8622c 100644 --- a/engines/zvision/scripting/scr_file_handling.cpp +++ b/engines/zvision/scripting/scr_file_handling.cpp @@ -47,15 +47,13 @@ namespace ZVision { void ScriptManager::parseScrFile(const Common::String &fileName, ScriptScope &scope) { Common::File file; if (!_engine->getSearchManager()->openFile(file, fileName)) { - warning("Script file not found: %s", fileName.c_str()); - return; + error("Script file not found: %s", fileName.c_str()); } while (!file.eos()) { Common::String line = file.readLine(); if (file.err()) { - warning("Error parsing scr file: %s", fileName.c_str()); - return; + error("Error parsing scr file: %s", fileName.c_str()); } trimCommentsAndWhiteSpace(&line); @@ -85,9 +83,18 @@ void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stre while (!stream.eos() && !line.contains('}')) { if (line.matchString("criteria {", true)) { - parseCriteria(stream, puzzle->criteriaList); + parseCriteria(stream, puzzle->criteriaList, puzzle->key); } else if (line.matchString("results {", true)) { parseResults(stream, puzzle->resultActions); + + // WORKAROUND for a script bug in Zork Nemesis, room ve5e (tuning + // fork box closeup). If the player leaves the screen while the + // box is open, puzzle 19398 shows the animation where the box + // closes, but the box state (state variable 19397) is not updated. + // We insert the missing assignment for the box state here. + // Fixes bug #6803. + if (_engine->getGameId() == GID_NEMESIS && puzzle->key == 19398) + puzzle->resultActions.push_back(new ActionAssign(_engine, 11, "19397, 0")); } else if (line.matchString("flags {", true)) { setStateFlag(puzzle->key, parseFlags(stream)); } @@ -99,11 +106,18 @@ void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stre puzzle->addedBySetState = false; } -bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const { +bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList, uint32 key) const { // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + // Skip any commented out criteria. If all the criteria are commented out, + // we might end up with an invalid criteria list (bug #6776). + while (line.empty()) { + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + } + // Criteria can be empty if (line.contains('}')) { return false; @@ -112,6 +126,21 @@ bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::Li // Create a new List to hold the CriteriaEntries criteriaList.push_back(Common::List<Puzzle::CriteriaEntry>()); + // WORKAROUND for a script bug in Zork: Nemesis, room td9e (fist puzzle) + // Since we patch the script that triggers when manipulating the left fist + // (below), we add an additional check for the left fist sound, so that it + // doesn't get killed immediately when the left fist animation starts. + // Together with the workaround below, it fixes bug #6783. + if (_engine->getGameId() == GID_NEMESIS && key == 3594) { + Puzzle::CriteriaEntry entry; + entry.key = 567; + entry.criteriaOperator = Puzzle::NOT_EQUAL_TO; + entry.argumentIsAKey = false; + entry.argument = 1; + + criteriaList.back().push_back(entry); + } + while (!stream.eos() && !line.contains('}')) { Puzzle::CriteriaEntry entry; @@ -123,6 +152,13 @@ bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::Li token = tokenizer.nextToken(); sscanf(token.c_str(), "[%u]", &(entry.key)); + // WORKAROUND for a script bug in Zork: Nemesis, room td9e (fist puzzle) + // Check for the state of animation 567 (left fist) when manipulating + // the fingers of the left fist (puzzle slots 3582, 3583). + // Together with the workaround above, it fixes bug #6783. + if (_engine->getGameId() == GID_NEMESIS && (key == 3582 || key == 3583) && entry.key == 568) + entry.key = 567; + // Parse the operator out of the second token token = tokenizer.nextToken(); if (token.c_str()[0] == '=') @@ -134,9 +170,17 @@ bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::Li else if (token.c_str()[0] == '<') entry.criteriaOperator = Puzzle::LESS_THAN; + // There are supposed to be three tokens, but there is no + // guarantee that there will be a space between the second and + // the third one (bug #6774) + if (token.size() == 1) { + token = tokenizer.nextToken(); + } else { + token.deleteChar(0); + } + // First determine if the last token is an id or a value // Then parse it into 'argument' - token = tokenizer.nextToken(); if (token.contains('[')) { sscanf(token.c_str(), "[%u]", &(entry.argument)); entry.argumentIsAKey = true; @@ -271,8 +315,8 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis actionList.push_back(new ActionRegion(_engine, slot, args)); } else if (act.matchString("restore_game", true)) { // Only used by ZGI to load the restart game slot, r.svr. - _engine->getScriptManager()->reset(); - _engine->getScriptManager()->changeLocation('g', 'a', 'r', 'y', 0); + // Used by the credits screen. + actionList.push_back(new ActionRestoreGame(_engine, slot, args)); } else if (act.matchString("rotate_to", true)) { actionList.push_back(new ActionRotateTo(_engine, slot, args)); } else if (act.matchString("save_game", true)) { @@ -343,6 +387,16 @@ Control *ScriptManager::parseControl(Common::String &line, Common::SeekableReadS Common::String controlType(controlTypeBuffer); if (controlType.equalsIgnoreCase("push_toggle")) { + // WORKAROUND for a script bug in ZGI: There is an invalid hotspot + // at scene em1h (bottom of tower), which points to a missing + // script em1n. This is a hotspot at the right of the screen. + // In the original, this hotspot doesn't lead anywhere anyway, + // so instead of moving to a missing scene, we just remove the + // hotspot altogether. The alternative would be to just process + // and ignore invalid scenes, but I don't think it's worth the + // effort. Fixes bug #6780. + if (_engine->getGameId() == GID_GRANDINQUISITOR && key == 5653) + return NULL; return new PushToggleControl(_engine, key, stream); } else if (controlType.equalsIgnoreCase("flat")) { Control::parseFlatControl(_engine); diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp index ba38d3a0e4..70eaab2a0a 100644 --- a/engines/zvision/scripting/script_manager.cpp +++ b/engines/zvision/scripting/script_manager.cpp @@ -72,21 +72,23 @@ void ScriptManager::initialize() { } void ScriptManager::update(uint deltaTimeMillis) { - if (_currentLocation.node != _nextLocation.node || - _currentLocation.room != _nextLocation.room || - _currentLocation.view != _nextLocation.view || - _currentLocation.world != _nextLocation.world) - ChangeLocationReal(); + if (_currentLocation != _nextLocation) { + ChangeLocationReal(false); + } updateNodes(deltaTimeMillis); - if (! execScope(nodeview)) + if (!execScope(nodeview)) { return; - if (! execScope(room)) + } + if (!execScope(room)) { return; - if (! execScope(world)) + } + if (!execScope(world)) { return; - if (! execScope(universe)) + } + if (!execScope(universe)) { return; + } updateControls(deltaTimeMillis); } @@ -97,17 +99,22 @@ bool ScriptManager::execScope(ScriptScope &scope) { scope.scopeQueue = tmp; scope.scopeQueue->clear(); - for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) { (*PuzzleIter)->addedBySetState = false; + } if (scope.procCount < 2 || getStateValue(StateKey_ExecScopeStyle)) { - for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) - if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) { + if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) { return false; + } + } } else { - for (PuzzleList::iterator PuzzleIter = scope.execQueue->begin(); PuzzleIter != scope.execQueue->end(); ++PuzzleIter) - if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) + for (PuzzleList::iterator PuzzleIter = scope.execQueue->begin(); PuzzleIter != scope.execQueue->end(); ++PuzzleIter) { + if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) { return false; + } + } } if (scope.procCount < 2) { @@ -119,9 +126,11 @@ bool ScriptManager::execScope(ScriptScope &scope) { void ScriptManager::referenceTableAddPuzzle(uint32 key, PuzzleRef ref) { if (_referenceTable.contains(key)) { Common::Array<PuzzleRef> *arr = &_referenceTable[key]; - for (uint32 i = 0; i < arr->size(); i++) - if ((*arr)[i].puz == ref.puz) + for (uint32 i = 0; i < arr->size(); i++) { + if ((*arr)[i].puz == ref.puz) { return; + } + } } _referenceTable[key].push_back(ref); @@ -139,9 +148,11 @@ void ScriptManager::addPuzzlesToReferenceTable(ScriptScope &scope) { referenceTableAddPuzzle(puzzlePtr->key, ref); // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*PuzzleIter)->criteriaList.begin(); criteriaIter != (*PuzzleIter)->criteriaList.end(); ++criteriaIter) - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) + for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*PuzzleIter)->criteriaList.begin(); criteriaIter != (*PuzzleIter)->criteriaList.end(); ++criteriaIter) { + for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { referenceTableAddPuzzle(entryIter->key, ref); + } + } } } @@ -159,8 +170,9 @@ void ScriptManager::updateNodes(uint deltaTimeMillis) { } void ScriptManager::updateControls(uint deltaTimeMillis) { - if (!_activeControls) + if (!_activeControls) { return; + } // Process only one event if (!_controlEvents.empty()) { @@ -187,21 +199,24 @@ void ScriptManager::updateControls(uint deltaTimeMillis) { _controlEvents.pop_front(); } - for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++) - if ((*iter)->process(deltaTimeMillis)) + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++) { + if ((*iter)->process(deltaTimeMillis)) { break; + } + } } bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) { // Check if the puzzle is already finished // Also check that the puzzle isn't disabled - if (getStateValue(puzzle->key) == 1 || (getStateFlag(puzzle->key) & Puzzle::DISABLED) == Puzzle::DISABLED) { + if (getStateValue(puzzle->key) == 1 || (getStateFlag(puzzle->key) & Puzzle::DISABLED)) { return true; } // Check each Criteria - if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0) + if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0) { return true; + } bool criteriaMet = false; for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) { @@ -210,10 +225,11 @@ bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) { for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { // Get the value to compare against int argumentValue; - if (entryIter->argumentIsAKey) + if (entryIter->argumentIsAKey) { argumentValue = getStateValue(entryIter->argument); - else + } else { argumentValue = entryIter->argument; + } // Do the comparison switch (entryIter->criteriaOperator) { @@ -251,8 +267,9 @@ bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) { setStateValue(puzzle->key, 1); for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) { - if (!(*resultIter)->execute()) + if (!(*resultIter)->execute()) { return false; + } } } @@ -275,13 +292,15 @@ void ScriptManager::cleanScriptScope(ScriptScope &scope) { scope.privQueueTwo.clear(); scope.scopeQueue = &scope.privQueueOne; scope.execQueue = &scope.privQueueTwo; - for (PuzzleList::iterator iter = scope.puzzles.begin(); iter != scope.puzzles.end(); ++iter) + for (PuzzleList::iterator iter = scope.puzzles.begin(); iter != scope.puzzles.end(); ++iter) { delete(*iter); + } scope.puzzles.clear(); - for (ControlList::iterator iter = scope.controls.begin(); iter != scope.controls.end(); ++iter) + for (ControlList::iterator iter = scope.controls.begin(); iter != scope.controls.end(); ++iter) { delete(*iter); + } scope.controls.clear(); @@ -289,44 +308,49 @@ void ScriptManager::cleanScriptScope(ScriptScope &scope) { } int ScriptManager::getStateValue(uint32 key) { - if (_globalState.contains(key)) + if (_globalState.contains(key)) { return _globalState[key]; - else + } else { return 0; + } } void ScriptManager::queuePuzzles(uint32 key) { if (_referenceTable.contains(key)) { Common::Array<PuzzleRef> *arr = &_referenceTable[key]; - for (int32 i = arr->size() - 1; i >= 0; i--) + for (int32 i = arr->size() - 1; i >= 0; i--) { if (!(*arr)[i].puz->addedBySetState) { (*arr)[i].scope->scopeQueue->push_back((*arr)[i].puz); (*arr)[i].puz->addedBySetState = true; } + } } } void ScriptManager::setStateValue(uint32 key, int value) { - if (value == 0) + if (value == 0) { _globalState.erase(key); - else + } else { _globalState[key] = value; + } queuePuzzles(key); } void ScriptManager::setStateValueSilent(uint32 key, int value) { - if (value == 0) + if (value == 0) { _globalState.erase(key); - else + } else { _globalState[key] = value; + } } uint ScriptManager::getStateFlag(uint32 key) { - if (_globalStateFlags.contains(key)) + if (_globalStateFlags.contains(key)) { return _globalStateFlags[key]; - else + } else { return 0; + } } void ScriptManager::setStateFlag(uint32 key, uint value) { @@ -336,10 +360,11 @@ void ScriptManager::setStateFlag(uint32 key, uint value) { } void ScriptManager::setStateFlagSilent(uint32 key, uint value) { - if (value == 0) + if (value == 0) { _globalStateFlags.erase(key); - else + } else { _globalStateFlags[key] = value; + } } void ScriptManager::unsetStateFlag(uint32 key, uint value) { @@ -348,23 +373,29 @@ void ScriptManager::unsetStateFlag(uint32 key, uint value) { if (_globalStateFlags.contains(key)) { _globalStateFlags[key] &= ~value; - if (_globalStateFlags[key] == 0) + if (_globalStateFlags[key] == 0) { _globalStateFlags.erase(key); + } } } Control *ScriptManager::getControl(uint32 key) { - for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) - if ((*iter)->getKey() == key) + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { + if ((*iter)->getKey() == key) { return *iter; + } + } + return nullptr; } void ScriptManager::focusControl(uint32 key) { - if (!_activeControls) + if (!_activeControls) { return; - if (_currentlyFocusedControl == key) + } + if (_currentlyFocusedControl == key) { return; + } for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { uint32 controlKey = (*iter)->getKey(); @@ -443,50 +474,60 @@ void ScriptManager::killSideFxType(ScriptingEffect::ScriptingEffectType type) { } void ScriptManager::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_activeControls) + if (!_activeControls) { return; + } for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { - if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos)) + if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos)) { return; + } } } void ScriptManager::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_activeControls) + if (!_activeControls) { return; + } for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { - if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos)) + if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos)) { return; + } } } bool ScriptManager::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_activeControls) + if (!_activeControls) { return false; + } for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { - if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos)) + if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos)) { return true; + } } return false; } void ScriptManager::onKeyDown(Common::KeyState keyState) { - if (!_activeControls) + if (!_activeControls) { return; + } for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { - if ((*iter)->onKeyDown(keyState)) + if ((*iter)->onKeyDown(keyState)) { return; + } } } void ScriptManager::onKeyUp(Common::KeyState keyState) { - if (!_activeControls) + if (!_activeControls) { return; + } for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { - if ((*iter)->onKeyUp(keyState)) + if ((*iter)->onKeyUp(keyState)) { return; + } } } @@ -500,8 +541,8 @@ void ScriptManager::changeLocation(char _world, char _room, char _node, char _vi _nextLocation.node = _node; _nextLocation.view = _view; _nextLocation.offset = offset; - // If next location 0000 - it's indicate to go to previous location. - if (_nextLocation.world == '0' && _nextLocation.room == '0' && _nextLocation.node == '0' && _nextLocation.view == '0') { + // If next location is 0000, return to the previous location. + if (_nextLocation == "0000") { if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') { _nextLocation.world = getStateValue(StateKey_LastWorld); _nextLocation.room = getStateValue(StateKey_LastRoom); @@ -518,36 +559,42 @@ void ScriptManager::changeLocation(char _world, char _room, char _node, char _vi } } -void ScriptManager::ChangeLocationReal() { +void ScriptManager::ChangeLocationReal(bool isLoading) { assert(_nextLocation.world != 0); debug(1, "Changing location to: %c %c %c %c %u", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view, _nextLocation.offset); - if (_nextLocation.world == 'g' && _nextLocation.room == 'j' && !ConfMan.getBool("originalsaveload")) { - if ((_nextLocation.node == 's' || _nextLocation.node == 'r') && _nextLocation.view == 'e') { + const bool enteringMenu = (_nextLocation.world == 'g' && _nextLocation.room == 'j'); + const bool leavingMenu = (_currentLocation.world == 'g' && _currentLocation.room == 'j'); + const bool isSaveScreen = (enteringMenu && _nextLocation.node == 's' && _nextLocation.view == 'e'); + const bool isRestoreScreen = (enteringMenu && _nextLocation.node == 'r' && _nextLocation.view == 'e'); + + if (enteringMenu && !ConfMan.getBool("originalsaveload")) { + if (isSaveScreen || isRestoreScreen) { // Hook up the ScummVM save/restore dialog - bool isSave = (_nextLocation.node == 's'); - bool gameSavedOrLoaded = _engine->getSaveManager()->scummVMSaveLoadDialog(isSave); - if (!gameSavedOrLoaded || isSave) { + bool gameSavedOrLoaded = _engine->getSaveManager()->scummVMSaveLoadDialog(isSaveScreen); + if (!gameSavedOrLoaded || isSaveScreen) { // Reload the current room _nextLocation.world = _currentLocation.world; _nextLocation.room = _currentLocation.room; _nextLocation.node = _currentLocation.node; _nextLocation.view = _currentLocation.view; _nextLocation.offset = _currentLocation.offset; - _currentLocation.world = '0'; + + return; + } else { + _currentLocation.world = 'g'; _currentLocation.room = '0'; _currentLocation.node = '0'; _currentLocation.view = '0'; _currentLocation.offset = 0; - } else - return; + } } } _engine->setRenderDelay(2); - if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') { - if (_nextLocation.world != 'g' || _nextLocation.room != 'j') { + if (!leavingMenu) { + if (!isLoading && !enteringMenu) { setStateValue(StateKey_LastWorld, getStateValue(StateKey_World)); setStateValue(StateKey_LastRoom, getStateValue(StateKey_Room)); setStateValue(StateKey_LastNode, getStateValue(StateKey_Node)); @@ -562,13 +609,14 @@ void ScriptManager::ChangeLocationReal() { } } - if (_nextLocation.world == 'g' && _nextLocation.room == 'j') { - if (_nextLocation.node == 's' && _nextLocation.view == 'e' && - _currentLocation.world != 'g' && _currentLocation.room != 'j') + if (enteringMenu) { + if (isSaveScreen && !leavingMenu) { _engine->getSaveManager()->prepareSaveBuffer(); + } } else { - if (_currentLocation.world == 'g' && _currentLocation.room == 'j') + if (leavingMenu) { _engine->getSaveManager()->flushSaveBuffer(); + } } setStateValue(StateKey_World, _nextLocation.world); @@ -631,7 +679,7 @@ void ScriptManager::ChangeLocationReal() { // Change the background position _engine->getRenderManager()->setBackgroundPosition(_nextLocation.offset); - if (_currentLocation.world == 0 && _currentLocation.room == 0 && _currentLocation.node == 0 && _currentLocation.view == 0) { + if (_currentLocation == "0000") { _currentLocation = _nextLocation; execScope(world); execScope(room); @@ -664,29 +712,33 @@ void ScriptManager::serialize(Common::WriteStream *stream) { stream->writeByte(getStateValue(StateKey_View)); stream->writeUint32LE(getStateValue(StateKey_ViewPos)); - for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { (*iter)->serialize(stream); + } stream->writeUint32BE(MKTAG('F', 'L', 'A', 'G')); int32 slots = 20000; - if (_engine->getGameId() == GID_NEMESIS) + if (_engine->getGameId() == GID_NEMESIS) { slots = 30000; + } stream->writeUint32LE(slots * 2); - for (int32 i = 0; i < slots; i++) + for (int32 i = 0; i < slots; i++) { stream->writeUint16LE(getStateFlag(i)); + } stream->writeUint32BE(MKTAG('P', 'U', 'Z', 'Z')); stream->writeUint32LE(slots * 2); - for (int32 i = 0; i < slots; i++) + for (int32 i = 0; i < slots; i++) { stream->writeSint16LE(getStateValue(i)); + } } -void ScriptManager::reset() { +void ScriptManager::deserialize(Common::SeekableReadStream *stream) { // Clear out the current table values _globalState.clear(); _globalStateFlags.clear(); @@ -700,16 +752,13 @@ void ScriptManager::reset() { _currentLocation.room = 0; _currentLocation.view = 0; - for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++) + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++) { delete(*iter); + } _activeSideFx.clear(); _referenceTable.clear(); -} - -void ScriptManager::deserialize(Common::SeekableReadStream *stream) { - reset(); if (stream->readUint32BE() != MKTAG('Z', 'N', 'S', 'G') || stream->readUint32LE() != 4) { changeLocation('g', 'a', 'r', 'y', 0); @@ -738,20 +787,23 @@ void ScriptManager::deserialize(Common::SeekableReadStream *stream) { case MKTAG('T', 'I', 'M', 'R'): { uint32 key = stream->readUint32LE(); uint32 time = stream->readUint32LE(); - if (_engine->getGameId() == GID_GRANDINQUISITOR) + if (_engine->getGameId() == GID_GRANDINQUISITOR) { time /= 100; - else if (_engine->getGameId() == GID_NEMESIS) + } else if (_engine->getGameId() == GID_NEMESIS) { time /= 1000; + } addSideFX(new TimerNode(_engine, key, time)); } break; case MKTAG('F', 'L', 'A', 'G'): - for (uint32 i = 0; i < tagSize / 2; i++) + for (uint32 i = 0; i < tagSize / 2; i++) { setStateFlagSilent(i, stream->readUint16LE()); + } break; case MKTAG('P', 'U', 'Z', 'Z'): - for (uint32 i = 0; i < tagSize / 2; i++) + for (uint32 i = 0; i < tagSize / 2; i++) { setStateValueSilent(i, stream->readUint16LE()); + } break; default: stream->seek(tagSize, SEEK_CUR); @@ -760,7 +812,7 @@ void ScriptManager::deserialize(Common::SeekableReadStream *stream) { _nextLocation = nextLocation; - ChangeLocationReal(); + ChangeLocationReal(true); _engine->setRenderDelay(10); setStateValue(StateKey_RestoreFlag, 1); @@ -805,10 +857,11 @@ void ScriptManager::flushEvent(Common::EventType type) { EventList::iterator it = _controlEvents.begin(); while (it != _controlEvents.end()) { - if ((*it).type == type) + if ((*it).type == type) { it = _controlEvents.erase(it); - else + } else { it++; + } } } @@ -837,12 +890,15 @@ ValueSlot::ValueSlot(ScriptManager *scriptManager, const char *slotValue): } int16 ValueSlot::getValue() { if (slot) { - if (value >= 0) + if (value >= 0) { return _scriptManager->getStateValue(value); - else + } + else { return 0; - } else + } + } else { return value; + } } } // End of namespace ZVision diff --git a/engines/zvision/scripting/script_manager.h b/engines/zvision/scripting/script_manager.h index a05c112a18..7c276bf917 100644 --- a/engines/zvision/scripting/script_manager.h +++ b/engines/zvision/scripting/script_manager.h @@ -113,6 +113,28 @@ struct Location { uint32 offset; }; +inline bool operator==(const Location& lhs, const Location& rhs) { + return ( + lhs.world == rhs.world && + lhs.room == rhs.room && + lhs.node == rhs.node && + lhs.view == rhs.view + ); +} + +inline bool operator==(const Location& lhs, const char* rhs) { + Common::String lhsStr = Common::String::format("%c%c%c%c", lhs.world, lhs.room, lhs.node, lhs.view); + return lhsStr == rhs; +} + +inline bool operator!=(const Location& lhs, const Location& rhs) { + return !(lhs == rhs); +} + +inline bool operator!=(const Location& lhs, const char* rhs) { + return !(lhs == rhs); +} + typedef Common::List<Puzzle *> PuzzleList; typedef Common::Queue<Puzzle *> PuzzleQueue; typedef Common::List<Control *> ControlList; @@ -248,7 +270,6 @@ public: void serialize(Common::WriteStream *stream); void deserialize(Common::SeekableReadStream *stream); - void reset(); Location getCurrentLocation() const; Location getLastLocation(); @@ -274,7 +295,7 @@ private: bool execScope(ScriptScope &scope); /** Perform change location */ - void ChangeLocationReal(); + void ChangeLocationReal(bool isLoading); int8 inventoryGetCount(); void inventorySetCount(int8 cnt); @@ -313,9 +334,10 @@ private: * * @param criteria Pointer to the Criteria object to fill * @param stream Scr file stream + * @param key Puzzle key (for workarounds) * @return Whether any criteria were read */ - bool parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const; + bool parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList, uint32 key) const; /** * Parses the stream into a ResultAction objects diff --git a/engines/zvision/scripting/scripting_effect.h b/engines/zvision/scripting/scripting_effect.h index 0af1d9c21c..2a2153204f 100644 --- a/engines/zvision/scripting/scripting_effect.h +++ b/engines/zvision/scripting/scripting_effect.h @@ -37,7 +37,7 @@ class ZVision; * The base class that represents effects created from Actions. * This class is virtual. * - * Detailed Description: + * Detailed Description: * A scene has Controls. By interacting with the controls, the user * causes Actions to execute. Certain Actions create 'effects', for * example, a sound or an animation. This is the base class for |