mirror of
https://github.com/prosolis/gogobee.git
synced 2026-09-14 19:01:09 +00:00
adventure: give tier 6 a treasure rate, and stop it lying about near misses
advTreasureDropRates stopped at tier 5, so every Mythic-zone roll returned nil before it reached a pool: postgame zones have dropped no treasure at all since T6 shipped. Add the rate, deliberately above T5's rather than continuing the downward curve — a Mythic run is gated behind L18 and both T5 bosses, so the same declining rate would mean a postgame player never sees one. The rate alone drops nothing: there is no advAllTreasures[6] yet, and writing those four items is content work, not a code fix. TODO in place where the pool goes, and a test that goes red the day it lands. An empty pool now reports a zero rate instead of the configured one. The caller reads a close roll as "treasure: just missed" — with a rate but no pool that DM fires on the rolls the player actually won, for a treasure that cannot be won. Better to say nothing until there is something to win.
This commit is contained in:
@@ -46,6 +46,16 @@ var advTreasureDropRates = map[int]float64{
|
|||||||
3: 0.008,
|
3: 0.008,
|
||||||
4: 0.004,
|
4: 0.004,
|
||||||
5: 0.0015,
|
5: 0.0015,
|
||||||
|
// Tier 6 (Mythic post-game) breaks the downward curve on purpose. The rate
|
||||||
|
// per roll falls tier over tier because the lower tiers are ground daily;
|
||||||
|
// a Mythic run is gated behind L18 and both T5 bosses and happens rarely,
|
||||||
|
// so the same declining rate would mean a postgame player effectively never
|
||||||
|
// sees a treasure. Slightly above T5 keeps the per-run odds in the band the
|
||||||
|
// other tiers land in.
|
||||||
|
//
|
||||||
|
// NOTE: this rate is inert until advAllTreasures gains a tier 6 pool — see
|
||||||
|
// the TODO there. A tier with a rate but no pool drops nothing.
|
||||||
|
6: 0.002,
|
||||||
}
|
}
|
||||||
|
|
||||||
const advMaxTreasures = 3
|
const advMaxTreasures = 3
|
||||||
@@ -221,6 +231,13 @@ var advAllTreasures = map[int][]AdvTreasureDef{
|
|||||||
InventoryDesc: "The Ocarina (Cracked). Three songs. +10 all skills. Do not play the third one.",
|
InventoryDesc: "The Ocarina (Cracked). Three songs. +10 all skills. Do not play the third one.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// TODO(t6-treasures): there is no tier 6 pool yet, so Mythic zones drop no
|
||||||
|
// treasure at all — advTreasureDropRates has a tier 6 rate waiting for it.
|
||||||
|
// What's missing is the content: four Mythic treasures with bonuses above
|
||||||
|
// the T5 line, InventoryDesc + RoomAnnounce strings for each (RoomAnnounce
|
||||||
|
// must use {location_mid}, never a literal zone name), and a TIER 6 register
|
||||||
|
// in TreasureDiscovery. Write them against internal/flavor/VOICE_CANON.md;
|
||||||
|
// the T5 pool below is the tonal floor to clear, not the ceiling.
|
||||||
5: {
|
5: {
|
||||||
{
|
{
|
||||||
Key: "shard_of_unnamed", Name: "Shard of the Unnamed", Tier: 5,
|
Key: "shard_of_unnamed", Name: "Shard of the Unnamed", Tier: 5,
|
||||||
@@ -285,7 +302,12 @@ func rollAdvTreasureDropDetailed(tier int, userID id.UserID, chatLevel int, weig
|
|||||||
|
|
||||||
pool, ok := advAllTreasures[tier]
|
pool, ok := advAllTreasures[tier]
|
||||||
if !ok || len(pool) == 0 {
|
if !ok || len(pool) == 0 {
|
||||||
return nil, roll, rate
|
// A tier that has a rate but no pool (tier 6, until the TODO above is
|
||||||
|
// filled) cannot drop anything. Report a zero rate rather than the
|
||||||
|
// configured one: the caller turns a close roll into a "just missed"
|
||||||
|
// DM, and telling a postgame player they nearly won a treasure that
|
||||||
|
// cannot be won is worse than staying quiet.
|
||||||
|
return nil, 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick random treasure
|
// Pick random treasure
|
||||||
|
|||||||
@@ -66,6 +66,36 @@ func TestAdvTreasureDropDetailed_ForcedRollGrantsTreasure(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestAdvTreasureTier6_PoolStillMissing pins the known tier 6 gap: Mythic zones
|
||||||
|
// carry a drop rate but no treasure pool, so a forced roll yields nothing and
|
||||||
|
// the player is told nothing either (a "just missed" DM for an unwinnable
|
||||||
|
// treasure would be a lie).
|
||||||
|
//
|
||||||
|
// This test is the reminder. Writing advAllTreasures[6] — see TODO(t6-treasures)
|
||||||
|
// in adventure_treasure.go — turns it red, and the fix is to delete it and
|
||||||
|
// assert the tier 6 drop instead, the way ForcedRollGrantsTreasure does for
|
||||||
|
// tier 1.
|
||||||
|
func TestAdvTreasureTier6_PoolStillMissing(t *testing.T) {
|
||||||
|
if err := db.Init(t.TempDir()); err != nil {
|
||||||
|
t.Fatalf("db.Init: %v", err)
|
||||||
|
}
|
||||||
|
if _, ok := advAllTreasures[6]; ok {
|
||||||
|
t.Fatal("a tier 6 treasure pool now exists — drop this test and assert the drop instead")
|
||||||
|
}
|
||||||
|
// The rate is configured and waiting, so the gap is the pool alone.
|
||||||
|
if advTreasureDropRates[6] == 0 {
|
||||||
|
t.Error("tier 6 drop rate went missing; a Mythic pool would be unreachable")
|
||||||
|
}
|
||||||
|
drop, roll, rate := rollAdvTreasureDropDetailed(6, "@mythic:example.org", 0, 1000)
|
||||||
|
if drop != nil {
|
||||||
|
t.Fatalf("tier 6 produced a drop from an empty pool: %+v", drop.Def)
|
||||||
|
}
|
||||||
|
// Zeroed, not merely no-drop: this is what keeps the near-miss DM quiet.
|
||||||
|
if roll != 0 || rate != 0 {
|
||||||
|
t.Errorf("empty pool reported roll=%v rate=%v, want 0/0 so no near-miss fires", roll, rate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The treasure and masterwork systems predate zones and speak AdvLocation.
|
// The treasure and masterwork systems predate zones and speak AdvLocation.
|
||||||
func TestAdvLocForZone(t *testing.T) {
|
func TestAdvLocForZone(t *testing.T) {
|
||||||
loc := advLocForZone(ZoneGoblinWarrens)
|
loc := advLocForZone(ZoneGoblinWarrens)
|
||||||
|
|||||||
Reference in New Issue
Block a user