载入中...
搜索中...
未找到
SkillSystem.cpp
浏览该文件的文档.
1#include "rpg/SkillSystem.h"
2#include "rpg/RPGActor.h"
3#include "rpg/Skill.h"
5#include "rpg/StatusSystem.h"
6
7#include <unordered_map>
8
9namespace eve::rpg {
10
11namespace {
12
13std::unordered_map<std::string, SkillSystem::CastCondition> &conditions() {
14 static std::unordered_map<std::string, SkillSystem::CastCondition> c;
15 return c;
16}
17
18std::vector<SkillCastEvent> &castQueue() {
19 static std::vector<SkillCastEvent> q;
20 return q;
21}
22
23bool checkCostsAffordable(RPGActor *actor, const SkillDefinition &def) {
24 for (const auto &cost : def.costs)
25 if (AttributeSystem::getFinal(actor, cost.attribute) < cost.amount) return false;
26 return true;
27}
28
29void deductCosts(RPGActor *actor, const SkillDefinition &def) {
30 for (const auto &cost : def.costs) AttributeSystem::modifyBase(actor, cost.attribute, -cost.amount);
31}
32
33void resolveCast(RPGActor *actor, const SkillDefinition &def, RPGActor *target) {
34 RPGActor *effectTarget = target ? target : actor;
35 for (const std::string &effectId : def.grantedEffects)
36 StatusSystem::apply(effectTarget, effectId, "skill:" + def.id);
37
38 SkillCastEvent evt;
39 evt.caster = actor;
40 evt.target = target;
41 evt.skillId = def.id;
42 castQueue().push_back(std::move(evt));
43}
44
45} // namespace
46
48 conditions()[name] = std::move(fn);
49}
50
51void SkillSystem::unregisterCastCondition(const std::string &name) { conditions().erase(name); }
52
53void SkillSystem::clearCastConditions() { conditions().clear(); }
54
55void SkillSystem::learn(RPGActor *actor, const std::string &skillId) {
56 if (!actor || skillId.empty()) return;
57 actor->skills()->known[skillId]; // default-constructs SkillRuntime if absent
58}
59
60bool SkillSystem::knows(RPGActor *actor, const std::string &skillId) {
61 if (!actor) return false;
62 auto &known = actor->skills()->known;
63 return known.find(skillId) != known.end();
64}
65
66bool SkillSystem::forget(RPGActor *actor, const std::string &skillId) {
67 if (!actor) return false;
68 return actor->skills()->known.erase(skillId) > 0;
69}
70
71float SkillSystem::getCooldownRemaining(RPGActor *actor, const std::string &skillId) {
72 if (!actor) return 0.f;
73 auto &known = actor->skills()->known;
74 auto it = known.find(skillId);
75 return it == known.end() ? 0.f : it->second.cooldownRemaining;
76}
77
78void SkillSystem::setCooldownRemaining(RPGActor *actor, const std::string &skillId, float seconds) {
79 if (!actor) return;
80 actor->skills()->known[skillId].cooldownRemaining = seconds;
81}
82
83bool SkillSystem::canCast(RPGActor *actor, const std::string &skillId, std::string *reason) {
84 auto fail = [&](const std::string &r) {
85 if (reason) *reason = r;
86 return false;
87 };
88 if (!actor) return fail("no_actor");
89 const SkillDefinition *def = SkillRegistry::find(skillId);
90 if (!def) return fail("unknown_skill");
91 if (!knows(actor, skillId)) return fail("not_learned");
92 if (isCasting(actor)) return fail("already_casting");
93 if (getCooldownRemaining(actor, skillId) > 0.f) return fail("on_cooldown");
94 if (!checkCostsAffordable(actor, *def)) return fail("insufficient_cost");
95
96 for (auto &kv : conditions()) {
97 std::string r;
98 if (!kv.second(actor, *def, r)) return fail(r.empty() ? kv.first : r);
99 }
100 return true;
101}
102
103bool SkillSystem::beginCast(RPGActor *actor, const std::string &skillId, RPGActor *target,
104 std::string *reason) {
105 if (!canCast(actor, skillId, reason)) return false;
106 const SkillDefinition *def = SkillRegistry::find(skillId);
107
108 deductCosts(actor, *def);
109 setCooldownRemaining(actor, skillId, def->cooldown);
110
111 if (def->castTime <= 0.f) {
112 resolveCast(actor, *def, target);
113 return true;
114 }
115
116 CastingState &cs = actor->skills()->casting;
117 cs.active = true;
118 cs.skillId = skillId;
119 cs.remaining = def->castTime;
120 cs.totalCastTime = def->castTime;
121 cs.target = target;
122 return true;
123}
124
126 if (!actor) return;
127 actor->skills()->casting = CastingState{};
128}
129
130bool SkillSystem::isCasting(RPGActor *actor) { return actor && actor->skills()->casting.active; }
131
133 return actor ? actor->skills()->casting.skillId : std::string{};
134}
135
137 if (!actor) return 0.f;
138 const CastingState &cs = actor->skills()->casting;
139 if (!cs.active || cs.totalCastTime <= 0.f) return 0.f;
140 float p = 1.f - (cs.remaining / cs.totalCastTime);
141 return p < 0.f ? 0.f : (p > 1.f ? 1.f : p);
142}
143
144void SkillSystem::update(float dt) {
145 for (RPGActor *actor : RPGActor::liveActors()) {
146 for (auto &kv : actor->skills()->known)
147 if (kv.second.cooldownRemaining > 0.f) kv.second.cooldownRemaining -= dt;
148
149 CastingState &cs = actor->skills()->casting;
150 if (!cs.active) continue;
151 cs.remaining -= dt;
152 if (cs.remaining <= 0.f) {
154 RPGActor *target = cs.target;
155 cs.active = false; // clear before resolveCast in case it re-enters casting
156 if (def) resolveCast(actor, *def, target);
157 }
158 }
159}
160
161void SkillSystem::pollCastEvents(std::vector<SkillCastEvent> &out) {
162 auto &q = castQueue();
163 for (auto &e : q) out.push_back(std::move(e));
164 q.clear();
165}
166
167} // namespace eve::rpg
std::string id
uint32_t c
std::vector< float > cost
glm::vec4 p[6]
const char * name
Definition RockMesh.cpp:21
SettlementPipeline::Stage fn
属性 / 状态 / 技能三表合一的 ECS 实体。
Definition RPGActor.h:28
static const std::vector< RPGActor * > & liveActors()
返回所有通过 createActor() 创建、且当前仍存活的 actor。 StatusSystem::update / SkillSystem::update 用它遍历所有 actor 逐帧推进。 ...
Definition RPGActor.cpp:33
static const SkillDefinition * find(const std::string &id)
Definition Skill.cpp:28
static bool forget(RPGActor *actor, const std::string &skillId)
static void update(float dt)
遍历 RPGActor::liveActors():冷却倒计时 + 读条推进/结算。
static void cancelCast(RPGActor *actor)
打断当前读条(不退还已扣除的消耗/冷却)。
static std::string getCastingSkillId(RPGActor *actor)
static float getCastProgress(RPGActor *actor)
0..1,非读条状态返回 0
static void setCooldownRemaining(RPGActor *actor, const std::string &skillId, float seconds)
static bool isCasting(RPGActor *actor)
static void clearCastConditions()
static void unregisterCastCondition(const std::string &name)
static float getCooldownRemaining(RPGActor *actor, const std::string &skillId)
static void learn(RPGActor *actor, const std::string &skillId)
std::function< bool(RPGActor *actor, const SkillDefinition &def, std::string &outReason)> CastCondition
返回 false 表示禁止释放;通过 outReason 说明原因。
Definition SkillSystem.h:24
static bool knows(RPGActor *actor, const std::string &skillId)
static void registerCastCondition(const std::string &name, CastCondition fn)
static bool canCast(RPGActor *actor, const std::string &skillId, std::string *reason=nullptr)
检查冷却/消耗/学会状态/自定义条件,不产生任何副作用。
static bool beginCast(RPGActor *actor, const std::string &skillId, RPGActor *target=nullptr, std::string *reason=nullptr)
尝试释放技能:通过 canCast 检查后立即扣除消耗并进入冷却; castTime<=0 时立即结算(授予效果 + 产生 SkillCastEvent), 否则进入读条状态,由 update() 在读...
static void pollCastEvents(std::vector< SkillCastEvent > &out)
RPG 模块入口:属性 / 效果 / 状态 / 技能 / 结算五套系统的脚本绑定与帧调度点。
施法状态:同一时间每个 actor 只有一个进行中的引导/读条(可按需扩展为多槽)。
Definition SkillTypes.h:16
class RPGActor * target
Definition SkillTypes.h:21
float castTime
0 = 瞬发
Definition Skill.h:27