diff options
Diffstat (limited to 'internal')
41 files changed, 531 insertions, 464 deletions
diff --git a/internal/action/action.go b/internal/action/action.go index 5e66708..a72f6ca 100644 --- a/internal/action/action.go +++ b/internal/action/action.go @@ -23,13 +23,40 @@ func WordPrefixMatch(input, name string) bool { return true } +type ActionType string + +const ( + TypeGather ActionType = "gather" + TypeSteal ActionType = "steal" + TypeTalk ActionType = "talk" + TypeUse ActionType = "use" + TypeBurn ActionType = "burn" + TypeStoke ActionType = "stoke" + TypeSearch ActionType = "search" + TypeIdentify ActionType = "identify" + TypePlant ActionType = "plant" + TypeHarvest ActionType = "harvest" + TypeRake ActionType = "rake" + TypeWater ActionType = "water" + TypeCure ActionType = "cure" + TypeObstacle ActionType = "obstacle" + TypeFletch ActionType = "fletch" + TypeClean ActionType = "clean" + TypeCook ActionType = "cook" + TypeSmelt ActionType = "smelt" + TypeSmith ActionType = "smith" + TypeCraft ActionType = "craft" + TypeCombine ActionType = "combine" + TypeMix ActionType = "mix" + TypeConstruct ActionType = "construct" +) + type Action struct { - Type string + Type ActionType TargetID string TargetName string - Step int WaitLeft int - Data map[string]any + Data any } func (a *Action) Advance() bool { @@ -40,6 +67,111 @@ func (a *Action) Advance() bool { return true } +type GatherData struct { + ObjDefID string + InstanceKey string + InstanceIdx int + EffectiveWait float64 + DepleteTimer bool + Step int + Verb string + ToolName string +} + +type ProductionData struct { + ItemID string + Phase int + Wait float64 + StartMsg string + EndMsg string + Remaining int + NextStepIndex int + StepsAccumulatedTicks float64 +} + +type StealData struct { + TargetType string + StealTable string + StealLevel int + StealXP int + StealSpeed float64 + TargetName string + MobInstanceID string + ObjDefID string + GuardMob string + GuardWatching bool +} + +type TalkData struct { + Node string + Cfg *TalkConfig + EstateDirectory bool + StealGuard bool +} + +type UseData struct { + Cfg *UseConfig + Step int +} + +type BurnData struct { + ItemID string + ToolSpeed float64 + Level int + XP int + BurnTicks float64 + Phase int +} + +type IdentifyData struct { + JunkID string + XPPer int +} + +type ObstacleData struct { + CourseID string + Phase int + ObstacleIndex int + TotalObstacles int + NextRoom int + StartRoom int + ObstacleXP int + CompletionXP int + FailChance float64 + FailDamageMin int + FailDamageMax int + Messages []any + TicksPerPhase float64 + RequiredLevel int +} + +type FarmData struct { + Prefix string + SeedID string + XP float64 + Product string + MinYield float64 + MaxYield float64 +} + +type SearchData struct { + ItemID string + SlotIdx int + Started bool +} + +type FletchData struct { + ItemID string + Phase int + Wait float64 + Remaining int +} + +type CleanData struct { + Phase int + Filter string +} + type DropEntry struct { ItemID string `yaml:"item_id"` Table string `yaml:"table"` diff --git a/internal/game/action.go b/internal/game/action.go index 3146f1a..19e79cf 100644 --- a/internal/game/action.go +++ b/internal/game/action.go @@ -184,14 +184,12 @@ func (g *Game) startAction(sess *net.Session, verb, target string) { func (g *Game) cancelAction(p *player.Player) { p.Action = nil - p.ActionState = nil p.WalkSequence = nil p.ClearMoveState() } func (g *Game) cancelBgAction(p *player.Player) { p.BackgroundAction = nil - p.BackgroundActionState = nil } func (g *Game) AdvanceActions() { @@ -234,7 +232,7 @@ func (g *Game) AdvanceActions() { case "obstacle": g.advanceObstacle(sess, p) default: - if productionActionTypes[p.Action.Type] { + if productionActionTypes[string(p.Action.Type)] { g.advanceProduction(sess, p) } } diff --git a/internal/game/action_agility.go b/internal/game/action_agility.go index f916a8d..116e888 100644 --- a/internal/game/action_agility.go +++ b/internal/game/action_agility.go @@ -24,42 +24,36 @@ func (g *Game) startObstacle(sess *net.Session, p *player.Player, info *Obstacle } p.Action = &action.Action{ - Type: "obstacle", + Type: action.TypeObstacle, TargetID: info.CourseID, TargetName: info.CourseName, WaitLeft: 0, - Data: map[string]any{ - "course_id": info.CourseID, - "phase": 0, - "obstacle_index": info.ObstacleIndex, - "total_obstacles": info.TotalObstacles, - "next_room": info.NextRoom, - "start_room": info.StartRoom, - "obstacle_xp": info.ObstacleXP, - "completion_xp": info.CompletionXP, - "fail_chance": failChance, - "fail_damage_min": info.FailDamage[0], - "fail_damage_max": info.FailDamage[1], - "messages": msgs, - "ticks_per_phase": info.TicksPerPhase, - "required_level": info.RequiredLevel, + Data: &action.ObstacleData{ + CourseID: info.CourseID, + Phase: 0, + ObstacleIndex: info.ObstacleIndex, + TotalObstacles: info.TotalObstacles, + NextRoom: info.NextRoom, + StartRoom: info.StartRoom, + ObstacleXP: info.ObstacleXP, + CompletionXP: info.CompletionXP, + FailChance: failChance, + FailDamageMin: info.FailDamage[0], + FailDamageMax: info.FailDamage[1], + Messages: msgs, + TicksPerPhase: info.TicksPerPhase, + RequiredLevel: info.RequiredLevel, }, } - p.ActionState = &ActionState{ - Type: ActionTraversing, - Verb: gerund, - TargetName: info.CourseName, - } - g.broadcastAction(sess, "\n%s starts %s on the %s.", p.Name, gerund, info.CourseName) } func (g *Game) advanceObstacle(sess *net.Session, p *player.Player) { - data := p.Action.Data - phase := data["phase"].(int) - messages := data["messages"].([]any) - ticksPerPhase := data["ticks_per_phase"].(float64) + d := p.Action.Data.(*action.ObstacleData) + phase := d.Phase + messages := d.Messages + ticksPerPhase := d.TicksPerPhase if phase >= len(messages) { g.cancelAction(p) @@ -70,9 +64,9 @@ func (g *Game) advanceObstacle(sess *net.Session, p *player.Player) { sess.WriteLine(g.colorize(sess, "broadcast", msg)) if phase == 1 { - failChance := data["fail_chance"].(float64) + failChance := d.FailChance if rand.Float64() < failChance { - g.obstacleFail(sess, p, data) + g.obstacleFail(sess, p, d) return } } @@ -80,13 +74,13 @@ func (g *Game) advanceObstacle(sess *net.Session, p *player.Player) { nextPhase := phase + 1 if nextPhase >= len(messages) { - obstacleXP := data["obstacle_xp"].(int) - completionXP := data["completion_xp"].(int) - nextRoom := data["next_room"].(int) - startRoom := data["start_room"].(int) - obstacleIndex := data["obstacle_index"].(int) - totalObstacles := data["total_obstacles"].(int) - courseID := data["course_id"].(string) + obstacleXP := d.ObstacleXP + completionXP := d.CompletionXP + nextRoom := d.NextRoom + startRoom := d.StartRoom + obstacleIndex := d.ObstacleIndex + totalObstacles := d.TotalObstacles + courseID := d.CourseID if obstacleXP > 0 { g.awardSkillXP(sess, p, player.Agility, obstacleXP) @@ -126,14 +120,14 @@ func (g *Game) advanceObstacle(sess *net.Session, p *player.Player) { return } - data["phase"] = nextPhase + d.Phase = nextPhase p.Action.WaitLeft = engine.ToTicks(ticksPerPhase) } -func (g *Game) obstacleFail(sess *net.Session, p *player.Player, data map[string]any) { - startRoom := data["start_room"].(int) - failMin := data["fail_damage_min"].(int) - failMax := data["fail_damage_max"].(int) +func (g *Game) obstacleFail(sess *net.Session, p *player.Player, d *action.ObstacleData) { + startRoom := d.StartRoom + failMin := d.FailDamageMin + failMax := d.FailDamageMax damage := failMin if failMax > failMin { diff --git a/internal/game/action_burn.go b/internal/game/action_burn.go index e86887b..e1872ed 100644 --- a/internal/game/action_burn.go +++ b/internal/game/action_burn.go @@ -118,22 +118,20 @@ func (g *Game) startBurn(sess *net.Session, p *player.Player, itemID string, fro phase = 0 } - p.ActionState = &ActionState{Type: ActionBurning} - g.broadcastAction(sess, "\n%s starts building a fire.", p.Name) p.Action = &action.Action{ - Type: "burn", + Type: action.TypeBurn, TargetID: itemID, TargetName: logDef.Name, WaitLeft: 0, - Data: map[string]any{ - "item_id": itemID, - "tool_speed": toolSpeed, - "level": logDef.FireLevel, - "xp": logDef.FireXP, - "burn_ticks": logDef.BurnTicks, - "phase": phase, + Data: &action.BurnData{ + ItemID: itemID, + ToolSpeed: toolSpeed, + Level: logDef.FireLevel, + XP: logDef.FireXP, + BurnTicks: logDef.BurnTicks, + Phase: phase, }, } } @@ -158,29 +156,26 @@ func (g *Game) startStoke(sess *net.Session, p *player.Player, itemID string) { sess.WriteLine("You begin to tend to the fire.") - p.ActionState = &ActionState{Type: ActionStoking} - g.broadcastAction(sess, "\n%s tends to the fire.", p.Name) p.Action = &action.Action{ - Type: "stoke", + Type: action.TypeStoke, TargetID: itemID, TargetName: logDef.Name, WaitLeft: engine.ToTicks(10), - Data: map[string]any{ - "item_id": itemID, - "fire_key": fireKey, - "burn_ticks": logDef.BurnTicks, - "xp": logDef.FireXP, + Data: &action.BurnData{ + ItemID: itemID, + BurnTicks: logDef.BurnTicks, + XP: logDef.FireXP, }, } } func (g *Game) advanceBurn(sess *net.Session, p *player.Player) { - data := p.Action.Data - itemID := data["item_id"].(string) - toolSpeed := data["tool_speed"].(float64) - phase := data["phase"].(int) + d := p.Action.Data.(*action.BurnData) + itemID := d.ItemID + toolSpeed := d.ToolSpeed + phase := d.Phase logDef, err := g.ItemStore.Load(itemID) if err != nil { @@ -201,7 +196,7 @@ func (g *Game) advanceBurn(sess *net.Session, p *player.Player) { sess.WriteLine(g.colorize(sess, "fire", fmt.Sprintf("You drop the %s and begin to make a fire...", g.itemColorize(sess, logDef, logDef.Name)))) g.broadcastDrop(p, itemID, logDef.Name) - data["phase"] = 1 + d.Phase = 1 p.Action.WaitLeft = engine.ToTicks(toolSpeed) return } @@ -215,7 +210,7 @@ func (g *Game) advanceBurn(sess *net.Session, p *player.Player) { if phase == 1 { sess.WriteLine(g.colorize(sess, "fire", fmt.Sprintf("You try burning the %s on the ground...", g.itemColorize(sess, logDef, logDef.Name)))) - data["phase"] = 2 + d.Phase = 2 p.Action.WaitLeft = engine.ToTicks(toolSpeed) return } @@ -253,17 +248,17 @@ func (g *Game) advanceBurn(sess *net.Session, p *player.Player) { } sess.WriteLine("You can't seem to get a fire going.") - data["phase"] = 1 + d.Phase = 1 p.Action.WaitLeft = engine.ToTicks(toolSpeed) } } func (g *Game) advanceStoke(sess *net.Session, p *player.Player) { - data := p.Action.Data - itemID := data["item_id"].(string) - fireKey := data["fire_key"].(string) - burnTicks := data["burn_ticks"].(float64) - xp := data["xp"].(int) + d := p.Action.Data.(*action.BurnData) + itemID := d.ItemID + fireKey := g.findFireObjectKey(p.RoomID) + burnTicks := d.BurnTicks + xp := d.XP st := g.World.GetObjStateByKey(fireKey) if st == nil || st.Quality <= 0 { @@ -437,7 +432,7 @@ func (g *Game) FireTick() { func (g *Game) cancelStokers(roomID int) { for _, other := range g.Hub.PlayersInRoom(roomID) { op := other.Player - if op != nil && op.Action != nil && op.Action.Type == "stoke" { + if op != nil && op.Action != nil && op.Action.Type == action.TypeStoke { other.WriteLine("The fire went out!") g.cancelAction(op) g.writePrompt(other) diff --git a/internal/game/action_clean.go b/internal/game/action_clean.go index 751ac34..d41746e 100644 --- a/internal/game/action_clean.go +++ b/internal/game/action_clean.go @@ -3,6 +3,7 @@ package game import ( "strings" + "thehouseoficarus/internal/action" "thehouseoficarus/internal/engine" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" @@ -10,11 +11,16 @@ import ( ) func (g *Game) advanceClean(sess *net.Session, p *player.Player) { - phase, _ := p.BackgroundAction.Data["phase"].(int) - filter, _ := p.BackgroundAction.Data["filter"].(string) + data, ok := p.BackgroundAction.Data.(*action.CleanData) + if !ok { + g.cancelBgAction(p) + return + } + phase := data.Phase + filter := data.Filter if phase == 0 { - p.BackgroundAction.Data["phase"] = 1 + data.Phase = 1 p.BackgroundAction.WaitLeft = engine.ToTicks(2) return } diff --git a/internal/game/action_farm.go b/internal/game/action_farm.go index d294c9c..61a66cc 100644 --- a/internal/game/action_farm.go +++ b/internal/game/action_farm.go @@ -6,6 +6,7 @@ import ( "sort" "strings" + "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" @@ -172,9 +173,13 @@ func (g *Game) advancePlant(sess *net.Session, p *player.Player) { if p.Action == nil || p.Action.Data == nil { return } - prefix, _ := p.Action.Data["prefix"].(string) - seedID, _ := p.Action.Data["seed_id"].(string) - xp, _ := p.Action.Data["xp"].(float64) + data, ok := p.Action.Data.(*action.FarmData) + if !ok { + return + } + prefix := data.Prefix + seedID := data.SeedID + xp := data.XP g.ensureFarmState(p, prefix) @@ -204,24 +209,26 @@ func (g *Game) advancePlant(sess *net.Session, p *player.Player) { sess.WriteLine(msg) p.Action = nil - p.ActionState = nil } func (g *Game) advanceHarvest(sess *net.Session, p *player.Player) { if p.Action == nil || p.Action.Data == nil { return } - prefix, _ := p.Action.Data["prefix"].(string) - product, _ := p.Action.Data["product"].(string) - minYield, _ := p.Action.Data["min_yield"].(float64) - maxYield, _ := p.Action.Data["max_yield"].(float64) - xp, _ := p.Action.Data["xp"].(float64) + data, ok := p.Action.Data.(*action.FarmData) + if !ok { + return + } + prefix := data.Prefix + product := data.Product + minYield := data.MinYield + maxYield := data.MaxYield + xp := data.XP ready, _ := p.Flags[prefix+"_ready"].(bool) if !ready { sess.WriteLine("There's nothing ready to harvest here.") p.Action = nil - p.ActionState = nil return } @@ -239,7 +246,6 @@ func (g *Game) advanceHarvest(sess *net.Session, p *player.Player) { if yield <= 0 { sess.WriteLine("Your inventory is too full!") p.Action = nil - p.ActionState = nil return } @@ -297,14 +303,17 @@ func (g *Game) advanceHarvest(sess *net.Session, p *player.Player) { sess.WriteLine(msg) p.Action = nil - p.ActionState = nil } func (g *Game) advanceRake(sess *net.Session, p *player.Player) { if p.Action == nil || p.Action.Data == nil { return } - prefix, _ := p.Action.Data["prefix"].(string) + data, ok := p.Action.Data.(*action.FarmData) + if !ok { + return + } + prefix := data.Prefix p.Flags[prefix+"_weeds"] = false p.Flags[prefix+"_dead"] = false @@ -320,14 +329,17 @@ func (g *Game) advanceRake(sess *net.Session, p *player.Player) { sess.WriteLine(fmt.Sprintf("You rake the %s clean.", patchName)) p.Action = nil - p.ActionState = nil } func (g *Game) advanceWater(sess *net.Session, p *player.Player) { if p.Action == nil || p.Action.Data == nil { return } - prefix, _ := p.Action.Data["prefix"].(string) + data, ok := p.Action.Data.(*action.FarmData) + if !ok { + return + } + prefix := data.Prefix p.Flags[prefix+"_watered"] = true @@ -337,14 +349,17 @@ func (g *Game) advanceWater(sess *net.Session, p *player.Player) { sess.WriteLine(fmt.Sprintf("You water the %s.", patchName)) p.Action = nil - p.ActionState = nil } func (g *Game) advanceCure(sess *net.Session, p *player.Player) { if p.Action == nil || p.Action.Data == nil { return } - prefix, _ := p.Action.Data["prefix"].(string) + data, ok := p.Action.Data.(*action.FarmData) + if !ok { + return + } + prefix := data.Prefix p.RemoveItem("plant_cure", 1) p.Flags[prefix+"_diseased"] = false @@ -354,7 +369,6 @@ func (g *Game) advanceCure(sess *net.Session, p *player.Player) { sess.WriteLine("You apply the plant cure. The patch looks healthy again.") p.Action = nil - p.ActionState = nil } func patchDisplayName(prefix string) string { diff --git a/internal/game/action_fletch.go b/internal/game/action_fletch.go index 27746c4..53346a2 100644 --- a/internal/game/action_fletch.go +++ b/internal/game/action_fletch.go @@ -112,22 +112,26 @@ func (g *Game) startTimedFletch(sess *net.Session, p *player.Player, item *objec Type: "fletch", TargetID: item.ID, TargetName: item.Name, - Data: map[string]any{ - "item_id": item.ID, - "phase": 0, - "wait": craft.Wait, - "remaining": count, + Data: &action.FletchData{ + ItemID: item.ID, + Phase: 0, + Wait: craft.Wait, + Remaining: count, }, WaitLeft: engine.ToTicks(1), } - p.BackgroundActionState = &ActionState{Type: ActionFletching, TargetName: item.Name} } func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { - itemID, _ := p.BackgroundAction.Data["item_id"].(string) - phase, _ := p.BackgroundAction.Data["phase"].(int) - wait, _ := p.BackgroundAction.Data["wait"].(float64) - remaining, _ := p.BackgroundAction.Data["remaining"].(int) + data, ok := p.BackgroundAction.Data.(*action.FletchData) + if !ok { + g.cancelBgAction(p) + return + } + itemID := data.ItemID + phase := data.Phase + wait := data.Wait + remaining := data.Remaining item := g.loadCraftItem(itemID) if item == nil { @@ -137,7 +141,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { c := item.FirstCraft() if phase == 0 { - p.BackgroundAction.Data["phase"] = 1 + data.Phase = 1 p.BackgroundAction.WaitLeft = engine.ToTicks(wait) return } @@ -192,7 +196,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { if remaining > 0 { remaining-- - p.BackgroundAction.Data["remaining"] = remaining + data.Remaining = remaining if remaining <= 0 { sess.WriteLine("You've finished fletching.") g.cancelBgAction(p) diff --git a/internal/game/action_gather.go b/internal/game/action_gather.go index fe3d2a9..1d685be 100644 --- a/internal/game/action_gather.go +++ b/internal/game/action_gather.go @@ -93,41 +93,41 @@ func (g *Game) startGather(sess *net.Session, p *player.Player, obj *object.Obje case "woodcutting": verb = "chopping" } - p.ActionState = &ActionState{Type: ActionGathering, TargetName: obj.Name, ToolName: toolName, Verb: verb} g.broadcastAction(sess, "\n%s starts %s the %s.", p.Name, verb, obj.Name) - data := map[string]any{ - "obj_def_id": obj.ID, - "instance_key": g.World.ObjStateKey(st.RoomID, st.DefID, st.Index), - "instance_idx": st.Index + 1, - "effective_wait": wait, - "step": 0, + 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 { - data["deplete_timer"] = true + d.DepleteTimer = true } p.Action = &action.Action{ - Type: "gather", + Type: action.TypeGather, TargetID: st.DefID, TargetName: obj.Name, WaitLeft: 0, - Data: data, + Data: d, } } func (g *Game) advanceGather(sess *net.Session, p *player.Player) { - objDefID := p.Action.Data["obj_def_id"].(string) - cfg := loadGatherConfig(g, objDefID) + d := p.Action.Data.(*action.GatherData) + cfg := loadGatherConfig(g, d.ObjDefID) if cfg == nil { g.cancelAction(p) return } - step := p.Action.Data["step"].(int) - wait := p.Action.Data["effective_wait"].(float64) - instanceKey := p.Action.Data["instance_key"].(string) - _, shared := p.Action.Data["deplete_timer"] + step := d.Step + wait := d.EffectiveWait + instanceKey := d.InstanceKey + shared := d.DepleteTimer if step == 0 { if p.FirstFreeSlot() == -1 { @@ -147,7 +147,7 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) { } } sess.WriteLine(fmt.Sprintf("%s", cfg.GatherMsg)) - p.Action.Data["step"] = 1 + d.Step = 1 p.Action.WaitLeft = engine.ToTicks(wait) return } @@ -158,7 +158,7 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) { p.Action.WaitLeft = engine.ToTicks(3) return } - p.Action.Data["step"] = 0 + d.Step = 0 p.Action.WaitLeft = engine.ToTicks(wait) return } @@ -229,11 +229,11 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) { if st != nil && st.SharedTimer <= 0 { g.pendingDepletions = append(g.pendingDepletions, pendingDepletion{ instanceKey: instanceKey, - objDefID: objDefID, + objDefID: d.ObjDefID, targetName: p.Action.TargetName, playerNames: []string{p.Name}, }) - p.Action.Data["step"] = 2 + d.Step = 2 p.Action.WaitLeft = engine.ToTicks(1) return } @@ -255,17 +255,17 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) { continue } op := other.Player - if op == nil || op.Action == nil || op.Action.Type != "gather" { + if op == nil || op.Action == nil || op.Action.Type != action.TypeGather { continue } - if op.Action.Data["instance_key"] == instanceKey { + 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) } } - p.Action.Data["step"] = 2 + d.Step = 2 p.Action.WaitLeft = engine.ToTicks(1) return } @@ -275,7 +275,7 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) { g.cancelAction(p) return } - p.Action.Data["step"] = 0 + d.Step = 0 p.Action.WaitLeft = engine.ToTicks(wait) return } @@ -287,7 +287,7 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) { g.cancelAction(p) return } - p.Action.Data["step"] = 0 + d.Step = 0 p.Action.WaitLeft = engine.ToTicks(wait) } @@ -316,10 +316,10 @@ func (g *Game) depleteSharedTree(st *world.ObjState, cfg *action.GatherConfig, t for _, sess := range g.Hub.PlayersInRoom(st.RoomID) { op := sess.Player - if op == nil || op.Action == nil || op.Action.Type != "gather" { + if op == nil || op.Action == nil || op.Action.Type != action.TypeGather { continue } - if op.Action.Data["instance_key"] != g.World.ObjStateKey(st.RoomID, st.DefID, st.Index) { + if gd, ok := op.Action.Data.(*action.GatherData); !ok || gd.InstanceKey != g.World.ObjStateKey(st.RoomID, st.DefID, st.Index) { continue } isDepleter := false diff --git a/internal/game/action_identify.go b/internal/game/action_identify.go index 8b60b13..401ab94 100644 --- a/internal/game/action_identify.go +++ b/internal/game/action_identify.go @@ -3,13 +3,19 @@ package game import ( "fmt" + "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) func (g *Game) advanceIdentify(sess *net.Session, p *player.Player) { - junkID := p.Action.Data["junk_id"].(string) - xpPer := p.Action.Data["xp_per"].(int) + data, ok := p.Action.Data.(*action.IdentifyData) + if !ok { + g.cancelAction(p) + return + } + junkID := data.JunkID + xpPer := data.XPPer scrapCount := p.CountItem("scrap") if scrapCount == 0 { diff --git a/internal/game/action_search.go b/internal/game/action_search.go index 5cb8644..0f755a5 100644 --- a/internal/game/action_search.go +++ b/internal/game/action_search.go @@ -26,43 +26,43 @@ func (g *Game) startSearch(sess *net.Session, p *player.Player, itemID string, s TargetID: itemID, TargetName: def.Name, WaitLeft: engine.ToTicks(ticks), - Data: map[string]any{ - "item_id": itemID, - "slot_idx": slotIdx, - "started": false, + Data: &action.SearchData{ + ItemID: itemID, + SlotIdx: slotIdx, + Started: false, }, } - p.ActionState = &ActionState{Type: ActionSearching, TargetName: def.Name} - g.broadcastAction(sess, "\n%s searches a %s.", p.Name, def.Name) } func (g *Game) advanceSearch(sess *net.Session, p *player.Player) { - data := p.Action.Data - itemID := data["item_id"].(string) - slotIdx := data["slot_idx"].(int) - started := data["started"].(bool) + d, ok := p.Action.Data.(*action.SearchData) + if !ok || d == nil { + sess.WriteLine("Something went wrong.") + g.cancelAction(p) + return + } - def, err := g.ItemStore.Load(itemID) + def, err := g.ItemStore.Load(d.ItemID) if err != nil { sess.WriteLine("Something went wrong.") g.cancelAction(p) return } - if !started { + if !d.Started { msg := def.SearchMessage if msg == "" { msg = fmt.Sprintf("digging through the %s", def.Name) } sess.WriteLine(fmt.Sprintf("You begin %s.", msg)) - data["started"] = true + d.Started = true return } - slot := p.InvSlot(slotIdx) - if slot == nil || slot.ItemID != itemID || slot.Quantity <= 0 { + slot := p.InvSlot(d.SlotIdx) + if slot == nil || slot.ItemID != d.ItemID || slot.Quantity <= 0 { sess.WriteLine("The item is gone.") g.cancelAction(p) return @@ -71,7 +71,7 @@ func (g *Game) advanceSearch(sess *net.Session, p *player.Player) { if slot.Quantity > 1 { slot.Quantity-- } else { - p.SetInvSlot(slotIdx, nil) + p.SetInvSlot(d.SlotIdx, nil) } dt, err := action.LoadDropTable(g.DataDir, def.SearchTable) diff --git a/internal/game/action_state.go b/internal/game/action_state.go index bed936d..fc4b461 100644 --- a/internal/game/action_state.go +++ b/internal/game/action_state.go @@ -1,109 +1,98 @@ package game -type ActionType string - -const ( - ActionIdle ActionType = "" - ActionGathering ActionType = "gathering" - ActionCombating ActionType = "combating" - ActionMoving ActionType = "moving" - ActionUsing ActionType = "using" - ActionTalking ActionType = "talking" - ActionBurning ActionType = "burning" - ActionStoking ActionType = "stoking" - ActionPickingUp ActionType = "picking_up" - ActionDropping ActionType = "dropping" - ActionSearching ActionType = "searching" - ActionResting ActionType = "resting" - ActionWalking ActionType = "walking" - ActionProducing ActionType = "producing" - ActionFletching ActionType = "fletching" - ActionEating ActionType = "eating" - ActionCleaning ActionType = "cleaning" - ActionIdentifying ActionType = "identifying" - ActionStealing ActionType = "stealing" - ActionPlanting ActionType = "planting" - ActionHarvesting ActionType = "harvesting_crop" - ActionRaking ActionType = "raking" - ActionWatering ActionType = "watering" - ActionCuring ActionType = "curing" - ActionTraversing ActionType = "traversing" - ActionHacking ActionType = "hacking" - ActionHiding ActionType = "hiding" - ActionWorking ActionType = "working" +import ( + "thehouseoficarus/internal/action" + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/player" ) -type ActionState struct { - Type ActionType - TargetName string - ToolName string - Direction string - Verb string -} +func (g *Game) playerActionDisplay(p *player.Player) string { + if cs := combat.GetCombat(p.Name); cs != nil { + mob := g.MobStore.GetInstance(cs.MobID) + if mob != nil { + if mob.IsTask() { + return "working on a " + mob.Name + } + return "fighting a " + mob.Name + } + } -func (a *ActionState) Description() string { - if a == nil || a.Type == ActionIdle { - return "" + if p.MoveTicks > 0 { + return "heading " + p.MoveDirection } - switch a.Type { - case ActionGathering: - desc := a.Verb + " a " + a.TargetName - if a.ToolName != "" { - desc += " with a " + a.ToolName - } - return desc - case ActionCombating: - return "fighting a " + a.TargetName - case ActionMoving: - return "heading " + a.Direction - case ActionUsing: - return "using a " + a.TargetName - case ActionTalking: - return "talking to " + a.TargetName - case ActionBurning: - return "trying to start a fire" - case ActionStoking: - return "tending to a fire" - case ActionPickingUp: - return "picking up " + a.TargetName - case ActionDropping: - return "dropping " + a.TargetName - case ActionSearching: - return "digging through a " + a.TargetName - case ActionResting: - return "resting" - case ActionWalking: + if len(p.WalkSequence) > 0 { return "walking somewhere with a purpose!" - case ActionProducing: - return a.Verb + " some " + a.TargetName - case ActionFletching: - return "fletching " + a.TargetName - case ActionEating: - return "eating " + a.TargetName - case ActionCleaning: - return "cleaning herbs" - case ActionIdentifying: - return "identifying scrap at " + a.TargetName - case ActionStealing: - return "stealing from " + a.TargetName - case ActionPlanting: - return "planting " + a.TargetName - case ActionHarvesting: - return "harvesting " + a.TargetName - case ActionRaking: - return "raking a " + a.TargetName - case ActionWatering: - return "watering a " + a.TargetName - case ActionCuring: - return "curing a " + a.TargetName - case ActionTraversing: - return a.Verb + " across " + a.TargetName - case ActionHacking: - return "jacked into a " + a.TargetName - case ActionHiding: - return "positioning behind a " + a.TargetName - case ActionWorking: - return "working on a " + a.TargetName } + + if ss, ok := g.safespot.Get(p.Name); ok && ss.Active { + obj, err := g.ObjectStore.Load(ss.ObjectDefID) + if err == nil { + return "positioning behind a " + obj.Name + } + return "hiding" + } + + if a := p.Action; a != nil { + switch a.Type { + case action.TypeGather: + if d, ok := a.Data.(*action.GatherData); ok { + desc := d.Verb + " a " + a.TargetName + if d.ToolName != "" { + desc += " with a " + d.ToolName + } + return desc + } + case action.TypeSteal: + return "stealing from " + a.TargetName + case action.TypeTalk: + return "talking to " + a.TargetName + case action.TypeUse: + return "using a " + a.TargetName + case action.TypeBurn: + return "trying to start a fire" + case action.TypeStoke: + return "tending to a fire" + case action.TypeSearch: + return "digging through a " + a.TargetName + case action.TypeIdentify: + return "identifying scrap at " + a.TargetName + case action.TypePlant: + return "planting " + a.TargetName + case action.TypeHarvest: + return "harvesting " + a.TargetName + case action.TypeRake: + return "raking a " + a.TargetName + case action.TypeWater: + return "watering a " + a.TargetName + case action.TypeCure: + return "curing a " + a.TargetName + case action.TypeObstacle: + return "traversing across " + a.TargetName + case action.TypeCook: + return "cooking some " + a.TargetName + case action.TypeSmelt: + return "smelting some " + a.TargetName + case action.TypeSmith: + return "smithing some " + a.TargetName + case action.TypeCraft: + return "crafting some " + a.TargetName + case action.TypeCombine: + return "combining some " + a.TargetName + case action.TypeMix: + return "mixing some " + a.TargetName + case action.TypeConstruct: + return "constructing some " + a.TargetName + } + } + + if a := p.BackgroundAction; a != nil { + switch a.Type { + case action.TypeFletch: + return "fletching " + a.TargetName + case action.TypeClean: + return "cleaning herbs" + } + } + return "" } diff --git a/internal/game/action_steal.go b/internal/game/action_steal.go index 259c914..65c684c 100644 --- a/internal/game/action_steal.go +++ b/internal/game/action_steal.go @@ -257,43 +257,42 @@ func (g *Game) startSteal(sess *net.Session, p *player.Player, targetType string } sess.WriteLine(fmt.Sprintf("You attempt to steal from the %s...", targetName)) - p.ActionState = &ActionState{Type: ActionStealing, TargetName: targetName} g.broadcastAction(sess, "\n%s glances around the room.", p.Name) p.Action = &action.Action{ - Type: "steal", + Type: action.TypeSteal, TargetID: targetID, TargetName: targetName, WaitLeft: engine.ToTicks(stealSpeed), - Data: map[string]any{ - "target_type": targetType, - "steal_table": stealTable, - "steal_level": stealLevel, - "steal_xp": stealXP, - "steal_speed": stealSpeed, - "target_name": targetName, - "mob_instance_id": mobInstanceID, - "obj_def_id": objDefID, - "guard_mob": guardMob, - "guard_watching": guardWatching, + Data: &action.StealData{ + TargetType: targetType, + StealTable: stealTable, + StealLevel: stealLevel, + StealXP: stealXP, + StealSpeed: stealSpeed, + TargetName: targetName, + MobInstanceID: mobInstanceID, + ObjDefID: objDefID, + GuardMob: guardMob, + GuardWatching: guardWatching, }, } } func (g *Game) advanceSteal(sess *net.Session, p *player.Player) { - data := p.Action.Data - targetType := data["target_type"].(string) - stealTable := data["steal_table"].(string) - stealLevel := data["steal_level"].(int) - stealXP := data["steal_xp"].(int) - stealSpeed := data["steal_speed"].(float64) - targetName := data["target_name"].(string) - guardMob := data["guard_mob"].(string) - guardWatching := data["guard_watching"].(bool) + d := p.Action.Data.(*action.StealData) + targetType := d.TargetType + stealTable := d.StealTable + stealLevel := d.StealLevel + stealXP := d.StealXP + stealSpeed := d.StealSpeed + targetName := d.TargetName + guardMob := d.GuardMob + guardWatching := d.GuardWatching if targetType == "mob" { - mobInstanceID := data["mob_instance_id"].(string) + mobInstanceID := d.MobInstanceID mob := g.MobStore.GetInstance(mobInstanceID) if mob == nil || mob.HP <= 0 || mob.RoomID != p.RoomID { sess.WriteLine("Your target is gone.") @@ -305,14 +304,14 @@ func (g *Game) advanceSteal(sess *net.Session, p *player.Player) { g.cancelAction(p) return } - data["steal_level"] = mob.StealLevel - data["steal_xp"] = mob.StealXP - data["steal_speed"] = mob.StealSpeed + d.StealLevel = mob.StealLevel + d.StealXP = mob.StealXP + d.StealSpeed = mob.StealSpeed stealLevel = mob.StealLevel stealXP = mob.StealXP stealSpeed = mob.StealSpeed } else { - objDefID := data["obj_def_id"].(string) + objDefID := d.ObjDefID found := false for _, st := range g.World.AllObjInstances(p.RoomID) { if st.DefID == objDefID && !st.Depleted { @@ -327,13 +326,13 @@ func (g *Game) advanceSteal(sess *net.Session, p *player.Player) { } objDef, err := g.ObjectStore.Load(objDefID) if err == nil { - data["steal_level"] = objDef.StealLevel - data["steal_xp"] = objDef.StealXP - data["steal_speed"] = objDef.StealSpeed + d.StealLevel = objDef.StealLevel + d.StealXP = objDef.StealXP + d.StealSpeed = objDef.StealSpeed stealLevel = objDef.StealLevel stealXP = objDef.StealXP stealSpeed = objDef.StealSpeed - data["guard_mob"] = objDef.GuardMob + d.GuardMob = objDef.GuardMob guardMob = objDef.GuardMob if guardMob != "" { @@ -344,7 +343,7 @@ func (g *Game) advanceSteal(sess *net.Session, p *player.Player) { g.guardWatchTimers[timerKey] = 0 } guardWatching = g.isGuardWatching(p.RoomID, objDefID) - data["guard_watching"] = guardWatching + d.GuardWatching = guardWatching } } } @@ -387,7 +386,7 @@ func (g *Game) advanceSteal(sess *net.Session, p *player.Player) { p.Action.WaitLeft = engine.ToTicks(stealSpeed) } else { if targetType == "mob" { - mobInstanceID := data["mob_instance_id"].(string) + mobInstanceID := d.MobInstanceID mob := g.MobStore.GetInstance(mobInstanceID) sess.WriteLine(fmt.Sprintf("The %s notices you! They attack!", targetName)) g.cancelAction(p) @@ -467,13 +466,11 @@ func (g *Game) startStealGuardTalk(sess *net.Session, p *player.Player, guardMob return } - p.ActionState = &ActionState{Type: ActionTalking, TargetName: guardMob.Name} - p.Action = &action.Action{ Type: "talk", TargetID: guardMob.DefID, TargetName: guardMob.Name, - Data: map[string]any{"node": "start", "talk_cfg": cfg, "steal_guard": true}, + Data: &action.TalkData{Node: "start", Cfg: cfg, StealGuard: true}, } g.showTalkNode(sess, node) diff --git a/internal/game/action_talk.go b/internal/game/action_talk.go index 560b34d..5b3a095 100644 --- a/internal/game/action_talk.go +++ b/internal/game/action_talk.go @@ -20,12 +20,11 @@ func (g *Game) startMobTalk(sess *net.Session, p *player.Player, mob *world.MobI } if node, ok := cfg.Nodes["start"]; ok { - p.ActionState = &ActionState{Type: ActionTalking, TargetName: mob.Name} p.Action = &action.Action{ - Type: "talk", + Type: action.TypeTalk, TargetID: mob.DefID, TargetName: mob.Name, - Data: map[string]any{"node": "start", "talk_cfg": cfg}, + Data: &action.TalkData{Node: "start", Cfg: cfg}, } g.showTalkNode(sess, node) } else { @@ -41,12 +40,11 @@ func (g *Game) startTalk(sess *net.Session, p *player.Player, obj *object.Object } if node, ok := cfg.Nodes["start"]; ok { - p.ActionState = &ActionState{Type: ActionTalking, TargetName: obj.Name} p.Action = &action.Action{ - Type: "talk", + Type: action.TypeTalk, TargetID: obj.ID, TargetName: obj.Name, - Data: map[string]any{"node": "start", "talk_cfg": cfg}, + Data: &action.TalkData{Node: "start", Cfg: cfg}, } g.showTalkNode(sess, node) } else { @@ -68,15 +66,17 @@ func (g *Game) showTalkNode(sess *net.Session, node action.TalkNode) { if v, ok := g.Flags.Get("guard_hostile"); ok && v != nil { g.Flags.Delete("guard_hostile") p := sess.Player - if p != nil && p.Action != nil && p.Action.Data["steal_guard"] == true { - guardMob := g.findGuardInRoom(p.RoomID, "guard") - if guardMob != nil { - sess.State = net.StateGame - g.cancelAction(p) - guardMob.Protected = false - g.startCombat(sess, p, guardMob) + if p != nil && p.Action != nil { + if td, ok := p.Action.Data.(*action.TalkData); ok && td.StealGuard { + guardMob := g.findGuardInRoom(p.RoomID, "guard") + if guardMob != nil { + sess.State = net.StateGame + g.cancelAction(p) + guardMob.Protected = false + g.startCombat(sess, p, guardMob) + } + return } - return } } } @@ -101,7 +101,7 @@ func (g *Game) showTalkNode(sess *net.Session, node action.TalkNode) { func (g *Game) handleTalkInput(sess *net.Session, input string) { p := sess.Player - if p == nil || p.Action == nil || p.Action.Type != "talk" { + if p == nil || p.Action == nil || p.Action.Type != action.TypeTalk { sess.State = net.StateGame g.writePrompt(sess) return @@ -116,20 +116,21 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { return } - if _, ok := p.Action.Data["estate_directory"].(bool); ok { + if td, ok := p.Action.Data.(*action.TalkData); ok && td.EstateDirectory { g.handleEstateDirectoryTalk(sess, input) return } - cfg, ok := p.Action.Data["talk_cfg"].(*action.TalkConfig) - if !ok || cfg == nil { + td, ok := p.Action.Data.(*action.TalkData) + if !ok || td.Cfg == nil { g.cancelAction(p) sess.State = net.StateGame g.writePrompt(sess) return } + cfg := td.Cfg - nodeKey := p.Action.Data["node"].(string) + nodeKey := td.Node node, ok := cfg.Nodes[nodeKey] if !ok { g.cancelAction(p) @@ -176,7 +177,7 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { if chosen.Goto != "" { if nextNode, ok := cfg.Nodes[chosen.Goto]; ok { - p.Action.Data["node"] = chosen.Goto + td.Node = chosen.Goto g.showTalkNode(sess, nextNode) return } diff --git a/internal/game/action_use.go b/internal/game/action_use.go index dde838f..4bac96d 100644 --- a/internal/game/action_use.go +++ b/internal/game/action_use.go @@ -34,8 +34,6 @@ func (g *Game) startUse(sess *net.Session, p *player.Player, obj *object.ObjectD return } - p.ActionState = &ActionState{Type: ActionUsing, TargetName: obj.Name} - g.broadcastAction(sess, "\n%s uses the %s.", p.Name, obj.Name) p.Action = &action.Action{ @@ -43,18 +41,19 @@ func (g *Game) startUse(sess *net.Session, p *player.Player, obj *object.ObjectD TargetID: obj.ID, TargetName: obj.Name, WaitLeft: engine.ToTicks(1), - Data: map[string]any{"step": 0, "use_cfg": cfg}, + Data: &action.UseData{Cfg: cfg, Step: 0}, } sess.WriteLine(fmt.Sprintf("%s", cfg.Message)) } func (g *Game) advanceUse(sess *net.Session, p *player.Player) { - cfg, ok := p.Action.Data["use_cfg"].(*action.UseConfig) - if !ok || cfg == nil { + d, ok := p.Action.Data.(*action.UseData) + if !ok || d == nil || d.Cfg == nil { g.cancelAction(p) return } + cfg := d.Cfg for itemID, qty := range cfg.Consume { if !p.HasItem(itemID) { diff --git a/internal/game/cmd_attack.go b/internal/game/cmd_attack.go index 27307fe..abaefbb 100644 --- a/internal/game/cmd_attack.go +++ b/internal/game/cmd_attack.go @@ -179,10 +179,8 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn } } if isTask { - p.ActionState = &ActionState{Type: ActionWorking, TargetName: mob.Name} g.broadcastAction(sess, "\n%s begins working on %s.", p.Name, mobDisplayName(mob, true)) } else { - p.ActionState = &ActionState{Type: ActionCombating, TargetName: mob.Name} g.broadcastAction(sess, "\n%s attacks %s!", p.Name, mobDisplayName(mob, true)) } @@ -265,7 +263,6 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn func (g *Game) playerAttack(sess *net.Session, p *player.Player, mob *world.MobInstance) { if g.processConsumeQueue(p, sess) { - p.ActionState = &ActionState{Type: ActionEating, TargetName: "food"} return } @@ -332,7 +329,6 @@ func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstanc func (g *Game) playerAttackUnarmed(sess *net.Session, p *player.Player, mob *world.MobInstance) { if g.processConsumeQueue(p, sess) { - p.ActionState = &ActionState{Type: ActionEating, TargetName: "food"} return } @@ -548,13 +544,11 @@ func (g *Game) applyMobHit(sess *net.Session, p *player.Player, mob *world.MobIn if ss, hasSS := g.safespot.Get(p.Name); hasSS && ss.HideCountdown > 0 { g.safespot.Delete(p.Name) - p.ActionState = &ActionState{Type: ActionCombating, TargetName: mob.Name} sess.WriteLine(g.colorize(sess, "error", "You're hit while repositioning! You failed to hide.")) } if p.MoveTicks > 0 { p.ClearMoveState() - p.ActionState = &ActionState{Type: ActionCombating, TargetName: mob.Name} sess.WriteLine("Can't escape!") } } @@ -569,7 +563,6 @@ func (g *Game) applyMobMiss(sess *net.Session, mob *world.MobInstance) { func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInstance) { combat.LeaveCombat(p.Name) - p.ActionState = nil if p.HP <= 0 { g.killPlayer(sess, p, mob) @@ -668,7 +661,6 @@ func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInst // retribution. func (g *Game) killPlayer(sess *net.Session, p *player.Player, mob *world.MobInstance) { combat.LeaveCombat(p.Name) - p.ActionState = nil if p.HasActiveTech("retribution") { retDef := GetTechDef("retribution") diff --git a/internal/game/cmd_clean.go b/internal/game/cmd_clean.go index a40f5fc..63bea24 100644 --- a/internal/game/cmd_clean.go +++ b/internal/game/cmd_clean.go @@ -66,13 +66,12 @@ func (g *Game) doClean(sess *net.Session, input string) { p.BackgroundAction = &action.Action{ Type: "clean", TargetID: "clean_herbs", - Data: map[string]any{ - "phase": 0, - "filter": filter, + Data: &action.CleanData{ + Phase: 0, + Filter: filter, }, WaitLeft: engine.ToTicks(1), } - p.BackgroundActionState = &ActionState{Type: ActionCleaning} g.broadcastAction(sess, "%s starts cleaning herbs.", p.Name) diff --git a/internal/game/cmd_consume.go b/internal/game/cmd_consume.go index f45b912..249bc9a 100644 --- a/internal/game/cmd_consume.go +++ b/internal/game/cmd_consume.go @@ -103,8 +103,6 @@ func (g *Game) doEatNow(sess *net.Session, p *player.Player, itemID string, def p.ConsumeCooldown = 3 g.AccountStore.SaveCharacter(p) - p.ActionState = &ActionState{Type: ActionEating, TargetName: def.Name} - sess.WriteLine(g.colorize(sess, "eat_food", def.EatMessage)) if p.HP <= 0 { @@ -280,7 +278,6 @@ func (g *Game) applyPotion(sess *net.Session, p *player.Player, itemID string, d } p.ConsumeCooldown = 3 - p.ActionState = &ActionState{Type: ActionEating} g.broadcastAction(sess, "\n%s drinks a %s.", p.Name, def.Name) } diff --git a/internal/game/cmd_drop.go b/internal/game/cmd_drop.go index ffed913..d77eb53 100644 --- a/internal/game/cmd_drop.go +++ b/internal/game/cmd_drop.go @@ -10,7 +10,6 @@ import ( func (g *Game) doDropAll(sess *net.Session) { p := sess.Player g.cancelAction(p) - p.ActionState = &ActionState{Type: ActionDropping, TargetName: "inventory"} count := 0 for _, slot := range p.Inventory { @@ -50,7 +49,6 @@ func (g *Game) doDropAllNamed(sess *net.Session, input string) { name = def.Name } coloredName := g.itemColorize(sess, def, name) - p.ActionState = &ActionState{Type: ActionDropping, TargetName: name} if def != nil && def.Stackable { slot := p.InvSlot(matches[0].Slot) @@ -109,7 +107,6 @@ func (g *Game) doDrop(sess *net.Session, input string) { if def != nil { name = def.Name } - p.ActionState = &ActionState{Type: ActionDropping, TargetName: name} if qty == 0 { if def != nil && def.Stackable { diff --git a/internal/game/cmd_estate_directory.go b/internal/game/cmd_estate_directory.go index 780bcce..ca28018 100644 --- a/internal/game/cmd_estate_directory.go +++ b/internal/game/cmd_estate_directory.go @@ -72,12 +72,11 @@ func (g *Game) showEstateDirectoryTalk(sess *net.Session, p *player.Player, home sess.WriteLine(" You are a registered homeowner in this neighborhood.") sess.WriteLine(" Type 'enter' to go to your house, or 'leave' to step away.") sess.State = net.StateTalk - p.ActionState = &ActionState{Type: ActionTalking, TargetName: "Estate Directory"} p.Action = &action.Action{ Type: "talk", TargetID: "estate_directory", TargetName: "Estate Directory", - Data: map[string]any{"node": "start", "estate_directory": true}, + Data: &action.TalkData{Node: "start", EstateDirectory: true}, } sess.Write("\nChoice: ") return @@ -104,19 +103,16 @@ func (g *Game) handleEstateDirectoryTalk(sess *net.Session, input string) { if houseRoom > 0 { sess.State = net.StateGame p.Action = nil - p.ActionState = nil g.teleportPlayer(sess, p, houseRoom) return } sess.State = net.StateGame p.Action = nil - p.ActionState = nil g.writePrompt(sess) case "leave", "bye", "exit", "quit": p := sess.Player if p != nil { p.Action = nil - p.ActionState = nil } sess.State = net.StateGame g.writePrompt(sess) diff --git a/internal/game/cmd_farm.go b/internal/game/cmd_farm.go index 791cb6d..eca0429 100644 --- a/internal/game/cmd_farm.go +++ b/internal/game/cmd_farm.go @@ -139,13 +139,12 @@ func (g *Game) doPlant(sess *net.Session, input string) { TargetID: seedID, TargetName: seedDef.Name, WaitLeft: 2, - Data: map[string]any{ - "seed_id": seedID, - "prefix": prefix, - "xp": float64(seedDef.FarmPlantXP), + Data: &action.FarmData{ + SeedID: seedID, + Prefix: prefix, + XP: float64(seedDef.FarmPlantXP), }, } - p.ActionState = &ActionState{Type: ActionPlanting, TargetName: seedDef.Name} g.AccountStore.SaveCharacter(p) } @@ -222,16 +221,15 @@ func (g *Game) doHarvest(sess *net.Session, input string) { TargetID: prefix, TargetName: productName, WaitLeft: 3, - Data: map[string]any{ - "prefix": prefix, - "seed_id": seedID, - "product": product, - "min_yield": float64(minYield), - "max_yield": float64(maxYield), - "xp": float64(harvestXP), + Data: &action.FarmData{ + Prefix: prefix, + SeedID: seedID, + Product: product, + MinYield: float64(minYield), + MaxYield: float64(maxYield), + XP: float64(harvestXP), }, } - p.ActionState = &ActionState{Type: ActionHarvesting, TargetName: productName} g.AccountStore.SaveCharacter(p) } @@ -273,11 +271,10 @@ func (g *Game) doRake(sess *net.Session, input string) { TargetID: prefix, TargetName: patchName, WaitLeft: 4, - Data: map[string]any{ - "prefix": prefix, + Data: &action.FarmData{ + Prefix: prefix, }, } - p.ActionState = &ActionState{Type: ActionRaking, TargetName: patchName} g.AccountStore.SaveCharacter(p) } @@ -333,11 +330,10 @@ func (g *Game) doWater(sess *net.Session, input string) { TargetID: prefix, TargetName: patchName, WaitLeft: 2, - Data: map[string]any{ - "prefix": prefix, + Data: &action.FarmData{ + Prefix: prefix, }, } - p.ActionState = &ActionState{Type: ActionWatering, TargetName: patchName} g.AccountStore.SaveCharacter(p) } @@ -377,11 +373,10 @@ func (g *Game) doCure(sess *net.Session, input string) { TargetID: prefix, TargetName: patchName, WaitLeft: 2, - Data: map[string]any{ - "prefix": prefix, + Data: &action.FarmData{ + Prefix: prefix, }, } - p.ActionState = &ActionState{Type: ActionCuring, TargetName: patchName} g.AccountStore.SaveCharacter(p) } diff --git a/internal/game/cmd_fletch.go b/internal/game/cmd_fletch.go index 088ce63..9cf50bc 100644 --- a/internal/game/cmd_fletch.go +++ b/internal/game/cmd_fletch.go @@ -67,7 +67,6 @@ func (g *Game) doFletch(sess *net.Session, input string) { if p.Action != nil { p.Action = nil - p.ActionState = nil } items := g.CraftIndex.ByType("fletching") diff --git a/internal/game/cmd_get.go b/internal/game/cmd_get.go index 30bc8c2..fe5d322 100644 --- a/internal/game/cmd_get.go +++ b/internal/game/cmd_get.go @@ -37,7 +37,6 @@ func (g *Game) doGet(sess *net.Session, input string) { if itemID == "credits" { g.pickupCredits(sess, p, itemID) - p.ActionState = &ActionState{Type: ActionPickingUp, TargetName: "credits"} return } @@ -46,7 +45,6 @@ func (g *Game) doGet(sess *net.Session, input string) { if def != nil { name = def.Name } - p.ActionState = &ActionState{Type: ActionPickingUp, TargetName: name} available := 0 if gqty, ok := ground[itemID]; ok { diff --git a/internal/game/cmd_hide.go b/internal/game/cmd_hide.go index 52ebaea..d22f3fa 100644 --- a/internal/game/cmd_hide.go +++ b/internal/game/cmd_hide.go @@ -105,8 +105,6 @@ func (g *Game) executeHide(sess *net.Session, args []string, rawInput string) { HideCountdown: hideCountdown, }) - p.ActionState = &ActionState{Type: ActionHiding, TargetName: objDef.Name} - if inCombat { sess.WriteLine(fmt.Sprintf("You try to get behind the %s for cover...", objDef.Name)) } @@ -124,7 +122,6 @@ func (g *Game) executeUnhide(sess *net.Session, args []string, rawInput string) if ss.HideCountdown > 0 { g.safespot.Delete(p.Name) - p.ActionState = nil sess.WriteLine("You stop trying to hide.") return } diff --git a/internal/game/cmd_id.go b/internal/game/cmd_id.go index 6514463..3ddfe33 100644 --- a/internal/game/cmd_id.go +++ b/internal/game/cmd_id.go @@ -139,11 +139,9 @@ func (g *Game) doIdentify(sess *net.Session, input string) { TargetID: found.AltarID, TargetName: altarName, WaitLeft: 1, - Data: map[string]any{ - "junk_id": found.JunkID, - "xp_per": found.XPPer, - "level_req": found.LevelReq, + Data: &action.IdentifyData{ + JunkID: found.JunkID, + XPPer: found.XPPer, }, } - p.ActionState = &ActionState{Type: ActionIdentifying, TargetName: altarName} } diff --git a/internal/game/cmd_jack.go b/internal/game/cmd_jack.go index f33ea85..ea31b7d 100644 --- a/internal/game/cmd_jack.go +++ b/internal/game/cmd_jack.go @@ -65,7 +65,6 @@ func (g *Game) doJack(sess *net.Session, target string) { Started: false, } - p.ActionState = &ActionState{Type: ActionHacking, TargetName: tDef.Name} sess.State = net.StateHacking g.broadcastAction(sess, "\n%s jacks into a terminal.", p.Name) diff --git a/internal/game/cmd_look.go b/internal/game/cmd_look.go index 266cd15..3f31a15 100644 --- a/internal/game/cmd_look.go +++ b/internal/game/cmd_look.go @@ -479,10 +479,8 @@ func (g *Game) showRoomPlayers(sess *net.Session, p *player.Player, room *world. } line += fmt.Sprintf(" (fighting %s)", name) } - } else if as, ok := op.ActionState.(*ActionState); ok && as != nil { - if desc := as.Description(); desc != "" { - line += ", " + desc - } + } else if desc := g.playerActionDisplay(op); desc != "" { + line += ", " + desc } sess.WriteLine(line + ".") } diff --git a/internal/game/cmd_move.go b/internal/game/cmd_move.go index b749e84..2939702 100644 --- a/internal/game/cmd_move.go +++ b/internal/game/cmd_move.go @@ -86,7 +86,6 @@ func (g *Game) doMove(sess *net.Session, dir string, multiplier float64) { } p.MoveTicks = ticks - p.ActionState = &ActionState{Type: ActionMoving, Direction: string(exitDir)} if inCombat && p.OptionBool("run_countdown") { if p.MoveTicks > 1 { @@ -178,7 +177,6 @@ func (g *Game) completeMove(sess *net.Session, p *player.Player) { } sess.WriteLine(fmt.Sprintf("You walk %s.", g.colorize(sess, "direction", exitDir))) - p.ActionState = &ActionState{Type: ActionMoving, Direction: exitDir} if p.OptionBool("description") { g.doLook(sess) } else { diff --git a/internal/game/cmd_quit.go b/internal/game/cmd_quit.go index 187d766..4599614 100644 --- a/internal/game/cmd_quit.go +++ b/internal/game/cmd_quit.go @@ -19,7 +19,6 @@ func (g *Game) doQuit(sess *net.Session) { } g.cancelAction(p) - p.ActionState = &ActionState{Type: ActionResting} g.cancelRest(p.Name) g.broadcastAction(sess, "\n%s sits down to rest.", p.Name) diff --git a/internal/game/cmd_score.go b/internal/game/cmd_score.go index 635c4b4..d4dd823 100644 --- a/internal/game/cmd_score.go +++ b/internal/game/cmd_score.go @@ -124,10 +124,8 @@ func (g *Game) doScore(sess *net.Session) { gap() actionDesc := "Idle" - if as, ok := p.ActionState.(*ActionState); ok && as != nil { - if d := as.Description(); d != "" { - actionDesc = d - } + if d := g.playerActionDisplay(p); d != "" { + actionDesc = d } content("Action: " + actionDesc) diff --git a/internal/game/cmd_shop.go b/internal/game/cmd_shop.go index 59cf5ee..b293ff9 100644 --- a/internal/game/cmd_shop.go +++ b/internal/game/cmd_shop.go @@ -393,15 +393,15 @@ func (g *Game) leaveShop(sess *net.Session) { return } - nodeKey, _ := p.Action.Data["node"].(string) - - cfg, ok := p.Action.Data["talk_cfg"].(*action.TalkConfig) - if !ok || cfg == nil { + td, ok := p.Action.Data.(*action.TalkData) + if !ok || td.Cfg == nil { sess.State = net.StateGame g.cancelAction(p) g.writePrompt(sess) return } + nodeKey := td.Node + cfg := td.Cfg node, ok := cfg.Nodes[nodeKey] if !ok { diff --git a/internal/game/cmd_stop.go b/internal/game/cmd_stop.go index 7a403f1..bfd8fd4 100644 --- a/internal/game/cmd_stop.go +++ b/internal/game/cmd_stop.go @@ -1,13 +1,14 @@ package game import ( + "thehouseoficarus/internal/combat" "thehouseoficarus/internal/net" ) func (g *Game) executeStop(sess *net.Session, args []string, rawInput string) { p := sess.Player - as, ok := p.ActionState.(*ActionState) - if !ok || as == nil || as.Type == "" { + ss, _ := g.safespot.Get(p.Name) + if p.Action == nil && p.BackgroundAction == nil && combat.GetCombat(p.Name) == nil && p.MoveTicks == 0 && len(p.WalkSequence) == 0 && !ss.Active { sess.WriteLine("You're not doing anything.") return } diff --git a/internal/game/cmd_trigger_combat.go b/internal/game/cmd_trigger_combat.go index 8ad585a..990ba86 100644 --- a/internal/game/cmd_trigger_combat.go +++ b/internal/game/cmd_trigger_combat.go @@ -17,7 +17,6 @@ func (g *Game) scienceAttack(sess *net.Session, p *player.Player, mob *world.Mob } if g.processConsumeQueue(p, sess) { - p.ActionState = &ActionState{Type: ActionEating, TargetName: "food"} return true } diff --git a/internal/game/cmd_use.go b/internal/game/cmd_use.go index 640e28b..a2cddaf 100644 --- a/internal/game/cmd_use.go +++ b/internal/game/cmd_use.go @@ -103,7 +103,6 @@ func (g *Game) useRoomObject(sess *net.Session, p *player.Player, input string) if ui.Action != nil { g.applyNodeAction(sess, ui.Action) } - p.ActionState = &ActionState{Type: ActionUsing, TargetName: def.Name} g.broadcastAction(sess, "\n%s uses the %s.", p.Name, def.Name) return true } diff --git a/internal/game/cmd_verbs.go b/internal/game/cmd_verbs.go index f66dc74..9ee1607 100644 --- a/internal/game/cmd_verbs.go +++ b/internal/game/cmd_verbs.go @@ -3,6 +3,7 @@ package game import ( "strings" + "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/world" ) @@ -89,8 +90,8 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) { addUnique(§ionObjs, &seen, "use "+name) for _, r := range recipes { if info, ok := productionTypes[r.FirstCraft().Type]; ok { - if info.ActionType != "combine" && info.ActionType != "fletch" && info.ActionType != "mix" { - addUnique(§ionObjs, &seen, info.ActionType) + if info.ActionType != action.TypeCombine && info.ActionType != action.TypeFletch && info.ActionType != action.TypeMix { + addUnique(§ionObjs, &seen, string(info.ActionType)) } } for _, c := range r.FirstCraft().Consume { diff --git a/internal/game/cmd_walk.go b/internal/game/cmd_walk.go index 9485af5..d7d51e2 100644 --- a/internal/game/cmd_walk.go +++ b/internal/game/cmd_walk.go @@ -112,12 +112,10 @@ func (g *Game) advanceWalk(sess *net.Session, p *player.Player) { if p.MoveTicks == 0 && p.RoomID == oldRoom { p.WalkSequence = nil - p.ActionState = nil return } if len(p.WalkSequence) > 0 && remaining != "" { - p.ActionState = &ActionState{Type: ActionWalking} sess.WriteLine(fmt.Sprintf("You're headed: %s.", remaining)) } } diff --git a/internal/game/core_hacking.go b/internal/game/core_hacking.go index b270593..a537057 100644 --- a/internal/game/core_hacking.go +++ b/internal/game/core_hacking.go @@ -87,7 +87,6 @@ func (g *Game) endHacking(sess *net.Session, p *player.Player, completed bool, w } delete(g.hackingStates, p.Name) - p.ActionState = nil sess.State = net.StateGame g.writePrompt(sess) } diff --git a/internal/game/core_production.go b/internal/game/core_production.go index dd36885..56d1ccc 100644 --- a/internal/game/core_production.go +++ b/internal/game/core_production.go @@ -75,7 +75,7 @@ func (g *Game) resolveCraftMessage(sess *net.Session, itemMsg, defaultMsg string return g.resolveCraftVar(sess, msg, craft, outputID, byproducts, hasItem) } -func (g *Game) startProduction(sess *net.Session, p *player.Player, item *object.ItemDef, craft *object.CraftDef, actionType, displayVerb, startMsg, endMsg string, count int) { +func (g *Game) startProduction(sess *net.Session, p *player.Player, item *object.ItemDef, craft *object.CraftDef, actionType action.ActionType, displayVerb, startMsg, endMsg string, count int) { g.cancelAction(p) g.cancelBgAction(p) @@ -111,19 +111,17 @@ func (g *Game) startProduction(sess *net.Session, p *player.Player, item *object Type: actionType, TargetID: item.ID, TargetName: outputName, - Data: map[string]any{ - "item_id": item.ID, - "phase": 0, - "wait": wait, - "start_msg": startMsg, - "end_msg": endMsg, - "remaining": count, + Data: &action.ProductionData{ + ItemID: item.ID, + Phase: 0, + Wait: wait, + StartMsg: startMsg, + EndMsg: endMsg, + Remaining: count, }, WaitLeft: engine.ToTicks(1), } - p.ActionState = &ActionState{Type: ActionProducing, TargetName: outputName, Verb: displayVerb} - g.broadcastAction(sess, "%s starts %s.", p.Name, displayVerb) } @@ -141,7 +139,7 @@ func (g *Game) startProductionFromItem(sess *net.Session, p *player.Player, item info, ok := productionTypes[craft.Type] if !ok { info = productionTypeInfo{ - ActionType: craft.Type, + ActionType: action.ActionType(craft.Type), DisplayVerb: craft.Type, StartMessage: "You start " + craft.Type + " %i1.", SuccessMessage: "You produce %n.", @@ -168,12 +166,17 @@ func (g *Game) loadCraftItem(itemID string) *object.ItemDef { } func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { - itemID := p.Action.Data["item_id"].(string) - phase := p.Action.Data["phase"].(int) - wait := p.Action.Data["wait"].(float64) - startMsg, _ := p.Action.Data["start_msg"].(string) - endMsg, _ := p.Action.Data["end_msg"].(string) - remaining, _ := p.Action.Data["remaining"].(int) + d, ok := p.Action.Data.(*action.ProductionData) + if !ok { + g.cancelAction(p) + return false + } + itemID := d.ItemID + phase := d.Phase + wait := d.Wait + startMsg := d.StartMsg + endMsg := d.EndMsg + remaining := d.Remaining item := g.loadCraftItem(itemID) if item == nil { @@ -187,22 +190,22 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { sess.WriteLine(startMsg) } if len(craft.Steps) > 0 { - p.Action.Data["next_step_index"] = 0 - p.Action.Data["steps_accumulated_ticks"] = float64(0) + d.NextStepIndex = 0 + d.StepsAccumulatedTicks = 0 } - p.Action.Data["phase"] = 1 + d.Phase = 1 p.Action.WaitLeft = engine.ToTicks(wait) return true } - if stepsIdx, ok := p.Action.Data["next_step_index"].(int); ok && stepsIdx < len(craft.Steps) { - accTicks, _ := p.Action.Data["steps_accumulated_ticks"].(float64) + if stepsIdx := d.NextStepIndex; stepsIdx < len(craft.Steps) { + accTicks := d.StepsAccumulatedTicks accTicks += wait - p.Action.Data["steps_accumulated_ticks"] = accTicks + d.StepsAccumulatedTicks = accTicks for i := stepsIdx; i < len(craft.Steps); i++ { if accTicks >= craft.Steps[i].Tick { sess.WriteLine(g.resolveCraftVar(sess, craft.Steps[i].Message, craft, item.ID, nil, p.HasItem)) - p.Action.Data["next_step_index"] = i + 1 + d.NextStepIndex = i + 1 } } } @@ -291,7 +294,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { if remaining > 0 { remaining-- - p.Action.Data["remaining"] = remaining + d.Remaining = remaining if remaining <= 0 { if endMsg != "" { sess.WriteLine(endMsg) @@ -646,7 +649,7 @@ func (g *Game) hasToolType(p *player.Player, toolType string) bool { } type productionTypeInfo struct { - ActionType string + ActionType action.ActionType DisplayVerb string StartMessage string SuccessMessage string @@ -656,7 +659,7 @@ type productionTypeInfo struct { var productionTypes = map[string]productionTypeInfo{ "cooking": { - ActionType: "cook", + ActionType: action.TypeCook, DisplayVerb: "cooking", StartMessage: "You start cooking %i1.", SuccessMessage: "Cooked to perfection. %n looks great!", @@ -664,7 +667,7 @@ var productionTypes = map[string]productionTypeInfo{ FailMessage: "You accidentally burn the %i1.", }, "smelting": { - ActionType: "smelt", + ActionType: action.TypeSmelt, DisplayVerb: "smelting", StartMessage: "You place the %i1 into the furnace.", SuccessMessage: "You remove a white hot %n!", @@ -672,42 +675,42 @@ var productionTypes = map[string]productionTypeInfo{ FailMessage: "The %i1 is consumed by the flames.", }, "smithing": { - ActionType: "smith", + ActionType: action.TypeSmith, DisplayVerb: "smithing", StartMessage: "You begin smithing %i1.", SuccessMessage: "You smith a %n.", EndMessage: "You've finished smithing.", }, "crafting": { - ActionType: "craft", + ActionType: action.TypeCraft, DisplayVerb: "crafting", StartMessage: "You begin crafting %i1.", SuccessMessage: "You craft a %n.", EndMessage: "You've finished crafting.", }, "combine": { - ActionType: "combine", + ActionType: action.TypeCombine, DisplayVerb: "combining", StartMessage: "You start combining %i1.", SuccessMessage: "You produce %n.", EndMessage: "You've finished combining.", }, "fletching": { - ActionType: "fletch", + ActionType: action.TypeFletch, DisplayVerb: "fletching", StartMessage: "You begin fletching %i1.", SuccessMessage: "You fletch a %n.", EndMessage: "You've finished fletching.", }, "pharmacy": { - ActionType: "mix", + ActionType: action.TypeMix, DisplayVerb: "mixing", StartMessage: "You start mixing %i1.", SuccessMessage: "You mix a %n.", EndMessage: "You've finished mixing.", }, "construction": { - ActionType: "construct", + ActionType: action.TypeConstruct, DisplayVerb: "constructing", StartMessage: "You begin constructing %i1.", SuccessMessage: "You construct a %n.", @@ -720,7 +723,7 @@ var productionActionTypes map[string]bool func init() { productionActionTypes = make(map[string]bool) for _, pt := range productionTypes { - productionActionTypes[pt.ActionType] = true + productionActionTypes[string(pt.ActionType)] = true } } diff --git a/internal/game/game.go b/internal/game/game.go index a6b64cc..dfa5143 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -252,30 +252,6 @@ func (g *Game) ProcessQueuedCommands() { continue } - if p.ActionState != nil { - as, ok := p.ActionState.(*ActionState) - if !ok { - p.ActionState = nil - } else { - switch as.Type { - case ActionGathering, ActionCombating, ActionUsing, ActionTalking, - ActionBurning, ActionStoking, ActionSearching, ActionIdentifying, - ActionHacking, ActionHiding, ActionWorking, - ActionResting, ActionWalking, ActionProducing, - ActionStealing, ActionPlanting, ActionHarvesting, ActionRaking, ActionWatering, ActionCuring, - ActionTraversing: - default: - if as.Type != ActionMoving || p.MoveTicks <= 0 { - p.ActionState = nil - } - } - } - } - - if p.BackgroundAction == nil { - p.BackgroundActionState = nil - } - cmds := g.queue.DrainFree(p.Name) for _, qc := range cmds { g.cancelRest(p.Name) @@ -321,8 +297,8 @@ func (g *Game) ProcessQueuedCommands() { if len(parts) > 0 { g.executeCommand(qc.Session, parts[0], parts[1:], raw) } - as, hasAction := p.ActionState.(*ActionState) - isHiding := hasAction && as.Type == ActionHiding + ss, _ := g.safespot.Get(p.Name) + isHiding := ss.Active isBusy := p.Action != nil || len(p.WalkSequence) > 0 || combat.GetCombat(p.Name) != nil || p.MoveTicks > 0 || isHiding _, isResting := g.restTimers[p.Name] if !isResting && !isBusy && qc.Session.State == net.StateGame { diff --git a/internal/game/sys_safespot.go b/internal/game/sys_safespot.go index 28f08d9..5544667 100644 --- a/internal/game/sys_safespot.go +++ b/internal/game/sys_safespot.go @@ -107,7 +107,6 @@ func (g *Game) activateSafespot(sess *net.Session, p *player.Player, ss *Safespo } st.SafespotOccupants = append(st.SafespotOccupants, p.Name) - p.ActionState = nil var msg string levelIdx := st.SafespotLevel - 1 @@ -258,7 +257,6 @@ func (g *Game) leaveSafespot(sess *net.Session, p *player.Player) { objName = objDef.Name } sess.WriteLine(fmt.Sprintf("You step out from behind the %s.", objName)) - p.ActionState = nil } func (g *Game) forceLeaveSafespot(sess *net.Session, p *player.Player, ss *SafespotState, reason string) { @@ -272,7 +270,6 @@ func (g *Game) forceLeaveSafespot(sess *net.Session, p *player.Player, ss *Safes sess.WriteLine(color.ExpandTags(g.colorMode(sess), alert)) } } - p.ActionState = nil } func (g *Game) removeSafespotOccupant(playerName string, ss *SafespotState) { diff --git a/internal/game/tick.go b/internal/game/tick.go index 1402b06..6d79964 100644 --- a/internal/game/tick.go +++ b/internal/game/tick.go @@ -4,6 +4,7 @@ import ( "fmt" "math/rand" + "thehouseoficarus/internal/action" "thehouseoficarus/internal/combat" "thehouseoficarus/internal/player" "thehouseoficarus/internal/world" @@ -166,8 +167,8 @@ func (g *Game) SharedDepletionTick() { if p == nil || p.Action == nil || p.Action.Type != "gather" { continue } - if key, ok := p.Action.Data["instance_key"].(string); ok { - activeKeys[key] = true + if gd, ok := p.Action.Data.(*action.GatherData); ok { + activeKeys[gd.InstanceKey] = true } } diff --git a/internal/player/player.go b/internal/player/player.go index 03ed7ac..4b74db7 100644 --- a/internal/player/player.go +++ b/internal/player/player.go @@ -174,9 +174,7 @@ type Player struct { RegenerateTick int AmmoQty int `yaml:"ammo_qty,omitempty"` Action *action.Action `yaml:"-"` - ActionState any `yaml:"-"` BackgroundAction *action.Action `yaml:"-"` - BackgroundActionState any `yaml:"-"` WalkSequence []string `yaml:"-"` ConsumeCooldown int `yaml:"-"` MoveTicks int `yaml:"-"` |
