载入中...
搜索中...
未找到
QuestSystem.cpp
浏览该文件的文档.
1#include "rpg/QuestSystem.h"
2
3#include "rpg/Quest.h"
4#include "rpg/Tracker.h"
5
6#include <algorithm>
7#include <string>
8#include <vector>
9
10namespace eve::rpg {
11
12namespace {
13
14bool objectivesFull(const QuestRuntime &rt) {
15 for (const auto &o : rt.objectives) {
16 if (!o.done) return false;
17 }
18 return true;
19}
20
21void pushEvent(Tracker *t, QuestEvent ev) { t->pending.push_back(std::move(ev)); }
22
23void pushReject(Tracker *t, const std::string &entryId, const std::string &reason) {
24 QuestEvent ev;
25 ev.entryId = entryId;
26 ev.action = "reject";
27 ev.reason = reason;
28 t->pending.push_back(std::move(ev));
29}
30
31void onObjectivesFull(Tracker *t, QuestRuntime &rt) {
32 const QuestDefinition *def = QuestRegistry::find(rt.id);
33 const std::string policy = def ? def->completePolicy : "auto";
34 if (policy == "claim") {
35 if (rt.state == "ready" || rt.state == "completed") return;
36 rt.state = "ready";
37 pushEvent(t, {rt.id, "", "ready", "", "", 0, ""});
38 } else {
39 if (rt.state == "completed") return;
40 rt.state = "completed";
41 pushEvent(t, {rt.id, "", "complete", "", "", 0, ""});
43 }
44}
45
46} // namespace
47
49 for (const auto &id : def.requiresIds) {
50 auto it = t.entries.find(id);
51 if (it == t.entries.end()) return false;
52 if (it->second.state != "completed") return false;
53 }
54 return true;
55}
56
58 return def.startPolicy == "auto" ? "active" : "inactive";
59}
60
62 if (!t) return;
63 // 1. 补建 Registry 里尚未出现在本 Tracker 上的条目。
64 for (const auto &id : QuestRegistry::ids()) {
65 if (t->entries.count(id)) continue;
66 const QuestDefinition *def = QuestRegistry::find(id);
67 if (!def) continue;
68 QuestRuntime rt;
69 rt.id = id;
70 rt.state = "locked";
71 for (const auto &obj : def->objectives) {
73 orun.id = obj.id;
74 orun.current = 0;
75 orun.count = obj.count > 0 ? obj.count : 1;
76 orun.done = false;
77 rt.objectives.push_back(std::move(orun));
78 }
79 t->entries[id] = std::move(rt);
80 t->order.push_back(id);
81 }
82 // 2. 反复解开前置已齐的 locked 条目。
83 for (size_t pass = 0; pass <= t->entries.size(); ++pass) {
84 bool changed = false;
85 for (auto &[id, rt] : t->entries) {
86 if (rt.state != "locked") continue;
87 const QuestDefinition *def = QuestRegistry::find(id);
88 if (!def) continue;
89 if (!hasMetRequirements(*t, *def)) continue;
90 const std::string newState = stateForUnlocked(*def);
91 rt.state = newState;
92 if (newState == "active") pushEvent(t, {id, "", "activate", "", "", 0, ""});
93 if (newState == "active" && objectivesFull(rt)) onObjectivesFull(t, rt);
94 changed = true;
95 }
96 if (!changed) break;
97 }
98}
99
100std::string QuestSystem::canActivateReason(Tracker *t, const std::string &id) {
101 if (!t) return "unknown";
102 auto it = t->entries.find(id);
103 if (it == t->entries.end()) return "unknown";
104 const QuestDefinition *def = QuestRegistry::find(id);
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";
112 if (!hasMetRequirements(*t, *def)) return "locked";
113 return "";
114}
115
116bool QuestSystem::canActivate(Tracker *t, const std::string &id, std::string *reason) {
117 std::string r = canActivateReason(t, id);
118 if (reason) *reason = r;
119 return r.empty();
120}
121
122bool QuestSystem::activate(Tracker *t, const std::string &id, std::string *reason) {
123 if (!t) {
124 if (reason) *reason = "unknown";
125 return false;
126 }
127 auto it = t->entries.find(id);
128 if (it == t->entries.end()) {
129 if (reason) *reason = "unknown";
130 pushReject(t, id, "unknown");
131 return false;
132 }
133 const std::string why = canActivateReason(t, id);
134 if (!why.empty()) {
135 if (reason) *reason = why;
136 pushReject(t, id, why);
137 return false;
138 }
139 it->second.state = "active";
140 pushEvent(t, {id, "", "activate", "", "", 0, ""});
141 if (objectivesFull(it->second)) onObjectivesFull(t, it->second);
142 return true;
143}
144
145void QuestSystem::notify(Tracker *t, const std::string &topic, const std::string &target, int amount) {
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;
150 const QuestDefinition *def = QuestRegistry::find(id);
151 if (!def) continue;
152 const size_t n = std::min(def->objectives.size(), rt.objectives.size());
153 for (size_t i = 0; i < n; ++i) {
154 const auto &objDef = def->objectives[i];
155 auto & rtObj = rt.objectives[i];
156 if (rtObj.done) continue;
157 if (rtObj.count <= 0) rtObj.count = 1;
158 const bool match =
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, ""});
165 }
166 if (objectivesFull(rt)) fullIds.push_back(id);
167 }
168 for (const auto &fid : fullIds) {
169 auto it = t->entries.find(fid);
170 if (it != t->entries.end()) onObjectivesFull(t, it->second);
171 }
172}
173
174bool QuestSystem::claim(Tracker *t, const std::string &id, std::string *reason) {
175 if (!t) {
176 if (reason) *reason = "unknown";
177 return false;
178 }
179 auto it = t->entries.find(id);
180 if (it == t->entries.end()) {
181 if (reason) *reason = "unknown";
182 pushReject(t, id, "unknown");
183 return false;
184 }
185 if (it->second.state != "ready") {
186 if (reason) *reason = it->second.state;
187 pushReject(t, id, it->second.state);
188 return false;
189 }
190 it->second.state = "completed";
191 pushEvent(t, {id, "", "complete", "", "", 0, ""});
192 syncAuto(t);
193 return true;
194}
195
196bool QuestSystem::reset(Tracker *t, const std::string &id) {
197 if (!t) return false;
198 auto it = t->entries.find(id);
199 if (it == t->entries.end()) return false; // 未知 id:false,无事件
200 const QuestDefinition *def = QuestRegistry::find(id);
201 QuestRuntime & rt = it->second;
202 rt.objectives.clear();
203 if (def) {
204 for (const auto &obj : def->objectives) {
205 ObjectiveRuntime orun;
206 orun.id = obj.id;
207 orun.current = 0;
208 orun.count = obj.count > 0 ? obj.count : 1;
209 orun.done = false;
210 rt.objectives.push_back(std::move(orun));
211 }
212 }
213 rt.state = (def && hasMetRequirements(*t, *def)) ? stateForUnlocked(*def) : std::string("locked");
214 pushEvent(t, {id, "", "reset", "", "", 0, ""});
215 if (rt.state == "active" && objectivesFull(rt)) onObjectivesFull(t, rt);
216 return true;
217}
218
219namespace {
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");
225 return false;
226 }
227 const std::string &st = it->second.state;
228 if (st != "inactive" && st != "active" && st != "ready") {
229 pushReject(t, id, st);
230 return false;
231 }
232 it->second.state = "failed";
233 pushEvent(t, {id, "", "fail", "", "", 0, reason});
234 return true;
235}
236} // namespace
237
238bool QuestSystem::abandon(Tracker *t, const std::string &id) { return failImpl(t, id, "abandon"); }
239
240bool QuestSystem::fail(Tracker *t, const std::string &id, const std::string &reason) {
241 return failImpl(t, id, reason);
242}
243
244void QuestSystem::pollEvents(Tracker *t, std::vector<QuestEvent> &out) {
245 out.clear();
246 if (!t) return;
247 t->pollEvents();
248 out = t->polled;
249}
250
251} // namespace eve::rpg
LogicalId target
glm::vec3 n
Definition Grass.cpp:63
double r
std::string id
Definition PlayHost.cpp:108
float t
目标追踪器的状态机与匹配行为。
任务 / 成就 / 教程的通用定义模板与进程级注册表。
Battle::Objectives objectives
目标追踪器运行时实例(玩家日志 / 成就 / 教程可各建一份)。
static std::vector< std::string > ids()
Ids.
Definition Quest.cpp:172
static const QuestDefinition * find(const std::string &id)
Find a registered quest definition by id.
Definition Quest.cpp:160
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 (脚本兼容门面))。
一份任务进度 + 本实例事件队列。
Definition Tracker.h:26
RPG 模块的基础实体:把属性 / 状态 / 技能三张表挂到一个 ECS 实体上。
单条目标的运行时进度。
Definition QuestTypes.h:33
数据驱动的任务模板。
Definition Quest.h:24
std::string startPolicy
"manual" | "auto",缺省 "manual"。
Definition Quest.h:27
std::vector< std::string > requiresIds
本 Tracker 上须已 completed 的条目 id,全部 AND。
Definition Quest.h:31
std::vector< QuestObjective > objectives
Definition Quest.h:32
一条任务在本 Tracker 上的运行时状态。
Definition QuestTypes.h:41
std::vector< ObjectiveRuntime > objectives
Definition QuestTypes.h:45
std::string state
locked | inactive | active | ready | completed | failed
Definition QuestTypes.h:44