aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision/scripting
diff options
context:
space:
mode:
authorFilippos Karapetis2014-12-03 00:06:38 +0200
committerFilippos Karapetis2014-12-03 00:06:38 +0200
commit637102d33b9ab69724c1badd9515e0e26a4b4b88 (patch)
tree72fe1291306ceb12c4da2956ab22814741dddce9 /engines/zvision/scripting
parentb1f7603263c368658a3b9b7e30a929bd77d895af (diff)
parent596a904a0c6aedba5bbe45cdfa931425450626c8 (diff)
downloadscummvm-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')
-rw-r--r--engines/zvision/scripting/actions.cpp889
-rw-r--r--engines/zvision/scripting/actions.h337
-rw-r--r--engines/zvision/scripting/control.cpp53
-rw-r--r--engines/zvision/scripting/control.h105
-rw-r--r--engines/zvision/scripting/controls/animation_control.cpp263
-rw-r--r--engines/zvision/scripting/controls/fist_control.cpp320
-rw-r--r--engines/zvision/scripting/controls/fist_control.h87
-rw-r--r--engines/zvision/scripting/controls/hotmov_control.cpp201
-rw-r--r--engines/zvision/scripting/controls/hotmov_control.h63
-rw-r--r--engines/zvision/scripting/controls/input_control.cpp200
-rw-r--r--engines/zvision/scripting/controls/input_control.h34
-rw-r--r--engines/zvision/scripting/controls/lever_control.cpp196
-rw-r--r--engines/zvision/scripting/controls/lever_control.h19
-rw-r--r--engines/zvision/scripting/controls/paint_control.cpp216
-rw-r--r--engines/zvision/scripting/controls/paint_control.h92
-rw-r--r--engines/zvision/scripting/controls/push_toggle_control.cpp98
-rw-r--r--engines/zvision/scripting/controls/push_toggle_control.h21
-rw-r--r--engines/zvision/scripting/controls/safe_control.cpp205
-rw-r--r--engines/zvision/scripting/controls/safe_control.h71
-rw-r--r--engines/zvision/scripting/controls/save_control.cpp123
-rw-r--r--engines/zvision/scripting/controls/save_control.h56
-rw-r--r--engines/zvision/scripting/controls/slot_control.cpp219
-rw-r--r--engines/zvision/scripting/controls/slot_control.h85
-rw-r--r--engines/zvision/scripting/controls/titler_control.cpp108
-rw-r--r--engines/zvision/scripting/controls/titler_control.h55
-rw-r--r--engines/zvision/scripting/inventory.cpp123
-rw-r--r--engines/zvision/scripting/puzzle.h11
-rw-r--r--engines/zvision/scripting/scr_file_handling.cpp292
-rw-r--r--engines/zvision/scripting/script_manager.cpp890
-rw-r--r--engines/zvision/scripting/script_manager.h197
-rw-r--r--engines/zvision/scripting/sidefx.cpp36
-rw-r--r--engines/zvision/scripting/sidefx.h114
-rw-r--r--engines/zvision/scripting/sidefx/animation_node.cpp207
-rw-r--r--engines/zvision/scripting/sidefx/animation_node.h (renamed from engines/zvision/scripting/controls/animation_control.h)69
-rw-r--r--engines/zvision/scripting/sidefx/distort_node.cpp109
-rw-r--r--engines/zvision/scripting/sidefx/distort_node.h63
-rw-r--r--engines/zvision/scripting/sidefx/music_node.cpp240
-rw-r--r--engines/zvision/scripting/sidefx/music_node.h135
-rw-r--r--engines/zvision/scripting/sidefx/region_node.cpp56
-rw-r--r--engines/zvision/scripting/sidefx/region_node.h57
-rw-r--r--engines/zvision/scripting/sidefx/syncsound_node.cpp86
-rw-r--r--engines/zvision/scripting/sidefx/syncsound_node.h56
-rw-r--r--engines/zvision/scripting/sidefx/timer_node.cpp (renamed from engines/zvision/scripting/controls/timer_node.cpp)37
-rw-r--r--engines/zvision/scripting/sidefx/timer_node.h (renamed from engines/zvision/scripting/controls/timer_node.h)14
-rw-r--r--engines/zvision/scripting/sidefx/ttytext_node.cpp175
-rw-r--r--engines/zvision/scripting/sidefx/ttytext_node.h73
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, &note, &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,", &centerX, &centerY, &frames, &amplitude, &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, &notUsed, 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 &parameter, 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 &parameter, 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 &parameter, 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 &parameter, 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 &parameter, 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 &parameter, 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