Compare commits
2 Commits
99574db3e9
...
6ccd18452c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ccd18452c | ||
|
|
e85ebe56f7 |
@@ -194,6 +194,14 @@ func advEventMeta(eventType string) (label, emoji string) {
|
|||||||
return "Pulled out", "🎒"
|
return "Pulled out", "🎒"
|
||||||
case "departure":
|
case "departure":
|
||||||
return "Wandered off", "🚪"
|
return "Wandered off", "🚪"
|
||||||
|
case "mischief_contract":
|
||||||
|
return "Coin on their head", "😈"
|
||||||
|
case "mischief_survived":
|
||||||
|
return "They walked away", "🛡️"
|
||||||
|
case "mischief_downed":
|
||||||
|
return "The contract landed", "💀"
|
||||||
|
case "mischief_fizzled":
|
||||||
|
return "Nobody home", "🚪"
|
||||||
}
|
}
|
||||||
return "Dispatch", "📣"
|
return "Dispatch", "📣"
|
||||||
}
|
}
|
||||||
@@ -401,6 +409,37 @@ func renderAdventure(f AdvFact) (headline, lede string, ok bool) {
|
|||||||
// the joke tells itself, and the player it's about may well be reading.
|
// the joke tells itself, and the player it's about may well be reading.
|
||||||
return fmt.Sprintf("%s got bored and left without waiting.", f.Subject),
|
return fmt.Sprintf("%s got bored and left without waiting.", f.Subject),
|
||||||
fmt.Sprintf("No orders, no escort, no fuss — %s packed the cheapest kit on the shelf and set off into %s%s. Nobody told them to. Nobody talked them out of it either. We'll let you know how it goes.", f.Subject, f.Zone, atLevel), true
|
fmt.Sprintf("No orders, no escort, no fuss — %s packed the cheapest kit on the shelf and set off into %s%s. Nobody told them to. Nobody talked them out of it either. We'll let you know how it goes.", f.Subject, f.Zone, atLevel), true
|
||||||
|
case "mischief_contract":
|
||||||
|
// Somebody paid to have a monster sent after an adventurer who is out in a
|
||||||
|
// dungeon right now. Anonymous unless the buyer paid extra to sign it, and
|
||||||
|
// the anonymity is the story: Pete reports the money, not the name he
|
||||||
|
// doesn't have. Opponent carries the buyer only when it's public.
|
||||||
|
if f.Opponent != "" {
|
||||||
|
return fmt.Sprintf("%s has put %s on %s's head.", f.Opponent, f.Stakes, f.Subject),
|
||||||
|
fmt.Sprintf("No secret about it — %s paid for a %s to go find %s out in whatever hole they're currently down, and signed the thing. It's out there looking right now. If %s comes back breathing, they keep a cut of that money.",
|
||||||
|
f.Opponent, strings.ToLower(f.Boss), f.Subject, f.Subject), true
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Someone's put %s on %s's head.", f.Stakes, f.Subject),
|
||||||
|
fmt.Sprintf("Word came in quiet: %s has been paid for a %s to go looking for %s, and whoever paid it isn't saying so. It's already out there. Survive it and the money's theirs — and we all find out who signed the cheque.",
|
||||||
|
f.Stakes, strings.ToLower(f.Boss), f.Subject), true
|
||||||
|
case "mischief_survived":
|
||||||
|
// The unseal. A survival is the only thing that names an anonymous buyer,
|
||||||
|
// and it is the whole brake on casual griefing — so Pete leads with it.
|
||||||
|
return fmt.Sprintf("%s walked away from it. It was %s who paid.", f.Subject, f.Opponent),
|
||||||
|
fmt.Sprintf("%s came for %s, and %s is the one still standing — %s richer for the trouble. The contract's been opened up, and the name inside it is %s. Make of that what you will, folks.",
|
||||||
|
f.Boss, f.Subject, f.Subject, f.Stakes, f.Opponent), true
|
||||||
|
case "mischief_downed":
|
||||||
|
who := "Nobody's saying who paid for it"
|
||||||
|
if f.Opponent != "" {
|
||||||
|
who = fmt.Sprintf("%s paid for it, and put their name on it", f.Opponent)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s didn't walk away.", f.Subject),
|
||||||
|
fmt.Sprintf("A %s found %s mid-run%s and put them on the floor. They're being carried home — alive, which is more than the contract asked for, but that expedition's finished. %s.",
|
||||||
|
f.Boss, f.Subject, atLevel, who), true
|
||||||
|
case "mischief_fizzled":
|
||||||
|
return fmt.Sprintf("The monster sent for %s arrived to an empty dungeon.", f.Subject),
|
||||||
|
fmt.Sprintf("Somebody spent good money to have %s ambushed, and %s had already gone home. It wandered the halls for a bit and left. Most of the fee's been refunded. The rest, the town's keeping.",
|
||||||
|
f.Subject, f.Subject), true
|
||||||
case "arrival":
|
case "arrival":
|
||||||
return fmt.Sprintf("Welcome to the realm, %s!", f.Subject),
|
return fmt.Sprintf("Welcome to the realm, %s!", f.Subject),
|
||||||
fmt.Sprintf("A new %s just walked through the gates. Say hello if you see them out there.", f.ClassRace), true
|
fmt.Sprintf("A new %s just walked through the gates. Say hello if you see them out there.", f.ClassRace), true
|
||||||
|
|||||||
@@ -311,3 +311,61 @@ func TestAdventureDisabled(t *testing.T) {
|
|||||||
t.Errorf("disabled: status = %d, want 404", rw.Code)
|
t.Errorf("disabled: status = %d, want 404", rw.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRenderMischief: gogobee's four mischief event types must all render. An
|
||||||
|
// unknown event_type is a 400 at ingest, which gogobee retries and then parks
|
||||||
|
// forever — so "Pete deploys first" only helps if Pete actually knows the types.
|
||||||
|
//
|
||||||
|
// It also pins the anonymity contract, which is the feature's whole social
|
||||||
|
// engine: an unsigned contract must not name the buyer, and a survival must.
|
||||||
|
func TestRenderMischief(t *testing.T) {
|
||||||
|
anon := AdvFact{EventType: "mischief_contract", Tier: "priority",
|
||||||
|
Subject: "Josie", Boss: "Elite", Stakes: "€350", Level: 14}
|
||||||
|
hl, lede, ok := renderAdventure(anon)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("mischief_contract did not render — ingest would 400")
|
||||||
|
}
|
||||||
|
if strings.Contains(hl+lede, "Brannigan") {
|
||||||
|
t.Error("anonymous contract leaked a buyer name")
|
||||||
|
}
|
||||||
|
if !strings.Contains(hl, "€350") {
|
||||||
|
t.Errorf("contract headline lost the stakes: %q", hl)
|
||||||
|
}
|
||||||
|
|
||||||
|
signed := anon
|
||||||
|
signed.Opponent = "Brannigan"
|
||||||
|
hl, _, ok = renderAdventure(signed)
|
||||||
|
if !ok || !strings.Contains(hl, "Brannigan") {
|
||||||
|
t.Errorf("signed contract should name the buyer: %q (ok=%v)", hl, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The unseal: a survival names the buyer whether or not they signed.
|
||||||
|
survived := AdvFact{EventType: "mischief_survived", Tier: "priority",
|
||||||
|
Subject: "Josie", Opponent: "Brannigan", Boss: "Bone Colossus", Stakes: "€228"}
|
||||||
|
hl, _, ok = renderAdventure(survived)
|
||||||
|
if !ok || !strings.Contains(hl, "Brannigan") {
|
||||||
|
t.Errorf("survival must unseal the buyer: %q (ok=%v)", hl, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A downed target with an anonymous buyer stays anonymous — being maimed
|
||||||
|
// doesn't buy you the name.
|
||||||
|
downed := AdvFact{EventType: "mischief_downed", Tier: "priority",
|
||||||
|
Subject: "Josie", Boss: "Bone Colossus", Level: 14}
|
||||||
|
hl, lede, ok = renderAdventure(downed)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("mischief_downed did not render")
|
||||||
|
}
|
||||||
|
if strings.Contains(hl+lede, "Brannigan") {
|
||||||
|
t.Error("anonymous buyer named on a downed contract")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, ok := renderAdventure(AdvFact{EventType: "mischief_fizzled", Subject: "Josie", Stakes: "€315"}); !ok {
|
||||||
|
t.Error("mischief_fizzled did not render")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, et := range []string{"mischief_contract", "mischief_survived", "mischief_downed", "mischief_fizzled"} {
|
||||||
|
if lbl, _ := advEventMeta(et); lbl == "Dispatch" {
|
||||||
|
t.Errorf("%s has no permalink label", et)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user