N1/A4+A6: wire the stubbed milestone rewards, re-anchor mid-day events

A4 — the three "deferred to hookup" milestone grants now pay out:

  Long Game (T5 clear)   guaranteed Legendary via pickMagicItemForRarity
                         -> dropMagicItemLoot, rendered in a new
                         milestoneAward.Extra block.
  Survivalist (clean T3+) writes AdventureCharacter.Title and announces to
                         the games room. No schema bump — player_meta.title
                         already exists and saveAdvCharacter persists it.
  Two Weeks (day 15)     restocks 3 days of rations (clamped to Supplies.Max)
                         and grants 3 zone-tier consumables.

Two Weeks was specced as +5 max HP "via the expedition row". Dropped: combat
MaxHP comes from stats.HPBonus, built in combat_stats.go from gear/arena/
housing with no expedition in scope. Threading one through would leak an
expedition-only buff into the sim's balance corpus. A supply cache
self-expires with the run and needs no combat math.

A6 — mid-day events rolled 0.5%/player/day from a deferred ticker slot: one
sighting per ~200 days. The roll and its roll-minute scheduler are gone.
Events now fire where the player is demonstrably present and reading a DM:
the end-of-day digest (8%), a sale at Thom's (5%), and an arena cashout (5%),
capped at one event per player per UTC day. A player who hits all three lands
at ~1.19/week. tryTriggerEvent returns bool so a bail (dead / mid-fight /
event already active) hands the day's slot back rather than burning it.

The frequency test drives its own seeded PCG over the chance constants and
the daily cap, so it measures the policy and can't flake on global RNG order.
This commit is contained in:
prosolis
2026-07-09 18:49:19 -07:00
parent c9df282fde
commit b5493a0e79
8 changed files with 481 additions and 92 deletions

View File

@@ -298,6 +298,10 @@ func (p *AdventurePlugin) tryAutoRun(e *Expedition, now time.Time) error {
if err := p.SendDM(uid, body); err != nil {
slog.Warn("expedition: autorun DM", "user", uid, "err", err)
}
// N1/A6 — the end-of-day digest is the primary mid-day event anchor.
if campDecision.Night {
p.maybeFireAnchoredEvent(uid, advEventChanceDigest)
}
}
// Emergence seam: a run-complete reached by the background ticker is