mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
N1/A1-A3: rewire the drop systems Phase R orphaned
Treasure, masterwork, and consumable drops each had zero call sites: they only ever fired from the legacy daily activity loop, which adventure.go now intercepts with a deprecation DM. Hook all three to the zone-combat seam. A1 - treasure: rollAdvTreasureDropDetailed takes a weight, applied to the base rate. Boss x4, elite x2, standard x1, plus one x1 roll on zone clear. Near-miss DMs now fire only for weighted moments; at x1 on autopilot they'd land on ~3% of every kill. A2 - masterwork: the catalog is keyed to mining/fishing/foraging, so the dungeon lookup returned nil and the hook would have been a silent no-op. masterworkDefForZone rolls across all three slot lines at the zone's tier. Flavor now follows loc.Activity rather than the item's catalog line, with a new dungeon pool - a crypt boss must not narrate a pickaxe striking ore. A3 - consumables + ingredients: the audit found more than the four named ingredients were stranded. generateAdvLoot is reachable only from resolveDungeonAction, which has no callers, so all four legacy loot tables were dead and every one of the 12 recipes was uncraftable. rollZoneIngredient draws from those tables directly at the zone's tier, reviving them wholesale rather than re-keying 24 ingredients into the per-zone slates.
This commit is contained in:
68
internal/plugin/adventure_masterwork_test.go
Normal file
68
internal/plugin/adventure_masterwork_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// N1/A2 — the masterwork catalog is keyed to gathering activities, so the
|
||||
// zone-combat seam had nothing to look up. masterworkDefForZone bridges it.
|
||||
|
||||
func TestMasterworkDefForZone_CoversEveryTier(t *testing.T) {
|
||||
for tier := 1; tier <= 5; tier++ {
|
||||
if def := masterworkDefForZone(tier); def == nil {
|
||||
t.Errorf("tier %d has no masterwork def", tier)
|
||||
} else if def.Tier != tier {
|
||||
t.Errorf("tier %d returned a tier-%d def", tier, def.Tier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A dungeon drop must be able to land in any of the three slots — otherwise
|
||||
// zone play would only ever upgrade one piece of gear.
|
||||
func TestMasterworkDefForZone_RollsAllSlots(t *testing.T) {
|
||||
seen := map[EquipmentSlot]bool{}
|
||||
for i := 0; i < 300; i++ {
|
||||
if def := masterworkDefForZone(3); def != nil {
|
||||
seen[def.Slot] = true
|
||||
}
|
||||
}
|
||||
for _, slot := range []EquipmentSlot{SlotWeapon, SlotArmor, SlotBoots} {
|
||||
if !seen[slot] {
|
||||
t.Errorf("slot %v never rolled in 300 draws", slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The pre-existing lookup must keep working for the gathering activities.
|
||||
func TestMasterworkDefFor_GatheringUnchanged(t *testing.T) {
|
||||
for _, act := range masterworkSlotActivities {
|
||||
for tier := 1; tier <= 5; tier++ {
|
||||
def := masterworkDefFor(act, tier)
|
||||
if def == nil {
|
||||
t.Fatalf("%s tier %d lost its def", act, tier)
|
||||
}
|
||||
if def.Activity != act {
|
||||
t.Errorf("%s tier %d returned activity %s", act, tier, def.Activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flavor follows the place, not the catalog line. A crypt boss must not
|
||||
// narrate a pickaxe striking ore.
|
||||
func TestMasterworkDropFlavorText_DungeonHasItsOwnVoice(t *testing.T) {
|
||||
gatheringWords := []string{"pickaxe", "fishing", "foraging", "vein", "ore", "branch"}
|
||||
for tier := 1; tier <= 5; tier++ {
|
||||
text := masterworkDropFlavorText(AdvActivityDungeon, tier)
|
||||
if text == "" {
|
||||
t.Fatalf("dungeon tier %d has no flavor", tier)
|
||||
}
|
||||
lower := strings.ToLower(text)
|
||||
for _, w := range gatheringWords {
|
||||
if strings.Contains(lower, w) {
|
||||
t.Errorf("dungeon tier %d flavor leaks gathering word %q", tier, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user