diff options
| author | historia <[not public]> | 2026-07-31 17:44:10 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-07-31 17:44:10 -0400 |
| commit | f51424c90dbce7191a31b6e675818c985f0f4539 (patch) | |
| tree | a7845a2e09bd6e83d2d034f5e702a4940f38126a /internal/game | |
| parent | 58758d41488a777d2bc0e787be655363bdd9eb60 (diff) | |
| download | thehouseoficarus-f51424c90dbce7191a31b6e675818c985f0f4539.tar.gz | |
feat: casino framework and basic slot machine
Diffstat (limited to 'internal/game')
| -rw-r--r-- | internal/game/act_effects.go | 7 | ||||
| -rw-r--r-- | internal/game/casino.go | 319 | ||||
| -rw-r--r-- | internal/game/casino_test.go | 29 | ||||
| -rw-r--r-- | internal/game/cmd_move.go | 4 | ||||
| -rw-r--r-- | internal/game/cmd_quit.go | 4 | ||||
| -rw-r--r-- | internal/game/cmd_registry.go | 5 | ||||
| -rw-r--r-- | internal/game/cmd_stop.go | 12 | ||||
| -rw-r--r-- | internal/game/core_login_char.go | 1 | ||||
| -rw-r--r-- | internal/game/game.go | 27 | ||||
| -rw-r--r-- | internal/game/look_entities.go | 37 | ||||
| -rw-r--r-- | internal/game/render_help.go | 4 | ||||
| -rw-r--r-- | internal/game/tick_systems.go | 3 | ||||
| -rw-r--r-- | internal/game/tick_systems_test.go | 3 |
13 files changed, 442 insertions, 13 deletions
diff --git a/internal/game/act_effects.go b/internal/game/act_effects.go index cadd05e..d1effac 100644 --- a/internal/game/act_effects.go +++ b/internal/game/act_effects.go @@ -177,7 +177,12 @@ func (g *Game) applyStep(sess *net.Session, p *player.Player, step *behavior.Ste } } - // 11/12. spawn_mob / despawn_mob (player-owned / owner-filtered). + // 11. casino game join. The table is resolved from the player's current room. + if step.StartGame != "" { + g.startCasinoGame(sess, p, step.StartGame) + } + + // 12/13. spawn_mob / despawn_mob (player-owned / owner-filtered). if step.SpawnMob != nil { g.spawnTriggerMob(sess, p, step.SpawnMob, roomID) } diff --git a/internal/game/casino.go b/internal/game/casino.go new file mode 100644 index 0000000..c6fb63b --- /dev/null +++ b/internal/game/casino.go @@ -0,0 +1,319 @@ +package game + +import ( + "fmt" + "strconv" + "strings" + + "thehouseoficarus/internal/casino" + "thehouseoficarus/internal/color" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +type casinoWallet struct { + g *Game + p *player.Player +} + +func (w casinoWallet) Wager(amount int) (casino.Wager, bool) { + chips := countChips(w.p) + if chips > amount { + chips = amount + } + credits := amount - chips + if w.p.Credits < credits { + return casino.Wager{}, false + } + if chips > 0 { + w.p.RemoveItem("chips", chips) + } + w.p.Credits -= credits + w.g.AccountStore.SaveCharacter(w.p) + return casino.Wager{Total: amount, Chips: chips, Credits: credits}, true +} + +func (w casinoWallet) PayCredits(amount int) { + w.p.Credits += amount + w.g.AccountStore.SaveCharacter(w.p) +} + +func (g *Game) casinoTable(roomID int, gameName string) (*casino.Table, bool) { + room, err := g.World.LoadRoom(roomID) + if err != nil { + return nil, false + } + for _, cfg := range room.CasinoTables { + if strings.EqualFold(string(cfg.Game), gameName) { + return g.Casino.EnsureTable(roomID, cfg), true + } + } + return nil, false +} + +func (g *Game) casinoMachine(roomID int, gameName string) (*casino.Machine, bool) { + room, err := g.World.LoadRoom(roomID) + if err != nil { + return nil, false + } + for _, cfg := range room.CasinoMachines { + if strings.EqualFold(string(cfg.Game), gameName) || strings.EqualFold(cfg.Variant, gameName) { + return g.Casino.EnsureMachine(roomID, cfg), true + } + } + // Migrate older room definitions that declared slots under casino_tables; + // slots are still always instantiated as one-player machines. + if strings.EqualFold(gameName, "slots") { + for _, cfg := range room.CasinoTables { + if strings.EqualFold(string(cfg.Game), "slots") { + return g.Casino.EnsureMachine(roomID, casino.MachineConfig{ + ID: cfg.ID, Game: casino.GameSlots, MinBet: cfg.MinBet, MaxBet: cfg.MaxBet, + }), true + } + } + } + return nil, false +} + +func (g *Game) executePlay(sess *net.Session, args []string, rawInput string) { + p := sess.Player + if p == nil || len(args) == 0 { + sess.WriteLine("Play what?") + return + } + if _, playing := g.Casino.Participation(p.Name); playing { + sess.WriteLine("You're already playing a game. Type \"stop\" between rounds to leave it.") + return + } + g.startCasinoGame(sess, p, args[0]) +} + +func (g *Game) startCasinoGame(sess *net.Session, p *player.Player, gameName string) { + if p == nil || sess == nil { + return + } + if _, playing := g.Casino.Participation(p.Name); playing { + sess.WriteLine("You're already playing a game. Type \"stop\" between rounds to leave it.") + return + } + if machine, ok := g.casinoMachine(p.RoomID, gameName); ok { + g.emitCasinoEvents(g.Casino.JoinMachine(machine.RoomID, machine.Config, p.Name)) + return + } + table, ok := g.casinoTable(p.RoomID, gameName) + if !ok { + sess.WriteLine(fmt.Sprintf("There is no %s table here.", gameName)) + return + } + g.emitCasinoEvents(g.Casino.Join(table.RoomID, table.Config, p.Name)) +} + +func (g *Game) executeBet(sess *net.Session, args []string, rawInput string) { + p := sess.Player + if p == nil { + sess.WriteLine("Bet how much?") + return + } + if machine, ok := g.Casino.MachineFor(p.Name); ok { + if len(args) == 0 { + g.emitCasinoEvents(g.Casino.StartMachine(machine.RoomID, machine.Config.ID, p.Name, casinoWallet{g: g, p: p})) + return + } + if len(args) == 1 && args[0] == "max" { + g.emitCasinoEvents(g.Casino.SetMachineBet(machine.RoomID, machine.Config.ID, p.Name, machine.Config.MaxBet)) + return + } + if len(args) == 1 { + if amount, err := strconv.Atoi(args[0]); err == nil && amount > 0 { + g.emitCasinoEvents(g.Casino.SetMachineBet(machine.RoomID, machine.Config.ID, p.Name, amount)) + return + } + } + g.emitCasinoEvents(g.Casino.StartMachine(machine.RoomID, machine.Config.ID, p.Name, casinoWallet{g: g, p: p})) + return + } + if len(args) == 0 { + sess.WriteLine("Bet how much?") + return + } + amount, err := strconv.Atoi(args[0]) + if err != nil || amount <= 0 { + sess.WriteLine("Your bet must be a positive whole number.") + return + } + table, playing := g.Casino.Participation(p.Name) + if !playing { + sess.WriteLine("You're not playing a game.") + return + } + g.emitCasinoEvents(g.Casino.Bet(table.RoomID, table.Config.ID, p.Name, amount, casinoWallet{g: g, p: p})) +} + +func (g *Game) executeAutoBet(sess *net.Session, args []string, rawInput string) { + p := sess.Player + if p == nil { + return + } + if machine, ok := g.Casino.MachineFor(p.Name); ok { + g.emitCasinoEvents(g.Casino.EnableMachineAutoBet(machine.RoomID, machine.Config.ID, p.Name, casinoWallet{g: g, p: p})) + return + } + sess.WriteLine("Autobet is only available at games without player choices.") +} + +func (g *Game) CasinoTick() { + if g.Casino != nil { + g.emitCasinoEvents(g.Casino.Tick()) + } +} + +func (g *Game) emitCasinoEvents(events []casino.Event) { + for _, event := range events { + if event.Message == "" { + continue + } + category := event.Color + if category == "" { + category = casinoEventColor(event.Type) + } + if event.Public && g.Hub != nil { + for _, sess := range g.Hub.PlayersInRoom(event.RoomID) { + if event.PrivateTo != "" && sess.Player != nil && sess.Player.Name == event.PrivateTo { + continue + } + message := event.Message + if category == "casino_menu" && sess.Player != nil && sess.Player.Name == event.PrivateTo { + message = g.casinoMenuBalance(sess, message) + } + if event.Slot != nil && sess.Player != nil { + message += "\n" + renderSlotSnapshot(event.Slot, g.colorMode(sess), sess.Player.OptionBool("unicode")) + } + sess.WriteLine(g.colorize(sess, category, message)) + } + } + if event.PrivateMessage != "" && event.PrivateTo != "" { + g.charsMu.Lock() + sess := g.loggedInChars[event.PrivateTo] + g.charsMu.Unlock() + if sess != nil { + privateMessage := event.PrivateMessage + if category == "casino_menu" { + privateMessage = g.casinoMenuBalance(sess, privateMessage) + } + sess.WriteLine(g.colorize(sess, category, privateMessage)) + if category == "casino_menu" { + g.writePrompt(sess) + } + } + } + if event.PrivateTo != "" { + g.charsMu.Lock() + sess := g.loggedInChars[event.PrivateTo] + g.charsMu.Unlock() + if sess != nil && event.PrivateMessage == "" { + privateMessage := event.Message + if category == "casino_menu" { + privateMessage = g.casinoMenuBalance(sess, privateMessage) + } + sess.WriteLine(g.colorize(sess, category, privateMessage)) + if category == "casino_menu" { + g.writePrompt(sess) + } + } + } + } +} + +func casinoEventColor(eventType casino.EventType) string { + if eventType == casino.EventPayout { + return "casino_win" + } + return "casino_action" +} + +func (g *Game) casinoMenuBalance(sess *net.Session, message string) string { + if sess == nil || sess.Player == nil { + return message + } + chips := g.colorize(sess, "casino_chips", fmt.Sprintf("%d", countChips(sess.Player))) + credits := g.colorize(sess, "casino_credits", fmt.Sprintf("%d", sess.Player.Credits)) + line := fmt.Sprintf("You have %s chips and %s credits.", chips, credits) + return strings.Replace(message, "Slot machine commands:", line+"\n\nSlot machine commands:", 1) +} + +func renderSlotSnapshot(snapshot *casino.SlotSnapshot, mode string, unicode bool) string { + if snapshot == nil { + return "" + } + left, junction, right, horizontal, vertical := '+', '+', '+', '-', '|' + bottomLeft, bottomJunction, bottomRight := '+', '+', '+' + if unicode { + left, junction, right, horizontal, vertical = '\u250c', '\u252c', '\u2510', '\u2500', '\u2502' + bottomLeft, bottomJunction, bottomRight = '\u2514', '\u2534', '\u2518' + } + separator := string(left) + for reel := 0; reel < 5; reel++ { + if reel > 0 { + separator += string(junction) + } + separator += strings.Repeat(string(horizontal), 9) + } + separator += string(right) + lines := []string{casinoFrame(mode, separator)} + frameVertical := casinoFrame(mode, string(vertical)) + for row := 0; row < 3; row++ { + line := frameVertical + for reel := 0; reel < 5; reel++ { + value := "..." + if reel < snapshot.StoppedReels { + value = snapshot.Grid[row][reel] + } + line += " " + colorSlotSymbol(mode, value) + strings.Repeat(" ", 7-len(value)) + " " + frameVertical + } + lines = append(lines, line) + } + bottom := string(bottomLeft) + for reel := 0; reel < 5; reel++ { + if reel > 0 { + bottom += string(bottomJunction) + } + bottom += strings.Repeat(string(horizontal), 9) + } + bottom += string(bottomRight) + lines = append(lines, casinoFrame(mode, bottom)) + return strings.Join(lines, "\n") +} + +func casinoFrame(mode, text string) string { + spec := color.NoColor() + spec.Fg = 244 + return color.Render(mode, spec, text) +} + +func colorSlotSymbol(mode, symbol string) string { + spec := color.NoColor() + spec.Fg = 250 + switch symbol { + case "straw": + spec = color.NoColor() + spec.Gradient = []int{220, 226} + case "stick": + spec = color.NoColor() + spec.Gradient = []int{34, 46} + case "brick": + spec = color.NoColor() + spec.Gradient = []int{160, 196} + case "hat": + spec = color.NoColor() + spec.Gradient = []int{129, 201} + case "wolf": + spec = color.NoColor() + spec.Gradient = []int{27, 39} + case "scatter": + spec = color.NoColor() + spec.Gradient = []int{196, 220, 46, 51, 129, 201} + default: + spec.Dim = true + } + return color.Render(mode, spec, symbol) +} diff --git a/internal/game/casino_test.go b/internal/game/casino_test.go new file mode 100644 index 0000000..b2b37c4 --- /dev/null +++ b/internal/game/casino_test.go @@ -0,0 +1,29 @@ +package game + +import ( + "strings" + "testing" + + "thehouseoficarus/internal/casino" + "thehouseoficarus/internal/color" +) + +func TestRenderSlotSnapshotColorsWordSymbols(t *testing.T) { + snapshot := &casino.SlotSnapshot{StoppedReels: 1} + snapshot.Grid[0][0] = "scatter" + if !strings.Contains(renderSlotSnapshot(snapshot, "none", false), "scatter") { + t.Fatal("expected word-based slot symbols") + } + output := renderSlotSnapshot(snapshot, "xterm256", true) + if !strings.Contains(output, "\033[38;5;") { + t.Fatalf("expected colored slot symbols, got %q", output) + } + for _, line := range strings.Split(output, "\n") { + if color.VisibleLen(line) != 51 { + t.Fatalf("line visible width = %d, want 51: %q", color.VisibleLen(line), line) + } + } + if !strings.Contains(output, "┌") || !strings.Contains(output, "└") { + t.Fatalf("slot output lacks the Unicode frame: %q", output) + } +} diff --git a/internal/game/cmd_move.go b/internal/game/cmd_move.go index 761db2f..4772a2c 100644 --- a/internal/game/cmd_move.go +++ b/internal/game/cmd_move.go @@ -13,6 +13,10 @@ import ( func (g *Game) doMove(sess *net.Session, dir string, isWalk bool) { p := sess.Player + if _, playing := g.Casino.Participation(p.Name); playing { + sess.WriteLine("You're playing a game. Type \"stop\" between rounds before moving.") + return + } exitDir := g.World.ResolveExit(dir) if exitDir == "" { sess.WriteLine("Go where?") diff --git a/internal/game/cmd_quit.go b/internal/game/cmd_quit.go index 12d3879..b7ec972 100644 --- a/internal/game/cmd_quit.go +++ b/internal/game/cmd_quit.go @@ -11,6 +11,10 @@ func (g *Game) executeQuit(sess *net.Session, args []string, rawInput string) { func (g *Game) doQuit(sess *net.Session) { p := sess.Player + if _, playing := g.Casino.Participation(p.Name); playing { + sess.WriteLine(g.colorize(sess, "warning", "WARNING: You're in the middle of a game!")) + g.emitCasinoEvents(g.Casino.MarkDisconnected(p.Name)) + } if g.Combat.Get(p.Name) != nil { sess.WriteLine("You can't rest during combat!") diff --git a/internal/game/cmd_registry.go b/internal/game/cmd_registry.go index d03993a..4c41216 100644 --- a/internal/game/cmd_registry.go +++ b/internal/game/cmd_registry.go @@ -23,6 +23,11 @@ var commandRegistry = map[string]commandDef{ "attack": {(*Game).executeAttack, ClassActive}, "kill": {(*Game).executeAttack, ClassActive}, "work": {(*Game).executeWork, ClassActive}, + "play": {(*Game).executePlay, ClassActive}, + "bet": {(*Game).executeBet, ClassActive}, + "spin": {(*Game).executeBet, ClassActive}, + "autobet": {(*Game).executeAutoBet, ClassActive}, + "autospin": {(*Game).executeAutoBet, ClassActive}, "style": {(*Game).executeStyle, ClassInstant}, "look": {(*Game).executeLook, ClassInstant}, "l": {(*Game).executeLook, ClassInstant}, diff --git a/internal/game/cmd_stop.go b/internal/game/cmd_stop.go index d1b8faa..5c347e6 100644 --- a/internal/game/cmd_stop.go +++ b/internal/game/cmd_stop.go @@ -6,6 +6,18 @@ import ( func (g *Game) executeStop(sess *net.Session, args []string, rawInput string) { p := sess.Player + if table, playing := g.Casino.Participation(p.Name); playing { + if table != nil { + g.emitCasinoEvents(g.Casino.Leave(table.RoomID, table.Config.ID, p.Name)) + } else if machine, ok := g.Casino.MachineFor(p.Name); ok { + if events, stopped := g.Casino.StopMachineAutoBet(machine.RoomID, machine.Config.ID, p.Name); stopped { + g.emitCasinoEvents(events) + return + } + g.emitCasinoEvents(g.Casino.LeaveMachine(machine.RoomID, machine.Config.ID, p.Name)) + } + return + } ss, _ := g.safespot.Get(p.Name) if p.Action == nil && p.BackgroundAction == nil && g.Combat.Get(p.Name) == nil && p.MoveTicks == 0 && len(p.WalkSequence) == 0 && !ss.Active { sess.WriteLine("You're not doing anything.") diff --git a/internal/game/core_login_char.go b/internal/game/core_login_char.go index 38499e2..4f59f1b 100644 --- a/internal/game/core_login_char.go +++ b/internal/game/core_login_char.go @@ -108,6 +108,7 @@ func (g *Game) connectCharacter(sess *net.Session, name string) { if g.Hub != nil { g.Hub.EnterRoom(sess, p.RoomID) } + g.Casino.MarkConnected(name) g.doLook(sess) g.checkAggro(sess) diff --git a/internal/game/game.go b/internal/game/game.go index 700877b..cac0ec9 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "thehouseoficarus/internal/casino" "thehouseoficarus/internal/combat" "thehouseoficarus/internal/config" "thehouseoficarus/internal/engine" @@ -31,13 +32,13 @@ const ( // constructed once at startup and never replaced. Deps is embedded in Game, so // game code accesses them directly (e.g. g.World, g.ItemStore). type Deps struct { - World *world.World - ObjectStore *object.ObjectStore - ItemStore *item.ItemStore - AccountStore *player.AccountStore - MobStore *world.MobStore - CraftIndex *CraftIndex - CourseStore *CourseStore + World *world.World + ObjectStore *object.ObjectStore + ItemStore *item.ItemStore + AccountStore *player.AccountStore + MobStore *world.MobStore + CraftIndex *CraftIndex + CourseStore *CourseStore Ticks *engine.Engine ColorConfig *config.ColorsConfig ConstantColorConfig *config.ColorsConfig @@ -53,6 +54,7 @@ type Game struct { Hub *net.Hub GlobalFlags *GlobalFlagStore Combat *combat.Tracker + Casino *casino.Manager flagIndex *flagTriggerIndex queue *CommandQueue safespot *SafespotManager @@ -83,7 +85,7 @@ func New(dataDir string, colorConfig *config.ColorsConfig, constantColorConfig * ObjectStore: object.NewObjectStore(dataDir), ItemStore: item.NewItemStore(dataDir), AccountStore: player.NewAccountStore(dataDir), - MobStore: world.NewMobStore(dataDir), + MobStore: world.NewMobStore(dataDir), CraftIndex: NewCraftIndex(), CourseStore: NewCourseStore(dataDir), Ticks: engine.New(), @@ -93,6 +95,7 @@ func New(dataDir string, colorConfig *config.ColorsConfig, constantColorConfig * }, GlobalFlags: NewGlobalFlagStore(), Combat: combat.NewTracker(), + Casino: casino.NewManager(time.Now().UnixNano()), flagIndex: newFlagTriggerIndex(), queue: NewCommandQueue(), safespot: NewSafespotManager(), @@ -131,6 +134,11 @@ func (g *Game) SetHub(hub *net.Hub) { } } }) + hub.OnDisconnect(func(sess *net.Session) { + if sess.Player != nil { + g.emitCasinoEvents(g.Casino.MarkDisconnected(sess.Player.Name)) + } + }) g.GlobalFlags.OnChange(func(name string, value any) { g.fireGlobalFlagTriggers(name, value) }) @@ -339,8 +347,9 @@ func (g *Game) ProcessQueuedCommands() { ss, _ := g.safespot.Get(p.Name) isHiding := ss.Active isBusy := p.Action != nil || len(p.WalkSequence) > 0 || g.Combat.Get(p.Name) != nil || p.MoveTicks > 0 || isHiding + isCasinoSpin := g.Casino != nil && g.Casino.MachineBusy(p.Name) _, isResting := g.restTimers[p.Name] - if !isResting && !isBusy && qc.Session.State == net.StateGame { + if !isResting && !isBusy && !isCasinoSpin && qc.Session.State == net.StateGame { g.writePrompt(qc.Session) } } diff --git a/internal/game/look_entities.go b/internal/game/look_entities.go index dd2cdf0..4ed47c9 100644 --- a/internal/game/look_entities.go +++ b/internal/game/look_entities.go @@ -5,6 +5,7 @@ import ( "sort" "strings" + "thehouseoficarus/internal/casino" "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" @@ -73,7 +74,7 @@ func (g *Game) showRoomMobs(sess *net.Session, p *player.Player, room *world.Roo func (g *Game) showRoomObjects(sess *net.Session, p *player.Player, room *world.Room) []string { objs := g.World.AllObjInstances(p.RoomID) if len(objs) == 0 { - return g.showFarmPatches(sess, p) + return appendRoomCasinos(g.showFarmPatches(sess, p), g.showRoomCasinos(sess, room)) } var lines []string lines = append(lines, "") @@ -220,9 +221,43 @@ func (g *Game) showRoomObjects(sess *net.Session, p *player.Player, room *world. } lines = append(lines, g.showFarmPatches(sess, p)...) + return appendRoomCasinos(lines, g.showRoomCasinos(sess, room)) +} + +func (g *Game) showRoomCasinos(sess *net.Session, room *world.Room) []string { + if room == nil || (len(room.CasinoTables) == 0 && len(room.CasinoMachines) == 0) { + return nil + } + var lines []string + for _, table := range room.CasinoTables { + name := casinoGameLabel(table.Game) + " table" + lines = append(lines, fmt.Sprintf("A %s is here.", g.colorize(sess, "casino_action", name))) + } + for _, machine := range room.CasinoMachines { + name := casinoGameLabel(machine.Game) + " machine" + lines = append(lines, fmt.Sprintf("A %s is here.", g.colorize(sess, "casino_action", name))) + } return lines } +func appendRoomCasinos(lines, casinos []string) []string { + if len(casinos) == 0 { + return lines + } + if len(lines) == 0 || lines[len(lines)-1] != "" { + lines = append(lines, "") + } + return append(lines, casinos...) +} + +func casinoGameLabel(game casino.GameName) string { + label := strings.ReplaceAll(string(game), "_", " ") + if label == "" { + return "casino" + } + return label +} + func (g *Game) showGroundItems(sess *net.Session, p *player.Player, room *world.Room) []string { ground := g.World.GroundItemsDetailed(p.RoomID) if len(ground) == 0 { diff --git a/internal/game/render_help.go b/internal/game/render_help.go index 7b7efa2..8af3096 100644 --- a/internal/game/render_help.go +++ b/internal/game/render_help.go @@ -53,6 +53,10 @@ var commandList = []cmdEntry{ {"jack / jackin", "Active", "Jack into a terminal (Hacking)"}, {"look / l", "Instant", "Look around or examine things"}, {"map", "Instant", "Display an ASCII map of the area"}, + {"play", "Active", "Join a casino game in the current room"}, + {"bet", "Active", "Place a casino wager"}, + {"autobet / autospin", "Active", "Automatically repeat a casino wager"}, + {"spin", "Active", "Spin the current casino wager"}, {"mine", "Active", "Mine rocks (Mining)"}, {"mix", "Active", "Mix potions (Pharmacy)"}, {"mods / modlist", "Instant", "List available science modules"}, diff --git a/internal/game/tick_systems.go b/internal/game/tick_systems.go index 4d8d4b6..b819454 100644 --- a/internal/game/tick_systems.go +++ b/internal/game/tick_systems.go @@ -27,6 +27,7 @@ func TickSystemOrder() []struct{ Name string } { var tickSystemOrder = []tickSystem{ {"ProcessQueuedCommands", (*Game).ProcessQueuedCommands}, + {"CasinoTick", (*Game).CasinoTick}, {"MoveTick", (*Game).MoveTick}, {"SequenceTick", (*Game).SequenceTick}, {"TransientMobTick", (*Game).TransientMobTick}, @@ -57,4 +58,4 @@ func (g *Game) RunTickSystems() { for _, s := range tickSystemOrder { s.Run(g) } -}
\ No newline at end of file +} diff --git a/internal/game/tick_systems_test.go b/internal/game/tick_systems_test.go index 6b44e91..2fa67ac 100644 --- a/internal/game/tick_systems_test.go +++ b/internal/game/tick_systems_test.go @@ -22,6 +22,7 @@ import ( // contract. var expectedTickSystemOrder = []string{ "ProcessQueuedCommands", + "CasinoTick", "MoveTick", "SequenceTick", "TransientMobTick", @@ -144,4 +145,4 @@ func newRunTickSystemsTestGame() *Game { hackingStates: map[string]*hacking.Session{}, sequences: map[string]*sequence{}, } -}
\ No newline at end of file +} |
