From 0ea4eec5dd2122c6704216971eb1249276297867 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Fri, 19 Jun 2026 18:20:26 -0400 Subject: shop fixes, 'toggle' completely removed, movement speed increased --- internal/game/game.go | 468 +++++--------------------------------------------- 1 file changed, 47 insertions(+), 421 deletions(-) (limited to 'internal/game/game.go') 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) - } - } -} -- cgit v1.2.3