[Scummvm-git-logs] scummvm master -> b25911c73187900ffefcefa5c4eab15ac364a98d
whoozle
noreply at scummvm.org
Sun Jul 19 09:44:31 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
b25911c731 PHOENIXVR: Factor script v1/commands v1 out
Commit: b25911c73187900ffefcefa5c4eab15ac364a98d
https://github.com/scummvm/scummvm/commit/b25911c73187900ffefcefa5c4eab15ac364a98d
Author: Vladimir Menshakov (vladimir.menshakov at gmail.com)
Date: 2026-07-19T10:43:24+01:00
Commit Message:
PHOENIXVR: Factor script v1/commands v1 out
Add Script::load(stream, version) factory function.
Move abstract Command, Scope and Execution context to the dedicated header
Factor V1 specific command/plugin factories out.
Changed paths:
A engines/phoenixvr/commands.cpp
A engines/phoenixvr/commands_v1.cpp
A engines/phoenixvr/commands_v1.h
A engines/phoenixvr/script_v1.cpp
A engines/phoenixvr/script_v1.h
engines/phoenixvr/commands.h
engines/phoenixvr/game_state.cpp
engines/phoenixvr/math.h
engines/phoenixvr/module.mk
engines/phoenixvr/phoenixvr.cpp
engines/phoenixvr/script.cpp
engines/phoenixvr/script.h
diff --git a/engines/phoenixvr/commands.cpp b/engines/phoenixvr/commands.cpp
new file mode 100644
index 00000000000..6fe15df4958
--- /dev/null
+++ b/engines/phoenixvr/commands.cpp
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "phoenixvr/commands.h"
+#include "phoenixvr/phoenixvr.h"
+
+namespace PhoenixVR {
+
+int Command::valueOf(const Common::String &value) {
+ if (!value.empty() && (Common::isDigit(value[0]) || value[0] == '-' || value[0] == '+'))
+ return atoi(value.c_str());
+ return g_engine->getVariable(value);
+}
+
+void Scope::exec(ExecutionContext &ctx) const {
+ exec(ctx, 0);
+}
+
+void Scope::exec(ExecutionContext &ctx, uint offset) const {
+ auto oldScope = ctx.scope;
+ if (!ctx.rootScope)
+ ctx.rootScope = this;
+ ctx.scope = this;
+ for (uint i = offset, n = commands.size(); i < n; ++i) {
+ if (!ctx.running)
+ break;
+ commands[i]->exec(ctx);
+ }
+ ctx.scope = oldScope;
+}
+
+} // namespace PhoenixVR
diff --git a/engines/phoenixvr/commands.h b/engines/phoenixvr/commands.h
index 4e6b1b22cee..0d9e1bb8d0e 100644
--- a/engines/phoenixvr/commands.h
+++ b/engines/phoenixvr/commands.h
@@ -22,1914 +22,48 @@
#ifndef PHOENIXVR_COMMANDS_H
#define PHOENIXVR_COMMANDS_H
-#include "common/debug.h"
-#include "common/stream.h"
-#include "common/system.h"
-#include "common/textconsole.h"
-#include "phoenixvr/phoenixvr.h"
-#include "phoenixvr/script.h"
+#include "common/array.h"
+#include "common/ptr.h"
+#include "common/str.h"
namespace PhoenixVR {
-namespace {
-constexpr int kMessengerInventorySlots = 12;
-constexpr int kMessengerDisplayedInventorySlots = 8;
-constexpr int kLouvreChestSize = 128;
-constexpr Common::Rect kLouvreTextRect({62, 402}, 292, 64);
-constexpr uint16 kLouvreTextColor = 1987;
-constexpr uint16 kLouvreWarningTextColor = 63687;
-constexpr uint32 kLouvreTextBlockMillis = 5000;
+struct Scope;
-struct LouvrePluginState {
- int objectChest[kLouvreChestSize];
- int monde4;
- uint32 rolloverBlockedUntil;
- bool initialized;
+struct ExecutionContext {
+ bool running = true;
+ bool subroutine = false;
+ const Scope *scope = nullptr;
+ const Scope *rootScope = nullptr;
};
-LouvrePluginState g_louvrePluginState;
+struct Command {
+ virtual ~Command() {}
+ virtual void exec(ExecutionContext &ctx) const = 0;
-void initLouvrePluginState() {
- if (g_louvrePluginState.initialized)
- return;
-
- for (int i = 0; i < kLouvreChestSize; ++i)
- g_louvrePluginState.objectChest[i] = 0;
- g_louvrePluginState.monde4 = 0;
- g_louvrePluginState.rolloverBlockedUntil = 0;
- g_louvrePluginState.initialized = true;
-}
-
-Common::String messengerInventorySlotName(int slot) {
- return Common::String::format("Pos%d", slot);
-}
-
-int louvreSelectionSlot(int selection) {
- return selection > 100 ? selection - 100 : selection;
-}
-
-int messengerInventorySlot(int slot) {
- if (slot < 1 || slot > kMessengerInventorySlots)
- return 0;
-
- return g_engine->getVariable(messengerInventorySlotName(slot));
-}
-
-void setMessengerInventorySlot(int slot, int objectId) {
- if (slot >= 1 && slot <= kMessengerInventorySlots)
- g_engine->setVariable(messengerInventorySlotName(slot), objectId);
-}
-
-int messengerSpecialObjectSlot(int objectId) {
- static const int kSpecialObjects[] = {300, 100, 200, 400};
-
- for (uint i = 0; i < ARRAYSIZE(kSpecialObjects); ++i) {
- if (kSpecialObjects[i] == objectId)
- return i + 9;
- }
- return 0;
-}
-
-Common::String louvreObjectImage(int objectId, int suffix) {
- return Common::String::format("Obj%02d%02d.bmp", objectId / 100, suffix);
-}
-
-void drawLouvreImage(const Common::String &image, int x, int y) {
- g_engine->drawArchiveImage(image, x, y);
-}
-
-void drawLouvreText(int textId, uint16 color = kLouvreTextColor) {
- drawLouvreImage("EffaceText.bmp", kLouvreTextRect.left, kLouvreTextRect.top);
- g_engine->clearArchiveText(kLouvreTextRect);
- g_engine->drawArchiveText(textId, kLouvreTextRect, 14, true, color);
-}
-
-void clearLouvreText() {
- drawLouvreImage("EffaceText.bmp", kLouvreTextRect.left, kLouvreTextRect.top);
- g_engine->clearArchiveText(kLouvreTextRect);
-}
-
-bool louvreTextBlocked() {
- return g_louvrePluginState.rolloverBlockedUntil > g_system->getMillis();
-}
-
-void drawBlockedLouvreText(int textId) {
- drawLouvreText(textId, kLouvreWarningTextColor);
- g_louvrePluginState.rolloverBlockedUntil = g_system->getMillis() + kLouvreTextBlockMillis;
-}
-
-template<size_t N>
-bool louvreContainsObject(const int (&objects)[N], int objectId) {
- for (int object : objects)
- if (object == objectId)
- return true;
- return false;
-}
-
-bool louvreObjectCanView(int objectId) {
- static const int kViewableObjects[] = {3000, 3100, 4200, 4300, 5500, 5900, 7600, 7700, 7800, 8500, 8600, 8800};
- return louvreContainsObject(kViewableObjects, objectId);
-}
-
-int louvreCombineObjects(int selectedObjectId, int objectId) {
- struct CombineEntry {
- int left;
- int right;
- int result;
- };
- static const CombineEntry kCombineTable[] = {
- {500, 1200, 1300},
- {500, 600, 1400},
- {500, 700, 9600},
- {9600, 600, 1500},
- {1400, 700, 1500},
- {3000, 2900, 3100},
- {2300, 2200, 3500},
- {2100, 2200, 3500},
- {2100, 2300, 3500},
- {3500, 2100, 3600},
- {3500, 2200, 3600},
- {3500, 2300, 3600},
- {1800, 2600, 3700},
- {1800, 1700, 3700},
- {2600, 1700, 3700},
- {3700, 1800, 3800},
- {3700, 2600, 3800},
- {3700, 1700, 3800},
- {4200, 3400, 4300},
- {4400, 6100, 6200},
- {4400, 6000, 6300},
- {6200, 6000, 6400},
- {6300, 6100, 6400},
- {7700, 3400, 7800},
- {6900, 8200, 9800},
- {9300, 7000, 9900}};
-
- for (const CombineEntry &entry : kCombineTable) {
- if ((entry.left == selectedObjectId && entry.right == objectId) ||
- (entry.left == objectId && entry.right == selectedObjectId)) {
- if (entry.result == 3500) {
- g_engine->setVariable("RedPastryA", selectedObjectId);
- g_engine->setVariable("RedPastryB", objectId);
- } else if (entry.result == 3700) {
- g_engine->setVariable("YellowSeedA", selectedObjectId);
- g_engine->setVariable("YellowSeedB", objectId);
- }
- return entry.result;
- }
- }
-
- return 0;
-}
-
-int louvreSeparateObject(int objectId, int *parts) {
- struct SeparateEntry {
- int object;
- int parts[3];
- };
- static const SeparateEntry kSeparateTable[] = {
- {1300, {500, 1200, 0}},
- {1400, {500, 600, 0}},
- {1500, {1400, 700, 0}},
- {3100, {3000, 2900, 0}},
- {3600, {3500, 2100, 0}},
- {3800, {3700, 1800, 0}},
- {4300, {4200, 3400, 0}},
- {6200, {4400, 6100, 0}},
- {6300, {4400, 6000, 0}},
- {6400, {6200, 6000, 0}},
- {7800, {7700, 3400, 0}},
- {9600, {500, 700, 0}},
- {9800, {6900, 8200, 0}},
- {9900, {9300, 7000, 0}},
- };
-
- for (const SeparateEntry &entry : kSeparateTable) {
- if (entry.object == objectId) {
- Common::copy(entry.parts, entry.parts + ARRAYSIZE(entry.parts), parts);
- return entry.parts[2] != 0 ? 3 : 2;
- }
- }
-
- return 0;
-}
-
-bool louvreObjectCanCombine(int objectId) {
- static const int kCombinableObjects[] = {
- 500, 600, 700, 1200, 1300, 1400, 1500, 1700, 1800, 2100, 2200, 2300, 2600, 2900,
- 3000, 3100, 3400, 3500, 3600, 3700, 3800, 4200, 4300, 4400, 6000, 6100, 6200,
- 6300, 6400, 6900, 7000, 7700, 7800, 8200, 9300, 9600, 9800, 9900};
- return louvreContainsObject(kCombinableObjects, objectId);
-}
-
-bool louvreObjectCanSeparate(int objectId) {
- if (objectId == 3500 || objectId == 3700)
- return true;
-
- int parts[3] = {0, 0, 0};
- return louvreSeparateObject(objectId, parts) != 0;
-}
-
-int louvreObjectActionMask(int objectId) {
- if (objectId == 0)
- return 0;
- if (messengerSpecialObjectSlot(objectId) != 0)
- return 1;
-
- int mask = 1;
- if (louvreObjectCanView(objectId))
- mask |= 2;
- if (louvreObjectCanCombine(objectId))
- mask |= 4;
- if (louvreObjectCanSeparate(objectId))
- mask |= 8;
- return mask;
-}
-
-int louvreSelectedObjectActionMask() {
- return louvreObjectActionMask(messengerInventorySlot(louvreSelectionSlot(g_engine->getVariable("Selection"))));
-}
-
-void drawLouvreActionButtons() {
- static const int kActionButtonX[] = {21, 22, 25, 24};
- static const int kActionButtonY[] = {145, 191, 270, 318};
- static const int kActionValues[] = {1, 2, 4, 8};
-
- int mask = louvreSelectedObjectActionMask();
- int currentAction = g_engine->getVariable("CurrentAction");
- for (uint i = 0; i < ARRAYSIZE(kActionValues); ++i) {
- drawLouvreImage(Common::String::format("Bout%04d.bmp", i + 1), kActionButtonX[i], kActionButtonY[i]);
- if ((mask & kActionValues[i]) != 0)
- drawLouvreImage(Common::String::format("Bout%04d.bmp", i + 11), kActionButtonX[i], kActionButtonY[i]);
- }
-
- for (uint i = 0; i < ARRAYSIZE(kActionValues); ++i) {
- if (currentAction == kActionValues[i])
- drawLouvreImage(Common::String::format("Bout%04d.bmp", i + 21), kActionButtonX[i], kActionButtonY[i]);
- }
-}
-
-void drawLouvreSelectionMarker(int slot, int imageNumber, bool selected) {
- static const Common::Point kSlotSelectedPos[kMessengerInventorySlots] = {
- Common::Point(389, 82),
- Common::Point(482, 83),
- Common::Point(574, 84),
- Common::Point(456, 170),
- Common::Point(556, 178),
- Common::Point(476, 258),
- Common::Point(567, 268),
- Common::Point(552, 352),
- Common::Point(8, 32),
- Common::Point(93, 32),
- Common::Point(182, 27),
- Common::Point(264, 28)};
-
- if (slot >= 1 && slot <= kMessengerInventorySlots && imageNumber > 0)
- drawLouvreImage(Common::String::format(selected ? "Sel%04d.bmp" : "DSel%04d.bmp", imageNumber), kSlotSelectedPos[slot - 1].x, kSlotSelectedPos[slot - 1].y);
-}
-
-void drawLouvreSelectedObject(int objectSlot) {
- static const int kSelectedObjectX = 103;
- static const int kSelectedObjectY = 123;
-
- initLouvrePluginState();
- objectSlot = louvreSelectionSlot(objectSlot);
- if (objectSlot < 1 || objectSlot > kMessengerInventorySlots)
- return;
-
- int objectId = messengerInventorySlot(objectSlot);
- if (objectId == 0)
- return;
-
- drawLouvreImage(louvreObjectImage(objectId, 0), kSelectedObjectX, kSelectedObjectY);
- clearLouvreText();
- drawLouvreActionButtons();
- drawLouvreSelectionMarker(objectSlot, objectSlot, true);
-}
-
-void clearLouvreSelection(bool clearObjectPreview = true) {
- int selection = g_engine->getVariable("Selection");
- int slot = louvreSelectionSlot(selection);
-
- g_engine->setVariable("Selection", 0);
- if (clearObjectPreview) {
- drawLouvreImage(louvreObjectImage(0, 0), 103, 123);
- clearLouvreText();
- drawLouvreActionButtons();
- }
- drawLouvreSelectionMarker(slot, selection, false);
-}
-
-void setLouvreSelectedSlot(int slot, int flags) {
- int previousSelection = g_engine->getVariable("Selection");
- int previousSlot = louvreSelectionSlot(previousSelection);
- int targetSlot = louvreSelectionSlot(slot);
-
- if (previousSelection == slot && (flags & 2) == 0) {
- clearLouvreSelection((flags & 1) == 0);
- return;
- }
-
- g_engine->setVariable("Selection", slot);
- drawLouvreSelectionMarker(previousSlot, previousSelection, false);
- drawLouvreSelectionMarker(targetSlot, slot, true);
-
- if ((slot < 100 || (flags & 2) != 0) && (flags & 5) == 0)
- drawLouvreSelectedObject(slot);
-}
-
-Common::String louvreNumberedImageName(const char *prefix, int value) {
- return Common::String::format("%s%04d", prefix, value);
-}
-
-int louvreChestLastUsedIndex() {
- for (int i = kLouvreChestSize - 1; i >= 0; --i)
- if (g_louvrePluginState.objectChest[i] != 0)
- return i + 1;
- return 0;
-}
-
-void drawLouvreChestScrollButtons() {
- static const Common::Point kUpButtonPos(191, 17);
- static const Common::Point kDownButtonPos(198, 375);
-
- int offset = g_engine->getVariable("CoffreOffset");
- int count = louvreChestLastUsedIndex();
- drawLouvreImage(offset <= 0 ? "CBou0001" : "CBou0011", kUpButtonPos.x, kUpButtonPos.y);
- drawLouvreImage(offset >= count - 1 || offset >= 124 ? "CBou0002" : "CBou0012", kDownButtonPos.x, kDownButtonPos.y);
-}
-
-void drawLouvreChestSlot(int slot) {
- static const Common::Point kChestImagePos[] = {
- Common::Point(80, 82), Common::Point(80, 145), Common::Point(80, 210), Common::Point(80, 273)};
- static const Common::Rect kChestTextRect[] = {
- Common::Rect(138, 80, 324, 134),
- Common::Rect(138, 145, 324, 199),
- Common::Rect(138, 208, 324, 262),
- Common::Rect(138, 272, 324, 326)};
-
- int index = g_engine->getVariable("CoffreOffset") + slot - 1;
- int objectId = (index >= 0 && index < kLouvreChestSize) ? g_louvrePluginState.objectChest[index] : 0;
- drawLouvreImage(louvreNumberedImageName("Cof", objectId + 1), kChestImagePos[slot - 1].x, kChestImagePos[slot - 1].y);
- drawLouvreImage(louvreNumberedImageName("CText", slot), kChestTextRect[slot - 1].left, kChestTextRect[slot - 1].top);
- g_engine->clearArchiveText(kChestTextRect[slot - 1]);
- if (objectId != 0)
- g_engine->drawArchiveText(objectId, kChestTextRect[slot - 1], 12, false, 1987);
-}
-
-void drawLouvreChest() {
- for (int slot = 1; slot < 5; ++slot)
- drawLouvreChestSlot(slot);
-}
-
-void drawLouvreChestSelection(int slot) {
- static const Common::Point kChestSelectionPos[] = {
- Common::Point(69, 70), Common::Point(70, 134), Common::Point(70, 199), Common::Point(70, 262), Common::Point(70, 326)};
-
- int current = g_engine->getVariable("CoffreSelect");
- if (current != 0 && current <= 4) {
- drawLouvreImage(louvreNumberedImageName("CDel", current), kChestSelectionPos[current - 1].x, kChestSelectionPos[current - 1].y);
- drawLouvreImage(louvreNumberedImageName("CDel", current + 1), kChestSelectionPos[current].x, kChestSelectionPos[current].y);
- }
-
- if (slot == 0 || current == slot) {
- g_engine->setVariable("CoffreSelect", 0);
- return;
- }
-
- drawLouvreImage(louvreNumberedImageName("Cel", slot), kChestSelectionPos[slot - 1].x, kChestSelectionPos[slot - 1].y);
- drawLouvreImage(louvreNumberedImageName("Cel", slot + 1), kChestSelectionPos[slot].x, kChestSelectionPos[slot].y);
- g_engine->setVariable("CoffreSelect", slot);
-}
-
-void drawLouvreInventorySlotObject(int slot, int objectId) {
- static const Common::Point kInventoryObjectPos[] = {
- Common::Point(381, 28),
- Common::Point(477, 28),
- Common::Point(565, 28),
- Common::Point(452, 116),
- Common::Point(549, 123),
- Common::Point(468, 204),
- Common::Point(558, 212),
- Common::Point(548, 300),
- Common::Point(18, 13),
- Common::Point(104, 20),
- Common::Point(193, 12),
- Common::Point(273, 15)};
-
- if (slot >= 1 && slot <= kMessengerInventorySlots && (slot <= kMessengerDisplayedInventorySlots || objectId != 0))
- drawLouvreImage(louvreNumberedImageName("Obj", objectId + 1), kInventoryObjectPos[slot - 1].x, kInventoryObjectPos[slot - 1].y);
-}
-
-void drawLouvreInventoryObjects(bool includeSpecialSlots) {
- for (int slot = 1; slot < (includeSpecialSlots ? 13 : 9); ++slot)
- drawLouvreInventorySlotObject(slot, messengerInventorySlot(slot));
-}
-
-void updateLouvreChestScroll(int direction) {
- int offset = g_engine->getVariable("CoffreOffset");
- int count = louvreChestLastUsedIndex();
- if (direction == 1)
- offset -= 3;
- else if (direction == 2)
- offset += 3;
-
- offset = CLIP(offset, 0, MIN(124, MAX(0, count - 1)));
- if (offset != g_engine->getVariable("CoffreOffset")) {
- g_engine->setVariable("CoffreSelect", 0);
- g_engine->setVariable("CoffreOffset", offset);
- drawLouvreChest();
- }
- drawLouvreChestScrollButtons();
-}
-
-void exchangeLouvreChestObject(int chestSlot, int inventorySlot) {
- if (chestSlot == 0)
- chestSlot = g_engine->getVariable("CoffreSelect");
- if (inventorySlot == 0)
- inventorySlot = g_engine->getVariable("Selection");
- inventorySlot = louvreSelectionSlot(inventorySlot);
-
- if (chestSlot < 1 || chestSlot > 4 || inventorySlot < 1 || inventorySlot > kMessengerInventorySlots)
- return;
-
- int chestIndex = g_engine->getVariable("CoffreOffset") + chestSlot - 1;
- if (chestIndex < 0 || chestIndex >= kLouvreChestSize)
- return;
- if (louvreChestLastUsedIndex() == 0)
- g_engine->setVariable("CoffreOffset", 0);
-
- int inventoryObject = messengerInventorySlot(inventorySlot);
- int chestObject = g_louvrePluginState.objectChest[chestIndex];
- g_louvrePluginState.objectChest[chestIndex] = inventoryObject;
- setMessengerInventorySlot(inventorySlot, chestObject);
- drawLouvreInventorySlotObject(inventorySlot, chestObject);
- drawLouvreChestSlot(chestSlot);
- drawLouvreChestSelection(0);
- g_engine->setVariable("Selection", 0);
- updateLouvreChestScroll(0);
-}
-
-struct MultiCD_Use_Install_Path : public Script::Command {
- Common::String path;
-
- MultiCD_Use_Install_Path(const Common::Array<Common::String> &args) : path(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("MultiCD_Use_Install_Path %s", path.c_str());
- }
-};
-
-struct MultiCD_Set_Transition_Script : public Script::Command {
- Common::String path;
-
- MultiCD_Set_Transition_Script(const Common::Array<Common::String> &args) : path(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("MultiCD_Set_Transition_Script %s", path.c_str());
- }
-};
-
-struct MultiCD_Set_Next_Script : public Script::Command {
- Common::String filename;
-
- MultiCD_Set_Next_Script(const Common::Array<Common::String> &args) : filename(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("MultiCD_Set_Next_Script %s", filename.c_str());
- g_engine->setNextScript(filename);
- }
-};
-
-struct MultiCD_If_Next_Script : public Script::Command {
- Common::String cd;
- Common::String var;
-
- MultiCD_If_Next_Script(const Common::Array<Common::String> &args) : cd(args[0]), var(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("MultiCD_If_Next_Script %s %s", cd.c_str(), var.c_str());
- }
-};
-
-struct LoadSave_Enter_Script : public Script::Command {
- Common::String reloading, notReloading;
-
- LoadSave_Enter_Script(const Common::Array<Common::String> &args) : reloading(args[0]), notReloading(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("LoadSave_Enter_Script %s, %s", reloading.c_str(), notReloading.c_str());
- auto loading = g_engine->enterScript();
- g_engine->setVariable(reloading, loading);
- g_engine->setVariable(notReloading, !loading);
- }
-};
-
-struct Play_Movie : public Script::Command {
- Common::String filename;
-
- Play_Movie(const Common::Array<Common::String> &args) : filename(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->playMovie(filename);
- }
-};
-
-struct Play_AnimBloc : public Script::Command {
- Common::String name;
- Common::String dstVar;
- int dstVarValue;
- float speed; // ticks per second
-
- Play_AnimBloc(const Common::Array<Common::String> &args) : name(args[0]), dstVar(args[1]), dstVarValue(atoi(args[2].c_str())), speed(args.size() >= 4 ? atof(args[3].c_str()) : 25) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("Play_AnimBloc %s %s %d %g", name.c_str(), dstVar.c_str(), dstVarValue, speed);
- g_engine->playAnimation(name, dstVar, dstVarValue, speed);
- }
-};
-
-struct Stop_AnimBloc : public Script::Command {
- Common::String name;
-
- Stop_AnimBloc(const Common::Array<Common::String> &args) : name(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("Stop_AnimBloc %s", name.c_str());
- g_engine->stopAnimation(name);
- }
-};
-
-struct Play_AnimBloc_Number : public Script::Command {
- Common::String prefix, var;
- Common::String dstVar;
- int dstVarValue;
- float speed;
-
- Play_AnimBloc_Number(const Common::Array<Common::String> &args) : prefix(args[0]), var(args[1]),
- dstVar(args[2]), dstVarValue(atoi(args[3].c_str())),
- speed(args.size() >= 5 ? atof(args[4].c_str()) : 25) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("Play_AnimBloc_Number %s %s %s %d, %g", prefix.c_str(), var.c_str(), dstVar.c_str(), dstVarValue, speed);
- int value = g_engine->getVariable(var);
- auto name = Common::String::format("%s%04d", prefix.c_str(), value);
- g_engine->playAnimation(name, dstVar, dstVarValue, speed);
- }
-};
-
-struct Until : public Script::Command {
- Common::String var;
- int value;
-
- Until(const Common::Array<Common::String> &args) : var(args[0]), value(atoi(args[1].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->until(var, value);
- }
-};
-
-struct While : public Script::Command {
- float seconds;
-
- While(const Common::Array<Common::String> &args) : seconds(atof(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->wait(seconds);
- }
-};
-
-struct StartTimer : public Script::Command {
- float seconds;
- bool showTimer;
-
- StartTimer(const Common::Array<Common::String> &args) : seconds(atof(args[0].c_str())), showTimer(args.size() < 2 || atoi(args[1].c_str()) != 0) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("starttimer %g %d", seconds, showTimer);
- g_engine->startTimer(seconds, showTimer);
- }
-};
-
-struct PauseTimer : public Script::Command {
- int paused, deactivate;
-
- PauseTimer(const Common::Array<Common::String> &args) : paused(atoi(args[0].c_str())), deactivate(atoi(args[1].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("pausetimer %d %d", paused, deactivate);
- g_engine->pauseTimer(paused, deactivate);
- }
-};
-
-struct KillTimer : public Script::Command {
- KillTimer(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("killtimer");
- g_engine->killTimer();
- }
-};
-
-struct ChangeCurseur : public Script::Command {
- int cursor;
- ChangeCurseur(const Common::Array<Common::String> &args) : cursor(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("changecurseur %d", cursor);
- g_engine->scheduleTest(cursor);
- }
-};
-
-struct Add : public Script::Command {
- Common::String dstVar;
- Common::String arg0;
- Common::String arg1;
-
- Add(const Common::Array<Common::String> &args) : dstVar(args[0]), arg0(args[1]), arg1(args[2]) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("add %s %s %s", dstVar.c_str(), arg0.c_str(), arg1.c_str());
- g_engine->setVariable(dstVar, valueOf(arg0) + valueOf(arg1));
- }
-};
-
-struct Sub : public Script::Command {
- Common::String dstVar;
- Common::String arg0;
- Common::String arg1;
-
- Sub(const Common::Array<Common::String> &args) : dstVar(args[0]), arg0(args[1]), arg1(args[2]) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("sub %s %s %s", dstVar.c_str(), arg0.c_str(), arg1.c_str());
- g_engine->setVariable(dstVar, valueOf(arg0) - valueOf(arg1));
- }
-};
-
-struct CopyVar : public Script::Command {
- Common::String srcVar;
- Common::String dstVar;
-
- CopyVar(const Common::Array<Common::String> &args) : srcVar(args[0]), dstVar(args[1]) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("copyvar %s %s", srcVar.c_str(), dstVar.c_str());
- g_engine->setVariable(dstVar, g_engine->getVariable(srcVar));
- }
-};
-
-struct Not : public Script::Command {
- Common::String var;
-
- Not(Common::String v) : var(Common::move(v)) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("not %s", var.c_str());
- g_engine->setVariable(var, g_engine->getVariable(var) ? 0 : 1);
- }
-};
-
-struct GetMonde4 : public Script::Command {
- Common::String var;
- Common::String negativeVar;
-
- GetMonde4(const Common::Array<Common::String> &args) : var(args[0]), negativeVar(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(var, g_louvrePluginState.monde4);
- g_engine->setVariable(negativeVar, g_louvrePluginState.monde4 == 0);
- }
-};
-
-struct SetMonde4 : public Script::Command {
- int value;
-
- SetMonde4(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_louvrePluginState.monde4 = value;
- }
-};
-
-struct AddObject : public Script::Command {
- int object;
- Common::String var;
- Common::String negativeVar;
-
- AddObject(const Common::Array<Common::String> &args) : object(atoi(args[0].c_str())), var(args[1]), negativeVar(args[2]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
-
- g_engine->setVariable(var, 1);
- g_engine->setVariable(negativeVar, 0);
- g_engine->setVariable("AddObjectOk", 0);
-
- int slot = messengerSpecialObjectSlot(object);
- if (slot != 0) {
- setMessengerInventorySlot(slot, object);
- g_engine->setVariable("Selection", slot);
- return;
- }
-
- for (slot = 1; slot < 9; ++slot) {
- if (messengerInventorySlot(slot) == 0) {
- setMessengerInventorySlot(slot, object);
- g_engine->setVariable("Selection", slot);
- return;
- }
- }
-
- g_engine->setVariable("Selection", 0);
- g_engine->setVariable("AddObjectOk", 1);
- g_engine->setVariable(var, 0);
- g_engine->setVariable(negativeVar, 1);
- }
-};
-
-struct AddCoffreObject : public Script::Command {
- int object;
-
- AddCoffreObject(const Common::Array<Common::String> &args) : object(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- for (int i = 0; i < kLouvreChestSize; ++i) {
- if (g_louvrePluginState.objectChest[i] == 0) {
- g_louvrePluginState.objectChest[i] = object;
- return;
- }
- }
- }
-};
-
-struct IsPresent : public Script::Command {
- int object;
- Common::String var;
- Common::String negativeVar;
-
- IsPresent(const Common::Array<Common::String> &args) : object(atoi(args[0].c_str())), var(args[1]), negativeVar(args[2]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- bool found = false;
- for (int i = 1; i <= kMessengerInventorySlots; ++i) {
- if (messengerInventorySlot(i) == object) {
- found = true;
- break;
- }
- }
- g_engine->setVariable(var, found);
- g_engine->setVariable(negativeVar, !found);
- }
-};
-
-struct RemoveObject : public Script::Command {
- Common::String object;
-
- RemoveObject(const Common::Array<Common::String> &args) : object(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- int objectId = Script::Command::valueOf(object);
- for (int i = 1; i <= kMessengerInventorySlots; ++i)
- if (messengerInventorySlot(i) == objectId)
- setMessengerInventorySlot(i, 0);
- }
-};
-
-struct Cmp : public Script::Command {
- Common::String var;
- Common::String negativeVar;
- Common::String arg0;
- Common::String op;
- Common::String arg1;
-
- Cmp(const Common::Array<Common::String> &args) : var(args[0]), negativeVar(args[1]), arg0(args[2]), op(args[3]) {
- if (args.size() == 5) {
- arg1 = args[4];
- } else {
- uint opLength = (op.size() > 1 && (op[1] == '=' || op[1] == '>')) ? 2 : 1;
- arg1 = op.substr(opLength);
- op = op.substr(0, opLength);
- }
- }
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("cmp %s %s %s %s %s", var.c_str(), negativeVar.c_str(), arg0.c_str(), op.c_str(), arg1.c_str());
- bool r;
- auto value0 = valueOf(arg0);
- auto value1 = valueOf(arg1);
- if (op == "==") {
- r = value0 == value1;
- } else if (op == "!=" || op == "<>") {
- r = value0 != value1;
- } else if (op == "<") {
- r = value0 < value1;
- } else if (op == "<=") {
- r = value0 <= value1;
- } else if (op == ">") {
- r = value0 > value1;
- } else if (op == ">=") {
- r = value0 >= value1;
- } else {
- error("invalid cmp op %s", op.c_str());
- }
- g_engine->setVariable(var, r);
- g_engine->setVariable(negativeVar, !r);
- }
-};
-
-struct Select : public Script::Command {
- int value;
- Common::String arg0;
- Common::String arg1;
-
- Select(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), arg0(args[1]), arg1(args[2]) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(arg1, 0);
-
- int objectId = messengerInventorySlot(value);
- if (objectId == 0)
- return;
-
- if (g_engine->getVariable("CurrentAction") == 4) {
- g_engine->setVariable(arg0, 1);
- g_engine->setVariable(arg1, 0);
-
- int selectedSlot = g_engine->getVariable("Selection") - 100;
- int selectedObjectId = messengerInventorySlot(selectedSlot);
- int combinedObjectId = louvreCombineObjects(selectedObjectId, objectId);
- if (combinedObjectId != 0) {
- g_engine->setVariable(arg1, 1);
- g_engine->setVariable("CurrentAction", 0);
- setMessengerInventorySlot(selectedSlot, combinedObjectId);
- setMessengerInventorySlot(value, 0);
- drawLouvreInventorySlotObject(selectedSlot, combinedObjectId);
- drawLouvreInventorySlotObject(value, 0);
- drawLouvreActionButtons();
- setLouvreSelectedSlot(selectedSlot, 0);
- }
- return;
- }
-
- setLouvreSelectedSlot(value, 0);
- }
-};
-
-struct DoAction : public Script::Command {
- int value;
- Common::String arg;
-
- DoAction(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), arg(args[1]) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(arg, 0);
-
- int selection = louvreSelectionSlot(g_engine->getVariable("Selection"));
- if (selection == 0)
- return;
-
- int objectId = messengerInventorySlot(selection);
- int actionMask = louvreSelectedObjectActionMask();
-
- int currentAction = g_engine->getVariable("CurrentAction");
- if (!((currentAction == value || currentAction == 0) && (actionMask & value) != 0))
- return;
-
- if (currentAction != 0) {
- setLouvreSelectedSlot(selection, 4);
- g_engine->setVariable("CurrentAction", 0);
- drawLouvreActionButtons();
- return;
- }
-
- g_engine->setVariable(arg, 1);
- switch (value) {
- case 1:
- g_engine->setVariable("Inventaire", objectId);
- break;
- case 2:
- if (louvreObjectCanView(objectId))
- g_engine->setVariable(arg, objectId);
- break;
- case 4:
- g_engine->setVariable("CurrentAction", value);
- setLouvreSelectedSlot(selection + 100, 0);
- drawLouvreActionButtons();
- break;
- case 8:
- g_engine->setVariable("CurrentAction", value);
- drawLouvreActionButtons();
- break;
- default:
- break;
- }
- }
-};
-
-struct IsHere : public Script::Command {
- IsHere(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- int comefrom = g_engine->getVariable("comefrom");
- if (comefrom > 10000000)
- comefrom -= 10000000;
-
- Common::String value = Common::String::format("%d", comefrom);
- if (value.size() >= 3) {
- Common::String name = Common::String::format("P0%cS%c%c", value[0], value[1], value[2]);
- g_engine->playAnimation(name, "y", 20, 20);
- }
- }
-};
-
-struct InitCoffre : public Script::Command {
- InitCoffre(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- int compacted[kLouvreChestSize];
- Common::fill(compacted, compacted + kLouvreChestSize, 0);
-
- int dst = 0;
- for (int i = 0; i < kLouvreChestSize; ++i)
- if (g_louvrePluginState.objectChest[i] != 0)
- compacted[dst++] = g_louvrePluginState.objectChest[i];
-
- Common::copy(compacted, compacted + kLouvreChestSize, g_louvrePluginState.objectChest);
- }
-};
-
-struct LoadCoffre : public Script::Command {
- LoadCoffre(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- for (int i = 0; i < kLouvreChestSize; ++i)
- g_louvrePluginState.objectChest[i] = g_engine->getVariable(Common::String::format("coffre%d", i + 1));
- }
-};
-
-struct SaveCoffre : public Script::Command {
- SaveCoffre(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- for (int i = 0; i < kLouvreChestSize; ++i)
- g_engine->setVariable(Common::String::format("coffre%d", i + 1), g_louvrePluginState.objectChest[i]);
- }
-};
-
-struct ExeDemo : public Script::Command {
- Common::String var;
-
- ExeDemo(const Common::Array<Common::String> &args) : var(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("ExeDemo %s", var.c_str());
- g_engine->setVariable(var, 1);
- }
-};
-
-struct AfficheImage : public Script::Command {
- Common::String image;
- int x;
- int y;
-
- AfficheImage(const Common::Array<Common::String> &args) : image(args[0]), x(atoi(args[1].c_str())), y(atoi(args[2].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->showImageOverlay(image, x, y);
- }
-};
-
-struct StopAffiche : public Script::Command {
- StopAffiche(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->stopImageOverlay();
- }
-};
-
-struct UpdateStage : public Script::Command {
- UpdateStage(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->updateStage();
- }
-};
-
-struct StartCible : public Script::Command {
- Common::String name;
- int periodSeconds;
- Common::Array<int> bounds;
-
- StartCible(const Common::Array<Common::String> &args) : name(args[0]), periodSeconds(atoi(args[1].c_str())) {
- for (uint i = 2; i < args.size(); ++i)
- bounds.push_back(atoi(args[i].c_str()));
- }
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->startCible(name, periodSeconds, bounds);
- }
+ static int valueOf(const Common::String &value);
};
+using CommandPtr = Common::SharedPtr<Command>;
-struct StopCible : public Script::Command {
- StopCible(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->stopCible();
- }
-};
-
-struct TestCible : public Script::Command {
- Common::String xVar;
- Common::String yVar;
-
- TestCible(const Common::Array<Common::String> &args) : xVar(args[0]), yVar(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->testCible(xVar, yVar);
- }
-};
-
-struct AfficheCoffre : public Script::Command {
- AfficheCoffre(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- drawLouvreChest();
- }
-};
-
-struct AfficheSelection : public Script::Command {
- AfficheSelection(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- int selection = louvreSelectionSlot(g_engine->getVariable("Selection"));
- if (selection != 0)
- drawLouvreSelectedObject(selection);
- }
-};
-
-struct AffichePorteF : public Script::Command {
- int value;
- AffichePorteF(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- drawLouvreInventoryObjects(value != 0);
- }
-};
-
-struct SelectPorteF : public Script::Command {
- int value;
- Common::String var;
- SelectPorteF(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), var(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(var, 0);
- if (g_engine->getVariable("CoffreSelect") != 0) {
- exchangeLouvreChestObject(0, value);
- } else if (messengerInventorySlot(value) != 0) {
- setLouvreSelectedSlot(value, 1);
- }
- g_engine->setVariable(var, g_engine->getVariable("Selection") != 0);
- }
-};
-
-struct SelectCoffre : public Script::Command {
- int value;
- Common::String var;
- SelectCoffre(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), var(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(var, 0);
- if (g_engine->getVariable("Selection") != 0) {
- exchangeLouvreChestObject(value, 0);
- } else {
- int index = g_engine->getVariable("CoffreOffset") + value - 1;
- if (index >= 0 && index < kLouvreChestSize && g_louvrePluginState.objectChest[index] != 0)
- drawLouvreChestSelection(value);
- }
- g_engine->setVariable(var, g_engine->getVariable("CoffreSelect") != 0);
- }
-};
-
-struct LoadSave_Init_Slots : public Script::Command {
- int slots;
-
- LoadSave_Init_Slots(const Common::Array<Common::String> &args) : slots(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("LoadSave_Init_Slots %d", slots);
- }
-};
-
-struct LoadSave_Draw_Slot : public Script::Command {
- int slot;
- int face;
- int x;
- int y;
-
- LoadSave_Draw_Slot(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())),
- face(atoi(args[1].c_str())),
- x(atoi(args[2].c_str())),
- y(atoi(args[3].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("LoadSave_Draw_Slot %d %d %d %d", slot, face, x, y);
- g_engine->drawSlot(slot, face, x, y);
- }
-};
-
-struct LoadSave_Test_Slot : public Script::Command {
- int slot;
- Common::String show;
- Common::String hide;
-
- LoadSave_Test_Slot(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())), show(args[1]), hide(args[2]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- bool exists = g_engine->testSaveSlot(slot);
- debug("LoadSave_Test_Slot %d %s %s -> %d", slot, show.c_str(), hide.c_str(), exists);
- g_engine->setVariable(show, exists);
- g_engine->setVariable(hide, !exists);
- }
-};
-
-struct Set : public Script::Command {
- Common::String var;
- Common::String value;
- Set(const Common::Array<Common::String> &args) {
- switch (args.size()) {
- case 2:
- var = args[0];
- value = args[1];
- break;
- case 1: {
- auto pos = args[0].rfind('=');
- if (pos == Common::String::npos)
- pos = args[0].size();
- var = args[0].substr(0, pos);
- value = args[0].c_str() + pos + 1;
- } break;
- default:
- error("invalid plugin set signature");
- }
- }
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->setVariable(var, valueOf(value));
- }
-};
-
-struct Set_Global_Pan : public Script::Command {
- Common::String arg;
- Set_Global_Pan(const Common::Array<Common::String> &args) : arg(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- auto value = valueOf(arg);
- debug("set_global_pan %s -> %d", arg.c_str(), value);
- g_engine->setGlobalPan(value);
- }
-};
-
-struct Set_Global_Volume : public Script::Command {
- Common::String arg;
- Set_Global_Volume(const Common::Array<Common::String> &args) : arg(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- auto value = valueOf(arg);
- debug("set_global_volume %s -> %d", arg.c_str(), value);
- g_engine->setGlobalVolume(value);
- }
-};
-
-struct Op : public Script::Command {
- Common::String var;
- Common::String negativeVar;
- Common::String arg;
- Op(const Common::Array<Common::String> &args) : var(args[0]), negativeVar(args[1]), arg(args[2]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- int value = g_engine->getVariable(arg);
- g_engine->setVariable(var, value);
- g_engine->setVariable(negativeVar, !value);
- }
-};
-
-// Amerzone-specific preload plugin
-struct Preload : public Script::Command {
- Common::String arg;
- Preload(const Common::Array<Common::String> &args) : arg(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("preload %s", arg.c_str());
- if (!arg.empty() && Common::isDigit(arg[0])) {
- g_engine->loadGameState(atoi(arg.c_str()));
- } else {
- auto loaded = g_engine->enterScript();
- debug("preload: loaded: %d", loaded);
- g_engine->setVariable(arg, loaded);
- if (loaded) {
- ctx.running = false;
- }
- }
- }
-};
-
-// Amerzone-specific loadsave plugin
-struct LoadSave : public Script::Command {
- Common::Array<Common::String> args;
- LoadSave(const Common::Array<Common::String> &args_) : args(args_) {}
-
- static bool testSlot(int slot) {
- auto status = g_engine->testSaveSlot(slot);
- if (!status)
- return false;
-
- g_engine->drawSaveCard(slot);
- return true;
- }
-
- void exec(Script::ExecutionContext &ctx) const override {
- uint n = args.size();
- if (n == 3) {
- auto slot = atoi(args[0].c_str());
- auto &var = args[1];
- auto &negativeVar = args[2];
- debug("loadsave %d %s %s", slot, var.c_str(), negativeVar.c_str());
- int status = 0;
- // Amerzone script checks those:
- // 99 -> true, 98 -> false: continue
- // 99 -> true, 98 -> true: initial main menu
- // 99 -> false, 98 -> true: new game
- // false, false -> black screen
- bool restarted = g_engine->wasRestarted();
- bool loaded = g_engine->wasLoaded();
- debug("engine status, loaded: %d, restarted: %d", loaded, restarted);
- if (slot == 99) {
- // special save idx - continue game
- status = !restarted;
- } else if (slot == 98) {
- // special save idx - new game started
- status = !loaded;
- } else if (slot >= 1 && slot <= 8) {
- status = testSlot(slot);
- } else {
- warning("LoadSave slot %d", slot);
- }
- g_engine->setVariable(var, status);
- g_engine->setVariable(negativeVar, !status);
- } else if (n == 2) {
- auto &srcVar = args[0];
- auto &dstVar = args[1];
- debug("loadsave %s %s", srcVar.c_str(), dstVar.c_str());
- if (!dstVar.empty() && Common::isDigit(dstVar[0])) {
- uint level = atoi(dstVar.c_str());
- uint currentLevel = g_engine->currentAmerzoneLevel();
- if (currentLevel != 0) {
- g_engine->setVariable(srcVar, currentLevel == level);
- return;
- }
- }
-
- auto value = g_engine->getVariable(srcVar);
- g_engine->setVariable(srcVar, 0);
- g_engine->setVariable(dstVar, value);
- if (!value) {
- for (int slot = 1; slot <= 8; ++slot)
- testSlot(slot);
- }
- } else {
- warning("LoadSave, %u args", n);
- for (uint i = 0; i < n; ++i)
- warning("LoadSave %u: %s", i, args[i].c_str());
- }
- }
-};
-
-// Amerzone-specific save plugin
-struct Save : public Script::Command {
- int slot;
- Save(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("Save %d", slot);
- g_engine->setContextLabel("Amerzone");
- g_engine->captureContext();
- auto err = g_engine->saveGameState(slot, {});
- if (err.getCode() != Common::ErrorCode::kNoError)
- error("saving state failed %d", slot);
- }
-};
-
-struct LoadSave_Capture_Context : public Script::Command {
- LoadSave_Capture_Context(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("LoadSave_Capture_Context");
- g_engine->captureContext();
- }
-};
-
-struct LoadSave_Context_Restored : public Script::Command {
- Common::String progress;
- Common::String done;
-
- LoadSave_Context_Restored(const Common::Array<Common::String> &args) : progress(args[0]), done(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- int value = g_engine->getVariable(progress);
- debug("LoadSave_Context_Restored: %s -> %d -> %s", progress.c_str(), value, done.c_str());
- g_engine->setVariable(progress, 0);
- g_engine->setVariable(done, value);
- }
-};
-
-struct LoadSave_Load : public Script::Command {
- int slot;
-
- LoadSave_Load(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("LoadSave_Load %d", slot);
- auto err = g_engine->loadGameState(slot);
- if (err.getCode() != Common::ErrorCode::kNoError)
- error("loading state failed %d", slot);
- }
-};
-
-struct LoadSave_Save : public Script::Command {
- int slot;
-
- LoadSave_Save(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("LoadSave_Save %d", slot);
- auto err = g_engine->saveGameState(slot, {});
- if (err.getCode() != Common::ErrorCode::kNoError)
- error("saving state failed %d", slot);
- }
-};
-
-struct LoadSave_Set_Context_Label : public Script::Command {
- Common::String label;
-
- LoadSave_Set_Context_Label(const Common::Array<Common::String> &args) : label(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->setContextLabel(label);
- }
-};
-
-struct Discocier : public Script::Command {
- Common::String var;
- Discocier(const Common::Array<Common::String> &args) : var(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(var, 0);
-
- int selection = g_engine->getVariable("Selection");
- int slot = louvreSelectionSlot(selection);
- int objectId = messengerInventorySlot(slot);
-
- int parts[3] = {0, 0, 0};
- int partCount = 0;
- if (objectId == 3500) {
- partCount = 2;
- parts[0] = g_engine->getVariable("RedPastryA");
- parts[1] = g_engine->getVariable("RedPastryB");
- } else if (objectId == 3700) {
- partCount = 2;
- parts[0] = g_engine->getVariable("YellowSeedA");
- parts[1] = g_engine->getVariable("YellowSeedB");
- } else {
- partCount = louvreSeparateObject(objectId, parts);
- }
-
- g_engine->setVariable("CurrentAction", 0);
- int emptySlots = 0;
- for (int i = 1; i < 9; ++i)
- if (messengerInventorySlot(i) == 0)
- ++emptySlots;
-
- if (partCount > emptySlots + 1) {
- drawLouvreActionButtons();
- drawBlockedLouvreText(28);
- return;
- }
-
- if (partCount == 0)
- return;
-
- setMessengerInventorySlot(slot, 0);
- for (int i = partCount - 1; i >= 0; --i) {
- for (int dstSlot = 1; dstSlot < 9; ++dstSlot) {
- if (messengerInventorySlot(dstSlot) == 0) {
- setMessengerInventorySlot(dstSlot, parts[i]);
- break;
- }
- }
- }
-
- setLouvreSelectedSlot(g_engine->getVariable("Selection"), 2);
- drawLouvreInventoryObjects(true);
- g_engine->setVariable(var, 1);
- }
-};
-
-struct Reset : public Script::Command {
- Reset(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- for (int i = 0; i < kLouvreChestSize; ++i)
- g_louvrePluginState.objectChest[i] = 0;
- for (int i = 1; i <= kMessengerInventorySlots; ++i)
- setMessengerInventorySlot(i, 0);
- }
-};
-
-struct Restart : public Script::Command {
- Restart(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->restart();
- }
-};
-
-struct MemoryRelease : public Script::Command {
- MemoryRelease(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("MemoryRelease");
- }
-};
-
-struct DrawTextSelection : public Script::Command {
- DrawTextSelection(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- if (louvreTextBlocked())
- return;
-
- clearLouvreText();
-
- int selection = louvreSelectionSlot(g_engine->getVariable("Selection"));
- if (selection != 0) {
- int objectId = messengerInventorySlot(selection);
- if (objectId != 0)
- g_engine->drawArchiveText(objectId, kLouvreTextRect, 14, true, kLouvreTextColor);
- }
- }
-};
-
-struct CarteDestination : public Script::Command {
- Common::String varX;
- Common::String varY;
- CarteDestination(const Common::Array<Common::String> &args) : varX(args[0]), varY(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- int comefrom = g_engine->getVariable("comefrom");
- if (comefrom > 10000000)
- comefrom -= 10000000;
-
- Common::String value = Common::String::format("%d", comefrom);
- if (value.size() >= 1)
- g_engine->setVariable(varX, value[0] - '0');
- if (value.size() >= 3)
- g_engine->setVariable(varY, atoi(value.substr(1, 2).c_str()));
- }
-};
-
-struct Scroll : public Script::Command {
- int value;
- Scroll(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- updateLouvreChestScroll(value);
- }
-};
-
-struct Waves : public Script::Command {
- Waves(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->showWaves();
- }
-};
-
-struct Rollover : public Script::Command {
- int textId;
- RolloverType type;
-
- Rollover(const Common::Array<Common::String> &args, RolloverType t = RolloverType::Default) : textId(atoi(args[0].c_str())), type(t) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->rollover(textId, type);
- }
-};
-
-struct RolloverMalette : public Rollover {
- RolloverMalette(const Common::Array<Common::String> &args) : Rollover(args, RolloverType::Malette) {}
-};
-
-struct RolloverSecretaire : public Rollover {
- RolloverSecretaire(const Common::Array<Common::String> &args) : Rollover(args, RolloverType::Secretaire) {}
-};
-
-struct PorteFRollover : public Script::Command {
- int arg;
-
- PorteFRollover(const Common::Array<Common::String> &args) : arg(atoi(args[0].c_str())) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- if (louvreTextBlocked())
- return;
-
- if (arg == 28) {
- drawBlockedLouvreText(arg);
- } else {
- drawLouvreText(arg);
- }
- }
-};
-
-struct SaveVariable : public Script::Command {
- SaveVariable(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->saveVariables();
- }
-};
-
-struct LoadVariable : public Script::Command {
- LoadVariable(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->loadVariables();
- }
-};
-
-struct Init2 : public Script::Command {
- Common::String var;
- Init2(const Common::Array<Common::String> &args) : var(args[0]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->setVariable(var, 0);
- }
-};
-
-struct Init : public Script::Command {
- int value;
- Common::String var;
- Init(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), var(args[1]) {}
- void exec(Script::ExecutionContext &ctx) const override {
- initLouvrePluginState();
- g_engine->setVariable(var, value == 2 ? 1 : 0);
- }
-};
-
-struct End : public Script::Command {
- End(const Common::Array<Common::String> &args) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("plugin end (quit)");
- g_engine->quitGame();
- }
-};
-
-#define PLUGIN_LIST(E) \
- E(Add) \
- E(AddCoffreObject) \
- E(AddObject) \
- E(AfficheCoffre) \
- E(AfficheImage) \
- E(AffichePorteF) \
- E(AfficheSelection) \
- E(CarteDestination) \
- E(ChangeCurseur) \
- E(CopyVar) \
- E(Cmp) \
- E(Discocier) \
- E(DrawTextSelection) \
- E(End) \
- E(ExeDemo) \
- E(GetMonde4) \
- E(SetMonde4) \
- E(Init) \
- E(Init2) \
- E(IsPresent) \
- E(KillTimer) \
- E(InitCoffre) \
- E(IsHere) \
- E(LoadCoffre) \
- E(SaveCoffre) \
- E(SelectPorteF) \
- E(SelectCoffre) \
- E(Op) \
- E(Set) \
- E(Preload) \
- E(LoadSave) \
- E(Save) \
- E(LoadSave_Capture_Context) \
- E(LoadSave_Context_Restored) \
- E(LoadSave_Enter_Script) \
- E(LoadSave_Init_Slots) \
- E(LoadSave_Load) \
- E(LoadSave_Save) \
- E(LoadSave_Set_Context_Label) \
- E(LoadSave_Draw_Slot) \
- E(LoadSave_Test_Slot) \
- E(LoadVariable) \
- E(MemoryRelease) \
- E(MultiCD_Set_Transition_Script) \
- E(MultiCD_If_Next_Script) \
- E(MultiCD_Use_Install_Path) \
- E(MultiCD_Set_Next_Script) \
- E(PauseTimer) \
- E(Play_AnimBloc) \
- E(Play_AnimBloc_Number) \
- E(Play_Movie) \
- E(Reset) \
- E(Restart) \
- E(RemoveObject) \
- E(Rollover) \
- E(RolloverMalette) \
- E(RolloverSecretaire) \
- E(PorteFRollover) \
- E(SaveVariable) \
- E(Select) \
- E(Set_Global_Pan) \
- E(Set_Global_Volume) \
- E(Scroll) \
- E(StartCible) \
- E(StopAffiche) \
- E(Stop_AnimBloc) \
- E(StopCible) \
- E(TestCible) \
- E(DoAction) \
- E(StartTimer) \
- E(Sub) \
- E(Until) \
- E(UpdateStage) \
- E(While) \
- E(Waves) \
- /* */
-
-#define ADD_PLUGIN(NAME) \
- if (cmd.equalsIgnoreCase(#NAME)) \
- return Script::CommandPtr(new NAME(args));
-
-Script::CommandPtr createCommand(const Common::String &cmd, const Common::Array<Common::String> &args, int lineno) {
- PLUGIN_LIST(ADD_PLUGIN)
- error("unhandled plugin command %s at line %d", cmd.c_str(), lineno);
-}
-
-struct IfAnd : public Script::Conditional {
- IfAnd(Common::Array<Common::String> args) : Script::Conditional(Common::move(args)) {}
- void exec(Script::ExecutionContext &ctx) const override {
- bool result = true;
- for (auto &var : vars) {
- if (var.empty() || !g_engine->hasVariable(var))
- continue;
- auto value = g_engine->getVariable(var);
- debug("ifand, %s: %d", var.c_str(), value);
- if (!value)
- result = false;
- }
- if (!result) {
- debug("ifand: not executing conditional block");
- return;
- }
- debug("ifand: executing conditional block");
- target->exec(ctx);
- }
-};
-
-struct IfOr : public Script::Conditional {
- IfOr(Common::Array<Common::String> args) : Script::Conditional(Common::move(args)) {}
- void exec(Script::ExecutionContext &ctx) const override {
- bool result = false;
- for (auto &var : vars) {
- if (var.empty() || !g_engine->hasVariable(var))
- continue;
- auto value = g_engine->getVariable(var);
- debug("ifor, %s: %d", var.c_str(), value);
- if (value)
- result = true;
- }
- if (!result)
- return;
- debug("ifor: executing conditional block");
- target->exec(ctx);
- }
-};
-
-struct SetVar : public Script::Command {
- Common::String name;
- int value;
-
- SetVar(Common::String n, int v) : name(Common::move(n)), value(v) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->setVariable(name, value);
- }
-};
-
-struct GoSub : public Script::Command {
- Common::String label;
- GoSub(const Common::String &l) : label(l) {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("gosub %s", label.c_str());
- auto *scope = ctx.rootScope ? ctx.rootScope : ctx.scope;
- assert(scope);
- auto *labelPtr = scope->findLabel(label);
- if (!labelPtr) {
- warning("gosub: label %s not found", label.c_str());
- return;
- }
- Script::ExecutionContext sub = {};
- sub.subroutine = true;
- sub.rootScope = scope;
- scope->exec(sub, labelPtr->offset);
- }
-};
-
-struct EndScript : public Script::Command {
- EndScript() {}
- void exec(Script::ExecutionContext &ctx) const override {
- debug("end");
- ctx.running = false;
- g_engine->end();
- }
-};
-
-struct Return : public Script::Command {
- Return() {}
- void exec(Script::ExecutionContext &ctx) const override {
- ctx.running = false;
- if (ctx.subroutine) {
- debug("return to caller");
- } else {
- debug("return to previous warp");
- g_engine->returnToWarp();
- }
- }
-};
-
-struct SetCursorDefault : public Script::Command {
- int idx;
- Common::String fname;
- SetCursorDefault(int i, Common::String f) : idx(i), fname(Common::move(f)) {}
- void exec(Script::ExecutionContext &ctx) const override {
- if (idx >= 0)
- g_engine->setCursorDefault(idx, fname);
- }
-};
-
-struct SetCursor : public Script::Command {
- Common::String fname;
- Common::String wname;
- int idx;
- SetCursor(Common::String f, Common::String w, int i) : fname(Common::move(f)), wname(Common::move(w)), idx(i) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->setCursor(fname, wname, idx);
- }
-};
-
-struct HideCursor : public Script::Command {
- Common::String warp;
- int idx;
- HideCursor(Common::String w, int i) : warp(Common::move(w)), idx(i) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->hideCursor(warp, idx);
- }
-};
-
-struct ResetLockKey : public Script::Command {
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->resetLockKey();
- }
-};
-
-struct LockKey : public Script::Command {
- int idx;
- Common::String warp;
-
- LockKey(int i, Common::String w) : idx(i), warp(Common::move(w)) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("lock key %d: %s", idx, warp.c_str());
- g_engine->lockKey(idx, warp);
- }
-};
+struct Scope : public Command {
+ Common::Array<CommandPtr> commands;
-struct SetZoom : public Script::Command {
- float fov;
- SetZoom(float f) : fov(f) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->setZoom(fov);
- }
-};
-
-struct AngleXMax : public Script::Command {
- float xMax;
- AngleXMax(float x) : xMax(x) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("anglexmax %g", xMax);
- g_engine->setXMax(xMax);
- }
-};
-
-struct AngleYMax : public Script::Command {
- float yMin, yMax;
- AngleYMax(float min, float max) : yMin(min), yMax(max) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- if (yMin != yMax) {
- debug("angleymax %g %g", yMin, yMax);
- g_engine->setYMax(yMin, yMax);
- } else {
- debug("angleymax: reset");
- g_engine->resetYMax();
- }
- }
-};
-
-struct SetAngle : public Script::Command {
- float x, y;
- SetAngle(float x_, float y_) : x(x_), y(y_) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("setangle %g %g", x, y);
- g_engine->setAngle(x, y);
- }
-};
-
-struct SetNord : public Script::Command {
- float angle;
- SetNord(float a) : angle(a) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- debug("setnord %g", angle);
- g_engine->setNord(angle);
- }
-};
-
-struct InterpolAngle : public Script::Command {
- float x, y, speed, zoom;
-
- InterpolAngle(float x_, float y_, float s, float z) : x(x_), y(y_), speed(s), zoom(z) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->interpolateAngle(x, y, speed, zoom);
- }
-};
-
-struct GoToWarp : public Script::Command {
- Common::String warp;
- GoToWarp(Common::String w) : warp(Common::move(w)) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- // terminate script after successful warp.
- // continue if not (for instance, goto to the same location)
- if (g_engine->goToWarp(warp))
- ctx.running = false;
- }
-};
-
-struct PlaySound : public Script::Command {
- Common::String sound;
- int volume;
- int loops;
- Audio::Mixer::SoundType type;
-
- PlaySound(Common::String s, int v, int l, Audio::Mixer::SoundType t = Audio::Mixer::kSFXSoundType) : sound(Common::move(s)), volume(v), loops(l), type(t) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->playSound(sound, type, volume, loops);
- }
-};
-
-struct PlayRndSound : public PlaySound {
- int probability;
-
- PlayRndSound(Common::String s, int v, int p, int l, Audio::Mixer::SoundType t = Audio::Mixer::kSFXSoundType) : PlaySound(Common::move(s), v, l, t), probability(p) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->playRandomSound(sound, type, volume, probability, loops);
- }
-};
-
-struct PlayMusique : public PlaySound {
- PlayMusique(Common::String s, int v) : PlaySound(Common::move(s), v, -1, Audio::Mixer::kMusicSoundType) {}
-};
-
-struct StopSound : public Script::Command {
- Common::String sound;
-
- StopSound(Common::String s) : sound(Common::move(s)) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->stopSound(sound);
- }
-};
-
-struct PlaySound3D : public Script::Command {
- Common::String sound;
- int volume;
- float angle;
- int loops;
-
- PlaySound3D(Common::String s, int v, float a, int l) : sound(Common::move(s)), volume(v), angle(a), loops(l) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->playSound(sound, Audio::Mixer::kSFXSoundType, volume, loops, true, angle);
- }
-};
-
-struct StopSound3D : public Script::Command {
- Common::String sound;
-
- StopSound3D(Common::String s) : sound(Common::move(s)) {}
-
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->stopSound(sound);
- }
-};
-
-struct Fade : public Script::Command {
- int start, stop, speed;
+ struct Label {
+ Common::String name;
+ uint offset;
+ };
+ Common::Array<Label> labels;
- Fade(int a0, int a1, int a2) : start(a0), stop(a1), speed(a2) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->fade(start, stop, speed);
+ const Label *findLabel(const Common::String &name) const {
+ auto it = Common::find_if(labels.begin(), labels.end(), [&](const Label &label) { return label.name.equalsIgnoreCase(name); });
+ return it != labels.end() ? &*it : nullptr;
}
-};
-
-struct Transfade : public Script::Command {
- int speed;
- Transfade(int a0) : speed(a0) {}
- void exec(Script::ExecutionContext &ctx) const override {
- g_engine->transFade(speed);
- }
+ void exec(ExecutionContext &ctx) const override;
+ void exec(ExecutionContext &ctx, uint offset) const;
};
+using ScopePtr = Common::SharedPtr<Scope>;
-} // namespace
} // namespace PhoenixVR
#endif
diff --git a/engines/phoenixvr/commands_v1.cpp b/engines/phoenixvr/commands_v1.cpp
new file mode 100644
index 00000000000..12275ff1655
--- /dev/null
+++ b/engines/phoenixvr/commands_v1.cpp
@@ -0,0 +1,2031 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "phoenixvr/commands_v1.h"
+#include "common/debug.h"
+#include "common/rect.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "phoenixvr/parser.h"
+#include "phoenixvr/phoenixvr.h"
+
+namespace PhoenixVR {
+
+namespace {
+constexpr int kMessengerInventorySlots = 12;
+constexpr int kMessengerDisplayedInventorySlots = 8;
+constexpr int kLouvreChestSize = 128;
+constexpr Common::Rect kLouvreTextRect({62, 402}, 292, 64);
+constexpr uint16 kLouvreTextColor = 1987;
+constexpr uint16 kLouvreWarningTextColor = 63687;
+constexpr uint32 kLouvreTextBlockMillis = 5000;
+
+struct LouvrePluginState {
+ int objectChest[kLouvreChestSize];
+ int monde4;
+ uint32 rolloverBlockedUntil;
+ bool initialized;
+};
+
+LouvrePluginState g_louvrePluginState;
+
+void initLouvrePluginState() {
+ if (g_louvrePluginState.initialized)
+ return;
+
+ for (int i = 0; i < kLouvreChestSize; ++i)
+ g_louvrePluginState.objectChest[i] = 0;
+ g_louvrePluginState.monde4 = 0;
+ g_louvrePluginState.rolloverBlockedUntil = 0;
+ g_louvrePluginState.initialized = true;
+}
+
+Common::String messengerInventorySlotName(int slot) {
+ return Common::String::format("Pos%d", slot);
+}
+
+int louvreSelectionSlot(int selection) {
+ return selection > 100 ? selection - 100 : selection;
+}
+
+int messengerInventorySlot(int slot) {
+ if (slot < 1 || slot > kMessengerInventorySlots)
+ return 0;
+
+ return g_engine->getVariable(messengerInventorySlotName(slot));
+}
+
+void setMessengerInventorySlot(int slot, int objectId) {
+ if (slot >= 1 && slot <= kMessengerInventorySlots)
+ g_engine->setVariable(messengerInventorySlotName(slot), objectId);
+}
+
+int messengerSpecialObjectSlot(int objectId) {
+ static const int kSpecialObjects[] = {300, 100, 200, 400};
+
+ for (uint i = 0; i < ARRAYSIZE(kSpecialObjects); ++i) {
+ if (kSpecialObjects[i] == objectId)
+ return i + 9;
+ }
+ return 0;
+}
+
+Common::String louvreObjectImage(int objectId, int suffix) {
+ return Common::String::format("Obj%02d%02d.bmp", objectId / 100, suffix);
+}
+
+void drawLouvreImage(const Common::String &image, int x, int y) {
+ g_engine->drawArchiveImage(image, x, y);
+}
+
+void drawLouvreText(int textId, uint16 color = kLouvreTextColor) {
+ drawLouvreImage("EffaceText.bmp", kLouvreTextRect.left, kLouvreTextRect.top);
+ g_engine->clearArchiveText(kLouvreTextRect);
+ g_engine->drawArchiveText(textId, kLouvreTextRect, 14, true, color);
+}
+
+void clearLouvreText() {
+ drawLouvreImage("EffaceText.bmp", kLouvreTextRect.left, kLouvreTextRect.top);
+ g_engine->clearArchiveText(kLouvreTextRect);
+}
+
+bool louvreTextBlocked() {
+ return g_louvrePluginState.rolloverBlockedUntil > g_system->getMillis();
+}
+
+void drawBlockedLouvreText(int textId) {
+ drawLouvreText(textId, kLouvreWarningTextColor);
+ g_louvrePluginState.rolloverBlockedUntil = g_system->getMillis() + kLouvreTextBlockMillis;
+}
+
+template<size_t N>
+bool louvreContainsObject(const int (&objects)[N], int objectId) {
+ for (int object : objects)
+ if (object == objectId)
+ return true;
+ return false;
+}
+
+bool louvreObjectCanView(int objectId) {
+ static const int kViewableObjects[] = {3000, 3100, 4200, 4300, 5500, 5900, 7600, 7700, 7800, 8500, 8600, 8800};
+ return louvreContainsObject(kViewableObjects, objectId);
+}
+
+int louvreCombineObjects(int selectedObjectId, int objectId) {
+ struct CombineEntry {
+ int left;
+ int right;
+ int result;
+ };
+ static const CombineEntry kCombineTable[] = {
+ {500, 1200, 1300},
+ {500, 600, 1400},
+ {500, 700, 9600},
+ {9600, 600, 1500},
+ {1400, 700, 1500},
+ {3000, 2900, 3100},
+ {2300, 2200, 3500},
+ {2100, 2200, 3500},
+ {2100, 2300, 3500},
+ {3500, 2100, 3600},
+ {3500, 2200, 3600},
+ {3500, 2300, 3600},
+ {1800, 2600, 3700},
+ {1800, 1700, 3700},
+ {2600, 1700, 3700},
+ {3700, 1800, 3800},
+ {3700, 2600, 3800},
+ {3700, 1700, 3800},
+ {4200, 3400, 4300},
+ {4400, 6100, 6200},
+ {4400, 6000, 6300},
+ {6200, 6000, 6400},
+ {6300, 6100, 6400},
+ {7700, 3400, 7800},
+ {6900, 8200, 9800},
+ {9300, 7000, 9900}};
+
+ for (const CombineEntry &entry : kCombineTable) {
+ if ((entry.left == selectedObjectId && entry.right == objectId) ||
+ (entry.left == objectId && entry.right == selectedObjectId)) {
+ if (entry.result == 3500) {
+ g_engine->setVariable("RedPastryA", selectedObjectId);
+ g_engine->setVariable("RedPastryB", objectId);
+ } else if (entry.result == 3700) {
+ g_engine->setVariable("YellowSeedA", selectedObjectId);
+ g_engine->setVariable("YellowSeedB", objectId);
+ }
+ return entry.result;
+ }
+ }
+
+ return 0;
+}
+
+int louvreSeparateObject(int objectId, int *parts) {
+ struct SeparateEntry {
+ int object;
+ int parts[3];
+ };
+ static const SeparateEntry kSeparateTable[] = {
+ {1300, {500, 1200, 0}},
+ {1400, {500, 600, 0}},
+ {1500, {1400, 700, 0}},
+ {3100, {3000, 2900, 0}},
+ {3600, {3500, 2100, 0}},
+ {3800, {3700, 1800, 0}},
+ {4300, {4200, 3400, 0}},
+ {6200, {4400, 6100, 0}},
+ {6300, {4400, 6000, 0}},
+ {6400, {6200, 6000, 0}},
+ {7800, {7700, 3400, 0}},
+ {9600, {500, 700, 0}},
+ {9800, {6900, 8200, 0}},
+ {9900, {9300, 7000, 0}},
+ };
+
+ for (const SeparateEntry &entry : kSeparateTable) {
+ if (entry.object == objectId) {
+ Common::copy(entry.parts, entry.parts + ARRAYSIZE(entry.parts), parts);
+ return entry.parts[2] != 0 ? 3 : 2;
+ }
+ }
+
+ return 0;
+}
+
+bool louvreObjectCanCombine(int objectId) {
+ static const int kCombinableObjects[] = {
+ 500, 600, 700, 1200, 1300, 1400, 1500, 1700, 1800, 2100, 2200, 2300, 2600, 2900,
+ 3000, 3100, 3400, 3500, 3600, 3700, 3800, 4200, 4300, 4400, 6000, 6100, 6200,
+ 6300, 6400, 6900, 7000, 7700, 7800, 8200, 9300, 9600, 9800, 9900};
+ return louvreContainsObject(kCombinableObjects, objectId);
+}
+
+bool louvreObjectCanSeparate(int objectId) {
+ if (objectId == 3500 || objectId == 3700)
+ return true;
+
+ int parts[3] = {0, 0, 0};
+ return louvreSeparateObject(objectId, parts) != 0;
+}
+
+int louvreObjectActionMask(int objectId) {
+ if (objectId == 0)
+ return 0;
+ if (messengerSpecialObjectSlot(objectId) != 0)
+ return 1;
+
+ int mask = 1;
+ if (louvreObjectCanView(objectId))
+ mask |= 2;
+ if (louvreObjectCanCombine(objectId))
+ mask |= 4;
+ if (louvreObjectCanSeparate(objectId))
+ mask |= 8;
+ return mask;
+}
+
+int louvreSelectedObjectActionMask() {
+ return louvreObjectActionMask(messengerInventorySlot(louvreSelectionSlot(g_engine->getVariable("Selection"))));
+}
+
+void drawLouvreActionButtons() {
+ static const int kActionButtonX[] = {21, 22, 25, 24};
+ static const int kActionButtonY[] = {145, 191, 270, 318};
+ static const int kActionValues[] = {1, 2, 4, 8};
+
+ int mask = louvreSelectedObjectActionMask();
+ int currentAction = g_engine->getVariable("CurrentAction");
+ for (uint i = 0; i < ARRAYSIZE(kActionValues); ++i) {
+ drawLouvreImage(Common::String::format("Bout%04d.bmp", i + 1), kActionButtonX[i], kActionButtonY[i]);
+ if ((mask & kActionValues[i]) != 0)
+ drawLouvreImage(Common::String::format("Bout%04d.bmp", i + 11), kActionButtonX[i], kActionButtonY[i]);
+ }
+
+ for (uint i = 0; i < ARRAYSIZE(kActionValues); ++i) {
+ if (currentAction == kActionValues[i])
+ drawLouvreImage(Common::String::format("Bout%04d.bmp", i + 21), kActionButtonX[i], kActionButtonY[i]);
+ }
+}
+
+void drawLouvreSelectionMarker(int slot, int imageNumber, bool selected) {
+ static const Common::Point kSlotSelectedPos[kMessengerInventorySlots] = {
+ Common::Point(389, 82),
+ Common::Point(482, 83),
+ Common::Point(574, 84),
+ Common::Point(456, 170),
+ Common::Point(556, 178),
+ Common::Point(476, 258),
+ Common::Point(567, 268),
+ Common::Point(552, 352),
+ Common::Point(8, 32),
+ Common::Point(93, 32),
+ Common::Point(182, 27),
+ Common::Point(264, 28)};
+
+ if (slot >= 1 && slot <= kMessengerInventorySlots && imageNumber > 0)
+ drawLouvreImage(Common::String::format(selected ? "Sel%04d.bmp" : "DSel%04d.bmp", imageNumber), kSlotSelectedPos[slot - 1].x, kSlotSelectedPos[slot - 1].y);
+}
+
+void drawLouvreSelectedObject(int objectSlot) {
+ static const int kSelectedObjectX = 103;
+ static const int kSelectedObjectY = 123;
+
+ initLouvrePluginState();
+ objectSlot = louvreSelectionSlot(objectSlot);
+ if (objectSlot < 1 || objectSlot > kMessengerInventorySlots)
+ return;
+
+ int objectId = messengerInventorySlot(objectSlot);
+ if (objectId == 0)
+ return;
+
+ drawLouvreImage(louvreObjectImage(objectId, 0), kSelectedObjectX, kSelectedObjectY);
+ clearLouvreText();
+ drawLouvreActionButtons();
+ drawLouvreSelectionMarker(objectSlot, objectSlot, true);
+}
+
+void clearLouvreSelection(bool clearObjectPreview = true) {
+ int selection = g_engine->getVariable("Selection");
+ int slot = louvreSelectionSlot(selection);
+
+ g_engine->setVariable("Selection", 0);
+ if (clearObjectPreview) {
+ drawLouvreImage(louvreObjectImage(0, 0), 103, 123);
+ clearLouvreText();
+ drawLouvreActionButtons();
+ }
+ drawLouvreSelectionMarker(slot, selection, false);
+}
+
+void setLouvreSelectedSlot(int slot, int flags) {
+ int previousSelection = g_engine->getVariable("Selection");
+ int previousSlot = louvreSelectionSlot(previousSelection);
+ int targetSlot = louvreSelectionSlot(slot);
+
+ if (previousSelection == slot && (flags & 2) == 0) {
+ clearLouvreSelection((flags & 1) == 0);
+ return;
+ }
+
+ g_engine->setVariable("Selection", slot);
+ drawLouvreSelectionMarker(previousSlot, previousSelection, false);
+ drawLouvreSelectionMarker(targetSlot, slot, true);
+
+ if ((slot < 100 || (flags & 2) != 0) && (flags & 5) == 0)
+ drawLouvreSelectedObject(slot);
+}
+
+Common::String louvreNumberedImageName(const char *prefix, int value) {
+ return Common::String::format("%s%04d", prefix, value);
+}
+
+int louvreChestLastUsedIndex() {
+ for (int i = kLouvreChestSize - 1; i >= 0; --i)
+ if (g_louvrePluginState.objectChest[i] != 0)
+ return i + 1;
+ return 0;
+}
+
+void drawLouvreChestScrollButtons() {
+ static const Common::Point kUpButtonPos(191, 17);
+ static const Common::Point kDownButtonPos(198, 375);
+
+ int offset = g_engine->getVariable("CoffreOffset");
+ int count = louvreChestLastUsedIndex();
+ drawLouvreImage(offset <= 0 ? "CBou0001" : "CBou0011", kUpButtonPos.x, kUpButtonPos.y);
+ drawLouvreImage(offset >= count - 1 || offset >= 124 ? "CBou0002" : "CBou0012", kDownButtonPos.x, kDownButtonPos.y);
+}
+
+void drawLouvreChestSlot(int slot) {
+ static const Common::Point kChestImagePos[] = {
+ Common::Point(80, 82), Common::Point(80, 145), Common::Point(80, 210), Common::Point(80, 273)};
+ static const Common::Rect kChestTextRect[] = {
+ Common::Rect(138, 80, 324, 134),
+ Common::Rect(138, 145, 324, 199),
+ Common::Rect(138, 208, 324, 262),
+ Common::Rect(138, 272, 324, 326)};
+
+ int index = g_engine->getVariable("CoffreOffset") + slot - 1;
+ int objectId = (index >= 0 && index < kLouvreChestSize) ? g_louvrePluginState.objectChest[index] : 0;
+ drawLouvreImage(louvreNumberedImageName("Cof", objectId + 1), kChestImagePos[slot - 1].x, kChestImagePos[slot - 1].y);
+ drawLouvreImage(louvreNumberedImageName("CText", slot), kChestTextRect[slot - 1].left, kChestTextRect[slot - 1].top);
+ g_engine->clearArchiveText(kChestTextRect[slot - 1]);
+ if (objectId != 0)
+ g_engine->drawArchiveText(objectId, kChestTextRect[slot - 1], 12, false, 1987);
+}
+
+void drawLouvreChest() {
+ for (int slot = 1; slot < 5; ++slot)
+ drawLouvreChestSlot(slot);
+}
+
+void drawLouvreChestSelection(int slot) {
+ static const Common::Point kChestSelectionPos[] = {
+ Common::Point(69, 70), Common::Point(70, 134), Common::Point(70, 199), Common::Point(70, 262), Common::Point(70, 326)};
+
+ int current = g_engine->getVariable("CoffreSelect");
+ if (current != 0 && current <= 4) {
+ drawLouvreImage(louvreNumberedImageName("CDel", current), kChestSelectionPos[current - 1].x, kChestSelectionPos[current - 1].y);
+ drawLouvreImage(louvreNumberedImageName("CDel", current + 1), kChestSelectionPos[current].x, kChestSelectionPos[current].y);
+ }
+
+ if (slot == 0 || current == slot) {
+ g_engine->setVariable("CoffreSelect", 0);
+ return;
+ }
+
+ drawLouvreImage(louvreNumberedImageName("Cel", slot), kChestSelectionPos[slot - 1].x, kChestSelectionPos[slot - 1].y);
+ drawLouvreImage(louvreNumberedImageName("Cel", slot + 1), kChestSelectionPos[slot].x, kChestSelectionPos[slot].y);
+ g_engine->setVariable("CoffreSelect", slot);
+}
+
+void drawLouvreInventorySlotObject(int slot, int objectId) {
+ static const Common::Point kInventoryObjectPos[] = {
+ Common::Point(381, 28),
+ Common::Point(477, 28),
+ Common::Point(565, 28),
+ Common::Point(452, 116),
+ Common::Point(549, 123),
+ Common::Point(468, 204),
+ Common::Point(558, 212),
+ Common::Point(548, 300),
+ Common::Point(18, 13),
+ Common::Point(104, 20),
+ Common::Point(193, 12),
+ Common::Point(273, 15)};
+
+ if (slot >= 1 && slot <= kMessengerInventorySlots && (slot <= kMessengerDisplayedInventorySlots || objectId != 0))
+ drawLouvreImage(louvreNumberedImageName("Obj", objectId + 1), kInventoryObjectPos[slot - 1].x, kInventoryObjectPos[slot - 1].y);
+}
+
+void drawLouvreInventoryObjects(bool includeSpecialSlots) {
+ for (int slot = 1; slot < (includeSpecialSlots ? 13 : 9); ++slot)
+ drawLouvreInventorySlotObject(slot, messengerInventorySlot(slot));
+}
+
+void updateLouvreChestScroll(int direction) {
+ int offset = g_engine->getVariable("CoffreOffset");
+ int count = louvreChestLastUsedIndex();
+ if (direction == 1)
+ offset -= 3;
+ else if (direction == 2)
+ offset += 3;
+
+ offset = CLIP(offset, 0, MIN(124, MAX(0, count - 1)));
+ if (offset != g_engine->getVariable("CoffreOffset")) {
+ g_engine->setVariable("CoffreSelect", 0);
+ g_engine->setVariable("CoffreOffset", offset);
+ drawLouvreChest();
+ }
+ drawLouvreChestScrollButtons();
+}
+
+void exchangeLouvreChestObject(int chestSlot, int inventorySlot) {
+ if (chestSlot == 0)
+ chestSlot = g_engine->getVariable("CoffreSelect");
+ if (inventorySlot == 0)
+ inventorySlot = g_engine->getVariable("Selection");
+ inventorySlot = louvreSelectionSlot(inventorySlot);
+
+ if (chestSlot < 1 || chestSlot > 4 || inventorySlot < 1 || inventorySlot > kMessengerInventorySlots)
+ return;
+
+ int chestIndex = g_engine->getVariable("CoffreOffset") + chestSlot - 1;
+ if (chestIndex < 0 || chestIndex >= kLouvreChestSize)
+ return;
+ if (louvreChestLastUsedIndex() == 0)
+ g_engine->setVariable("CoffreOffset", 0);
+
+ int inventoryObject = messengerInventorySlot(inventorySlot);
+ int chestObject = g_louvrePluginState.objectChest[chestIndex];
+ g_louvrePluginState.objectChest[chestIndex] = inventoryObject;
+ setMessengerInventorySlot(inventorySlot, chestObject);
+ drawLouvreInventorySlotObject(inventorySlot, chestObject);
+ drawLouvreChestSlot(chestSlot);
+ drawLouvreChestSelection(0);
+ g_engine->setVariable("Selection", 0);
+ updateLouvreChestScroll(0);
+}
+
+struct MultiCD_Use_Install_Path : public Command {
+ Common::String path;
+
+ MultiCD_Use_Install_Path(const Common::Array<Common::String> &args) : path(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("MultiCD_Use_Install_Path %s", path.c_str());
+ }
+};
+
+struct MultiCD_Set_Transition_Script : public Command {
+ Common::String path;
+
+ MultiCD_Set_Transition_Script(const Common::Array<Common::String> &args) : path(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("MultiCD_Set_Transition_Script %s", path.c_str());
+ }
+};
+
+struct MultiCD_Set_Next_Script : public Command {
+ Common::String filename;
+
+ MultiCD_Set_Next_Script(const Common::Array<Common::String> &args) : filename(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("MultiCD_Set_Next_Script %s", filename.c_str());
+ g_engine->setNextScript(filename);
+ }
+};
+
+struct MultiCD_If_Next_Script : public Command {
+ Common::String cd;
+ Common::String var;
+
+ MultiCD_If_Next_Script(const Common::Array<Common::String> &args) : cd(args[0]), var(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("MultiCD_If_Next_Script %s %s", cd.c_str(), var.c_str());
+ }
+};
+
+struct LoadSave_Enter_Script : public Command {
+ Common::String reloading, notReloading;
+
+ LoadSave_Enter_Script(const Common::Array<Common::String> &args) : reloading(args[0]), notReloading(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("LoadSave_Enter_Script %s, %s", reloading.c_str(), notReloading.c_str());
+ auto loading = g_engine->enterScript();
+ g_engine->setVariable(reloading, loading);
+ g_engine->setVariable(notReloading, !loading);
+ }
+};
+
+struct Play_Movie : public Command {
+ Common::String filename;
+
+ Play_Movie(const Common::Array<Common::String> &args) : filename(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->playMovie(filename);
+ }
+};
+
+struct Play_AnimBloc : public Command {
+ Common::String name;
+ Common::String dstVar;
+ int dstVarValue;
+ float speed; // ticks per second
+
+ Play_AnimBloc(const Common::Array<Common::String> &args) : name(args[0]), dstVar(args[1]), dstVarValue(atoi(args[2].c_str())), speed(args.size() >= 4 ? atof(args[3].c_str()) : 25) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("Play_AnimBloc %s %s %d %g", name.c_str(), dstVar.c_str(), dstVarValue, speed);
+ g_engine->playAnimation(name, dstVar, dstVarValue, speed);
+ }
+};
+
+struct Stop_AnimBloc : public Command {
+ Common::String name;
+
+ Stop_AnimBloc(const Common::Array<Common::String> &args) : name(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("Stop_AnimBloc %s", name.c_str());
+ g_engine->stopAnimation(name);
+ }
+};
+
+struct Play_AnimBloc_Number : public Command {
+ Common::String prefix, var;
+ Common::String dstVar;
+ int dstVarValue;
+ float speed;
+
+ Play_AnimBloc_Number(const Common::Array<Common::String> &args) : prefix(args[0]), var(args[1]),
+ dstVar(args[2]), dstVarValue(atoi(args[3].c_str())),
+ speed(args.size() >= 5 ? atof(args[4].c_str()) : 25) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("Play_AnimBloc_Number %s %s %s %d, %g", prefix.c_str(), var.c_str(), dstVar.c_str(), dstVarValue, speed);
+ int value = g_engine->getVariable(var);
+ auto name = Common::String::format("%s%04d", prefix.c_str(), value);
+ g_engine->playAnimation(name, dstVar, dstVarValue, speed);
+ }
+};
+
+struct Until : public Command {
+ Common::String var;
+ int value;
+
+ Until(const Common::Array<Common::String> &args) : var(args[0]), value(atoi(args[1].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->until(var, value);
+ }
+};
+
+struct While : public Command {
+ float seconds;
+
+ While(const Common::Array<Common::String> &args) : seconds(atof(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->wait(seconds);
+ }
+};
+
+struct StartTimer : public Command {
+ float seconds;
+ bool showTimer;
+
+ StartTimer(const Common::Array<Common::String> &args) : seconds(atof(args[0].c_str())), showTimer(args.size() < 2 || atoi(args[1].c_str()) != 0) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("starttimer %g %d", seconds, showTimer);
+ g_engine->startTimer(seconds, showTimer);
+ }
+};
+
+struct PauseTimer : public Command {
+ int paused, deactivate;
+
+ PauseTimer(const Common::Array<Common::String> &args) : paused(atoi(args[0].c_str())), deactivate(atoi(args[1].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("pausetimer %d %d", paused, deactivate);
+ g_engine->pauseTimer(paused, deactivate);
+ }
+};
+
+struct KillTimer : public Command {
+ KillTimer(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("killtimer");
+ g_engine->killTimer();
+ }
+};
+
+struct ChangeCurseur : public Command {
+ int cursor;
+ ChangeCurseur(const Common::Array<Common::String> &args) : cursor(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("changecurseur %d", cursor);
+ g_engine->scheduleTest(cursor);
+ }
+};
+
+struct Add : public Command {
+ Common::String dstVar;
+ Common::String arg0;
+ Common::String arg1;
+
+ Add(const Common::Array<Common::String> &args) : dstVar(args[0]), arg0(args[1]), arg1(args[2]) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("add %s %s %s", dstVar.c_str(), arg0.c_str(), arg1.c_str());
+ g_engine->setVariable(dstVar, valueOf(arg0) + valueOf(arg1));
+ }
+};
+
+struct Sub : public Command {
+ Common::String dstVar;
+ Common::String arg0;
+ Common::String arg1;
+
+ Sub(const Common::Array<Common::String> &args) : dstVar(args[0]), arg0(args[1]), arg1(args[2]) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("sub %s %s %s", dstVar.c_str(), arg0.c_str(), arg1.c_str());
+ g_engine->setVariable(dstVar, valueOf(arg0) - valueOf(arg1));
+ }
+};
+
+struct CopyVar : public Command {
+ Common::String srcVar;
+ Common::String dstVar;
+
+ CopyVar(const Common::Array<Common::String> &args) : srcVar(args[0]), dstVar(args[1]) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("copyvar %s %s", srcVar.c_str(), dstVar.c_str());
+ g_engine->setVariable(dstVar, g_engine->getVariable(srcVar));
+ }
+};
+
+struct Not : public Command {
+ Common::String var;
+
+ Not(Common::String v) : var(Common::move(v)) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("not %s", var.c_str());
+ g_engine->setVariable(var, g_engine->getVariable(var) ? 0 : 1);
+ }
+};
+
+struct GetMonde4 : public Command {
+ Common::String var;
+ Common::String negativeVar;
+
+ GetMonde4(const Common::Array<Common::String> &args) : var(args[0]), negativeVar(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(var, g_louvrePluginState.monde4);
+ g_engine->setVariable(negativeVar, g_louvrePluginState.monde4 == 0);
+ }
+};
+
+struct SetMonde4 : public Command {
+ int value;
+
+ SetMonde4(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_louvrePluginState.monde4 = value;
+ }
+};
+
+struct AddObject : public Command {
+ int object;
+ Common::String var;
+ Common::String negativeVar;
+
+ AddObject(const Common::Array<Common::String> &args) : object(atoi(args[0].c_str())), var(args[1]), negativeVar(args[2]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+
+ g_engine->setVariable(var, 1);
+ g_engine->setVariable(negativeVar, 0);
+ g_engine->setVariable("AddObjectOk", 0);
+
+ int slot = messengerSpecialObjectSlot(object);
+ if (slot != 0) {
+ setMessengerInventorySlot(slot, object);
+ g_engine->setVariable("Selection", slot);
+ return;
+ }
+
+ for (slot = 1; slot < 9; ++slot) {
+ if (messengerInventorySlot(slot) == 0) {
+ setMessengerInventorySlot(slot, object);
+ g_engine->setVariable("Selection", slot);
+ return;
+ }
+ }
+
+ g_engine->setVariable("Selection", 0);
+ g_engine->setVariable("AddObjectOk", 1);
+ g_engine->setVariable(var, 0);
+ g_engine->setVariable(negativeVar, 1);
+ }
+};
+
+struct AddCoffreObject : public Command {
+ int object;
+
+ AddCoffreObject(const Common::Array<Common::String> &args) : object(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ for (int i = 0; i < kLouvreChestSize; ++i) {
+ if (g_louvrePluginState.objectChest[i] == 0) {
+ g_louvrePluginState.objectChest[i] = object;
+ return;
+ }
+ }
+ }
+};
+
+struct IsPresent : public Command {
+ int object;
+ Common::String var;
+ Common::String negativeVar;
+
+ IsPresent(const Common::Array<Common::String> &args) : object(atoi(args[0].c_str())), var(args[1]), negativeVar(args[2]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ bool found = false;
+ for (int i = 1; i <= kMessengerInventorySlots; ++i) {
+ if (messengerInventorySlot(i) == object) {
+ found = true;
+ break;
+ }
+ }
+ g_engine->setVariable(var, found);
+ g_engine->setVariable(negativeVar, !found);
+ }
+};
+
+struct RemoveObject : public Command {
+ Common::String object;
+
+ RemoveObject(const Common::Array<Common::String> &args) : object(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ int objectId = Command::valueOf(object);
+ for (int i = 1; i <= kMessengerInventorySlots; ++i)
+ if (messengerInventorySlot(i) == objectId)
+ setMessengerInventorySlot(i, 0);
+ }
+};
+
+struct Cmp : public Command {
+ Common::String var;
+ Common::String negativeVar;
+ Common::String arg0;
+ Common::String op;
+ Common::String arg1;
+
+ Cmp(const Common::Array<Common::String> &args) : var(args[0]), negativeVar(args[1]), arg0(args[2]), op(args[3]) {
+ if (args.size() == 5) {
+ arg1 = args[4];
+ } else {
+ uint opLength = (op.size() > 1 && (op[1] == '=' || op[1] == '>')) ? 2 : 1;
+ arg1 = op.substr(opLength);
+ op = op.substr(0, opLength);
+ }
+ }
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("cmp %s %s %s %s %s", var.c_str(), negativeVar.c_str(), arg0.c_str(), op.c_str(), arg1.c_str());
+ bool r;
+ auto value0 = valueOf(arg0);
+ auto value1 = valueOf(arg1);
+ if (op == "==") {
+ r = value0 == value1;
+ } else if (op == "!=" || op == "<>") {
+ r = value0 != value1;
+ } else if (op == "<") {
+ r = value0 < value1;
+ } else if (op == "<=") {
+ r = value0 <= value1;
+ } else if (op == ">") {
+ r = value0 > value1;
+ } else if (op == ">=") {
+ r = value0 >= value1;
+ } else {
+ error("invalid cmp op %s", op.c_str());
+ }
+ g_engine->setVariable(var, r);
+ g_engine->setVariable(negativeVar, !r);
+ }
+};
+
+struct Select : public Command {
+ int value;
+ Common::String arg0;
+ Common::String arg1;
+
+ Select(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), arg0(args[1]), arg1(args[2]) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(arg1, 0);
+
+ int objectId = messengerInventorySlot(value);
+ if (objectId == 0)
+ return;
+
+ if (g_engine->getVariable("CurrentAction") == 4) {
+ g_engine->setVariable(arg0, 1);
+ g_engine->setVariable(arg1, 0);
+
+ int selectedSlot = g_engine->getVariable("Selection") - 100;
+ int selectedObjectId = messengerInventorySlot(selectedSlot);
+ int combinedObjectId = louvreCombineObjects(selectedObjectId, objectId);
+ if (combinedObjectId != 0) {
+ g_engine->setVariable(arg1, 1);
+ g_engine->setVariable("CurrentAction", 0);
+ setMessengerInventorySlot(selectedSlot, combinedObjectId);
+ setMessengerInventorySlot(value, 0);
+ drawLouvreInventorySlotObject(selectedSlot, combinedObjectId);
+ drawLouvreInventorySlotObject(value, 0);
+ drawLouvreActionButtons();
+ setLouvreSelectedSlot(selectedSlot, 0);
+ }
+ return;
+ }
+
+ setLouvreSelectedSlot(value, 0);
+ }
+};
+
+struct DoAction : public Command {
+ int value;
+ Common::String arg;
+
+ DoAction(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), arg(args[1]) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(arg, 0);
+
+ int selection = louvreSelectionSlot(g_engine->getVariable("Selection"));
+ if (selection == 0)
+ return;
+
+ int objectId = messengerInventorySlot(selection);
+ int actionMask = louvreSelectedObjectActionMask();
+
+ int currentAction = g_engine->getVariable("CurrentAction");
+ if (!((currentAction == value || currentAction == 0) && (actionMask & value) != 0))
+ return;
+
+ if (currentAction != 0) {
+ setLouvreSelectedSlot(selection, 4);
+ g_engine->setVariable("CurrentAction", 0);
+ drawLouvreActionButtons();
+ return;
+ }
+
+ g_engine->setVariable(arg, 1);
+ switch (value) {
+ case 1:
+ g_engine->setVariable("Inventaire", objectId);
+ break;
+ case 2:
+ if (louvreObjectCanView(objectId))
+ g_engine->setVariable(arg, objectId);
+ break;
+ case 4:
+ g_engine->setVariable("CurrentAction", value);
+ setLouvreSelectedSlot(selection + 100, 0);
+ drawLouvreActionButtons();
+ break;
+ case 8:
+ g_engine->setVariable("CurrentAction", value);
+ drawLouvreActionButtons();
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+struct IsHere : public Command {
+ IsHere(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ int comefrom = g_engine->getVariable("comefrom");
+ if (comefrom > 10000000)
+ comefrom -= 10000000;
+
+ Common::String value = Common::String::format("%d", comefrom);
+ if (value.size() >= 3) {
+ Common::String name = Common::String::format("P0%cS%c%c", value[0], value[1], value[2]);
+ g_engine->playAnimation(name, "y", 20, 20);
+ }
+ }
+};
+
+struct InitCoffre : public Command {
+ InitCoffre(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ int compacted[kLouvreChestSize];
+ Common::fill(compacted, compacted + kLouvreChestSize, 0);
+
+ int dst = 0;
+ for (int i = 0; i < kLouvreChestSize; ++i)
+ if (g_louvrePluginState.objectChest[i] != 0)
+ compacted[dst++] = g_louvrePluginState.objectChest[i];
+
+ Common::copy(compacted, compacted + kLouvreChestSize, g_louvrePluginState.objectChest);
+ }
+};
+
+struct LoadCoffre : public Command {
+ LoadCoffre(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ for (int i = 0; i < kLouvreChestSize; ++i)
+ g_louvrePluginState.objectChest[i] = g_engine->getVariable(Common::String::format("coffre%d", i + 1));
+ }
+};
+
+struct SaveCoffre : public Command {
+ SaveCoffre(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ for (int i = 0; i < kLouvreChestSize; ++i)
+ g_engine->setVariable(Common::String::format("coffre%d", i + 1), g_louvrePluginState.objectChest[i]);
+ }
+};
+
+struct ExeDemo : public Command {
+ Common::String var;
+
+ ExeDemo(const Common::Array<Common::String> &args) : var(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("ExeDemo %s", var.c_str());
+ g_engine->setVariable(var, 1);
+ }
+};
+
+struct AfficheImage : public Command {
+ Common::String image;
+ int x;
+ int y;
+
+ AfficheImage(const Common::Array<Common::String> &args) : image(args[0]), x(atoi(args[1].c_str())), y(atoi(args[2].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->showImageOverlay(image, x, y);
+ }
+};
+
+struct StopAffiche : public Command {
+ StopAffiche(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->stopImageOverlay();
+ }
+};
+
+struct UpdateStage : public Command {
+ UpdateStage(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->updateStage();
+ }
+};
+
+struct StartCible : public Command {
+ Common::String name;
+ int periodSeconds;
+ Common::Array<int> bounds;
+
+ StartCible(const Common::Array<Common::String> &args) : name(args[0]), periodSeconds(atoi(args[1].c_str())) {
+ for (uint i = 2; i < args.size(); ++i)
+ bounds.push_back(atoi(args[i].c_str()));
+ }
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->startCible(name, periodSeconds, bounds);
+ }
+};
+
+struct StopCible : public Command {
+ StopCible(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->stopCible();
+ }
+};
+
+struct TestCible : public Command {
+ Common::String xVar;
+ Common::String yVar;
+
+ TestCible(const Common::Array<Common::String> &args) : xVar(args[0]), yVar(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->testCible(xVar, yVar);
+ }
+};
+
+struct AfficheCoffre : public Command {
+ AfficheCoffre(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ drawLouvreChest();
+ }
+};
+
+struct AfficheSelection : public Command {
+ AfficheSelection(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ int selection = louvreSelectionSlot(g_engine->getVariable("Selection"));
+ if (selection != 0)
+ drawLouvreSelectedObject(selection);
+ }
+};
+
+struct AffichePorteF : public Command {
+ int value;
+ AffichePorteF(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ drawLouvreInventoryObjects(value != 0);
+ }
+};
+
+struct SelectPorteF : public Command {
+ int value;
+ Common::String var;
+ SelectPorteF(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), var(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(var, 0);
+ if (g_engine->getVariable("CoffreSelect") != 0) {
+ exchangeLouvreChestObject(0, value);
+ } else if (messengerInventorySlot(value) != 0) {
+ setLouvreSelectedSlot(value, 1);
+ }
+ g_engine->setVariable(var, g_engine->getVariable("Selection") != 0);
+ }
+};
+
+struct SelectCoffre : public Command {
+ int value;
+ Common::String var;
+ SelectCoffre(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), var(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(var, 0);
+ if (g_engine->getVariable("Selection") != 0) {
+ exchangeLouvreChestObject(value, 0);
+ } else {
+ int index = g_engine->getVariable("CoffreOffset") + value - 1;
+ if (index >= 0 && index < kLouvreChestSize && g_louvrePluginState.objectChest[index] != 0)
+ drawLouvreChestSelection(value);
+ }
+ g_engine->setVariable(var, g_engine->getVariable("CoffreSelect") != 0);
+ }
+};
+
+struct LoadSave_Init_Slots : public Command {
+ int slots;
+
+ LoadSave_Init_Slots(const Common::Array<Common::String> &args) : slots(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("LoadSave_Init_Slots %d", slots);
+ }
+};
+
+struct LoadSave_Draw_Slot : public Command {
+ int slot;
+ int face;
+ int x;
+ int y;
+
+ LoadSave_Draw_Slot(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())),
+ face(atoi(args[1].c_str())),
+ x(atoi(args[2].c_str())),
+ y(atoi(args[3].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("LoadSave_Draw_Slot %d %d %d %d", slot, face, x, y);
+ g_engine->drawSlot(slot, face, x, y);
+ }
+};
+
+struct LoadSave_Test_Slot : public Command {
+ int slot;
+ Common::String show;
+ Common::String hide;
+
+ LoadSave_Test_Slot(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())), show(args[1]), hide(args[2]) {}
+ void exec(ExecutionContext &ctx) const override {
+ bool exists = g_engine->testSaveSlot(slot);
+ debug("LoadSave_Test_Slot %d %s %s -> %d", slot, show.c_str(), hide.c_str(), exists);
+ g_engine->setVariable(show, exists);
+ g_engine->setVariable(hide, !exists);
+ }
+};
+
+struct Set : public Command {
+ Common::String var;
+ Common::String value;
+ Set(const Common::Array<Common::String> &args) {
+ switch (args.size()) {
+ case 2:
+ var = args[0];
+ value = args[1];
+ break;
+ case 1: {
+ auto pos = args[0].rfind('=');
+ if (pos == Common::String::npos)
+ pos = args[0].size();
+ var = args[0].substr(0, pos);
+ value = args[0].c_str() + pos + 1;
+ } break;
+ default:
+ error("invalid plugin set signature");
+ }
+ }
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->setVariable(var, valueOf(value));
+ }
+};
+
+struct Set_Global_Pan : public Command {
+ Common::String arg;
+ Set_Global_Pan(const Common::Array<Common::String> &args) : arg(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ auto value = valueOf(arg);
+ debug("set_global_pan %s -> %d", arg.c_str(), value);
+ g_engine->setGlobalPan(value);
+ }
+};
+
+struct Set_Global_Volume : public Command {
+ Common::String arg;
+ Set_Global_Volume(const Common::Array<Common::String> &args) : arg(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ auto value = valueOf(arg);
+ debug("set_global_volume %s -> %d", arg.c_str(), value);
+ g_engine->setGlobalVolume(value);
+ }
+};
+
+struct Op : public Command {
+ Common::String var;
+ Common::String negativeVar;
+ Common::String arg;
+ Op(const Common::Array<Common::String> &args) : var(args[0]), negativeVar(args[1]), arg(args[2]) {}
+ void exec(ExecutionContext &ctx) const override {
+ int value = g_engine->getVariable(arg);
+ g_engine->setVariable(var, value);
+ g_engine->setVariable(negativeVar, !value);
+ }
+};
+
+// Amerzone-specific preload plugin
+struct Preload : public Command {
+ Common::String arg;
+ Preload(const Common::Array<Common::String> &args) : arg(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("preload %s", arg.c_str());
+ if (!arg.empty() && Common::isDigit(arg[0])) {
+ g_engine->loadGameState(atoi(arg.c_str()));
+ } else {
+ auto loaded = g_engine->enterScript();
+ debug("preload: loaded: %d", loaded);
+ g_engine->setVariable(arg, loaded);
+ if (loaded) {
+ ctx.running = false;
+ }
+ }
+ }
+};
+
+// Amerzone-specific loadsave plugin
+struct LoadSave : public Command {
+ Common::Array<Common::String> args;
+ LoadSave(const Common::Array<Common::String> &args_) : args(args_) {}
+
+ static bool testSlot(int slot) {
+ auto status = g_engine->testSaveSlot(slot);
+ if (!status)
+ return false;
+
+ g_engine->drawSaveCard(slot);
+ return true;
+ }
+
+ void exec(ExecutionContext &ctx) const override {
+ uint n = args.size();
+ if (n == 3) {
+ auto slot = atoi(args[0].c_str());
+ auto &var = args[1];
+ auto &negativeVar = args[2];
+ debug("loadsave %d %s %s", slot, var.c_str(), negativeVar.c_str());
+ int status = 0;
+ // Amerzone script checks those:
+ // 99 -> true, 98 -> false: continue
+ // 99 -> true, 98 -> true: initial main menu
+ // 99 -> false, 98 -> true: new game
+ // false, false -> black screen
+ bool restarted = g_engine->wasRestarted();
+ bool loaded = g_engine->wasLoaded();
+ debug("engine status, loaded: %d, restarted: %d", loaded, restarted);
+ if (slot == 99) {
+ // special save idx - continue game
+ status = !restarted;
+ } else if (slot == 98) {
+ // special save idx - new game started
+ status = !loaded;
+ } else if (slot >= 1 && slot <= 8) {
+ status = testSlot(slot);
+ } else {
+ warning("LoadSave slot %d", slot);
+ }
+ g_engine->setVariable(var, status);
+ g_engine->setVariable(negativeVar, !status);
+ } else if (n == 2) {
+ auto &srcVar = args[0];
+ auto &dstVar = args[1];
+ debug("loadsave %s %s", srcVar.c_str(), dstVar.c_str());
+ if (!dstVar.empty() && Common::isDigit(dstVar[0])) {
+ uint level = atoi(dstVar.c_str());
+ uint currentLevel = g_engine->currentAmerzoneLevel();
+ if (currentLevel != 0) {
+ g_engine->setVariable(srcVar, currentLevel == level);
+ return;
+ }
+ }
+
+ auto value = g_engine->getVariable(srcVar);
+ g_engine->setVariable(srcVar, 0);
+ g_engine->setVariable(dstVar, value);
+ if (!value) {
+ for (int slot = 1; slot <= 8; ++slot)
+ testSlot(slot);
+ }
+ } else {
+ warning("LoadSave, %u args", n);
+ for (uint i = 0; i < n; ++i)
+ warning("LoadSave %u: %s", i, args[i].c_str());
+ }
+ }
+};
+
+// Amerzone-specific save plugin
+struct Save : public Command {
+ int slot;
+ Save(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("Save %d", slot);
+ g_engine->setContextLabel("Amerzone");
+ g_engine->captureContext();
+ auto err = g_engine->saveGameState(slot, {});
+ if (err.getCode() != Common::ErrorCode::kNoError)
+ error("saving state failed %d", slot);
+ }
+};
+
+struct LoadSave_Capture_Context : public Command {
+ LoadSave_Capture_Context(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("LoadSave_Capture_Context");
+ g_engine->captureContext();
+ }
+};
+
+struct LoadSave_Context_Restored : public Command {
+ Common::String progress;
+ Common::String done;
+
+ LoadSave_Context_Restored(const Common::Array<Common::String> &args) : progress(args[0]), done(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ int value = g_engine->getVariable(progress);
+ debug("LoadSave_Context_Restored: %s -> %d -> %s", progress.c_str(), value, done.c_str());
+ g_engine->setVariable(progress, 0);
+ g_engine->setVariable(done, value);
+ }
+};
+
+struct LoadSave_Load : public Command {
+ int slot;
+
+ LoadSave_Load(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("LoadSave_Load %d", slot);
+ auto err = g_engine->loadGameState(slot);
+ if (err.getCode() != Common::ErrorCode::kNoError)
+ error("loading state failed %d", slot);
+ }
+};
+
+struct LoadSave_Save : public Command {
+ int slot;
+
+ LoadSave_Save(const Common::Array<Common::String> &args) : slot(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("LoadSave_Save %d", slot);
+ auto err = g_engine->saveGameState(slot, {});
+ if (err.getCode() != Common::ErrorCode::kNoError)
+ error("saving state failed %d", slot);
+ }
+};
+
+struct LoadSave_Set_Context_Label : public Command {
+ Common::String label;
+
+ LoadSave_Set_Context_Label(const Common::Array<Common::String> &args) : label(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->setContextLabel(label);
+ }
+};
+
+struct Discocier : public Command {
+ Common::String var;
+ Discocier(const Common::Array<Common::String> &args) : var(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(var, 0);
+
+ int selection = g_engine->getVariable("Selection");
+ int slot = louvreSelectionSlot(selection);
+ int objectId = messengerInventorySlot(slot);
+
+ int parts[3] = {0, 0, 0};
+ int partCount = 0;
+ if (objectId == 3500) {
+ partCount = 2;
+ parts[0] = g_engine->getVariable("RedPastryA");
+ parts[1] = g_engine->getVariable("RedPastryB");
+ } else if (objectId == 3700) {
+ partCount = 2;
+ parts[0] = g_engine->getVariable("YellowSeedA");
+ parts[1] = g_engine->getVariable("YellowSeedB");
+ } else {
+ partCount = louvreSeparateObject(objectId, parts);
+ }
+
+ g_engine->setVariable("CurrentAction", 0);
+ int emptySlots = 0;
+ for (int i = 1; i < 9; ++i)
+ if (messengerInventorySlot(i) == 0)
+ ++emptySlots;
+
+ if (partCount > emptySlots + 1) {
+ drawLouvreActionButtons();
+ drawBlockedLouvreText(28);
+ return;
+ }
+
+ if (partCount == 0)
+ return;
+
+ setMessengerInventorySlot(slot, 0);
+ for (int i = partCount - 1; i >= 0; --i) {
+ for (int dstSlot = 1; dstSlot < 9; ++dstSlot) {
+ if (messengerInventorySlot(dstSlot) == 0) {
+ setMessengerInventorySlot(dstSlot, parts[i]);
+ break;
+ }
+ }
+ }
+
+ setLouvreSelectedSlot(g_engine->getVariable("Selection"), 2);
+ drawLouvreInventoryObjects(true);
+ g_engine->setVariable(var, 1);
+ }
+};
+
+struct Reset : public Command {
+ Reset(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ for (int i = 0; i < kLouvreChestSize; ++i)
+ g_louvrePluginState.objectChest[i] = 0;
+ for (int i = 1; i <= kMessengerInventorySlots; ++i)
+ setMessengerInventorySlot(i, 0);
+ }
+};
+
+struct Restart : public Command {
+ Restart(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->restart();
+ }
+};
+
+struct MemoryRelease : public Command {
+ MemoryRelease(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("MemoryRelease");
+ }
+};
+
+struct DrawTextSelection : public Command {
+ DrawTextSelection(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ if (louvreTextBlocked())
+ return;
+
+ clearLouvreText();
+
+ int selection = louvreSelectionSlot(g_engine->getVariable("Selection"));
+ if (selection != 0) {
+ int objectId = messengerInventorySlot(selection);
+ if (objectId != 0)
+ g_engine->drawArchiveText(objectId, kLouvreTextRect, 14, true, kLouvreTextColor);
+ }
+ }
+};
+
+struct CarteDestination : public Command {
+ Common::String varX;
+ Common::String varY;
+ CarteDestination(const Common::Array<Common::String> &args) : varX(args[0]), varY(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ int comefrom = g_engine->getVariable("comefrom");
+ if (comefrom > 10000000)
+ comefrom -= 10000000;
+
+ Common::String value = Common::String::format("%d", comefrom);
+ if (value.size() >= 1)
+ g_engine->setVariable(varX, value[0] - '0');
+ if (value.size() >= 3)
+ g_engine->setVariable(varY, atoi(value.substr(1, 2).c_str()));
+ }
+};
+
+struct Scroll : public Command {
+ int value;
+ Scroll(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ updateLouvreChestScroll(value);
+ }
+};
+
+struct Waves : public Command {
+ Waves(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->showWaves();
+ }
+};
+
+struct Rollover : public Command {
+ int textId;
+ RolloverType type;
+
+ Rollover(const Common::Array<Common::String> &args, RolloverType t = RolloverType::Default) : textId(atoi(args[0].c_str())), type(t) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->rollover(textId, type);
+ }
+};
+
+struct RolloverMalette : public Rollover {
+ RolloverMalette(const Common::Array<Common::String> &args) : Rollover(args, RolloverType::Malette) {}
+};
+
+struct RolloverSecretaire : public Rollover {
+ RolloverSecretaire(const Common::Array<Common::String> &args) : Rollover(args, RolloverType::Secretaire) {}
+};
+
+struct PorteFRollover : public Command {
+ int arg;
+
+ PorteFRollover(const Common::Array<Common::String> &args) : arg(atoi(args[0].c_str())) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ if (louvreTextBlocked())
+ return;
+
+ if (arg == 28) {
+ drawBlockedLouvreText(arg);
+ } else {
+ drawLouvreText(arg);
+ }
+ }
+};
+
+struct SaveVariable : public Command {
+ SaveVariable(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->saveVariables();
+ }
+};
+
+struct LoadVariable : public Command {
+ LoadVariable(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->loadVariables();
+ }
+};
+
+struct Init2 : public Command {
+ Common::String var;
+ Init2(const Common::Array<Common::String> &args) : var(args[0]) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->setVariable(var, 0);
+ }
+};
+
+struct Init : public Command {
+ int value;
+ Common::String var;
+ Init(const Common::Array<Common::String> &args) : value(atoi(args[0].c_str())), var(args[1]) {}
+ void exec(ExecutionContext &ctx) const override {
+ initLouvrePluginState();
+ g_engine->setVariable(var, value == 2 ? 1 : 0);
+ }
+};
+
+struct End : public Command {
+ End(const Common::Array<Common::String> &args) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("plugin end (quit)");
+ g_engine->quitGame();
+ }
+};
+
+#define PLUGIN_LIST(E) \
+ E(Add) \
+ E(AddCoffreObject) \
+ E(AddObject) \
+ E(AfficheCoffre) \
+ E(AfficheImage) \
+ E(AffichePorteF) \
+ E(AfficheSelection) \
+ E(CarteDestination) \
+ E(ChangeCurseur) \
+ E(CopyVar) \
+ E(Cmp) \
+ E(Discocier) \
+ E(DrawTextSelection) \
+ E(End) \
+ E(ExeDemo) \
+ E(GetMonde4) \
+ E(SetMonde4) \
+ E(Init) \
+ E(Init2) \
+ E(IsPresent) \
+ E(KillTimer) \
+ E(InitCoffre) \
+ E(IsHere) \
+ E(LoadCoffre) \
+ E(SaveCoffre) \
+ E(SelectPorteF) \
+ E(SelectCoffre) \
+ E(Op) \
+ E(Set) \
+ E(Preload) \
+ E(LoadSave) \
+ E(Save) \
+ E(LoadSave_Capture_Context) \
+ E(LoadSave_Context_Restored) \
+ E(LoadSave_Enter_Script) \
+ E(LoadSave_Init_Slots) \
+ E(LoadSave_Load) \
+ E(LoadSave_Save) \
+ E(LoadSave_Set_Context_Label) \
+ E(LoadSave_Draw_Slot) \
+ E(LoadSave_Test_Slot) \
+ E(LoadVariable) \
+ E(MemoryRelease) \
+ E(MultiCD_Set_Transition_Script) \
+ E(MultiCD_If_Next_Script) \
+ E(MultiCD_Use_Install_Path) \
+ E(MultiCD_Set_Next_Script) \
+ E(PauseTimer) \
+ E(Play_AnimBloc) \
+ E(Play_AnimBloc_Number) \
+ E(Play_Movie) \
+ E(Reset) \
+ E(Restart) \
+ E(RemoveObject) \
+ E(Rollover) \
+ E(RolloverMalette) \
+ E(RolloverSecretaire) \
+ E(PorteFRollover) \
+ E(SaveVariable) \
+ E(Select) \
+ E(Set_Global_Pan) \
+ E(Set_Global_Volume) \
+ E(Scroll) \
+ E(StartCible) \
+ E(StopAffiche) \
+ E(Stop_AnimBloc) \
+ E(StopCible) \
+ E(TestCible) \
+ E(DoAction) \
+ E(StartTimer) \
+ E(Sub) \
+ E(Until) \
+ E(UpdateStage) \
+ E(While) \
+ E(Waves) \
+ /* */
+
+#define ADD_PLUGIN(NAME) \
+ if (cmd.equalsIgnoreCase(#NAME)) \
+ return CommandPtr(new NAME(args));
+
+struct SetVar : public Command {
+ Common::String name;
+ int value;
+
+ SetVar(Common::String n, int v) : name(Common::move(n)), value(v) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->setVariable(name, value);
+ }
+};
+
+struct GoSub : public Command {
+ Common::String label;
+ GoSub(const Common::String &l) : label(l) {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("gosub %s", label.c_str());
+ auto *scope = ctx.rootScope ? ctx.rootScope : ctx.scope;
+ assert(scope);
+ auto *labelPtr = scope->findLabel(label);
+ if (!labelPtr) {
+ warning("gosub: label %s not found", label.c_str());
+ return;
+ }
+ ExecutionContext sub = {};
+ sub.subroutine = true;
+ sub.rootScope = scope;
+ scope->exec(sub, labelPtr->offset);
+ }
+};
+
+struct EndScript : public Command {
+ EndScript() {}
+ void exec(ExecutionContext &ctx) const override {
+ debug("end");
+ ctx.running = false;
+ g_engine->end();
+ }
+};
+
+struct Return : public Command {
+ Return() {}
+ void exec(ExecutionContext &ctx) const override {
+ ctx.running = false;
+ if (ctx.subroutine) {
+ debug("return to caller");
+ } else {
+ debug("return to previous warp");
+ g_engine->returnToWarp();
+ }
+ }
+};
+
+struct SetCursorDefault : public Command {
+ int idx;
+ Common::String fname;
+ SetCursorDefault(int i, Common::String f) : idx(i), fname(Common::move(f)) {}
+ void exec(ExecutionContext &ctx) const override {
+ if (idx >= 0)
+ g_engine->setCursorDefault(idx, fname);
+ }
+};
+
+struct SetCursor : public Command {
+ Common::String fname;
+ Common::String wname;
+ int idx;
+ SetCursor(Common::String f, Common::String w, int i) : fname(Common::move(f)), wname(Common::move(w)), idx(i) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->setCursor(fname, wname, idx);
+ }
+};
+
+struct HideCursor : public Command {
+ Common::String warp;
+ int idx;
+ HideCursor(Common::String w, int i) : warp(Common::move(w)), idx(i) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->hideCursor(warp, idx);
+ }
+};
+
+struct ResetLockKey : public Command {
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->resetLockKey();
+ }
+};
+
+struct LockKey : public Command {
+ int idx;
+ Common::String warp;
+
+ LockKey(int i, Common::String w) : idx(i), warp(Common::move(w)) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("lock key %d: %s", idx, warp.c_str());
+ g_engine->lockKey(idx, warp);
+ }
+};
+
+struct SetZoom : public Command {
+ float fov;
+ SetZoom(float f) : fov(f) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->setZoom(fov);
+ }
+};
+
+struct AngleXMax : public Command {
+ float xMax;
+ AngleXMax(float x) : xMax(x) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("anglexmax %g", xMax);
+ g_engine->setXMax(xMax);
+ }
+};
+
+struct AngleYMax : public Command {
+ float yMin, yMax;
+ AngleYMax(float min, float max) : yMin(min), yMax(max) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ if (yMin != yMax) {
+ debug("angleymax %g %g", yMin, yMax);
+ g_engine->setYMax(yMin, yMax);
+ } else {
+ debug("angleymax: reset");
+ g_engine->resetYMax();
+ }
+ }
+};
+
+struct SetAngle : public Command {
+ float x, y;
+ SetAngle(float x_, float y_) : x(x_), y(y_) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("setangle %g %g", x, y);
+ g_engine->setAngle(x, y);
+ }
+};
+
+struct SetNord : public Command {
+ float angle;
+ SetNord(float a) : angle(a) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ debug("setnord %g", angle);
+ g_engine->setNord(angle);
+ }
+};
+
+struct InterpolAngle : public Command {
+ float x, y, speed, zoom;
+
+ InterpolAngle(float x_, float y_, float s, float z) : x(x_), y(y_), speed(s), zoom(z) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->interpolateAngle(x, y, speed, zoom);
+ }
+};
+
+struct GoToWarp : public Command {
+ Common::String warp;
+ GoToWarp(Common::String w) : warp(Common::move(w)) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ // terminate script after successful warp.
+ // continue if not (for instance, goto to the same location)
+ if (g_engine->goToWarp(warp))
+ ctx.running = false;
+ }
+};
+
+struct PlaySound : public Command {
+ Common::String sound;
+ int volume;
+ int loops;
+ Audio::Mixer::SoundType type;
+
+ PlaySound(Common::String s, int v, int l, Audio::Mixer::SoundType t = Audio::Mixer::kSFXSoundType) : sound(Common::move(s)), volume(v), loops(l), type(t) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->playSound(sound, type, volume, loops);
+ }
+};
+
+struct PlayRndSound : public PlaySound {
+ int probability;
+
+ PlayRndSound(Common::String s, int v, int p, int l, Audio::Mixer::SoundType t = Audio::Mixer::kSFXSoundType) : PlaySound(Common::move(s), v, l, t), probability(p) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->playRandomSound(sound, type, volume, probability, loops);
+ }
+};
+
+struct PlayMusique : public PlaySound {
+ PlayMusique(Common::String s, int v) : PlaySound(Common::move(s), v, -1, Audio::Mixer::kMusicSoundType) {}
+};
+
+struct StopSound : public Command {
+ Common::String sound;
+
+ StopSound(Common::String s) : sound(Common::move(s)) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->stopSound(sound);
+ }
+};
+
+struct PlaySound3D : public Command {
+ Common::String sound;
+ int volume;
+ float angle;
+ int loops;
+
+ PlaySound3D(Common::String s, int v, float a, int l) : sound(Common::move(s)), volume(v), angle(a), loops(l) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->playSound(sound, Audio::Mixer::kSFXSoundType, volume, loops, true, angle);
+ }
+};
+
+struct StopSound3D : public Command {
+ Common::String sound;
+
+ StopSound3D(Common::String s) : sound(Common::move(s)) {}
+
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->stopSound(sound);
+ }
+};
+
+struct Fade : public Command {
+ int start, stop, speed;
+
+ Fade(int a0, int a1, int a2) : start(a0), stop(a1), speed(a2) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->fade(start, stop, speed);
+ }
+};
+
+struct Transfade : public Command {
+ int speed;
+
+ Transfade(int a0) : speed(a0) {}
+ void exec(ExecutionContext &ctx) const override {
+ g_engine->transFade(speed);
+ }
+};
+
+} // namespace
+
+CommandPtr createV1PluginCommand(const Common::String &cmd, const Common::Array<Common::String> &args, int lineno) {
+ PLUGIN_LIST(ADD_PLUGIN)
+ error("unhandled plugin command %s at line %d", cmd.c_str(), lineno);
+}
+
+CommandPtr parseV1Command(Parser &p) {
+ if (p.keyword("setcursordefault")) {
+ auto idx = p.nextWord();
+ p.expect(',');
+ bool valid = !idx.empty() && Common::isDigit(idx[0]);
+ // this skips garbage cursor default found in Amerzone
+ // e.g. `setcursordefault cursor1.pcx,cursor1`
+ return CommandPtr(new SetCursorDefault(valid ? atoi(idx.c_str()) : -1, p.nextWord()));
+ } else if (p.keyword("lockkey")) {
+ auto idx = p.nextInt();
+ p.expect(',');
+ auto fname = p.nextWord();
+ return CommandPtr(new LockKey(idx, Common::move(fname)));
+ } else if (p.keyword("resetlockkey")) {
+ return CommandPtr(new ResetLockKey());
+ } else if (p.maybe("fade=")) {
+ auto arg0 = p.nextInt();
+ p.expect(',');
+ auto arg1 = p.nextInt();
+ p.expect(',');
+ auto arg2 = p.nextInt();
+ return CommandPtr(new Fade(arg0, arg1, arg2));
+ } else if (p.keyword("transfade")) {
+ return CommandPtr(new Transfade(p.nextInt()));
+ } else if (p.maybe("setzoom=")) {
+ return CommandPtr(new SetZoom(toRadian(p.nextInt())));
+ } else if (p.maybe("setangle=") || p.keyword("setangle")) {
+ auto a0 = toAngle(p.nextInt());
+ p.expect(',');
+ auto a1 = toAngle(p.nextInt());
+ return CommandPtr(new SetAngle(a0, a1));
+ } else if (p.maybe("setnord=")) {
+ auto a0 = toAngle(p.nextInt());
+ return CommandPtr(new SetNord(a0));
+ } else if (p.keyword("interpolangle") || p.keyword("interpolanglezoom")) {
+ p.maybe(',');
+ p.maybe('=');
+ auto a0 = toAngle(p.nextInt());
+ p.expect(',');
+ auto a1 = toAngle(p.nextInt());
+ p.expect(',');
+ float a2 = p.nextInt();
+ float a3 = 0;
+ if (p.maybe(','))
+ a3 = p.nextInt();
+ // x, y, speed
+ // or
+ // x, y, zoom, speed
+ return CommandPtr(a3 != 0 ? new InterpolAngle(a0, a1, a3, toRadian(a2)) : new InterpolAngle(a0, a1, a2, 0));
+ } else if (p.maybe("anglexmax=") || p.keyword("anglexmax")) {
+ return CommandPtr(new AngleXMax(toAngle(p.nextInt())));
+ } else if (p.maybe("angleymax=") || p.keyword("angleymax")) {
+ auto y0 = toAngle(p.nextInt());
+ p.expect(',');
+ auto y1 = toAngle(p.nextInt());
+ return CommandPtr(new AngleYMax(y0, y1));
+ } else if (p.keyword("gotowarp")) {
+ return CommandPtr(new GoToWarp(p.nextWord()));
+ } else if (p.keyword("playsound3d")) {
+ auto sound = p.nextWord();
+ p.expect(',');
+ auto arg0 = p.nextInt();
+ p.expect(',');
+ auto arg1 = p.nextInt();
+ int arg2 = 0;
+ if (p.maybe(','))
+ arg2 = p.nextInt();
+ return CommandPtr(new PlaySound3D(Common::move(sound), arg0, toAngle(arg1), arg2));
+ } else if (p.keyword("playmusique")) {
+ auto sound = p.nextWord();
+ int vol = 255;
+ if (p.maybe(','))
+ vol = p.nextInt();
+ return CommandPtr(new PlayMusique(Common::move(sound), vol));
+ } else if (p.keyword("playsound")) {
+ auto sound = p.nextWord();
+ p.expect(',');
+ auto arg0 = p.nextInt();
+ int arg1 = 0;
+ if (p.maybe(','))
+ arg1 = p.nextInt();
+ return CommandPtr(new PlaySound(Common::move(sound), arg0, arg1));
+ } else if (p.keyword("playrndsound")) {
+ auto sound = p.nextWord();
+ p.expect(',');
+ auto arg0 = p.nextInt();
+ p.expect(',');
+ auto arg1 = p.nextInt();
+ int arg2 = 0;
+ if (p.maybe(','))
+ arg2 = p.nextInt();
+ return CommandPtr(new PlayRndSound(Common::move(sound), arg0, arg1, arg2));
+ } else if (p.keyword("stopsound3d")) {
+ return CommandPtr(new StopSound3D(p.nextWord()));
+ } else if (p.keyword("stopsound") || p.keyword("stopmusique")) {
+ return CommandPtr(new StopSound(p.nextWord()));
+ } else if (p.keyword("setcursor")) {
+ auto image = p.nextWord();
+ p.maybe(',');
+ auto warp = p.nextWord();
+ int idx = 0;
+ if (p.maybe(','))
+ idx = p.nextInt();
+ return CommandPtr(new SetCursor(Common::move(image), Common::move(warp), idx));
+ } else if (p.keyword("hidecursor")) {
+ auto warp = p.nextWord();
+ p.expect(',');
+ auto idx = p.nextInt();
+ return CommandPtr(new HideCursor(Common::move(warp), idx));
+ } else if (p.keyword("set")) {
+ auto var = p.nextWord();
+ if (p.maybe(',')) {
+ // this is typo in amerzone, this meant to be setCursor
+ auto warp = p.nextWord();
+ int idx = 0;
+ if (p.maybe(','))
+ idx = p.nextInt();
+ return CommandPtr(new SetCursor(Common::move(var), Common::move(warp), idx));
+ }
+ int value = 0;
+ if (p.maybe('=')) {
+ p.skip();
+ if (!p.atEnd() && p.peek() != '!')
+ value = p.nextInt();
+ }
+ return CommandPtr(new SetVar(Common::move(var), value));
+ } else if (p.keyword("not")) {
+ auto var = p.nextWord();
+ return CommandPtr(new Not(Common::move(var)));
+ } else if (p.keyword("gosub")) {
+ return CommandPtr(new GoSub(p.nextWord()));
+ } else if (p.keyword("return")) {
+ return CommandPtr{new Return()};
+ } else if (p.keyword("end")) {
+ return CommandPtr{new EndScript()};
+ }
+ return {};
+};
+
+} // namespace PhoenixVR
diff --git a/engines/phoenixvr/commands_v1.h b/engines/phoenixvr/commands_v1.h
new file mode 100644
index 00000000000..e5356f0019e
--- /dev/null
+++ b/engines/phoenixvr/commands_v1.h
@@ -0,0 +1,35 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PHOENIXVR_COMMANDS_V1_H
+#define PHOENIXVR_COMMANDS_V1_H
+
+#include "phoenixvr/commands.h"
+
+namespace PhoenixVR {
+class Parser;
+
+CommandPtr parseV1Command(Parser &p);
+CommandPtr createV1PluginCommand(const Common::String &cmd, const Common::Array<Common::String> &args, int lineno);
+
+} // namespace PhoenixVR
+
+#endif
diff --git a/engines/phoenixvr/game_state.cpp b/engines/phoenixvr/game_state.cpp
index 62b78a66f61..91bc3463e20 100644
--- a/engines/phoenixvr/game_state.cpp
+++ b/engines/phoenixvr/game_state.cpp
@@ -1,3 +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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
#include "phoenixvr/game_state.h"
#include "common/debug.h"
#include "graphics/surface.h"
diff --git a/engines/phoenixvr/math.h b/engines/phoenixvr/math.h
index 82b5b2e59dd..f9950bc47df 100644
--- a/engines/phoenixvr/math.h
+++ b/engines/phoenixvr/math.h
@@ -22,10 +22,29 @@
#ifndef PHOENIXVR_MATH_H
#define PHOENIXVR_MATH_H
+#include "common/scummsys.h"
+
namespace PhoenixVR {
static constexpr auto kTau = static_cast<float>(M_PI * 2);
static constexpr auto kPi = static_cast<float>(M_PI);
static constexpr auto kPi2 = static_cast<float>(M_PI_2);
+
+inline float toRadian(float deg) {
+ return kPi * deg / 180;
+}
+
+inline float toAngle(int a) {
+ static const float angleToFloat = kPi / 4096.0f;
+ return angleToFloat * static_cast<float>(a);
+}
+
+inline int fromAngle(float a) {
+ if (a == INFINITY || a == -INFINITY)
+ return -1;
+ static const float floatToAngle = 4096.0f / kPi;
+ return static_cast<int>(floatToAngle * a);
+}
+
} // namespace PhoenixVR
#endif
diff --git a/engines/phoenixvr/module.mk b/engines/phoenixvr/module.mk
index 57272f53d80..bb330490f64 100644
--- a/engines/phoenixvr/module.mk
+++ b/engines/phoenixvr/module.mk
@@ -3,6 +3,8 @@ MODULE := engines/phoenixvr
MODULE_OBJS = \
arn.o \
bigf.o \
+ commands.o \
+ commands_v1.o \
game_state.o \
console.o \
metaengine.o \
@@ -11,6 +13,7 @@ MODULE_OBJS = \
rectf.o \
region_set.o \
script.o \
+ script_v1.o \
variables.o \
vr.o
diff --git a/engines/phoenixvr/phoenixvr.cpp b/engines/phoenixvr/phoenixvr.cpp
index a8cab090e52..d6dbd61d0b8 100644
--- a/engines/phoenixvr/phoenixvr.cpp
+++ b/engines/phoenixvr/phoenixvr.cpp
@@ -461,7 +461,7 @@ void PhoenixVREngine::loadNextScript() {
if (!s)
error("can't open script file %s", nextScript.c_str());
- _script.reset(new Script(*s));
+ _script.reset(Script::load(*s, 1));
for (auto &var : _script->getVarNames())
declareVariable(var);
if (gameIdMatches("dracula1")) {
@@ -1193,7 +1193,7 @@ void PhoenixVREngine::executeTest(int idx) {
debug("execute test %d", idx);
auto test = _warp->getTest(idx);
if (test) {
- Script::ExecutionContext ctx;
+ ExecutionContext ctx;
test->scope.exec(ctx);
} else
warning("invalid test id %d", idx);
@@ -1502,7 +1502,7 @@ void PhoenixVREngine::tick(float dt) {
debug("no region %s", _warp->testFile.c_str());
}
- Script::ExecutionContext ctx;
+ ExecutionContext ctx;
debug("execute warp script %s", _warp->vrFile.c_str());
auto test = _warp->getDefaultTest();
if (test)
@@ -1799,7 +1799,7 @@ Common::Error PhoenixVREngine::run() {
if (_vr.isVR() ? region->contains3D(vrPos) : region->contains2D(event.mouse.x, event.mouse.y)) {
debug("click region %u", i);
if (auto clickTest = _warp->getLastTest(i)) {
- Script::ExecutionContext ctx;
+ ExecutionContext ctx;
clickTest->scope.exec(ctx);
} else
warning("invalid test id %u", i);
@@ -2055,7 +2055,7 @@ Common::Error PhoenixVREngine::loadGameStream(Common::SeekableReadStream *slot)
_loadedState = state.state;
{
auto test = _script->getWarp(0)->getDefaultTest();
- Script::ExecutionContext ctx;
+ ExecutionContext ctx;
test->scope.exec(ctx);
}
_loaded = false;
diff --git a/engines/phoenixvr/script.cpp b/engines/phoenixvr/script.cpp
index a4219aab369..79c794ba4a3 100644
--- a/engines/phoenixvr/script.cpp
+++ b/engines/phoenixvr/script.cpp
@@ -1,167 +1,33 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
#include "phoenixvr/script.h"
#include "common/stream.h"
#include "common/textconsole.h"
-#include "phoenixvr/commands.h"
-#include "phoenixvr/parser.h"
-#include "phoenixvr/phoenixvr.h"
+#include "phoenixvr/script_v1.h"
namespace PhoenixVR {
-Script::CommandPtr Script::parseCommand(Parser &p) {
- if (p.keyword("setcursordefault")) {
- auto idx = p.nextWord();
- p.expect(',');
- bool valid = !idx.empty() && Common::isDigit(idx[0]);
- // this skips garbage cursor default found in Amerzone
- // e.g. `setcursordefault cursor1.pcx,cursor1`
- return CommandPtr(new SetCursorDefault(valid ? atoi(idx.c_str()) : -1, p.nextWord()));
- } else if (p.keyword("lockkey")) {
- auto idx = p.nextInt();
- p.expect(',');
- auto fname = p.nextWord();
- return CommandPtr(new LockKey(idx, Common::move(fname)));
- } else if (p.keyword("resetlockkey")) {
- return CommandPtr(new ResetLockKey());
- } else if (p.maybe("fade=")) {
- auto arg0 = p.nextInt();
- p.expect(',');
- auto arg1 = p.nextInt();
- p.expect(',');
- auto arg2 = p.nextInt();
- return CommandPtr(new Fade(arg0, arg1, arg2));
- } else if (p.keyword("transfade")) {
- return CommandPtr(new Transfade(p.nextInt()));
- } else if (p.maybe("setzoom=")) {
- return CommandPtr(new SetZoom(toRadian(p.nextInt())));
- } else if (p.maybe("setangle=") || p.keyword("setangle")) {
- auto a0 = toAngle(p.nextInt());
- p.expect(',');
- auto a1 = toAngle(p.nextInt());
- return CommandPtr(new SetAngle(a0, a1));
- } else if (p.maybe("setnord=")) {
- auto a0 = toAngle(p.nextInt());
- return CommandPtr(new SetNord(a0));
- } else if (p.keyword("interpolangle") || p.keyword("interpolanglezoom")) {
- p.maybe(',');
- p.maybe('=');
- auto a0 = toAngle(p.nextInt());
- p.expect(',');
- auto a1 = toAngle(p.nextInt());
- p.expect(',');
- float a2 = p.nextInt();
- float a3 = 0;
- if (p.maybe(','))
- a3 = p.nextInt();
- // x, y, speed
- // or
- // x, y, zoom, speed
- return CommandPtr(a3 != 0 ? new InterpolAngle(a0, a1, a3, toRadian(a2)) : new InterpolAngle(a0, a1, a2, 0));
- } else if (p.maybe("anglexmax=") || p.keyword("anglexmax")) {
- return CommandPtr(new AngleXMax(toAngle(p.nextInt())));
- } else if (p.maybe("angleymax=") || p.keyword("angleymax")) {
- auto y0 = toAngle(p.nextInt());
- p.expect(',');
- auto y1 = toAngle(p.nextInt());
- return CommandPtr(new AngleYMax(y0, y1));
- } else if (p.keyword("gotowarp")) {
- return CommandPtr(new GoToWarp(p.nextWord()));
- } else if (p.keyword("playsound3d")) {
- auto sound = p.nextWord();
- p.expect(',');
- auto arg0 = p.nextInt();
- p.expect(',');
- auto arg1 = p.nextInt();
- int arg2 = 0;
- if (p.maybe(','))
- arg2 = p.nextInt();
- return CommandPtr(new PlaySound3D(Common::move(sound), arg0, toAngle(arg1), arg2));
- } else if (p.keyword("playmusique")) {
- auto sound = p.nextWord();
- int vol = 255;
- if (p.maybe(','))
- vol = p.nextInt();
- return CommandPtr(new PlayMusique(Common::move(sound), vol));
- } else if (p.keyword("playsound")) {
- auto sound = p.nextWord();
- p.expect(',');
- auto arg0 = p.nextInt();
- int arg1 = 0;
- if (p.maybe(','))
- arg1 = p.nextInt();
- return CommandPtr(new PlaySound(Common::move(sound), arg0, arg1));
- } else if (p.keyword("playrndsound")) {
- auto sound = p.nextWord();
- p.expect(',');
- auto arg0 = p.nextInt();
- p.expect(',');
- auto arg1 = p.nextInt();
- int arg2 = 0;
- if (p.maybe(','))
- arg2 = p.nextInt();
- return CommandPtr(new PlayRndSound(Common::move(sound), arg0, arg1, arg2));
- } else if (p.keyword("stopsound3d")) {
- return CommandPtr(new StopSound3D(p.nextWord()));
- } else if (p.keyword("stopsound") || p.keyword("stopmusique")) {
- return CommandPtr(new StopSound(p.nextWord()));
- } else if (p.keyword("setcursor")) {
- auto image = p.nextWord();
- p.maybe(',');
- auto warp = p.nextWord();
- int idx = 0;
- if (p.maybe(','))
- idx = p.nextInt();
- return CommandPtr(new SetCursor(Common::move(image), Common::move(warp), idx));
- } else if (p.keyword("hidecursor")) {
- auto warp = p.nextWord();
- p.expect(',');
- auto idx = p.nextInt();
- return CommandPtr(new HideCursor(Common::move(warp), idx));
- } else if (p.keyword("set")) {
- auto var = p.nextWord();
- if (p.maybe(',')) {
- // this is typo in amerzone, this meant to be setCursor
- auto warp = p.nextWord();
- int idx = 0;
- if (p.maybe(','))
- idx = p.nextInt();
- return CommandPtr(new SetCursor(Common::move(var), Common::move(warp), idx));
- }
- int value = 0;
- if (p.maybe('=')) {
- p.skip();
- if (!p.atEnd() && p.peek() != '!')
- value = p.nextInt();
- }
- return CommandPtr(new SetVar(Common::move(var), value));
- } else if (p.keyword("not")) {
- auto var = p.nextWord();
- return CommandPtr(new Not(Common::move(var)));
- } else if (p.keyword("gosub")) {
- return CommandPtr(new GoSub(p.nextWord()));
- } else if (p.keyword("return")) {
- return CommandPtr{new Return()};
- } else if (p.keyword("end")) {
- return CommandPtr{new EndScript()};
- }
- return {};
-};
-
-void Script::Scope::exec(ExecutionContext &ctx) const {
- exec(ctx, 0);
-}
-
-void Script::Scope::exec(ExecutionContext &ctx, uint offset) const {
- auto oldScope = ctx.scope;
- if (!ctx.rootScope)
- ctx.rootScope = this;
- ctx.scope = this;
- for (uint i = offset, n = commands.size(); i < n; ++i) {
- if (!ctx.running)
- break;
- commands[i]->exec(ctx);
- }
- ctx.scope = oldScope;
-}
+Script::Script() = default;
+Script::~Script() = default;
Script::TestPtr Script::Warp::getTest(int idx) const {
auto it = Common::find_if(tests.begin(), tests.end(), [&](const TestPtr &test) { return test->idx == idx; });
@@ -177,7 +43,15 @@ Script::TestPtr Script::Warp::getLastTest(int idx) const {
return Script::TestPtr{};
}
-Script::Script(Common::SeekableReadStream &s) {
+Script *Script::load(Common::SeekableReadStream &s, int version) {
+ Common::ScopedPtr<Script> script;
+ switch (version) {
+ case 1:
+ script.reset(new ScriptV1);
+ break;
+ default:
+ error("unsupported script version: %d", version);
+ }
s.seek(0);
Common::Array<char> text(s.size());
if (s.read(text.data(), text.size()) != text.size())
@@ -191,115 +65,9 @@ Script::Script(Common::SeekableReadStream &s) {
lineStartOffset += Common::distance(lineStart, lineEnd) + 1;
while (lineEnd > lineStart && Common::isSpace(lineEnd[-1]))
--lineEnd;
- parseLine({lineStart, lineEnd}, lineno++);
+ script->parseLine({lineStart, lineEnd}, lineno++);
}
-}
-
-void Script::parseLine(const Common::String &line, uint lineno) {
- if (line.empty())
- return;
-
- Parser p(line, lineno);
- if (p.atEnd())
- return;
-
- if (p.maybe('[')) {
- if (p.maybe("bool]=") || p.maybe("bool)=") || p.maybe({"b\x00\x00ool]=", 8})) {
- _vars.push_back(p.nextWord());
- } else if (p.maybe("warp]=")) {
- auto vr = p.nextWord();
- Common::String test;
- if (p.maybe(','))
- test = p.nextWord();
- _currentWarp.reset(new Warp{vr, Common::move(test), {}});
- if (!_warpsIndex.contains(vr))
- _warpsIndex[vr] = _warps.size();
- else
- warning("duplicate warp %s", vr.c_str());
- _warps.push_back(_currentWarp);
- _warpNames.push_back(vr);
- } else if (p.maybe("test]=")) {
- if (!_currentWarp)
- error("test without warp");
- auto idx = p.nextInt();
- auto hover = 0;
- if (!_currentWarp)
- error("text must have parent wrap section");
- if (p.maybe(',')) {
- hover = p.nextInt();
- }
- _currentTest.reset(new Test{idx, hover, {}});
- _currentWarp->tests.push_back(_currentTest);
- } else {
- error("invalid [] directive on line %u: %s", lineno, line.c_str());
- }
- } else if (_currentTest) {
- auto &commands = _currentTest->scope.commands;
- if (p.maybe("ifand=") || p.maybe("ifand")) {
- if (_pluginScope)
- error("ifand in plugin scope");
- _conditional.reset(new IfAnd(p.readStringList()));
- } else if (p.maybe("ifor=") || p.maybe("ifor")) {
- if (_pluginScope)
- error("ifor in plugin scope");
- _conditional.reset(new IfOr(p.readStringList()));
- } else if (p.maybe("plugin")) {
- if (_pluginScope)
- error("nested plugin context is not allowed, line: %u", lineno);
- _pluginScope.reset(new Script::Scope);
- } else if (p.maybe("endplugin")) {
- if (!_pluginScope)
- error("endplugin without plugin");
- if (_conditional) {
- _conditional->target = Common::move(_pluginScope);
- _pluginScope.reset();
- commands.push_back(Common::move(_conditional));
- _conditional.reset();
- } else {
- commands.push_back(Common::move(_pluginScope));
- _pluginScope.reset();
- }
- } else if (p.maybe("label")) {
- if (_pluginScope)
- error("no labels in plugin scope allowed");
- auto name = p.nextWord();
- auto offset = _currentTest->scope.commands.size();
- _currentTest->scope.labels.push_back({Common::move(name), offset});
- } else {
- if (_pluginScope) {
- auto name = p.nextWord();
- p.expect('(');
- auto args = p.readStringList();
- p.expect(')');
- auto cmd = createCommand(name, args, lineno);
- if (cmd)
- _pluginScope->commands.push_back(Common::move(cmd));
- else
- error("unhandled plugin command %s at line %d", line.c_str(), lineno);
- } else {
- auto cmd = parseCommand(p);
- if (cmd) {
- if (_conditional) {
- _conditional->target = Common::move(cmd);
- commands.push_back(Common::move(_conditional));
- _conditional.reset();
- } else
- commands.push_back(Common::move(cmd));
- } else
- error("unhandled script command %s at line %d", line.c_str(), lineno);
- }
- }
- } else
- error("invalid directive at line %u: %s", lineno, line.c_str());
-}
-
-int Script::Command::valueOf(const Common::String &value) {
- if (!value.empty() && (Common::isDigit(value[0]) || value[0] == '-' || value[0] == '+'))
- return atoi(value.c_str());
- return g_engine->getVariable(value);
-}
-
-Script::~Script() {
+ return script.release();
}
int Script::getWarp(const Common::String &name) const {
diff --git a/engines/phoenixvr/script.h b/engines/phoenixvr/script.h
index 99f8389b183..5db007f9a26 100644
--- a/engines/phoenixvr/script.h
+++ b/engines/phoenixvr/script.h
@@ -26,73 +26,16 @@
#include "common/hashmap.h"
#include "common/ptr.h"
#include "common/str.h"
-#include "phoenixvr/math.h"
+#include "phoenixvr/commands.h"
namespace Common {
class SeekableReadStream;
}
namespace PhoenixVR {
-namespace {
-inline float toRadian(float deg) {
- return kPi * deg / 180;
-}
-inline float toAngle(int a) {
- static const float angleToFloat = kPi / 4096.0f;
- return angleToFloat * static_cast<float>(a);
-}
-
-inline int fromAngle(float a) {
- if (a == INFINITY || a == -INFINITY)
- return -1;
- static const float floatToAngle = 4096.0f / kPi;
- return static_cast<int>(floatToAngle * a);
-}
-} // namespace
class Parser;
class Script {
public:
- struct Scope;
- struct ExecutionContext {
- bool running = true;
- bool subroutine = false;
- const Scope *scope = nullptr;
- const Scope *rootScope = nullptr;
- };
- struct Command {
- virtual ~Command() {}
- virtual void exec(ExecutionContext &ctx) const = 0;
-
- static int valueOf(const Common::String &value);
- };
- using CommandPtr = Common::SharedPtr<Command>;
-
- struct Scope : public Script::Command {
- Common::Array<CommandPtr> commands;
-
- struct Label {
- Common::String name;
- uint offset;
- };
- Common::Array<Label> labels;
-
- const Label *findLabel(const Common::String &name) const {
- auto it = Common::find_if(labels.begin(), labels.end(), [&](const Label &label) { return label.name.equalsIgnoreCase(name); });
- return it != labels.end() ? &*it : nullptr;
- }
-
- void exec(ExecutionContext &ctx) const override;
- void exec(ExecutionContext &ctx, uint offset) const;
- };
- using ScopePtr = Common::SharedPtr<Scope>;
-
- struct Conditional : public Script::Command {
- Common::Array<Common::String> vars;
- Script::CommandPtr target;
- Conditional(Common::Array<Common::String> args) : vars(Common::move(args)) {}
- };
- using ConditionalPtr = Common::SharedPtr<Conditional>;
-
struct Test {
int idx;
int hover;
@@ -116,23 +59,19 @@ public:
using WarpPtr = Common::SharedPtr<Warp>;
using ConstWarpPtr = Common::SharedPtr<const Warp>;
-private:
+protected:
Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _warpsIndex;
Common::Array<Common::String> _warpNames;
Common::Array<Common::String> _vars;
Common::Array<WarpPtr> _warps;
- WarpPtr _currentWarp;
- TestPtr _currentTest;
- ScopePtr _pluginScope;
- ConditionalPtr _conditional;
-private:
- Script::CommandPtr parseCommand(Parser &parser);
- void parseLine(const Common::String &line, uint lineno);
+ virtual void parseLine(const Common::String &line, uint lineno) = 0;
public:
- Script(Common::SeekableReadStream &s);
- ~Script();
+ Script();
+ virtual ~Script();
+
+ static Script *load(Common::SeekableReadStream &s, int version);
int getWarp(const Common::String &name) const;
ConstWarpPtr getWarp(int index) const;
diff --git a/engines/phoenixvr/script_v1.cpp b/engines/phoenixvr/script_v1.cpp
new file mode 100644
index 00000000000..b6d02ea701c
--- /dev/null
+++ b/engines/phoenixvr/script_v1.cpp
@@ -0,0 +1,169 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "phoenixvr/script_v1.h"
+#include "phoenixvr/commands_v1.h"
+#include "phoenixvr/parser.h"
+#include "phoenixvr/phoenixvr.h"
+
+namespace PhoenixVR {
+
+namespace {
+struct IfAnd : public ScriptV1::Conditional {
+ IfAnd(Common::Array<Common::String> args) : ScriptV1::Conditional(Common::move(args)) {}
+ void exec(ExecutionContext &ctx) const override {
+ bool result = true;
+ for (auto &var : vars) {
+ if (var.empty() || !g_engine->hasVariable(var))
+ continue;
+ auto value = g_engine->getVariable(var);
+ debug("ifand, %s: %d", var.c_str(), value);
+ if (!value)
+ result = false;
+ }
+ if (!result) {
+ debug("ifand: not executing conditional block");
+ return;
+ }
+ debug("ifand: executing conditional block");
+ target->exec(ctx);
+ }
+};
+
+struct IfOr : public ScriptV1::Conditional {
+ IfOr(Common::Array<Common::String> args) : ScriptV1::Conditional(Common::move(args)) {}
+ void exec(ExecutionContext &ctx) const override {
+ bool result = false;
+ for (auto &var : vars) {
+ if (var.empty() || !g_engine->hasVariable(var))
+ continue;
+ auto value = g_engine->getVariable(var);
+ debug("ifor, %s: %d", var.c_str(), value);
+ if (value)
+ result = true;
+ }
+ if (!result)
+ return;
+ debug("ifor: executing conditional block");
+ target->exec(ctx);
+ }
+};
+
+} // namespace
+
+void ScriptV1::parseLine(const Common::String &line, uint lineno) {
+ if (line.empty())
+ return;
+
+ Parser p(line, lineno);
+ if (p.atEnd())
+ return;
+
+ if (p.maybe('[')) {
+ if (p.maybe("bool]=") || p.maybe("bool)=") || p.maybe({"b\x00\x00ool]=", 8})) {
+ _vars.push_back(p.nextWord());
+ } else if (p.maybe("warp]=")) {
+ auto vr = p.nextWord();
+ Common::String test;
+ if (p.maybe(','))
+ test = p.nextWord();
+ _currentWarp.reset(new Warp{vr, Common::move(test), {}});
+ if (!_warpsIndex.contains(vr))
+ _warpsIndex[vr] = _warps.size();
+ else
+ warning("duplicate warp %s", vr.c_str());
+ _warps.push_back(_currentWarp);
+ _warpNames.push_back(vr);
+ } else if (p.maybe("test]=")) {
+ if (!_currentWarp)
+ error("test without warp");
+ auto idx = p.nextInt();
+ auto hover = 0;
+ if (!_currentWarp)
+ error("text must have parent wrap section");
+ if (p.maybe(',')) {
+ hover = p.nextInt();
+ }
+ _currentTest.reset(new Test{idx, hover, {}});
+ _currentWarp->tests.push_back(_currentTest);
+ } else {
+ error("invalid [] directive on line %u: %s", lineno, line.c_str());
+ }
+ } else if (_currentTest) {
+ auto &commands = _currentTest->scope.commands;
+ if (p.maybe("ifand=") || p.maybe("ifand")) {
+ if (_pluginScope)
+ error("ifand in plugin scope");
+ _conditional.reset(new IfAnd(p.readStringList()));
+ } else if (p.maybe("ifor=") || p.maybe("ifor")) {
+ if (_pluginScope)
+ error("ifor in plugin scope");
+ _conditional.reset(new IfOr(p.readStringList()));
+ } else if (p.maybe("plugin")) {
+ if (_pluginScope)
+ error("nested plugin context is not allowed, line: %u", lineno);
+ _pluginScope.reset(new Scope);
+ } else if (p.maybe("endplugin")) {
+ if (!_pluginScope)
+ error("endplugin without plugin");
+ if (_conditional) {
+ _conditional->target = Common::move(_pluginScope);
+ _pluginScope.reset();
+ commands.push_back(Common::move(_conditional));
+ _conditional.reset();
+ } else {
+ commands.push_back(Common::move(_pluginScope));
+ _pluginScope.reset();
+ }
+ } else if (p.maybe("label")) {
+ if (_pluginScope)
+ error("no labels in plugin scope allowed");
+ auto name = p.nextWord();
+ auto offset = _currentTest->scope.commands.size();
+ _currentTest->scope.labels.push_back({Common::move(name), offset});
+ } else {
+ if (_pluginScope) {
+ auto name = p.nextWord();
+ p.expect('(');
+ auto args = p.readStringList();
+ p.expect(')');
+ auto cmd = createV1PluginCommand(name, args, lineno);
+ if (cmd)
+ _pluginScope->commands.push_back(Common::move(cmd));
+ else
+ error("unhandled plugin command %s at line %d", line.c_str(), lineno);
+ } else {
+ auto cmd = parseV1Command(p);
+ if (cmd) {
+ if (_conditional) {
+ _conditional->target = Common::move(cmd);
+ commands.push_back(Common::move(_conditional));
+ _conditional.reset();
+ } else
+ commands.push_back(Common::move(cmd));
+ } else
+ error("unhandled script command %s at line %d", line.c_str(), lineno);
+ }
+ }
+ } else
+ error("invalid directive at line %u: %s", lineno, line.c_str());
+}
+
+} // namespace PhoenixVR
diff --git a/engines/phoenixvr/script_v1.h b/engines/phoenixvr/script_v1.h
new file mode 100644
index 00000000000..a672f38e407
--- /dev/null
+++ b/engines/phoenixvr/script_v1.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PHOENIXVR_SCRIPT_V1_H
+#define PHOENIXVR_SCRIPT_V1_H
+
+#include "phoenixvr/script.h"
+
+namespace PhoenixVR {
+class ScriptV1 : public Script {
+public:
+ struct Conditional : public Command {
+ Common::Array<Common::String> vars;
+ CommandPtr target;
+ Conditional(Common::Array<Common::String> args) : vars(Common::move(args)) {}
+ };
+ using ConditionalPtr = Common::SharedPtr<Conditional>;
+
+private:
+ WarpPtr _currentWarp;
+ TestPtr _currentTest;
+ ScopePtr _pluginScope;
+ ConditionalPtr _conditional;
+
+private:
+ void parseLine(const Common::String &line, uint lineno) override;
+};
+} // namespace PhoenixVR
+
+#endif
More information about the Scummvm-git-logs
mailing list