[Scummvm-git-logs] scummvm master -> bd997f5abff2fb1bad57a5289a1bb8afb7716b5e

whoozle noreply at scummvm.org
Sun Jul 19 14:42:40 UTC 2026


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
ceec833d19 PHOENIXVR: add stop sound command
bd997f5abf PHOENIXVR: implement conditionals/hover blocks in V2 script


Commit: ceec833d19cba17fcb1895d904aa3bfe1da1161c
    https://github.com/scummvm/scummvm/commit/ceec833d19cba17fcb1895d904aa3bfe1da1161c
Author: Vladimir Menshakov (vladimir.menshakov at gmail.com)
Date: 2026-07-19T15:22:22+01:00

Commit Message:
PHOENIXVR: add stop sound command

Changed paths:
    engines/phoenixvr/commands_v2.cpp
    engines/phoenixvr/phoenixvr.cpp


diff --git a/engines/phoenixvr/commands_v2.cpp b/engines/phoenixvr/commands_v2.cpp
index c2ebb09d0ba..c5a40d4f01f 100644
--- a/engines/phoenixvr/commands_v2.cpp
+++ b/engines/phoenixvr/commands_v2.cpp
@@ -79,6 +79,15 @@ struct Play_Sound : public Command {
 	}
 };
 
+struct Stop_Sound : public Command {
+	Common::String name;
+	Stop_Sound(const Common::Array<Common::String> &args) : name(args[0]) {}
+
+	void exec(ExecutionContext &ctx) const override {
+		g_engine->stopSound(name);
+	}
+};
+
 struct Stop_All_Sounds : public Command {
 	Stop_All_Sounds(const Common::Array<Common::String> &args) {}
 
@@ -125,6 +134,7 @@ struct Cursor_Set : public Command {
 	E(Play_Sound)       \
 	E(Play_AnimBloc)    \
 	E(Stop_All_Sounds)  \
+	E(Stop_Sound)       \
 	E(Sub)
 
 #define ADD_COMMAND(NAME)            \
diff --git a/engines/phoenixvr/phoenixvr.cpp b/engines/phoenixvr/phoenixvr.cpp
index 75872c4c28b..05958d53eb1 100644
--- a/engines/phoenixvr/phoenixvr.cpp
+++ b/engines/phoenixvr/phoenixvr.cpp
@@ -917,6 +917,7 @@ void PhoenixVREngine::stopSound(const Common::String &sound) {
 }
 
 void PhoenixVREngine::stopAllSounds() {
+	debug("stop all sounds");
 	_mixer->stopAll();
 	_currentMusic.clear();
 	for (auto &kv : _sounds) {


Commit: bd997f5abff2fb1bad57a5289a1bb8afb7716b5e
    https://github.com/scummvm/scummvm/commit/bd997f5abff2fb1bad57a5289a1bb8afb7716b5e
Author: Vladimir Menshakov (vladimir.menshakov at gmail.com)
Date: 2026-07-19T15:40:17+01:00

Commit Message:
PHOENIXVR: implement conditionals/hover blocks in V2 script

Changed paths:
    engines/phoenixvr/script.h
    engines/phoenixvr/script_v1.cpp
    engines/phoenixvr/script_v2.cpp
    engines/phoenixvr/script_v2.h


diff --git a/engines/phoenixvr/script.h b/engines/phoenixvr/script.h
index 5db007f9a26..b61583db58f 100644
--- a/engines/phoenixvr/script.h
+++ b/engines/phoenixvr/script.h
@@ -40,6 +40,8 @@ public:
 		int idx;
 		int hover;
 		Scope scope;
+		ScopePtr enter;
+		ScopePtr leave;
 	};
 	using TestPtr = Common::SharedPtr<Test>;
 
diff --git a/engines/phoenixvr/script_v1.cpp b/engines/phoenixvr/script_v1.cpp
index b6d02ea701c..96f400440bb 100644
--- a/engines/phoenixvr/script_v1.cpp
+++ b/engines/phoenixvr/script_v1.cpp
@@ -101,7 +101,7 @@ void ScriptV1::parseLine(const Common::String &line, uint lineno) {
 			if (p.maybe(',')) {
 				hover = p.nextInt();
 			}
-			_currentTest.reset(new Test{idx, hover, {}});
+			_currentTest.reset(new Test{idx, hover, {}, {}, {}});
 			_currentWarp->tests.push_back(_currentTest);
 		} else {
 			error("invalid [] directive on line %u: %s", lineno, line.c_str());
diff --git a/engines/phoenixvr/script_v2.cpp b/engines/phoenixvr/script_v2.cpp
index 958a3923ca3..265e5ebc4cf 100644
--- a/engines/phoenixvr/script_v2.cpp
+++ b/engines/phoenixvr/script_v2.cpp
@@ -34,8 +34,90 @@ struct SetVariable : public Command {
 		g_engine->setVariable(name, valueOf(value));
 	}
 };
+
+struct IfAnd : public ScriptV2::Conditional {
+	IfAnd(const Common::Array<Common::String> &args) : ScriptV2::Conditional(args) {}
+	void exec(ExecutionContext &ctx) const override {
+		bool result = true;
+		for (auto &c : conditions) {
+			if (!c->value()) {
+				result = false;
+				break;
+			}
+		}
+		branch(ctx, result);
+	}
+};
+
+struct IfOr : public ScriptV2::Conditional {
+	IfOr(const Common::Array<Common::String> &args) : ScriptV2::Conditional(args) {}
+	void exec(ExecutionContext &ctx) const override {
+		bool result = false;
+		for (auto &c : conditions) {
+			if (c->value()) {
+				result = true;
+				break;
+			}
+		}
+		branch(ctx, result);
+	}
+};
 } // namespace
 
+ScriptV2::Conditional::Conditional(const Common::Array<Common::String> &args) {
+	conditions.reserve(args.size());
+	for (auto &arg : args) {
+		conditions.push_back(ConditionPtr{new Condition(arg)});
+	}
+}
+
+void ScriptV2::Conditional::branch(ExecutionContext &ctx, bool branch) const {
+	if (branch && trueScope)
+		trueScope->exec(ctx);
+	if (!branch && falseScope)
+		falseScope->exec(ctx);
+}
+
+ScriptV2::Condition::Condition(const Common::String &text) {
+	if (
+		!parse(text, "!=") &&
+		!parse(text, "<>") &&
+		!parse(text, "<=") &&
+		!parse(text, ">=") &&
+		!parse(text, "<") &&
+		!parse(text, ">") &&
+		!parse(text, "="))
+		error("unknown condition %s", text.c_str());
+}
+
+bool ScriptV2::Condition::parse(const Common::String &text, const Common::String &maybeOp) {
+	auto opPos = text.find(maybeOp);
+	if (opPos == text.npos)
+		return false;
+	arg1 = text.substr(0, opPos);
+	op = maybeOp;
+	arg2 = text.substr(opPos + maybeOp.size());
+	return true;
+}
+
+int ScriptV2::Condition::value() const {
+	auto val1 = Command::valueOf(arg1);
+	auto val2 = Command::valueOf(arg2);
+	if (op == "=")
+		return val1 == val2;
+	else if (op == "!=" || op == "<>")
+		return val1 != val2;
+	else if (op == "<")
+		return val1 < val2;
+	else if (op == "<=")
+		return val1 <= val2;
+	else if (op == ">")
+		return val1 > val2;
+	else if (op == ">=")
+		return val1 >= val2;
+	error("invalid condition %s %s %s", arg1.c_str(), op.c_str(), arg2.c_str());
+}
+
 void ScriptV2::parseLine(const Common::String &line, uint lineno) {
 	if (line.empty())
 		return;
@@ -72,31 +154,64 @@ void ScriptV2::parseLine(const Common::String &line, uint lineno) {
 			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, {}});
+			_currentTest.reset(new Test{idx, 0, {}, {}, {}});
 			_currentWarp->tests.push_back(_currentTest);
+			if (!_conditionals.empty())
+				error("condition didn't have endif at the last test at line %d", lineno);
+			_testScope.reset();
 		} else if (p.maybe("ifand]:")) {
 			if (!_currentTest)
-				error("ifand without test");
+				error("ifand without test at line %d", lineno);
+			ConditionalPtr conditional(new IfAnd(p.readStringList()));
+			conditional->trueScope.reset(new Scope);
+			_conditionalScope = conditional->trueScope;
+			_conditionals.push_back(Common::move(conditional));
 		} else if (p.maybe("ifor]:")) {
 			if (!_currentTest)
-				error("ifor without test");
+				error("ifor without test at line %d", lineno);
+			ConditionalPtr conditional(new IfOr(p.readStringList()));
+			conditional->trueScope.reset(new Scope);
+			_conditionalScope = conditional->trueScope;
+			_conditionals.push_back(Common::move(conditional));
 		} else if (p.maybe("else]")) {
+			if (!_currentTest)
+				error("else without test at line %d", lineno);
+			if (_conditionals.empty())
+				error("else without conditional at line %d", lineno);
+			auto &conditional = _conditionals.back();
+			if (conditional->falseScope)
+				error("double else in condition at line %d", lineno);
+			conditional->falseScope.reset(new Scope());
+			_conditionalScope = conditional->falseScope;
 		} else if (p.maybe("endif]")) {
+			if (!_currentTest)
+				error("endif without test at line %d", lineno);
+			if (_conditionals.empty())
+				error("endif without conditional at line %d", lineno);
+			auto conditional = _conditionals.back();
+			_conditionals.pop_back();
+			_conditionalScope.reset();
+			_currentTest->scope.commands.push_back(Common::move(conditional));
 		} else if (p.maybe("clic]")) {
 			if (!_currentTest)
-				error("clic without test");
+				error("clic without test at line %d", lineno);
+			_testScope.reset();
 		} else if (p.maybe("in]")) {
 			if (!_currentTest)
-				error("clic without test");
+				error("in without test at line %d", lineno);
+			if (_currentTest->enter)
+				error("duplicate [in] handler");
+			_currentTest->enter.reset(new Scope);
+			_testScope = _currentTest->enter;
 		} else if (p.maybe("out]")) {
 			if (!_currentTest)
-				error("clic without test");
+				error("out without test at line %d", lineno);
+			if (_currentTest->leave)
+				error("duplicate [out] handler");
+			_currentTest->leave.reset(new Scope);
+			_testScope = _currentTest->leave;
 		} else {
 			error("invalid [] directive on line %u: %s", lineno, line.c_str());
 		}
@@ -115,12 +230,14 @@ void ScriptV2::parseLine(const Common::String &line, uint lineno) {
 		} else
 			error("invalid syntax at %d", lineno);
 
-		auto &commands = _currentTest->scope.commands;
+		auto &commands = _testScope ? _testScope->commands : _currentTest->scope.commands;
 		if (command)
 			commands.push_back(command);
 		else {
 			warning("unimplemented command %s at line %d", name.c_str(), lineno);
 		}
+	} else {
+		error("command %s is out of the test block at line %d", line.c_str(), lineno);
 	}
 }
 
diff --git a/engines/phoenixvr/script_v2.h b/engines/phoenixvr/script_v2.h
index b56090d3477..f1b6b8b2190 100644
--- a/engines/phoenixvr/script_v2.h
+++ b/engines/phoenixvr/script_v2.h
@@ -27,18 +27,33 @@
 namespace PhoenixVR {
 class ScriptV2 : public Script {
 public:
+	struct Condition {
+		Common::String op;
+		Common::String arg1;
+		Common::String arg2;
+
+		Condition(const Common::String &text);
+		bool parse(const Common::String &text, const Common::String &maybeOp);
+		int value() const;
+	};
+	using ConditionPtr = Common::SharedPtr<Condition>;
+
 	struct Conditional : public Command {
-		Common::Array<Common::String> conditions;
-		CommandPtr target;
-		Conditional(Common::Array<Common::String> args) : conditions(Common::move(args)) {}
+		Common::Array<ConditionPtr> conditions;
+		ScopePtr trueScope;
+		ScopePtr falseScope;
+
+		Conditional(const Common::Array<Common::String> &args);
+		void branch(ExecutionContext &ctx, bool branch) const;
 	};
 	using ConditionalPtr = Common::SharedPtr<Conditional>;
 
 private:
 	WarpPtr _currentWarp;
 	TestPtr _currentTest;
-	ScopePtr _pluginScope;
-	ConditionalPtr _conditional;
+	Common::Array<ConditionalPtr> _conditionals;
+	ScopePtr _conditionalScope;
+	ScopePtr _testScope;
 
 private:
 	void parseLine(const Common::String &line, uint lineno) override;




More information about the Scummvm-git-logs mailing list