mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 17:02:42 +00:00
adventure: Tier 6 postgame "Mythic" dungeons (P1–P7 calibration)
Five post-game dungeons above the T5 ceiling, gated on both T5 bosses beaten + level 18. Opt-in endgame: deadly solo, clearable by a party with Pete + pets. - P1 gating: postgameUnlocked (T5 clears + level floor), zonesForLevel excludes T6 unconditionally; wired into startZoneRun, !zone/!expedition, party accept, boredom picker, and the list dividers. - P2 bestiary: 15 elites + 5 signature bosses (Layer-1 stat blocks). - P3 zone defs + 4-region registries; ZoneLootEntry.BossOnly. - P4 five zone graphs on a shared builder (44–52 rooms, no soft-lock; Ossuary secret Verse nodes). - P5 loot: BossOnly enforced; signature items are real registry magic items; five Thom pity recipes off the per-zone crafting anchors. - P6 narration/flavor (5 files), T6 achievements, Pete stays zone-parametric. - P7 (in progress): sim can now reach gated T6 (SimRunner.SeedPostgameUnlock + IsPostgameZone). First calibration pass on millenia — hardened ossuary + drowned_star, softened first_hoard + unplace; last_meridian in band. Fix: party members were refused from every T6 zone because expeditionCmdAccept ran the level gate (which excludes T6) before the postgame check — the intended party endgame was unreachable. Route T6 through postgameUnlocked. Regression tests added.
This commit is contained in:
@@ -357,7 +357,7 @@ func (p *AdventurePlugin) resolveTrapRoomLegacy(userID id.UserID, run *DungeonRu
|
||||
// to a single "coins" item with rolled value; everything else becomes a
|
||||
// treasure-tier inventory item with a tier-derived placeholder value
|
||||
// (zone equipment registry wiring is a later content phase).
|
||||
func (p *AdventurePlugin) rollZoneLoot(userID id.UserID, run *DungeonRun, zone ZoneDefinition) []string {
|
||||
func (p *AdventurePlugin) rollZoneLoot(userID id.UserID, run *DungeonRun, zone ZoneDefinition, bossCleared bool) []string {
|
||||
rng := rand.New(rand.NewPCG(uint64(zoneSelectorHash(run.RunID, run.CurrentRoom)), 0x100712))
|
||||
// DM mood tilts probabilistic drop chances. UniqueAlways entries are
|
||||
// untouched — those are story drops, not flavor for the DM to gate.
|
||||
@@ -367,6 +367,13 @@ func (p *AdventurePlugin) rollZoneLoot(userID id.UserID, run *DungeonRun, zone Z
|
||||
}
|
||||
var granted []string
|
||||
for _, entry := range zone.Loot {
|
||||
// BossOnly (signature) drops only roll on the true zone-boss / whole-zone
|
||||
// clear. rollZoneLoot fires on every region completion of a multi-region
|
||||
// zone; without this gate a T6 signature item would get four roll chances
|
||||
// per run instead of one at the boss.
|
||||
if entry.BossOnly && !bossCleared {
|
||||
continue
|
||||
}
|
||||
if !entry.UniqueAlways {
|
||||
chance := entry.DropChance * moodMult
|
||||
if rng.Float64() > chance {
|
||||
@@ -404,6 +411,15 @@ func zoneLootToInventory(entry ZoneLootEntry, zone ZoneDefinition, rng *rand.Ran
|
||||
Value: int64(val),
|
||||
}, true
|
||||
}
|
||||
// Registry-backed loot (T6 signature items and any future magic-item drops)
|
||||
// materializes as a real equippable magic_item — the SkillSource tag is what
|
||||
// the equip path and magicItemEffectFor key off. Plain named entries (legacy
|
||||
// zone signature items not in the registry) fall through to treasure below.
|
||||
if mi, ok := magicItemRegistry[entry.ItemID]; ok {
|
||||
item := magicItemSell(mi)
|
||||
item.SkillSource = "magic_item:" + mi.ID
|
||||
return item, true
|
||||
}
|
||||
tier := int(zone.Tier)
|
||||
displayName := titleCaseUnderscored(entry.ItemID)
|
||||
value := int64(50 * tier * tier) // T1=50, T2=200, T3=450, T4=800, T5=1250
|
||||
|
||||
Reference in New Issue
Block a user