aboutsummaryrefslogtreecommitdiff
path: root/internal/behavior/behavior.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-01 16:37:45 -0400
committerhistoria <[not public]>2026-07-01 16:37:45 -0400
commite6b4cb9f5816c6ee239233bc85f74ee446a161c2 (patch)
tree1c3bf71c8b7f095baae989afe5e33183a7ed3929 /internal/behavior/behavior.go
parent649ef4b7416ce7053145878841fc9b0bff2f5fec (diff)
downloadthehouseoficarus-e6b4cb9f5816c6ee239233bc85f74ee446a161c2.tar.gz
feat: shop system overhauled, gui conversation tree editor overhauled
Diffstat (limited to 'internal/behavior/behavior.go')
-rw-r--r--internal/behavior/behavior.go128
1 files changed, 99 insertions, 29 deletions
diff --git a/internal/behavior/behavior.go b/internal/behavior/behavior.go
index 2ef7fae..646495a 100644
--- a/internal/behavior/behavior.go
+++ b/internal/behavior/behavior.go
@@ -28,8 +28,7 @@ type TalkConfig struct {
}
type TalkNode struct {
- Message MessageList `yaml:"message"`
- Sequence []string `yaml:"sequence,omitempty"`
+ Messages []string `yaml:"messages,omitempty"`
Condition *Condition `yaml:"condition,omitempty"`
Options []TalkOption `yaml:"options"`
Action *NodeAction `yaml:"action"`
@@ -37,9 +36,9 @@ type TalkNode struct {
}
type TalkOption struct {
- Text string `yaml:"text"`
- Goto string `yaml:"goto"`
- Condition *Condition `yaml:"condition"`
+ Text string `yaml:"text"`
+ Goto string `yaml:"goto"`
+ Condition *Condition `yaml:"condition"`
Action *NodeAction `yaml:"action,omitempty"`
}
@@ -50,31 +49,102 @@ type NodeAction struct {
TakeItem string `yaml:"take_item"`
Teleport int `yaml:"teleport"`
Heal int `yaml:"heal"`
- Cost int `yaml:"cost"`
- Shop *ShopConfig `yaml:"shop"`
- AssignTask bool `yaml:"assign_task"`
- SkipTask bool `yaml:"skip_task"`
- ExtendTask bool `yaml:"extend_task"`
+ Credits int `yaml:"credits"`
ReputationCost int `yaml:"reputation_cost"`
- Sawmill bool `yaml:"sawmill"`
ApsNode bool `yaml:"aps_node"`
}
+// ShopConfig is a root-level mob property (mob YAML `shop:`). Buy prices are
+// always 100% of the item's value; sell prices follow the OSRS store formula:
+//
+// sell = value * max(10, buy_percentage - stock*change_percentage) / 100
+//
+// where stock is the shop's current holding of that item. BuyPercentage
+// defaults to 40 and ChangePercentage to 3 when unset (see ShopBuyPercentage /
+// ShopChangePercentage).
type ShopConfig struct {
- Message string `yaml:"message"`
- Items []ShopItem `yaml:"items"`
+ Message string `yaml:"message"`
+ BuyPercentage float64 `yaml:"buy_percentage"` // sell price at zero stock, % of value (default 40)
+ ChangePercentage float64 `yaml:"change_percentage"` // sell price drop per unit of stock, % of value (default 3)
+ RestockTicks float64 `yaml:"restock_ticks"` // shop-wide default restock interval
+ BuysAnything *bool `yaml:"buys_anything"` // buy items not in the list (default true)
+ Items []ShopItem `yaml:"items"`
}
type ShopItem struct {
- ItemID string `yaml:"item_id"`
- BuyPrice int `yaml:"buy_price"`
- SellPrice int `yaml:"sell_price"`
+ ItemID string `yaml:"item_id"`
+ Stock int `yaml:"stock"` // target/max stock; also starting stock
+ RestockTicks float64 `yaml:"restock_ticks"` // per-item restock interval (overrides shop default)
+}
+
+// Shop pricing defaults, applied when the YAML leaves a field at zero.
+const (
+ ShopBuyPercentage = 40.0
+ ShopChangePercentage = 3.0
+ ShopMinSellPercent = 10.0
+ ShopDefaultRestock = 100.0
+)
+
+// EffectiveBuyPercentage returns BuyPercentage or the default.
+func (c *ShopConfig) EffectiveBuyPercentage() float64 {
+ if c.BuyPercentage > 0 {
+ return c.BuyPercentage
+ }
+ return ShopBuyPercentage
+}
+
+// EffectiveChangePercentage returns ChangePercentage or the default.
+func (c *ShopConfig) EffectiveChangePercentage() float64 {
+ if c.ChangePercentage > 0 {
+ return c.ChangePercentage
+ }
+ return ShopChangePercentage
+}
+
+// Buys reports whether the shop will buy items not in its item list.
+func (c *ShopConfig) Buys() bool {
+ return c.BuysAnything == nil || *c.BuysAnything
+}
+
+// SellPrice computes the per-unit price the shop pays for an item of the given
+// value when the shop currently holds `stock` of it.
+func (c *ShopConfig) SellPrice(value, stock int) int {
+ if stock < 0 {
+ stock = 0
+ }
+ pct := c.EffectiveBuyPercentage() - float64(stock)*c.EffectiveChangePercentage()
+ if pct < ShopMinSellPercent {
+ pct = ShopMinSellPercent
+ }
+ return int(float64(value) * pct / 100.0)
+}
+
+// RestockInterval returns the effective restock interval (in ticks) for an item,
+// honoring the per-item override, then the shop default, then the global default.
+func (c *ShopConfig) RestockInterval(item *ShopItem) int {
+ if item != nil && item.RestockTicks > 0 {
+ return int(item.RestockTicks)
+ }
+ if c.RestockTicks > 0 {
+ return int(c.RestockTicks)
+ }
+ return int(ShopDefaultRestock)
+}
+
+// FindItem returns the configured shop item with the given id, or nil.
+func (c *ShopConfig) FindItem(itemID string) *ShopItem {
+ for i := range c.Items {
+ if c.Items[i].ItemID == itemID {
+ return &c.Items[i]
+ }
+ }
+ return nil
}
type Condition struct {
Flag string `yaml:"flag"`
Value any `yaml:"value"`
- Not bool `yaml:"not"`
+ Not bool `yaml:"not"`
PlayerFlag string `yaml:"player_flag"`
HasItem string `yaml:"has_item"`
MinCredits int `yaml:"min_credits"`
@@ -83,16 +153,16 @@ type Condition struct {
}
type UseConfig struct {
- StartMessage string `yaml:"start_message"`
- TicksPerCycle float64 `yaml:"ticks_per_cycle"`
- Consume map[string]int `yaml:"consume"`
- Reward DropEntry `yaml:"reward"`
- FailMessage string `yaml:"fail_message"`
- Success *SuccessFormula `yaml:"success"`
- Skill string `yaml:"skill"`
- Level int `yaml:"level"`
- XP int `yaml:"xp"`
- SuccessMessage string `yaml:"success_message"`
- EndMessage string `yaml:"end_message"`
- BroadcastMessage string `yaml:"broadcast_message"`
+ StartMessage string `yaml:"start_message"`
+ TicksPerCycle float64 `yaml:"ticks_per_cycle"`
+ Consume map[string]int `yaml:"consume"`
+ Reward DropEntry `yaml:"reward"`
+ FailMessage string `yaml:"fail_message"`
+ Success *SuccessFormula `yaml:"success"`
+ Skill string `yaml:"skill"`
+ Level int `yaml:"level"`
+ XP int `yaml:"xp"`
+ SuccessMessage string `yaml:"success_message"`
+ EndMessage string `yaml:"end_message"`
+ BroadcastMessage string `yaml:"broadcast_message"`
}