aboutsummaryrefslogtreecommitdiff
path: root/internal/behavior/store.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-25 15:40:48 -0400
committerhistoria <[not public]>2026-06-25 15:40:48 -0400
commitabd612c15799f604e671e83dc7c410ed2b44185f (patch)
tree0597ca92350de73aac2a7cf26b2f2d6595dac0cc /internal/behavior/store.go
parent2725e2927a1595c7b100d942d1f14146252adeb7 (diff)
downloadthehouseoficarus-abd612c15799f604e671e83dc7c410ed2b44185f.tar.gz
slop refactor
Diffstat (limited to 'internal/behavior/store.go')
-rw-r--r--internal/behavior/store.go164
1 files changed, 164 insertions, 0 deletions
diff --git a/internal/behavior/store.go b/internal/behavior/store.go
new file mode 100644
index 0000000..7695b8d
--- /dev/null
+++ b/internal/behavior/store.go
@@ -0,0 +1,164 @@
+package behavior
+
+import (
+ "fmt"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+
+ "gopkg.in/yaml.v3"
+)
+
+func BuildPathIndex(dir string) map[string]string {
+ index := make(map[string]string)
+ filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") {
+ return nil
+ }
+ id := strings.TrimSuffix(d.Name(), ".yaml")
+ index[id] = path
+ return nil
+ })
+ return index
+}
+
+func BuildRoomIndex(dir string) map[int]string {
+ index := make(map[int]string)
+ filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") {
+ return nil
+ }
+ id := strings.TrimSuffix(d.Name(), ".yaml")
+ var n int
+ if _, scanErr := fmt.Sscanf(id, "%d", &n); scanErr == nil {
+ index[n] = path
+ }
+ return nil
+ })
+ return index
+}
+
+func WalkYAMLDir(dir string, fn func(path, id string, data []byte) error) error {
+ return filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") {
+ return nil
+ }
+ data, readErr := os.ReadFile(path)
+ if readErr != nil {
+ return nil
+ }
+ id := strings.TrimSuffix(d.Name(), ".yaml")
+ return fn(path, id, data)
+ })
+}
+
+type Duplicate struct {
+ ID string
+ Paths []string
+}
+
+func CheckDuplicateIDs(dir string) []Duplicate {
+ seen := make(map[string][]string)
+ filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") {
+ return nil
+ }
+ id := strings.TrimSuffix(d.Name(), ".yaml")
+ seen[id] = append(seen[id], path)
+ return nil
+ })
+ var dups []Duplicate
+ for id, paths := range seen {
+ if len(paths) > 1 {
+ dups = append(dups, Duplicate{ID: id, Paths: paths})
+ }
+ }
+ return dups
+}
+
+func SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64 {
+ chance := cfg.Base + float64(level-requiredLevel)*cfg.PerLevel
+ if chance > cfg.Cap {
+ chance = cfg.Cap
+ }
+ if chance < 0 {
+ chance = 0
+ }
+ return chance
+}
+
+var (
+ dropIndex map[string]string
+ dropIndexMu sync.Mutex
+)
+
+func loadDropIndex(dataDir string) map[string]string {
+ dropIndexMu.Lock()
+ defer dropIndexMu.Unlock()
+ if dropIndex == nil {
+ dropIndex = BuildPathIndex(filepath.Join(dataDir, "drops"))
+ }
+ return dropIndex
+}
+
+func LoadDropTable(dataDir, id string) (*DropTableDef, error) {
+ index := loadDropIndex(dataDir)
+ path, ok := index[id]
+ if !ok {
+ path = filepath.Join(dataDir, "drops", id+".yaml")
+ }
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("read drop table %s: %w", id, err)
+ }
+ var dt DropTableDef
+ if err := yaml.Unmarshal(data, &dt); err != nil {
+ return nil, fmt.Errorf("parse drop table %s: %w", id, err)
+ }
+ return &dt, nil
+}
+
+func ResolveDrop(dataDir string, drops []DropEntry) *DropEntry {
+ if len(drops) == 0 {
+ return nil
+ }
+ total := 0
+ for _, d := range drops {
+ total += d.Weight
+ }
+ if total <= 0 {
+ return nil
+ }
+ roll := rand.Intn(total)
+ cumulative := 0
+ for i := range drops {
+ cumulative += drops[i].Weight
+ if roll < cumulative {
+ if drops[i].Table != "" {
+ sub, err := LoadDropTable(dataDir, drops[i].Table)
+ if err == nil {
+ if resolved := ResolveDrop(dataDir, sub.Drops); resolved != nil {
+ qty := drops[i].Quantity
+ if qty <= 0 {
+ qty = resolved.Quantity
+ }
+ if qty <= 0 {
+ qty = 1
+ }
+ return &DropEntry{
+ ItemID: resolved.ItemID,
+ Quantity: qty,
+ Depletes: drops[i].Depletes,
+ Message: drops[i].Message,
+ }
+ }
+ }
+ return nil
+ }
+ return &drops[i]
+ }
+ }
+ return &drops[0]
+}