aboutsummaryrefslogtreecommitdiff
path: root/internal/game
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-25 00:44:47 -0400
committerhistoria <[not public]>2026-06-25 00:44:47 -0400
commit94a06fbbe682701ca4d4bd2a70cd74d8df29c932 (patch)
treeeb49fb1893e61092138164d419e863ee3fe0d1e2 /internal/game
parent15b7e221b799ef107dec44ecdb294026dfd3d059 (diff)
downloadthehouseoficarus-94a06fbbe682701ca4d4bd2a70cd74d8df29c932.tar.gz
refactor: replaced map[string]any with typed structs for Data
Diffstat (limited to 'internal/game')
-rw-r--r--internal/game/action.go4
-rw-r--r--internal/game/action_agility.go74
-rw-r--r--internal/game/action_burn.go57
-rw-r--r--internal/game/action_clean.go12
-rw-r--r--internal/game/action_farm.go50
-rw-r--r--internal/game/action_fletch.go28
-rw-r--r--internal/game/action_gather.go54
-rw-r--r--internal/game/action_identify.go10
-rw-r--r--internal/game/action_search.go32
-rw-r--r--internal/game/action_state.go187
-rw-r--r--internal/game/action_steal.go69
-rw-r--r--internal/game/action_talk.go41
-rw-r--r--internal/game/action_use.go9
-rw-r--r--internal/game/cmd_attack.go8
-rw-r--r--internal/game/cmd_clean.go7
-rw-r--r--internal/game/cmd_consume.go3
-rw-r--r--internal/game/cmd_drop.go3
-rw-r--r--internal/game/cmd_estate_directory.go6
-rw-r--r--internal/game/cmd_farm.go39
-rw-r--r--internal/game/cmd_fletch.go1
-rw-r--r--internal/game/cmd_get.go2
-rw-r--r--internal/game/cmd_hide.go3
-rw-r--r--internal/game/cmd_id.go8
-rw-r--r--internal/game/cmd_jack.go1
-rw-r--r--internal/game/cmd_look.go6
-rw-r--r--internal/game/cmd_move.go2
-rw-r--r--internal/game/cmd_quit.go1
-rw-r--r--internal/game/cmd_score.go6
-rw-r--r--internal/game/cmd_shop.go8
-rw-r--r--internal/game/cmd_stop.go5
-rw-r--r--internal/game/cmd_trigger_combat.go1
-rw-r--r--internal/game/cmd_use.go1
-rw-r--r--internal/game/cmd_verbs.go5
-rw-r--r--internal/game/cmd_walk.go2
-rw-r--r--internal/game/core_hacking.go1
-rw-r--r--internal/game/core_production.go73
-rw-r--r--internal/game/game.go28
-rw-r--r--internal/game/sys_safespot.go3
-rw-r--r--internal/game/tick.go5
39 files changed, 396 insertions, 459 deletions
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(&sectionObjs, &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(&sectionObjs, &seen, info.ActionType)
+ if info.ActionType != action.TypeCombine && info.ActionType != action.TypeFletch && info.ActionType != action.TypeMix {
+ addUnique(&sectionObjs, &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
}
}