aboutsummaryrefslogtreecommitdiff
path: root/internal/game/action_gather.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/game/action_gather.go
parent2725e2927a1595c7b100d942d1f14146252adeb7 (diff)
downloadthehouseoficarus-abd612c15799f604e671e83dc7c410ed2b44185f.tar.gz
slop refactor
Diffstat (limited to 'internal/game/action_gather.go')
-rw-r--r--internal/game/action_gather.go405
1 files changed, 0 insertions, 405 deletions
diff --git a/internal/game/action_gather.go b/internal/game/action_gather.go
deleted file mode 100644
index 1d685be..0000000
--- a/internal/game/action_gather.go
+++ /dev/null
@@ -1,405 +0,0 @@
-package game
-
-import (
- "fmt"
- "math/rand"
- "strings"
-
- "thehouseoficarus/internal/action"
- "thehouseoficarus/internal/color"
- "thehouseoficarus/internal/engine"
- "thehouseoficarus/internal/net"
- "thehouseoficarus/internal/object"
- "thehouseoficarus/internal/player"
- "thehouseoficarus/internal/world"
-)
-
-const birdsNestItemID = "birds_nest"
-
-func loadGatherConfig(g *Game, objDefID string) *action.GatherConfig {
- def, err := g.ObjectStore.Load(objDefID)
- if err != nil {
- return nil
- }
- return def.Gather
-}
-
-func (g *Game) startGather(sess *net.Session, p *player.Player, obj *object.ObjectDef, st *world.ObjState) {
- cfg := obj.Gather
- if cfg == nil {
- sess.WriteLine("Something is wrong with this object.")
- return
- }
-
- skillLevel := p.Level(player.SkillName(cfg.Skill))
- if cfg.Level > 0 && skillLevel < cfg.Level {
- sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", cfg.Level, cfg.Skill))
- return
- }
-
- if st.Depleted {
- if cfg.DepletedMessage != "" {
- msg := cfg.DepletedMessage
- if p.OptionBool("depletion") {
- msg += fmt.Sprintf(" (%d ticks to respawn)", int(st.DepleteTimer))
- }
- sess.WriteLine(msg)
- } else if cfg.DepleteTimer > 0 {
- sess.WriteLine(fmt.Sprintf("The %s has been cut down for %d more ticks.", obj.Name, int(st.DepleteTimer)))
- } else {
- sess.WriteLine(fmt.Sprintf("The %s is depleted for %d more ticks.", obj.Name, int(st.DepleteTimer)))
- }
- return
- }
-
- wait := cfg.BaseWait
- var toolName string
-
- if len(cfg.Tools) > 0 {
- toolSpeed, name, found := g.findTool(p, cfg.Tools)
- if !found {
- names := make([]string, len(cfg.Tools))
- for i, t := range cfg.Tools {
- names[i] = strings.ReplaceAll(t, "_", " ")
- }
- toolList := strings.Join(names, " or ")
- sess.WriteLine(fmt.Sprintf("You need a %s to do that.", toolList))
- return
- }
- toolName = name
- wait = cfg.BaseWait - toolSpeed
- if wait < 1 {
- wait = 1
- }
- }
-
- if cfg.Bait != "" {
- if !p.HasItem(cfg.Bait) {
- baitName := cfg.Bait
- if def, err := g.ItemStore.Load(cfg.Bait); err == nil {
- baitName = def.Name
- }
- sess.WriteLine(fmt.Sprintf("You need %s to fish here.", baitName))
- return
- }
- }
-
- if p.FirstFreeSlot() == -1 {
- sess.WriteLine("Your inventory is too full!")
- return
- }
- verb := cfg.Skill
- switch cfg.Skill {
- case "woodcutting":
- verb = "chopping"
- }
-
- g.broadcastAction(sess, "\n%s starts %s the %s.", p.Name, verb, obj.Name)
-
- d := &action.GatherData{
- ObjDefID: obj.ID,
- InstanceKey: g.World.ObjStateKey(st.RoomID, st.DefID, st.Index),
- InstanceIdx: st.Index + 1,
- EffectiveWait: wait,
- Verb: verb,
- ToolName: toolName,
- }
- if cfg.DepleteTimer > 0 {
- d.DepleteTimer = true
- }
- p.Action = &action.Action{
- Type: action.TypeGather,
- TargetID: st.DefID,
- TargetName: obj.Name,
- WaitLeft: 0,
- Data: d,
- }
-}
-
-func (g *Game) advanceGather(sess *net.Session, p *player.Player) {
- d := p.Action.Data.(*action.GatherData)
- cfg := loadGatherConfig(g, d.ObjDefID)
- if cfg == nil {
- g.cancelAction(p)
- return
- }
-
- step := d.Step
- wait := d.EffectiveWait
- instanceKey := d.InstanceKey
- shared := d.DepleteTimer
-
- if step == 0 {
- if p.FirstFreeSlot() == -1 {
- sess.WriteLine(g.colorize(sess, "error", "Your inventory is too full!"))
- g.cancelAction(p)
- return
- }
- if cfg.Bait != "" {
- if !p.HasItem(cfg.Bait) {
- baitName := cfg.Bait
- if def, err := g.ItemStore.Load(cfg.Bait); err == nil {
- baitName = def.Name
- }
- sess.WriteLine(g.colorize(sess, "error", fmt.Sprintf("You've run out of %s.", baitName)))
- g.cancelAction(p)
- return
- }
- }
- sess.WriteLine(fmt.Sprintf("%s", cfg.GatherMsg))
- d.Step = 1
- p.Action.WaitLeft = engine.ToTicks(wait)
- return
- }
-
- if step == 2 {
- st := g.World.GetObjStateByKey(instanceKey)
- if st != nil && st.Depleted {
- p.Action.WaitLeft = engine.ToTicks(3)
- return
- }
- d.Step = 0
- p.Action.WaitLeft = engine.ToTicks(wait)
- return
- }
-
- if cfg.Bait != "" {
- if !p.HasItem(cfg.Bait) {
- baitName := cfg.Bait
- if def, err := g.ItemStore.Load(cfg.Bait); err == nil {
- baitName = def.Name
- }
- sess.WriteLine(g.colorize(sess, "error", fmt.Sprintf("You've run out of %s.", baitName)))
- g.cancelAction(p)
- return
- }
- p.RemoveItem(cfg.Bait, 1)
- }
-
- skillLevel := p.Level(player.SkillName(cfg.Skill))
- chance := action.SuccessChance(cfg.Success, skillLevel, cfg.Level)
-
- if rand.Float64() < chance {
- eligible := filterDropsByLevel(cfg.Drops, skillLevel)
- drop := action.ResolveDrop(g.DataDir, eligible)
- if drop != nil {
- freeSlot := p.FirstFreeSlot()
- if freeSlot == -1 {
- sess.WriteLine(g.colorize(sess, "error", "Your inventory is too full!"))
- g.cancelAction(p)
- return
- }
-
- qty := drop.Quantity
- if qty <= 0 {
- qty = 1
- }
-
- itemName := drop.ItemID
- itemDef, _ := g.ItemStore.Load(drop.ItemID)
- if itemDef != nil {
- itemName = itemDef.Name
- }
-
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: drop.ItemID, Quantity: qty})
- xp := drop.XP
- if xp <= 0 {
- xp = cfg.XP
- }
- if xp > 0 {
- g.awardSkillXP(sess, p, player.SkillName(cfg.Skill), xp)
- }
- g.AccountStore.SaveCharacter(p)
-
- msg := drop.Message
- if msg == "" {
- msg = fmt.Sprintf("You manage to get some %s.", g.itemColorize(sess, itemDef, itemName))
- } else {
- msg = color.ExpandTags(g.colorMode(sess), msg)
- }
- if xp > 0 && p.OptionBool("xp_drops") {
- msg += g.formatXpDropSingle(sess, p, player.SkillName(cfg.Skill), xp)
- }
- sess.WriteLine(msg)
-
- g.checkBirdNest(sess, p, cfg, freeSlot)
-
- if shared {
- st := g.World.GetObjStateByKey(instanceKey)
- if st != nil && st.SharedTimer <= 0 {
- g.pendingDepletions = append(g.pendingDepletions, pendingDepletion{
- instanceKey: instanceKey,
- objDefID: d.ObjDefID,
- targetName: p.Action.TargetName,
- playerNames: []string{p.Name},
- })
- d.Step = 2
- p.Action.WaitLeft = engine.ToTicks(1)
- return
- }
- }
-
- if !shared && drop.Depletes {
- delay := engine.ToTicks(cfg.RespawnTimer)
- if delay <= 0 {
- delay = 10
- }
- st := g.World.GetObjStateByKey(instanceKey)
- if st != nil {
- st.Depleted = true
- st.DepleteTimer = float64(delay)
- }
-
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other == sess {
- continue
- }
- op := other.Player
- if op == nil || op.Action == nil || op.Action.Type != action.TypeGather {
- continue
- }
- if gd, ok := op.Action.Data.(*action.GatherData); ok && gd.InstanceKey == instanceKey {
- other.WriteLine(fmt.Sprintf("\nThe %s was depleted by %s!", g.colorize(sess, "item", p.Action.TargetName), g.colorize(sess, "player_name", p.Name)))
- g.cancelAction(op)
- g.writePrompt(other)
- }
- }
-
- d.Step = 2
- p.Action.WaitLeft = engine.ToTicks(1)
- return
- }
-
- if p.FirstFreeSlot() == -1 {
- sess.WriteLine(g.colorize(sess, "error", "Your inventory is too full!"))
- g.cancelAction(p)
- return
- }
- d.Step = 0
- p.Action.WaitLeft = engine.ToTicks(wait)
- return
- }
- }
-
- sess.WriteLine(cfg.FailMsg)
- if p.FirstFreeSlot() == -1 {
- sess.WriteLine(g.colorize(sess, "error", "Your inventory is too full!"))
- g.cancelAction(p)
- return
- }
- d.Step = 0
- p.Action.WaitLeft = engine.ToTicks(wait)
-}
-
-func filterDropsByLevel(drops []action.DropEntry, level int) []action.DropEntry {
- var eligible []action.DropEntry
- for _, d := range drops {
- if level >= d.Level {
- eligible = append(eligible, d)
- }
- }
- if len(eligible) == 0 {
- return drops
- }
- return eligible
-}
-
-func (g *Game) depleteSharedTree(st *world.ObjState, cfg *action.GatherConfig, targetName string, playerNames []string) {
- st.Depleted = true
- st.DepleteTimer = float64(engine.ToTicks(cfg.RespawnTimer))
- st.SharedTimer = 0
-
- msg := cfg.ExhaustedMessage
- if msg == "" {
- msg = fmt.Sprintf("The %s falls to the ground!", targetName)
- }
-
- for _, sess := range g.Hub.PlayersInRoom(st.RoomID) {
- op := sess.Player
- if op == nil || op.Action == nil || op.Action.Type != action.TypeGather {
- continue
- }
- if gd, ok := op.Action.Data.(*action.GatherData); !ok || gd.InstanceKey != g.World.ObjStateKey(st.RoomID, st.DefID, st.Index) {
- continue
- }
- isDepleter := false
- for _, name := range playerNames {
- if op.Name == name {
- isDepleter = true
- break
- }
- }
- if isDepleter {
- sess.WriteLine(fmt.Sprintf("\n%s", msg))
- continue
- }
- sess.WriteLine(fmt.Sprintf("\n%s", msg))
- g.cancelAction(op)
- g.writePrompt(sess)
- }
-}
-
-func (g *Game) flushPendingDepletions() {
- if len(g.pendingDepletions) == 0 {
- return
- }
-
- merged := make(map[string]*pendingDepletion)
- for _, pd := range g.pendingDepletions {
- if existing, ok := merged[pd.instanceKey]; ok {
- existing.playerNames = append(existing.playerNames, pd.playerNames...)
- } else {
- copy := pd
- merged[pd.instanceKey] = &copy
- }
- }
-
- for _, pd := range merged {
- st := g.World.GetObjStateByKey(pd.instanceKey)
- if st == nil || st.Depleted {
- continue
- }
- cfg := loadGatherConfig(g, pd.objDefID)
- if cfg == nil {
- continue
- }
- g.depleteSharedTree(st, cfg, pd.targetName, pd.playerNames)
- }
-
- g.pendingDepletions = nil
-}
-
-func (g *Game) checkBirdNest(sess *net.Session, p *player.Player, cfg *action.GatherConfig, currentDropSlot int) {
- if cfg.NestChance <= 0 {
- return
- }
- if rand.Intn(cfg.NestChance) != 0 {
- return
- }
-
- nestName := "bird's nest"
- nestDef, _ := g.ItemStore.Load(birdsNestItemID)
- if nestDef != nil {
- nestName = g.itemColorize(sess, nestDef, nestDef.Name)
- }
-
- freeSlot := -1
- for i := 0; i < 28; i++ {
- if i == currentDropSlot {
- continue
- }
- if p.InvSlot(i) == nil {
- freeSlot = i
- break
- }
- }
- if freeSlot == -1 {
- g.World.AddGroundItem(p.RoomID, birdsNestItemID, 1)
- sess.WriteLine(fmt.Sprintf("A %s falls to the ground.", nestName))
- return
- }
-
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: birdsNestItemID, Quantity: 1})
- g.AccountStore.SaveCharacter(p)
- sess.WriteLine(fmt.Sprintf("A %s falls out of the tree!", nestName))
-}