aboutsummaryrefslogtreecommitdiff
path: root/internal/game/game.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-19 18:20:26 -0400
committerhistoria <[not public]>2026-06-19 18:20:26 -0400
commit0ea4eec5dd2122c6704216971eb1249276297867 (patch)
tree430fbbef04e837820f1d031c190f52ecd6112e25 /internal/game/game.go
parent3a58125d14bb307f861b38c6c5b0a63babde7e08 (diff)
downloadthehouseoficarus-0ea4eec5dd2122c6704216971eb1249276297867.tar.gz
shop fixes, 'toggle' completely removed, movement speed increased
Diffstat (limited to 'internal/game/game.go')
-rw-r--r--internal/game/game.go468
1 files changed, 47 insertions, 421 deletions
diff --git a/internal/game/game.go b/internal/game/game.go
index 03300a4..b8eadce 100644
--- a/internal/game/game.go
+++ b/internal/game/game.go
@@ -11,6 +11,7 @@ import (
"thehouseoficarus/internal/combat"
"thehouseoficarus/internal/config"
"thehouseoficarus/internal/engine"
+ "thehouseoficarus/internal/game/hacking"
"thehouseoficarus/internal/net"
"thehouseoficarus/internal/object"
"thehouseoficarus/internal/player"
@@ -39,25 +40,23 @@ type Game struct {
ItemStore *object.ItemStore
AccountStore *player.AccountStore
MobStore *world.MobStore
- BehaviorStore *action.Store
RecipeStore *action.RecipeStore
CourseStore *CourseStore
Hub *net.Hub
Ticks *engine.Engine
WorldFlags map[string]any
ColorConfig *config.ColorsConfig
- dataDir string
+ DataDir string
restTimers map[string]uint64
charsMu sync.Mutex
loggedInChars map[string]*net.Session
- combatPadWidth int
freeQueue map[string][]QueuedCommand
activeQueue map[string]*QueuedCommand
consumeQueue map[string]*QueuedCommand
pendingDepletions []pendingDepletion
guardWatchTimers map[string]int
farmTickCounter int
- hackingStates map[string]*HackingSession
+ hackingStates map[string]*hacking.Session
}
func New(dataDir string, colorConfig *config.ColorsConfig) *Game {
@@ -67,13 +66,12 @@ func New(dataDir string, colorConfig *config.ColorsConfig) *Game {
ItemStore: object.NewItemStore(dataDir),
AccountStore: player.NewAccountStore(dataDir),
MobStore: world.NewMobStore(dataDir),
- BehaviorStore: action.NewStore(dataDir),
RecipeStore: action.NewRecipeStore(dataDir),
CourseStore: NewCourseStore(dataDir),
Ticks: engine.New(),
WorldFlags: make(map[string]any),
ColorConfig: colorConfig,
- dataDir: dataDir,
+ DataDir: dataDir,
restTimers: make(map[string]uint64),
loggedInChars: make(map[string]*net.Session),
freeQueue: make(map[string][]QueuedCommand),
@@ -81,16 +79,17 @@ func New(dataDir string, colorConfig *config.ColorsConfig) *Game {
consumeQueue: make(map[string]*QueuedCommand),
pendingDepletions: nil,
guardWatchTimers: make(map[string]int),
- hackingStates: make(map[string]*HackingSession),
+ hackingStates: make(map[string]*hacking.Session),
}
g.CourseStore.LoadAll()
+ g.LoadMods()
return g
}
func (g *Game) SetHub(hub *net.Hub) {
g.Hub = hub
hub.OnRemove(func(sess *net.Session) {
- if p, ok := sess.Player.(*player.Player); ok {
+ if p := sess.Player; p != nil {
p.DeactivateAllTechs()
g.charsMu.Lock()
delete(g.loggedInChars, p.Name)
@@ -150,44 +149,6 @@ func (g *Game) HandleSession(sess *net.Session, input string) {
}
}
-func classifyCommand(cmd string) CommandClass {
- switch cmd {
- case "say", "score", "sc", "inventory", "i", "inv",
- "look", "l", "exits", "help",
- "map", "option", "options", "alias", "unalias",
- "description", "desc", "queued", "color", "colors",
- "colortable", "prompt", "style", "stats",
- "tech", "t", "sneak",
- "autocast", "auto", "mods", "modlist",
- "task", "inspect":
- return ClassInstant
- case "equip", "eq", "equipment", "wear", "wield", "remove", "unwear", "unwield":
- return ClassFree
- case "get", "take", "grab", "pick", "drop",
- "attack", "kill",
- "north", "n", "south", "s", "east", "e",
- "west", "w", "up", "u", "down", "d",
- "quit", "use", "burn", "stoke", "search", "walk", "cook", "smelt", "smith", "craft", "mix",
- "id", "identify",
- "steal", "thieve",
- "trigger", "cast",
- "plant", "harvest", "rake", "water", "cure",
- "bank", "construct", "make":
- return ClassActive
- case "jack", "jackin":
- return ClassActive
- case "eat", "fletch", "clean", "drink":
- return ClassFree
- }
- if _, ok := verbAliases[cmd]; ok {
- return ClassActive
- }
- if obstacleVerbs[cmd] {
- return ClassActive
- }
- return ClassUnknown
-}
-
func (g *Game) writePrompt(sess *net.Session) {
sess.Write("\r\n" + g.promptStr(sess))
}
@@ -240,7 +201,7 @@ func (g *Game) handleGameCommand(sess *net.Session, input string) {
return
}
- p, _ := sess.Player.(*player.Player)
+ p := sess.Player
if p == nil {
return
}
@@ -276,363 +237,60 @@ func (g *Game) handleGameCommand(sess *net.Session, input string) {
}
}
-func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawInput string) {
- p, _ := sess.Player.(*player.Player)
-
- switch cmd {
- case "get", "take", "grab", "pick":
- if len(args) == 0 {
- sess.WriteLine("Get what?")
- } else if args[0] == "all" {
- if len(args) == 1 {
- g.doGetAll(sess)
- } else {
- g.doGetAllNamed(sess, strings.Join(args[1:], " "))
- }
- } else {
- g.doGet(sess, strings.Join(args, " "))
- }
- case "drop":
- if len(args) == 0 {
- sess.WriteLine("Drop what?")
- } else if args[0] == "all" {
- if len(args) == 1 {
- g.doDropAll(sess)
- } else {
- g.doDropAllNamed(sess, strings.Join(args[1:], " "))
- }
- } else {
- g.doDrop(sess, strings.Join(args, " "))
- }
- case "attack", "kill":
- if len(args) == 0 {
- target := g.resolveDefaultMob(p.RoomID)
- if target == "" {
- sess.WriteLine("Attack what?")
- break
- }
- g.doAttack(sess, target)
- return
- } else {
- g.doAttack(sess, strings.Join(args, " "))
- return
- }
- case "style":
- if len(args) == 0 {
- g.doStyle(sess, "")
- } else {
- g.doStyle(sess, args[0])
- }
- case "look", "l":
- if len(args) == 0 {
- g.doLook(sess)
- } else {
- g.doLookTarget(sess, strings.Join(args, " "))
- }
- case "north", "n", "south", "s", "east", "e", "west", "w", "up", "u", "down", "d":
- g.doMove(sess, cmd)
- case "say":
- if len(args) == 0 {
- sess.WriteLine("Say what?")
- } else {
- msgStart := strings.Index(strings.ToLower(rawInput), "say ") + 4
- if msgStart >= 4 && msgStart < len(rawInput) {
- g.doSay(sess, rawInput[msgStart:])
- } else {
- g.doSay(sess, strings.Join(args, " "))
- }
- }
- case "sc", "score":
- g.doScore(sess)
- case "task":
- g.doTask(sess)
- case "stats":
- g.doStats(sess)
- case "tech", "t":
- g.doTech(sess, strings.Join(args, " "))
- case "i", "inv", "inventory":
- g.doInventory(sess)
- case "quit":
- g.doQuit(sess)
- return
- case "description", "desc":
- g.doDescription(sess)
- case "option", "options":
- g.doOption(sess, strings.Join(args, " "))
- case "color", "colors":
- g.doColor(sess, strings.Join(args, " "))
- case "colortable":
- g.doColortable(sess)
- case "prompt":
- if len(args) == 0 {
- g.doPrompt(sess, "")
- } else {
- msgStart := strings.Index(strings.ToLower(rawInput), "prompt ") + 7
- if msgStart >= 7 && msgStart < len(rawInput) {
- g.doPrompt(sess, rawInput[msgStart:])
- } else {
- g.doPrompt(sess, strings.Join(args, " "))
- }
- }
- case "exits":
- g.doExits(sess)
- case "map":
- g.doMap(sess)
- case "queued":
- g.doQueued(sess)
- case "help":
- if len(args) == 0 {
- g.doHelp(sess, "")
- } else {
- g.doHelp(sess, strings.Join(args, " "))
- }
- case "mine", "chop", "fish", "cut", "pull", "push":
- g.CancelAction(p)
- if len(args) == 0 {
- target := g.resolveDefaultTarget(p.RoomID, cmd)
- if target == "" {
- sess.WriteLine(fmt.Sprintf("%s what?", cmd))
- break
- }
- g.StartAction(sess, cmd, target)
- return
- } else {
- g.StartAction(sess, cmd, strings.Join(args, " "))
- return
- }
- case "use":
- if g.tryFinishingBlow(sess, strings.Join(args, " ")) {
- return
- }
- g.doUse(sess, strings.Join(args, " "))
- return
- case "cook":
- g.doCook(sess, strings.Join(args, " "))
- return
- case "smelt":
- g.doSmelt(sess, strings.Join(args, " "))
- return
- case "smith":
- g.doSmith(sess, strings.Join(args, " "))
- return
- case "craft":
- g.doCraft(sess, strings.Join(args, " "))
- return
- case "eat":
- g.doEat(sess, strings.Join(args, " "))
- return
- case "drink":
- g.doDrink(sess, args)
- return
- case "fletch":
- g.doFletch(sess, strings.Join(args, " "))
- return
- case "clean":
- g.doClean(sess, strings.Join(args, " "))
- return
- case "mix":
- g.doMix(sess, strings.Join(args, " "))
- return
- case "id", "identify":
- g.doIdentify(sess, strings.Join(args, " "))
- return
- case "autocast", "auto":
- g.doAutocast(sess, strings.Join(args, " "))
- case "mods", "modlist":
- g.doMods(sess)
- case "sneak":
- g.doSneak(sess)
- case "trigger", "cast":
- g.doTrigger(sess, strings.Join(args, " "))
- return
- case "talk", "speak", "ask":
- g.CancelAction(p)
- if len(args) == 0 {
- sess.WriteLine("Talk to whom?")
- } else {
- g.StartAction(sess, "talk", strings.Join(args, " "))
- return
- }
- case "burn":
- g.CancelAction(p)
- g.doBurn(sess, p, strings.Join(args, " "))
- return
- case "stoke":
- g.CancelAction(p)
- g.doStoke(sess, p, strings.Join(args, " "))
- return
- case "alias":
- g.doAlias(sess, args)
- return
- case "unalias":
- g.doUnalias(sess, args)
- return
- case "search":
- g.CancelAction(p)
- if len(args) == 0 {
- sess.WriteLine("Search what?")
- } else {
- g.doSearch(sess, strings.Join(args, " "))
- }
- return
- case "steal", "thieve":
- g.CancelAction(p)
- if len(args) == 0 {
- g.doSteal(sess, "")
- } else {
- g.doSteal(sess, strings.Join(args, " "))
- }
- return
- case "plant":
- g.CancelAction(p)
- if len(args) == 0 {
- sess.WriteLine("Plant what?")
- } else {
- g.doPlant(sess, strings.Join(args, " "))
- }
- return
- case "harvest":
- g.CancelAction(p)
- if len(args) == 0 {
- g.doHarvest(sess, "")
- } else {
- g.doHarvest(sess, strings.Join(args, " "))
- }
- return
- case "rake":
- g.CancelAction(p)
- if len(args) == 0 {
- g.doRake(sess, "")
- } else {
- g.doRake(sess, strings.Join(args, " "))
- }
- return
- case "water":
- g.CancelAction(p)
- if len(args) == 0 {
- g.doWater(sess, "")
- } else {
- g.doWater(sess, strings.Join(args, " "))
- }
- return
- case "cure":
- g.CancelAction(p)
- if len(args) == 0 {
- g.doCure(sess, "")
- } else {
- g.doCure(sess, strings.Join(args, " "))
- }
- return
- case "inspect":
- if len(args) == 0 {
- g.doInspect(sess, "")
- } else {
- g.doInspect(sess, strings.Join(args, " "))
- }
- case "walk":
- g.doWalk(sess, args)
- return
- case "bank":
- g.doBank(sess)
- return
- case "construct", "make":
- g.doConstruct(sess, strings.Join(args, " "))
- return
- case "jack", "jackin":
- g.CancelAction(p)
- g.doJack(sess, strings.Join(args, " "))
- return
- case "eq", "equipment", "equip", "wear", "wield":
- g.doWear(sess, strings.Join(args, " "))
- return
- case "remove", "unwear", "unwield":
- g.doRemove(sess, strings.Join(args, " "))
- return
- default:
- if obstacleVerbs[cmd] {
- g.doObstacle(sess, cmd)
- return
- }
- if a, ok := verbAliases[cmd]; ok {
- g.CancelAction(p)
- switch a {
- case "gather", "toggle":
- if len(args) == 0 {
- target := g.resolveDefaultTarget(p.RoomID, cmd)
- if target == "" {
- sess.WriteLine(fmt.Sprintf("%s what?", cmd))
- break
- }
- g.StartAction(sess, cmd, target)
- return
- }
- g.StartAction(sess, cmd, strings.Join(args, " "))
- return
- case "talk":
- if len(args) == 0 {
- sess.WriteLine("Talk to whom?")
- } else {
- g.StartAction(sess, "talk", strings.Join(args, " "))
- return
- }
- }
- } else {
- sess.WriteLine("Unknown command.")
- }
- }
-}
-
func (g *Game) ProcessQueuedCommands() {
if g.Hub == nil {
return
}
for _, sess := range g.Hub.AllSessions() {
- p, ok := sess.Player.(*player.Player)
- if !ok || p == nil || p.ActionState == nil {
- continue
- }
- as, ok := p.ActionState.(*ActionState)
- if !ok {
+ p := sess.Player
+ if p == nil {
continue
}
- switch as.Type {
- case ActionGathering, ActionCombating, ActionUsing, ActionTalking,
- ActionToggling, ActionBurning, ActionStoking, ActionResting, ActionWalking, ActionProducing,
- ActionStealing, ActionPlanting, ActionHarvesting, ActionRaking, ActionWatering, ActionCuring,
- ActionTraversing:
- default:
- if as.Type != ActionMoving || p.MoveTicks <= 0 {
+
+ 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, ActionResting, ActionWalking, ActionProducing,
+ ActionStealing, ActionPlanting, ActionHarvesting, ActionRaking, ActionWatering, ActionCuring,
+ ActionTraversing:
+ default:
+ if as.Type != ActionMoving || p.MoveTicks <= 0 {
+ p.ActionState = nil
+ }
+ }
}
}
- }
- for _, sess := range g.Hub.AllSessions() {
- p, ok := sess.Player.(*player.Player)
- if !ok || p == nil {
- continue
- }
if p.BackgroundAction == nil {
p.BackgroundActionState = nil
}
- }
- for _, sess := range g.Hub.AllSessions() {
- p, ok := sess.Player.(*player.Player)
- if !ok || p == nil {
- continue
- }
cmds := g.freeQueue[p.Name]
for _, qc := range cmds {
g.cancelRest(p.Name)
- parts := strings.Fields(qc.Command + " " + qc.Args)
+ raw := qc.Command
+ if qc.Args != "" {
+ raw += " " + qc.Args
+ }
+ parts := strings.Fields(raw)
if len(parts) > 0 {
- g.executeCommand(qc.Session, parts[0], parts[1:], qc.Command+" "+qc.Args)
+ g.executeCommand(qc.Session, parts[0], parts[1:], raw)
}
g.writePrompt(qc.Session)
}
delete(g.freeQueue, p.Name)
+
+ if len(p.WalkSequence) > 0 {
+ g.advanceWalk(sess, p)
+ if len(p.WalkSequence) == 0 && p.MoveTicks == 0 {
+ g.writePrompt(sess)
+ }
+ }
}
var actives []QueuedCommand
@@ -644,16 +302,20 @@ func (g *Game) ProcessQueuedCommands() {
})
for _, qc := range actives {
- parts := strings.Fields(qc.Command + " " + qc.Args)
- p, ok := qc.Session.Player.(*player.Player)
- if !ok || p == nil {
+ raw := qc.Command
+ if qc.Args != "" {
+ raw += " " + qc.Args
+ }
+ parts := strings.Fields(raw)
+ p := qc.Session.Player
+ if p == nil {
continue
}
if p.MoveTicks > 0 {
p.ClearMoveState()
}
if len(parts) > 0 {
- g.executeCommand(qc.Session, parts[0], parts[1:], qc.Command+" "+qc.Args)
+ g.executeCommand(qc.Session, parts[0], parts[1:], raw)
}
isBusy := p.Action != nil || len(p.WalkSequence) > 0 || combat.GetCombat(p.Name) != nil || p.MoveTicks > 0
_, isResting := g.restTimers[p.Name]
@@ -663,48 +325,12 @@ func (g *Game) ProcessQueuedCommands() {
}
g.activeQueue = make(map[string]*QueuedCommand)
- for _, sess := range g.Hub.AllSessions() {
- p, ok := sess.Player.(*player.Player)
- if !ok || p == nil || len(p.WalkSequence) == 0 {
- continue
- }
- g.advanceWalk(sess, p)
- if len(p.WalkSequence) == 0 && p.MoveTicks == 0 {
- g.writePrompt(sess)
- }
- }
-
g.flushPendingDepletions()
}
type pendingDepletion struct {
instanceKey string
- behaviorID string
+ objDefID string
targetName string
playerNames []string
}
-
-func (g *Game) MoveTick() {
- if g.Hub == nil {
- return
- }
- for _, sess := range g.Hub.AllSessions() {
- p, ok := sess.Player.(*player.Player)
- if !ok || p == nil || p.MoveTicks <= 0 {
- continue
- }
- p.MoveTicks--
- if p.MoveTicks > 0 {
- if combat.GetCombat(p.Name) != nil && p.OptionBool("run_countdown") {
- if p.MoveTicks > 1 {
- sess.WriteLine(fmt.Sprintf("Running in %d ticks...", p.MoveTicks))
- } else {
- sess.WriteLine("Running next tick!")
- }
- }
- } else {
- g.completeMove(sess, p)
- g.writePrompt(sess)
- }
- }
-}