feat(battle-xp): BattleXpGrantResult carries LeveledUp signal
BattleXpGrantResult gains a LeveledUp bool set true iff at least one curve threshold was crossed during the grant (comparing pre-Level to post-Level after the level-up loop). Callers will gate class_level_up mission emits on this flag rather than caching pre-state themselves. No behavior change for existing callers — they read GetXp/TotalXp/Level today and never check LeveledUp yet. Tests cover: unchanged level → false, single threshold → true, multi-threshold within one grant → still true, unknown class guardrail → false. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ public sealed class BattleXpService : IBattleXpService
|
||||
_log.LogWarning(
|
||||
"BattleXpService: viewer {ViewerId} has no ViewerClassData for classId {ClassId}; skipping grant.",
|
||||
viewer.Id, classId);
|
||||
return new BattleXpGrantResult(0, 0, 1);
|
||||
return new BattleXpGrantResult(0, 0, 1, LeveledUp: false);
|
||||
}
|
||||
|
||||
int amount = ResolveAmount(mode, isWin);
|
||||
@@ -42,6 +42,7 @@ public sealed class BattleXpService : IBattleXpService
|
||||
var byLevel = curve.ToDictionary(e => e.Id, e => e.NecessaryExp);
|
||||
int maxLevel = curve.Count == 0 ? row.Level : curve.Max(e => e.Id);
|
||||
|
||||
int startingLevel = row.Level;
|
||||
while (row.Level < maxLevel
|
||||
&& byLevel.TryGetValue(row.Level, out var needed)
|
||||
&& row.Exp >= needed)
|
||||
@@ -50,7 +51,7 @@ public sealed class BattleXpService : IBattleXpService
|
||||
row.Level += 1;
|
||||
}
|
||||
|
||||
return new BattleXpGrantResult(amount, row.Exp, row.Level);
|
||||
return new BattleXpGrantResult(amount, row.Exp, row.Level, LeveledUp: row.Level > startingLevel);
|
||||
}
|
||||
|
||||
private int ResolveAmount(BattleXpMode mode, bool isWin)
|
||||
|
||||
@@ -6,8 +6,11 @@ namespace SVSim.Database.Services.BattleXp;
|
||||
/// Amounts returned to callers after a class-XP grant. <see cref="TotalXp"/> and
|
||||
/// <see cref="Level"/> are POST-grant, POST-level-up (matching the wire shape's
|
||||
/// <c>class_experience</c> + <c>class_level</c> post-state semantics).
|
||||
/// <see cref="LeveledUp"/> is <c>true</c> iff at least one level threshold was
|
||||
/// crossed during this grant — callers gate <c>class_level_up</c> mission emits
|
||||
/// on this flag rather than caching pre-state themselves.
|
||||
/// </summary>
|
||||
public sealed record BattleXpGrantResult(int GetXp, int TotalXp, int Level);
|
||||
public sealed record BattleXpGrantResult(int GetXp, int TotalXp, int Level, bool LeveledUp);
|
||||
|
||||
public interface IBattleXpService
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user