mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 00:52:40 +00:00
mischief: price a ward against the thing it wards off
The M1 close-out sweep (new, skip-gated: n=400/cell through the REAL delivery path, not SimulateCombat) says three wards buy roughly +40pp of survival — a level 12 fighter meeting a boss at 70% HP goes from 48% to 90%. At a flat €25 that let three friends halve a €1,200 boss contract for €75, which makes the tier the entire economy rests on feel like money thrown away. A ward now costs max(€25, 10% of the contract): €25 at grunt and mob, €35 at elite, €120 at a boss — so covering someone against a boss costs the town €360. Still a bargain against €1,200, but it has to be a real rally rather than pocket change. It reads the contract's current basis, so an escalation raises the price of saving its target too: the counterplay tracks the threat. The sweep also shows the M0 fee table was priced on a fight we don't deliver. Its control arm (full HP) diverges from M0 in both directions — up where an engine timeout now counts as survival, down where the turn engine loops a boss's full multiattack profile and SimulateCombat doesn't. And the arm M0 could not see at all, a wounded mid-run target, is the one that matters: boss tier at 70% HP collapses everywhere. Fees stand; the tiers still do what they were priced to do. The real-path table is now the reference.
This commit is contained in:
@@ -586,6 +586,36 @@ func mischiefCtx(sender id.UserID) MessageContext {
|
||||
return MessageContext{Sender: sender, RoomID: id.RoomID("!room:x"), EventID: id.EventID("$e")}
|
||||
}
|
||||
|
||||
// A ward is priced against the thing it defends against. The M1-close-out sweep
|
||||
// measured three wards buying ~+40pp of survival, which at a flat fee let the room
|
||||
// halve a €1,200 boss contract for €75 — the tier the whole economy rests on,
|
||||
// bought off for pocket change. Cheap at the impulse tiers, real money at the top.
|
||||
func TestMischiefBlessingFee_ScalesWithTheContract(t *testing.T) {
|
||||
want := map[string]int{"grunt": 25, "mob": 25, "elite": 35, "boss": 120}
|
||||
for _, tier := range mischiefTiers {
|
||||
if got := mischiefBlessingFee(tier.Fee); got != want[tier.Key] {
|
||||
t.Errorf("%s ward = %d, want %d", tier.Key, got, want[tier.Key])
|
||||
}
|
||||
// Where a ward is a rational purchase — the tiers the sweep says can
|
||||
// actually put someone on the floor — covering a target must cost less than
|
||||
// the contract does. Otherwise the room's counterplay is priced out and the
|
||||
// window is dead.
|
||||
//
|
||||
// Grunt and mob are deliberately exempt: the €25 floor is above-market
|
||||
// there (3 wards cost more than a €40 grunt), and that is fine, because
|
||||
// nothing in the sweep needs warding against theatre — those tiers sit at
|
||||
// 100% survival unwounded. The floor is there to keep a ward an impulse
|
||||
// buy, not to make it a sensible one against a goblin.
|
||||
if tier.Key != "elite" && tier.Key != "boss" {
|
||||
continue
|
||||
}
|
||||
if full := mischiefBlessingFee(tier.Fee) * mischiefBlessingCap; full >= tier.Fee {
|
||||
t.Errorf("%s: %d wards cost %d, which is more than the %d contract — "+
|
||||
"the room can't afford to save anyone", tier.Key, mischiefBlessingCap, full, tier.Fee)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The cap lives in the UPDATE, not in the read that precedes it. A room that
|
||||
// piles four wards on in the same second must still land exactly three — and the
|
||||
// player who lost that race must get their money back rather than pay for
|
||||
@@ -629,6 +659,7 @@ func TestMischiefBlessing_FeeIsASinkNotAPurseTopUp(t *testing.T) {
|
||||
|
||||
c := seedContract(t, "@buyer:x", target, "elite", false)
|
||||
feeBefore := c.Fee
|
||||
ward := mischiefBlessingFee(c.Fee) // 10% of the €350 elite fee
|
||||
|
||||
if err := p.mischiefBlessCmd(mischiefCtx(friend), []string{string(target)}); err != nil {
|
||||
t.Fatalf("bless: %v", err)
|
||||
@@ -642,11 +673,11 @@ func TestMischiefBlessing_FeeIsASinkNotAPurseTopUp(t *testing.T) {
|
||||
t.Errorf("a blessing moved the payout basis to %d (was %d) — wards must not pay the target",
|
||||
got.Fee, feeBefore)
|
||||
}
|
||||
if bal := p.euro.GetBalance(friend); bal != 500-mischiefBlessingFee {
|
||||
t.Errorf("blesser balance %.0f, want %d", bal, 500-mischiefBlessingFee)
|
||||
if bal := p.euro.GetBalance(friend); bal != float64(500-ward) {
|
||||
t.Errorf("blesser balance %.0f, want %d", bal, 500-ward)
|
||||
}
|
||||
if pot := communityPotBalance(); pot != mischiefBlessingFee {
|
||||
t.Errorf("pot holds %d, want the %d blessing fee", pot, mischiefBlessingFee)
|
||||
if pot := communityPotBalance(); pot != ward {
|
||||
t.Errorf("pot holds %d, want the %d ward fee", pot, ward)
|
||||
}
|
||||
// Broke, so the second ward can't be bought — and must cost nothing.
|
||||
pauper := id.UserID("@pauper:x")
|
||||
|
||||
Reference in New Issue
Block a user