refactor(battle-xp): retire ArenaTwoPickConfig.ClassXpPerBattle for shared BattleXpService

- ArenaTwoPickService now delegates class-XP grants to IBattleXpService
  with BattleXpMode.ArenaTwoPick. Inline GrantClassXp/ResolveClassLevel
  helpers deleted.
- ClassXpPerBattle field removed from ArenaTwoPickConfig; TK2 XP now
  configurable via ArenaTwoPickXpPerWin/XpPerLoss overrides or the global
  BattleXpConfig defaults (100/25).
- Updated 5 test files (ArenaTwoPickService callers) for the new
  constructor arg. Added loss-XP assertion to Finish tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-04 08:54:52 -04:00
parent 81771bb0a0
commit f85f221bfa
7 changed files with 31 additions and 23 deletions

View File

@@ -6,6 +6,7 @@ using SVSim.Database.Models;
using SVSim.Database.Repositories.Globals;
using SVSim.Database.Repositories.Viewer;
using SVSim.Database.Services;
using SVSim.Database.Services.BattleXp;
using SVSim.Database.Services.Inventory;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common.ArenaTwoPick;
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses.ArenaTwoPick;
@@ -20,6 +21,7 @@ public class ArenaTwoPickService : IArenaTwoPickService
private readonly IGameConfigService _config;
private readonly IViewerRepository _viewers;
private readonly IInventoryService _inv;
private readonly IBattleXpService _xp;
private readonly IRandom _rng;
private readonly SVSimDbContext _db;
@@ -30,11 +32,12 @@ public class ArenaTwoPickService : IArenaTwoPickService
IGameConfigService config,
IViewerRepository viewers,
IInventoryService inv,
IBattleXpService xp,
IRandom rng,
SVSimDbContext db)
{
_runs = runs; _rewards = rewards; _pool = pool; _config = config;
_viewers = viewers; _inv = inv; _rng = rng; _db = db;
_viewers = viewers; _inv = inv; _xp = xp; _rng = rng; _db = db;
}
public async Task<TopResponseDto> GetTopAsync(long viewerId)
@@ -375,8 +378,7 @@ public class ArenaTwoPickService : IArenaTwoPickService
var viewer = await LoadViewerForGrantsAsync(viewerId);
int before = (int)(viewer.Currency?.SpotPoints ?? 0);
int newClassXp = GrantClassXp(viewer, run.ClassId, aCfg.ClassXpPerBattle);
int classLevel = ResolveClassLevel(viewer, run.ClassId);
var xp = await _xp.GrantAsync(viewer, run.ClassId, isWin, BattleXpMode.ArenaTwoPick);
viewer.Currency!.SpotPoints += (ulong)aCfg.SpotPointsPerBattle;
int after = (int)viewer.Currency.SpotPoints;
@@ -385,29 +387,15 @@ public class ArenaTwoPickService : IArenaTwoPickService
return new BattleFinishResultDto
{
BattleResult = isWin ? 1 : 0,
GetClassExperience = aCfg.ClassXpPerBattle,
ClassExperience = newClassXp,
ClassLevel = classLevel,
GetClassExperience = xp.GetXp,
ClassExperience = xp.TotalXp,
ClassLevel = xp.Level,
BeforeSpotPoint = before,
AddSpotPoint = aCfg.SpotPointsPerBattle,
AfterSpotPoint = after,
};
}
private static int GrantClassXp(SVSim.Database.Models.Viewer viewer, int classId, int xp)
{
var row = viewer.Classes.FirstOrDefault(c => c.Class.Id == classId);
if (row is null) return 0;
row.Exp += xp;
return row.Exp;
}
private static int ResolveClassLevel(SVSim.Database.Models.Viewer viewer, int classId)
{
var row = viewer.Classes.FirstOrDefault(c => c.Class.Id == classId);
return row is null ? 1 : row.Level;
}
// --- projection helpers (kept internal so test subclasses could exercise if needed) ---
internal static EntryInfoDto ProjectEntryInfo(ViewerArenaTwoPickRun run, long viewerId) => new()