aboutsummaryrefslogtreecommitdiff
path: root/internal/game
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game')
-rw-r--r--internal/game/action.go4
-rw-r--r--internal/game/action_agility.go8
-rw-r--r--internal/game/action_burn.go48
-rw-r--r--internal/game/action_clean.go6
-rw-r--r--internal/game/action_default_target.go2
-rw-r--r--internal/game/action_farm.go10
-rw-r--r--internal/game/action_fletch.go20
-rw-r--r--internal/game/action_gather.go78
-rw-r--r--internal/game/action_search.go8
-rw-r--r--internal/game/action_steal.go8
-rw-r--r--internal/game/action_use.go8
-rw-r--r--internal/game/cmd_agility.go2
-rw-r--r--internal/game/cmd_attack.go14
-rw-r--r--internal/game/cmd_clean.go11
-rw-r--r--internal/game/cmd_consume.go8
-rw-r--r--internal/game/cmd_cook.go59
-rw-r--r--internal/game/cmd_craft.go34
-rw-r--r--internal/game/cmd_description.go4
-rw-r--r--internal/game/cmd_drop.go2
-rw-r--r--internal/game/cmd_fletch.go2
-rw-r--r--internal/game/cmd_get.go22
-rw-r--r--internal/game/cmd_jack.go10
-rw-r--r--internal/game/cmd_look.go4
-rw-r--r--internal/game/cmd_mix.go108
-rw-r--r--internal/game/cmd_quit.go10
-rw-r--r--internal/game/cmd_registry.go4
-rw-r--r--internal/game/cmd_smelt.go52
-rw-r--r--internal/game/cmd_smith.go4
-rw-r--r--internal/game/cmd_trigger_combat.go2
-rw-r--r--internal/game/cmd_trigger_enchant.go18
-rw-r--r--internal/game/cmd_trigger_transport.go9
-rw-r--r--internal/game/cmd_trigger_utility.go71
-rw-r--r--internal/game/cmd_use.go24
-rw-r--r--internal/game/core_login_account.go6
-rw-r--r--internal/game/core_messages.go13
-rw-r--r--internal/game/core_production.go142
-rw-r--r--internal/game/core_startup.go65
-rw-r--r--internal/game/core_types.go2
-rw-r--r--internal/game/core_utils.go16
-rw-r--r--internal/game/game.go16
-rw-r--r--internal/game/hacking/liars_dice.go (renamed from internal/game/hacking/hacking_liars_dice.go)0
-rw-r--r--internal/game/hacking/mastermind.go (renamed from internal/game/hacking/hacking_mastermind.go)0
-rw-r--r--internal/game/hacking/wumpus.go (renamed from internal/game/hacking/hacking_wumpus.go)0
-rw-r--r--internal/game/sys_combat.go6
-rw-r--r--internal/game/sys_science.go32
45 files changed, 301 insertions, 671 deletions
diff --git a/internal/game/action.go b/internal/game/action.go
index f25cabc..2f5dbaf 100644
--- a/internal/game/action.go
+++ b/internal/game/action.go
@@ -57,7 +57,7 @@ func (g *Game) startAction(sess *net.Session, verb, target string) {
if p.Action != nil {
g.cancelAction(p)
}
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
lower := strings.ToLower(target)
instanceIdx := -1
@@ -206,7 +206,7 @@ func (g *Game) cancelAction(p *player.Player) {
p.ClearMoveState()
}
-func (g *Game) cancelBackgroundAction(p *player.Player) {
+func (g *Game) cancelBgAction(p *player.Player) {
p.BackgroundAction = nil
p.BackgroundActionState = nil
}
diff --git a/internal/game/action_agility.go b/internal/game/action_agility.go
index 37fbab9..43c9cfd 100644
--- a/internal/game/action_agility.go
+++ b/internal/game/action_agility.go
@@ -52,13 +52,7 @@ func (g *Game) startObstacle(sess *net.Session, p *player.Player, info *Obstacle
TargetName: info.CourseName,
}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts %s on the %s.", p.Name, gerund, 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) {
diff --git a/internal/game/action_burn.go b/internal/game/action_burn.go
index c31d7d5..71b5a35 100644
--- a/internal/game/action_burn.go
+++ b/internal/game/action_burn.go
@@ -28,7 +28,7 @@ func (g *Game) doBurn(sess *net.Session, p *player.Player, input string) {
if p.Action != nil {
g.cancelAction(p)
}
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
itemID, fromGround, ambiguous := g.resolveBurnTarget(p, input)
if ambiguous {
@@ -47,7 +47,7 @@ func (g *Game) doStoke(sess *net.Session, p *player.Player, input string) {
if p.Action != nil {
g.cancelAction(p)
}
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
if !g.hasFireObject(p.RoomID) {
sess.WriteLine("There's no fire here to stoke.")
@@ -120,13 +120,7 @@ func (g *Game) startBurn(sess *net.Session, p *player.Player, itemID string, fro
p.ActionState = &ActionState{Type: ActionBurning}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts building a fire.", p.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s starts building a fire.", p.Name)
p.Action = &action.Action{
Type: "burn",
@@ -166,13 +160,7 @@ func (g *Game) startStoke(sess *net.Session, p *player.Player, itemID string) {
p.ActionState = &ActionState{Type: ActionStoking}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s tends to the fire.", p.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s tends to the fire.", p.Name)
p.Action = &action.Action{
Type: "stoke",
@@ -260,11 +248,7 @@ func (g *Game) advanceBurn(sess *net.Session, p *player.Player) {
}
sess.WriteLine(msg)
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s started a fire!", p.Name)))
- }
- }
+ g.broadcastAction(sess, "\n%s started a fire!", p.Name)
return
}
@@ -458,12 +442,12 @@ func (g *Game) cancelStokers(roomID int) {
func (g *Game) resolveBurnTarget(p *player.Player, input string) (itemID string, fromGround bool, ambiguous bool) {
if input != "" {
- return g.resolveNamedBurnTarget(p, input)
+ return g.namedBurnTarget(p, input)
}
- return g.resolveDefaultBurnTarget(p)
+ return g.defaultBurnTarget(p)
}
-func (g *Game) collectBurnableGround(roomID int, name string) []string {
+func (g *Game) burnableGround(roomID int, name string) []string {
var out []string
for itemID := range g.World.GroundItems(roomID) {
def, err := g.ItemStore.Load(itemID)
@@ -477,7 +461,7 @@ func (g *Game) collectBurnableGround(roomID int, name string) []string {
return out
}
-func (g *Game) collectBurnableInv(p *player.Player, name string) []string {
+func (g *Game) burnableInv(p *player.Player, name string) []string {
var out []string
seen := make(map[string]bool)
for _, slot := range p.Inventory {
@@ -496,8 +480,8 @@ func (g *Game) collectBurnableInv(p *player.Player, name string) []string {
return out
}
-func (g *Game) resolveNamedBurnTarget(p *player.Player, input string) (itemID string, fromGround bool, ambiguous bool) {
- groundMatches := g.collectBurnableGround(p.RoomID, input)
+func (g *Game) namedBurnTarget(p *player.Player, input string) (itemID string, fromGround bool, ambiguous bool) {
+ groundMatches := g.burnableGround(p.RoomID, input)
if len(groundMatches) > 1 {
return "", false, true
}
@@ -505,7 +489,7 @@ func (g *Game) resolveNamedBurnTarget(p *player.Player, input string) (itemID st
return groundMatches[0], true, false
}
- invMatches := g.collectBurnableInv(p, input)
+ invMatches := g.burnableInv(p, input)
if len(invMatches) > 1 {
return "", false, true
}
@@ -516,8 +500,8 @@ func (g *Game) resolveNamedBurnTarget(p *player.Player, input string) (itemID st
return "", false, false
}
-func (g *Game) resolveDefaultBurnTarget(p *player.Player) (itemID string, fromGround bool, ambiguous bool) {
- groundBurnable := g.collectBurnableGround(p.RoomID, "")
+func (g *Game) defaultBurnTarget(p *player.Player) (itemID string, fromGround bool, ambiguous bool) {
+ groundBurnable := g.burnableGround(p.RoomID, "")
if len(groundBurnable) == 1 {
return groundBurnable[0], true, false
}
@@ -525,7 +509,7 @@ func (g *Game) resolveDefaultBurnTarget(p *player.Player) (itemID string, fromGr
return "", false, true
}
- invBurnable := g.collectBurnableInv(p, "")
+ invBurnable := g.burnableInv(p, "")
if len(invBurnable) == 1 {
return invBurnable[0], false, false
}
@@ -537,7 +521,7 @@ func (g *Game) resolveDefaultBurnTarget(p *player.Player) (itemID string, fromGr
}
func (g *Game) resolveStokeTarget(p *player.Player, input string) (string, bool) {
- invBurnable := g.collectBurnableInv(p, input)
+ invBurnable := g.burnableInv(p, input)
if len(invBurnable) == 1 {
return invBurnable[0], false
}
diff --git a/internal/game/action_clean.go b/internal/game/action_clean.go
index 104dcb0..7330883 100644
--- a/internal/game/action_clean.go
+++ b/internal/game/action_clean.go
@@ -21,7 +21,7 @@ func (g *Game) advanceClean(sess *net.Session, p *player.Player) {
allRecipes, err := g.RecipeStore.LoadAll()
if err != nil {
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
@@ -51,7 +51,7 @@ func (g *Game) advanceClean(sess *net.Session, p *player.Player) {
if recipe == nil {
sess.WriteLine("\nYou've finished cleaning herbs.")
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
@@ -105,7 +105,7 @@ func (g *Game) advanceClean(sess *net.Session, p *player.Player) {
if !hasMore {
sess.WriteLine("\nYou've finished cleaning herbs.")
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
diff --git a/internal/game/action_default_target.go b/internal/game/action_default_target.go
index 2ca0bd3..a184f32 100644
--- a/internal/game/action_default_target.go
+++ b/internal/game/action_default_target.go
@@ -8,7 +8,7 @@ func verbToSkill(verb string) string {
return verbSkill[verb]
}
-func (g *Game) resolveDefaultTarget(roomID int, verb string) string {
+func (g *Game) defaultTarget(roomID int, verb string) string {
skill := verbToSkill(verb)
if skill == "" {
return ""
diff --git a/internal/game/action_farm.go b/internal/game/action_farm.go
index d79150f..21604aa 100644
--- a/internal/game/action_farm.go
+++ b/internal/game/action_farm.go
@@ -51,7 +51,7 @@ func (g *Game) ensureFarmState(p *player.Player, prefix string) {
}
}
-func (g *Game) findActiveFarmPrefixes(p *player.Player) []string {
+func (g *Game) findFarmPrefixes(p *player.Player) []string {
seen := make(map[string]bool)
var prefixes []string
for key := range p.Flags {
@@ -94,7 +94,7 @@ func (g *Game) FarmTick() {
}
func (g *Game) advanceFarmGrowth(sess *net.Session, p *player.Player) {
- prefixes := g.findActiveFarmPrefixes(p)
+ prefixes := g.findFarmPrefixes(p)
for _, prefix := range prefixes {
seedID, _ := p.Flags[prefix+"_seed"].(string)
if seedID == "" {
@@ -492,7 +492,7 @@ func (g *Game) farmMatchPrefix(p *player.Player, input string) (prefix string, d
return "", "", -1
}
-func (g *Game) farmLookSuffixForObj(p *player.Player, defID string, index int) string {
+func (g *Game) farmObjSuffix(p *player.Player, defID string, index int) string {
if defID == "tool_shed" {
return g.toolShedLookSuffix(p)
}
@@ -538,7 +538,7 @@ func (g *Game) showFarmPatches(sess *net.Session, p *player.Player) {
g.ensureFarmState(p, prefix)
idxStr := ""
- if obj.Index > 0 || g.countFarmPatchesOfType(objInstances, obj.DefID) > 1 {
+ if obj.Index > 0 || g.countPatchesByType(objInstances, obj.DefID) > 1 {
idxStr = fmt.Sprintf(" %d", obj.Index+1)
}
@@ -618,7 +618,7 @@ func (g *Game) showFarmPatches(sess *net.Session, p *player.Player) {
}
}
-func (g *Game) countFarmPatchesOfType(instances []world.ObjState, defID string) int {
+func (g *Game) countPatchesByType(instances []world.ObjState, defID string) int {
count := 0
for _, obj := range instances {
if obj.DefID == defID && farmPatchDefIDs[obj.DefID] {
diff --git a/internal/game/action_fletch.go b/internal/game/action_fletch.go
index aa5dfc7..3d8c30f 100644
--- a/internal/game/action_fletch.go
+++ b/internal/game/action_fletch.go
@@ -115,13 +115,7 @@ func (g *Game) startTimedFletch(sess *net.Session, p *player.Player, recipe *act
}
p.BackgroundActionState = &ActionState{Type: ActionFletching, TargetName: outputName}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts fletching.", p.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s starts fletching.", p.Name)
sess.WriteLine(fmt.Sprintf("\nYou begin fletching %s.", outputName))
}
@@ -132,9 +126,9 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
wait, _ := p.BackgroundAction.Data["wait"].(float64)
remaining, _ := p.BackgroundAction.Data["remaining"].(int)
- recipe := g.loadProductionRecipe(recipeID)
+ recipe := g.loadRecipe(recipeID)
if recipe == nil {
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
@@ -146,7 +140,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
if !g.canDoFletchRecipe(p, recipe) {
sess.WriteLine("\nYou've run out of fletching materials.")
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
@@ -175,7 +169,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
freeSlot := p.FirstFreeSlot()
if freeSlot == -1 {
sess.WriteLine("\nYour inventory is too full!")
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty})
@@ -205,14 +199,14 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
p.BackgroundAction.Data["remaining"] = remaining
if remaining <= 0 {
sess.WriteLine("\nYou've finished fletching.")
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
}
if !g.canContinueProduction(p, recipe) {
sess.WriteLine("\nYou've run out of fletching materials.")
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
return
}
diff --git a/internal/game/action_gather.go b/internal/game/action_gather.go
index e169beb..9b47de2 100644
--- a/internal/game/action_gather.go
+++ b/internal/game/action_gather.go
@@ -53,42 +53,11 @@ func (g *Game) startGather(sess *net.Session, p *player.Player, obj *object.Obje
}
wait := cfg.BaseWait
+ var toolName string
if len(cfg.Tools) > 0 {
- var toolSpeed float64 = -1
- if itemID, ok := p.Equipment[object.SlotMainHand]; ok {
- def, err := g.ItemStore.Load(itemID)
- if err == nil {
- for _, t := range cfg.Tools {
- if def.ToolType == t {
- toolSpeed = def.ToolSpeed
- break
- }
- }
- }
- }
- if toolSpeed < 0 {
- for i := 0; i < 28; i++ {
- slot := p.InvSlot(i)
- if slot == nil {
- continue
- }
- def, err := g.ItemStore.Load(slot.ItemID)
- if err != nil {
- continue
- }
- for _, t := range cfg.Tools {
- if def.ToolType == t {
- toolSpeed = def.ToolSpeed
- break
- }
- }
- if toolSpeed >= 0 {
- break
- }
- }
- }
- if toolSpeed < 0 {
+ toolSpeed, name, found := g.findTool(p, cfg.Tools)
+ if !found {
names := make([]string, len(cfg.Tools))
for i, t := range cfg.Tools {
names[i] = strings.ReplaceAll(t, "_", " ")
@@ -97,6 +66,7 @@ func (g *Game) startGather(sess *net.Session, p *player.Player, obj *object.Obje
sess.WriteLine(fmt.Sprintf("You need a %s to do that.", toolList))
return
}
+ toolName = name
wait = cfg.BaseWait - toolSpeed
if wait < 1 {
wait = 1
@@ -118,38 +88,6 @@ func (g *Game) startGather(sess *net.Session, p *player.Player, obj *object.Obje
sess.WriteLine("Your inventory is too full!")
return
}
-
- toolName := ""
- if itemID, ok := p.Equipment[object.SlotMainHand]; ok {
- if def, err := g.ItemStore.Load(itemID); err == nil {
- for _, t := range cfg.Tools {
- if def.ToolType == t {
- toolName = def.Name
- break
- }
- }
- }
- }
- if toolName == "" {
- for _, slot := range p.Inventory {
- if slot == nil || slot.Quantity <= 0 {
- continue
- }
- def, err := g.ItemStore.Load(slot.ItemID)
- if err != nil {
- continue
- }
- for _, t := range cfg.Tools {
- if def.ToolType == t {
- toolName = def.Name
- break
- }
- }
- if toolName != "" {
- break
- }
- }
- }
verb := cfg.Skill
switch cfg.Skill {
case "woodcutting":
@@ -157,13 +95,7 @@ func (g *Game) startGather(sess *net.Session, p *player.Player, obj *object.Obje
}
p.ActionState = &ActionState{Type: ActionGathering, TargetName: obj.Name, ToolName: toolName, Verb: verb}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts %s the %s.", p.Name, verb, obj.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s starts %s the %s.", p.Name, verb, obj.Name)
data := map[string]any{
"obj_def_id": obj.ID,
diff --git a/internal/game/action_search.go b/internal/game/action_search.go
index d7dabe0..5cb8644 100644
--- a/internal/game/action_search.go
+++ b/internal/game/action_search.go
@@ -35,13 +35,7 @@ func (g *Game) startSearch(sess *net.Session, p *player.Player, itemID string, s
p.ActionState = &ActionState{Type: ActionSearching, TargetName: def.Name}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s searches a %s.", p.Name, def.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s searches a %s.", p.Name, def.Name)
}
func (g *Game) advanceSearch(sess *net.Session, p *player.Player) {
diff --git a/internal/game/action_steal.go b/internal/game/action_steal.go
index 3510ce7..a95be25 100644
--- a/internal/game/action_steal.go
+++ b/internal/game/action_steal.go
@@ -259,13 +259,7 @@ 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}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s glances around the room.", p.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s glances around the room.", p.Name)
p.Action = &action.Action{
Type: "steal",
diff --git a/internal/game/action_use.go b/internal/game/action_use.go
index 368162b..a3858a9 100644
--- a/internal/game/action_use.go
+++ b/internal/game/action_use.go
@@ -36,13 +36,7 @@ func (g *Game) startUse(sess *net.Session, p *player.Player, obj *object.ObjectD
p.ActionState = &ActionState{Type: ActionUsing, TargetName: obj.Name}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s uses the %s.", p.Name, obj.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s uses the %s.", p.Name, obj.Name)
p.Action = &action.Action{
Type: "use",
diff --git a/internal/game/cmd_agility.go b/internal/game/cmd_agility.go
index 084c5cf..e347322 100644
--- a/internal/game/cmd_agility.go
+++ b/internal/game/cmd_agility.go
@@ -31,7 +31,7 @@ func (g *Game) doObstacle(sess *net.Session, verb string) {
if p.Action != nil {
g.cancelAction(p)
}
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
g.startObstacle(sess, p, info)
}
diff --git a/internal/game/cmd_attack.go b/internal/game/cmd_attack.go
index f9cfba2..89cde46 100644
--- a/internal/game/cmd_attack.go
+++ b/internal/game/cmd_attack.go
@@ -126,7 +126,7 @@ func (g *Game) findMob(sess *net.Session, input string, roomID int) *world.MobIn
func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobInstance) {
g.cancelRest(p.Name)
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
combat.EnterCombat(p.Name, mob.InstanceID)
p.AttackTimer = 0
@@ -162,13 +162,7 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn
}
p.ActionState = &ActionState{Type: ActionCombating, TargetName: mob.Name}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s attacks %s!", p.Name, mobDisplayName(mob, true))))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s attacks %s!", p.Name, mobDisplayName(mob, true))
g.Ticks.Subscribe(1, func() bool {
cs := combat.GetCombat(p.Name)
@@ -567,7 +561,7 @@ func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInst
}
if mob.Drops.Remains != "" {
- g.World.AddReservedGroundItem(p.RoomID, mob.Drops.Remains, 1, p.Name)
+ g.World.AddReservedItem(p.RoomID, mob.Drops.Remains, 1, p.Name)
def, _ := g.ItemStore.Load(mob.Drops.Remains)
name := mob.Drops.Remains
if def != nil {
@@ -588,7 +582,7 @@ func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInst
if qty <= 0 {
qty = 1
}
- g.World.AddReservedGroundItem(p.RoomID, entry.ItemID, qty, p.Name)
+ g.World.AddReservedItem(p.RoomID, entry.ItemID, qty, p.Name)
def, _ := g.ItemStore.Load(entry.ItemID)
name := entry.ItemID
if def != nil {
diff --git a/internal/game/cmd_clean.go b/internal/game/cmd_clean.go
index 47896bb..951b41d 100644
--- a/internal/game/cmd_clean.go
+++ b/internal/game/cmd_clean.go
@@ -1,7 +1,6 @@
package game
import (
- "fmt"
"strings"
"thehouseoficarus/internal/action"
@@ -54,7 +53,7 @@ func (g *Game) doClean(sess *net.Session, input string) {
return
}
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
p.BackgroundAction = &action.Action{
Type: "clean",
@@ -67,13 +66,7 @@ func (g *Game) doClean(sess *net.Session, input string) {
}
p.BackgroundActionState = &ActionState{Type: ActionCleaning}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts cleaning herbs.", p.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s starts cleaning herbs.", p.Name)
sess.WriteLine("\nYou begin cleaning herbs.")
}
diff --git a/internal/game/cmd_consume.go b/internal/game/cmd_consume.go
index 0a7d335..3782237 100644
--- a/internal/game/cmd_consume.go
+++ b/internal/game/cmd_consume.go
@@ -283,11 +283,5 @@ func (g *Game) applyPotion(sess *net.Session, p *player.Player, itemID string, d
p.ConsumeCooldown = 3
p.ActionState = &ActionState{Type: ActionEating}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s drinks a %s.", p.Name, def.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s drinks a %s.", p.Name, def.Name)
}
diff --git a/internal/game/cmd_cook.go b/internal/game/cmd_cook.go
index 288afb0..04c98bb 100644
--- a/internal/game/cmd_cook.go
+++ b/internal/game/cmd_cook.go
@@ -61,28 +61,13 @@ func (g *Game) doCook(sess *net.Session, input string) {
}
}
- if len(recipes) == 0 {
- sess.WriteLine("You can't cook that.")
- return
- }
-
- if len(recipes) == 1 {
- g.promptHowMany(sess, recipes[0].ID)
- return
- }
-
- sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes))
- sess.State = net.StateRecipeChoice
- var names []string
- for _, r := range recipes {
- names = append(names, g.recipeName(sess, &r))
- }
- g.showMenuTable(sess, fmt.Sprintf("What would you like to cook on the %s?", stationName), names)
+ title := fmt.Sprintf("What would you like to cook on the %s?", stationName)
+ g.showRecipeChoice(sess, p, recipes, "You can't cook that.", title, "")
}
func (g *Game) showCookMenu(sess *net.Session, p *player.Player, allRecipes []action.RecipeDef, stationDefID, stationName string) {
seen := make(map[string]bool)
- var entries []recipeEntry
+ var recipes []action.RecipeDef
for _, r := range allRecipes {
if r.Type != "cooking" {
@@ -98,41 +83,9 @@ func (g *Game) showCookMenu(sess *net.Session, p *player.Player, allRecipes []ac
continue
}
seen[r.ID] = true
- entries = append(entries, recipeEntry{g.recipeName(sess, &r), r})
- }
-
- if len(entries) == 0 {
- sess.WriteLine("You don't have anything you can cook.")
- return
+ recipes = append(recipes, r)
}
- if len(entries) == 1 {
- if p.OptionBool("cook_all") {
- g.startProductionFromRecipe(sess, p, &entries[0].Recipe, 0)
- return
- }
- g.promptHowMany(sess, entries[0].Recipe.ID)
- return
- }
-
- sess.State = net.StateRecipeChoice
- var names []string
- for _, e := range entries {
- names = append(names, e.ItemName)
- }
- g.showMenuTable(sess, fmt.Sprintf("What would you like to cook on the %s?", stationName), names)
- ids := make([]string, len(entries))
- for i, e := range entries {
- ids[i] = e.Recipe.ID
- }
- sess.PendingMenu = recipeMenuData(ids)
-}
-
-func (g *Game) recipeName(sess *net.Session, r *action.RecipeDef) string {
- if r.Output != "" {
- if def, err := g.ItemStore.Load(r.Output); err == nil {
- return g.itemColorize(sess, def, def.Name)
- }
- }
- return r.DisplayName()
+ title := fmt.Sprintf("What would you like to cook on the %s?", stationName)
+ g.showRecipeChoice(sess, p, recipes, "You don't have anything you can cook.", title, "cook_all")
}
diff --git a/internal/game/cmd_craft.go b/internal/game/cmd_craft.go
index 447d980..d061a9c 100644
--- a/internal/game/cmd_craft.go
+++ b/internal/game/cmd_craft.go
@@ -17,14 +17,14 @@ func (g *Game) executeConstruct(sess *net.Session, args []string, rawInput strin
}
func (g *Game) doCraft(sess *net.Session, input string) {
- g.doGenericStationSkill(sess, input, "crafting", player.Crafting, "last_craft", "Crafting", "craft", "Craft")
+ g.doStationSkill(sess, input, "crafting", player.Crafting, "last_craft", "Crafting", "craft", "Craft")
}
func (g *Game) doConstruct(sess *net.Session, input string) {
- g.doGenericStationSkill(sess, input, "construction", player.Construction, "last_construct", "Construction", "construct", "Construct")
+ g.doStationSkill(sess, input, "construction", player.Construction, "last_construct", "Construction", "construct", "Construct")
}
-func (g *Game) doGenericStationSkill(sess *net.Session, input string, recipeType string, skill player.SkillName, flagKey, label, verbPast, verbCap string) {
+func (g *Game) doStationSkill(sess *net.Session, input string, recipeType string, skill player.SkillName, flagKey, label, verbPast, verbCap string) {
p := sess.Player
g.cancelAction(p)
@@ -39,14 +39,14 @@ func (g *Game) doGenericStationSkill(sess *net.Session, input string, recipeType
if r.Type != recipeType {
continue
}
- if !g.genericRecipeVisible(p, &r) {
+ if !g.recipeVisible(p, &r) {
continue
}
recipes = append(recipes, r)
}
if input != "" {
- g.doGenericWithInput(sess, p, recipes, input, skill, flagKey, label, verbCap)
+ g.doWithInput(sess, p, recipes, input, skill, flagKey, label, verbCap)
return
}
@@ -55,8 +55,8 @@ func (g *Game) doGenericStationSkill(sess *net.Session, input string, recipeType
for i := range recipes {
if recipes[i].ID == lastRecipeID {
r := &recipes[i]
- if g.canDoGenericRecipe(p, r, skill) {
- g.startGenericRecipe(sess, p, r, 0, flagKey)
+ if g.canDoRecipe(p, r, skill) {
+ g.startRecipe(sess, p, r, 0, flagKey)
return
}
break
@@ -64,7 +64,7 @@ func (g *Game) doGenericStationSkill(sess *net.Session, input string, recipeType
}
}
- available := g.availableGenericRecipes(p, recipes)
+ available := g.availableRecipes(p, recipes)
if len(available) == 0 {
sess.WriteLine("You don't have any materials to " + verbPast + ".")
return
@@ -72,14 +72,14 @@ func (g *Game) doGenericStationSkill(sess *net.Session, input string, recipeType
optionKey := verbPast + "_all"
if p.OptionBool(optionKey) && len(available) == 1 {
- g.startGenericRecipe(sess, p, &available[0], 0, flagKey)
+ g.startRecipe(sess, p, &available[0], 0, flagKey)
return
}
g.showProductionTable(sess, p, available, label, recipeType, flagKey, verbCap, false)
}
-func (g *Game) doGenericWithInput(sess *net.Session, p *player.Player, recipes []action.RecipeDef, input string, skill player.SkillName, flagKey, label, verbCap string) {
+func (g *Game) doWithInput(sess *net.Session, p *player.Player, recipes []action.RecipeDef, input string, skill player.SkillName, flagKey, label, verbCap string) {
qty, productName := parseQty(input)
productName = strings.TrimSpace(productName)
@@ -102,7 +102,7 @@ func (g *Game) doGenericWithInput(sess *net.Session, p *player.Player, recipes [
var available []action.RecipeDef
for _, r := range matched {
- if g.canDoGenericRecipe(p, &r, skill) {
+ if g.canDoRecipe(p, &r, skill) {
available = append(available, r)
}
}
@@ -113,14 +113,14 @@ func (g *Game) doGenericWithInput(sess *net.Session, p *player.Player, recipes [
}
if len(available) == 1 {
- g.startGenericRecipe(sess, p, &available[0], qty, flagKey)
+ g.startRecipe(sess, p, &available[0], qty, flagKey)
return
}
g.showProductionTable(sess, p, available, label, label, flagKey, verbCap, false)
}
-func (g *Game) genericRecipeVisible(p *player.Player, r *action.RecipeDef) bool {
+func (g *Game) recipeVisible(p *player.Player, r *action.RecipeDef) bool {
if len(r.Station) > 0 {
stID, _ := g.findStation(p.RoomID, r.Station)
if stID == "" {
@@ -133,7 +133,7 @@ func (g *Game) genericRecipeVisible(p *player.Player, r *action.RecipeDef) bool
return true
}
-func (g *Game) canDoGenericRecipe(p *player.Player, r *action.RecipeDef, skill player.SkillName) bool {
+func (g *Game) canDoRecipe(p *player.Player, r *action.RecipeDef, skill player.SkillName) bool {
if p.Level(skill) < r.Level {
return false
}
@@ -152,7 +152,7 @@ func (g *Game) canDoGenericRecipe(p *player.Player, r *action.RecipeDef, skill p
return true
}
-func (g *Game) availableGenericRecipes(p *player.Player, allRecipes []action.RecipeDef) []action.RecipeDef {
+func (g *Game) availableRecipes(p *player.Player, allRecipes []action.RecipeDef) []action.RecipeDef {
var result []action.RecipeDef
for _, r := range allRecipes {
if r.HasAllItemsQty(p.CountItem) {
@@ -162,7 +162,7 @@ func (g *Game) availableGenericRecipes(p *player.Player, allRecipes []action.Rec
return result
}
-func (g *Game) startGenericRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int, flagKey string) {
+func (g *Game) startRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int, flagKey string) {
p.EnsureFlags()
p.Flags[flagKey] = recipe.ID
g.AccountStore.SaveCharacter(p)
@@ -170,7 +170,7 @@ func (g *Game) startGenericRecipe(sess *net.Session, p *player.Player, recipe *a
g.startProductionFromRecipe(sess, p, recipe, count)
}
-func (g *Game) findCraftRecipesForItems(p *player.Player, itemAID, itemBID string) []action.RecipeDef {
+func (g *Game) findCraftRecipes(p *player.Player, itemAID, itemBID string) []action.RecipeDef {
allRecipes, err := g.RecipeStore.LoadAll()
if err != nil {
return nil
diff --git a/internal/game/cmd_description.go b/internal/game/cmd_description.go
index 5d0c5c1..1fc24ae 100644
--- a/internal/game/cmd_description.go
+++ b/internal/game/cmd_description.go
@@ -20,10 +20,10 @@ func (g *Game) doDescription(sess *net.Session) {
}
sess.WriteLine("")
sess.Write("Enter a new description (or press enter to keep current): ")
- sess.State = net.StateChangeDescription
+ sess.State = net.StateChangeDesc
}
-func (g *Game) handleDescriptionChange(sess *net.Session, input string) {
+func (g *Game) handleDescChange(sess *net.Session, input string) {
if input != "" {
p := sess.Player
p.Description = input
diff --git a/internal/game/cmd_drop.go b/internal/game/cmd_drop.go
index 551b014..ca3c244 100644
--- a/internal/game/cmd_drop.go
+++ b/internal/game/cmd_drop.go
@@ -194,7 +194,7 @@ func (g *Game) executeDrop(sess *net.Session, args []string, rawInput string) {
}
}
-func (g *Game) handleDropAllConfirm(sess *net.Session, input string) {
+func (g *Game) handleDropAll(sess *net.Session, input string) {
p := sess.Player
if p == nil {
sess.State = net.StateGame
diff --git a/internal/game/cmd_fletch.go b/internal/game/cmd_fletch.go
index e218dca..5a4bc19 100644
--- a/internal/game/cmd_fletch.go
+++ b/internal/game/cmd_fletch.go
@@ -184,7 +184,7 @@ func (g *Game) availableFletchRecipes(p *player.Player, allFletch []action.Recip
return result
}
-func (g *Game) findFletchRecipesForItems(p *player.Player, itemAID, itemBID string) []action.RecipeDef {
+func (g *Game) findFletchRecipes(p *player.Player, itemAID, itemBID string) []action.RecipeDef {
allRecipes, err := g.RecipeStore.LoadAll()
if err != nil {
return nil
diff --git a/internal/game/cmd_get.go b/internal/game/cmd_get.go
index f3485fe..30bc8c2 100644
--- a/internal/game/cmd_get.go
+++ b/internal/game/cmd_get.go
@@ -77,7 +77,7 @@ func (g *Game) doGet(sess *net.Session, input string) {
for i := 0; i < 28; i++ {
slot := p.InvSlot(i)
if slot != nil && slot.ItemID == itemID {
- if _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name); !ok {
+ if _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, qty, p.Name); !ok {
sess.WriteLine("That's not yours!")
return
}
@@ -92,7 +92,7 @@ func (g *Game) doGet(sess *net.Session, input string) {
sess.WriteLine("Your inventory is full.")
return
}
- if _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name); !ok {
+ if _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, qty, p.Name); !ok {
sess.WriteLine("That's not yours!")
return
}
@@ -112,7 +112,7 @@ func (g *Game) doGet(sess *net.Session, input string) {
if fs == -1 {
break
}
- if _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 1, p.Name); !ok {
+ if _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, 1, p.Name); !ok {
break
}
p.SetInvSlot(fs, &player.InventorySlot{ItemID: itemID, Quantity: 1})
@@ -193,7 +193,7 @@ func (g *Game) doGetAllNamed(sess *net.Session, input string) {
for i := 0; i < 28; i++ {
slot := p.InvSlot(i)
if slot != nil && slot.ItemID == itemID {
- removed, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, wanted, p.Name)
+ removed, ok := g.World.RemoveReservedItem(p.RoomID, itemID, wanted, p.Name)
if !ok {
sess.WriteLine("That's not yours!")
return
@@ -209,7 +209,7 @@ func (g *Game) doGetAllNamed(sess *net.Session, input string) {
sess.WriteLine("Your inventory is full.")
return
}
- removed, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, wanted, p.Name)
+ removed, ok := g.World.RemoveReservedItem(p.RoomID, itemID, wanted, p.Name)
if !ok {
sess.WriteLine("That's not yours!")
return
@@ -230,7 +230,7 @@ func (g *Game) doGetAllNamed(sess *net.Session, input string) {
if fs == -1 {
break
}
- _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 1, p.Name)
+ _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, 1, p.Name)
if !ok {
break
}
@@ -266,7 +266,7 @@ func (g *Game) doGetAll(sess *net.Session) {
continue
}
if itemID == "credits" {
- taken, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 999999, p.Name)
+ taken, ok := g.World.RemoveReservedItem(p.RoomID, itemID, 999999, p.Name)
if !ok {
continue
}
@@ -286,7 +286,7 @@ func (g *Game) doGetAll(sess *net.Session) {
for i := 0; i < 28; i++ {
slot := p.InvSlot(i)
if slot != nil && slot.ItemID == itemID {
- _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name)
+ _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, qty, p.Name)
if !ok {
qty = 0
stacked = true
@@ -313,7 +313,7 @@ func (g *Game) doGetAll(sess *net.Session) {
g.AccountStore.SaveCharacter(p)
return
}
- _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name)
+ _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, qty, p.Name)
if !ok {
break
}
@@ -339,7 +339,7 @@ func (g *Game) doGetAll(sess *net.Session) {
}
take := 1
- _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, take, p.Name)
+ _, ok := g.World.RemoveReservedItem(p.RoomID, itemID, take, p.Name)
if !ok {
break
}
@@ -364,7 +364,7 @@ func (g *Game) doGetAll(sess *net.Session) {
}
func (g *Game) pickupCredits(sess *net.Session, p *player.Player, itemID string) {
- qty, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 999999, p.Name)
+ qty, ok := g.World.RemoveReservedItem(p.RoomID, itemID, 999999, p.Name)
if !ok {
sess.WriteLine("That's not yours!")
return
diff --git a/internal/game/cmd_jack.go b/internal/game/cmd_jack.go
index 16f8b2a..f33ea85 100644
--- a/internal/game/cmd_jack.go
+++ b/internal/game/cmd_jack.go
@@ -52,7 +52,7 @@ func (g *Game) doJack(sess *net.Session, target string) {
}
g.cancelAction(p)
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
minigame := tDef.Minigame()
display := minigame.Init(hackLevel)
@@ -68,13 +68,7 @@ func (g *Game) doJack(sess *net.Session, target string) {
p.ActionState = &ActionState{Type: ActionHacking, TargetName: tDef.Name}
sess.State = net.StateHacking
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess {
- other.WriteLine(fmt.Sprintf("\n%s jacks into a terminal.", p.Name))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s jacks into a terminal.", p.Name)
sess.WriteLine(display)
sess.Write("\nhack> ")
diff --git a/internal/game/cmd_look.go b/internal/game/cmd_look.go
index 6913333..505f7a6 100644
--- a/internal/game/cmd_look.go
+++ b/internal/game/cmd_look.go
@@ -48,7 +48,7 @@ func (g *Game) showRoomDescription(sess *net.Session, p *player.Player, room *wo
roomDescSpec := g.resolveColor(sess, "room_desc")
descLines := make([]string, len(rawLines))
for i, l := range rawLines {
- descLines[i] = color.ExpandTagsWithDefault(mode, roomDescSpec, l)
+ descLines[i] = color.ExpandTagsDefault(mode, roomDescSpec, l)
}
wroteDesc := false
if p.OptionString("tiny_map") != "off" {
@@ -546,7 +546,7 @@ func (g *Game) doLookTarget(sess *net.Session, input string) {
}
}
- farmSuffix := g.farmLookSuffixForObj(p, st.DefID, st.Index)
+ farmSuffix := g.farmObjSuffix(p, st.DefID, st.Index)
if farmSuffix != "" {
sess.WriteLine(farmSuffix)
}
diff --git a/internal/game/cmd_mix.go b/internal/game/cmd_mix.go
index 7bf1f7b..337bb18 100644
--- a/internal/game/cmd_mix.go
+++ b/internal/game/cmd_mix.go
@@ -3,7 +3,6 @@ package game
import (
"strings"
- "thehouseoficarus/internal/action"
"thehouseoficarus/internal/net"
"thehouseoficarus/internal/player"
)
@@ -13,110 +12,5 @@ func (g *Game) executeMix(sess *net.Session, args []string, rawInput string) {
}
func (g *Game) doMix(sess *net.Session, input string) {
- p := sess.Player
- g.cancelAction(p)
-
- allRecipes, err := g.RecipeStore.LoadAll()
- if err != nil {
- sess.WriteLine("Error loading recipes.")
- return
- }
-
- if input == "" {
- g.showMixMenu(sess, p, allRecipes)
- return
- }
-
- qty, itemName := parseQty(input)
- _ = qty
-
- var matched []action.RecipeDef
- for _, r := range allRecipes {
- if r.Type != "pharmacy" {
- continue
- }
- outDef, _ := g.ItemStore.Load(r.Output)
- name := r.Output
- if outDef != nil {
- name = outDef.Name
- }
- if action.WordPrefixMatch(itemName, name) {
- matched = append(matched, r)
- }
- }
-
- if len(matched) == 0 {
- sess.WriteLine("You can't mix that.")
- return
- }
-
- var available []action.RecipeDef
- for _, r := range matched {
- if r.HasAllItems(p.HasItem) && p.Level(player.Pharmacy) >= r.Level {
- available = append(available, r)
- }
- }
-
- if len(available) == 0 {
- sess.WriteLine("You don't have the materials for that.")
- return
- }
-
- if len(available) == 1 {
- g.promptHowMany(sess, available[0].ID)
- return
- }
-
- sess.State = net.StateRecipeChoice
- var names []string
- for _, r := range available {
- names = append(names, g.recipeName(sess, &r))
- }
- g.showMenuTable(sess, "What would you like to mix?", names)
- sess.PendingMenu = recipeMenuData(recipeDefIDs(available))
-}
-
-func (g *Game) showMixMenu(sess *net.Session, p *player.Player, allRecipes []action.RecipeDef) {
- seen := make(map[string]bool)
- var entries []recipeEntry
-
- for _, r := range allRecipes {
- if r.Type != "pharmacy" {
- continue
- }
- if seen[r.ID] {
- continue
- }
- if !r.HasAllItems(p.HasItem) {
- continue
- }
- seen[r.ID] = true
- entries = append(entries, recipeEntry{g.recipeName(sess, &r), r})
- }
-
- if len(entries) == 0 {
- sess.WriteLine("You don't have anything you can mix.")
- return
- }
-
- if len(entries) == 1 {
- if p.OptionBool("mix_all") {
- g.startProductionFromRecipe(sess, p, &entries[0].Recipe, 0)
- return
- }
- g.promptHowMany(sess, entries[0].Recipe.ID)
- return
- }
-
- sess.State = net.StateRecipeChoice
- var names []string
- for _, e := range entries {
- names = append(names, e.ItemName)
- }
- g.showMenuTable(sess, "What would you like to mix?", names)
- ids := make([]string, len(entries))
- for i, e := range entries {
- ids[i] = e.Recipe.ID
- }
- sess.PendingMenu = recipeMenuData(ids)
+ g.doStationSkill(sess, input, "pharmacy", player.Pharmacy, "last_mix", "Mixing", "mix", "Mix")
}
diff --git a/internal/game/cmd_quit.go b/internal/game/cmd_quit.go
index 46403f4..187d766 100644
--- a/internal/game/cmd_quit.go
+++ b/internal/game/cmd_quit.go
@@ -1,8 +1,6 @@
package game
import (
- "fmt"
-
"thehouseoficarus/internal/combat"
"thehouseoficarus/internal/engine"
"thehouseoficarus/internal/net"
@@ -24,13 +22,7 @@ func (g *Game) doQuit(sess *net.Session) {
p.ActionState = &ActionState{Type: ActionResting}
g.cancelRest(p.Name)
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s sits down to rest.", p.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s sits down to rest.", p.Name)
ticksLeft := 10
id := g.Ticks.Subscribe(engine.ToTicks(1), func() bool {
diff --git a/internal/game/cmd_registry.go b/internal/game/cmd_registry.go
index c4f7700..ea741d9 100644
--- a/internal/game/cmd_registry.go
+++ b/internal/game/cmd_registry.go
@@ -149,7 +149,7 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
switch a {
case "gather":
if len(args) == 0 {
- target := g.resolveDefaultTarget(p.RoomID, cmd)
+ target := g.defaultTarget(p.RoomID, cmd)
if target == "" {
sess.WriteLine(fmt.Sprintf("%s what?", cmd))
return
@@ -176,7 +176,7 @@ func (g *Game) executeGather(sess *net.Session, args []string, rawInput string)
p := sess.Player
g.cancelAction(p)
if len(args) == 0 {
- target := g.resolveDefaultTarget(p.RoomID, verb)
+ target := g.defaultTarget(p.RoomID, verb)
if target == "" {
sess.WriteLine(fmt.Sprintf("%s what?", verb))
return
diff --git a/internal/game/cmd_smelt.go b/internal/game/cmd_smelt.go
index a72cf53..f1ff4e2 100644
--- a/internal/game/cmd_smelt.go
+++ b/internal/game/cmd_smelt.go
@@ -53,69 +53,29 @@ func (g *Game) doSmelt(sess *net.Session, input string) {
if r.Type != "smelting" || !stationMatch(stationDefID, r.Station) || !r.MatchesEntry(itemID) {
continue
}
- if !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.EffectiveSkill())) < r.Level {
+ if !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.EffectiveSkill())) < r.Level {
continue
}
recipes = append(recipes, r)
}
- if len(recipes) == 0 {
- sess.WriteLine("You can't smelt that.")
- return
- }
-
- if len(recipes) == 1 {
- g.promptHowMany(sess, recipes[0].ID)
- return
- }
-
- sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes))
- sess.State = net.StateRecipeChoice
- var names []string
- for _, r := range recipes {
- names = append(names, g.recipeName(sess, &r))
- }
- g.showMenuTable(sess, "What would you like to smelt?", names)
+ g.showRecipeChoice(sess, p, recipes, "You can't smelt that.", "What would you like to smelt?", "")
}
func (g *Game) showSmeltMenu(sess *net.Session, p *player.Player, allRecipes []action.RecipeDef, stationDefID, stationName string) {
seen := make(map[string]bool)
- var entries []recipeEntry
+ var recipes []action.RecipeDef
for _, r := range allRecipes {
if r.Type != "smelting" || !stationMatch(stationDefID, r.Station) {
continue
}
- if seen[r.ID] || !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.EffectiveSkill())) < r.Level {
+ if seen[r.ID] || !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.EffectiveSkill())) < r.Level {
continue
}
seen[r.ID] = true
- entries = append(entries, recipeEntry{g.recipeName(sess, &r), r})
- }
-
- if len(entries) == 0 {
- sess.WriteLine("You don't have anything you can smelt.")
- return
- }
-
- if len(entries) == 1 {
- if p.OptionBool("smelt_all") {
- g.startProductionFromRecipe(sess, p, &entries[0].Recipe, 0)
- return
- }
- g.promptHowMany(sess, entries[0].Recipe.ID)
- return
+ recipes = append(recipes, r)
}
- sess.State = net.StateRecipeChoice
- var names []string
- for _, e := range entries {
- names = append(names, e.ItemName)
- }
- g.showMenuTable(sess, "What would you like to smelt?", names)
- ids := make([]string, len(entries))
- for i, e := range entries {
- ids[i] = e.Recipe.ID
- }
- sess.PendingMenu = recipeMenuData(ids)
+ g.showRecipeChoice(sess, p, recipes, "You don't have anything you can smelt.", "What would you like to smelt?", "smelt_all")
}
diff --git a/internal/game/cmd_smith.go b/internal/game/cmd_smith.go
index a2eaad7..c7a32cd 100644
--- a/internal/game/cmd_smith.go
+++ b/internal/game/cmd_smith.go
@@ -63,7 +63,7 @@ func (g *Game) doSmith(sess *net.Session, input string) {
if len(barTypes) == 1 {
if p.OptionBool("smith_all") {
- if recipe := g.findSingleSmithRecipe(p, barTypes[0], allRecipes); recipe != nil {
+ if recipe := g.findSmithRecipe(p, barTypes[0], allRecipes); recipe != nil {
g.startProductionFromRecipe(sess, p, recipe, 0)
return
}
@@ -148,7 +148,7 @@ func barMenuData(barIDs []string) []map[string]string {
return out
}
-func (g *Game) findSingleSmithRecipe(p *player.Player, barID string, allRecipes []action.RecipeDef) *action.RecipeDef {
+func (g *Game) findSmithRecipe(p *player.Player, barID string, allRecipes []action.RecipeDef) *action.RecipeDef {
var makeable []*action.RecipeDef
skillLevel := p.Level(player.Smithing)
for i, r := range allRecipes {
diff --git a/internal/game/cmd_trigger_combat.go b/internal/game/cmd_trigger_combat.go
index 62c5083..444f80d 100644
--- a/internal/game/cmd_trigger_combat.go
+++ b/internal/game/cmd_trigger_combat.go
@@ -23,7 +23,7 @@ func (g *Game) scienceAttack(sess *net.Session, p *player.Player, mob *world.Mob
g.consumeJunkCost(p, mod)
- equipSciBonus := g.totalEquipScienceAttack(p)
+ equipSciBonus := g.totalScienceAttack(p)
attRoll := (p.Level(player.Science) + g.buffLevelBonus(p, "science") + 8) * (equipSciBonus + 64)
mobSciDef := mob.ScienceDefense
diff --git a/internal/game/cmd_trigger_enchant.go b/internal/game/cmd_trigger_enchant.go
index 535616b..a1a6950 100644
--- a/internal/game/cmd_trigger_enchant.go
+++ b/internal/game/cmd_trigger_enchant.go
@@ -41,13 +41,9 @@ func (g *Game) triggerEnchant(sess *net.Session, p *player.Player, mod *ModDef,
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
inv.ItemID = outputID
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0)
outputDef, _ := g.ItemStore.Load(outputID)
outputName := outputID
@@ -61,9 +57,6 @@ func (g *Game) triggerEnchant(sess *net.Session, p *player.Player, mod *ModDef,
}
sess.WriteLine(fmt.Sprintf("You enchant the %s and it becomes a %s!", inputName, outputName))
- if p.OptionBool("xp_drops") {
- sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
- }
}
func (g *Game) triggerChipBolts(sess *net.Session, p *player.Player, mod *ModDef, chip chipEntry) {
@@ -82,8 +75,6 @@ func (g *Game) triggerChipBolts(sess *net.Session, p *player.Player, mod *ModDef
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
p.RemoveItem(chip.Input, chip.Qty)
placed := false
for i := 0; i < 28; i++ {
@@ -99,9 +90,7 @@ func (g *Game) triggerChipBolts(sess *net.Session, p *player.Player, mod *ModDef
p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: chip.Output, Quantity: chip.Qty})
}
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0)
inputDef, _ := g.ItemStore.Load(chip.Input)
name := chip.Input
@@ -110,7 +99,4 @@ func (g *Game) triggerChipBolts(sess *net.Session, p *player.Player, mod *ModDef
}
sess.WriteLine(fmt.Sprintf("You chip %d %s with arcane circuitry.", chip.Qty, name))
- if p.OptionBool("xp_drops") {
- sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
- }
}
diff --git a/internal/game/cmd_trigger_transport.go b/internal/game/cmd_trigger_transport.go
index 2ca8db2..2354c27 100644
--- a/internal/game/cmd_trigger_transport.go
+++ b/internal/game/cmd_trigger_transport.go
@@ -18,14 +18,7 @@ func (g *Game) triggerTransport(sess *net.Session, p *player.Player, mod *ModDef
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
- if p.OptionBool("xp_drops") {
- sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
- }
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0)
if g.Hub != nil {
for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
diff --git a/internal/game/cmd_trigger_utility.go b/internal/game/cmd_trigger_utility.go
index efb23e7..ce59975 100644
--- a/internal/game/cmd_trigger_utility.go
+++ b/internal/game/cmd_trigger_utility.go
@@ -14,7 +14,7 @@ func (g *Game) triggerUtility(sess *net.Session, p *player.Player, mod *ModDef,
case "low_process", "high_process":
g.triggerProcessing(sess, p, mod, targetArg)
case "bones_to_nutrients":
- g.triggerBonesToNutrients(sess, p, mod)
+ g.triggerBonesToNuts(sess, p, mod)
case "em_grab":
g.triggerEmGrab(sess, p, mod, targetArg)
case "superheat":
@@ -51,8 +51,6 @@ func (g *Game) triggerProcessing(sess *net.Session, p *player.Player, mod *ModDe
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
creditValue := itemDef.Value
if mod.ID == "low_process" {
creditValue = itemDef.Value / 2
@@ -69,19 +67,13 @@ func (g *Game) triggerProcessing(sess *net.Session, p *player.Player, mod *ModDe
p.Credits += creditValue
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0)
sess.WriteLine(fmt.Sprintf("You process the %s. You receive %s credits.",
itemDef.Name, g.colorize(sess, "credits_pickup", fmt.Sprint(creditValue))))
-
- if p.OptionBool("xp_drops") {
- sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
- }
}
-func (g *Game) triggerBonesToNutrients(sess *net.Session, p *player.Player, mod *ModDef) {
+func (g *Game) triggerBonesToNuts(sess *net.Session, p *player.Player, mod *ModDef) {
if combat.GetCombat(p.Name) != nil {
sess.WriteLine("You can't do that during combat!")
return
@@ -97,8 +89,6 @@ func (g *Game) triggerBonesToNutrients(sess *net.Session, p *player.Player, mod
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
for i := 0; i < 28; i++ {
slot := p.InvSlot(i)
if slot != nil && slot.ItemID == "bones" {
@@ -106,14 +96,9 @@ func (g *Game) triggerBonesToNutrients(sess *net.Session, p *player.Player, mod
}
}
- sciXP := mod.BaseXP * boneCount
- g.awardSkillXP(sess, p, player.Science, sciXP)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, float64(boneCount))
sess.WriteLine(fmt.Sprintf("You convert %d bones into nutrient bars.", boneCount))
- if p.OptionBool("xp_drops") {
- sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
- }
}
func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
@@ -150,8 +135,6 @@ func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, t
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
qty := groundItems[matchedID]
g.World.RemoveGroundItem(p.RoomID, matchedID, qty)
@@ -164,14 +147,9 @@ func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, t
freeSlot := p.FirstFreeSlot()
p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: matchedID, Quantity: qty})
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0)
sess.WriteLine(fmt.Sprintf("You magnetically pull the %s toward you.", name))
- if p.OptionBool("xp_drops") {
- sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
- }
}
func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
@@ -224,8 +202,6 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
for _, e := range recipe.Consume {
for _, itemID := range e.Items {
qty := e.Quantity
@@ -254,12 +230,11 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef
p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty})
}
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
+ var extraGains []xpGain
if recipe.XP > 0 {
- g.awardSkillXP(sess, p, player.SkillName(recipe.Skill), recipe.XP)
+ extraGains = []xpGain{{recipe.Skill, recipe.XP}}
}
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0, extraGains...)
outputDef, _ := g.ItemStore.Load(recipe.Output)
outputName := recipe.Output
@@ -273,13 +248,6 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef
}
sess.WriteLine(fmt.Sprintf("You superheat the %s and produce a %s.", inputName, outputName))
- if p.OptionBool("xp_drops") {
- parts := []string{fmt.Sprintf("+%dxp sci", sciXP)}
- if recipe.XP > 0 {
- parts = append(parts, fmt.Sprintf("+%dxp %s", recipe.XP, player.SkillAbbr[player.SkillName(recipe.Skill)]))
- }
- sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
- }
}
func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
@@ -320,8 +288,6 @@ func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
p.RemoveItem(inv.ItemID, 1)
p.Credits -= info.cost
@@ -332,16 +298,9 @@ func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef
}
p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1})
- sciXP := mod.BaseXP
- g.awardSkillXP(sess, p, player.Science, sciXP)
- g.awardSkillXP(sess, p, player.Construction, 10)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, 1.0, xpGain{Skill: string(player.Construction), XP: 10})
sess.WriteLine(fmt.Sprintf("You convert the log into %s.", info.name))
- if p.OptionBool("xp_drops") {
- parts := []string{fmt.Sprintf("+%dxp sci", sciXP), "+10xp con"}
- sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
- }
return
}
@@ -360,8 +319,6 @@ func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef
g.cancelAction(p)
}
- g.consumeJunkCost(p, mod)
-
p.RemoveItem(logID, qty)
p.Credits -= totalCost
@@ -376,20 +333,12 @@ func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef
processed++
}
- sciXP := mod.BaseXP * qty
- g.awardSkillXP(sess, p, player.Science, sciXP)
- conXP := 10 * qty
- g.awardSkillXP(sess, p, player.Construction, conXP)
- g.AccountStore.SaveCharacter(p)
+ g.triggerModReward(sess, p, mod, float64(qty), xpGain{Skill: string(player.Construction), XP: 10 * qty})
sess.WriteLine(fmt.Sprintf("You convert %d logs into %s for %d credits.", processed, info.name, totalCost))
if processed < qty {
sess.WriteLine(fmt.Sprintf("Your inventory is full. The remaining %d planks fall to the ground.", qty-processed))
}
- if p.OptionBool("xp_drops") {
- parts := []string{fmt.Sprintf("+%dxp sci", sciXP), fmt.Sprintf("+%dxp con", conXP)}
- sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
- }
return
}
diff --git a/internal/game/cmd_use.go b/internal/game/cmd_use.go
index 4f830a8..e653c93 100644
--- a/internal/game/cmd_use.go
+++ b/internal/game/cmd_use.go
@@ -83,7 +83,7 @@ func (g *Game) useRoomObject(sess *net.Session, p *player.Player, input string)
}
recipes := g.stationRecipes(p, objSt.DefID)
if len(recipes) > 0 {
- g.showStationRecipeMenu(sess, p, recipes, def.Name)
+ g.showRecipeMenu(sess, p, recipes, def.Name)
return true
}
bt := def.BehaviorType()
@@ -105,13 +105,7 @@ func (g *Game) useRoomObject(sess *net.Session, p *player.Player, input string)
g.applyNodeAction(sess, ui.Action)
}
p.ActionState = &ActionState{Type: ActionUsing, TargetName: def.Name}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s uses the %s.", p.Name, def.Name)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s uses the %s.", p.Name, def.Name)
return true
}
if len(def.UseInteractions) > 0 {
@@ -160,7 +154,7 @@ func (g *Game) stationRecipes(p *player.Player, stationDefID string) []action.Re
return results
}
-func (g *Game) showStationRecipeMenu(sess *net.Session, p *player.Player, recipes []action.RecipeDef, stationName string) {
+func (g *Game) showRecipeMenu(sess *net.Session, p *player.Player, recipes []action.RecipeDef, stationName string) {
if len(recipes) == 0 {
sess.WriteLine(fmt.Sprintf("You don't have anything you can make at the %s.", stationName))
return
@@ -320,8 +314,8 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName,
itemBID := matchesB[0].ID
- craftRecipes := g.findCraftRecipesForItems(p, itemAID, itemBID)
- fletchRecipes := g.findFletchRecipesForItems(p, itemAID, itemBID)
+ craftRecipes := g.findCraftRecipes(p, itemAID, itemBID)
+ fletchRecipes := g.findFletchRecipes(p, itemAID, itemBID)
if len(craftRecipes) > 0 && len(fletchRecipes) > 0 {
var menu []map[string]string
@@ -353,12 +347,12 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName,
if len(craftRecipes) > 0 {
var available []action.RecipeDef
for _, r := range craftRecipes {
- if g.canDoGenericRecipe(p, &r, player.Crafting) {
+ if g.canDoRecipe(p, &r, player.Crafting) {
available = append(available, r)
}
}
if len(available) == 1 {
- g.startGenericRecipe(sess, p, &available[0], 0, "last_craft")
+ g.startRecipe(sess, p, &available[0], 0, "last_craft")
return
}
if len(available) > 1 {
@@ -429,7 +423,7 @@ func (g *Game) findCombineResults(sess *net.Session, p *player.Player, itemAID,
}
}
}
- if aEntry >= 0 && bEntry >= 0 && aEntry != bEntry && madeFromItemsAvailable(p, def.MadeFrom) {
+ if aEntry >= 0 && bEntry >= 0 && aEntry != bEntry && madeFromAvailable(p, def.MadeFrom) {
matched = append(matched, def)
}
}
@@ -444,7 +438,7 @@ func combineMenuData(defs []*object.ItemDef) []map[string]string {
return out
}
-func madeFromItemsAvailable(p *player.Player, madeFrom []object.MadeFromEntry) bool {
+func madeFromAvailable(p *player.Player, madeFrom []object.MadeFromEntry) bool {
for _, entry := range madeFrom {
found := false
for _, id := range entry.Items {
diff --git a/internal/game/core_login_account.go b/internal/game/core_login_account.go
index 87f8c62..a2c1bd8 100644
--- a/internal/game/core_login_account.go
+++ b/internal/game/core_login_account.go
@@ -83,7 +83,7 @@ func (g *Game) handlePassword(sess *net.Session, input string) {
g.showMenu(sess)
}
-func (g *Game) handleNewAccountPass(sess *net.Session, input string) {
+func (g *Game) handleNewPass(sess *net.Session, input string) {
input = strings.TrimSpace(input)
if input == "" {
sess.Conn.SetEcho(true)
@@ -98,11 +98,11 @@ func (g *Game) handleNewAccountPass(sess *net.Session, input string) {
return
}
sess.PendingPass = input
- sess.State = net.StateNewAccountConfirm
+ sess.State = net.StateNewAccount
sess.Write("Confirm password: ")
}
-func (g *Game) handleNewAccountConfirm(sess *net.Session, input string) {
+func (g *Game) handleNewAccount(sess *net.Session, input string) {
input = strings.TrimSpace(input)
if input == "" {
sess.Conn.SetEcho(true)
diff --git a/internal/game/core_messages.go b/internal/game/core_messages.go
deleted file mode 100644
index 1c9e85a..0000000
--- a/internal/game/core_messages.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package game
-
-const (
- MsgErrLoadRecipes = "Error loading recipes."
- MsgNoCombat = "You can't do that during combat!"
- MsgNoDontHave = "You don't have any '%s'."
- MsgNeverMind = "Never mind."
- MsgSomethingWrongObject = "Something is wrong with this object."
- MsgSomethingWrongThat = "Something is wrong with that."
- MsgInventoryFull = "Your inventory is too full!"
- MsgAmbiguous = "That's ambiguous, which one?"
- MsgWhichOne = "Which one?"
-)
diff --git a/internal/game/core_production.go b/internal/game/core_production.go
index 227c4ad..59517d5 100644
--- a/internal/game/core_production.go
+++ b/internal/game/core_production.go
@@ -18,7 +18,7 @@ import (
func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *action.RecipeDef, actionType, displayVerb, startMsg, endMsg string, count int) {
g.cancelAction(p)
- g.cancelBackgroundAction(p)
+ g.cancelBgAction(p)
skill := recipe.EffectiveSkill()
if skill != "" {
@@ -65,13 +65,7 @@ func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *acti
p.ActionState = &ActionState{Type: ActionProducing, TargetName: outputName, Verb: displayVerb}
- if g.Hub != nil {
- for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
- if other != sess && other.Player != nil {
- other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts %s.", p.Name, displayVerb)))
- }
- }
- }
+ g.broadcastAction(sess, "\n%s starts %s.", p.Name, displayVerb)
}
func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) {
@@ -106,14 +100,9 @@ func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, re
g.startProduction(sess, p, recipe, actionType, displayVerb, startMsg, endMsg, count)
}
-func (g *Game) loadProductionRecipe(recipeID string) *action.RecipeDef {
- all, err := g.RecipeStore.LoadAll()
- if err == nil {
- for _, r := range all {
- if r.ID == recipeID {
- return &r
- }
- }
+func (g *Game) loadRecipe(recipeID string) *action.RecipeDef {
+ if r := g.RecipeStore.GetByID(recipeID); r != nil {
+ return r
}
if strings.HasPrefix(recipeID, "combine_") {
itemID := strings.TrimPrefix(recipeID, "combine_")
@@ -132,7 +121,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool {
endMsg, _ := p.Action.Data["end_msg"].(string)
remaining, _ := p.Action.Data["remaining"].(int)
- recipe := g.loadProductionRecipe(recipeID)
+ recipe := g.loadRecipe(recipeID)
if recipe == nil {
g.cancelAction(p)
return false
@@ -350,25 +339,19 @@ func (g *Game) handleRecipeChoice(sess *net.Session, input string) {
func (g *Game) menuEntryName(entry map[string]string) string {
if rid, ok := entry["recipe_id"]; ok {
- all, _ := g.RecipeStore.LoadAll()
- for _, r := range all {
- if r.ID == rid {
- if def, err := g.ItemStore.Load(r.Output); err == nil {
- return def.Name
- }
- return r.Output
+ if r := g.RecipeStore.GetByID(rid); r != nil {
+ if def, err := g.ItemStore.Load(r.Output); err == nil {
+ return def.Name
}
+ return r.Output
}
}
if rid, ok := entry["fletch_recipe_id"]; ok {
- all, _ := g.RecipeStore.LoadAll()
- for _, r := range all {
- if r.ID == rid {
- if def, err := g.ItemStore.Load(r.Output); err == nil {
- return def.Name
- }
- return r.Output
+ if r := g.RecipeStore.GetByID(rid); r != nil {
+ if def, err := g.ItemStore.Load(r.Output); err == nil {
+ return def.Name
}
+ return r.Output
}
}
if barID, ok := entry["bar_id"]; ok {
@@ -399,12 +382,9 @@ func (g *Game) dispatchMenuEntry(sess *net.Session, entry map[string]string) {
}
if rid, ok := entry["fletch_recipe_id"]; ok {
p := sess.Player
- allRecipes, _ := g.RecipeStore.LoadAll()
- for _, r := range allRecipes {
- if r.ID == rid {
- g.startFletchAction(sess, p, &r, 0)
- return
- }
+ if r := g.RecipeStore.GetByID(rid); r != nil {
+ g.startFletchAction(sess, p, r, 0)
+ return
}
g.reprompt(sess)
return
@@ -416,7 +396,7 @@ func (g *Game) dispatchMenuEntry(sess *net.Session, entry map[string]string) {
g.reprompt(sess)
}
-func (g *Game) formatRecipeMaterials(r *action.RecipeDef) string {
+func (g *Game) formatMaterials(r *action.RecipeDef) string {
var parts []string
for _, e := range r.Consume {
itemName := e.Items[0]
@@ -461,7 +441,7 @@ func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes
productName = fmt.Sprintf("%s x%d", productName, outputQty)
}
- matStr := g.formatRecipeMaterials(&r)
+ matStr := g.formatMaterials(&r)
levelStr := fmt.Sprint(r.Level)
numStr := fmt.Sprintf("%d", i+1)
@@ -524,20 +504,11 @@ func (g *Game) handleProductChoice(sess *net.Session, input string) {
input = strings.TrimSpace(input)
- allRecipes, err := g.RecipeStore.LoadAll()
- if err != nil {
- g.reprompt(sess)
- return
- }
-
var recipes []action.RecipeDef
for _, entry := range menuData {
rid := entry["recipe_id"]
- for _, r := range allRecipes {
- if r.ID == rid {
- recipes = append(recipes, r)
- break
- }
+ if r := g.RecipeStore.GetByID(rid); r != nil {
+ recipes = append(recipes, *r)
}
}
@@ -587,10 +558,15 @@ func (g *Game) handleProductChoice(sess *net.Session, input string) {
}
}
-func (g *Game) hasToolType(p *player.Player, toolType string) bool {
+func (g *Game) findTool(p *player.Player, toolTypes []string) (toolSpeed float64, toolName string, found bool) {
+ toolSpeed = -1
if itemID, ok := p.Equipment[object.SlotMainHand]; ok {
- if def, err := g.ItemStore.Load(itemID); err == nil && def.ToolType == toolType {
- return true
+ if def, err := g.ItemStore.Load(itemID); err == nil {
+ for _, t := range toolTypes {
+ if def.ToolType == t {
+ return def.ToolSpeed, def.Name, true
+ }
+ }
}
}
for i := 0; i < 28; i++ {
@@ -598,11 +574,22 @@ func (g *Game) hasToolType(p *player.Player, toolType string) bool {
if slot == nil {
continue
}
- if def, err := g.ItemStore.Load(slot.ItemID); err == nil && def.ToolType == toolType {
- return true
+ def, err := g.ItemStore.Load(slot.ItemID)
+ if err != nil {
+ continue
+ }
+ for _, t := range toolTypes {
+ if def.ToolType == t {
+ return def.ToolSpeed, def.Name, true
+ }
}
}
- return false
+ return -1, "", false
+}
+
+func (g *Game) hasToolType(p *player.Player, toolType string) bool {
+ _, _, found := g.findTool(p, []string{toolType})
+ return found
}
type recipeEntry struct {
ItemName string
@@ -729,6 +716,37 @@ func (g *Game) showMenuTable(sess *net.Session, title string, names []string) {
}
}
+func (g *Game) recipeName(sess *net.Session, r *action.RecipeDef) string {
+ if r.Output != "" {
+ if def, err := g.ItemStore.Load(r.Output); err == nil {
+ return g.itemColorize(sess, def, def.Name)
+ }
+ }
+ return r.DisplayName()
+}
+
+func (g *Game) showRecipeChoice(sess *net.Session, p *player.Player, recipes []action.RecipeDef, emptyMsg, title string, autoOption string) {
+ if len(recipes) == 0 {
+ sess.WriteLine(emptyMsg)
+ return
+ }
+ if len(recipes) == 1 {
+ if autoOption != "" && p.OptionBool(autoOption) {
+ g.startProductionFromRecipe(sess, p, &recipes[0], 0)
+ return
+ }
+ g.promptHowMany(sess, recipes[0].ID)
+ return
+ }
+ sess.State = net.StateRecipeChoice
+ sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes))
+ var names []string
+ for i := range recipes {
+ names = append(names, g.recipeName(sess, &recipes[i]))
+ }
+ g.showMenuTable(sess, title, names)
+}
+
func (g *Game) handleHowMany(sess *net.Session, input string) {
p := sess.Player
recipeID := sess.PendingRecipeID
@@ -758,17 +776,7 @@ func (g *Game) handleHowMany(sess *net.Session, input string) {
}
recipe = g.buildCombineRecipe(itemDef)
} else {
- all, err := g.RecipeStore.LoadAll()
- if err != nil {
- g.reprompt(sess)
- return
- }
- for _, r := range all {
- if r.ID == recipeID {
- recipe = &r
- break
- }
- }
+ recipe = g.RecipeStore.GetByID(recipeID)
}
if recipe == nil {
diff --git a/internal/game/core_startup.go b/internal/game/core_startup.go
index ab52762..ef33ff7 100644
--- a/internal/game/core_startup.go
+++ b/internal/game/core_startup.go
@@ -8,6 +8,7 @@ import (
"strings"
"thehouseoficarus/internal/action"
+ "thehouseoficarus/internal/world"
)
type StartupIssue struct {
@@ -19,29 +20,29 @@ type StartupIssue struct {
func (g *Game) ValidateStartup() []StartupIssue {
var issues []StartupIssue
- issues = append(issues, validateDuplicateIDs(g.DataDir, "items", "item")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "rooms", "room")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "mobs", "mob")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "objects", "object")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "drops", "drop table")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "recipes", "recipe")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "courses", "course")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "modules", "module")...)
- issues = append(issues, validateDuplicateIDs(g.DataDir, "help", "help topic")...)
-
- issues = append(issues, validateRoomReferences(g)...)
- issues = append(issues, validateMobReferences(g)...)
- issues = append(issues, validateObjectReferences(g)...)
- issues = append(issues, validateItemReferences(g)...)
- issues = append(issues, validateRecipeReferences(g)...)
- issues = append(issues, validateDropTableReferences(g)...)
- issues = append(issues, validateCourseReferences(g)...)
+ issues = append(issues, validateIDs(g.DataDir, "items", "item")...)
+ issues = append(issues, validateIDs(g.DataDir, "rooms", "room")...)
+ issues = append(issues, validateIDs(g.DataDir, "mobs", "mob")...)
+ issues = append(issues, validateIDs(g.DataDir, "objects", "object")...)
+ issues = append(issues, validateIDs(g.DataDir, "drops", "drop table")...)
+ issues = append(issues, validateIDs(g.DataDir, "recipes", "recipe")...)
+ issues = append(issues, validateIDs(g.DataDir, "courses", "course")...)
+ issues = append(issues, validateIDs(g.DataDir, "modules", "module")...)
+ issues = append(issues, validateIDs(g.DataDir, "help", "help topic")...)
+
+ issues = append(issues, validateRooms(g)...)
+ issues = append(issues, validateMobs(g)...)
+ issues = append(issues, validateObjects(g)...)
+ issues = append(issues, validateItems(g)...)
+ issues = append(issues, validateRecipes(g)...)
+ issues = append(issues, validateDropTables(g)...)
+ issues = append(issues, validateCourses(g)...)
issues = append(issues, validateRoomWiring(g)...)
return issues
}
-func validateDuplicateIDs(dataDir, subDir, label string) []StartupIssue {
+func validateIDs(dataDir, subDir, label string) []StartupIssue {
dir := filepath.Join(dataDir, subDir)
dups := action.CheckDuplicateIDs(dir)
var issues []StartupIssue
@@ -60,7 +61,7 @@ func validateDuplicateIDs(dataDir, subDir, label string) []StartupIssue {
return issues
}
-func validateRoomReferences(g *Game) []StartupIssue {
+func validateRooms(g *Game) []StartupIssue {
var issues []StartupIssue
roomIndex := g.World.RoomIndex()
itemIDs := g.ItemStore.IDSet()
@@ -86,6 +87,16 @@ func validateRoomReferences(g *Game) []StartupIssue {
}
for dir, exit := range room.Exits {
+ switch dir {
+ case world.North, world.South, world.East, world.West, world.Up, world.Down:
+ default:
+ issues = append(issues, StartupIssue{
+ Level: "ERROR",
+ Type: "reference",
+ Message: fmt.Sprintf("Room %d: invalid exit direction %q (only north/south/east/west/up/down supported)", id, dir),
+ })
+ continue
+ }
if exit.Room <= 0 {
continue
}
@@ -159,7 +170,7 @@ func validateRoomReferences(g *Game) []StartupIssue {
return issues
}
-func validateMobReferences(g *Game) []StartupIssue {
+func validateMobs(g *Game) []StartupIssue {
var issues []StartupIssue
itemIDs := g.ItemStore.IDSet()
dropIDs := dropTableIDSet(g.DataDir)
@@ -233,7 +244,7 @@ func validateMobReferences(g *Game) []StartupIssue {
return issues
}
-func validateObjectReferences(g *Game) []StartupIssue {
+func validateObjects(g *Game) []StartupIssue {
var issues []StartupIssue
objIDs := g.ObjectStore.IDSet()
itemIDs := g.ItemStore.IDSet()
@@ -301,7 +312,7 @@ func validateObjectReferences(g *Game) []StartupIssue {
}
if obj.Gather != nil {
- issues = append(issues, validateGatherConfig(fmt.Sprintf("Object %q: gather", id), obj.Gather, itemIDs, dropIDs)...)
+ issues = append(issues, validateGather(fmt.Sprintf("Object %q: gather", id), obj.Gather, itemIDs, dropIDs)...)
}
if obj.Talk != nil {
@@ -316,7 +327,7 @@ func validateObjectReferences(g *Game) []StartupIssue {
return issues
}
-func validateItemReferences(g *Game) []StartupIssue {
+func validateItems(g *Game) []StartupIssue {
var issues []StartupIssue
itemIDs := g.ItemStore.IDSet()
dropIDs := dropTableIDSet(g.DataDir)
@@ -393,7 +404,7 @@ func validateItemReferences(g *Game) []StartupIssue {
return issues
}
-func validateRecipeReferences(g *Game) []StartupIssue {
+func validateRecipes(g *Game) []StartupIssue {
var issues []StartupIssue
itemIDs := g.ItemStore.IDSet()
@@ -456,7 +467,7 @@ func validateRecipeReferences(g *Game) []StartupIssue {
return issues
}
-func validateDropTableReferences(g *Game) []StartupIssue {
+func validateDropTables(g *Game) []StartupIssue {
var issues []StartupIssue
dropIDs := dropTableIDSet(g.DataDir)
itemIDs := g.ItemStore.IDSet()
@@ -494,7 +505,7 @@ func validateDropTableReferences(g *Game) []StartupIssue {
return issues
}
-func validateCourseReferences(g *Game) []StartupIssue {
+func validateCourses(g *Game) []StartupIssue {
var issues []StartupIssue
roomIndex := g.World.RoomIndex()
@@ -582,7 +593,7 @@ func validateRoomWiring(g *Game) []StartupIssue {
return issues
}
-func validateGatherConfig(prefix string, cfg *action.GatherConfig, itemIDs map[string]bool, dropIDs map[string]bool) []StartupIssue {
+func validateGather(prefix string, cfg *action.GatherConfig, itemIDs map[string]bool, dropIDs map[string]bool) []StartupIssue {
var issues []StartupIssue
if cfg.Bait != "" && !itemIDs[cfg.Bait] {
diff --git a/internal/game/core_types.go b/internal/game/core_types.go
index d41b18a..898078b 100644
--- a/internal/game/core_types.go
+++ b/internal/game/core_types.go
@@ -22,7 +22,7 @@ type xpGain struct {
type deathDrop struct {
itemID string
quantity int
- totalVal int
+ totalValue int
isEquip bool
equipSlot object.EquipSlot
invSlot int
diff --git a/internal/game/core_utils.go b/internal/game/core_utils.go
index 409422e..c169580 100644
--- a/internal/game/core_utils.go
+++ b/internal/game/core_utils.go
@@ -104,6 +104,22 @@ func formatPickupList(sess *net.Session, picked []string) {
}
}
+func (g *Game) broadcastAction(sess *net.Session, format string, args ...interface{}) {
+ if g.Hub == nil {
+ return
+ }
+ p := sess.Player
+ if p == nil {
+ return
+ }
+ msg := fmt.Sprintf(format, args...)
+ for _, other := range g.Hub.PlayersInRoom(p.RoomID) {
+ if other != sess && other.Player != nil {
+ other.WriteLine(g.colorize(other, "broadcast", msg))
+ }
+ }
+}
+
func (g *Game) newInventorySlot(itemID string, qty int) *player.InventorySlot {
slot := &player.InventorySlot{ItemID: itemID, Quantity: qty}
if def, err := g.ItemStore.Load(itemID); err == nil && def.MaxQuality > 0 {
diff --git a/internal/game/game.go b/internal/game/game.go
index 5d6e21e..ac8622e 100644
--- a/internal/game/game.go
+++ b/internal/game/game.go
@@ -47,7 +47,7 @@ type Game struct {
WorldFlags map[string]any
ColorConfig *config.ColorsConfig
DataDir string
- ValidationConfig config.StartupValidationConfig
+ ValidationConfig config.ValidationConfig
restTimers map[string]uint64
charsMu sync.Mutex
loggedInChars map[string]*net.Session
@@ -60,7 +60,7 @@ type Game struct {
hackingStates map[string]*hacking.Session
}
-func New(dataDir string, colorConfig *config.ColorsConfig, valConfig config.StartupValidationConfig) *Game {
+func New(dataDir string, colorConfig *config.ColorsConfig, valConfig config.ValidationConfig) *Game {
g := &Game{
World: world.New(dataDir),
ObjectStore: object.NewObjectStore(dataDir),
@@ -110,9 +110,9 @@ func (g *Game) HandleSession(sess *net.Session, input string) {
case net.StatePassword:
g.handlePassword(sess, input)
case net.StateNewAccountPass:
- g.handleNewAccountPass(sess, input)
- case net.StateNewAccountConfirm:
- g.handleNewAccountConfirm(sess, input)
+ g.handleNewPass(sess, input)
+ case net.StateNewAccount:
+ g.handleNewAccount(sess, input)
case net.StateMenu:
g.handleMenu(sess, input)
case net.StateNewCharName:
@@ -129,8 +129,8 @@ func (g *Game) HandleSession(sess *net.Session, input string) {
g.handlePurgeAccount(sess, input)
case net.StateGame:
g.handleGameCommand(sess, input)
- case net.StateChangeDescription:
- g.handleDescriptionChange(sess, input)
+ case net.StateChangeDesc:
+ g.handleDescChange(sess, input)
case net.StateTalk:
g.handleTalkInput(sess, input)
case net.StateShop:
@@ -138,7 +138,7 @@ func (g *Game) HandleSession(sess *net.Session, input string) {
case net.StateBank:
g.handleBankInput(sess, input)
case net.StateDropAllConfirm:
- g.handleDropAllConfirm(sess, input)
+ g.handleDropAll(sess, input)
case net.StateRecipeChoice:
g.handleRecipeChoice(sess, input)
case net.StateHowMany:
diff --git a/internal/game/hacking/hacking_liars_dice.go b/internal/game/hacking/liars_dice.go
index bcfbd40..bcfbd40 100644
--- a/internal/game/hacking/hacking_liars_dice.go
+++ b/internal/game/hacking/liars_dice.go
diff --git a/internal/game/hacking/hacking_mastermind.go b/internal/game/hacking/mastermind.go
index 8d4eb1c..8d4eb1c 100644
--- a/internal/game/hacking/hacking_mastermind.go
+++ b/internal/game/hacking/mastermind.go
diff --git a/internal/game/hacking/hacking_wumpus.go b/internal/game/hacking/wumpus.go
index 91b9243..91b9243 100644
--- a/internal/game/hacking/hacking_wumpus.go
+++ b/internal/game/hacking/wumpus.go
diff --git a/internal/game/sys_combat.go b/internal/game/sys_combat.go
index 030bed1..702871c 100644
--- a/internal/game/sys_combat.go
+++ b/internal/game/sys_combat.go
@@ -31,7 +31,7 @@ func (g *Game) dropItemsOnDeath(p *player.Player) {
items = append(items, deathDrop{
itemID: inv.ItemID,
quantity: inv.Quantity,
- totalVal: val,
+ totalValue: val,
invSlot: slot,
})
}
@@ -44,7 +44,7 @@ func (g *Game) dropItemsOnDeath(p *player.Player) {
items = append(items, deathDrop{
itemID: itemID,
quantity: 1,
- totalVal: val,
+ totalValue: val,
isEquip: true,
equipSlot: eqSlot,
})
@@ -55,7 +55,7 @@ func (g *Game) dropItemsOnDeath(p *player.Player) {
}
sort.Slice(items, func(i, j int) bool {
- return items[i].totalVal > items[j].totalVal
+ return items[i].totalValue > items[j].totalValue
})
for i := 3; i < len(items); i++ {
diff --git a/internal/game/sys_science.go b/internal/game/sys_science.go
index e35105a..376d7c7 100644
--- a/internal/game/sys_science.go
+++ b/internal/game/sys_science.go
@@ -9,6 +9,7 @@ import (
"gopkg.in/yaml.v3"
"thehouseoficarus/internal/action"
+ "thehouseoficarus/internal/net"
"thehouseoficarus/internal/object"
"thehouseoficarus/internal/player"
)
@@ -182,7 +183,7 @@ func (g *Game) hasDeckEquipped(p *player.Player) bool {
return def.WeaponType == object.WeaponScience
}
-func (g *Game) equippedProvidesJunk(p *player.Player) string {
+func (g *Game) providesJunk(p *player.Player) string {
itemID, ok := p.Equipment[object.SlotMainHand]
if !ok {
return ""
@@ -206,7 +207,7 @@ func (g *Game) effectiveJunkCost(p *player.Player, mod *ModDef) map[string]int {
delete(cost, "scrap_metal")
}
- providesJunk := g.equippedProvidesJunk(p)
+ providesJunk := g.providesJunk(p)
if providesJunk != "" {
delete(cost, providesJunk)
}
@@ -235,6 +236,31 @@ func (g *Game) consumeJunkCost(p *player.Player, mod *ModDef) bool {
return true
}
+func (g *Game) triggerModReward(sess *net.Session, p *player.Player, mod *ModDef, multiplier float64, extraGains ...xpGain) int {
+ g.consumeJunkCost(p, mod)
+
+ sciXP := int(float64(mod.BaseXP) * multiplier)
+ if sciXP < 1 {
+ sciXP = 1
+ }
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+
+ for _, gain := range extraGains {
+ g.awardSkillXP(sess, p, player.SkillName(gain.Skill), gain.XP)
+ }
+
+ g.AccountStore.SaveCharacter(p)
+
+ if p.OptionBool("xp_drops") {
+ parts := []string{fmt.Sprintf("+%dxp %s", sciXP, player.SkillAbbr[player.Science])}
+ for _, gain := range extraGains {
+ parts = append(parts, fmt.Sprintf("+%dxp %s", gain.XP, player.SkillAbbr[player.SkillName(gain.Skill)]))
+ }
+ sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
+ }
+ return sciXP
+}
+
func (g *Game) junkCostString(p *player.Player, mod *ModDef) string {
cost := g.effectiveJunkCost(p, mod)
delete(cost, "scrap_metal")
@@ -259,7 +285,7 @@ func (g *Game) junkCostString(p *player.Player, mod *ModDef) string {
return strings.Join(parts, ", ")
}
-func (g *Game) totalEquipScienceAttack(p *player.Player) int {
+func (g *Game) totalScienceAttack(p *player.Player) int {
total := 0
for _, itemID := range p.Equipment {
def, err := g.ItemStore.Load(itemID)