From c85608753d53d04f104fb3bfdd8ad57278943beb Mon Sep 17 00:00:00 2001 From: Eldbury Date: Wed, 22 Apr 2026 21:52:25 +0930 Subject: [PATCH] Fix trigger action updates and dialogue continuation semantics --- include/reone/game/object.h | 1 + src/libs/game/object.cpp | 29 ++++++++++++++++++++++++++++- src/libs/game/object/area.cpp | 2 +- src/libs/game/object/trigger.cpp | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/reone/game/object.h b/include/reone/game/object.h index 5f50f2909..69ea5e78b 100644 --- a/include/reone/game/object.h +++ b/include/reone/game/object.h @@ -256,6 +256,7 @@ class Object : public scene::IUser, boost::noncopyable { std::deque> _actions; std::vector _delayed; + std::weak_ptr _executingAction; // END Actions diff --git a/src/libs/game/object.cpp b/src/libs/game/object.cpp index ebe9c6716..cd6733ca6 100644 --- a/src/libs/game/object.cpp +++ b/src/libs/game/object.cpp @@ -65,6 +65,26 @@ void Object::setLocalNumber(int index, int value) { } void Object::clearAllActions(bool force) { + // If the current front action clears the queue while it is executing, keep + // that action and its queued continuation alive instead of trimming from the + // back and deleting the follow-up it is about to hand off to. + if (!force) { + auto executingAction = _executingAction.lock(); + if (executingAction) { + while (!_actions.empty() && _actions.front() != executingAction) { + const std::shared_ptr &action = _actions.front(); + if (action->locked()) { + break; + } + action->cancel(action, *this); + _actions.pop_front(); + } + if (!_actions.empty() && _actions.front() == executingAction) { + return; + } + } + } + while (!_actions.empty()) { const std::shared_ptr &action = _actions.back(); if (!force && action->locked()) { @@ -129,7 +149,14 @@ void Object::executeActions(float dt) { return; } std::shared_ptr action(_actions.front()); - action->execute(action, *this, dt); + _executingAction = action; + try { + action->execute(action, *this, dt); + } catch (...) { + _executingAction.reset(); + throw; + } + _executingAction.reset(); } bool Object::hasUserActionsPending() const { diff --git a/src/libs/game/object/area.cpp b/src/libs/game/object/area.cpp index 6661dc415..5697c9e79 100644 --- a/src/libs/game/object/area.cpp +++ b/src/libs/game/object/area.cpp @@ -802,7 +802,7 @@ void Area::startDialog(const std::shared_ptr &object, const std::string if (resRef.empty()) { finalResRef = object->conversation(); } - if (resRef.empty()) { + if (finalResRef.empty()) { return; } _game.startDialog(object, finalResRef); diff --git a/src/libs/game/object/trigger.cpp b/src/libs/game/object/trigger.cpp index 29779a80c..afe58fd34 100644 --- a/src/libs/game/object/trigger.cpp +++ b/src/libs/game/object/trigger.cpp @@ -83,6 +83,8 @@ void Trigger::loadFromBlueprint(const std::string &resRef) { } void Trigger::update(float dt) { + Object::update(dt); + std::set> tenantsToRemove; for (auto &tenant : _tenants) { if (tenant) {