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/game/action_gather.go | 405 ----------------------------------------- 1 file changed, 405 deletions(-) delete mode 100644 internal/game/action_gather.go (limited to 'internal/game/action_gather.go') 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] = © - } - } - - 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)) -} -- cgit v1.2.3