14bool objectivesFull(
const QuestRuntime &rt) {
16 if (!o.done)
return false;
21void pushEvent(Tracker *
t, QuestEvent ev) {
t->pending.push_back(std::move(ev)); }
23void pushReject(Tracker *
t,
const std::string &entryId,
const std::string &reason) {
28 t->pending.push_back(std::move(ev));
31void onObjectivesFull(Tracker *
t, QuestRuntime &rt) {
33 const std::string policy = def ? def->completePolicy :
"auto";
34 if (policy ==
"claim") {
35 if (rt.state ==
"ready" || rt.state ==
"completed")
return;
37 pushEvent(
t, {rt.id,
"",
"ready",
"",
"", 0,
""});
39 if (rt.state ==
"completed")
return;
40 rt.state =
"completed";
41 pushEvent(
t, {rt.id,
"",
"complete",
"",
"", 0,
""});
50 auto it =
t.entries.find(
id);
51 if (it ==
t.entries.end())
return false;
52 if (it->second.state !=
"completed")
return false;
58 return def.
startPolicy ==
"auto" ?
"active" :
"inactive";
65 if (
t->entries.count(
id))
continue;
75 orun.
count = obj.count > 0 ? obj.count : 1;
79 t->entries[
id] = std::move(rt);
80 t->order.push_back(
id);
83 for (
size_t pass = 0; pass <=
t->entries.size(); ++pass) {
85 for (
auto &[
id, rt] :
t->entries) {
86 if (rt.state !=
"locked")
continue;
92 if (newState ==
"active") pushEvent(
t, {
id,
"",
"activate",
"",
"", 0,
""});
93 if (newState ==
"active" && objectivesFull(rt)) onObjectivesFull(
t, rt);
101 if (!
t)
return "unknown";
102 auto it =
t->entries.find(
id);
103 if (it ==
t->entries.end())
return "unknown";
105 if (!def)
return "unknown";
106 const std::string &
state = it->second.state;
107 if (
state ==
"locked")
return "locked";
108 if (
state ==
"active")
return "alreadyActive";
109 if (
state ==
"completed")
return "alreadyCompleted";
110 if (
state ==
"failed")
return "failed";
111 if (
state ==
"ready")
return "ready";
118 if (reason) *reason =
r;
124 if (reason) *reason =
"unknown";
127 auto it =
t->entries.find(
id);
128 if (it ==
t->entries.end()) {
129 if (reason) *reason =
"unknown";
130 pushReject(
t,
id,
"unknown");
135 if (reason) *reason = why;
136 pushReject(
t,
id, why);
139 it->second.state =
"active";
140 pushEvent(
t, {
id,
"",
"activate",
"",
"", 0,
""});
141 if (objectivesFull(it->second)) onObjectivesFull(
t, it->second);
146 if (!
t || amount <= 0)
return;
147 std::vector<std::string> fullIds;
148 for (
auto &[
id, rt] :
t->entries) {
149 if (rt.state !=
"active")
continue;
152 const size_t n = std::min(def->
objectives.size(), rt.objectives.size());
153 for (
size_t i = 0; i <
n; ++i) {
155 auto & rtObj = rt.objectives[i];
156 if (rtObj.done)
continue;
157 if (rtObj.count <= 0) rtObj.count = 1;
159 objDef.topic == topic && (objDef.target.empty() || objDef.target ==
target);
160 if (!match)
continue;
161 const int added = std::min(amount, rtObj.count - rtObj.current);
162 rtObj.current += added;
163 if (rtObj.current >= rtObj.count) rtObj.done =
true;
164 pushEvent(
t, {
id, rtObj.id,
"progress", topic,
target, added,
""});
166 if (objectivesFull(rt)) fullIds.push_back(
id);
168 for (
const auto &fid : fullIds) {
169 auto it =
t->entries.find(fid);
170 if (it !=
t->entries.end()) onObjectivesFull(
t, it->second);
176 if (reason) *reason =
"unknown";
179 auto it =
t->entries.find(
id);
180 if (it ==
t->entries.end()) {
181 if (reason) *reason =
"unknown";
182 pushReject(
t,
id,
"unknown");
185 if (it->second.state !=
"ready") {
186 if (reason) *reason = it->second.state;
187 pushReject(
t,
id, it->second.state);
190 it->second.state =
"completed";
191 pushEvent(
t, {
id,
"",
"complete",
"",
"", 0,
""});
197 if (!
t)
return false;
198 auto it =
t->entries.find(
id);
199 if (it ==
t->entries.end())
return false;
208 orun.
count = obj.count > 0 ? obj.count : 1;
214 pushEvent(
t, {
id,
"",
"reset",
"",
"", 0,
""});
215 if (rt.
state ==
"active" && objectivesFull(rt)) onObjectivesFull(
t, rt);
220bool failImpl(
Tracker *
t,
const std::string &
id,
const std::string &reason) {
221 if (!
t)
return false;
222 auto it =
t->entries.find(
id);
223 if (it ==
t->entries.end()) {
224 pushReject(
t,
id,
"unknown");
227 const std::string &st = it->second.state;
228 if (st !=
"inactive" && st !=
"active" && st !=
"ready") {
229 pushReject(
t,
id, st);
232 it->second.state =
"failed";
233 pushEvent(
t, {
id,
"",
"fail",
"",
"", 0, reason});
241 return failImpl(
t,
id, reason);
任务 / 成就 / 教程的通用定义模板与进程级注册表。
Battle::Objectives objectives
目标追踪器运行时实例(玩家日志 / 成就 / 教程可各建一份)。
static std::vector< std::string > ids()
Ids.
static const QuestDefinition * find(const std::string &id)
Find a registered quest definition by id.
static bool canActivate(Tracker *t, const std::string &id, std::string *reason=nullptr)
是否可激活(谓词查询,可返回 reason)。
static bool reset(Tracker *t, const std::string &id)
进度清零并按当前 requires 回落 locked/inactive/active;不级联(compatibility facade (脚本兼容门面))。
static bool claim(Tracker *t, const std::string &id, std::string *reason=nullptr)
仅 state==ready 时成功 → completed 并触发解锁;否则 reject(compatibility facade (脚本兼容门面))。
static void syncAuto(Tracker *t)
补建 Registry 里尚不在 Tracker 上的条目,并解开前置已齐的 locked 条目。
static std::string canActivateReason(Tracker *t, const std::string &id)
不可激活的原因("" 可激活,否则 unknown/locked/alreadyActive/alreadyCompleted/failed/ready)。
static std::string stateForUnlocked(const QuestDefinition &def)
解锁后的落点:startPolicy==auto → "active",否则 "inactive"。
static bool hasMetRequirements(const Tracker &t, const QuestDefinition &def)
def 的全部 requires 在本 Tracker 上均已 completed(谓词查询)。
static bool fail(Tracker *t, const std::string &id, const std::string &reason)
Fail.
static bool activate(Tracker *t, const std::string &id, std::string *reason=nullptr)
激活:仅 inactive 且前置已齐时成功;否则 push reject 并返回 false(compatibility facade (脚本兼容门面))。
static void pollEvents(Tracker *t, std::vector< QuestEvent > &out)
把 Tracker 的 pending 移动并清空到 out。
static void notify(Tracker *t, const std::string &topic, const std::string &target, int amount)
报告事实 (topic, target, amount);只推进 state==active 的条目。
static bool abandon(Tracker *t, const std::string &id)
abandon/fail → failed;对 completed/failed/locked/未知 id 为 reject(compatibility facade (脚本兼容门面))。
RPG 模块的基础实体:把属性 / 状态 / 技能三张表挂到一个 ECS 实体上。
std::string startPolicy
"manual" | "auto",缺省 "manual"。
std::vector< std::string > requiresIds
本 Tracker 上须已 completed 的条目 id,全部 AND。
std::vector< QuestObjective > objectives
std::vector< ObjectiveRuntime > objectives
std::string state
locked | inactive | active | ready | completed | failed