From abd612c15799f604e671e83dc7c410ed2b44185f Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Thu, 25 Jun 2026 15:40:48 -0400 Subject: slop refactor --- internal/object/doc.go | 5 + internal/object/item.go | 211 ------------------------------------------ internal/object/item_store.go | 78 ---------------- internal/object/object.go | 68 ++++++-------- internal/object/store.go | 4 +- 5 files changed, 37 insertions(+), 329 deletions(-) create mode 100644 internal/object/doc.go delete mode 100644 internal/object/item.go delete mode 100644 internal/object/item_store.go (limited to 'internal/object') diff --git a/internal/object/doc.go b/internal/object/doc.go new file mode 100644 index 0000000..04aa4f7 --- /dev/null +++ b/internal/object/doc.go @@ -0,0 +1,5 @@ +// Package object defines room-object definitions (ObjectDef), safespot +// configuration, use interactions, and the ObjectStore YAML loader. Objects +// are placed in rooms via room YAML and may provide gather/talk/use/safespot +// behaviors. Distinct from the item package (item definitions). +package object diff --git a/internal/object/item.go b/internal/object/item.go deleted file mode 100644 index b90432d..0000000 --- a/internal/object/item.go +++ /dev/null @@ -1,211 +0,0 @@ -package object - -import ( - "fmt" - "strings" - - "gopkg.in/yaml.v3" -) - -func WordPrefixMatch(input, name string) bool { - inputWords := strings.Fields(strings.ToLower(input)) - if len(inputWords) == 0 { - return false - } - nameWords := strings.Fields(strings.ToLower(name)) - for _, iw := range inputWords { - found := false - for _, nw := range nameWords { - if strings.HasPrefix(nw, iw) || strings.HasPrefix(iw, nw) { - found = true - break - } - } - if !found { - return false - } - } - return true -} - -type EquipSlot string - -const ( - SlotHead EquipSlot = "head" - SlotNeck EquipSlot = "neck" - SlotTorso EquipSlot = "torso" - SlotLegs EquipSlot = "legs" - SlotHands EquipSlot = "hands" - SlotFeet EquipSlot = "feet" - SlotBack EquipSlot = "back" - SlotAmmo EquipSlot = "ammo" - SlotMainHand EquipSlot = "main_hand" - SlotOffHand EquipSlot = "off_hand" - SlotRing EquipSlot = "ring" -) - -type WeaponType string - -const ( - WeaponMelee WeaponType = "melee" - WeaponRanged WeaponType = "ranged" - WeaponScience WeaponType = "science" -) - -type ItemDef struct { - ID string `yaml:"id"` - Name string `yaml:"name"` - Color string `yaml:"color"` - Description string `yaml:"description"` - Value int `yaml:"value"` - Stackable bool `yaml:"stackable"` - EquipSlot EquipSlot `yaml:"equip_slot"` - WeaponType WeaponType `yaml:"weapon_type"` - AttackType string `yaml:"attack_type"` - Stats ItemStats `yaml:"stats"` - Speed float64 `yaml:"speed"` - Requirements map[string]int `yaml:"requirements,omitempty"` - ToolType string `yaml:"tool_type"` - ToolSpeed float64 `yaml:"tool_speed"` - BurnTicks float64 `yaml:"burn_ticks"` - FireLevel int `yaml:"fire_level"` - FireXP int `yaml:"fire_xp"` - Quality int `yaml:"quality"` - MaxQuality int `yaml:"max_quality"` - SearchTable string `yaml:"search_table"` - SearchMiscTable string `yaml:"search_misc_table"` - SearchTicks float64 `yaml:"search_ticks"` - SearchMessage string `yaml:"search_message"` - HealValue int `yaml:"heal_value"` - EatMessage string `yaml:"eat_message"` - Craft CraftList `yaml:"craft,omitempty"` - ProvidesJunk string `yaml:"provides_junk,omitempty"` - FarmPatchType string `yaml:"farm_patch_type"` - FarmLevel int `yaml:"farm_level"` - FarmPlantXP int `yaml:"farm_plant_xp"` - FarmHarvestXP int `yaml:"farm_harvest_xp"` - FarmStages int `yaml:"farm_stages"` - FarmProduct string `yaml:"farm_product"` - FarmMinYield int `yaml:"farm_min_yield"` - FarmMaxYield int `yaml:"farm_max_yield"` - PotionEffect string `yaml:"potion_effect"` - PotionBonus int `yaml:"potion_bonus"` - PotionDuration float64 `yaml:"potion_duration"` - Recoverable bool `yaml:"recoverable"` -} - -type CraftList []CraftDef - -func (cl *CraftList) UnmarshalYAML(value *yaml.Node) error { - switch value.Kind { - case yaml.SequenceNode: - return value.Decode((*[]CraftDef)(cl)) - case yaml.MappingNode: - var single CraftDef - if err := value.Decode(&single); err != nil { - return err - } - *cl = []CraftDef{single} - return nil - } - return fmt.Errorf("craft: expected mapping or sequence") -} - -func (d *ItemDef) FirstCraft() *CraftDef { - if len(d.Craft) == 0 { - return nil - } - return &d.Craft[0] -} - -func (d *ItemDef) FindCraft(fn func(CraftDef) bool) *CraftDef { - for i := range d.Craft { - if fn(d.Craft[i]) { - return &d.Craft[i] - } - } - return nil -} - -func (d *ItemDef) MatchingCrafts(fn func(CraftDef) bool) []*CraftDef { - var result []*CraftDef - for i := range d.Craft { - if fn(d.Craft[i]) { - result = append(result, &d.Craft[i]) - } - } - return result -} - -type ConsumeEntry struct { - Items []string `yaml:"items"` - Quantity int `yaml:"quantity"` - Byproducts []string `yaml:"byproducts"` -} - -type CraftStep struct { - Tick float64 `yaml:"tick"` - Message string `yaml:"message"` -} - -type SuccessFormula struct { - Base float64 `yaml:"base"` - PerLevel float64 `yaml:"per_level"` - Cap float64 `yaml:"cap"` -} - -type CraftDef struct { - Type string `yaml:"type"` - Skill string `yaml:"skill"` - Level int `yaml:"level"` - XP int `yaml:"xp"` - Wait float64 `yaml:"wait"` - Station []string `yaml:"station"` - Tool string `yaml:"tool"` - Consume []ConsumeEntry `yaml:"consume"` - OutputQty int `yaml:"output_qty"` - Fail string `yaml:"fail"` - Message string `yaml:"message"` - FailMessage string `yaml:"fail_message"` - StartMessage string `yaml:"start_message"` - EndMessage string `yaml:"end_message"` - Steps []CraftStep `yaml:"steps"` - Success *SuccessFormula `yaml:"success"` -} - -func (c *CraftDef) EffectiveSkill() string { - if c.Skill != "" { - return c.Skill - } - return c.Type -} - -type ItemStats struct { - StabAttack int `yaml:"stab_attack"` - SlashAttack int `yaml:"slash_attack"` - CrushAttack int `yaml:"crush_attack"` - ScienceAttack int `yaml:"science_attack"` - RangedAttack int `yaml:"ranged_attack"` - - StabDefense int `yaml:"stab_defense"` - SlashDefense int `yaml:"slash_defense"` - CrushDefense int `yaml:"crush_defense"` - ScienceDefense int `yaml:"science_defense"` - RangedDefense int `yaml:"ranged_defense"` - - StrengthBonus int `yaml:"strength_bonus"` - RangedStrength int `yaml:"ranged_strength"` - ScienceDamage int `yaml:"science_damage"` - TechnologyBonus int `yaml:"technology_bonus"` -} - -func (d *ItemDef) MatchesName(input string) bool { - lower := strings.ToLower(strings.TrimSpace(input)) - if lower == "" { - return false - } - if strings.ToLower(d.Name) == lower { - return true - } - return WordPrefixMatch(lower, d.Name) -} diff --git a/internal/object/item_store.go b/internal/object/item_store.go deleted file mode 100644 index e930220..0000000 --- a/internal/object/item_store.go +++ /dev/null @@ -1,78 +0,0 @@ -package object - -import ( - "fmt" - "os" - "path/filepath" - - "thehouseoficarus/internal/action" - "gopkg.in/yaml.v3" -) - -type ItemStore struct { - dataDir string - pathIndex map[string]string - cache map[string]*ItemDef -} - -func NewItemStore(dataDir string) *ItemStore { - s := &ItemStore{ - dataDir: dataDir, - pathIndex: action.BuildPathIndex(filepath.Join(dataDir, "items")), - cache: make(map[string]*ItemDef), - } - return s -} - -func (s *ItemStore) Load(id string) (*ItemDef, error) { - if def, ok := s.cache[id]; ok { - return def, nil - } - path, ok := s.pathIndex[id] - if !ok { - return nil, fmt.Errorf("read item %s: no such item", id) - } - data, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("read item %s: %w", id, err) - } - var def ItemDef - if err := yaml.Unmarshal(data, &def); err != nil { - return nil, fmt.Errorf("parse item %s: %w", id, err) - } - def.ID = id - s.cache[id] = &def - return &def, nil -} - -func (s *ItemStore) LoadAll() ([]*ItemDef, error) { - dir := filepath.Join(s.dataDir, "items") - var defs []*ItemDef - err := action.WalkYAMLDir(dir, func(path, id string, data []byte) error { - if def, ok := s.cache[id]; ok { - defs = append(defs, def) - return nil - } - var def ItemDef - if err := yaml.Unmarshal(data, &def); err != nil { - return fmt.Errorf("parse item %s: %w", id, err) - } - def.ID = id - s.cache[id] = &def - defs = append(defs, &def) - return nil - }) - return defs, err -} - -func (s *ItemStore) PathIndex() map[string]string { - return s.pathIndex -} - -func (s *ItemStore) IDSet() map[string]bool { - ids := make(map[string]bool) - for id := range s.pathIndex { - ids[id] = true - } - return ids -} diff --git a/internal/object/object.go b/internal/object/object.go index f7a0e7b..8d1e02e 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -1,44 +1,34 @@ package object -import "thehouseoficarus/internal/action" +import "thehouseoficarus/internal/behavior" type UseInteraction struct { - Item string `yaml:"item_id"` - Condition *action.Condition `yaml:"condition"` - Message string `yaml:"message"` - Action *action.NodeAction `yaml:"action"` + Item string `yaml:"item_id"` + Condition *behavior.Condition `yaml:"condition"` + Message string `yaml:"message"` + Action *behavior.NodeAction `yaml:"action"` } type ObjectDef struct { - ID string `yaml:"id"` - Name string `yaml:"name"` - Aliases []string `yaml:"aliases"` - Color string `yaml:"color"` - Hidden bool `yaml:"hidden"` - InRoomDescription string `yaml:"inroom_description"` - RemovalItem string `yaml:"removal_item"` - Description string `yaml:"description"` - Descriptions []ConditionalDesc `yaml:"descriptions,omitempty"` - UseInteractions []UseInteraction `yaml:"use_interactions"` - StealTable string `yaml:"steal_table"` - StealLevel int `yaml:"steal_level"` - StealXP int `yaml:"steal_xp"` - StealSpeed float64 `yaml:"steal_speed"` - GuardMob string `yaml:"guard_mob"` + ID string `yaml:"id"` + Name string `yaml:"name"` + Aliases []string `yaml:"aliases"` + Color string `yaml:"color"` + Hidden bool `yaml:"hidden"` + InRoomDescription string `yaml:"inroom_description"` + RemovalItem string `yaml:"removal_item"` + Description behavior.DescList `yaml:"description"` + UseInteractions []UseInteraction `yaml:"use_interactions"` + StealTable string `yaml:"steal_table"` + StealLevel int `yaml:"steal_level"` + StealXP int `yaml:"steal_xp"` + StealSpeed float64 `yaml:"steal_speed"` + GuardMob string `yaml:"guard_mob"` - Gather *action.GatherConfig `yaml:"gather,omitempty"` - Talk *action.TalkConfig `yaml:"talk,omitempty"` - Use *action.UseConfig `yaml:"use,omitempty"` - Safespot *SafespotConfig `yaml:"safespot,omitempty"` -} - -// ConditionalDesc is a description variant gated by a condition. They are -// evaluated in order per-looker; the first whose condition passes (or has no -// condition) wins. If a def has Descriptions but none match for a given player, -// the object is treated as absent for that player. -type ConditionalDesc struct { - Text string `yaml:"text"` - Condition *action.Condition `yaml:"condition"` + Gather *behavior.GatherConfig `yaml:"gather,omitempty"` + Talk *behavior.TalkConfig `yaml:"talk,omitempty"` + Use *behavior.UseConfig `yaml:"use,omitempty"` + Safespot *SafespotConfig `yaml:"safespot,omitempty"` } type SafespotConfig struct { @@ -58,11 +48,13 @@ type SafespotLevel struct { DegradeMessage string `yaml:"degrade_message"` } -func (d *ObjectDef) IsGatherable() bool { return d.Gather != nil } -func (d *ObjectDef) IsTalkable() bool { return d.Talk != nil } -func (d *ObjectDef) IsUsable() bool { return d.Use != nil } -func (d *ObjectDef) IsSafespot() bool { return d.Safespot != nil } -func (d *ObjectDef) IsInteractable() bool { return d.Gather != nil || d.Talk != nil || d.Use != nil || d.Safespot != nil } +func (d *ObjectDef) IsGatherable() bool { return d.Gather != nil } +func (d *ObjectDef) IsTalkable() bool { return d.Talk != nil } +func (d *ObjectDef) IsUsable() bool { return d.Use != nil } +func (d *ObjectDef) IsSafespot() bool { return d.Safespot != nil } +func (d *ObjectDef) IsInteractable() bool { + return d.Gather != nil || d.Talk != nil || d.Use != nil || d.Safespot != nil +} func (d *ObjectDef) BehaviorType() string { switch { diff --git a/internal/object/store.go b/internal/object/store.go index cf8b4f9..a441705 100644 --- a/internal/object/store.go +++ b/internal/object/store.go @@ -5,8 +5,8 @@ import ( "os" "path/filepath" - "thehouseoficarus/internal/action" "gopkg.in/yaml.v3" + "thehouseoficarus/internal/behavior" ) type ObjectStore struct { @@ -18,7 +18,7 @@ type ObjectStore struct { func NewObjectStore(dataDir string) *ObjectStore { return &ObjectStore{ dataDir: dataDir, - pathIndex: action.BuildPathIndex(filepath.Join(dataDir, "objects")), + pathIndex: behavior.BuildPathIndex(filepath.Join(dataDir, "objects")), cache: make(map[string]*ObjectDef), } } -- cgit v1.2.3