adventure: show whether a backpack item is an upgrade over what's worn
On the owner's own page, each wearable backpack item now carries a compare card: a verdict chip (upgrade / downgrade / sidegrade / new / inert / same), the per-stat deltas, and the name of the worn item it's measured against. gogobee computes all of it — the power math needs tempering and bond state, which live in the engine — so Pete only colours the result and does no arithmetic. It rides the owner-private inventory, so it never reaches the public page; the item names are game-authored, so unlike the LLM dispatch prose there's no injection surface. The verdict chip is always visible (a phone has no hover to lean on) with the deltas beside it. Chip colours mix a fixed hue into --ink for text and --card for fill, so they land on the readable side of the card in all four phases — the same by-construction contrast trick the dungeon map uses, not a Tailwind dark: variant. Screenshot-verified day and night, all six verdict states, including the purple 'new' chip that the theme-contrast history warned about. output.css rebuilt and committed.
This commit is contained in:
@@ -78,6 +78,17 @@ func seedWho(t *testing.T, owner string) *Server {
|
||||
// Wants a bond, but it's in the backpack: not worn, so not inert.
|
||||
{Name: "Ring of Protection", Type: "ring", Tier: 4, Value: 900,
|
||||
Slot: "ring", Attunement: true, Effect: "-8% damage taken"},
|
||||
// A wearable magic item (carries an equip id) with gogobee's compare
|
||||
// card attached: a sidegrade against the worn Flame Tongue.
|
||||
{Name: "Blazing Brand", Type: "weapon", Tier: 5, Value: 4000, ID: 77,
|
||||
Slot: "main_hand", Desc: "A blade that hums.", Effect: "+20% damage",
|
||||
Compare: &storage.ItemCompare{
|
||||
Verdict: "sidegrade", VsName: "Flame Tongue", VsSlot: "main_hand",
|
||||
Deltas: []storage.ItemDelta{
|
||||
{Label: "damage", Better: true, Text: "+5% damage"},
|
||||
{Label: "hp", Better: false, Text: "-4 HP"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
Equipped: []storage.ItemView{
|
||||
{Name: "Flame Tongue", Type: "weapon", Value: 5000, Temper: 1, Slot: "weapon",
|
||||
@@ -220,6 +231,34 @@ func TestWhoInertOnlyWhenWorn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestWhoItemCompare: the compare card that gogobee attaches to a backpack magic
|
||||
// item renders on the owner's page — verdict chip, per-stat deltas, and the name
|
||||
// of the worn item it's measured against — and stays off the public page, since
|
||||
// it rides the owner-private inventory.
|
||||
func TestWhoItemCompare(t *testing.T) {
|
||||
s := seedWho(t, "josie")
|
||||
|
||||
owner := getWho(t, s, "tok-josie", "josie").Body.String()
|
||||
for _, want := range []string{
|
||||
"sidegrade", // the verdict chip
|
||||
"vs worn Flame Tongue", // what it's measured against
|
||||
"5% damage", // the better delta ("+5%" — leading + is escaped to +)
|
||||
"-4 HP", // the worse delta (minus is not escaped)
|
||||
"cmp-delta-up", // the gain is coloured as a gain
|
||||
"cmp-delta-down", // the loss as a loss
|
||||
} {
|
||||
if !strings.Contains(owner, want) {
|
||||
t.Errorf("owner compare card missing %q", want)
|
||||
}
|
||||
}
|
||||
|
||||
// The compare rides the private inventory, so an anonymous visitor never sees it.
|
||||
anon := getWho(t, s, "tok-josie", "").Body.String()
|
||||
if strings.Contains(anon, "sidegrade") || strings.Contains(anon, "Blazing Brand") {
|
||||
t.Error("compare card leaked onto the public page")
|
||||
}
|
||||
}
|
||||
|
||||
// TestWhoSelfUnlockCaseInsensitive: Authentik may hand back a mixed-case
|
||||
// username; the localpart it maps to is lowercase. The owner must still unlock.
|
||||
func TestWhoSelfUnlockCaseInsensitive(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user