Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/leaderboard/leaderboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import (
// Leaderboard keys constants.
const (
LBEarningsBonus = "eb"
LBPrestigedEarningsBonus = "prestiged_eb"
LBFutureEarningsBonus = "future_eb"
LBPendingEarningsBonus = LBFutureEarningsBonus // Deprecated: use LBFutureEarningsBonus
LBPrestigedEarningsBonus = LBEarningsBonus // Deprecated: use LBEarningsBonus
LBSoulEggs = "soul_eggs"
LBProphecyEggs = "prophecy_eggs"
LBTerrorEvents = "terror_events"
Expand Down Expand Up @@ -111,8 +113,8 @@ type LBGroup struct {
var AllLeaderboards = []LBDef{
{Key: LBSoulEggs, DisplayName: "Soul Eggs", HeaderName: "SE", Description: "Total soul eggs collected.", ValueFmt: "ei", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBProphecyEggs, DisplayName: "Prophecy Eggs", HeaderName: "PE", Description: "Total eggs of prophecy collected.", ValueFmt: "int", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBEarningsBonus, DisplayName: "Earnings Bonus", Description: "Nekkid and Dressed earnings bonus (includes pending TE).", ValueFmt: "eb", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBPrestigedEarningsBonus, DisplayName: "Prestiged Earnings Bonus", Description: "Nekkid and Dressed earnings bonus (excludes pending TE).", ValueFmt: "eb", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBEarningsBonus, DisplayName: "Earnings Bonus", Description: "Nekkid and Dressed earnings bonus (excludes pending TE).", ValueFmt: "eb", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBFutureEarningsBonus, DisplayName: "Future Earnings Bonus", Description: "Nekkid and Dressed earnings bonus (includes pending TE).", ValueFmt: "eb", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBVirtueShifts, DisplayName: "Virtue Shifts", HeaderName: "Shifts", Description: "Total virtue shifts completed.", ValueFmt: "int", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBTETotal, DisplayName: "Total Truth Eggs", HeaderName: "TE", Description: "Sum of truth eggs across all virtues.", ValueFmt: "int", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
{Key: LBCTETotal, DisplayName: "Total CTE", HeaderName: "CTE", Description: "Clothed Truth Egg equivalent for pending and current TE.", ValueFmt: "int", HigherIsBetter: true, Source: SourceFirstContact, RetainRecentOnly: true},
Expand Down Expand Up @@ -142,7 +144,7 @@ var AllGroups = []LBGroup{
{
Key: "group_core",
DisplayName: "EB Stats",
Members: []string{LBEarningsBonus, LBPrestigedEarningsBonus, LBSoulEggs, LBProphecyEggs, LBTETotal, LBCTETotal, LBVirtueShifts, LBPrestiges},
Members: []string{LBEarningsBonus, LBFutureEarningsBonus, LBSoulEggs, LBProphecyEggs, LBTETotal, LBCTETotal, LBVirtueShifts, LBPrestiges},
},
{
Key: "group_cs_stats",
Expand Down Expand Up @@ -287,7 +289,11 @@ var legacyKeyAliases = map[string]string{
"cxp_weekly_delta": LBCXPWeeklyDelta,
"group_prestige_stats": "group_misc",
LBVirtueTEEarnedSum: LBVirtueEggsSum,
"eb_prestiged": LBPrestigedEarningsBonus,
"prestiged_eb": LBEarningsBonus,
"eb_prestiged": LBEarningsBonus,
"pending_eb": LBFutureEarningsBonus,
"eb_pending": LBFutureEarningsBonus,
"eb_future": LBFutureEarningsBonus,
}

func resolveAlias(key string) string {
Expand Down
24 changes: 12 additions & 12 deletions src/leaderboard/leaderboard_calculators.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,36 +203,36 @@ func RunCalculators(
emit(LBEntry{LBType: LBSoulEggs, Player: userID, GameName: gameName, SnapDate: snapDate, Value: game.GetSoulEggsD()})
emit(LBEntry{LBType: LBProphecyEggs, Player: userID, GameName: gameName, SnapDate: snapDate, Value: float64(game.GetEggsOfProphecy())})

// For Earnings Bonus, we need total Truth Eggs (EoV) including pending TE
// For Future Earnings Bonus, we need total Truth Eggs (EoV) including pending TE
totalTE := 0.0
if virtue != nil {
deliveries := virtue.GetEggsDelivered()
for i := 0; i < 5 && i < len(deliveries); i++ {
totalTE += float64(ei.CountTruthEggTiersPassed(deliveries[i]))
}
}
nakedEB := ei.GetEarningsBonus(backup, totalTE)
dressedEB := ei.GetDressedEarningsBonus(backup, totalTE)
futureNakedEB := ei.GetEarningsBonus(backup, totalTE)
futureDressedEB := ei.GetDressedEarningsBonus(backup, totalTE)
emit(LBEntry{
LBType: LBEarningsBonus,
LBType: LBFutureEarningsBonus,
Player: userID,
GameName: gameName,
SnapDate: snapDate,
Value: nakedEB,
Details: fmt.Sprintf("dressed:%.6f", dressedEB),
Value: futureNakedEB,
Details: fmt.Sprintf("dressed:%.6f", futureDressedEB),
})

// For Prestiged Earnings Bonus, we use credited/prestiged Truth Eggs (excludes pending TE)
// For Earnings Bonus, we use credited/prestiged Truth Eggs (excludes pending TE)
prestigedTE := float64(ei.GetCurrentTruthEggs(backup))
prestigedNakedEB := ei.GetEarningsBonus(backup, prestigedTE)
prestigedDressedEB := ei.GetDressedEarningsBonus(backup, prestigedTE)
nakedEB := ei.GetEarningsBonus(backup, prestigedTE)
dressedEB := ei.GetDressedEarningsBonus(backup, prestigedTE)
emit(LBEntry{
LBType: LBPrestigedEarningsBonus,
LBType: LBEarningsBonus,
Player: userID,
GameName: gameName,
SnapDate: snapDate,
Value: prestigedNakedEB,
Details: fmt.Sprintf("dressed:%.6f", prestigedDressedEB),
Value: nakedEB,
Details: fmt.Sprintf("dressed:%.6f", dressedEB),
})
}

Expand Down
82 changes: 50 additions & 32 deletions src/leaderboard/leaderboard_calculators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,31 @@ func TestRunCalculators_EarningsBonusPendingVsPrestiged(t *testing.T) {
"user-test-1",
backup,
nil,
[]string{LBEarningsBonus, LBPrestigedEarningsBonus},
[]string{LBEarningsBonus, LBFutureEarningsBonus},
"2026-10-12",
0,
)

var entryEB, entryPrestigedEB *LBEntry
var entryEB, entryFutureEB *LBEntry
for i := range entries {
if entries[i].LBType == LBEarningsBonus {
entryEB = &entries[i]
}
if entries[i].LBType == LBPrestigedEarningsBonus {
entryPrestigedEB = &entries[i]
if entries[i].LBType == LBFutureEarningsBonus {
entryFutureEB = &entries[i]
}
}

if entryEB == nil {
t.Fatalf("expected %s entry to be emitted", LBEarningsBonus)
}
if entryPrestigedEB == nil {
t.Fatalf("expected %s entry to be emitted", LBPrestigedEarningsBonus)
if entryFutureEB == nil {
t.Fatalf("expected %s entry to be emitted", LBFutureEarningsBonus)
}

if entryEB.Value <= entryPrestigedEB.Value {
t.Errorf("expected Earnings Bonus (%f) to be strictly greater than Prestiged Earnings Bonus (%f) when pending TE > 0",
entryEB.Value, entryPrestigedEB.Value)
if entryFutureEB.Value <= entryEB.Value {
t.Errorf("expected Future Earnings Bonus (%f) to be strictly greater than Earnings Bonus (%f) when pending TE > 0",
entryFutureEB.Value, entryEB.Value)
}

// 2. Without pending TE (earned TE matches tiers passed)
Expand All @@ -59,28 +59,28 @@ func TestRunCalculators_EarningsBonusPendingVsPrestiged(t *testing.T) {
"user-test-1",
backup,
nil,
[]string{LBEarningsBonus, LBPrestigedEarningsBonus},
[]string{LBEarningsBonus, LBFutureEarningsBonus},
"2026-10-12",
0,
)

var entryEB2, entryPrestigedEB2 *LBEntry
var entryEB2, entryFutureEB2 *LBEntry
for i := range entriesNoPending {
if entriesNoPending[i].LBType == LBEarningsBonus {
entryEB2 = &entriesNoPending[i]
}
if entriesNoPending[i].LBType == LBPrestigedEarningsBonus {
entryPrestigedEB2 = &entriesNoPending[i]
if entriesNoPending[i].LBType == LBFutureEarningsBonus {
entryFutureEB2 = &entriesNoPending[i]
}
}

if entryEB2 == nil || entryPrestigedEB2 == nil {
if entryEB2 == nil || entryFutureEB2 == nil {
t.Fatalf("expected both entries to be emitted when no pending TE")
}

if entryEB2.Value != entryPrestigedEB2.Value {
t.Errorf("expected Earnings Bonus (%f) to equal Prestiged Earnings Bonus (%f) when pending TE == 0",
entryEB2.Value, entryPrestigedEB2.Value)
if entryEB2.Value != entryFutureEB2.Value {
t.Errorf("expected Earnings Bonus (%f) to equal Future Earnings Bonus (%f) when pending TE == 0",
entryEB2.Value, entryFutureEB2.Value)
}
}

Expand All @@ -89,38 +89,56 @@ func TestEarningsBonusRegistryDefinitions(t *testing.T) {
if !okEB {
t.Fatalf("expected definition for %s", LBEarningsBonus)
}
if !strings.Contains(defEB.Description, "pending TE") {
t.Errorf("expected %s description to mention pending TE, got %q", LBEarningsBonus, defEB.Description)
if defEB.DisplayName != "Earnings Bonus" {
t.Errorf("expected %s display name to be 'Earnings Bonus', got %q", LBEarningsBonus, defEB.DisplayName)
}
if !strings.Contains(defEB.Description, "excludes pending TE") {
t.Errorf("expected %s description to mention excluding pending TE, got %q", LBEarningsBonus, defEB.Description)
}

defPrestigedEB, okPrestigedEB := LBDefByKey(LBPrestigedEarningsBonus)
if !okPrestigedEB {
t.Fatalf("expected definition for %s", LBPrestigedEarningsBonus)
defFutureEB, okFutureEB := LBDefByKey(LBFutureEarningsBonus)
if !okFutureEB {
t.Fatalf("expected definition for %s", LBFutureEarningsBonus)
}
if defFutureEB.DisplayName != "Future Earnings Bonus" {
t.Errorf("expected %s display name to be 'Future Earnings Bonus', got %q", LBFutureEarningsBonus, defFutureEB.DisplayName)
}
if !strings.Contains(defPrestigedEB.Description, "excludes pending TE") {
t.Errorf("expected %s description to mention excluding pending TE, got %q", LBPrestigedEarningsBonus, defPrestigedEB.Description)
if !strings.Contains(defFutureEB.Description, "includes pending TE") {
t.Errorf("expected %s description to mention including pending TE, got %q", LBFutureEarningsBonus, defFutureEB.Description)
}

// Verify alias
if resolveAlias("eb_prestiged") != LBPrestigedEarningsBonus {
t.Errorf("expected alias eb_prestiged to resolve to %s, got %s", LBPrestigedEarningsBonus, resolveAlias("eb_prestiged"))
// Verify aliases
if resolveAlias("prestiged_eb") != LBEarningsBonus {
t.Errorf("expected alias prestiged_eb to resolve to %s, got %s", LBEarningsBonus, resolveAlias("prestiged_eb"))
}
if resolveAlias("eb_prestiged") != LBEarningsBonus {
t.Errorf("expected alias eb_prestiged to resolve to %s, got %s", LBEarningsBonus, resolveAlias("eb_prestiged"))
}
if resolveAlias("pending_eb") != LBFutureEarningsBonus {
t.Errorf("expected alias pending_eb to resolve to %s, got %s", LBFutureEarningsBonus, resolveAlias("pending_eb"))
}
if resolveAlias("eb_pending") != LBFutureEarningsBonus {
t.Errorf("expected alias eb_pending to resolve to %s, got %s", LBFutureEarningsBonus, resolveAlias("eb_pending"))
}
if resolveAlias("eb_future") != LBFutureEarningsBonus {
t.Errorf("expected alias eb_future to resolve to %s, got %s", LBFutureEarningsBonus, resolveAlias("eb_future"))
}

// Verify group_core contains both
groupCoreMembers := ExpandConfigKey("group_core")
foundEB, foundPrestigedEB := false, false
foundEB, foundFutureEB := false, false
for _, m := range groupCoreMembers {
if m == LBEarningsBonus {
foundEB = true
}
if m == LBPrestigedEarningsBonus {
foundPrestigedEB = true
if m == LBFutureEarningsBonus {
foundFutureEB = true
}
}
if !foundEB {
t.Errorf("expected %s in group_core members", LBEarningsBonus)
}
if !foundPrestigedEB {
t.Errorf("expected %s in group_core members", LBPrestigedEarningsBonus)
if !foundFutureEB {
t.Errorf("expected %s in group_core members", LBFutureEarningsBonus)
}
}
2 changes: 1 addition & 1 deletion src/leaderboard/leaderboard_post.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ func renderTable(def LBDef, rows []LBEntry, prevMap map[string]float64, rankOffs
rankWidth := runewidth.StringWidth(rankHeader)
maxValOnlyWidth := runewidth.StringWidth(shortDisplayName)

isEB := def.Key == LBEarningsBonus || def.Key == LBPrestigedEarningsBonus
isEB := def.Key == LBEarningsBonus || def.Key == LBFutureEarningsBonus
hasCTEComparisonColumn := def.Key == LBCTETotal
hasTEColumn := def.Key == LBEggsCuriosity || def.Key == LBEggsIntegrity || def.Key == LBEggsHumility || def.Key == LBEggsResilience || def.Key == LBEggsKindness || def.Key == LBVirtueEggsSum
teWidth := runewidth.StringWidth("TE")
Expand Down
4 changes: 2 additions & 2 deletions src/leaderboard/leaderboard_post_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestRenderTable_AllLeaderboards(t *testing.T) {
}

switch {
case def.Key == LBEarningsBonus || def.Key == LBPrestigedEarningsBonus:
case def.Key == LBEarningsBonus || def.Key == LBFutureEarningsBonus:
row.Details = "dressed:23456"
case def.Key == LBCXPWeeklyDelta:
row.Details = "na"
Expand Down Expand Up @@ -127,7 +127,7 @@ func TestRenderTable_AllLeaderboards(t *testing.T) {
}
}

if def.Key == LBEarningsBonus || def.Key == LBPrestigedEarningsBonus {
if def.Key == LBEarningsBonus || def.Key == LBFutureEarningsBonus {
if !strings.Contains(colHeader, "Nekkid") || !strings.Contains(colHeader, "Dressed") {
t.Fatalf("expected EB columns for %s, got %q", def.Key, colHeader)
}
Expand Down
Loading