载入中...
搜索中...
未找到
LevelSystem.cpp
浏览该文件的文档.
1#include "rpg/LevelSystem.h"
2
3#include "rpg/RPGActor.h"
4
5#include <cmath>
6
7namespace eve::rpg {
8
9namespace {
10std::vector<LevelUpEvent> &levelUpEvents() {
11 static std::vector<LevelUpEvent> events;
12 return events;
13}
14} // namespace
15
17 return actor ? actor->progression()->level : 1;
18}
19
21 return actor ? actor->progression()->xp : 0.0;
22}
23
25 return actor ? actor->progression()->xpToNext : 100.0;
26}
27
29 if (!actor) return;
30 actor->progression()->xpToNext = value > 0.0 ? value : 0.0;
31}
32
34 if (!actor) return;
35 actor->progression()->level = level > 0 ? level : 1;
36}
37
38eve::Result<void> LevelSystem::restoreProgression(RPGActor *actor, int level, double xp, double xpToNext) {
39 if (!actor)
41 eve::DiagnosticCode::InvalidArgument, "progression restore requires an actor", "actor"));
42 if (level < 1)
44 eve::DiagnosticCode::InvalidArgument, "progression level must be positive", "level"));
45 if (!std::isfinite(xp) || xp < 0.0)
47 eve::DiagnosticCode::InvalidArgument, "progression xp must be finite and non-negative", "xp"));
48 if (!std::isfinite(xpToNext) || xpToNext <= 0.0 || xp >= xpToNext)
51 "progression threshold must be finite, positive and greater than current xp", "xpToNext"));
52 auto candidate = *actor->progression();
53 candidate.level = level;
54 candidate.xp = xp;
55 candidate.xpToNext = xpToNext;
56 *actor->progression() = candidate;
58}
59
60bool LevelSystem::gainXp(RPGActor *actor, double amount, double xpGrowth) {
61 auto prepared = prepareGainXp(actor, amount, xpGrowth);
62 if (!prepared.ok()) return false;
63 auto committed = commitGainXp(std::move(prepared).takeValue());
64 return committed.ok() && std::move(committed).takeValue() > 0;
65}
66
68 double xpGrowth) {
69 if (!actor)
71 eve::DiagnosticCode::InvalidArgument, "XP gain requires an actor", "actor"));
72 if (!std::isfinite(amount) || amount <= 0.0)
74 eve::DiagnosticCode::InvalidArgument, "XP gain must be finite and positive", "amount"));
75 if (!std::isfinite(xpGrowth) || xpGrowth < 1.0)
77 eve::DiagnosticCode::InvalidArgument, "XP growth must be finite and at least one", "xpGrowth"));
78 const auto &current = *actor->progression();
79 if (current.level < 1 || !std::isfinite(current.xp) || current.xp < 0.0 ||
80 !std::isfinite(current.xpToNext) || current.xpToNext <= 0.0 || current.xp >= current.xpToNext)
82 eve::DiagnosticCode::InvariantViolation, "actor progression is not valid for XP gain", "progression"));
83
85 prepared.actor_ = actor;
86 prepared.previousLevel_ = current.level;
87 prepared.previousXp_ = current.xp;
88 prepared.previousXpToNext_ = current.xpToNext;
89 prepared.nextLevel_ = current.level;
90 prepared.nextXp_ = current.xp + amount;
91 prepared.nextXpToNext_ = current.xpToNext;
92 if (!std::isfinite(prepared.nextXp_))
94 eve::DiagnosticCode::InvalidArgument, "XP gain would overflow progression", "amount"));
95 constexpr int maxLevelsPerGain = 10000;
96 int levels = 0;
97 while (prepared.nextXp_ >= prepared.nextXpToNext_) {
98 if (++levels > maxLevelsPerGain)
101 "XP gain exceeds the maximum levels allowed in one transaction", "amount"));
102 prepared.nextXp_ -= prepared.nextXpToNext_;
103 ++prepared.nextLevel_;
104 prepared.nextXpToNext_ *= xpGrowth;
105 if (!std::isfinite(prepared.nextXpToNext_) || prepared.nextXpToNext_ <= 0.0)
107 eve::DiagnosticCode::InvalidArgument, "XP growth would overflow progression", "xpGrowth"));
108 }
110 std::move(prepared), eve::Status::success(eve::StatusCode::Pending));
111}
112
114 if (!prepared.actor_)
116 eve::DiagnosticCode::InvalidArgument, "prepared XP gain is empty", "prepared"));
117 auto &current = *prepared.actor_->progression();
118 if (current.level != prepared.previousLevel_ || current.xp != prepared.previousXp_ ||
119 current.xpToNext != prepared.previousXpToNext_)
121 eve::DiagnosticCode::Conflict, "actor progression changed after XP preparation", "progression"));
122 current.level = prepared.nextLevel_;
123 current.xp = prepared.nextXp_;
124 current.xpToNext = prepared.nextXpToNext_;
125 const int levels = prepared.nextLevel_ - prepared.previousLevel_;
126 for (int offset = 0; offset < levels; ++offset) {
127 LevelUpEvent event;
128 event.actor = prepared.actor_;
129 event.previousLevel = prepared.previousLevel_ + offset;
130 event.newLevel = event.previousLevel + 1;
131 levelUpEvents().push_back(std::move(event));
132 }
134}
135
136void LevelSystem::pollLevelUps(std::vector<LevelUpEvent> &out) {
137 out.clear();
138 out = std::move(levelUpEvents());
139 levelUpEvents().clear();
140}
141
142} // namespace eve::rpg
double value
size_t offset
角色成长:等级 / 经验 / 升级。
int level
double current
Battle::Events events
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
static eve::Result< PreparedProgressionGain > prepareGainXp(RPGActor *actor, double amount, double xpGrowth=1.2)
Validate an XP gain and calculate its complete progression candidate without mutation/events.
static void setXpToNext(RPGActor *actor, double value)
设置当前等级的升级阈值。
static void pollLevelUps(std::vector< LevelUpEvent > &out)
取出并清空自上次调用以来累积的升级事件(push/poll 风格)。
static eve::Result< int > commitGainXp(PreparedProgressionGain prepared)
Commit a prepared XP gain if actor progression is still unchanged.
static double getXpToNext(RPGActor *actor)
升级所需经验。
static double getXp(RPGActor *actor)
当前经验。
static eve::Result< void > restoreProgression(RPGActor *actor, int level, double xp, double xpToNext)
Atomically restore one validated progression checkpoint.
static bool gainXp(RPGActor *actor, double amount, double xpGrowth=1.2)
增加经验;每跨过阈值升一级并发出 LevelUpEvent(compatibility facade (脚本兼容门面))。
static int getLevel(RPGActor *actor)
当前等级(无 progression 时返回 1)。
static void setLevel(RPGActor *actor, int level)
直接设定等级(不改经验;用于读档/初始化)。
Move-only progression gain prepared against one actor revision.
Definition LevelSystem.h:25
属性 / 状态 / 技能三表合一的 ECS 实体。
Definition RPGActor.h:34
RPG 模块的基础实体:把属性 / 状态 / 技能三张表挂到一个 ECS 实体上。
升级事件。
Definition LevelSystem.h:44
class RPGActor * actor
Definition LevelSystem.h:45