mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
R3 — Combat Event Integration: - dnd_expedition_combat.go: Combat Interrupt rolls (§4.2) with threat-clock and Ranger-wilderness modifiers; Patrol Encounters scaled by threat level; recordZoneKill writer with monsterKillTags. - Interrupt gate at head of handleHarvestCmd; patrol gate before resolveRoom in zoneCmdAdvance; kill writer wired into combat-win paths. R4a — Zone Loot Tables: - dnd_zone_loot.go: §5 loot drop tables for all 10 zones × 5 tiers with §8.1 sell-value bands. dropTierFromCR brackets + boss floor. - Hooks on combat-win in resolveCombatRoom, resolveBossRoom, runHarvestInterrupt, tryPatrolEncounter. R4b — Fishing Integration: - dnd_zone_fish.go: fishingZones allow-list, fishingSkillBonus, rangerRareCatchUpgrade (§6.2), feywildFishDistortion narration. - §6.1 fish entries added to resource registry for Forest, Sunken Temple, Underdark, Feywild zones. - !fish wired through handleHarvestCmd; zoneItemFlavor matrix populated for all 10 zones × all loot items. R5 — Economy Integration: - dnd_economy.go: !sell (post-expedition gate, single CHA Persuasion DC 17 → +15% bump), !craft (§8.2 4 exemplar recipes), !lore (INT/Arcana DC 15 recipe discovery). - dnd_known_recipe table for persistent recipe discovery. Flavor reuse: HarvestInterrupt, PatrolEncounter, CombatVictory, PlayerDeath, LootDrop*, FeywildTimeDistortion* — all existing pools. No new flavor file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
package plugin
|
||
|
||
import (
|
||
"math/rand/v2"
|
||
|
||
"gogobee/internal/flavor"
|
||
)
|
||
|
||
// Resource & Combat Integration §6 — Fishing System Integration.
|
||
//
|
||
// Fishing reuses the harvest pipeline (HarvestFish action). This file
|
||
// adds the §6 zone gate, the existing FishingSkill rank bonus, the
|
||
// Ranger +20% rare-catch rule, and the Feywild Time Distortion hook.
|
||
|
||
// fishingZones is the §6.1 allow-list — only these zones expose !fish.
|
||
var fishingZones = map[ZoneID]bool{
|
||
ZoneForestShadows: true,
|
||
ZoneSunkenTemple: true,
|
||
ZoneUnderdark: true,
|
||
ZoneFeywildCrossing: true,
|
||
}
|
||
|
||
// isFishingZone returns true if !fish is permitted in zoneID.
|
||
func isFishingZone(zoneID ZoneID) bool { return fishingZones[zoneID] }
|
||
|
||
// fishingSkillBonus folds the legacy FishingSkill (0–10) into a small
|
||
// roll bonus so existing rank progression still pays off inside the
|
||
// expedition pipeline. +1 per 5 levels, capped at +2.
|
||
func fishingSkillBonus(fishingSkill int) int {
|
||
if fishingSkill <= 0 {
|
||
return 0
|
||
}
|
||
bonus := fishingSkill / 5
|
||
if bonus > 2 {
|
||
bonus = 2
|
||
}
|
||
return bonus
|
||
}
|
||
|
||
// rangerRareCatchUpgrade implements §6.2 — Ranger +20% rare catch rate.
|
||
// When the harvest outcome is Common or Standard for a fishing attempt
|
||
// by a Ranger, 20% chance to upgrade to Rich. Returns the (possibly
|
||
// upgraded) outcome.
|
||
func rangerRareCatchUpgrade(class DnDClass, action HarvestAction, outcome HarvestOutcome, rng *rand.Rand) HarvestOutcome {
|
||
if class != ClassRanger || action != HarvestFish {
|
||
return outcome
|
||
}
|
||
if outcome != OutcomeCommon && outcome != OutcomeStandard {
|
||
return outcome
|
||
}
|
||
if rngFloat(rng) < 0.20 {
|
||
return OutcomeRich
|
||
}
|
||
return outcome
|
||
}
|
||
|
||
// feywildFishDistortion narrates a Time Distortion flicker on a fishing
|
||
// attempt in Feywild Crossing. 15% chance per attempt; pure flavor for
|
||
// R4b (mechanical Time Loop event lives in the temporal-events system
|
||
// and is not duplicated here).
|
||
func feywildFishDistortion(zoneID ZoneID, action HarvestAction, rng *rand.Rand) string {
|
||
if zoneID != ZoneFeywildCrossing || action != HarvestFish {
|
||
return ""
|
||
}
|
||
if rngFloat(rng) >= 0.15 {
|
||
return ""
|
||
}
|
||
line := flavor.Pick(flavor.FeywildTimeDistortionHalf)
|
||
if line == "" {
|
||
line = flavor.Pick(flavor.FeywildTimeLoop)
|
||
}
|
||
if line == "" {
|
||
return ""
|
||
}
|
||
return "_⏳ " + line + "_\n\n"
|
||
}
|