From a226d72e51eecb768b13600303f73483118d9104 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 10 Jun 2026 01:48:28 -0400 Subject: feat: implemented janky object interaction model --- internal/action/store.go | 174 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 internal/action/store.go (limited to 'internal/action/store.go') diff --git a/internal/action/store.go b/internal/action/store.go new file mode 100644 index 0000000..fd58281 --- /dev/null +++ b/internal/action/store.go @@ -0,0 +1,174 @@ +package action + +import ( + "fmt" + "math/rand" + "os" + "path/filepath" + "sync" + + "gopkg.in/yaml.v3" +) + +type Store struct { + dataDir string + mu sync.Mutex + cache map[string]*RawBehavior +} + +type RawBehavior struct { + ID string + Type string + Raw map[string]any +} + +func NewStore(dataDir string) *Store { + return &Store{ + dataDir: dataDir, + cache: make(map[string]*RawBehavior), + } +} + +func (s *Store) Load(id string) (*RawBehavior, error) { + s.mu.Lock() + if b, ok := s.cache[id]; ok { + s.mu.Unlock() + return b, nil + } + s.mu.Unlock() + + path := filepath.Join(s.dataDir, "behaviors", id+".yaml") + data, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("read behavior %s: %w", id, err) + } + + var raw map[string]any + if err := yaml.Unmarshal(data, &raw); err != nil { + return nil, fmt.Errorf("parse behavior %s: %w", id, err) + } + + rb := &RawBehavior{ID: id, Raw: raw} + if t, ok := raw["type"].(string); ok { + rb.Type = t + } + if rid, ok := raw["id"].(string); ok { + rb.ID = rid + } + + s.mu.Lock() + s.cache[id] = rb + s.mu.Unlock() + return rb, nil +} + +func unmarshalRaw[T any](rb *RawBehavior, expectedType string) (*T, error) { + if rb.Type != expectedType { + return nil, fmt.Errorf("behavior %s is type %s, expected %s", rb.ID, rb.Type, expectedType) + } + var cfg T + raw, _ := yaml.Marshal(rb.Raw) + if err := yaml.Unmarshal(raw, &cfg); err != nil { + return nil, fmt.Errorf("parse %s config %s: %w", expectedType, rb.ID, err) + } + return &cfg, nil +} + +func (s *Store) LoadGather(id string) (*GatherConfig, error) { + rb, err := s.Load(id) + if err != nil { + return nil, err + } + return unmarshalRaw[GatherConfig](rb, "gather") +} + +func (s *Store) LoadTalk(id string) (*TalkConfig, error) { + rb, err := s.Load(id) + if err != nil { + return nil, err + } + return unmarshalRaw[TalkConfig](rb, "talk") +} + +func (s *Store) LoadUse(id string) (*UseConfig, error) { + rb, err := s.Load(id) + if err != nil { + return nil, err + } + return unmarshalRaw[UseConfig](rb, "use") +} + +func (s *Store) LoadToggle(id string) (*ToggleConfig, error) { + rb, err := s.Load(id) + if err != nil { + return nil, err + } + return unmarshalRaw[ToggleConfig](rb, "toggle") +} + +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 +} + +func (s *Store) LoadDropTable(id string) (*DropTableDef, error) { + path := filepath.Join(s.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 (s *Store) ResolveDrop(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 := s.LoadDropTable(drops[i].Table) + if err == nil { + if resolved := s.ResolveDrop(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] +} -- cgit v1.2.3