N7/B4: Renown achievements wing

Three passive achievements (renown_1/5/10) gated on the derived Renown level
via renownAtLeast, reading player_meta.renown_xp through the achievements
plugin's existing Check(d, userID) seam. No event hook — the passive checker
grants them on the next message once the level is reached.

Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
This commit is contained in:
prosolis
2026-07-10 20:09:30 -07:00
parent aaa45eab14
commit 1a47a2fdee
2 changed files with 56 additions and 0 deletions

View File

@@ -147,6 +147,32 @@ func TestAddRenownXP_Accumulates(t *testing.T) {
}
}
// TestRenownAtLeast — the B4 achievement gate reads the derived level correctly.
func TestRenownAtLeast(t *testing.T) {
newRenownTestDB(t)
uid := id.UserID("@renown_ach:example")
if err := createAdvCharacter(uid, "Achiever"); err != nil {
t.Fatal(err)
}
d := db.Get()
if renownAtLeast(d, uid, 1) {
t.Errorf("no renown yet, should not meet level 1")
}
if _, _, err := addRenownXP(uid, renownXPPerLevel*5); err != nil {
t.Fatal(err)
}
if !renownAtLeast(d, uid, 5) {
t.Errorf("renown 5 should meet level 5")
}
if renownAtLeast(d, uid, 6) {
t.Errorf("renown 5 should not meet level 6")
}
// Absent player → false, not a crash.
if renownAtLeast(d, id.UserID("@nobody:nowhere.invalid"), 1) {
t.Errorf("absent player should not meet any renown level")
}
}
// TestRenownOverlay — applyPlayerMetaOverlay populates RenownXP and RenownLevel.
func TestRenownOverlay(t *testing.T) {
newRenownTestDB(t)