diff options
author | Filippos Karapetis | 2014-12-03 00:06:38 +0200 |
---|---|---|
committer | Filippos Karapetis | 2014-12-03 00:06:38 +0200 |
commit | 637102d33b9ab69724c1badd9515e0e26a4b4b88 (patch) | |
tree | 72fe1291306ceb12c4da2956ab22814741dddce9 /engines/zvision/scripting | |
parent | b1f7603263c368658a3b9b7e30a929bd77d895af (diff) | |
parent | 596a904a0c6aedba5bbe45cdfa931425450626c8 (diff) | |
download | scummvm-rg350-637102d33b9ab69724c1badd9515e0e26a4b4b88.tar.gz scummvm-rg350-637102d33b9ab69724c1badd9515e0e26a4b4b88.tar.bz2 scummvm-rg350-637102d33b9ab69724c1badd9515e0e26a4b4b88.zip |
Merge pull request #532 from Marisa-Chan/zvision
ZVISION: More complete engine implementation
Diffstat (limited to 'engines/zvision/scripting')
46 files changed, 5930 insertions, 1226 deletions
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp index 219f418b13..8ff6bd0496 100644 --- a/engines/zvision/scripting/actions.cpp +++ b/engines/zvision/scripting/actions.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -29,8 +29,21 @@ #include "zvision/graphics/render_manager.h" #include "zvision/sound/zork_raw.h" #include "zvision/video/zork_avi_decoder.h" -#include "zvision/scripting/controls/timer_node.h" -#include "zvision/scripting/controls/animation_control.h" +#include "zvision/scripting/sidefx/timer_node.h" +#include "zvision/scripting/sidefx/music_node.h" +#include "zvision/scripting/sidefx/syncsound_node.h" +#include "zvision/scripting/sidefx/animation_node.h" +#include "zvision/scripting/sidefx/distort_node.h" +#include "zvision/scripting/sidefx/ttytext_node.h" +#include "zvision/scripting/sidefx/region_node.h" +#include "zvision/scripting/controls/titler_control.h" +#include "zvision/graphics/render_table.h" +#include "zvision/graphics/effect.h" +#include "zvision/graphics/effects/fog.h" +#include "zvision/graphics/effects/light.h" +#include "zvision/graphics/effects/wave.h" +#include "zvision/core/save_manager.h" +#include "zvision/cursors/cursor_manager.h" #include "common/file.h" @@ -43,12 +56,13 @@ namespace ZVision { // ActionAdd ////////////////////////////////////////////////////////////////////////////// -ActionAdd::ActionAdd(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u,%u)", &_key, &_value); +ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u,%d", &_key, &_value); } -bool ActionAdd::execute(ZVision *engine) { - engine->getScriptManager()->addToStateValue(_key, _value); +bool ActionAdd::execute() { + _engine->getScriptManager()->setStateValue(_key, _engine->getScriptManager()->getStateValue(_key) + _value); return true; } @@ -57,12 +71,21 @@ bool ActionAdd::execute(ZVision *engine) { // ActionAssign ////////////////////////////////////////////////////////////////////////////// -ActionAssign::ActionAssign(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u, %u)", &_key, &_value); +ActionAssign::ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char buf[64]; + memset(buf, 0, 64); + sscanf(line.c_str(), "%u, %s", &_key, buf); + _value = new ValueSlot(_engine->getScriptManager(), buf); } -bool ActionAssign::execute(ZVision *engine) { - engine->getScriptManager()->setStateValue(_key, _value); +ActionAssign::~ActionAssign() { + if (_value) + delete _value; +} + +bool ActionAssign::execute() { + _engine->getScriptManager()->setStateValue(_key, _value->getValue()); return true; } @@ -71,12 +94,17 @@ bool ActionAssign::execute(ZVision *engine) { // ActionAttenuate ////////////////////////////////////////////////////////////////////////////// -ActionAttenuate::ActionAttenuate(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u, %d)", &_key, &_attenuation); +ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u, %d", &_key, &_attenuation); } -bool ActionAttenuate::execute(ZVision *engine) { - // TODO: Implement +bool ActionAttenuate::execute() { + SideFX *fx = _engine->getScriptManager()->getSideFX(_key); + if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) { + MusicNode *mus = (MusicNode *)fx; + mus->setVolume(255 - (abs(_attenuation) >> 7)); + } return true; } @@ -85,13 +113,14 @@ bool ActionAttenuate::execute(ZVision *engine) { // ActionChangeLocation ////////////////////////////////////////////////////////////////////////////// -ActionChangeLocation::ActionChangeLocation(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%c,%c,%c%c,%u)", &_world, &_room, &_node, &_view, &_offset); +ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%c, %c, %c%c, %u", &_world, &_room, &_node, &_view, &_offset); } -bool ActionChangeLocation::execute(ZVision *engine) { +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); + _engine->getScriptManager()->changeLocation(_world, _room, _node, _view, _offset); // Tell the puzzle system to stop checking any more puzzles return false; } @@ -101,133 +130,455 @@ bool ActionChangeLocation::execute(ZVision *engine) { // ActionCrossfade ////////////////////////////////////////////////////////////////////////////// -ActionCrossfade::ActionCrossfade(const Common::String &line) { +ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { sscanf(line.c_str(), - "%*[^(](%u %u %u %u %u %u %u)", - &_keyOne, &_keyTwo, &_oneStartVolume, &_twoStartVolume, &_oneEndVolume, &_twoEndVolume, &_timeInMillis); + "%u %u %d %d %d %d %d", + &_keyOne, &_keyTwo, &_oneStartVolume, &_twoStartVolume, &_oneEndVolume, &_twoEndVolume, &_timeInMillis); +} + +bool ActionCrossfade::execute() { + if (_keyOne) { + SideFX *fx = _engine->getScriptManager()->getSideFX(_keyOne); + if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) { + MusicNode *mus = (MusicNode *)fx; + if (_oneStartVolume >= 0) + mus->setVolume((_oneStartVolume * 255) / 100); + + mus->setFade(_timeInMillis, (_oneEndVolume * 255) / 100); + } + } + + if (_keyTwo) { + SideFX *fx = _engine->getScriptManager()->getSideFX(_keyTwo); + if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) { + MusicNode *mus = (MusicNode *)fx; + if (_twoStartVolume >= 0) + mus->setVolume((_twoStartVolume * 255) / 100); + + mus->setFade(_timeInMillis, (_twoEndVolume * 255) / 100); + } + } + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionCursor +////////////////////////////////////////////////////////////////////////////// + +ActionCursor::ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + Common::String up = line; + up.toUppercase(); + _action = 0; + + if (up[0] == 'B') + _action = 2; + else if (up[0] == 'I') + _action = 3; + else if (up[0] == 'U') + _action = 0; + else if (up[0] == 'H') + _action = 1; } -bool ActionCrossfade::execute(ZVision *engine) { - // TODO: Implement +bool ActionCursor::execute() { + switch (_action) { + case 1: + _engine->getCursorManager()->showMouse(false); + break; + default: + _engine->getCursorManager()->showMouse(true); + break; + } return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionDelayRender +////////////////////////////////////////////////////////////////////////////// + +ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u", &_framesToDelay); +} + +bool ActionDelayRender::execute() { + _engine->setRenderDelay(_framesToDelay); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionDisableControl ////////////////////////////////////////////////////////////////////////////// -ActionDisableControl::ActionDisableControl(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u)", &_key); +ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u", &_key); } -bool ActionDisableControl::execute(ZVision *engine) { - debug("Disabling control %u", _key); +bool ActionDisableControl::execute() { + _engine->getScriptManager()->setStateFlag(_key, Puzzle::DISABLED); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionDisableVenus +////////////////////////////////////////////////////////////////////////////// + +ActionDisableVenus::ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%d", &_key); +} + +bool ActionDisableVenus::execute() { + _engine->getScriptManager()->setStateValue(_key, 0); + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionDisplayMessage +////////////////////////////////////////////////////////////////////////////// - ScriptManager *scriptManager = engine->getScriptManager(); - scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) | ScriptManager::DISABLED); +ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%hd %hd", &_control, &_msgid); +} +bool ActionDisplayMessage::execute() { + Control *ctrl = _engine->getScriptManager()->getControl(_control); + if (ctrl && ctrl->getType() == Control::CONTROL_TITLER) { + TitlerControl *titler = (TitlerControl *)ctrl; + titler->setString(_msgid); + } return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionDissolve +////////////////////////////////////////////////////////////////////////////// + +ActionDissolve::ActionDissolve(ZVision *engine) : + ResultAction(engine, 0) { +} + +bool ActionDissolve::execute() { + // Cause black screen flick + // _engine->getRenderManager()->bkgFill(0, 0, 0); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionDistort +////////////////////////////////////////////////////////////////////////////// + +ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%hd %hd %f %f %f %f", &_distSlot, &_speed, &_startAngle, &_endAngle, &_startLineScale, &_endLineScale); +} + +ActionDistort::~ActionDistort() { + _engine->getScriptManager()->killSideFx(_distSlot); +} + +bool ActionDistort::execute() { + if (_engine->getScriptManager()->getSideFX(_distSlot)) + return true; + + _engine->getScriptManager()->addSideFX(new DistortNode(_engine, _distSlot, _speed, _startAngle, _endAngle, _startLineScale, _endLineScale)); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionEnableControl ////////////////////////////////////////////////////////////////////////////// -ActionEnableControl::ActionEnableControl(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u)", &_key); +ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u", &_key); +} + +bool ActionEnableControl::execute() { + _engine->getScriptManager()->unsetStateFlag(_key, Puzzle::DISABLED); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionFlushMouseEvents +////////////////////////////////////////////////////////////////////////////// + +ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotkey) : + ResultAction(engine, slotkey) { } -bool ActionEnableControl::execute(ZVision *engine) { - debug("Enabling control %u", _key); +bool ActionFlushMouseEvents::execute() { + _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONUP); + _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONDOWN); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionInventory +////////////////////////////////////////////////////////////////////////////// + +ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char buf[25]; + sscanf(line.c_str(), "%25s %d", buf, &_key); + + if (strcmp(buf, "add") == 0) { + _type = 0; + } else if (strcmp(buf, "addi") == 0) { + _type = 1; + } else if (strcmp(buf, "drop") == 0) { + _type = 2; + } else if (strcmp(buf, "dropi") == 0) { + _type = 3; + } else if (strcmp(buf, "cycle") == 0) { + _type = 4; + } - ScriptManager *scriptManager = engine->getScriptManager(); - scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) & ~ScriptManager::DISABLED); +} +bool ActionInventory::execute() { + switch (_type) { + case 0: // add + _engine->getScriptManager()->inventoryAdd(_key); + break; + case 1: // addi + _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(_key)); + break; + case 2: // drop + if (_key >= 0) + _engine->getScriptManager()->inventoryDrop(_key); + else + _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(StateKey_InventoryItem)); + break; + case 3: // dropi + _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(_key)); + break; + case 4: // cycle + _engine->getScriptManager()->inventoryCycle(); + break; + default: + break; + } return true; } ////////////////////////////////////////////////////////////////////////////// +// ActionKill +////////////////////////////////////////////////////////////////////////////// + +ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + _key = 0; + _type = 0; + char keytype[25]; + sscanf(line.c_str(), "%25s", keytype); + if (keytype[0] == '"') { + if (!scumm_stricmp(keytype, "\"ANIM\"")) + _type = SideFX::SIDEFX_ANIM; + else if (!scumm_stricmp(keytype, "\"AUDIO\"")) + _type = SideFX::SIDEFX_AUDIO; + else if (!scumm_stricmp(keytype, "\"DISTORT\"")) + _type = SideFX::SIDEFX_DISTORT; + else if (!scumm_stricmp(keytype, "\"PANTRACK\"")) + _type = SideFX::SIDEFX_PANTRACK; + else if (!scumm_stricmp(keytype, "\"REGION\"")) + _type = SideFX::SIDEFX_REGION; + else if (!scumm_stricmp(keytype, "\"TIMER\"")) + _type = SideFX::SIDEFX_TIMER; + else if (!scumm_stricmp(keytype, "\"TTYTEXT\"")) + _type = SideFX::SIDEFX_TTYTXT; + else if (!scumm_stricmp(keytype, "\"ALL\"")) + _type = SideFX::SIDEFX_ALL; + } else + _key = atoi(keytype); +} + +bool ActionKill::execute() { + if (_type) + _engine->getScriptManager()->killSideFxType((SideFX::SideFXType)_type); + else + _engine->getScriptManager()->killSideFx(_key); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionMenuBarEnable +////////////////////////////////////////////////////////////////////////////// + +ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%hu", &_menus); +} + +bool ActionMenuBarEnable::execute() { + _engine->menuBarEnable(_menus); + return true; +} + +////////////////////////////////////////////////////////////////////////////// // ActionMusic ////////////////////////////////////////////////////////////////////////////// -ActionMusic::ActionMusic(const Common::String &line) : _volume(255) { +ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global) : + ResultAction(engine, slotkey), + _volume(255), + _universe(global) { uint type; - char fileNameBuffer[26]; + char fileNameBuffer[25]; uint loop; uint volume = 255; - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%u %25s %u %u)", &_key, &type, fileNameBuffer, &loop, &volume); + sscanf(line.c_str(), "%u %25s %u %u", &type, fileNameBuffer, &loop, &volume); // type 4 are midi sound effect files if (type == 4) { - _soundType = Audio::Mixer::kSFXSoundType; - _fileName = Common::String::format("midi/%s/%u.wav", fileNameBuffer, loop); - _loop = false; + _midi = true; + int note; + int prog; + sscanf(line.c_str(), "%u %d %d %u", &type, &prog, ¬e, &volume); + _volume = volume; + _note = note; + _prog = prog; } else { - // TODO: See what the other types are so we can specify the correct Mixer::SoundType. In the meantime use kPlainSoundType - _soundType = Audio::Mixer::kPlainSoundType; + _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; + // 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; + } } + + } -bool ActionMusic::execute(ZVision *engine) { - Audio::RewindableAudioStream *audioStream; +ActionMusic::~ActionMusic() { + if (!_universe) + _engine->getScriptManager()->killSideFx(_slotKey); +} - if (_fileName.contains(".wav")) { - Common::File *file = new Common::File(); - if (file->open(_fileName)) { - audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); - } else { - warning("Unable to open %s", _fileName.c_str()); - return false; - } - } else { - audioStream = makeRawZorkStream(_fileName, engine); - } +bool ActionMusic::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; - if (_loop) { - Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); - engine->_mixer->playStream(_soundType, 0, loopingAudioStream, -1, _volume); + if (_midi) { + _engine->getScriptManager()->addSideFX(new MusicMidiNode(_engine, _slotKey, _prog, _note, _volume)); } else { - engine->_mixer->playStream(_soundType, 0, audioStream, -1, _volume); + if (!_engine->getSearchManager()->hasFile(_fileName)) + return true; + + _engine->getScriptManager()->addSideFX(new MusicNode(_engine, _slotKey, _fileName, _loop, _volume)); } return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionPanTrack +////////////////////////////////////////////////////////////////////////////// + +ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey), + _pos(0), + _musicSlot(0) { + + sscanf(line.c_str(), "%u %d", &_musicSlot, &_pos); +} + +ActionPanTrack::~ActionPanTrack() { + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionPanTrack::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + + _engine->getScriptManager()->addSideFX(new PanTrackNode(_engine, _slotKey, _musicSlot, _pos)); + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionPreferences +////////////////////////////////////////////////////////////////////////////// + +ActionPreferences::ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + if (line.compareToIgnoreCase("save") == 0) + _save = true; + else + _save = false; +} + +bool ActionPreferences::execute() { + if (_save) + _engine->saveSettings(); + else + _engine->loadSettings(); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionPreloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPreloadAnimation::ActionPreloadAnimation(const Common::String &line) { - char fileName[26]; +ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; // The two %*u are always 0 and dont seem to have a use - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%25s %*u %*u %u %u)", &_key, fileName, &_mask, &_framerate); + sscanf(line.c_str(), "%25s %*u %*u %d %d", fileName, &_mask, &_framerate); + + if (_mask > 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b); + _mask = _engine->_pixelFormat.RGBToColor(r, g, b); + } _fileName = Common::String(fileName); } -bool ActionPreloadAnimation::execute(ZVision *engine) { - // TODO: We ignore the mask and framerate atm. Mask refers to a key color used for binary alpha. We assume the framerate is the default framerate embedded in the videos +ActionPreloadAnimation::~ActionPreloadAnimation() { + _engine->getScriptManager()->deleteSideFx(_slotKey); +} + +bool ActionPreloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey); + + if (!nod) { + nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate, false); + _engine->getScriptManager()->addSideFX(nod); + } else + nod->stop(); + _engine->getScriptManager()->setStateValue(_slotKey, 2); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionUnloadAnimation +////////////////////////////////////////////////////////////////////////////// + +ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + + sscanf(line.c_str(), "%u", &_key); +} - // TODO: Check if the Control already exists +bool ActionUnloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_key); - // Create the control, but disable it until PlayPreload is called - ScriptManager *scriptManager = engine->getScriptManager(); - scriptManager->addControl(new AnimationControl(engine, _key, _fileName)); - scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) | ScriptManager::DISABLED); + if (nod && nod->getType() == SideFX::SIDEFX_ANIM) + _engine->getScriptManager()->deleteSideFx(_key); return true; } @@ -237,19 +588,40 @@ bool ActionPreloadAnimation::execute(ZVision *engine) { // ActionPlayAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPlayAnimation::ActionPlayAnimation(const Common::String &line) { - char fileName[26]; +ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; // The two %*u are always 0 and dont seem to have a use sscanf(line.c_str(), - "%*[^:]:%*[^:]:%u(%25s %u %u %u %u %u %u %u %*u %*u %u %u)", - &_key, fileName, &_x, &_y, &_width, &_height, &_start, &_end, &_loopCount, &_mask, &_framerate); + "%25s %u %u %u %u %u %u %d %*u %*u %d %d", + fileName, &_x, &_y, &_x2, &_y2, &_start, &_end, &_loopCount, &_mask, &_framerate); + + if (_mask > 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b); + _mask = _engine->_pixelFormat.RGBToColor(r, g, b); + } _fileName = Common::String(fileName); } -bool ActionPlayAnimation::execute(ZVision *engine) { - // TODO: Implement +ActionPlayAnimation::~ActionPlayAnimation() { + _engine->getScriptManager()->deleteSideFx(_slotKey); +} + +bool ActionPlayAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey); + + if (!nod) { + nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate); + _engine->getScriptManager()->addSideFX(nod); + } else + nod->stop(); + + if (nod) + nod->addPlayNode(_slotKey, _x, _y, _x2, _y2, _start, _end, _loopCount); + return true; } @@ -258,24 +630,18 @@ bool ActionPlayAnimation::execute(ZVision *engine) { // ActionPlayPreloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(const Common::String &line) { +ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { sscanf(line.c_str(), - "%*[^:]:%*[^:]:%u(%u %u %u %u %u %u %u %u)", - &_animationKey, &_controlKey, &_x1, &_y1, &_x2, &_y2, &_startFrame, &_endFrame, &_loopCount); + "%u %u %u %u %u %u %u %u", + &_controlKey, &_x1, &_y1, &_x2, &_y2, &_startFrame, &_endFrame, &_loopCount); } -bool ActionPlayPreloadAnimation::execute(ZVision *engine) { - // Find the control - AnimationControl *control = (AnimationControl *)engine->getScriptManager()->getControl(_controlKey); - - // Set the needed values within the control - control->setAnimationKey(_animationKey); - control->setLoopCount(_loopCount); - control->setXPos(_x1); - control->setYPost(_y1); +bool ActionPlayPreloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_controlKey); - // Enable the control. ScriptManager will take care of the rest - control->enable(); + if (nod) + nod->addPlayNode(_slotKey, _x1, _y1, _x2, _y2, _startFrame, _endFrame, _loopCount); return true; } @@ -285,24 +651,138 @@ bool ActionPlayPreloadAnimation::execute(ZVision *engine) { // ActionQuit ////////////////////////////////////////////////////////////////////////////// -bool ActionQuit::execute(ZVision *engine) { - engine->quitGame(); +bool ActionQuit::execute() { + _engine->quitGame(); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionRegion +////////////////////////////////////////////////////////////////////////////// + +ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + + char art[64]; + char custom[64]; + + int32 x1, x2, y1, y2; + + sscanf(line.c_str(), "%s %d %d %d %d %hu %hu %hu %hu %s", art, &x1, &y1, &x2, &y2, &_delay, &_type, &_unk1, &_unk2, custom); + _art = Common::String(art); + _custom = Common::String(custom); + _rect = Common::Rect(x1, y1, x2 + 1, y2 + 1); +} + +ActionRegion::~ActionRegion() { + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionRegion::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + + Effect *effct = NULL; + switch (_type) { + case 0: { + uint16 centerX, centerY, frames; + double amplitude, waveln, speed; + sscanf(_custom.c_str(), "%hu,%hu,%hu,%lf,%lf,%lf,", ¢erX, ¢erY, &frames, &litude, &waveln, &speed); + effct = new WaveFx(_engine, _slotKey, _rect, _unk1, frames, centerX, centerY, amplitude, waveln, speed); + } + break; + case 1: { + uint16 aX, aY, aD; + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) + sscanf(_art.c_str(), "useart[%hu,%hu,%hu]", &aY, &aX, &aD); + else + sscanf(_art.c_str(), "useart[%hu,%hu,%hu]", &aX, &aY, &aD); + int8 minD; + int8 maxD; + EffectMap *_map = _engine->getRenderManager()->makeEffectMap(Common::Point(aX, aY), aD, _rect, &minD, &maxD); + effct = new LightFx(_engine, _slotKey, _rect, _unk1, _map, atoi(_custom.c_str()), minD, maxD); + } + break; + case 9: { + int16 dum1; + int32 dum2; + char buf[64]; + sscanf(_custom.c_str(), "%hd,%d,%s", &dum1, &dum2, buf); + Graphics::Surface tempMask; + _engine->getRenderManager()->readImageToSurface(_art, tempMask); + if (_rect.width() != tempMask.w) + _rect.setWidth(tempMask.w); + if (_rect.height() != tempMask.h) + _rect.setHeight(tempMask.h); + + EffectMap *_map = _engine->getRenderManager()->makeEffectMap(tempMask, 0); + effct = new FogFx(_engine, _slotKey, _rect, _unk1, _map, Common::String(buf)); + } + break; + default: + break; + } + + if (effct) { + _engine->getScriptManager()->addSideFX(new RegionNode(_engine, _slotKey, effct, _delay)); + _engine->getRenderManager()->addEffect(effct); + } + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionRandom ////////////////////////////////////////////////////////////////////////////// -ActionRandom::ActionRandom(const Common::String &line) { - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u, %u)", &_key, &_max); +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); +} + +ActionRandom::~ActionRandom() { + if (_max) + delete _max; +} + +bool ActionRandom::execute() { + uint randNumber = _engine->getRandomSource()->getRandomNumber(_max->getValue()); + _engine->getScriptManager()->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(_fileName); + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionRotateTo +////////////////////////////////////////////////////////////////////////////// + +ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%d, %d", &_toPos, &_time); } -bool ActionRandom::execute(ZVision *engine) { - uint randNumber = engine->getRandomSource()->getRandomNumber(_max); - engine->getScriptManager()->setStateValue(_key, randNumber); +bool ActionRotateTo::execute() { + _engine->rotateTo(_toPos, _time); + return true; } @@ -311,27 +791,44 @@ bool ActionRandom::execute(ZVision *engine) { // ActionSetPartialScreen ////////////////////////////////////////////////////////////////////////////// -ActionSetPartialScreen::ActionSetPartialScreen(const Common::String &line) { - char fileName[26]; - uint color; +ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + int color; - sscanf(line.c_str(), "%*[^(](%u %u %25s %*u %u)", &_x, &_y, fileName, &color); + sscanf(line.c_str(), "%u %u %25s %*u %d", &_x, &_y, fileName, &color); _fileName = Common::String(fileName); - if (color > 0xFFFF) { + if (color >= 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(color, r, g, b); + _backgroundColor = _engine->_pixelFormat.RGBToColor(r, g, b); + } else { + _backgroundColor = color; + } + + if (color > 65535) { warning("Background color for ActionSetPartialScreen is bigger than a uint16"); } - _backgroundColor = color; } -bool ActionSetPartialScreen::execute(ZVision *engine) { - RenderManager *renderManager = engine->getRenderManager(); +bool ActionSetPartialScreen::execute() { + RenderManager *renderManager = _engine->getRenderManager(); - if (_backgroundColor > 0) { - renderManager->clearWorkingWindowTo555Color(_backgroundColor); + if (_engine->getGameId() == GID_NEMESIS) { + if (_backgroundColor) + renderManager->renderImageToBackground(_fileName, _x, _y, 0, 0); + else + renderManager->renderImageToBackground(_fileName, _x, _y); + } else { + if (_backgroundColor >= 0) + renderManager->renderImageToBackground(_fileName, _x, _y, _backgroundColor); + else if (_backgroundColor == -2) + renderManager->renderImageToBackground(_fileName, _x, _y, 0, 0); + else + renderManager->renderImageToBackground(_fileName, _x, _y); } - renderManager->renderImageToScreen(_fileName, _x, _y); return true; } @@ -341,16 +838,49 @@ bool ActionSetPartialScreen::execute(ZVision *engine) { // ActionSetScreen ////////////////////////////////////////////////////////////////////////////// -ActionSetScreen::ActionSetScreen(const Common::String &line) { - char fileName[26]; - sscanf(line.c_str(), "%*[^(](%25[^)])", fileName); +ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + sscanf(line.c_str(), "%25s", fileName); _fileName = Common::String(fileName); } -bool ActionSetScreen::execute(ZVision *engine) { - engine->getRenderManager()->setBackgroundImage(_fileName); +bool ActionSetScreen::execute() { + _engine->getRenderManager()->setBackgroundImage(_fileName); + + return true; +} + + +////////////////////////////////////////////////////////////////////////////// +// ActionSetVenus +////////////////////////////////////////////////////////////////////////////// + +ActionSetVenus::ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%d", &_key); +} + +bool ActionSetVenus::execute() { + if (_engine->getScriptManager()->getStateValue(_key)) + _engine->getScriptManager()->setStateValue(StateKey_Venus, _key); + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionStop +////////////////////////////////////////////////////////////////////////////// + +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); return true; } @@ -359,42 +889,127 @@ bool ActionSetScreen::execute(ZVision *engine) { // ActionStreamVideo ////////////////////////////////////////////////////////////////////////////// -ActionStreamVideo::ActionStreamVideo(const Common::String &line) { - char fileName[26]; - uint skippable; +ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + uint skipline; //skipline - render video with skip every second line, not skippable. - sscanf(line.c_str(), "%*[^(](%25s %u %u %u %u %u %u)", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skippable); + sscanf(line.c_str(), "%25s %u %u %u %u %u %u", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skipline); _fileName = Common::String(fileName); - _skippable = (skippable == 0) ? false : true; + _skippable = true; } -bool ActionStreamVideo::execute(ZVision *engine) { +bool ActionStreamVideo::execute() { ZorkAVIDecoder decoder; - if (!decoder.loadFile(_fileName)) { - return true; - } + Common::File *_file = _engine->getSearchManager()->openFile(_fileName); + + if (_file) { + if (!decoder.loadStream(_file)) { + return true; + } + + _engine->getCursorManager()->showMouse(false); + + 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); + + Subtitle *sub = NULL; + + if (_engine->getSearchManager()->hasFile(subname)) + sub = new Subtitle(_engine, subname); - Common::Rect destRect; - if ((_flags & DIFFERENT_DIMENSIONS) == DIFFERENT_DIMENSIONS) { - destRect = Common::Rect(_x1, _y1, _x2, _y2); + _engine->playVideo(decoder, destRect, _skippable, sub); + + _engine->getCursorManager()->showMouse(true); + + if (sub) + delete sub; } - engine->playVideo(decoder, destRect, _skippable); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionSyncSound +////////////////////////////////////////////////////////////////////////////// + +ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + int notUsed; + + sscanf(line.c_str(), "%d %d %25s", &_syncto, ¬Used, fileName); + + _fileName = Common::String(fileName); +} + +bool ActionSyncSound::execute() { + SideFX *fx = _engine->getScriptManager()->getSideFX(_syncto); + if (!fx) + return true; + + if (!(fx->getType() & SideFX::SIDEFX_ANIM)) + return true; + + AnimationNode *animnode = (AnimationNode *)fx; + if (animnode->getFrameDelay() > 200) // Hack for fix incorrect framedelay in some animpreload + animnode->setNewFrameDelay(66); // ~15fps + + _engine->getScriptManager()->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto)); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionTimer ////////////////////////////////////////////////////////////////////////////// -ActionTimer::ActionTimer(const Common::String &line) { - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%u)", &_key, &_time); +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); +} + +ActionTimer::~ActionTimer() { + if (_time) + delete _time; + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionTimer::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + _engine->getScriptManager()->addSideFX(new TimerNode(_engine, _slotKey, _time->getValue())); + return true; } -bool ActionTimer::execute(ZVision *engine) { - engine->getScriptManager()->addControl(new TimerNode(engine, _key, _time)); +////////////////////////////////////////////////////////////////////////////// +// ActionTtyText +////////////////////////////////////////////////////////////////////////////// + +ActionTtyText::ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char filename[64]; + int32 x1, y1, x2, y2; + sscanf(line.c_str(), "%d %d %d %d %s %u", &x1, &y1, &x2, &y2, filename, &_delay); + _r = Common::Rect(x1, y1, x2, y2); + _filename = Common::String(filename); +} + +ActionTtyText::~ActionTtyText() { + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionTtyText::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + _engine->getScriptManager()->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 01457d21cc..03a249e580 100644 --- a/engines/zvision/scripting/actions.h +++ b/engines/zvision/scripting/actions.h @@ -24,6 +24,7 @@ #define ZVISION_ACTIONS_H #include "common/str.h" +#include "common/rect.h" #include "audio/mixer.h" @@ -32,6 +33,7 @@ namespace ZVision { // Forward declaration of ZVision. This file is included before ZVision is declared class ZVision; +class ValueSlot; /** * The base class that represents any action that a Puzzle can take. @@ -39,6 +41,7 @@ class ZVision; */ class ResultAction { public: + ResultAction(ZVision *engine, int32 slotkey) : _engine(engine), _slotKey(slotkey) {} virtual ~ResultAction() {} /** * This is called by the script system whenever a Puzzle's criteria are found to be true. @@ -48,75 +51,47 @@ public: * @param engine A pointer to the base engine so the ResultAction can access all the necessary methods * @return Should the script system continue to test any remaining puzzles (true) or immediately break and go on to the next frame (false) */ - virtual bool execute(ZVision *engine) = 0; -}; - - -// The different types of actions -// DEBUG, -// DISABLE_CONTROL, -// DISABLE_VENUS, -// DISPLAY_MESSAGE, -// DISSOLVE, -// DISTORT, -// ENABLE_CONTROL, -// FLUSH_MOUSE_EVENTS, -// INVENTORY, -// KILL, -// MENU_BAR_ENABLE, -// MUSIC, -// PAN_TRACK, -// PLAY_PRELOAD, -// PREFERENCES, -// QUIT, -// RANDOM, -// REGION, -// RESTORE_GAME, -// ROTATE_TO, -// SAVE_GAME, -// SET_PARTIAL_SCREEN, -// SET_SCREEN, -// SET_VENUS, -// STOP, -// STREAM_VIDEO, -// SYNC_SOUND, -// TTY_TEXT, -// UNIVERSE_MUSIC, + virtual bool execute() = 0; +protected: + ZVision *_engine; + int32 _slotKey; +}; class ActionAdd : public ResultAction { public: - ActionAdd(const Common::String &line); - bool execute(ZVision *engine); + ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; - uint _value; + int _value; }; class ActionAssign : public ResultAction { public: - ActionAssign(const Common::String &line); - bool execute(ZVision *engine); + ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionAssign(); + bool execute(); private: uint32 _key; - uint _value; + ValueSlot *_value; }; class ActionAttenuate : public ResultAction { public: - ActionAttenuate(const Common::String &line); - bool execute(ZVision *engine); + ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; - int _attenuation; + int32 _attenuation; }; class ActionChangeLocation : public ResultAction { public: - ActionChangeLocation(const Common::String &line); - bool execute(ZVision *engine); + ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: char _world; @@ -128,41 +103,49 @@ private: class ActionCrossfade : public ResultAction { public: - ActionCrossfade(const Common::String &line); - bool execute(ZVision *engine); + ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _keyOne; uint32 _keyTwo; - uint _oneStartVolume; - uint _twoStartVolume; - uint _oneEndVolume; - uint _twoEndVolume; - uint _timeInMillis; + int32 _oneStartVolume; + int32 _twoStartVolume; + int32 _oneEndVolume; + int32 _twoEndVolume; + int32 _timeInMillis; +}; + +class ActionCursor : public ResultAction { +public: + ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + uint8 _action; }; class ActionDebug : public ResultAction { public: - ActionDebug(const Common::String &line); - bool execute(ZVision *engine); + ActionDebug(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: }; class ActionDelayRender : public ResultAction { public: - ActionDelayRender(const Common::String &line); - bool execute(ZVision *engine); + ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: - // TODO: Check if this should actually be frames or if it should be milliseconds/seconds - uint32 framesToDelay; + uint32 _framesToDelay; }; class ActionDisableControl : public ResultAction { public: - ActionDisableControl(const Common::String &line); - bool execute(ZVision *engine); + ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; @@ -170,79 +153,138 @@ private: class ActionDisableVenus : public ResultAction { public: - ActionDisableVenus(const Common::String &line); - bool execute(ZVision *engine); + ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: + int32 _key; }; class ActionDisplayMessage : public ResultAction { public: - ActionDisplayMessage(const Common::String &line); - bool execute(ZVision *engine); + ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: + int16 _control; + int16 _msgid; }; class ActionDissolve : public ResultAction { public: - ActionDissolve(); - bool execute(ZVision *engine); + ActionDissolve(ZVision *engine); + bool execute(); }; class ActionDistort : public ResultAction { public: - ActionDistort(const Common::String &line); - bool execute(ZVision *engine); + ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionDistort(); + bool execute(); private: + int16 _distSlot; + int16 _speed; + float _startAngle; + float _endAngle; + float _startLineScale; + float _endLineScale; }; class ActionEnableControl : public ResultAction { public: - ActionEnableControl(const Common::String &line); - bool execute(ZVision *engine); + ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + uint32 _key; +}; + +class ActionFlushMouseEvents : public ResultAction { +public: + ActionFlushMouseEvents(ZVision *engine, int32 slotkey); + bool execute(); +}; + +class ActionInventory : public ResultAction { +public: + ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); +private: + uint8 _type; + int32 _key; +}; + +class ActionKill : public ResultAction { +public: + ActionKill(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; + uint32 _type; +}; + +class ActionMenuBarEnable : public ResultAction { +public: + ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); +private: + uint16 _menus; }; class ActionMusic : public ResultAction { public: - ActionMusic(const Common::String &line); - bool execute(ZVision *engine); + ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global); + ~ActionMusic(); + bool execute(); private: uint32 _key; - Audio::Mixer::SoundType _soundType; Common::String _fileName; bool _loop; byte _volume; + bool _universe; + bool _midi; + int8 _note; + int8 _prog; +}; + +class ActionPanTrack : public ResultAction { +public: + ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionPanTrack(); + bool execute(); + +private: + int32 _pos; + uint32 _musicSlot; }; class ActionPlayAnimation : public ResultAction { public: - ActionPlayAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionPlayAnimation(); + bool execute(); private: uint32 _key; Common::String _fileName; uint32 _x; uint32 _y; - uint32 _width; - uint32 _height; + uint32 _x2; + uint32 _y2; uint32 _start; uint32 _end; - uint _mask; - uint _framerate; - uint _loopCount; + int32 _mask; + int32 _framerate; + int32 _loopCount; }; class ActionPlayPreloadAnimation : public ResultAction { public: - ActionPlayPreloadAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _animationKey; @@ -258,64 +300,130 @@ private: class ActionPreloadAnimation : public ResultAction { public: - ActionPreloadAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionPreloadAnimation(); + bool execute(); private: uint32 _key; Common::String _fileName; - uint _mask; - uint _framerate; + int32 _mask; + int32 _framerate; +}; + +class ActionPreferences : public ResultAction { +public: + ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + bool _save; }; class ActionQuit : public ResultAction { public: - ActionQuit() {} - bool execute(ZVision *engine); + ActionQuit(ZVision *engine, int32 slotkey) : ResultAction(engine, slotkey) {} + bool execute(); +}; + +class ActionRegion : public ResultAction { +public: + ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionRegion(); + bool execute(); + +private: + Common::String _art; + Common::String _custom; + Common::Rect _rect; + uint16 _delay; + uint16 _type; + uint16 _unk1; + uint16 _unk2; }; // TODO: See if this exists in ZGI. It doesn't in ZNem class ActionUnloadAnimation : public ResultAction { public: - ActionUnloadAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); +private: + uint32 _key; }; class ActionRandom : public ResultAction { public: - ActionRandom(const Common::String &line); - bool execute(ZVision *engine); + ActionRandom(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionRandom(); + bool execute(); private: uint32 _key; - uint _max; + 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); + bool execute(); + +private: + int32 _toPos; + int32 _time; }; class ActionSetPartialScreen : public ResultAction { public: - ActionSetPartialScreen(const Common::String &line); - bool execute(ZVision *engine); + ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint _x; uint _y; Common::String _fileName; - uint16 _backgroundColor; + int32 _backgroundColor; }; class ActionSetScreen : public ResultAction { public: - ActionSetScreen(const Common::String &line); - bool execute(ZVision *engine); + ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: Common::String _fileName; }; +class ActionSetVenus : public ResultAction { +public: + ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + int32 _key; +}; + +class ActionStop : public ResultAction { +public: + ActionStop(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + uint32 _key; +}; + class ActionStreamVideo : public ResultAction { public: - ActionStreamVideo(const Common::String &line); - bool execute(ZVision *engine); + ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: enum { @@ -331,16 +439,37 @@ private: bool _skippable; }; -class ActionTimer : public ResultAction { +class ActionSyncSound : public ResultAction { public: - ActionTimer(const Common::String &line); - bool execute(ZVision *engine); + ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: + int _syncto; + Common::String _fileName; +}; + +class ActionTimer : public ResultAction { +public: + ActionTimer(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionTimer(); + bool execute(); +private: uint32 _key; - uint _time; + ValueSlot *_time; }; +class ActionTtyText : public ResultAction { +public: + ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionTtyText(); + bool execute(); + +private: + Common::String _filename; + uint32 _delay; + Common::Rect _r; +}; } // End of namespace ZVision #endif diff --git a/engines/zvision/scripting/control.cpp b/engines/zvision/scripting/control.cpp index 2343c83c56..e69d57f75c 100644 --- a/engines/zvision/scripting/control.cpp +++ b/engines/zvision/scripting/control.cpp @@ -23,6 +23,7 @@ #include "common/scummsys.h" #include "zvision/scripting/control.h" +#include "zvision/scripting/script_manager.h" #include "zvision/zvision.h" #include "zvision/graphics/render_manager.h" @@ -33,24 +34,6 @@ namespace ZVision { -void Control::enable() { - if (!_enabled) { - _enabled = true; - return; - } - - debug("Control %u is already enabled", _key); -} - -void Control::disable() { - if (_enabled) { - _enabled = false; - return; - } - - debug("Control %u is already disabled", _key); -} - void Control::parseFlatControl(ZVision *engine) { engine->getRenderManager()->getRenderTable()->setRenderState(RenderTable::FLAT); } @@ -79,7 +62,9 @@ void Control::parsePanoramaControl(ZVision *engine, Common::SeekableReadStream & renderTable->setPanoramaReverse(true); } } else if (line.matchString("zeropoint*", true)) { - // TODO: Implement + uint point; + sscanf(line.c_str(), "zeropoint(%u)", &point); + renderTable->setPanoramaZeroPoint(point); } line = stream.readLine(); @@ -121,4 +106,34 @@ void Control::parseTiltControl(ZVision *engine, Common::SeekableReadStream &stre renderTable->generateRenderTable(); } +void Control::getParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values) { + const char *chrs = inputStr.c_str(); + uint lbr; + + for (lbr = 0; lbr < inputStr.size(); lbr++) + if (chrs[lbr] == '(') + break; + + if (lbr >= inputStr.size()) + return; + + uint rbr; + + for (rbr = lbr + 1; rbr < inputStr.size(); rbr++) + if (chrs[rbr] == ')') + break; + + if (rbr >= inputStr.size()) + return; + + parameter = Common::String(chrs, chrs + lbr); + values = Common::String(chrs + lbr + 1, chrs + rbr); +} + +void Control::setVenus() { + if (_venusId >= 0) + if (_engine->getScriptManager()->getStateValue(_venusId) > 0) + _engine->getScriptManager()->setStateValue(StateKey_Venus, _venusId); +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/control.h b/engines/zvision/scripting/control.h index ffeacb273d..5814c9e419 100644 --- a/engines/zvision/scripting/control.h +++ b/engines/zvision/scripting/control.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -24,6 +24,7 @@ #define ZVISION_CONTROL_H #include "common/keyboard.h" +#include "common/str.h" namespace Common { @@ -38,14 +39,32 @@ class ZVision; class Control { public: - Control() : _engine(0), _key(0), _enabled(false) {} - Control(ZVision *engine, uint32 key) : _engine(engine), _key(key), _enabled(false) {} + + enum ControlType { + CONTROL_UNKNOW, + CONTROL_INPUT, + CONTROL_PUSHTGL, + CONTROL_SLOT, + CONTROL_LEVER, + CONTROL_SAVE, + CONTROL_SAFE, + CONTROL_FIST, + CONTROL_TITLER, + CONTROL_HOTMOV, + CONTROL_PAINT + }; + + Control(ZVision *engine, uint32 key, ControlType type) : _engine(engine), _key(key), _type(type), _venusId(-1) {} virtual ~Control() {} - uint32 getKey() { return _key; } + uint32 getKey() { + return _key; + } + + ControlType getType() { + return _type; + } - virtual void enable(); - virtual void disable(); virtual void focus() {} virtual void unfocus() {} /** @@ -54,14 +73,18 @@ public: * @param screenSpacePos The position of the mouse in screen space * @param backgroundImageSpacePos The position of the mouse in background image space */ - virtual void onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {} + virtual bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + return false; + } /** * Called when LeftMouse is lifted. Default is NOP. * * @param screenSpacePos The position of the mouse in screen space * @param backgroundImageSpacePos The position of the mouse in background image space */ - virtual void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {} + virtual bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + return false; + } /** * Called on every MouseMove. Default is NOP. * @@ -69,78 +92,52 @@ public: * @param backgroundImageSpacePos The position of the mouse in background image space * @return Was the cursor changed? */ - virtual bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { return false; } + virtual bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + return false; + } /** * Called when a key is pressed. Default is NOP. * * @param keycode The key that was pressed */ - virtual void onKeyDown(Common::KeyState keyState) {} + virtual bool onKeyDown(Common::KeyState keyState) { + return false; + } /** * Called when a key is released. Default is NOP. * * @param keycode The key that was pressed */ - virtual void onKeyUp(Common::KeyState keyState) {} + virtual bool onKeyUp(Common::KeyState keyState) { + return false; + } /** * Processes the node given the deltaTime since last frame. Default is NOP. * * @param deltaTimeInMillis The number of milliseconds that have passed since last frame * @return If true, the node can be deleted after process() finishes */ - virtual bool process(uint32 deltaTimeInMillis) { return false; } - /** - * Serialize a Control for save game use. This should only be used if a Control needs - * to save values that would be different from initialization. AKA a TimerNode needs to - * store the amount of time left on the timer. Any Controls overriding this *MUST* write - * their key as the first data outputted. The default implementation is NOP. - * - * NOTE: If this method is overridden, you MUST also override deserialize() - * and needsSerialization() - * - * @param stream Stream to write any needed data to - */ - virtual void serialize(Common::WriteStream *stream) {} - /** - * De-serialize data from a save game stream. This should only be implemented if the - * Control also implements serialize(). The calling method assumes the size of the - * data read from the stream exactly equals that written in serialize(). The default - * implementation is NOP. - * - * NOTE: If this method is overridden, you MUST also override serialize() - * and needsSerialization() - * - * @param stream Save game file stream - */ - virtual void deserialize(Common::SeekableReadStream *stream) {} - /** - * If a Control overrides serialize() and deserialize(), this should return true - * - * @return Does the Control need save game serialization? - */ - virtual inline bool needsSerialization() { return false; } + virtual bool process(uint32 deltaTimeInMillis) { + return false; + } + + void setVenus(); protected: - ZVision * _engine; + ZVision *_engine; uint32 _key; - bool _enabled; + int32 _venusId; + void getParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values); // Static member functions public: static void parseFlatControl(ZVision *engine); static void parsePanoramaControl(ZVision *engine, Common::SeekableReadStream &stream); static void parseTiltControl(ZVision *engine, Common::SeekableReadStream &stream); +private: + ControlType _type; }; -// TODO: Implement InputControl -// TODO: Implement SaveControl -// TODO: Implement SlotControl -// TODO: Implement SafeControl -// TODO: Implement FistControl -// TODO: Implement HotMovieControl -// TODO: Implement PaintControl -// TODO: Implement TilterControl - } // End of namespace ZVision #endif diff --git a/engines/zvision/scripting/controls/animation_control.cpp b/engines/zvision/scripting/controls/animation_control.cpp deleted file mode 100644 index e351e81d25..0000000000 --- a/engines/zvision/scripting/controls/animation_control.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/scummsys.h" - -#include "zvision/scripting/controls/animation_control.h" - -#include "zvision/zvision.h" -#include "zvision/graphics/render_manager.h" -#include "zvision/scripting/script_manager.h" -#include "zvision/animation/rlf_animation.h" -#include "zvision/video/zork_avi_decoder.h" - -#include "video/video_decoder.h" - -#include "graphics/surface.h" - - -namespace ZVision { - -AnimationControl::AnimationControl(ZVision *engine, uint32 controlKey, const Common::String &fileName) - : Control(engine, controlKey), - _fileType(RLF), - _loopCount(1), - _currentLoop(0), - _accumulatedTime(0), - _cachedFrame(0), - _cachedFrameNeedsDeletion(false) { - if (fileName.hasSuffix(".rlf")) { - _fileType = RLF; - _animation.rlf = new RlfAnimation(fileName, false); - } else if (fileName.hasSuffix(".avi")) { - _fileType = AVI; - _animation.avi = new ZorkAVIDecoder(); - _animation.avi->loadFile(fileName); - } else { - warning("Unrecognized animation file type: %s", fileName.c_str()); - } - - _cachedFrame = new Graphics::Surface(); -} - -AnimationControl::~AnimationControl() { - if (_fileType == RLF) { - delete _animation.rlf; - } else if (_fileType == AVI) { - delete _animation.avi; - } - - _cachedFrame->free(); - delete _cachedFrame; -} - -bool AnimationControl::process(uint32 deltaTimeInMillis) { - if (!_enabled) { - return false; - } - - bool finished = false; - - if (_fileType == RLF) { - _accumulatedTime += deltaTimeInMillis; - - uint32 frameTime = _animation.rlf->frameTime(); - if (_accumulatedTime >= frameTime) { - while (_accumulatedTime >= frameTime) { - _accumulatedTime -= frameTime; - - // Make sure the frame is inside the working window - // If it's not, then just return - - RenderManager *renderManager = _engine->getRenderManager(); - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _animation.rlf->width(), workingWindowPoint.y + _animation.rlf->height()); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - const Graphics::Surface *frame = _animation.rlf->getNextFrame(); - - // Animation frames for PANORAMAs are transposed, so un-transpose them - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - if (state == RenderTable::PANORAMA) { - Graphics::Surface *tranposedFrame = RenderManager::tranposeSurface(frame); - - renderManager->copyRectToWorkingWindow((uint16 *)tranposedFrame->getBasePtr(tranposedFrame->w - subRect.width(), tranposedFrame->h - subRect.height()), subRect.left, subRect.top, _animation.rlf->width(), subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame = tranposedFrame; - _cachedFrameNeedsDeletion = true; - } else { - // Cleanup - tranposedFrame->free(); - delete tranposedFrame; - } - } else { - renderManager->copyRectToWorkingWindow((const uint16 *)frame->getBasePtr(frame->w - subRect.width(), frame->h - subRect.height()), subRect.left, subRect.top, _animation.rlf->width(), subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame->copyFrom(*frame); - } - } - - // Check if we should continue looping - if (_animation.rlf->endOfAnimation()) { - _animation.rlf->seekToFrame(-1); - if (_loopCount > 0) { - _currentLoop++; - if (_currentLoop >= _loopCount) { - finished = true; - } - } - } - } - } else { - // If the background can move, we have to keep rendering animation frames, otherwise the animation flickers during background movement - RenderManager *renderManager = _engine->getRenderManager(); - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _cachedFrame->w, workingWindowPoint.y + _cachedFrame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - renderManager->copyRectToWorkingWindow((uint16 *)_cachedFrame->getBasePtr(_cachedFrame->w - subRect.width(), _cachedFrame->h - subRect.height()), subRect.left, subRect.top, _cachedFrame->w, subRect.width(), subRect.height()); - } - } - } else if (_fileType == AVI) { - if (!_animation.avi->isPlaying()) { - _animation.avi->start(); - } - - if (_animation.avi->needsUpdate()) { - const Graphics::Surface *frame = _animation.avi->decodeNextFrame(); - - if (frame) { - // Make sure the frame is inside the working window - // If it's not, then just return - - RenderManager *renderManager = _engine->getRenderManager(); - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + frame->w, workingWindowPoint.y + frame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - // Animation frames for PANORAMAs are transposed, so un-transpose them - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - if (state == RenderTable::PANORAMA) { - Graphics::Surface *tranposedFrame = RenderManager::tranposeSurface(frame); - - renderManager->copyRectToWorkingWindow((uint16 *)tranposedFrame->getBasePtr(tranposedFrame->w - subRect.width(), tranposedFrame->h - subRect.height()), subRect.left, subRect.top, frame->w, subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame = tranposedFrame; - _cachedFrameNeedsDeletion = true; - } else { - // Cleanup - tranposedFrame->free(); - delete tranposedFrame; - } - } else { - renderManager->copyRectToWorkingWindow((const uint16 *)frame->getBasePtr(frame->w - subRect.width(), frame->h - subRect.height()), subRect.left, subRect.top, frame->w, subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame->copyFrom(*frame); - } - } - } else { - // If the background can move, we have to keep rendering animation frames, otherwise the animation flickers during background movement - RenderManager *renderManager = _engine->getRenderManager(); - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _cachedFrame->w, workingWindowPoint.y + _cachedFrame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - renderManager->copyRectToWorkingWindow((uint16 *)_cachedFrame->getBasePtr(_cachedFrame->w - subRect.width(), _cachedFrame->h - subRect.height()), subRect.left, subRect.top, _cachedFrame->w, subRect.width(), subRect.height()); - } - } - } - - // Check if we should continue looping - if (_animation.avi->endOfVideo()) { - _animation.avi->rewind(); - if (_loopCount > 0) { - _currentLoop++; - if (_currentLoop >= _loopCount) { - _animation.avi->stop(); - finished = true; - } - } - } - } - - // If we're done, set _animation key = 2 (Why 2? I don't know. It's just the value that they used) - // Then disable the control. DON'T delete it. It can be re-used - if (finished) { - _engine->getScriptManager()->setStateValue(_animationKey, 2); - disable(); - _currentLoop = 0; - } - - return false; -} - -} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/fist_control.cpp b/engines/zvision/scripting/controls/fist_control.cpp new file mode 100644 index 0000000000..9bb03cba51 --- /dev/null +++ b/engines/zvision/scripting/controls/fist_control.cpp @@ -0,0 +1,320 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/fist_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" +#include "common/file.h" +#include "common/system.h" + +#include "graphics/surface.h" + + +namespace ZVision { + +FistControl::FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_FIST) { + _cursor = CursorIndex_Idle; + _animation = NULL; + _soundKey = 0; + _fiststatus = 0; + _order = 0; + _fistnum = 0; + + _frameCur = -1; + _frameEnd = -1; + _frameTime = 0; + _lastRenderedFrame = -1; + _animationId = 0; + + clearFistArray(_fistsUp); + clearFistArray(_fistsDwn); + + _numEntries = 0; + _entries.clear(); + + _anmRect = Common::Rect(); + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("sound_key", true)) { + _soundKey = atoi(values.c_str()); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("descfile", true)) { + readDescFile(values); + } else if (param.matchString("animation_id", true)) { + _animationId = atoi(values.c_str()); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } +} + +FistControl::~FistControl() { + if (_animation) + delete _animation; + + clearFistArray(_fistsUp); + clearFistArray(_fistsDwn); + _entries.clear(); +} + +void FistControl::renderFrame(uint frameNumber) { + if ((int32)frameNumber == _lastRenderedFrame) + return; + + _lastRenderedFrame = frameNumber; + + const Graphics::Surface *frameData; + + if (_animation) { + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _anmRect); + } +} + +bool FistControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_frameCur >= 0 && _frameEnd >= 0) + if (_frameCur <= _frameEnd) { + _frameTime -= deltaTimeInMillis; + + if (_frameTime <= 0) { + _frameTime = _animation->frameTime(); + + renderFrame(_frameCur); + + _frameCur++; + + if (_frameCur > _frameEnd) + _engine->getScriptManager()->setStateValue(_animationId, 2); + } + } + + return false; +} + +bool FistControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (mouseIn(screenSpacePos, backgroundImageSpacePos) >= 0) { + _engine->getCursorManager()->changeCursor(_cursor); + return true; + } + + return false; +} + +bool FistControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + int fistNumber = mouseIn(screenSpacePos, backgroundImageSpacePos); + + if (fistNumber >= 0) { + setVenus(); + + uint32 oldStatus = _fiststatus; + _fiststatus ^= (1 << fistNumber); + + for (int i = 0; i < _numEntries; i++) + if (_entries[i]._bitsStrt == oldStatus && _entries[i]._bitsEnd == _fiststatus) { + _frameCur = _entries[i]._anmStrt; + _frameEnd = _entries[i]._anmEnd; + _frameTime = 0; + + _engine->getScriptManager()->setStateValue(_animationId, 1); + _engine->getScriptManager()->setStateValue(_soundKey, _entries[i]._sound); + break; + } + + _engine->getScriptManager()->setStateValue(_key, _fiststatus); + } + + return false; +} + +void FistControl::readDescFile(const Common::String &fileName) { + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("Desc file %s could could be opened", fileName.c_str()); + return; + } + + Common::String line; + Common::String param; + Common::String values; + + while (!file.eos()) { + line = file.readLine(); + getFistParams(line, param, values); + + if (param.matchString("animation_id", true)) { + // Not used + } else if (param.matchString("animation", true)) { + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("anim_rect", true)) { + int left, top, right, bottom; + sscanf(values.c_str(), "%d %d %d %d", &left, &top, &right, &bottom); + _anmRect = Common::Rect(left, top, right, bottom); + } else if (param.matchString("num_fingers", true)) { + sscanf(values.c_str(), "%d", &_fistnum); + _fistsUp.resize(_fistnum); + _fistsDwn.resize(_fistnum); + } else if (param.matchString("entries", true)) { + sscanf(values.c_str(), "%d", &_numEntries); + _entries.resize(_numEntries); + } else if (param.matchString("eval_order_ascending", true)) { + sscanf(values.c_str(), "%d", &_order); + } else if (param.matchString("up_hs_num_*", true)) { + int fist, num; + num = atoi(values.c_str()); + + sscanf(param.c_str(), "up_hs_num_%d", &fist); + _fistsUp[fist].resize(num); + } else if (param.matchString("up_hs_*", true)) { + int16 fist, box, x1, y1, x2, y2; + sscanf(param.c_str(), "up_hs_%hd_%hd", &fist, &box); + sscanf(values.c_str(), "%hd %hd %hd %hd", &x1, &y1, &x2, &y2); + (_fistsUp[fist])[box] = Common::Rect(x1, y1, x2, y2); + } else if (param.matchString("down_hs_num_*", true)) { + int fist, num; + num = atoi(values.c_str()); + + sscanf(param.c_str(), "down_hs_num_%d", &fist); + _fistsDwn[fist].resize(num); + } else if (param.matchString("down_hs_*", true)) { + int16 fist, box, x1, y1, x2, y2; + sscanf(param.c_str(), "down_hs_%hd_%hd", &fist, &box); + sscanf(values.c_str(), "%hd %hd %hd %hd", &x1, &y1, &x2, &y2); + (_fistsDwn[fist])[box] = Common::Rect(x1, y1, x2, y2); + } else { + int entry, start, end, sound; + char bitsStart[33]; + char bitsEnd[33]; + entry = atoi(param.c_str()); + if (sscanf(values.c_str(), "%s %s %d %d (%d)", bitsStart, bitsEnd, &start, &end, &sound) == 5) { + _entries[entry]._bitsStrt = readBits(bitsStart); + _entries[entry]._bitsEnd = readBits(bitsEnd); + _entries[entry]._anmStrt = start; + _entries[entry]._anmEnd = end; + _entries[entry]._sound = sound; + } + } + } + file.close(); +} + +void FistControl::clearFistArray(Common::Array< Common::Array<Common::Rect> > &arr) { + for (uint i = 0; i < arr.size(); i++) + arr[i].clear(); + + arr.clear(); +} + +uint32 FistControl::readBits(const char *str) { + uint32 bfield = 0; + int len = strlen(str); + for (int i = 0; i < len; i++) + if (str[i] != '0') + bfield |= (1 << i); + return bfield; +} + +int FistControl::mouseIn(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_order) { + for (int i = 0; i < _fistnum; i++) { + if (((_fiststatus >> i) & 1) == 1) { + for (uint j = 0; j < _fistsDwn[i].size(); j++) + if ((_fistsDwn[i])[j].contains(backgroundImageSpacePos)) + return i; + } else { + for (uint j = 0; j < _fistsUp[i].size(); j++) + if ((_fistsUp[i])[j].contains(backgroundImageSpacePos)) + return i; + } + } + } else { + for (int i = _fistnum - 1; i >= 0; i--) { + if (((_fiststatus >> i) & 1) == 1) { + for (uint j = 0; j < _fistsDwn[i].size(); j++) + if ((_fistsDwn[i])[j].contains(backgroundImageSpacePos)) + return i; + } else { + for (uint j = 0; j < _fistsUp[i].size(); j++) + if ((_fistsUp[i])[j].contains(backgroundImageSpacePos)) + return i; + } + } + } + return -1; +} + +void FistControl::getFistParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values) { + const char *chrs = inputStr.c_str(); + uint lbr; + + for (lbr = 0; lbr < inputStr.size(); lbr++) + if (chrs[lbr] == ':') + break; + + if (lbr >= inputStr.size()) + return; + + uint rbr; + + for (rbr = lbr + 1; rbr < inputStr.size(); rbr++) + if (chrs[rbr] == '~') + break; + + if (rbr >= inputStr.size()) + return; + + parameter = Common::String(chrs, chrs + lbr); + values = Common::String(chrs + lbr + 1, chrs + rbr); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/fist_control.h b/engines/zvision/scripting/controls/fist_control.h new file mode 100644 index 0000000000..33c3c7b579 --- /dev/null +++ b/engines/zvision/scripting/controls/fist_control.h @@ -0,0 +1,87 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_FIST_CONTROL_H +#define ZVISION_FIST_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/array.h" +#include "common/rect.h" + + +namespace ZVision { + +class MetaAnimation; + +class FistControl : public Control { +public: + FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~FistControl(); + +private: + uint32 _fiststatus; + int _fistnum; + int16 _cursor; + int _order; + + Common::Array< Common::Array<Common::Rect> > _fistsUp; + Common::Array< Common::Array<Common::Rect> > _fistsDwn; + + int32 _numEntries; + + struct entries { + uint32 _bitsStrt; + uint32 _bitsEnd; + int32 _anmStrt; + int32 _anmEnd; + int32 _sound; + }; + + Common::Array<entries> _entries; + + MetaAnimation *_animation; + Common::Rect _anmRect; + int32 _soundKey; + int32 _frameCur; + int32 _frameEnd; + int32 _frameTime; + int32 _lastRenderedFrame; + int32 _animationId; + +public: + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool process(uint32 deltaTimeInMillis); + +private: + void renderFrame(uint frameNumber); + void readDescFile(const Common::String &fileName); + void clearFistArray(Common::Array< Common::Array<Common::Rect> > &arr); + uint32 readBits(const char *str); + int mouseIn(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + void getFistParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/hotmov_control.cpp b/engines/zvision/scripting/controls/hotmov_control.cpp new file mode 100644 index 0000000000..fd7afb92d1 --- /dev/null +++ b/engines/zvision/scripting/controls/hotmov_control.cpp @@ -0,0 +1,201 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/hotmov_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" +#include "common/file.h" +#include "common/system.h" + +#include "graphics/surface.h" + + +namespace ZVision { + +HotMovControl::HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_HOTMOV) { + _animation = NULL; + _cycle = 0; + _curFrame = -1; + _lastRenderedFrame = -1; + _frames.clear(); + _frameTime = 0; + _cyclesCount = 0; + _framesCount = 0; + + _engine->getScriptManager()->setStateValue(_key, 0); + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("hs_frame_list", true)) { + readHsFile(values); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width, height); + } else if (param.matchString("num_frames", true)) { + _framesCount = atoi(values.c_str()); + } else if (param.matchString("num_cycles", true)) { + _cyclesCount = atoi(values.c_str()); + } else if (param.matchString("animation", true)) { + char filename[64]; + sscanf(values.c_str(), "%s", filename); + values = Common::String(filename); + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } +} + +HotMovControl::~HotMovControl() { + if (_animation) + delete _animation; + + _frames.clear(); +} + +void HotMovControl::renderFrame(uint frameNumber) { + if ((int)frameNumber == _lastRenderedFrame) + return; + + _lastRenderedFrame = frameNumber; + + const Graphics::Surface *frameData; + + if (_animation) { + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _rectangle); + } +} + +bool HotMovControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_cycle < _cyclesCount) { + _frameTime -= deltaTimeInMillis; + + if (_frameTime <= 0) { + _curFrame++; + if (_curFrame >= _framesCount) { + _curFrame = 0; + _cycle++; + } + if (_cycle != _cyclesCount) + renderFrame(_curFrame); + else + _engine->getScriptManager()->setStateValue(_key, 2); + + _frameTime = _animation->frameTime(); + } + } + + return false; +} + +bool HotMovControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_cycle < _cyclesCount) { + if (_frames[_curFrame].contains(backgroundImageSpacePos)) { + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + return true; + } + } + + return false; +} + +bool HotMovControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_cycle < _cyclesCount) { + if (_frames[_curFrame].contains(backgroundImageSpacePos)) { + setVenus(); + _engine->getScriptManager()->setStateValue(_key, 1); + return true; + } + } + + return false; +} + +void HotMovControl::readHsFile(const Common::String &fileName) { + if (_framesCount == 0) + return; + + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("HS file %s could could be opened", fileName.c_str()); + return; + } + + Common::String line; + + _frames.resize(_framesCount); + + while (!file.eos()) { + line = file.readLine(); + + int frame; + int x; + int y; + int width; + int height; + + sscanf(line.c_str(), "%d:%d %d %d %d~", &frame, &x, &y, &width, &height); + + if (frame >= 0 && frame < _framesCount) + _frames[frame] = Common::Rect(x, y, width, height); + } + file.close(); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/hotmov_control.h b/engines/zvision/scripting/controls/hotmov_control.h new file mode 100644 index 0000000000..9e01b40bab --- /dev/null +++ b/engines/zvision/scripting/controls/hotmov_control.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_HOTMOV_CONTROL_H +#define ZVISION_HOTMOV_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/array.h" +#include "common/rect.h" + + +namespace ZVision { + +class MetaAnimation; + +class HotMovControl : public Control { +public: + HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~HotMovControl(); + +private: + int32 _framesCount; + int32 _frameTime; + int32 _curFrame; + int32 _lastRenderedFrame; + int32 _cycle; + int32 _cyclesCount; + MetaAnimation *_animation; + Common::Rect _rectangle; + Common::Array<Common::Rect> _frames; +public: + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool process(uint32 deltaTimeInMillis); + +private: + void renderFrame(uint frameNumber); + void readHsFile(const Common::String &fileName); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp index a35548d02e..8af436bb40 100644 --- a/engines/zvision/scripting/controls/input_control.cpp +++ b/engines/zvision/scripting/controls/input_control.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -23,10 +23,11 @@ #include "common/scummsys.h" #include "zvision/scripting/controls/input_control.h" +#include "zvision/cursors/cursor_manager.h" #include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" -#include "zvision/strings/string_manager.h" +#include "zvision/text/string_manager.h" #include "zvision/graphics/render_manager.h" #include "zvision/utility/utility.h" @@ -38,105 +39,218 @@ namespace ZVision { InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) - : Control(engine, key), - _nextTabstop(0), - _focused(false), - _textChanged(false), - _cursorOffset(0) { + : Control(engine, key, CONTROL_INPUT), + _nextTabstop(0), + _focused(false), + _textChanged(false), + _cursorOffset(0), + _enterPressed(false), + _readOnly(false), + _txtWidth(0), + _animation(NULL) { // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { - if (line.matchString("*rectangle*", true)) { + if (param.matchString("rectangle", true)) { int x1; int y1; int x2; int y2; - sscanf(line.c_str(), "%*[^(](%d %d %d %d)", &x1, &y1, &x2, &y2); + sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _textRectangle = Common::Rect(x1, y1, x2, y2); - } else if (line.matchString("*aux_hotspot*", true)) { + } else if (param.matchString("aux_hotspot", true)) { int x1; int y1; int x2; int y2; - sscanf(line.c_str(), "%*[^(](%d %d %d %d)", &x1, &y1, &x2, &y2); + sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _headerRectangle = Common::Rect(x1, y1, x2, y2); - } else if (line.matchString("*string_init*", true)) { + } else if (param.matchString("string_init", true)) { uint fontFormatNumber; - sscanf(line.c_str(), "%*[^(](%u)", &fontFormatNumber); + sscanf(values.c_str(), "%u", &fontFormatNumber); - _textStyle = _engine->getStringManager()->getTextStyle(fontFormatNumber); - } else if (line.matchString("*next_tabstop*", true)) { - sscanf(line.c_str(), "%*[^(](%u)", &_nextTabstop); - } else if (line.matchString("*cursor_animation*", true)) { - char fileName[26]; + _stringInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); + } else if (param.matchString("chooser_init_string", true)) { + uint fontFormatNumber; - sscanf(line.c_str(), "%*[^(](%25s %*u)", fileName); + sscanf(values.c_str(), "%u", &fontFormatNumber); - _cursorAnimationFileName = Common::String(fileName); - } else if (line.matchString("*cursor_dimensions*", true)) { + _stringChooserInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); + } else if (param.matchString("next_tabstop", true)) { + sscanf(values.c_str(), "%u", &_nextTabstop); + } else if (param.matchString("cursor_dimensions", true)) { // Ignore, use the dimensions in the animation file - } else if (line.matchString("*cursor_animation_frames*", true)) { + } else if (param.matchString("cursor_animation_frames", true)) { // Ignore, use the frame count in the animation file - } else if (line.matchString("*focus*", true)) { + } else if (param.matchString("cursor_animation", true)) { + char fileName[25]; + + sscanf(values.c_str(), "%25s %*u", fileName); + + _animation = new MetaAnimation(fileName, _engine); + _frame = -1; + _frameDelay = 0; + } else if (param.matchString("focus", true)) { _focused = true; + _engine->getScriptManager()->setFocusControlKey(_key); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); } } -void InputControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - _engine->getScriptManager()->focusControl(_key); +bool InputControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_textRectangle.contains(backgroundImageSpacePos)) { + if (!_readOnly) { + // Save + _engine->getScriptManager()->focusControl(_key); + setVenus(); + } else { + // Restore + if (_currentInputText.size()) { + setVenus(); + _enterPressed = true; + } + } + } + return false; } -void InputControl::onKeyDown(Common::KeyState keyState) { +bool InputControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_textRectangle.contains(backgroundImageSpacePos)) { + if (!_readOnly) { + // Save + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + return true; + } else { + // Restore + if (_currentInputText.size()) { + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + _engine->getScriptManager()->focusControl(_key); + return true; + } + } + } + return false; +} + +bool InputControl::onKeyDown(Common::KeyState keyState) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + if (!_focused) { - return; + return false; } if (keyState.keycode == Common::KEYCODE_BACKSPACE) { - _currentInputText.deleteLastChar(); + if (!_readOnly) { + _currentInputText.deleteLastChar(); + _textChanged = true; + } + } else if (keyState.keycode == Common::KEYCODE_RETURN) { + _enterPressed = true; } else if (keyState.keycode == Common::KEYCODE_TAB) { - _focused = false; + unfocus(); // Focus the next input control _engine->getScriptManager()->focusControl(_nextTabstop); + // Don't process this event for other controls + return true; } else { - // Otherwise, append the new character to the end of the current text - - uint16 asciiValue = keyState.ascii; - // We only care about text values - if (asciiValue >= 32 && asciiValue <= 126) { - _currentInputText += (char)asciiValue; - _textChanged = true; + if (!_readOnly) { + // Otherwise, append the new character to the end of the current text + uint16 asciiValue = keyState.ascii; + // We only care about text values + if (asciiValue >= 32 && asciiValue <= 126) { + _currentInputText += (char)asciiValue; + _textChanged = true; + } } } + return false; } bool InputControl::process(uint32 deltaTimeInMillis) { - if (!_focused) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } // First see if we need to render the text if (_textChanged) { // Blit the text using the RenderManager - Common::Rect destRect = _engine->getRenderManager()->renderTextToWorkingWindow(_key, _currentInputText, _textStyle.font, _textRectangle.left, _textRectangle.top, _textStyle.color, _textRectangle.width()); - _cursorOffset = destRect.left - _textRectangle.left; + Graphics::Surface txt; + txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_pixelFormat); + + if (!_readOnly || !_focused) + _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt); + else + _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringChooserInit, txt); + + _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top); + + txt.free(); } - // Render the next frame of the animation - // TODO: Implement animation handling + if (_animation && !_readOnly && _focused) { + bool needDraw = true;// = _textChanged; + _frameDelay -= deltaTimeInMillis; + if (_frameDelay <= 0) { + _frame = (_frame + 1) % _animation->frameCount(); + _frameDelay = _animation->frameTime(); + needDraw = true; + } + if (needDraw) { + const Graphics::Surface *srf = _animation->getFrameData(_frame); + uint32 xx = _textRectangle.left + _txtWidth; + if (xx >= _textRectangle.left + (_textRectangle.width() - _animation->width())) + xx = _textRectangle.left + _textRectangle.width() - _animation->width(); + _engine->getRenderManager()->blitSurfaceToBkg(*srf, xx, _textRectangle.top); + } + } + + _textChanged = false; + return false; +} + +bool InputControl::enterPress() { + if (_enterPressed) { + _enterPressed = false; + return true; + } return false; } +void InputControl::setText(const Common::String &_str) { + _currentInputText = _str; + _textChanged = true; +} + +const Common::String InputControl::getText() { + return _currentInputText; +} + +void InputControl::setReadOnly(bool readonly) { + _readOnly = readonly; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/input_control.h b/engines/zvision/scripting/controls/input_control.h index 32432438bb..9a829d30f6 100644 --- a/engines/zvision/scripting/controls/input_control.h +++ b/engines/zvision/scripting/controls/input_control.h @@ -24,7 +24,9 @@ #define ZVISION_INPUT_CONTROL_H #include "zvision/scripting/control.h" -#include "zvision/strings/string_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/text/text.h" +#include "zvision/text/string_manager.h" #include "common/rect.h" @@ -38,21 +40,39 @@ public: private: Common::Rect _textRectangle; Common::Rect _headerRectangle; - StringManager::TextStyle _textStyle; + cTxtStyle _stringInit; + cTxtStyle _stringChooserInit; uint32 _nextTabstop; - Common::String _cursorAnimationFileName; bool _focused; Common::String _currentInputText; bool _textChanged; uint _cursorOffset; + bool _enterPressed; + bool _readOnly; + + int16 _txtWidth; + MetaAnimation *_animation; + int32 _frameDelay; + int16 _frame; public: - void focus() { _focused = true; } - void unfocus() { _focused = false; } - void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); - void onKeyDown(Common::KeyState keyState); + void focus() { + _focused = true; + _textChanged = true; + } + void unfocus() { + _focused = false; + _textChanged = true; + } + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onKeyDown(Common::KeyState keyState); bool process(uint32 deltaTimeInMillis); + void setText(const Common::String &_str); + const Common::String getText(); + bool enterPress(); + void setReadOnly(bool); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/lever_control.cpp b/engines/zvision/scripting/controls/lever_control.cpp index c029a2a7a1..1f176ef9d0 100644 --- a/engines/zvision/scripting/controls/lever_control.cpp +++ b/engines/zvision/scripting/controls/lever_control.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,8 +28,7 @@ #include "zvision/scripting/script_manager.h" #include "zvision/graphics/render_manager.h" #include "zvision/cursors/cursor_manager.h" -#include "zvision/animation/rlf_animation.h" -#include "zvision/video/zork_avi_decoder.h" +#include "zvision/animation/meta_animation.h" #include "zvision/utility/utility.h" #include "common/stream.h" @@ -43,114 +42,113 @@ namespace ZVision { LeverControl::LeverControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) - : Control(engine, key), - _frameInfo(0), - _frameCount(0), - _startFrame(0), - _currentFrame(0), - _lastRenderedFrame(0), - _mouseIsCaptured(false), - _isReturning(false), - _accumulatedTime(0), - _returnRoutesCurrentFrame(0) { + : Control(engine, key, CONTROL_LEVER), + _frameInfo(0), + _frameCount(0), + _startFrame(0), + _currentFrame(0), + _lastRenderedFrame(0), + _mouseIsCaptured(false), + _isReturning(false), + _accumulatedTime(0), + _returnRoutesCurrentFrame(0) { // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + while (!stream.eos() && !line.contains('}')) { - if (line.matchString("*descfile*", true)) { + if (param.matchString("descfile", true)) { char levFileName[25]; - sscanf(line.c_str(), "%*[^(](%25[^)])", levFileName); + sscanf(values.c_str(), "%25s", levFileName); parseLevFile(levFileName); - } else if (line.matchString("*cursor*", true)) { + } else if (param.matchString("cursor", true)) { char cursorName[25]; - sscanf(line.c_str(), "%*[^(](%25[^)])", cursorName); + sscanf(values.c_str(), "%25s", cursorName); - _cursorName = Common::String(cursorName); + _cursor = _engine->getCursorManager()->getCursorId(Common::String(cursorName)); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); } renderFrame(_currentFrame); } LeverControl::~LeverControl() { - if (_fileType == AVI) { - delete _animation.avi; - } else if (_fileType == RLF) { - delete _animation.rlf; - } + if (_animation) + delete _animation; delete[] _frameInfo; } void LeverControl::parseLevFile(const Common::String &fileName) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("LEV file %s could could be opened", fileName.c_str()); return; } - Common::String line = file.readLine(); + Common::String line; + Common::String param; + Common::String values; while (!file.eos()) { - if (line.matchString("*animation_id*", true)) { + line = file.readLine(); + getLevParams(line, param, values); + + if (param.matchString("animation_id", true)) { // Not used - } else if (line.matchString("*filename*", true)) { - char fileNameBuffer[25]; - sscanf(line.c_str(), "%*[^:]:%25[^~]~", fileNameBuffer); - - Common::String animationFileName(fileNameBuffer); - - if (animationFileName.hasSuffix(".avi")) { - _animation.avi = new ZorkAVIDecoder(); - _animation.avi->loadFile(animationFileName); - _fileType = AVI; - } else if (animationFileName.hasSuffix(".rlf")) { - _animation.rlf = new RlfAnimation(animationFileName, false); - _fileType = RLF; - } - } else if (line.matchString("*skipcolor*", true)) { + } else if (param.matchString("filename", true)) { + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("skipcolor", true)) { // Not used - } else if (line.matchString("*anim_coords*", true)) { + } else if (param.matchString("anim_coords", true)) { int left, top, right, bottom; - sscanf(line.c_str(), "%*[^:]:%d %d %d %d~", &left, &top, &right, &bottom); + sscanf(values.c_str(), "%d %d %d %d", &left, &top, &right, &bottom); _animationCoords.left = left; _animationCoords.top = top; _animationCoords.right = right; _animationCoords.bottom = bottom; - } else if (line.matchString("*mirrored*", true)) { + } else if (param.matchString("mirrored", true)) { uint mirrored; - sscanf(line.c_str(), "%*[^:]:%u~", &mirrored); + sscanf(values.c_str(), "%u", &mirrored); _mirrored = mirrored == 0 ? false : true; - } else if (line.matchString("*frames*", true)) { - sscanf(line.c_str(), "%*[^:]:%u~", &_frameCount); + } else if (param.matchString("frames", true)) { + sscanf(values.c_str(), "%u", &_frameCount); _frameInfo = new FrameInfo[_frameCount]; - } else if (line.matchString("*elsewhere*", true)) { + } else if (param.matchString("elsewhere", true)) { // Not used - } else if (line.matchString("*out_of_control*", true)) { + } else if (param.matchString("out_of_control", true)) { // Not used - } else if (line.matchString("*start_pos*", true)) { - sscanf(line.c_str(), "%*[^:]:%u~", &_startFrame); + } else if (param.matchString("start_pos", true)) { + sscanf(values.c_str(), "%u", &_startFrame); _currentFrame = _startFrame; - } else if (line.matchString("*hotspot_deltas*", true)) { + } else if (param.matchString("hotspot_deltas", true)) { uint x; uint y; - sscanf(line.c_str(), "%*[^:]:%u %u~", &x, &y); + sscanf(values.c_str(), "%u %u", &x, &y); _hotspotDelta.x = x; _hotspotDelta.y = y; + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); } else { uint frameNumber; uint x, y; + line.toLowercase(); + if (sscanf(line.c_str(), "%u:%u %u", &frameNumber, &x, &y) == 3) { _frameInfo[frameNumber].hotspot.left = x; _frameInfo[frameNumber].hotspot.top = y; @@ -158,13 +156,13 @@ void LeverControl::parseLevFile(const Common::String &fileName) { _frameInfo[frameNumber].hotspot.bottom = y + _hotspotDelta.y; } - Common::StringTokenizer tokenizer(line, " ^=()"); + Common::StringTokenizer tokenizer(line, " ^=()~"); tokenizer.nextToken(); tokenizer.nextToken(); Common::String token = tokenizer.nextToken(); while (!tokenizer.empty()) { - if (token == "D") { + if (token == "d") { token = tokenizer.nextToken(); uint angle; @@ -172,7 +170,7 @@ void LeverControl::parseLevFile(const Common::String &fileName) { sscanf(token.c_str(), "%u,%u", &toFrame, &angle); _frameInfo[frameNumber].directions.push_back(Direction(angle, toFrame)); - } else if (token.hasPrefix("P")) { + } else if (token.hasPrefix("p")) { // Format: P(<from> to <to>) tokenizer.nextToken(); tokenizer.nextToken(); @@ -186,25 +184,25 @@ void LeverControl::parseLevFile(const Common::String &fileName) { } } - line = file.readLine(); + // Don't read lines in this place because last will not be parsed. } } -void LeverControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { - return; - } +bool LeverControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) { + setVenus(); _mouseIsCaptured = true; _lastMousePos = backgroundImageSpacePos; } + return false; } -void LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { - return; - } +bool LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; if (_mouseIsCaptured) { _mouseIsCaptured = false; @@ -214,12 +212,12 @@ void LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common:: _returnRoutesCurrentProgress = _frameInfo[_currentFrame].returnRoute.begin(); _returnRoutesCurrentFrame = _currentFrame; } + return false; } bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } bool cursorWasChanged = false; @@ -240,7 +238,7 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common } } } else if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) { - _engine->getCursorManager()->changeCursor(_cursorName); + _engine->getCursorManager()->changeCursor(_cursor); cursorWasChanged = true; } @@ -248,9 +246,8 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common } bool LeverControl::process(uint32 deltaTimeInMillis) { - if (!_enabled) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } if (_isReturning) { _accumulatedTime += deltaTimeInMillis; @@ -301,7 +298,7 @@ int LeverControl::calculateVectorAngle(const Common::Point &pointOne, const Comm // Calculate the angle using arctan // Then convert to degrees. (180 / 3.14159 = 57.2958) - int angle = int(atan((float)yDist / (float)xDist) * 57); + int angle = int(atan((float)yDist / (float)abs(xDist)) * 57); // Calculate what quadrant pointTwo is in uint quadrant = ((yDist > 0 ? 1 : 0) << 1) | (xDist < 0 ? 1 : 0); @@ -350,16 +347,16 @@ int LeverControl::calculateVectorAngle(const Common::Point &pointOne, const Comm // Convert the local angles to unit circle angles switch (quadrant) { case 0: - angle = 180 + angle; + angle = -angle; break; case 1: - // Do nothing + angle = angle + 180; break; case 2: - angle = 180 + angle; + angle = 360 - angle; break; case 3: - angle = 360 + angle; + angle = 180 + angle; break; } @@ -377,26 +374,35 @@ void LeverControl::renderFrame(uint frameNumber) { _lastRenderedFrame = frameNumber; } - const uint16 *frameData = 0; - int x = _animationCoords.left; - int y = _animationCoords.top; - int width = 0; - int height = 0; - - if (_fileType == RLF) { - // getFrameData() will automatically optimize to getNextFrame() / getPreviousFrame() if it can - frameData = (const uint16 *)_animation.rlf->getFrameData(frameNumber)->getPixels(); - width = _animation.rlf->width(); // Use the animation width instead of _animationCoords.width() - height = _animation.rlf->height(); // Use the animation height instead of _animationCoords.height() - } else if (_fileType == AVI) { - _animation.avi->seekToFrame(frameNumber); - const Graphics::Surface *surface = _animation.avi->decodeNextFrame(); - frameData = (const uint16 *)surface->getPixels(); - width = surface->w; - height = surface->h; - } + const Graphics::Surface *frameData; + + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _animationCoords); +} + +void LeverControl::getLevParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values) { + const char *chrs = inputStr.c_str(); + uint lbr; + + for (lbr = 0; lbr < inputStr.size(); lbr++) + if (chrs[lbr] == ':') + break; + + if (lbr >= inputStr.size()) + return; + + uint rbr; + + for (rbr = lbr + 1; rbr < inputStr.size(); rbr++) + if (chrs[rbr] == '~') + break; + + if (rbr >= inputStr.size()) + return; - _engine->getRenderManager()->copyRectToWorkingWindow(frameData, x, y, width, width, height); + parameter = Common::String(chrs, chrs + lbr); + values = Common::String(chrs + lbr + 1, chrs + rbr); } } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/lever_control.h b/engines/zvision/scripting/controls/lever_control.h index 49e4fd3806..8de6d1e5c9 100644 --- a/engines/zvision/scripting/controls/lever_control.h +++ b/engines/zvision/scripting/controls/lever_control.h @@ -32,7 +32,7 @@ namespace ZVision { class ZorkAVIDecoder; -class RlfAnimation; +class MetaAnimation; class LeverControl : public Control { public: @@ -40,10 +40,6 @@ public: ~LeverControl(); private: - enum FileType { - RLF = 1, - AVI = 2 - }; struct Direction { Direction(uint a, uint t) : angle(a), toFrame(t) {} @@ -64,13 +60,9 @@ private: }; private: - union { - RlfAnimation *rlf; - ZorkAVIDecoder *avi; - } _animation; - FileType _fileType; + MetaAnimation *_animation; - Common::String _cursorName; + int _cursor; Common::Rect _animationCoords; bool _mirrored; uint _frameCount; @@ -88,8 +80,8 @@ private: uint32 _accumulatedTime; public: - void onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); - void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); bool process(uint32 deltaTimeInMillis); @@ -120,6 +112,7 @@ private: */ static int calculateVectorAngle(const Common::Point &pointOne, const Common::Point &pointTwo); void renderFrame(uint frameNumber); + void getLevParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/paint_control.cpp b/engines/zvision/scripting/controls/paint_control.cpp new file mode 100644 index 0000000000..cb3c17e0fd --- /dev/null +++ b/engines/zvision/scripting/controls/paint_control.cpp @@ -0,0 +1,216 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/paint_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +namespace ZVision { + +PaintControl::PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_PAINT) { + + _cursor = CursorIndex_Active; + _paint = NULL; + _bkg = NULL; + _brush = NULL; + _colorKey = 0; + _mouseDown = false; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width + x, height + y); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("brush_file", true)) { + _brush = _engine->getRenderManager()->loadImage(values, false); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } else if (param.matchString("paint_file", true)) { + _paint = _engine->getRenderManager()->loadImage(values, false); + } else if (param.matchString("eligible_objects", true)) { + char buf[256]; + memset(buf, 0, 256); + strcpy(buf, values.c_str()); + + char *curpos = buf; + char *strend = buf + strlen(buf); + while (true) { + char *st = curpos; + + if (st >= strend) + break; + + while (*curpos != ' ' && curpos < strend) + curpos++; + + *curpos = 0; + curpos++; + + int obj = atoi(st); + + _eligibleObjects.push_back(obj); + } + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + if (_paint) { + _colorKey = _paint->format.RGBToColor(255, 0, 255); + _bkg = new Graphics::Surface; + _bkg->create(_rectangle.width(), _rectangle.height(), _paint->format); + _bkg->fillRect(Common::Rect(_rectangle.width(), _rectangle.height()), _colorKey); + + Graphics::Surface *tmp = new Graphics::Surface; + tmp->create(_rectangle.width(), _rectangle.height(), _paint->format); + _engine->getRenderManager()->blitSurfaceToSurface(*_paint, _rectangle, *tmp, 0, 0); + _paint->free(); + delete _paint; + _paint = tmp; + } + + +} + +PaintControl::~PaintControl() { + // Clear the state value back to 0 + //_engine->getScriptManager()->setStateValue(_key, 0); + if (_paint) + delete _paint; + if (_brush) + delete _brush; + if (_bkg) + delete _bkg; +} + +bool PaintControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + _mouseDown = false; + + return false; +} + +bool PaintControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + + if (eligeblity(mouseItem)) { + setVenus(); + _mouseDown = true; + } + } + + return false; +} + +bool PaintControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + + if (eligeblity(mouseItem)) { + _engine->getCursorManager()->changeCursor(_cursor); + + if (_mouseDown) { + Common::Rect bkgRect = paint(backgroundImageSpacePos); + if (!bkgRect.isEmpty()) { + Common::Rect imgRect = bkgRect; + imgRect.translate(-_rectangle.left, -_rectangle.top); + + Graphics::Surface imgUpdate = _bkg->getSubArea(imgRect); + + _engine->getRenderManager()->blitSurfaceToBkg(imgUpdate, bkgRect.left, bkgRect.top, _colorKey); + } + } + return true; + } + } + + return false; +} + +bool PaintControl::eligeblity(int itemId) { + for (Common::List<int>::iterator it = _eligibleObjects.begin(); it != _eligibleObjects.end(); it++) + if (*it == itemId) + return true; + return false; +} + +Common::Rect PaintControl::paint(const Common::Point &point) { + Common::Rect paintRect = Common::Rect(_brush->w, _brush->h); + paintRect.moveTo(point); + paintRect.clip(_rectangle); + + if (!paintRect.isEmpty()) { + Common::Rect brushRect = paintRect; + brushRect.translate(-point.x, -point.y); + + Common::Rect bkgRect = paintRect; + bkgRect.translate(-_rectangle.left, -_rectangle.top); + + for (int yy = 0; yy < brushRect.height(); yy++) { + uint16 *mask = (uint16 *)_brush->getBasePtr(brushRect.left, brushRect.top + yy); + uint16 *from = (uint16 *)_paint->getBasePtr(bkgRect.left, bkgRect.top + yy); + uint16 *to = (uint16 *)_bkg->getBasePtr(bkgRect.left, bkgRect.top + yy); + for (int xx = 0; xx < brushRect.width(); xx++) { + if (*mask != 0) + *(to + xx) = *(from + xx); + + mask++; + } + } + + } + return paintRect; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/paint_control.h b/engines/zvision/scripting/controls/paint_control.h new file mode 100644 index 0000000000..aac4755fcd --- /dev/null +++ b/engines/zvision/scripting/controls/paint_control.h @@ -0,0 +1,92 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_PAINT_CONTROL_H +#define ZVISION_PAINT_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/list.h" + + +namespace ZVision { + +class PaintControl : public Control { +public: + PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~PaintControl(); + + /** + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + + /** + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + /** + * Called on every MouseMove. Tests if the mouse is inside _hotspot, and if so, sets the cursor. + * + * @param engine The base engine + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + * @return Was the cursor changed? + */ + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + + bool process(uint32 deltaTimeInMillis) { + return false; + }; + +private: + /** + * The area that will trigger the event + * This is in image space coordinates, NOT screen space + */ + + uint32 _colorKey; + + Graphics::Surface *_paint; + Graphics::Surface *_bkg; + Graphics::Surface *_brush; + + Common::List<int> _eligibleObjects; + + int _cursor; + Common::Rect _rectangle; + + bool _mouseDown; + + bool eligeblity(int itemId); + Common::Rect paint(const Common::Point &point); + +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/push_toggle_control.cpp b/engines/zvision/scripting/controls/push_toggle_control.cpp index a96c95b377..ea4e947abe 100644 --- a/engines/zvision/scripting/controls/push_toggle_control.cpp +++ b/engines/zvision/scripting/controls/push_toggle_control.cpp @@ -35,64 +35,114 @@ namespace ZVision { PushToggleControl::PushToggleControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) - : Control(engine, key) { + : Control(engine, key, CONTROL_PUSHTGL), + _countTo(2), + _event(Common::EVENT_LBUTTONUP) { + + _hotspots.clear(); + // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { - if (line.matchString("*_hotspot*", true)) { + if (param.matchString("*_hotspot", true)) { uint x; uint y; uint width; uint height; - sscanf(line.c_str(), "%*[^(](%u,%u,%u,%u)", &x, &y, &width, &height); - - _hotspot = Common::Rect(x, y, x + width, y + height); - } else if (line.matchString("cursor*", true)) { - char nameBuffer[25]; - - sscanf(line.c_str(), "%*[^(](%25[^)])", nameBuffer); - - _hoverCursor = Common::String(nameBuffer); + sscanf(values.c_str(), "%u,%u,%u,%u", &x, &y, &width, &height); + + _hotspots.push_back(Common::Rect(x, y, x + width + 1, y + height + 1)); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("animation", true)) { + // Not used + } else if (param.matchString("sound", true)) { + // Not used + } else if (param.matchString("count_to", true)) { + sscanf(values.c_str(), "%u", &_countTo); + } else if (param.matchString("mouse_event", true)) { + if (values.equalsIgnoreCase("up")) { + _event = Common::EVENT_LBUTTONUP; + } else if (values.equalsIgnoreCase("down")) { + _event = Common::EVENT_LBUTTONDOWN; + } else if (values.equalsIgnoreCase("double")) { + // Not used + } + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); } - if (_hotspot.isEmpty() || _hoverCursor.empty()) { - warning("Push_toggle cursor %u was parsed incorrectly", key); + if (_hotspots.size() == 0) { + warning("Push_toggle %u was parsed incorrectly", key); } } PushToggleControl::~PushToggleControl() { - // Clear the state value back to 0 - _engine->getScriptManager()->setStateValue(_key, 0); + _hotspots.clear(); } -void PushToggleControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { - return; +bool PushToggleControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_event != Common::EVENT_LBUTTONUP) + return false; + + if (contain(backgroundImageSpacePos)) { + setVenus(); + int32 val = _engine->getScriptManager()->getStateValue(_key); + val = (val + 1) % _countTo; + _engine->getScriptManager()->setStateValue(_key, val); + return true; } + return false; +} + +bool PushToggleControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; - if (_hotspot.contains(backgroundImageSpacePos)) { - _engine->getScriptManager()->setStateValue(_key, 1); + if (_event != Common::EVENT_LBUTTONDOWN) + return false; + + if (contain(backgroundImageSpacePos)) { + setVenus(); + int32 val = _engine->getScriptManager()->getStateValue(_key); + val = (val + 1) % _countTo; + _engine->getScriptManager()->setStateValue(_key, val); + return true; } + return false; } bool PushToggleControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } - if (_hotspot.contains(backgroundImageSpacePos)) { - _engine->getCursorManager()->changeCursor(_hoverCursor); + if (contain(backgroundImageSpacePos)) { + _engine->getCursorManager()->changeCursor(_cursor); return true; } return false; } +bool PushToggleControl::contain(const Common::Point &point) { + for (uint i = 0; i < _hotspots.size(); i++) + if (_hotspots[i].contains(point)) + return true; + return false; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/push_toggle_control.h b/engines/zvision/scripting/controls/push_toggle_control.h index 3854fc2005..6d68b8f162 100644 --- a/engines/zvision/scripting/controls/push_toggle_control.h +++ b/engines/zvision/scripting/controls/push_toggle_control.h @@ -26,6 +26,8 @@ #include "zvision/scripting/control.h" #include "common/rect.h" +#include "common/events.h" +#include "common/array.h" namespace ZVision { @@ -36,12 +38,19 @@ public: ~PushToggleControl(); /** + * Called when LeftMouse is pushed. Default is NOP. + * + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + /** * Called when LeftMouse is lifted. Calls ScriptManager::setStateValue(_key, 1); * * @param screenSpacePos The position of the mouse in screen space * @param backgroundImageSpacePos The position of the mouse in background image space */ - void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); /** * Called on every MouseMove. Tests if the mouse is inside _hotspot, and if so, sets the cursor. * @@ -57,9 +66,15 @@ private: * The area that will trigger the event * This is in image space coordinates, NOT screen space */ - Common::Rect _hotspot; + Common::Array<Common::Rect> _hotspots; /** The cursor to use when hovering over _hotspot */ - Common::String _hoverCursor; + int _cursor; + /** Button maximal values count */ + uint _countTo; + + Common::EventType _event; + + bool contain(const Common::Point &point); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/safe_control.cpp b/engines/zvision/scripting/controls/safe_control.cpp new file mode 100644 index 0000000000..de1ece5b19 --- /dev/null +++ b/engines/zvision/scripting/controls/safe_control.cpp @@ -0,0 +1,205 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/safe_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" +#include "common/file.h" +#include "common/tokenizer.h" +#include "common/system.h" + +#include "graphics/surface.h" + + +namespace ZVision { + +SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_SAFE) { + _statesCount = 0; + _curState = 0; + _animation = NULL; + _innerRaduis = 0; + _innerRadiusSqr = 0; + _outerRadius = 0; + _outerRadiusSqr = 0; + _zeroPointer = 0; + _startPointer = 0; + _curFrame = -1; + _targetFrame = 0; + _frameTime = 0; + _lastRenderedFrame = -1; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("animation", true)) { + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width, height); + } else if (param.matchString("num_states", true)) { + _statesCount = atoi(values.c_str()); + } else if (param.matchString("center", true)) { + int x; + int y; + + sscanf(values.c_str(), "%d %d", &x, &y); + _center = Common::Point(x, y); + } else if (param.matchString("dial_inner_radius", true)) { + _innerRaduis = atoi(values.c_str()); + _innerRadiusSqr = _innerRaduis * _innerRaduis; + } else if (param.matchString("radius", true)) { + _outerRadius = atoi(values.c_str()); + _outerRadiusSqr = _outerRadius * _outerRadius; + } else if (param.matchString("zero_radians_offset", true)) { + _zeroPointer = atoi(values.c_str()); + } else if (param.matchString("pointer_offset", true)) { + _startPointer = atoi(values.c_str()); + _curState = _startPointer; + } else if (param.matchString("cursor", true)) { + // Not used + } else if (param.matchString("mirrored", true)) { + // Not used + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + renderFrame(_curState); +} + +SafeControl::~SafeControl() { + if (_animation) + delete _animation; + +} + +void SafeControl::renderFrame(uint frameNumber) { + if (frameNumber == 0) { + _lastRenderedFrame = frameNumber; + } else if ((int16)frameNumber < _lastRenderedFrame) { + _lastRenderedFrame = frameNumber; + frameNumber = (_statesCount * 2) - frameNumber; + } else { + _lastRenderedFrame = frameNumber; + } + + const Graphics::Surface *frameData; + int x = _rectangle.left; + int y = _rectangle.top; + + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkg(*frameData, x, y); +} + +bool SafeControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_curFrame != _targetFrame) { + _frameTime -= deltaTimeInMillis; + + if (_frameTime <= 0) { + if (_curFrame < _targetFrame) { + _curFrame++; + renderFrame(_curFrame); + } else if (_curFrame > _targetFrame) { + _curFrame--; + renderFrame(_curFrame); + } + _frameTime = _animation->frameTime(); + } + } + return false; +} + +bool SafeControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int32 mR = backgroundImageSpacePos.sqrDist(_center); + if (mR <= _outerRadiusSqr && mR >= _innerRadiusSqr) { + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + return true; + } + } + return false; +} + +bool SafeControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int32 mR = backgroundImageSpacePos.sqrDist(_center); + if (mR <= _outerRadiusSqr && mR >= _innerRadiusSqr) { + setVenus(); + + Common::Point tmp = backgroundImageSpacePos - _center; + + float dd = atan2(tmp.x, tmp.y) * 57.29578; + + int16 dp_state = 360 / _statesCount; + + int16 m_state = (_statesCount - ((((int16)dd + 540) % 360) / dp_state)) % _statesCount; + + int16 tmp2 = (m_state + _curState - _zeroPointer + _statesCount - 1) % _statesCount; + + _curFrame = (_curState + _statesCount - _startPointer) % _statesCount; + + _curState = (_statesCount * 2 + tmp2) % _statesCount; + + _targetFrame = (_curState + _statesCount - _startPointer) % _statesCount; + + _engine->getScriptManager()->setStateValue(_key, _curState); + return true; + } + } + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/safe_control.h b/engines/zvision/scripting/controls/safe_control.h new file mode 100644 index 0000000000..e682e35050 --- /dev/null +++ b/engines/zvision/scripting/controls/safe_control.h @@ -0,0 +1,71 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SAFE_CONTROL_H +#define ZVISION_SAFE_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/list.h" +#include "common/rect.h" + + +namespace ZVision { + +class ZorkAVIDecoder; +class MetaAnimation; + +class SafeControl : public Control { +public: + SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~SafeControl(); + +private: + int16 _statesCount; + int16 _curState; + MetaAnimation *_animation; + Common::Point _center; + Common::Rect _rectangle; + int16 _innerRaduis; + int32 _innerRadiusSqr; + int16 _outerRadius; + int32 _outerRadiusSqr; + int16 _zeroPointer; + int16 _startPointer; + int16 _curFrame; + int16 _targetFrame; + int32 _frameTime; + + int16 _lastRenderedFrame; + +public: + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool process(uint32 deltaTimeInMillis); + +private: + void renderFrame(uint frameNumber); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/save_control.cpp b/engines/zvision/scripting/controls/save_control.cpp new file mode 100644 index 0000000000..7e1a65a9cc --- /dev/null +++ b/engines/zvision/scripting/controls/save_control.cpp @@ -0,0 +1,123 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/input_control.h" +#include "zvision/scripting/controls/save_control.h" +#include "zvision/utility/utility.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/text/string_manager.h" + +#include "zvision/core/save_manager.h" + +#include "common/str.h" +#include "common/stream.h" + + +namespace ZVision { + +SaveControl::SaveControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_SAVE), + _saveControl(false) { + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("savebox", true)) { + int saveId; + int inputId; + + sscanf(values.c_str(), "%d %d", &saveId, &inputId); + saveElement elmnt; + elmnt.inputKey = inputId; + elmnt.saveId = saveId; + elmnt.exist = false; + _inputs.push_back(elmnt); + } else if (param.matchString("control_type", true)) { + if (values.contains("save")) + _saveControl = true; + else + _saveControl = false; + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + for (saveElmntList::iterator iter = _inputs.begin(); iter != _inputs.end(); ++iter) { + Control *ctrl = _engine->getScriptManager()->getControl(iter->inputKey); + if (ctrl && ctrl->getType() == Control::CONTROL_INPUT) { + InputControl *inp = (InputControl *)ctrl; + inp->setReadOnly(!_saveControl); + Common::SeekableReadStream *save = _engine->getSaveManager()->getSlotFile(iter->saveId); + if (save) { + SaveGameHeader header; + _engine->getSaveManager()->readSaveGameHeader(save, header); + delete save; + inp->setText(header.saveName); + iter->exist = true; + } + } + } +} + +bool SaveControl::process(uint32 deltaTimeInMillis) { + for (saveElmntList::iterator iter = _inputs.begin(); iter != _inputs.end(); ++iter) { + Control *ctrl = _engine->getScriptManager()->getControl(iter->inputKey); + if (ctrl && ctrl->getType() == Control::CONTROL_INPUT) { + InputControl *inp = (InputControl *)ctrl; + if (inp->enterPress()) { + if (_saveControl) { + if (inp->getText().size() > 0) { + bool toSave = true; + if (iter->exist) + if (!_engine->askQuestion(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEXIST))) + toSave = false; + + if (toSave) { + _engine->getSaveManager()->saveGameBuffered(iter->saveId, inp->getText()); + _engine->delayedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVED), 2000); + _engine->getScriptManager()->changeLocation(_engine->getScriptManager()->getLastMenuLocation()); + } + } else { + _engine->timedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEMPTY), 2000); + } + } else { + _engine->getSaveManager()->loadGame(iter->saveId); + return true; + } + break; + } + } + } + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/save_control.h b/engines/zvision/scripting/controls/save_control.h new file mode 100644 index 0000000000..fefb0e0ce2 --- /dev/null +++ b/engines/zvision/scripting/controls/save_control.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SAVE_CONTROL_H +#define ZVISION_SAVE_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/list.h" + + +namespace ZVision { + +class SaveControl : public Control { +public: + SaveControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + +private: + struct saveElement { + int saveId; + int inputKey; + bool exist; + }; + typedef Common::List<saveElement> saveElmntList; + saveElmntList _inputs; + + bool _saveControl; + +public: + + bool process(uint32 deltaTimeInMillis); + +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/slot_control.cpp b/engines/zvision/scripting/controls/slot_control.cpp new file mode 100644 index 0000000000..074d1905b4 --- /dev/null +++ b/engines/zvision/scripting/controls/slot_control.cpp @@ -0,0 +1,219 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/slot_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" + + +namespace ZVision { + +SlotControl::SlotControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_SLOT) { + + _renderedItem = 0; + _bkg = NULL; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("hotspot", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _hotspot = Common::Rect(x, y, width, height); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width, height); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("distance_id", true)) { + sscanf(values.c_str(), "%c", &_distanceId); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } else if (param.matchString("eligible_objects", true)) { + char buf[256]; + memset(buf, 0, 256); + strcpy(buf, values.c_str()); + + char *curpos = buf; + char *strend = buf + strlen(buf); + while (true) { + char *st = curpos; + + if (st >= strend) + break; + + while (*curpos != ' ' && curpos < strend) + curpos++; + + *curpos = 0; + curpos++; + + int obj = atoi(st); + + _eligibleObjects.push_back(obj); + } + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + if (_hotspot.isEmpty() || _rectangle.isEmpty()) { + warning("Slot %u was parsed incorrectly", key); + } +} + +SlotControl::~SlotControl() { + // Clear the state value back to 0 + //_engine->getScriptManager()->setStateValue(_key, 0); + + if (_bkg) + delete _bkg; +} + +bool SlotControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_hotspot.contains(backgroundImageSpacePos)) { + setVenus(); + + int item = _engine->getScriptManager()->getStateValue(_key); + int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + if (item != 0) { + if (mouseItem != 0) { + if (eligeblity(mouseItem)) { + _engine->getScriptManager()->inventoryDrop(mouseItem); + _engine->getScriptManager()->inventoryAdd(item); + _engine->getScriptManager()->setStateValue(_key, mouseItem); + } + } else { + _engine->getScriptManager()->inventoryAdd(item); + _engine->getScriptManager()->setStateValue(_key, 0); + } + } else if (mouseItem == 0) { + if (eligeblity(0)) { + _engine->getScriptManager()->inventoryDrop(0); + _engine->getScriptManager()->setStateValue(_key, 0); + } + } else if (eligeblity(mouseItem)) { + _engine->getScriptManager()->setStateValue(_key, mouseItem); + _engine->getScriptManager()->inventoryDrop(mouseItem); + } + } + return false; +} + +bool SlotControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_hotspot.contains(backgroundImageSpacePos)) { + _engine->getCursorManager()->changeCursor(_cursor); + return true; + } + + return false; +} + +bool SlotControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_engine->canRender()) { + int curItem = _engine->getScriptManager()->getStateValue(_key); + if (curItem != _renderedItem) { + if (_renderedItem != 0 && curItem == 0) { + _engine->getRenderManager()->blitSurfaceToBkg(*_bkg, _rectangle.left, _rectangle.top); + _renderedItem = curItem; + } else { + if (_renderedItem == 0) { + if (_bkg) + delete _bkg; + + _bkg = _engine->getRenderManager()->getBkgRect(_rectangle); + } else { + _engine->getRenderManager()->blitSurfaceToBkg(*_bkg, _rectangle.left, _rectangle.top); + } + + char buf[16]; + if (_engine->getGameId() == GID_NEMESIS) + sprintf(buf, "%d%cobj.tga", curItem, _distanceId); + else + sprintf(buf, "g0z%cu%2.2x1.tga", _distanceId, curItem); + + Graphics::Surface *srf = _engine->getRenderManager()->loadImage(buf); + + int16 drawx = _rectangle.left; + int16 drawy = _rectangle.top; + + if (_rectangle.width() > srf->w) + drawx = _rectangle.left + (_rectangle.width() - srf->w) / 2; + + if (_rectangle.height() > srf->h) + drawy = _rectangle.top + (_rectangle.height() - srf->h) / 2; + + _engine->getRenderManager()->blitSurfaceToBkg(*srf, drawx, drawy, 0); + + delete srf; + + _renderedItem = curItem; + } + } + } + return false; +} + +bool SlotControl::eligeblity(int itemId) { + for (Common::List<int>::iterator it = _eligibleObjects.begin(); it != _eligibleObjects.end(); it++) + if (*it == itemId) + return true; + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/slot_control.h b/engines/zvision/scripting/controls/slot_control.h new file mode 100644 index 0000000000..86fd261f25 --- /dev/null +++ b/engines/zvision/scripting/controls/slot_control.h @@ -0,0 +1,85 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SLOT_CONTROL_H +#define ZVISION_SLOT_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/list.h" + + +namespace ZVision { + +class SlotControl : public Control { +public: + SlotControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~SlotControl(); + + /** + * Called when LeftMouse is lifted. Calls ScriptManager::setStateValue(_key, 1); + * + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + /** + * Called on every MouseMove. Tests if the mouse is inside _hotspot, and if so, sets the cursor. + * + * @param engine The base engine + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + * @return Was the cursor changed? + */ + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + + bool process(uint32 deltaTimeInMillis); + +private: + /** + * The area that will trigger the event + * This is in image space coordinates, NOT screen space + */ + Common::Rect _rectangle; + Common::Rect _hotspot; + + int _cursor; + char _distanceId; + + int _renderedItem; + + Common::List<int> _eligibleObjects; + + bool eligeblity(int itemId); + + Graphics::Surface *_bkg; + + /** The cursor to use when hovering over _hotspot */ + Common::String _hoverCursor; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/titler_control.cpp b/engines/zvision/scripting/controls/titler_control.cpp new file mode 100644 index 0000000000..b803501033 --- /dev/null +++ b/engines/zvision/scripting/controls/titler_control.cpp @@ -0,0 +1,108 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/titler_control.h" + +#include "zvision/zvision.h" +#include "zvision/text/text.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" + + +namespace ZVision { + +TitlerControl::TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_TITLER) { + + _surface = NULL; + _curString = -1; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("string_resource_file", true)) { + readStringsFile(values); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int x2; + int y2; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &x2, &y2); + + _rectangle = Common::Rect(x, y, x2, y2); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + if (!_rectangle.isEmpty()) { + _surface = new Graphics::Surface; + _surface->create(_rectangle.width(), _rectangle.height(), _engine->_pixelFormat); + _surface->fillRect(Common::Rect(_surface->w, _surface->h), 0); + } +} + +TitlerControl::~TitlerControl() { + if (_surface) + delete _surface; +} + +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->getRenderManager()->blitSurfaceToBkg(*_surface, _rectangle.left, _rectangle.top); + _curString = strLine; + } +} + +void TitlerControl::readStringsFile(const Common::String &fileName) { + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("String_resource_file %s could could be opened", fileName.c_str()); + return; + } + + _strings.clear(); + + while (!file.eos()) { + + Common::String line = readWideLine(file); + _strings.push_back(line); + } + file.close(); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/titler_control.h b/engines/zvision/scripting/controls/titler_control.h new file mode 100644 index 0000000000..ee230afa97 --- /dev/null +++ b/engines/zvision/scripting/controls/titler_control.h @@ -0,0 +1,55 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_TITLER_CONTROL_H +#define ZVISION_TITLER_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/array.h" + + +namespace ZVision { + +class TitlerControl : public Control { +public: + TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~TitlerControl(); + + void setString(int strLine); + +private: + + Common::Array< Common::String > _strings; + Common::Rect _rectangle; + int16 _curString; + Graphics::Surface *_surface; + + void readStringsFile(const Common::String &fileName); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/inventory.cpp b/engines/zvision/scripting/inventory.cpp new file mode 100644 index 0000000000..98d063395b --- /dev/null +++ b/engines/zvision/scripting/inventory.cpp @@ -0,0 +1,123 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "common/scummsys.h" + +#include "zvision/scripting/script_manager.h" + + +namespace ZVision { + +int8 ScriptManager::inventoryGetCount() { + return getStateValue(StateKey_Inv_Cnt_Slot); +} + +void ScriptManager::inventorySetCount(int8 cnt) { + setStateValue(StateKey_Inv_Cnt_Slot, cnt); +} + +int16 ScriptManager::inventoryGetItem(int8 id) { + if (id < 49 && id >= 0) + return getStateValue(StateKey_Inv_1_Slot + id); + return -1; +} + +void ScriptManager::inventorySetItem(int8 id, int16 item) { + if (id < 49 && id >= 0) + setStateValue(StateKey_Inv_1_Slot + id, item); +} + +void ScriptManager::inventoryAdd(int16 item) { + int8 cnt = inventoryGetCount(); + + if (cnt < 49) { + bool notExist = true; + + if (cnt == 0) { + inventorySetItem(0, 0); + inventorySetCount(1); // we needed empty item for cycle code + cnt = 1; + } + + for (int8 cur = 0; cur < cnt; cur++) + if (inventoryGetItem(cur) == item) { + notExist = false; + break; + } + + if (notExist) { + for (int8 i = cnt; i > 0; i--) + inventorySetItem(i, inventoryGetItem(i - 1)); + + inventorySetItem(0, item); + + setStateValue(StateKey_InventoryItem, item); + + inventorySetCount(cnt + 1); + } + } +} + +void ScriptManager::inventoryDrop(int16 item) { + int8 itemCount = inventoryGetCount(); + + // if items in inventory > 0 + if (itemCount != 0) { + int8 index = 0; + + // finding needed item + while (index < itemCount) { + if (inventoryGetItem(index) == item) + break; + + index++; + } + + // if item in the inventory + if (itemCount != index) { + // shift all items left with rewrite founded item + for (int8 v = index; v < itemCount - 1 ; v++) + inventorySetItem(v, inventoryGetItem(v + 1)); + + // del last item + inventorySetItem(itemCount - 1, 0); + inventorySetCount(inventoryGetCount() - 1); + + setStateValue(StateKey_InventoryItem, inventoryGetItem(0)); + } + } +} +void ScriptManager::inventoryCycle() { + int8 itemCount = inventoryGetCount(); + int8 curItem = inventoryGetItem(0); + if (itemCount > 1) { + for (int8 i = 0; i < itemCount - 1; i++) + inventorySetItem(i, inventoryGetItem(i + 1)); + + inventorySetItem(itemCount - 1, curItem); + + setStateValue(StateKey_InventoryItem, inventoryGetItem(0)); + + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/puzzle.h b/engines/zvision/scripting/puzzle.h index ee9ce521c9..ab38c5fc5d 100644 --- a/engines/zvision/scripting/puzzle.h +++ b/engines/zvision/scripting/puzzle.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -63,10 +63,17 @@ struct Puzzle { bool argumentIsAKey; }; + enum StateFlags { + ONCE_PER_INST = 0x01, + DISABLED = 0x02, + DO_ME_NOW = 0x04 + }; + uint32 key; Common::List<Common::List <CriteriaEntry> > criteriaList; // This has to be list of pointers because ResultAction is abstract Common::List<ResultAction *> resultActions; + bool addedBySetState; }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/scr_file_handling.cpp b/engines/zvision/scripting/scr_file_handling.cpp index 416bac00f3..697de58ed8 100644 --- a/engines/zvision/scripting/scr_file_handling.cpp +++ b/engines/zvision/scripting/scr_file_handling.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,6 +22,7 @@ #include "common/scummsys.h" +#include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" #include "zvision/utility/utility.h" @@ -29,6 +30,14 @@ #include "zvision/scripting/actions.h" #include "zvision/scripting/controls/push_toggle_control.h" #include "zvision/scripting/controls/lever_control.h" +#include "zvision/scripting/controls/slot_control.h" +#include "zvision/scripting/controls/save_control.h" +#include "zvision/scripting/controls/input_control.h" +#include "zvision/scripting/controls/safe_control.h" +#include "zvision/scripting/controls/hotmov_control.h" +#include "zvision/scripting/controls/fist_control.h" +#include "zvision/scripting/controls/paint_control.h" +#include "zvision/scripting/controls/titler_control.h" #include "common/textconsole.h" #include "common/file.h" @@ -37,14 +46,14 @@ namespace ZVision { -void ScriptManager::parseScrFile(const Common::String &fileName, bool isGlobal) { +void ScriptManager::parseScrFile(const Common::String &fileName, ScriptScope &scope) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("Script file not found: %s", fileName.c_str()); return; } - while(!file.eos()) { + while (!file.eos()) { Common::String line = file.readLine(); if (file.err()) { warning("Error parsing scr file: %s", fileName.c_str()); @@ -57,18 +66,19 @@ void ScriptManager::parseScrFile(const Common::String &fileName, bool isGlobal) if (line.matchString("puzzle:*", true)) { Puzzle *puzzle = new Puzzle(); - sscanf(line.c_str(),"puzzle:%u",&(puzzle->key)); - + sscanf(line.c_str(), "puzzle:%u", &(puzzle->key)); + if (getStateFlag(puzzle->key) & Puzzle::ONCE_PER_INST) + setStateValue(puzzle->key, 0); parsePuzzle(puzzle, file); - if (isGlobal) { - _globalPuzzles.push_back(puzzle); - } else { - _activePuzzles.push_back(puzzle); - } + scope.puzzles.push_back(puzzle); + } else if (line.matchString("control:*", true)) { - parseControl(line, file); + Control *ctrl = parseControl(line, file); + if (ctrl) + scope.controls.push_back(ctrl); } } + scope.procCount = 0; } void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stream) { @@ -81,12 +91,14 @@ void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stre } else if (line.matchString("results {", true)) { parseResults(stream, puzzle->resultActions); } else if (line.matchString("flags {", true)) { - setStateFlags(puzzle->key, parseFlags(stream)); + setStateFlag(puzzle->key, parseFlags(stream)); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); } + + puzzle->addedBySetState = 0; } bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const { @@ -148,103 +160,150 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + line.toLowercase(); // TODO: Re-order the if-then statements in order of highest occurrence while (!stream.eos() && !line.contains('}')) { if (line.empty()) { line = stream.readLine(); trimCommentsAndWhiteSpace(&line); - + line.toLowercase(); continue; } - // Parse for the action type - if (line.matchString("*:add*", true)) { - actionList.push_back(new ActionAdd(line)); - } else if (line.matchString("*:animplay*", true)) { - actionList.push_back(new ActionPlayAnimation(line)); - } else if (line.matchString("*:animpreload*", true)) { - actionList.push_back(new ActionPreloadAnimation(line)); - } else if (line.matchString("*:animunload*", true)) { - //actionList.push_back(new ActionUnloadAnimation(line)); - } else if (line.matchString("*:attenuate*", true)) { - // TODO: Implement ActionAttenuate - } else if (line.matchString("*:assign*", true)) { - actionList.push_back(new ActionAssign(line)); - } else if (line.matchString("*:change_location*", true)) { - actionList.push_back(new ActionChangeLocation(line)); - } else if (line.matchString("*:crossfade*", true)) { - // TODO: Implement ActionCrossfade - } else if (line.matchString("*:debug*", true)) { - // TODO: Implement ActionDebug - } else if (line.matchString("*:delay_render*", true)) { - // TODO: Implement ActionDelayRender - } else if (line.matchString("*:disable_control*", true)) { - actionList.push_back(new ActionDisableControl(line)); - } else if (line.matchString("*:disable_venus*", true)) { - // TODO: Implement ActionDisableVenus - } else if (line.matchString("*:display_message*", true)) { - // TODO: Implement ActionDisplayMessage - } else if (line.matchString("*:dissolve*", true)) { - // TODO: Implement ActionDissolve - } else if (line.matchString("*:distort*", true)) { - // TODO: Implement ActionDistort - } else if (line.matchString("*:enable_control*", true)) { - actionList.push_back(new ActionEnableControl(line)); - } else if (line.matchString("*:flush_mouse_events*", true)) { - // TODO: Implement ActionFlushMouseEvents - } else if (line.matchString("*:inventory*", true)) { - // TODO: Implement ActionInventory - } else if (line.matchString("*:kill*", true)) { - // TODO: Implement ActionKill - } else if (line.matchString("*:menu_bar_enable*", true)) { - // TODO: Implement ActionMenuBarEnable - } else if (line.matchString("*:music*", true)) { - actionList.push_back(new ActionMusic(line)); - } else if (line.matchString("*:pan_track*", true)) { - // TODO: Implement ActionPanTrack - } else if (line.matchString("*:playpreload*", true)) { - actionList.push_back(new ActionPlayPreloadAnimation(line)); - } else if (line.matchString("*:preferences*", true)) { - // TODO: Implement ActionPreferences - } else if (line.matchString("*:quit*", true)) { - actionList.push_back(new ActionQuit()); - } else if (line.matchString("*:random*", true)) { - actionList.push_back(new ActionRandom(line)); - } else if (line.matchString("*:region*", true)) { - // TODO: Implement ActionRegion - } else if (line.matchString("*:restore_game*", true)) { - // TODO: Implement ActionRestoreGame - } else if (line.matchString("*:rotate_to*", true)) { - // TODO: Implement ActionRotateTo - } else if (line.matchString("*:save_game*", true)) { - // TODO: Implement ActionSaveGame - } else if (line.matchString("*:set_partial_screen*", true)) { - actionList.push_back(new ActionSetPartialScreen(line)); - } else if (line.matchString("*:set_screen*", true)) { - actionList.push_back(new ActionSetScreen(line)); - } else if (line.matchString("*:set_venus*", true)) { - // TODO: Implement ActionSetVenus - } else if (line.matchString("*:stop*", true)) { - // TODO: Implement ActionStop - } else if (line.matchString("*:streamvideo*", true)) { - actionList.push_back(new ActionStreamVideo(line)); - } else if (line.matchString("*:syncsound*", true)) { - // TODO: Implement ActionSyncSound - } else if (line.matchString("*:timer*", true)) { - actionList.push_back(new ActionTimer(line)); - } else if (line.matchString("*:ttytext*", true)) { - // TODO: Implement ActionTTYText - } else if (line.matchString("*:universe_music*", true)) { - // TODO: Implement ActionUniverseMusic - } else if (line.matchString("*:copy_file*", true)) { - // Not used. Purposely left empty - } else { - warning("Unhandled result action type: %s", line.c_str()); + const char *chrs = line.c_str(); + uint pos; + for (pos = 0; pos < line.size(); pos++) + if (chrs[pos] == ':') + break; + + if (pos < line.size()) { + + uint startpos = pos + 1; + + for (pos = startpos; pos < line.size(); pos++) + if (chrs[pos] == ':' || chrs[pos] == '(') + break; + + if (pos < line.size()) { + int32 slot = 11; + Common::String args = ""; + Common::String act(chrs + startpos, chrs + pos); + + startpos = pos + 1; + + if (chrs[pos] == ':') { + for (pos = startpos; pos < line.size(); pos++) + if (chrs[pos] == '(') + break; + Common::String strSlot(chrs + startpos, chrs + pos); + slot = atoi(strSlot.c_str()); + + startpos = pos + 1; + } + + if (pos < line.size()) { + for (pos = startpos; pos < line.size(); pos++) + if (chrs[pos] == ')') + break; + + args = Common::String(chrs + startpos, chrs + pos); + } + + + + // Parse for the action type + if (act.matchString("add", true)) { + actionList.push_back(new ActionAdd(_engine, slot, args)); + } else if (act.matchString("animplay", true)) { + actionList.push_back(new ActionPlayAnimation(_engine, slot, args)); + } else if (act.matchString("animpreload", true)) { + actionList.push_back(new ActionPreloadAnimation(_engine, slot, args)); + } else if (act.matchString("animunload", true)) { + actionList.push_back(new ActionUnloadAnimation(_engine, slot, args)); + } else if (act.matchString("attenuate", true)) { + actionList.push_back(new ActionAttenuate(_engine, slot, args)); + } else if (act.matchString("assign", true)) { + actionList.push_back(new ActionAssign(_engine, slot, args)); + } else if (act.matchString("change_location", true)) { + actionList.push_back(new ActionChangeLocation(_engine, slot, args)); + } else if (act.matchString("crossfade", true)) { + actionList.push_back(new ActionCrossfade(_engine, slot, args)); + } else if (act.matchString("cursor", true)) { + actionList.push_back(new ActionCursor(_engine, slot, args)); + } else if (act.matchString("debug", true)) { + // Not used. Purposely left empty + } else if (act.matchString("delay_render", true)) { + actionList.push_back(new ActionDelayRender(_engine, slot, args)); + } else if (act.matchString("disable_control", true)) { + actionList.push_back(new ActionDisableControl(_engine, slot, args)); + } else if (act.matchString("disable_venus", true)) { + actionList.push_back(new ActionDisableVenus(_engine, slot, args)); + } else if (act.matchString("display_message", true)) { + actionList.push_back(new ActionDisplayMessage(_engine, slot, args)); + } else if (act.matchString("dissolve", true)) { + actionList.push_back(new ActionDissolve(_engine)); + } else if (act.matchString("distort", true)) { + actionList.push_back(new ActionDistort(_engine, slot, args)); + } else if (act.matchString("enable_control", true)) { + actionList.push_back(new ActionEnableControl(_engine, slot, args)); + } else if (act.matchString("flush_mouse_events", true)) { + actionList.push_back(new ActionFlushMouseEvents(_engine, slot)); + } else if (act.matchString("inventory", true)) { + actionList.push_back(new ActionInventory(_engine, slot, args)); + } else if (act.matchString("kill", true)) { + actionList.push_back(new ActionKill(_engine, slot, args)); + } else if (act.matchString("menu_bar_enable", true)) { + actionList.push_back(new ActionMenuBarEnable(_engine, slot, args)); + } else if (act.matchString("music", true)) { + actionList.push_back(new ActionMusic(_engine, slot, args, false)); + } else if (act.matchString("pan_track", true)) { + actionList.push_back(new ActionPanTrack(_engine, slot, args)); + } else if (act.matchString("playpreload", true)) { + actionList.push_back(new ActionPlayPreloadAnimation(_engine, slot, args)); + } else if (act.matchString("preferences", true)) { + actionList.push_back(new ActionPreferences(_engine, slot, args)); + } else if (act.matchString("quit", true)) { + actionList.push_back(new ActionQuit(_engine, slot)); + } else if (act.matchString("random", true)) { + actionList.push_back(new ActionRandom(_engine, slot, args)); + } else if (act.matchString("region", true)) { + actionList.push_back(new ActionRegion(_engine, slot, args)); + } else if (act.matchString("restore_game", true)) { + 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)) { + // Not used. Purposely left empty + } else if (act.matchString("set_partial_screen", true)) { + actionList.push_back(new ActionSetPartialScreen(_engine, slot, args)); + } else if (act.matchString("set_screen", true)) { + actionList.push_back(new ActionSetScreen(_engine, slot, args)); + } else if (act.matchString("set_venus", true)) { + actionList.push_back(new ActionSetVenus(_engine, slot, args)); + } else if (act.matchString("stop", true)) { + actionList.push_back(new ActionStop(_engine, slot, args)); + } else if (act.matchString("streamvideo", true)) { + actionList.push_back(new ActionStreamVideo(_engine, slot, args)); + } else if (act.matchString("syncsound", true)) { + actionList.push_back(new ActionSyncSound(_engine, slot, args)); + } else if (act.matchString("timer", true)) { + actionList.push_back(new ActionTimer(_engine, slot, args)); + } else if (act.matchString("ttytext", true)) { + actionList.push_back(new ActionTtyText(_engine, slot, args)); + } else if (act.matchString("universe_music", true)) { + actionList.push_back(new ActionMusic(_engine, slot, args, true)); + } else if (act.matchString("copy_file", true)) { + // Not used. Purposely left empty + } else { + warning("Unhandled result action type: %s", line.c_str()); + } + } } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + line.toLowercase(); } return; @@ -259,11 +318,11 @@ uint ScriptManager::parseFlags(Common::SeekableReadStream &stream) const { while (!stream.eos() && !line.contains('}')) { if (line.matchString("ONCE_PER_INST", true)) { - flags |= ONCE_PER_INST; + flags |= Puzzle::ONCE_PER_INST; } else if (line.matchString("DO_ME_NOW", true)) { - flags |= DO_ME_NOW; + flags |= Puzzle::DO_ME_NOW; } else if (line.matchString("DISABLED", true)) { - flags |= DISABLED; + flags |= Puzzle::DISABLED; } line = stream.readLine(); @@ -273,7 +332,7 @@ uint ScriptManager::parseFlags(Common::SeekableReadStream &stream) const { return flags; } -void ScriptManager::parseControl(Common::String &line, Common::SeekableReadStream &stream) { +Control *ScriptManager::parseControl(Common::String &line, Common::SeekableReadStream &stream) { uint32 key; char controlTypeBuffer[20]; @@ -282,21 +341,36 @@ void ScriptManager::parseControl(Common::String &line, Common::SeekableReadStrea Common::String controlType(controlTypeBuffer); if (controlType.equalsIgnoreCase("push_toggle")) { - _activeControls.push_back(new PushToggleControl(_engine, key, stream)); - return; + return new PushToggleControl(_engine, key, stream); } else if (controlType.equalsIgnoreCase("flat")) { Control::parseFlatControl(_engine); - return; + return NULL; } else if (controlType.equalsIgnoreCase("pana")) { Control::parsePanoramaControl(_engine, stream); - return; + return NULL; } else if (controlType.equalsIgnoreCase("tilt")) { Control::parseTiltControl(_engine, stream); - return; + return NULL; } else if (controlType.equalsIgnoreCase("lever")) { - _activeControls.push_back(new LeverControl(_engine, key, stream)); - return; + return new LeverControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("slot")) { + return new SlotControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("input")) { + return new InputControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("save")) { + return new SaveControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("safe")) { + return new SafeControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("hotmovie")) { + return new HotMovControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("fist")) { + return new FistControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("paint")) { + return new PaintControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("titler")) { + return new TitlerControl(_engine, key, stream); } + return NULL; } } // End of namespace ZVision diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp index da82308051..2a54cc4314 100644 --- a/engines/zvision/scripting/script_manager.cpp +++ b/engines/zvision/scripting/script_manager.cpp @@ -1,24 +1,24 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" @@ -30,6 +30,7 @@ #include "zvision/core/save_manager.h" #include "zvision/scripting/actions.h" #include "zvision/utility/utility.h" +#include "zvision/scripting/sidefx/timer_node.h" #include "common/algorithm.h" #include "common/hashmap.h" @@ -41,157 +42,221 @@ namespace ZVision { ScriptManager::ScriptManager(ZVision *engine) : _engine(engine), - _currentlyFocusedControl(0) { + _currentlyFocusedControl(0), + _activeControls(NULL) { } ScriptManager::~ScriptManager() { - for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) { - delete (*iter); - } - for (PuzzleList::iterator iter = _globalPuzzles.begin(); iter != _globalPuzzles.end(); ++iter) { - delete (*iter); - } - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - delete (*iter); - } + cleanScriptScope(universe); + cleanScriptScope(world); + cleanScriptScope(room); + cleanScriptScope(nodeview); + _controlEvents.clear(); } void ScriptManager::initialize() { - parseScrFile("universe.scr", true); + cleanScriptScope(universe); + cleanScriptScope(world); + cleanScriptScope(room); + cleanScriptScope(nodeview); + + _currentLocation.node = 0; + _currentLocation.world = 0; + _currentLocation.room = 0; + _currentLocation.view = 0; + + parseScrFile("universe.scr", universe); changeLocation('g', 'a', 'r', 'y', 0); + + _controlEvents.clear(); } void ScriptManager::update(uint deltaTimeMillis) { + if (_currentLocation.node != _nextLocation.node || + _currentLocation.room != _nextLocation.room || + _currentLocation.view != _nextLocation.view || + _currentLocation.world != _nextLocation.world) + ChangeLocationReal(); + updateNodes(deltaTimeMillis); - checkPuzzleCriteria(); + if (! execScope(nodeview)) + return; + if (! execScope(room)) + return; + if (! execScope(world)) + return; + if (! execScope(universe)) + return; + updateControls(deltaTimeMillis); } -void ScriptManager::createReferenceTable() { - // Iterate through each local Puzzle - for (PuzzleList::iterator activePuzzleIter = _activePuzzles.begin(); activePuzzleIter != _activePuzzles.end(); ++activePuzzleIter) { - Puzzle *puzzlePtr = (*activePuzzleIter); - - // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*activePuzzleIter)->criteriaList.begin(); criteriaIter != (*activePuzzleIter)->criteriaList.end(); ++criteriaIter) { - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { - _referenceTable[entryIter->key].push_back(puzzlePtr); - - // If the argument is a key, add a reference to it as well - if (entryIter->argumentIsAKey) { - _referenceTable[entryIter->argument].push_back(puzzlePtr); - } - } - } +bool ScriptManager::execScope(ScriptScope &scope) { + // Swap queues + PuzzleList *tmp = scope.execQueue; + scope.execQueue = scope.scopeQueue; + scope.scopeQueue = tmp; + scope.scopeQueue->clear(); + + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) + (*PuzzleIter)->addedBySetState = 0; + + if (scope.procCount < 2 || getStateValue(StateKey_ExecScopeStyle)) { + 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)) + return false; } - // Iterate through each global Puzzle - for (PuzzleList::iterator globalPuzzleIter = _globalPuzzles.begin(); globalPuzzleIter != _globalPuzzles.end(); ++globalPuzzleIter) { - Puzzle *puzzlePtr = (*globalPuzzleIter); + if (scope.procCount < 2) { + scope.procCount++; + } + return true; +} - // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*globalPuzzleIter)->criteriaList.begin(); criteriaIter != (*globalPuzzleIter)->criteriaList.end(); ++criteriaIter) { - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { - _referenceTable[entryIter->key].push_back(puzzlePtr); - - // If the argument is a key, add a reference to it as well - if (entryIter->argumentIsAKey) { - _referenceTable[entryIter->argument].push_back(puzzlePtr); - } - } - } +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) + return; } - // Remove duplicate entries - for (PuzzleMap::iterator referenceTableIter = _referenceTable.begin(); referenceTableIter != _referenceTable.end(); ++referenceTableIter) { - removeDuplicateEntries(referenceTableIter->_value); + _referenceTable[key].push_back(ref); +} + +void ScriptManager::addPuzzlesToReferenceTable(ScriptScope &scope) { + // Iterate through each local Puzzle + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) { + Puzzle *puzzlePtr = (*PuzzleIter); + + PuzzleRef ref; + ref.scope = &scope; + ref.puz = puzzlePtr; + + 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) + referenceTableAddPuzzle(entryIter->key, ref); } } void ScriptManager::updateNodes(uint deltaTimeMillis) { // If process() returns true, it means the node can be deleted - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end();) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) { if ((*iter)->process(deltaTimeMillis)) { - delete (*iter); + delete(*iter); // Remove the node - iter = _activeControls.erase(iter); + iter = _activeSideFx.erase(iter); } else { ++iter; } } } -void ScriptManager::checkPuzzleCriteria() { - while (!_puzzlesToCheck.empty()) { - Puzzle *puzzle = _puzzlesToCheck.pop(); - - // Check if the puzzle is already finished - // Also check that the puzzle isn't disabled - if (getStateValue(puzzle->key) == 1 && (getStateFlags(puzzle->key) & DISABLED) == 0) { - continue; +void ScriptManager::updateControls(uint deltaTimeMillis) { + if (!_activeControls) + return; + + // Process only one event + if (!_controlEvents.empty()) { + Common::Event _event = _controlEvents.front(); + Common::Point imageCoord; + switch (_event.type) { + case Common::EVENT_LBUTTONDOWN: + imageCoord = _engine->getRenderManager()->screenSpaceToImageSpace(_event.mouse); + onMouseDown(_event.mouse, imageCoord); + break; + case Common::EVENT_LBUTTONUP: + imageCoord = _engine->getRenderManager()->screenSpaceToImageSpace(_event.mouse); + onMouseUp(_event.mouse, imageCoord); + break; + case Common::EVENT_KEYDOWN: + onKeyDown(_event.kbd); + break; + case Common::EVENT_KEYUP: + onKeyUp(_event.kbd); + break; + default: + break; } + _controlEvents.pop_front(); + } + + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++) + if ((*iter)->process(deltaTimeMillis)) + break; +} - // Check each Criteria - - bool criteriaMet = false; - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) { - criteriaMet = false; - - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { - // Get the value to compare against - uint argumentValue; - if (entryIter->argumentIsAKey) - argumentValue = getStateValue(entryIter->argument); - else - argumentValue = entryIter->argument; - - // Do the comparison - switch (entryIter->criteriaOperator) { - case Puzzle::EQUAL_TO: - criteriaMet = getStateValue(entryIter->key) == argumentValue; - break; - case Puzzle::NOT_EQUAL_TO: - criteriaMet = getStateValue(entryIter->key) != argumentValue; - break; - case Puzzle::GREATER_THAN: - criteriaMet = getStateValue(entryIter->key) > argumentValue; - break; - case Puzzle::LESS_THAN: - criteriaMet = getStateValue(entryIter->key) < argumentValue; - break; - } - - // If one check returns false, don't keep checking - if (!criteriaMet) { - 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) { + return true; + } + + // Check each Criteria + 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) { + criteriaMet = false; + + for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { + // Get the value to compare against + int argumentValue; + if (entryIter->argumentIsAKey) + argumentValue = getStateValue(entryIter->argument); + else + argumentValue = entryIter->argument; + + // Do the comparison + switch (entryIter->criteriaOperator) { + case Puzzle::EQUAL_TO: + criteriaMet = getStateValue(entryIter->key) == argumentValue; + break; + case Puzzle::NOT_EQUAL_TO: + criteriaMet = getStateValue(entryIter->key) != argumentValue; + break; + case Puzzle::GREATER_THAN: + criteriaMet = getStateValue(entryIter->key) > argumentValue; + break; + case Puzzle::LESS_THAN: + criteriaMet = getStateValue(entryIter->key) < argumentValue; + break; } - // If any of the Criteria are *fully* met, then execute the results - if (criteriaMet) { + // If one check returns false, don't keep checking + if (!criteriaMet) { break; } } - // criteriaList can be empty. Aka, the puzzle should be executed immediately - if (puzzle->criteriaList.empty() || criteriaMet) { - debug(1, "Puzzle %u criteria passed. Executing its ResultActions", puzzle->key); + // If any of the Criteria are *fully* met, then execute the results + if (criteriaMet) { + break; + } + } - // Set the puzzle as completed - setStateValue(puzzle->key, 1); + // criteriaList can be empty. Aka, the puzzle should be executed immediately + if (puzzle->criteriaList.empty() || criteriaMet) { + debug(1, "Puzzle %u criteria passed. Executing its ResultActions", puzzle->key); - bool shouldContinue = true; - for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) { - shouldContinue = shouldContinue && (*resultIter)->execute(_engine); - if (!shouldContinue) { - break; - } - } + // Set the puzzle as completed + setStateValue(puzzle->key, 1); - if (!shouldContinue) { - break; - } + for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) { + if (!(*resultIter)->execute()) + return false; } } + + return true; } void ScriptManager::cleanStateTable() { @@ -205,60 +270,102 @@ void ScriptManager::cleanStateTable() { } } -uint ScriptManager::getStateValue(uint32 key) { +void ScriptManager::cleanScriptScope(ScriptScope &scope) { + scope.privQueueOne.clear(); + scope.privQueueTwo.clear(); + scope.scopeQueue = &scope.privQueueOne; + scope.execQueue = &scope.privQueueTwo; + 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) + delete(*iter); + + scope.controls.clear(); + + scope.procCount = 0; +} + +int ScriptManager::getStateValue(uint32 key) { if (_globalState.contains(key)) return _globalState[key]; else return 0; } -void ScriptManager::setStateValue(uint32 key, uint value) { - _globalState[key] = value; - +void ScriptManager::queuePuzzles(uint32 key) { if (_referenceTable.contains(key)) { - for (Common::Array<Puzzle *>::iterator iter = _referenceTable[key].begin(); iter != _referenceTable[key].end(); ++iter) { - _puzzlesToCheck.push((*iter)); - } + Common::Array<PuzzleRef> *arr = &_referenceTable[key]; + 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; + } } } -uint ScriptManager::getStateFlags(uint32 key) { +void ScriptManager::setStateValue(uint32 key, int value) { + if (value == 0) + _globalState.erase(key); + else + _globalState[key] = value; + + queuePuzzles(key); +} + +void ScriptManager::setStateValueSilent(uint32 key, int value) { + if (value == 0) + _globalState.erase(key); + else + _globalState[key] = value; +} + +uint ScriptManager::getStateFlag(uint32 key) { if (_globalStateFlags.contains(key)) return _globalStateFlags[key]; else return 0; } -void ScriptManager::setStateFlags(uint32 key, uint flags) { - _globalStateFlags[key] = flags; +void ScriptManager::setStateFlag(uint32 key, uint value) { + queuePuzzles(key); - if (_referenceTable.contains(key)) { - for (Common::Array<Puzzle *>::iterator iter = _referenceTable[key].begin(); iter != _referenceTable[key].end(); ++iter) { - _puzzlesToCheck.push((*iter)); - } - } + _globalStateFlags[key] |= value; } -void ScriptManager::addToStateValue(uint32 key, uint valueToAdd) { - _globalState[key] += valueToAdd; +void ScriptManager::setStateFlagSilent(uint32 key, uint value) { + if (value == 0) + _globalStateFlags.erase(key); + else + _globalStateFlags[key] = value; } -void ScriptManager::addControl(Control *control) { - _activeControls.push_back(control); -} +void ScriptManager::unsetStateFlag(uint32 key, uint value) { + queuePuzzles(key); -Control *ScriptManager::getControl(uint32 key) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - if ((*iter)->getKey() == key) { - return (*iter); - } + if (_globalStateFlags.contains(key)) { + _globalStateFlags[key] &= ~value; + + 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) + return *iter; return nullptr; } void ScriptManager::focusControl(uint32 key) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { + if (!_activeControls) + return; + if (_currentlyFocusedControl == key) + return; + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { uint32 controlKey = (*iter)->getKey(); if (controlKey == key) { @@ -271,167 +378,372 @@ void ScriptManager::focusControl(uint32 key) { _currentlyFocusedControl = key; } +void ScriptManager::setFocusControlKey(uint32 key) { + _currentlyFocusedControl = key; +} + +void ScriptManager::addSideFX(SideFX *fx) { + _activeSideFx.push_back(fx); +} + +SideFX *ScriptManager::getSideFX(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + return (*iter); + } + } + + return nullptr; +} + +void ScriptManager::deleteSideFx(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + delete(*iter); + _activeSideFx.erase(iter); + break; + } + } +} + +void ScriptManager::stopSideFx(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + bool ret = (*iter)->stop(); + if (ret) { + delete(*iter); + _activeSideFx.erase(iter); + } + break; + } + } +} + +void ScriptManager::killSideFx(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + (*iter)->kill(); + delete(*iter); + _activeSideFx.erase(iter); + break; + } + } +} + +void ScriptManager::killSideFxType(SideFX::SideFXType type) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) { + if ((*iter)->getType() & type) { + (*iter)->kill(); + delete(*iter); + iter = _activeSideFx.erase(iter); + } else { + ++iter; + } + } +} + void ScriptManager::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { + if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos)) + return; } } void ScriptManager::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { + if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos)) + return; } } bool ScriptManager::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - bool cursorWasChanged = false; - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - cursorWasChanged = cursorWasChanged || (*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos); + if (!_activeControls) + return false; + + for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { + if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos)) + return true; } - return cursorWasChanged; + return false; } void ScriptManager::onKeyDown(Common::KeyState keyState) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onKeyDown(keyState); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { + if ((*iter)->onKeyDown(keyState)) + return; } } void ScriptManager::onKeyUp(Common::KeyState keyState) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onKeyUp(keyState); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { + if ((*iter)->onKeyUp(keyState)) + return; } } -void ScriptManager::changeLocation(char world, char room, char node, char view, uint32 offset) { - assert(world != 0); - debug(1, "Changing location to: %c %c %c %c %u", world, room, node, view, offset); +void ScriptManager::changeLocation(const Location &_newLocation) { + changeLocation(_newLocation.world, _newLocation.room, _newLocation.node, _newLocation.view, _newLocation.offset); +} - // Auto save - _engine->getSaveManager()->autoSave(); +void ScriptManager::changeLocation(char _world, char _room, char _node, char _view, uint32 offset) { + _nextLocation.world = _world; + _nextLocation.room = _room; + _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 (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') { + _nextLocation.world = getStateValue(StateKey_LastWorld); + _nextLocation.room = getStateValue(StateKey_LastRoom); + _nextLocation.node = getStateValue(StateKey_LastNode); + _nextLocation.view = getStateValue(StateKey_LastView); + _nextLocation.offset = getStateValue(StateKey_LastViewPos); + } else { + _nextLocation.world = getStateValue(StateKey_Menu_LastWorld); + _nextLocation.room = getStateValue(StateKey_Menu_LastRoom); + _nextLocation.node = getStateValue(StateKey_Menu_LastNode); + _nextLocation.view = getStateValue(StateKey_Menu_LastView); + _nextLocation.offset = getStateValue(StateKey_Menu_LastViewPos); + } + } +} - // Clear all the containers - _referenceTable.clear(); - _puzzlesToCheck.clear(); - for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) { - delete (*iter); +void ScriptManager::ChangeLocationReal() { + assert(_nextLocation.world != 0); + debug(1, "Changing location to: %c %c %c %c %u", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view, _nextLocation.offset); + + _engine->setRenderDelay(2); + + if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') { + if (_nextLocation.world != 'g' || _nextLocation.room != 'j') { + setStateValue(StateKey_LastWorld, getStateValue(StateKey_World)); + setStateValue(StateKey_LastRoom, getStateValue(StateKey_Room)); + setStateValue(StateKey_LastNode, getStateValue(StateKey_Node)); + setStateValue(StateKey_LastView, getStateValue(StateKey_View)); + setStateValue(StateKey_LastViewPos, getStateValue(StateKey_ViewPos)); + } else { + setStateValue(StateKey_Menu_LastWorld, getStateValue(StateKey_World)); + setStateValue(StateKey_Menu_LastRoom, getStateValue(StateKey_Room)); + setStateValue(StateKey_Menu_LastNode, getStateValue(StateKey_Node)); + setStateValue(StateKey_Menu_LastView, getStateValue(StateKey_View)); + setStateValue(StateKey_Menu_LastViewPos, getStateValue(StateKey_ViewPos)); + } } - _activePuzzles.clear(); - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - delete (*iter); + + if (_nextLocation.world == 'g' && _nextLocation.room == 'j') { + if (_nextLocation.node == 's' && _nextLocation.view == 'e' && + _currentLocation.world != 'g' && _currentLocation.room != 'j') + _engine->getSaveManager()->prepareSaveBuffer(); + } else { + if (_currentLocation.world == 'g' && _currentLocation.room == 'j') + _engine->getSaveManager()->flushSaveBuffer(); + else { + // Auto save + //_engine->getSaveManager()->autoSave(); + } } - _activeControls.clear(); - // Revert to the idle cursor - _engine->getCursorManager()->revertToIdle(); + setStateValue(StateKey_World, _nextLocation.world); + setStateValue(StateKey_Room, _nextLocation.room); + setStateValue(StateKey_Node, _nextLocation.node); + setStateValue(StateKey_View, _nextLocation.view); + setStateValue(StateKey_ViewPos, _nextLocation.offset); - // Reset the background velocity - _engine->getRenderManager()->setBackgroundVelocity(0); + _referenceTable.clear(); + addPuzzlesToReferenceTable(universe); - // Remove any alphaEntries - _engine->getRenderManager()->clearAlphaEntries(); + _engine->menuBarEnable(0xFFFF); - // Clean the global state table - cleanStateTable(); + if (_nextLocation.world != _currentLocation.world) { + cleanScriptScope(nodeview); + cleanScriptScope(room); + cleanScriptScope(world); - // Parse into puzzles and controls - Common::String fileName = Common::String::format("%c%c%c%c.scr", world, room, node, view); - parseScrFile(fileName); + Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view); + parseScrFile(fileName, nodeview); + addPuzzlesToReferenceTable(nodeview); - // Change the background position - _engine->getRenderManager()->setBackgroundPosition(offset); + fileName = Common::String::format("%c%c.scr", _nextLocation.world, _nextLocation.room); + parseScrFile(fileName, room); + addPuzzlesToReferenceTable(room); - // Enable all the controls - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->enable(); - } + fileName = Common::String::format("%c.scr", _nextLocation.world); + parseScrFile(fileName, world); + addPuzzlesToReferenceTable(world); + } else if (_nextLocation.room != _currentLocation.room) { + cleanScriptScope(nodeview); + cleanScriptScope(room); - // Add all the local puzzles to the queue to be checked - for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) { - // Reset any Puzzles that have the flag ONCE_PER_INST - if ((getStateFlags((*iter)->key) & ONCE_PER_INST) == ONCE_PER_INST) { - setStateValue((*iter)->key, 0); - } + addPuzzlesToReferenceTable(world); - _puzzlesToCheck.push((*iter)); - } + Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view); + parseScrFile(fileName, nodeview); + addPuzzlesToReferenceTable(nodeview); - // Add all the global puzzles to the queue to be checked - for (PuzzleList::iterator iter = _globalPuzzles.begin(); iter != _globalPuzzles.end(); ++iter) { - // Reset any Puzzles that have the flag ONCE_PER_INST - if ((getStateFlags((*iter)->key) & ONCE_PER_INST) == ONCE_PER_INST) { - setStateValue((*iter)->key, 0); - } + fileName = Common::String::format("%c%c.scr", _nextLocation.world, _nextLocation.room); + parseScrFile(fileName, room); + addPuzzlesToReferenceTable(room); + + } else if (_nextLocation.node != _currentLocation.node || _nextLocation.view != _currentLocation.view) { + cleanScriptScope(nodeview); - _puzzlesToCheck.push((*iter)); + addPuzzlesToReferenceTable(room); + addPuzzlesToReferenceTable(world); + + Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view); + parseScrFile(fileName, nodeview); + addPuzzlesToReferenceTable(nodeview); } - // Create the puzzle reference table - createReferenceTable(); + _activeControls = &nodeview.controls; + + // Revert to the idle cursor + _engine->getCursorManager()->changeCursor(CursorIndex_Idle); - // Update _currentLocation - _currentLocation.world = world; - _currentLocation.room = room; - _currentLocation.node = node; - _currentLocation.view = view; - _currentLocation.offset = offset; + // Change the background position + _engine->getRenderManager()->setBackgroundPosition(_nextLocation.offset); + + if (_currentLocation.world == 0 && _currentLocation.room == 0 && _currentLocation.node == 0 && _currentLocation.view == 0) { + _currentLocation = _nextLocation; + execScope(world); + execScope(room); + execScope(nodeview); + } else if (_nextLocation.world != _currentLocation.world) { + _currentLocation = _nextLocation; + execScope(room); + execScope(nodeview); + } else if (_nextLocation.room != _currentLocation.room) { + _currentLocation = _nextLocation; + execScope(room); + execScope(nodeview); + } else if (_nextLocation.node != _currentLocation.node || _nextLocation.view != _currentLocation.view) { + _currentLocation = _nextLocation; + execScope(nodeview); + } + + _engine->checkBorders(); } -void ScriptManager::serializeStateTable(Common::WriteStream *stream) { - // Write the number of state value entries - stream->writeUint32LE(_globalState.size()); +void ScriptManager::serialize(Common::WriteStream *stream) { + stream->writeUint32BE(MKTAG('Z', 'N', 'S', 'G')); + stream->writeUint32LE(4); + stream->writeUint32LE(0); + stream->writeUint32BE(MKTAG('L', 'O', 'C', ' ')); + stream->writeUint32LE(8); + stream->writeByte(getStateValue(StateKey_World)); + stream->writeByte(getStateValue(StateKey_Room)); + stream->writeByte(getStateValue(StateKey_Node)); + stream->writeByte(getStateValue(StateKey_View)); + stream->writeUint32LE(getStateValue(StateKey_ViewPos)); + + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) + (*iter)->serialize(stream); - for (StateMap::iterator iter = _globalState.begin(); iter != _globalState.end(); ++iter) { - // Write out the key/value pair - stream->writeUint32LE(iter->_key); - stream->writeUint32LE(iter->_value); - } + stream->writeUint32BE(MKTAG('F', 'L', 'A', 'G')); + + int32 slots = 20000; + if (_engine->getGameId() == GID_NEMESIS) + slots = 30000; + + stream->writeUint32LE(slots * 2); + + 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++) + stream->writeSint16LE(getStateValue(i)); } -void ScriptManager::deserializeStateTable(Common::SeekableReadStream *stream) { +void ScriptManager::deserialize(Common::SeekableReadStream *stream) { // Clear out the current table values _globalState.clear(); + _globalStateFlags.clear(); - // Read the number of key/value pairs - uint32 numberOfPairs = stream->readUint32LE(); + cleanScriptScope(nodeview); + cleanScriptScope(room); + cleanScriptScope(world); - for (uint32 i = 0; i < numberOfPairs; ++i) { - uint32 key = stream->readUint32LE(); - uint32 value = stream->readUint32LE(); - // Directly access the state table so we don't trigger Puzzle checks - _globalState[key] = value; - } -} + _currentLocation.node = 0; + _currentLocation.world = 0; + _currentLocation.room = 0; + _currentLocation.view = 0; -void ScriptManager::serializeControls(Common::WriteStream *stream) { - // Count how many controls need to save their data - // Because WriteStream isn't seekable - uint32 numberOfControlsNeedingSerialization = 0; - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - if ((*iter)->needsSerialization()) { - numberOfControlsNeedingSerialization++; - } - } - stream->writeUint32LE(numberOfControlsNeedingSerialization); + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++) + delete(*iter); - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->serialize(stream); + _activeSideFx.clear(); + + _referenceTable.clear(); + + if (stream->readUint32BE() != MKTAG('Z', 'N', 'S', 'G') || stream->readUint32LE() != 4) { + changeLocation('g', 'a', 'r', 'y', 0); + return; } -} -void ScriptManager::deserializeControls(Common::SeekableReadStream *stream) { - uint32 numberOfControls = stream->readUint32LE(); + stream->seek(4, SEEK_CUR); - for (uint32 i = 0; i < numberOfControls; ++i) { - uint32 key = stream->readUint32LE(); - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - if ((*iter)->getKey() == key) { - (*iter)->deserialize(stream); - break; - } + if (stream->readUint32BE() != MKTAG('L', 'O', 'C', ' ') || stream->readUint32LE() != 8) { + changeLocation('g', 'a', 'r', 'y', 0); + return; + } + + Location nextLocation; + + nextLocation.world = stream->readByte(); + nextLocation.room = stream->readByte(); + nextLocation.node = stream->readByte(); + nextLocation.view = stream->readByte(); + nextLocation.offset = stream->readUint32LE() & 0x0000FFFF; + + while (stream->pos() < stream->size()) { + uint32 tag = stream->readUint32BE(); + uint32 tagSize = stream->readUint32LE(); + switch (tag) { + case MKTAG('T', 'I', 'M', 'R'): { + uint32 key = stream->readUint32LE(); + uint32 time = stream->readUint32LE(); + if (_engine->getGameId() == GID_GRANDINQUISITOR) + time /= 100; + 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++) + setStateFlagSilent(i, stream->readUint16LE()); + break; + case MKTAG('P', 'U', 'Z', 'Z'): + for (uint32 i = 0; i < tagSize / 2; i++) + setStateValueSilent(i, stream->readUint16LE()); + break; + default: + stream->seek(tagSize, SEEK_CUR); } } + + _nextLocation = nextLocation; + + ChangeLocationReal(); + + _engine->setRenderDelay(10); + setStateValue(StateKey_RestoreFlag, 1); + + _engine->loadSettings(); } Location ScriptManager::getCurrentLocation() const { @@ -441,4 +753,64 @@ Location ScriptManager::getCurrentLocation() const { return location; } +Location ScriptManager::getLastLocation() { + Location location; + location.world = getStateValue(StateKey_LastWorld); + location.room = getStateValue(StateKey_LastRoom); + location.node = getStateValue(StateKey_LastNode); + location.view = getStateValue(StateKey_LastView); + location.offset = getStateValue(StateKey_LastViewPos); + + return location; +} + +Location ScriptManager::getLastMenuLocation() { + Location location; + location.world = getStateValue(StateKey_Menu_LastWorld); + location.room = getStateValue(StateKey_Menu_LastRoom); + location.node = getStateValue(StateKey_Menu_LastNode); + location.view = getStateValue(StateKey_Menu_LastView); + location.offset = getStateValue(StateKey_Menu_LastViewPos); + + return location; +} + +void ScriptManager::addEvent(Common::Event event) { + _controlEvents.push_back(event); +} + +void ScriptManager::flushEvent(Common::EventType type) { + EventList::iterator it = _controlEvents.begin(); + while (it != _controlEvents.end()) { + + if ((*it).type == type) + it = _controlEvents.erase(it); + else + it++; + } +} + +ValueSlot::ValueSlot(ScriptManager *scriptManager, const char *slotValue): + _scriptManager(scriptManager) { + value = 0; + slot = false; + const char *isSlot = strstr(slotValue, "["); + if (isSlot) { + slot = true; + value = atoi(isSlot + 1); + } else { + slot = false; + value = atoi(slotValue); + } +} +int16 ValueSlot::getValue() { + if (slot) { + if (value >= 0) + return _scriptManager->getStateValue(value); + else + return 0; + } else + return value; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/script_manager.h b/engines/zvision/scripting/script_manager.h index 4d1b1f359b..5701cde6d0 100644 --- a/engines/zvision/scripting/script_manager.h +++ b/engines/zvision/scripting/script_manager.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -25,9 +25,11 @@ #include "zvision/scripting/puzzle.h" #include "zvision/scripting/control.h" +#include "zvision/scripting/sidefx.h" #include "common/hashmap.h" #include "common/queue.h" +#include "common/events.h" namespace Common { @@ -39,6 +41,63 @@ namespace ZVision { class ZVision; +enum StateKey { + StateKey_World = 3, + StateKey_Room = 4, + StateKey_Node = 5, + StateKey_View = 6, + StateKey_ViewPos = 7, + StateKey_KeyPress = 8, + StateKey_InventoryItem = 9, + StateKey_LMouse = 10, + StateKey_NotSet = 11, // This key doesn't set + StateKey_Rounds = 12, + StateKey_Venus = 13, + StateKey_RMouse = 18, + StateKey_MenuState = 19, + StateKey_RestoreFlag = 20, + StateKey_Quitting = 39, + StateKey_LastWorld = 40, + StateKey_LastRoom = 41, + StateKey_LastNode = 42, + StateKey_LastView = 43, + StateKey_LastViewPos = 44, + StateKey_Menu_LastWorld = 45, + StateKey_Menu_LastRoom = 46, + StateKey_Menu_LastNode = 47, + StateKey_Menu_LastView = 48, + StateKey_Menu_LastViewPos = 49, + StateKey_KbdRotateSpeed = 50, + StateKey_Subtitles = 51, + StateKey_StreamSkipKey = 52, + StateKey_RotateSpeed = 53, + StateKey_Volume = 56, + StateKey_Qsound = 57, + StateKey_VenusEnable = 58, + StateKey_HighQuality = 59, + StateKey_VideoLineSkip = 65, + StateKey_Platform = 66, + StateKey_InstallLevel = 67, + StateKey_CountryCode = 68, + StateKey_CPU = 69, + StateKey_MovieCursor = 70, + StateKey_NoTurnAnim = 71, + StateKey_WIN958 = 72, + StateKey_ShowErrorDlg = 73, + StateKey_DebugCheats = 74, + StateKey_JapanFonts = 75, + StateKey_ExecScopeStyle = 76, + StateKey_Brightness = 77, + StateKey_EF9_R = 91, + StateKey_EF9_G = 92, + StateKey_EF9_B = 93, + StateKey_EF9_Speed = 94, + StateKey_Inv_Cnt_Slot = 100, + StateKey_Inv_1_Slot = 101, + StateKey_Inv_49_Slot = 149, + StateKey_Inv_TotalSlots = 150 +}; + struct Location { Location() : world('g'), room('a'), node('r'), view('y'), offset(0) {} @@ -49,68 +108,99 @@ struct Location { uint32 offset; }; -typedef Common::HashMap<uint32, Common::Array<Puzzle *> > PuzzleMap; typedef Common::List<Puzzle *> PuzzleList; typedef Common::Queue<Puzzle *> PuzzleQueue; typedef Common::List<Control *> ControlList; -typedef Common::HashMap<uint32, uint32> StateMap; -typedef Common::HashMap<uint32, uint> StateFlagMap; +typedef Common::HashMap<uint32, int32> StateMap; +typedef Common::List<SideFX *> SideFXList; +typedef Common::List<Common::Event> EventList; class ScriptManager { public: ScriptManager(ZVision *engine); ~ScriptManager(); -public: - enum StateFlags { - ONCE_PER_INST = 0x01, - DO_ME_NOW = 0x02, // Somewhat useless flag since anything that needs to be done immediately has no criteria - DISABLED = 0x04 - }; - private: ZVision *_engine; + + struct ScriptScope { + uint32 procCount; + + PuzzleList *scopeQueue; // For adding puzzles to queue + PuzzleList *execQueue; // Switch to it when execute + PuzzleList privQueueOne; + PuzzleList privQueueTwo; + + PuzzleList puzzles; + ControlList controls; + }; + + struct PuzzleRef { + Puzzle *puz; + ScriptScope *scope; + }; + + typedef Common::HashMap<uint32, Common::Array<PuzzleRef> > PuzzleMap; + /** * Holds the global state variable. Do NOT directly modify this. Use the accessors and * mutators getStateValue() and setStateValue(). This ensures that Puzzles that reference a * particular state key are checked after the key is modified. */ StateMap _globalState; - /** - * Holds the flags for the global states. This is used to enable/disable puzzles and/or - * controls as well as which puzzles should are allowed to be re-executed - */ - StateFlagMap _globalStateFlags; + /** Holds execute flags */ + StateMap _globalStateFlags; /** References _globalState keys to Puzzles */ PuzzleMap _referenceTable; - /** Holds the Puzzles that should be checked this frame */ - PuzzleQueue _puzzlesToCheck; - /** Holds the currently active puzzles */ - PuzzleList _activePuzzles; - /** Holds the global puzzles */ - PuzzleList _globalPuzzles; /** Holds the currently active controls */ - ControlList _activeControls; + ControlList *_activeControls; + + EventList _controlEvents; + + ScriptScope universe; + ScriptScope world; + ScriptScope room; + ScriptScope nodeview; + + /** Holds the currently active timers, musics, other */ + SideFXList _activeSideFx; Location _currentLocation; + Location _nextLocation; uint32 _currentlyFocusedControl; public: void initialize(); void update(uint deltaTimeMillis); + void queuePuzzles(uint32 key); - uint getStateValue(uint32 key); - void setStateValue(uint32 key, uint value); - void addToStateValue(uint32 key, uint valueToAdd); + int getStateValue(uint32 key); + void setStateValue(uint32 key, int value); - uint getStateFlags(uint32 key); - void setStateFlags(uint32 key, uint flags); + uint getStateFlag(uint32 key); + void setStateFlag(uint32 key, uint value); + void unsetStateFlag(uint32 key, uint value); void addControl(Control *control); Control *getControl(uint32 key); + void enableControl(uint32 key); + void disableControl(uint32 key); + void focusControl(uint32 key); + // Only change focus control without call focus/unfocus. + void setFocusControlKey(uint32 key); + + void addSideFX(SideFX *fx); + SideFX *getSideFX(uint32 key); + void deleteSideFx(uint32 key); + void stopSideFx(uint32 key); + void killSideFx(uint32 key); + void killSideFxType(SideFX::SideFXType type); + + void addEvent(Common::Event); + void flushEvent(Common::EventType type); /** * Called when LeftMouse is pushed. @@ -147,30 +237,51 @@ public: */ void onKeyUp(Common::KeyState keyState); + /** Mark next location */ void changeLocation(char world, char room, char node, char view, uint32 offset); + void changeLocation(const Location &_newLocation); - void serializeStateTable(Common::WriteStream *stream); - void deserializeStateTable(Common::SeekableReadStream *stream); - void serializeControls(Common::WriteStream *stream); - void deserializeControls(Common::SeekableReadStream *stream); + void serialize(Common::WriteStream *stream); + void deserialize(Common::SeekableReadStream *stream); Location getCurrentLocation() const; + Location getLastLocation(); + Location getLastMenuLocation(); private: - void createReferenceTable(); + void referenceTableAddPuzzle(uint32 key, PuzzleRef ref); + void addPuzzlesToReferenceTable(ScriptScope &scope); void updateNodes(uint deltaTimeMillis); - void checkPuzzleCriteria(); + void updateControls(uint deltaTimeMillis); + bool checkPuzzleCriteria(Puzzle *puzzle, uint counter); void cleanStateTable(); + void cleanScriptScope(ScriptScope &scope); + bool execScope(ScriptScope &scope); + + /** Perform change location */ + void ChangeLocationReal(); + + int8 inventoryGetCount(); + void inventorySetCount(int8 cnt); + int16 inventoryGetItem(int8 id); + void inventorySetItem(int8 id, int16 item); + + void setStateFlagSilent(uint32 key, uint value); + void setStateValueSilent(uint32 key, int value); -// TODO: Make this private. It was only made public so Console::cmdParseAllScrFiles() could use it public: + void inventoryAdd(int16 item); + void inventoryDrop(int16 item); + void inventoryCycle(); + + // TODO: Make this private. It was only made public so Console::cmdParseAllScrFiles() could use it /** * Parses a script file into triggers and events * * @param fileName Name of the .scr file * @param isGlobal Are the puzzles included in the file global (true). AKA, the won't be purged during location changes */ - void parseScrFile(const Common::String &fileName, bool isGlobal = false); + void parseScrFile(const Common::String &fileName, ScriptScope &scope); private: /** @@ -216,7 +327,17 @@ private: * @param line The line initially read * @param stream Scr file stream */ - void parseControl(Common::String &line, Common::SeekableReadStream &stream); + Control *parseControl(Common::String &line, Common::SeekableReadStream &stream); +}; + +class ValueSlot { +public: + ValueSlot(ScriptManager *scriptManager, const char *slotValue); + int16 getValue(); +private: + int16 value; + bool slot; + ScriptManager *_scriptManager; }; diff --git a/engines/zvision/scripting/sidefx.cpp b/engines/zvision/scripting/sidefx.cpp new file mode 100644 index 0000000000..c0b8a4d12f --- /dev/null +++ b/engines/zvision/scripting/sidefx.cpp @@ -0,0 +1,36 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" + +namespace ZVision { + + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx.h b/engines/zvision/scripting/sidefx.h new file mode 100644 index 0000000000..5bb14f0cdd --- /dev/null +++ b/engines/zvision/scripting/sidefx.h @@ -0,0 +1,114 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SIDEFX_H_INCLUDED +#define SIDEFX_H_INCLUDED + +namespace Common { +class SeekableReadStream; +struct Point; +class WriteStream; +} + +namespace ZVision { + +class ZVision; + +class SideFX { +public: + + enum SideFXType { + SIDEFX_ANIM = 1, + SIDEFX_AUDIO = 2, + SIDEFX_DISTORT = 4, + SIDEFX_PANTRACK = 8, + SIDEFX_REGION = 16, + SIDEFX_TIMER = 32, + SIDEFX_TTYTXT = 64, + SIDEFX_UNK = 128, + SIDEFX_ALL = 255 + }; + + SideFX() : _engine(0), _key(0), _type(SIDEFX_UNK) {} + SideFX(ZVision *engine, uint32 key, SideFXType type) : _engine(engine), _key(key), _type(type) {} + virtual ~SideFX() {} + + uint32 getKey() { + return _key; + } + SideFXType getType() { + return _type; + } + + virtual bool process(uint32 deltaTimeInMillis) { + return false; + } + /** + * Serialize a SideFX for save game use. This should only be used if a SideFX needs + * to save values that would be different from initialization. AKA a TimerNode needs to + * store the amount of time left on the timer. Any Controls overriding this *MUST* write + * their key as the first data outputted. The default implementation is NOP. + * + * NOTE: If this method is overridden, you MUST also override deserialize() + * and needsSerialization() + * + * @param stream Stream to write any needed data to + */ + virtual void serialize(Common::WriteStream *stream) {} + /** + * De-serialize data from a save game stream. This should only be implemented if the + * SideFX also implements serialize(). The calling method assumes the size of the + * data read from the stream exactly equals that written in serialize(). The default + * implementation is NOP. + * + * NOTE: If this method is overridden, you MUST also override serialize() + * and needsSerialization() + * + * @param stream Save game file stream + */ + virtual void deserialize(Common::SeekableReadStream *stream) {} + /** + * If a SideFX overrides serialize() and deserialize(), this should return true + * + * @return Does the SideFX need save game serialization? + */ + virtual inline bool needsSerialization() { + return false; + } + + virtual bool stop() { + return true; + } + virtual void kill() {} + +protected: + ZVision *_engine; + uint32 _key; + SideFXType _type; + +// Static member functions +public: + +}; +} // End of namespace ZVision + +#endif // SIDEFX_H_INCLUDED diff --git a/engines/zvision/scripting/sidefx/animation_node.cpp b/engines/zvision/scripting/sidefx/animation_node.cpp new file mode 100644 index 0000000000..98ac4e3b37 --- /dev/null +++ b/engines/zvision/scripting/sidefx/animation_node.cpp @@ -0,0 +1,207 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/animation_node.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/animation/meta_animation.h" + +#include "graphics/surface.h" + + +namespace ZVision { + +AnimationNode::AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse) + : SideFX(engine, controlKey, SIDEFX_ANIM), + _DisposeAfterUse(DisposeAfterUse), + _mask(mask), + _animation(NULL) { + + _animation = new MetaAnimation(fileName, engine); + _frmDelay = _animation->frameTime(); + + if (frate > 0) + _frmDelay = 1000.0 / frate; +} + +AnimationNode::~AnimationNode() { + if (_animation) + delete _animation; + + _engine->getScriptManager()->setStateValue(_key, 2); + + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + _engine->getScriptManager()->setStateValue((*it).slot, 2); + + if ((*it)._scaled) + delete(*it)._scaled; + } + + _playList.clear(); +} + +bool AnimationNode::process(uint32 deltaTimeInMillis) { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + playnode *nod = &(*it); + + nod->_delay -= deltaTimeInMillis; + if (nod->_delay <= 0) { + nod->_delay += _frmDelay; + + const Graphics::Surface *frame = NULL; + + if (nod->_curFrame == -1) { // Start of new playlist node + nod->_curFrame = nod->start; + + _animation->seekToFrame(nod->_curFrame); + frame = _animation->decodeNextFrame(); + + nod->_delay = _frmDelay; + if (nod->slot) + _engine->getScriptManager()->setStateValue(nod->slot, 1); + } else { + nod->_curFrame++; + + if (nod->_curFrame > nod->stop) { + nod->loop--; + + if (nod->loop == 0) { + if (nod->slot >= 0) + _engine->getScriptManager()->setStateValue(nod->slot, 2); + if (nod->_scaled) + delete nod->_scaled; + _playList.erase(it); + return _DisposeAfterUse; + } + + nod->_curFrame = nod->start; + _animation->seekToFrame(nod->_curFrame); + } + + frame = _animation->decodeNextFrame(); + } + + if (frame) { + + uint32 dstw; + uint32 dsth; + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) { + dstw = nod->pos.height(); + dsth = nod->pos.width(); + } else { + dstw = nod->pos.width(); + dsth = nod->pos.height(); + } + + if (frame->w != dstw || frame->h != dsth) { + if (nod->_scaled) + if (nod->_scaled->w != dstw || nod->_scaled->h != dsth) { + delete nod->_scaled; + nod->_scaled = NULL; + } + + if (!nod->_scaled) { + nod->_scaled = new Graphics::Surface; + nod->_scaled->create(dstw, dsth, frame->format); + } + + _engine->getRenderManager()->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth); + frame = nod->_scaled; + } + + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) { + Graphics::Surface *transposed = RenderManager::tranposeSurface(frame); + if (_mask > 0) + _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask); + else + _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top); + delete transposed; + } else { + if (_mask > 0) + _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask); + else + _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top); + } + } + } + } + + return false; +} + + + +void AnimationNode::addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops) { + playnode nod; + nod.loop = loops; + nod.pos = Common::Rect(x, y, x2 + 1, y2 + 1); + nod.start = startFrame; + nod.stop = endFrame; + + if (nod.stop >= (int)_animation->frameCount()) + nod.stop = _animation->frameCount() - 1; + + nod.slot = slot; + nod._curFrame = -1; + nod._delay = 0; + nod._scaled = NULL; + _playList.push_back(nod); +} + +bool AnimationNode::stop() { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + _engine->getScriptManager()->setStateValue((*it).slot, 2); + if ((*it)._scaled) + delete(*it)._scaled; + } + + _playList.clear(); + + // We don't need to delete, it's may be reused + return false; +} + +void AnimationNode::setNewFrameDelay(int32 newDelay) { + if (newDelay > 0) { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + playnode *nod = &(*it); + float percent = (float)nod->_delay / (float)_frmDelay; + nod->_delay = percent * newDelay; // Scale to new max + } + + _frmDelay = newDelay; + } +} + +int32 AnimationNode::getFrameDelay() { + return _frmDelay; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/animation_control.h b/engines/zvision/scripting/sidefx/animation_node.h index bdb07d39ea..dab3d88d80 100644 --- a/engines/zvision/scripting/controls/animation_control.h +++ b/engines/zvision/scripting/sidefx/animation_node.h @@ -8,32 +8,30 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -#ifndef ZVISION_ANIMATION_CONTROL_H -#define ZVISION_ANIMATION_CONTROL_H +#ifndef ZVISION_ANIMATION_NODE_H +#define ZVISION_ANIMATION_NODE_H -#include "zvision/scripting/control.h" +#include "zvision/scripting/sidefx.h" +#include "common/rect.h" +#include "common/list.h" namespace Common { class String; } -namespace Video { -class VideoDecoder; -} - namespace Graphics { struct Surface; } @@ -41,45 +39,44 @@ struct Surface; namespace ZVision { class ZVision; -class RlfAnimation; +class MetaAnimation; -class AnimationControl : public Control { +class AnimationNode : public SideFX { public: - AnimationControl(ZVision *engine, uint32 controlKey, const Common::String &fileName); - ~AnimationControl(); - -private: - enum FileType { - RLF = 1, - AVI = 2 + AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse = true); + ~AnimationNode(); + + struct playnode { + Common::Rect pos; + int32 slot; + int32 start; + int32 stop; + int32 loop; + int32 _curFrame; + int32 _delay; + Graphics::Surface *_scaled; }; private: - uint32 _animationKey; - - union { - RlfAnimation *rlf; - Video::VideoDecoder *avi; - } _animation; + typedef Common::List<playnode> PlayNodes; - FileType _fileType; - uint _loopCount; - int32 _x; - int32 _y; + PlayNodes _playList; - uint _accumulatedTime; - uint _currentLoop; + int32 _mask; + bool _DisposeAfterUse; - Graphics::Surface *_cachedFrame; - bool _cachedFrameNeedsDeletion; + MetaAnimation *_animation; + int32 _frmDelay; public: bool process(uint32 deltaTimeInMillis); - void setAnimationKey(uint32 animationKey) { _animationKey = animationKey; } - void setLoopCount(uint loopCount) { _loopCount = loopCount; } - void setXPos(int32 x) { _x = x; } - void setYPost(int32 y) { _y = y; } + void addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops = 1); + + bool stop(); + + void setNewFrameDelay(int32 newDelay); + int32 getFrameDelay(); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/distort_node.cpp b/engines/zvision/scripting/sidefx/distort_node.cpp new file mode 100644 index 0000000000..9be6b29413 --- /dev/null +++ b/engines/zvision/scripting/sidefx/distort_node.cpp @@ -0,0 +1,109 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/distort_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/graphics/render_table.h" + +#include "common/stream.h" + + +namespace ZVision { + +DistortNode::DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale) + : SideFX(engine, key, SIDEFX_DISTORT) { + + _angle = _engine->getRenderManager()->getRenderTable()->getAngle(); + _linScale = _engine->getRenderManager()->getRenderTable()->getLinscale(); + + _speed = speed; + _incr = true; + _startAngle = startAngle; + _endAngle = endAngle; + _startLineScale = startLineScale; + _endLineScale = endLineScale; + + _curFrame = 1.0; + + _diffAngle = endAngle - startAngle; + _diffLinScale = endLineScale - startLineScale; + + _frmSpeed = (float)speed / 15.0; + _frames = ceil((5.0 - _frmSpeed * 2.0) / _frmSpeed); + if (_frames <= 0) + _frames = 1; + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); +} + +DistortNode::~DistortNode() { + setParams(_angle, _linScale); +} + +bool DistortNode::process(uint32 deltaTimeInMillis) { + + float updTime = deltaTimeInMillis / (1000.0 / 60.0); + + if (_incr) + _curFrame += updTime; + else + _curFrame -= updTime; + + if (_curFrame < 1.0) { + _curFrame = 1.0; + _incr = true; + } else if (_curFrame > _frames) { + _curFrame = _frames; + _incr = false; + } + + float diff = (1.0 / (5.0 - (_curFrame * _frmSpeed))) / (5.0 - _frmSpeed); + + + setParams(_startAngle + diff * _diffAngle, _startLineScale + diff * _diffLinScale); + + return false; +} + +void DistortNode::setParams(float angl, float linScale) { + RenderTable *table = _engine->getRenderManager()->getRenderTable(); + if (table->getRenderState() == RenderTable::PANORAMA) { + table->setPanoramaFoV(angl); + table->setPanoramaScale(linScale); + table->generateRenderTable(); + _engine->getRenderManager()->markDirty(); + } else if (table->getRenderState() == RenderTable::TILT) { + table->setTiltFoV(angl); + table->setTiltScale(linScale); + table->generateRenderTable(); + _engine->getRenderManager()->markDirty(); + } +} + + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/distort_node.h b/engines/zvision/scripting/sidefx/distort_node.h new file mode 100644 index 0000000000..787a69bdde --- /dev/null +++ b/engines/zvision/scripting/sidefx/distort_node.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_DISTORT_NODE_H +#define ZVISION_DISTORT_NODE_H + +#include "zvision/scripting/sidefx.h" + +namespace ZVision { + +class ZVision; + +class DistortNode : public SideFX { +public: + DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale); + ~DistortNode(); + + bool process(uint32 deltaTimeInMillis); + +private: + int16 _speed; + float _startAngle; + float _endAngle; + float _startLineScale; + float _endLineScale; + + float _frmSpeed; + float _diffAngle; + float _diffLinScale; + bool _incr; + int16 _frames; + + float _curFrame; + + float _angle; + float _linScale; + +private: + void setParams(float angl, float linScale); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/music_node.cpp b/engines/zvision/scripting/sidefx/music_node.cpp new file mode 100644 index 0000000000..e9baadb011 --- /dev/null +++ b/engines/zvision/scripting/sidefx/music_node.cpp @@ -0,0 +1,240 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/music_node.h" + +#include "zvision/zvision.h" +#include "zvision/core/midi.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/sound/zork_raw.h" + +#include "common/stream.h" +#include "common/file.h" +#include "audio/decoders/wave.h" + + +namespace ZVision { + +MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, int8 volume) + : MusicNodeBASE(engine, key, SIDEFX_AUDIO) { + _loop = loop; + _volume = volume; + _crossfade = false; + _crossfadeTarget = 0; + _crossfadeTime = 0; + _attenuate = 0; + _pantrack = false; + _pantrackPosition = 0; + _sub = NULL; + + Audio::RewindableAudioStream *audioStream; + + if (filename.contains(".wav")) { + Common::File *file = new Common::File(); + if (_engine->getSearchManager()->openFile(*file, filename)) { + audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); + } + } else { + audioStream = makeRawZorkStream(filename, _engine); + } + + _stereo = audioStream->isStereo(); + + if (_loop) { + Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, _volume); + } else { + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, _volume); + } + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); + + Common::String subname = filename; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + + if (_engine->getSearchManager()->hasFile(subname)) + _sub = new Subtitle(_engine, subname); +} + +MusicNode::~MusicNode() { + _engine->_mixer->stopHandle(_handle); + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); + if (_sub) + delete _sub; + debug(1, "MusicNode: %d destroyed\n", _key); +} + +void MusicNode::setPanTrack(int16 pos) { + if (!_stereo) { + _pantrack = true; + _pantrackPosition = pos; + setVolume(_volume); + } +} + +void MusicNode::unsetPanTrack() { + _pantrack = false; + setVolume(_volume); +} + +void MusicNode::setFade(int32 time, uint8 target) { + _crossfadeTarget = target; + _crossfadeTime = time; + _crossfade = true; +} + +bool MusicNode::process(uint32 deltaTimeInMillis) { + if (! _engine->_mixer->isSoundHandleActive(_handle)) + return stop(); + else { + uint8 _newvol = _volume; + + if (_crossfade) { + if (_crossfadeTime > 0) { + if ((int32)deltaTimeInMillis > _crossfadeTime) + deltaTimeInMillis = _crossfadeTime; + _newvol += floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis; + _crossfadeTime -= deltaTimeInMillis; + } else { + _crossfade = false; + _newvol = _crossfadeTarget; + } + } + + if (_pantrack || _volume != _newvol) + setVolume(_newvol); + + if (_sub) + _sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100); + } + return false; +} + +void MusicNode::setVolume(uint8 newVolume) { + 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; + + 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); + } + } + + _volume = newVolume; +} + +PanTrackNode::PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos) + : SideFX(engine, key, SIDEFX_PANTRACK) { + _slot = slot; + + SideFX *fx = _engine->getScriptManager()->getSideFX(slot); + if (fx && fx->getType() == SIDEFX_AUDIO) { + MusicNodeBASE *mus = (MusicNodeBASE *)fx; + mus->setPanTrack(pos); + } +} + +PanTrackNode::~PanTrackNode() { + SideFX *fx = _engine->getScriptManager()->getSideFX(_slot); + if (fx && fx->getType() == SIDEFX_AUDIO) { + MusicNodeBASE *mus = (MusicNodeBASE *)fx; + mus->unsetPanTrack(); + } +} + + +MusicMidiNode::MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume) + : MusicNodeBASE(engine, key, SIDEFX_AUDIO) { + _volume = volume; + _prog = program; + _noteNumber = note; + _pan = 0; + + _chan = _engine->getMidiManager()->getFreeChannel(); + + if (_chan >= 0) { + _engine->getMidiManager()->setVolume(_chan, _volume); + _engine->getMidiManager()->setPan(_chan, _pan); + _engine->getMidiManager()->setProgram(_chan, _prog); + _engine->getMidiManager()->noteOn(_chan, _noteNumber, _volume); + } + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); +} + +MusicMidiNode::~MusicMidiNode() { + if (_chan >= 0) { + _engine->getMidiManager()->noteOff(_chan); + } + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); +} + +void MusicMidiNode::setPanTrack(int16 pos) { +} + +void MusicMidiNode::unsetPanTrack() { +} + +void MusicMidiNode::setFade(int32 time, uint8 target) { +} + +bool MusicMidiNode::process(uint32 deltaTimeInMillis) { + return false; +} + +void MusicMidiNode::setVolume(uint8 newVolume) { + if (_chan >= 0) { + _engine->getMidiManager()->setVolume(_chan, newVolume); + } + _volume = newVolume; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/music_node.h b/engines/zvision/scripting/sidefx/music_node.h new file mode 100644 index 0000000000..954e2f474e --- /dev/null +++ b/engines/zvision/scripting/sidefx/music_node.h @@ -0,0 +1,135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_MUSIC_NODE_H +#define ZVISION_MUSIC_NODE_H + +#include "audio/mixer.h" +#include "zvision/scripting/sidefx.h" +#include "zvision/subtitles/subtitles.h" + +namespace Common { +class String; +} + +namespace ZVision { + +class MusicNodeBASE : public SideFX { +public: + MusicNodeBASE(ZVision *engine, uint32 key, SideFXType type) : SideFX(engine, key, type) {} + ~MusicNodeBASE() {} + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + virtual bool process(uint32 deltaTimeInMillis) = 0; + + virtual void setVolume(uint8 volume) = 0; + + virtual void setPanTrack(int16 pos) = 0; + virtual void unsetPanTrack() = 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(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); + + void setVolume(uint8 volume); + + void setPanTrack(int16 pos); + void unsetPanTrack(); + + void setFade(int32 time, uint8 target); + +private: + int32 _timeLeft; + bool _pantrack; + int32 _pantrackPosition; + int32 _attenuate; + uint8 _volume; + bool _loop; + bool _crossfade; + uint8 _crossfadeTarget; + int32 _crossfadeTime; + bool _stereo; + Audio::SoundHandle _handle; + Subtitle *_sub; +}; + +class MusicMidiNode : public MusicNodeBASE { +public: + MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume); + ~MusicMidiNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); + + void setVolume(uint8 volume); + + void setPanTrack(int16 pos); + void unsetPanTrack(); + + void setFade(int32 time, uint8 target); + +private: + int8 _chan; + int8 _noteNumber; + int8 _velocity; + int8 _pan; + int8 _volume; + int8 _prog; +}; + +class PanTrackNode : public SideFX { +public: + PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos); + ~PanTrackNode(); + +private: + uint32 _slot; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/region_node.cpp b/engines/zvision/scripting/sidefx/region_node.cpp new file mode 100644 index 0000000000..de613d8af2 --- /dev/null +++ b/engines/zvision/scripting/sidefx/region_node.cpp @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/region_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" + +namespace ZVision { + +RegionNode::RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay) + : SideFX(engine, key, SIDEFX_REGION) { + _effect = effect; + _delay = delay; + _timeLeft = 0; +} + +RegionNode::~RegionNode() { + _engine->getRenderManager()->deleteEffect(_key); +} + +bool RegionNode::process(uint32 deltaTimeInMillis) { + _timeLeft -= deltaTimeInMillis; + + if (_timeLeft <= 0) { + _timeLeft = _delay; + if (_effect) + _effect->update(); + } + + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/region_node.h b/engines/zvision/scripting/sidefx/region_node.h new file mode 100644 index 0000000000..ec716b6e3e --- /dev/null +++ b/engines/zvision/scripting/sidefx/region_node.h @@ -0,0 +1,57 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_REGION_NODE_H +#define ZVISION_REGION_NODE_H + +#include "graphics/surface.h" + +#include "zvision/scripting/sidefx.h" +#include "zvision/graphics/effect.h" + +namespace ZVision { + +class ZVision; + +class RegionNode : public SideFX { +public: + RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay); + ~RegionNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); + +private: + int32 _timeLeft; + uint32 _delay; + Effect *_effect; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/syncsound_node.cpp b/engines/zvision/scripting/sidefx/syncsound_node.cpp new file mode 100644 index 0000000000..2bfdc349d1 --- /dev/null +++ b/engines/zvision/scripting/sidefx/syncsound_node.cpp @@ -0,0 +1,86 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/syncsound_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/sound/zork_raw.h" + +#include "common/stream.h" +#include "common/file.h" +#include "audio/decoders/wave.h" + + +namespace ZVision { + +SyncSoundNode::SyncSoundNode(ZVision *engine, uint32 key, Common::String &filename, int32 syncto) + : SideFX(engine, key, SIDEFX_AUDIO) { + _syncto = syncto; + _sub = NULL; + + Audio::RewindableAudioStream *audioStream; + + if (filename.contains(".wav")) { + Common::File *file = new Common::File(); + if (_engine->getSearchManager()->openFile(*file, filename)) { + audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); + } + } else { + audioStream = makeRawZorkStream(filename, _engine); + } + + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream); + + Common::String subname = filename; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + + if (_engine->getSearchManager()->hasFile(subname)) + _sub = new Subtitle(_engine, subname); +} + +SyncSoundNode::~SyncSoundNode() { + _engine->_mixer->stopHandle(_handle); + if (_sub) + delete _sub; +} + +bool SyncSoundNode::process(uint32 deltaTimeInMillis) { + if (! _engine->_mixer->isSoundHandleActive(_handle)) + return stop(); + else { + + if (_engine->getScriptManager()->getSideFX(_syncto) == NULL) + return stop(); + + if (_sub) + _sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100); + } + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/syncsound_node.h b/engines/zvision/scripting/sidefx/syncsound_node.h new file mode 100644 index 0000000000..c16ffebe7f --- /dev/null +++ b/engines/zvision/scripting/sidefx/syncsound_node.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SYNCSOUND_NODE_H +#define ZVISION_SYNCSOUND_NODE_H + +#include "audio/mixer.h" +#include "zvision/scripting/sidefx.h" +#include "zvision/subtitles/subtitles.h" + +namespace Common { +class String; +} + +namespace ZVision { +class SyncSoundNode : public SideFX { +public: + SyncSoundNode(ZVision *engine, uint32 key, Common::String &file, int32 syncto); + ~SyncSoundNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); +private: + int32 _syncto; + Audio::SoundHandle _handle; + Subtitle *_sub; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/timer_node.cpp b/engines/zvision/scripting/sidefx/timer_node.cpp index 6f88b056a1..6e71101acd 100644 --- a/engines/zvision/scripting/controls/timer_node.cpp +++ b/engines/zvision/scripting/sidefx/timer_node.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,7 +22,7 @@ #include "common/scummsys.h" -#include "zvision/scripting/controls/timer_node.h" +#include "zvision/scripting/sidefx/timer_node.h" #include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" @@ -33,35 +33,42 @@ namespace ZVision { TimerNode::TimerNode(ZVision *engine, uint32 key, uint timeInSeconds) - : Control(engine, key) { - if (_engine->getGameId() == GID_NEMESIS) { + : SideFX(engine, key, SIDEFX_TIMER) { + if (_engine->getGameId() == GID_NEMESIS) _timeLeft = timeInSeconds * 1000; - } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { + else if (_engine->getGameId() == GID_GRANDINQUISITOR) _timeLeft = timeInSeconds * 100; - } - _engine->getScriptManager()->setStateValue(_key, 1); + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); } TimerNode::~TimerNode() { - if (_timeLeft <= 0) + if (_key != StateKey_NotSet) _engine->getScriptManager()->setStateValue(_key, 2); - else - _engine->getScriptManager()->setStateValue(_key, _timeLeft); // If timer was stopped by stop or kill + int32 timeLeft = _timeLeft / (_engine->getGameId() == GID_NEMESIS ? 1000 : 100); + if (timeLeft > 0) + _engine->getScriptManager()->setStateValue(_key, timeLeft); // If timer was stopped by stop or kill } bool TimerNode::process(uint32 deltaTimeInMillis) { _timeLeft -= deltaTimeInMillis; - if (_timeLeft <= 0) { - // Let the destructor reset the state value - return true; - } + if (_timeLeft <= 0) + return stop(); return false; } +bool TimerNode::stop() { + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); + return true; +} + void TimerNode::serialize(Common::WriteStream *stream) { + stream->writeUint32BE(MKTAG('T', 'I', 'M', 'R')); + stream->writeUint32LE(8); // size stream->writeUint32LE(_key); stream->writeUint32LE(_timeLeft); } diff --git a/engines/zvision/scripting/controls/timer_node.h b/engines/zvision/scripting/sidefx/timer_node.h index 48b5fad1e9..7a26aff251 100644 --- a/engines/zvision/scripting/controls/timer_node.h +++ b/engines/zvision/scripting/sidefx/timer_node.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -23,13 +23,13 @@ #ifndef ZVISION_TIMER_NODE_H #define ZVISION_TIMER_NODE_H -#include "zvision/scripting/control.h" +#include "zvision/scripting/sidefx.h" namespace ZVision { class ZVision; -class TimerNode : public Control { +class TimerNode : public SideFX { public: TimerNode(ZVision *engine, uint32 key, uint timeInSeconds); ~TimerNode(); @@ -44,7 +44,11 @@ public: bool process(uint32 deltaTimeInMillis); void serialize(Common::WriteStream *stream); void deserialize(Common::SeekableReadStream *stream); - inline bool needsSerialization() { return true; } + inline bool needsSerialization() { + return true; + } + + bool stop(); private: int32 _timeLeft; diff --git a/engines/zvision/scripting/sidefx/ttytext_node.cpp b/engines/zvision/scripting/sidefx/ttytext_node.cpp new file mode 100644 index 0000000000..68636eb422 --- /dev/null +++ b/engines/zvision/scripting/sidefx/ttytext_node.cpp @@ -0,0 +1,175 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/ttytext_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/text/text.h" + +#include "common/stream.h" +#include "common/file.h" + + +namespace ZVision { + +ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay) : + SideFX(engine, key, SIDEFX_TTYTXT), + _fnt(engine) { + _delay = delay; + _r = r; + _txtpos = 0; + _nexttime = 0; + _dx = 0; + _dy = 0; + + Common::File *infile = _engine->getSearchManager()->openFile(file); + if (infile) { + while (!infile->eos()) { + Common::String asciiLine = readWideLine(*infile); + if (asciiLine.empty()) { + continue; + } + _txtbuf += asciiLine; + } + + delete infile; + } + _img.create(_r.width(), _r.height(), _engine->_pixelFormat); + _style.sharp = true; + _style.readAllStyle(_txtbuf); + _style.setFont(_fnt); + _engine->getScriptManager()->setStateValue(_key, 1); +} + +ttyTextNode::~ttyTextNode() { + _engine->getScriptManager()->setStateValue(_key, 2); + _img.free(); +} + +bool ttyTextNode::process(uint32 deltaTimeInMillis) { + _nexttime -= deltaTimeInMillis; + + if (_nexttime < 0) { + if (_txtpos < _txtbuf.size()) { + if (_txtbuf[_txtpos] == '<') { + int32 strt = _txtpos; + int32 endt = 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(); + } + + if (ret & TXT_RET_HASSTBOX) { + Common::String buf; + buf.format("%d", _style.statebox); + + for (uint8 j = 0; j < buf.size(); j++) + outchar(buf[j]); + } + + _txtpos++; + } else { + int8 charsz = getUtf8CharSize(_txtbuf[_txtpos]); + + uint16 chr = readUtf8Char(_txtbuf.c_str() + _txtpos); + + if (chr == ' ') { + uint32 i = _txtpos + charsz; + uint16 width = _fnt.getCharWidth(chr); + + while (i < _txtbuf.size() && _txtbuf[i] != ' ' && _txtbuf[i] != '<') { + + int8 chsz = getUtf8CharSize(_txtbuf[i]); + uint16 uchr = readUtf8Char(_txtbuf.c_str() + _txtpos); + + width += _fnt.getCharWidth(uchr); + + i += chsz; + } + + if (_dx + width > _r.width()) + newline(); + else + outchar(chr); + } else + outchar(chr); + + _txtpos += charsz; + } + _nexttime = _delay; + _engine->getRenderManager()->blitSurfaceToBkg(_img, _r.left, _r.top); + } else + return stop(); + } + + return false; +} + +void ttyTextNode::scroll() { + int32 scrl = 0; + while (_dy - scrl > _r.height() - _fnt.getFontHeight()) + scrl += _fnt.getFontHeight(); + int8 *pixels = (int8 *)_img.getPixels(); + for (uint16 h = scrl; h < _img.h; h++) + memcpy(pixels + _img.pitch * (h - scrl), pixels + _img.pitch * h, _img.pitch); + + _img.fillRect(Common::Rect(0, _img.h - scrl, _img.w, _img.h), 0); + _dy -= scrl; +} + +void ttyTextNode::newline() { + _dy += _fnt.getFontHeight(); + _dx = 0; +} + +void ttyTextNode::outchar(uint16 chr) { + uint32 clr = _engine->_pixelFormat.RGBToColor(_style.red, _style.green, _style.blue); + + if (_dx + _fnt.getCharWidth(chr) > _r.width()) + newline(); + + if (_dy + _fnt.getFontHeight() >= _r.height()) + scroll(); + + _fnt.drawChar(&_img, chr, _dx, _dy, clr); + + _dx += _fnt.getCharWidth(chr); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/ttytext_node.h b/engines/zvision/scripting/sidefx/ttytext_node.h new file mode 100644 index 0000000000..a229129b9d --- /dev/null +++ b/engines/zvision/scripting/sidefx/ttytext_node.h @@ -0,0 +1,73 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_TTYTEXT_NODE_H +#define ZVISION_TTYTEXT_NODE_H + +#include "common/rect.h" +#include "graphics/surface.h" + +#include "zvision/scripting/sidefx.h" +#include "zvision/text/text.h" +#include "zvision/fonts/truetype_font.h" + +namespace Common { +class String; +} + +namespace ZVision { +class ttyTextNode : public SideFX { +public: + ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay); + ~ttyTextNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); +private: + Common::Rect _r; + + cTxtStyle _style; + StyledTTFont _fnt; + Common::String _txtbuf; + uint32 _txtpos; + + int32 _delay; + int32 _nexttime; + Graphics::Surface _img; + int16 _dx; + int16 _dy; +private: + + void newline(); + void scroll(); + void outchar(uint16 chr); +}; + +} // End of namespace ZVision + +#endif |