From ab2597b22ccdb71116992aec78080d9858358d04 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 7 Jul 2026 16:24:27 -0400 Subject: rename flags to global_flags (differentiate from player_flags) --- internal/admin/api_flags.go | 14 -------- internal/admin/api_global_flags.go | 14 ++++++++ internal/admin/server.go | 2 +- internal/behavior/behavior.go | 4 +-- internal/game/act.go | 7 ++-- internal/game/act_room.go | 10 +++--- internal/game/act_steal.go | 2 +- internal/game/act_talk.go | 8 ++--- internal/game/cmd_inspect.go | 8 ++--- internal/game/cmd_move.go | 8 ++--- internal/game/cmd_registry.go | 2 +- internal/game/cmd_room_insert.go | 4 +-- internal/game/cmd_room_remove.go | 4 +-- internal/game/cmd_setflag.go | 38 -------------------- internal/game/cmd_setglobalflag.go | 38 ++++++++++++++++++++ internal/game/condition_test.go | 22 ++++++------ internal/game/core_flagstore.go | 30 ++++++++-------- internal/game/exit_discovery_test.go | 6 ++-- internal/game/game.go | 10 +++--- internal/game/map_test.go | 16 ++++----- internal/game/sys_triggers.go | 20 +++++------ internal/player/player.go | 4 +-- internal/world/grid_test.go | 4 +-- internal/world/insert_remove.go | 2 +- internal/world/room.go | 6 ++-- internal/world/room_migrate_test.go | 6 ++-- internal/world/trigger.go | 8 ++--- internal/world/trigger_store.go | 68 ++++++++++++++++++------------------ 28 files changed, 183 insertions(+), 182 deletions(-) delete mode 100644 internal/admin/api_flags.go create mode 100644 internal/admin/api_global_flags.go delete mode 100644 internal/game/cmd_setflag.go create mode 100644 internal/game/cmd_setglobalflag.go (limited to 'internal') diff --git a/internal/admin/api_flags.go b/internal/admin/api_flags.go deleted file mode 100644 index e2594f3..0000000 --- a/internal/admin/api_flags.go +++ /dev/null @@ -1,14 +0,0 @@ -package admin - -import "net/http" - -func (s *AdminServer) handleFlags(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) - return - } - writeJSON(w, map[string]any{ - "flags": []any{}, - "note": "world flags are in-memory only", - }) -} diff --git a/internal/admin/api_global_flags.go b/internal/admin/api_global_flags.go new file mode 100644 index 0000000..ab286ad --- /dev/null +++ b/internal/admin/api_global_flags.go @@ -0,0 +1,14 @@ +package admin + +import "net/http" + +func (s *AdminServer) handleGlobalFlags(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + writeJSON(w, map[string]any{ + "global_flags": []any{}, + "note": "global flags are in-memory only", + }) +} diff --git a/internal/admin/server.go b/internal/admin/server.go index 17835db..f06b7cf 100644 --- a/internal/admin/server.go +++ b/internal/admin/server.go @@ -167,7 +167,7 @@ func NewServer(cfg *config.Config, useTLS bool, accountStore *player.AccountStor apiMux.HandleFunc("/api/courses/", s.handleCourseByID) apiMux.HandleFunc("/api/players", s.handlePlayers) apiMux.HandleFunc("/api/dashboard", s.handleDashboard) - apiMux.HandleFunc("/api/flags", s.handleFlags) + apiMux.HandleFunc("/api/global_flags", s.handleGlobalFlags) apiMux.HandleFunc("/api/tools", s.handleTools) apiMux.HandleFunc("/api/search", s.handleSearch) apiMux.HandleFunc("/api/undo/state", s.handleUndoState) diff --git a/internal/behavior/behavior.go b/internal/behavior/behavior.go index 7d8ce8f..ec9fc7c 100644 --- a/internal/behavior/behavior.go +++ b/internal/behavior/behavior.go @@ -43,7 +43,7 @@ type TalkOption struct { } type NodeAction struct { - SetFlags map[string]any `yaml:"set_flags"` + SetGlobalFlags map[string]any `yaml:"set_global_flags"` SetPlayerFlags map[string]any `yaml:"set_player_flags"` GiveItem string `yaml:"give_item"` TakeItem string `yaml:"take_item"` @@ -143,7 +143,7 @@ func (c *ShopConfig) FindItem(itemID string) *ShopItem { } type Condition struct { - Flag string `yaml:"flag"` + GlobalFlag string `yaml:"global_flag"` Value any `yaml:"value"` Not bool `yaml:"not"` PlayerFlag string `yaml:"player_flag"` diff --git a/internal/game/act.go b/internal/game/act.go index f2ea121..ddeed04 100644 --- a/internal/game/act.go +++ b/internal/game/act.go @@ -297,8 +297,8 @@ func (g *Game) checkCondition(sess *net.Session, c *behavior.Condition) bool { return flagMatches(present, val, c.Value, c.Not) } - if c.Flag != "" { - val, present := g.Flags.Get(c.Flag) + if c.GlobalFlag != "" { + val, present := g.GlobalFlags.Get(c.GlobalFlag) return flagMatches(present, val, c.Value, c.Not) } if c.HasItem != "" { @@ -318,7 +318,8 @@ func (g *Game) checkCondition(sess *net.Session, c *behavior.Condition) bool { return true } -// flagMatches evaluates a flag/player_flag condition. +// flagMatches evaluates a global_flag/player_flag condition. The name is +// historical; it evaluates both flag types. // // If the condition specifies no `value`, the flag matches when it is present // and truthy (so `{player_flag: x}` means "x is set" and diff --git a/internal/game/act_room.go b/internal/game/act_room.go index ddca261..da74d6e 100644 --- a/internal/game/act_room.go +++ b/internal/game/act_room.go @@ -161,8 +161,8 @@ func (g *Game) fireEnterStep(seq *enterSeq, step world.EnterStep) { } } } - if len(step.SetFlags) > 0 || len(step.SetPlayerFlags) > 0 { - g.applyFlagMutations(p, step.SetFlags, step.SetPlayerFlags) + if len(step.SetGlobalFlags) > 0 || len(step.SetPlayerFlags) > 0 { + g.applyFlagMutations(p, step.SetGlobalFlags, step.SetPlayerFlags) g.AccountStore.SaveCharacter(p) } if step.SpawnMob != nil { @@ -229,10 +229,10 @@ func (g *Game) isCharLive(name string, sess *net.Session) bool { return g.loggedInChars[name] == sess } -// applyFlagMutations sets world and player flags, shared by on_enter steps and +// applyFlagMutations sets global and player flags, shared by on_enter steps and // exit traversal. -func (g *Game) applyFlagMutations(p *player.Player, setFlags, setPlayerFlags map[string]any) { - g.Flags.SetAll(setFlags) +func (g *Game) applyFlagMutations(p *player.Player, setGlobalFlags, setPlayerFlags map[string]any) { + g.GlobalFlags.SetAll(setGlobalFlags) if len(setPlayerFlags) > 0 { for k, v := range setPlayerFlags { g.setPlayerFlag(p, k, v) diff --git a/internal/game/act_steal.go b/internal/game/act_steal.go index b5c1210..0aae6d1 100644 --- a/internal/game/act_steal.go +++ b/internal/game/act_steal.go @@ -47,7 +47,7 @@ var stallGuardTalk = &behavior.TalkConfig{ }, "fight": { Messages: []string{"Then defend yourself!"}, - Action: &behavior.NodeAction{SetFlags: map[string]any{"guard_hostile": true}}, + Action: &behavior.NodeAction{SetGlobalFlags: map[string]any{"guard_hostile": true}}, Options: []behavior.TalkOption{{Text: "(The guard attacks!)"}}, }, }, diff --git a/internal/game/act_talk.go b/internal/game/act_talk.go index 7cfdf7c..ca6054c 100644 --- a/internal/game/act_talk.go +++ b/internal/game/act_talk.go @@ -60,8 +60,8 @@ func (g *Game) startTalk(sess *net.Session, p *player.Player, obj *object.Object func (g *Game) handleNodeAction(sess *net.Session, na *behavior.NodeAction) (intercepted bool) { g.applyNodeAction(sess, na) - if v, ok := g.Flags.Get("guard_hostile"); ok && v != nil { - g.Flags.Delete("guard_hostile") + if v, ok := g.GlobalFlags.Get("guard_hostile"); ok && v != nil { + g.GlobalFlags.Delete("guard_hostile") p := sess.Player if p != nil && p.Action != nil { if td, ok := p.Action.Data.(*behavior.TalkData); ok && td.StealGuard { @@ -348,8 +348,8 @@ func (g *Game) applyNodeAction(sess *net.Session, na *behavior.NodeAction) { g.AccountStore.SaveCharacter(p) } - for k, v := range na.SetFlags { - g.Flags.Set(k, v) + for k, v := range na.SetGlobalFlags { + g.GlobalFlags.Set(k, v) } for k, v := range na.SetPlayerFlags { g.setPlayerFlag(p, k, v) diff --git a/internal/game/cmd_inspect.go b/internal/game/cmd_inspect.go index 62392b7..7488591 100644 --- a/internal/game/cmd_inspect.go +++ b/internal/game/cmd_inspect.go @@ -92,8 +92,8 @@ func (g *Game) executeInspect(sess *net.Session, args []string, rawInput string) sess.WriteLine(fmt.Sprintf("\nRoom Triggers: %d", len(room.Triggers))) for _, trigger := range room.Triggers { kind := "" - if trigger.OnFlag != "" { - kind = fmt.Sprintf("world flag %q", trigger.OnFlag) + if trigger.OnGlobalFlag != "" { + kind = fmt.Sprintf("global flag %q", trigger.OnGlobalFlag) } else if trigger.OnPlayerFlag != "" { kind = fmt.Sprintf("player flag %q", trigger.OnPlayerFlag) } @@ -101,8 +101,8 @@ func (g *Game) executeInspect(sess *net.Session, args []string, rawInput string) } } - sess.WriteLine("\n--- World Flags ---") - allFlags := g.Flags.All() + sess.WriteLine("\n--- Global Flags ---") + allFlags := g.GlobalFlags.All() if len(allFlags) == 0 { sess.WriteLine(" (none)") } else { diff --git a/internal/game/cmd_move.go b/internal/game/cmd_move.go index f236d67..2f27eed 100644 --- a/internal/game/cmd_move.go +++ b/internal/game/cmd_move.go @@ -67,7 +67,7 @@ func (g *Game) doMove(sess *net.Session, dir string, multiplier float64) { } } - p.MovePendingFlags = exitDef.SetFlags + p.MovePendingGlobalFlags = exitDef.SetGlobalFlags p.MovePendingPlayerFlags = exitDef.SetPlayerFlags inCombat := g.Combat.Get(p.Name) != nil @@ -132,7 +132,7 @@ func (g *Game) moveTicks(p *player.Player, multiplier float64) int { func (g *Game) completeMove(sess *net.Session, p *player.Player) { exitDir := p.MoveDirection targetID := p.MoveTarget - pendingFlags := p.MovePendingFlags + pendingGlobalFlags := p.MovePendingGlobalFlags pendingPlayerFlags := p.MovePendingPlayerFlags p.ClearMoveState() @@ -163,8 +163,8 @@ func (g *Game) completeMove(sess *net.Session, p *player.Player) { if p.EnterSeqRoom != 0 && p.EnterSeqRoom == oldRoom { p.EnterSeqRoom = 0 } - if len(pendingFlags) > 0 || len(pendingPlayerFlags) > 0 { - g.applyFlagMutations(p, pendingFlags, pendingPlayerFlags) + if len(pendingGlobalFlags) > 0 || len(pendingPlayerFlags) > 0 { + g.applyFlagMutations(p, pendingGlobalFlags, pendingPlayerFlags) } g.AccountStore.SaveCharacter(p) diff --git a/internal/game/cmd_registry.go b/internal/game/cmd_registry.go index 462bf53..e2c34aa 100644 --- a/internal/game/cmd_registry.go +++ b/internal/game/cmd_registry.go @@ -150,7 +150,7 @@ var commandRegistry = map[string]commandDef{ "goto": {(*Game).executeGoto, ClassInstant}, "summon": {(*Game).executeSummon, ClassInstant}, "dig": {(*Game).executeDig, ClassInstant}, - "setflag": {(*Game).executeSetFlag, ClassInstant}, + "setglobalflag": {(*Game).executeSetGlobalFlag, ClassInstant}, "setplayerflag": {(*Game).executeSetPlayerFlag, ClassInstant}, "reload": {(*Game).executeReload, ClassInstant}, "shutdown": {(*Game).executeShutdown, ClassInstant}, diff --git a/internal/game/cmd_room_insert.go b/internal/game/cmd_room_insert.go index b72591f..713c5ee 100644 --- a/internal/game/cmd_room_insert.go +++ b/internal/game/cmd_room_insert.go @@ -138,7 +138,7 @@ func (g *Game) roomInsert(sess *net.Session, args []string) { Room: newID, Condition: exitDef.Condition, BlockedMessage: exitDef.BlockedMessage, - SetFlags: exitDef.SetFlags, + SetGlobalFlags: exitDef.SetGlobalFlags, SetPlayerFlags: exitDef.SetPlayerFlags, Hidden: exitDef.Hidden, AlwaysBlocked: exitDef.AlwaysBlocked, @@ -158,7 +158,7 @@ func (g *Game) roomInsert(sess *net.Session, args []string) { Room: newID, Condition: targetExit.Condition, BlockedMessage: targetExit.BlockedMessage, - SetFlags: targetExit.SetFlags, + SetGlobalFlags: targetExit.SetGlobalFlags, SetPlayerFlags: targetExit.SetPlayerFlags, Hidden: targetExit.Hidden, AlwaysBlocked: targetExit.AlwaysBlocked, diff --git a/internal/game/cmd_room_remove.go b/internal/game/cmd_room_remove.go index 78c1234..28433ff 100644 --- a/internal/game/cmd_room_remove.go +++ b/internal/game/cmd_room_remove.go @@ -171,7 +171,7 @@ func (g *Game) roomRemove(sess *net.Session, args []string) { Room: cID, Condition: aExit.Condition, BlockedMessage: aExit.BlockedMessage, - SetFlags: aExit.SetFlags, + SetGlobalFlags: aExit.SetGlobalFlags, SetPlayerFlags: aExit.SetPlayerFlags, Hidden: aExit.Hidden, AlwaysBlocked: aExit.AlwaysBlocked, @@ -191,7 +191,7 @@ func (g *Game) roomRemove(sess *net.Session, args []string) { Room: aID, Condition: cOppExit.Condition, BlockedMessage: cOppExit.BlockedMessage, - SetFlags: cOppExit.SetFlags, + SetGlobalFlags: cOppExit.SetGlobalFlags, SetPlayerFlags: cOppExit.SetPlayerFlags, Hidden: cOppExit.Hidden, AlwaysBlocked: cOppExit.AlwaysBlocked, diff --git a/internal/game/cmd_setflag.go b/internal/game/cmd_setflag.go deleted file mode 100644 index a18c635..0000000 --- a/internal/game/cmd_setflag.go +++ /dev/null @@ -1,38 +0,0 @@ -package game - -import ( - "fmt" - "strconv" - - "thehouseoficarus/internal/net" -) - -func (g *Game) executeSetFlag(sess *net.Session, args []string, rawInput string) { - if !g.checkAdmin(sess) { - sess.WriteLine("Unknown command.") - return - } - if len(args) == 0 { - sess.WriteLine("Usage: setflag [value]") - return - } - name := args[0] - var value any = true - if len(args) > 1 { - valStr := args[1] - switch valStr { - case "true": - value = true - case "false": - value = false - default: - if n, err := strconv.Atoi(valStr); err == nil { - value = n - } else { - value = valStr - } - } - } - g.Flags.Set(name, value) - sess.WriteLine(fmt.Sprintf("Flag '%s' set to %v.", name, value)) -} diff --git a/internal/game/cmd_setglobalflag.go b/internal/game/cmd_setglobalflag.go new file mode 100644 index 0000000..1ac5080 --- /dev/null +++ b/internal/game/cmd_setglobalflag.go @@ -0,0 +1,38 @@ +package game + +import ( + "fmt" + "strconv" + + "thehouseoficarus/internal/net" +) + +func (g *Game) executeSetGlobalFlag(sess *net.Session, args []string, rawInput string) { + if !g.checkAdmin(sess) { + sess.WriteLine("Unknown command.") + return + } + if len(args) == 0 { + sess.WriteLine("Usage: setglobalflag [value]") + return + } + name := args[0] + var value any = true + if len(args) > 1 { + valStr := args[1] + switch valStr { + case "true": + value = true + case "false": + value = false + default: + if n, err := strconv.Atoi(valStr); err == nil { + value = n + } else { + value = valStr + } + } + } + g.GlobalFlags.Set(name, value) + sess.WriteLine(fmt.Sprintf("Global flag '%s' set to %v.", name, value)) +} diff --git a/internal/game/condition_test.go b/internal/game/condition_test.go index f365f2e..f7a5dc6 100644 --- a/internal/game/condition_test.go +++ b/internal/game/condition_test.go @@ -39,7 +39,7 @@ func TestIsTruthy(t *testing.T) { } func TestCheckConditionPlayerFlagTruthy(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} set := sessWithFlags(map[string]any{"x": true}) unset := sessWithFlags(map[string]any{}) @@ -73,7 +73,7 @@ func TestCheckConditionPlayerFlagTruthy(t *testing.T) { } func TestCheckConditionValueComparisonPreserved(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} sess := sessWithFlags(map[string]any{"n": 1}) if !g.checkCondition(sess, &behavior.Condition{PlayerFlag: "n", Value: 1}) { @@ -87,24 +87,24 @@ func TestCheckConditionValueComparisonPreserved(t *testing.T) { } } -func TestCheckConditionWorldFlag(t *testing.T) { - g := &Game{Flags: NewFlagStore()} - g.Flags.Set("gate_open", true) +func TestCheckConditionGlobalFlag(t *testing.T) { + g := &Game{GlobalFlags: NewGlobalFlagStore()} + g.GlobalFlags.Set("gate_open", true) sess := sessWithFlags(map[string]any{}) - if !g.checkCondition(sess, &behavior.Condition{Flag: "gate_open"}) { - t.Error("world flag truthy check should pass") + if !g.checkCondition(sess, &behavior.Condition{GlobalFlag: "gate_open"}) { + t.Error("global flag truthy check should pass") } - if g.checkCondition(sess, &behavior.Condition{Flag: "gate_open", Not: true}) { + if g.checkCondition(sess, &behavior.Condition{GlobalFlag: "gate_open", Not: true}) { t.Error("negated world flag should fail when set") } - if g.checkCondition(sess, &behavior.Condition{Flag: "missing"}) { + if g.checkCondition(sess, &behavior.Condition{GlobalFlag: "missing"}) { t.Error("missing world flag should not pass") } } func TestResolveObjDescPresence(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} def := &object.ObjectDef{ Description: behavior.DescList{ @@ -140,7 +140,7 @@ func TestResolveObjDescPresence(t *testing.T) { } func TestRoomDescriptionSelection(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} room := &world.Room{ Description: behavior.DescList{ {Text: "crowd", Condition: &behavior.Condition{PlayerFlag: "done", Not: true}}, diff --git a/internal/game/core_flagstore.go b/internal/game/core_flagstore.go index ecefccf..18578b7 100644 --- a/internal/game/core_flagstore.go +++ b/internal/game/core_flagstore.go @@ -2,37 +2,37 @@ package game import "sync" -// FlagChangeCallback is invoked when a world flag value actually changes +// GlobalFlagChangeCallback is invoked when a global flag value actually changes // (old value differs from new, or new flag is created with a truthy value). -type FlagChangeCallback func(name string, value any) +type GlobalFlagChangeCallback func(name string, value any) -// FlagStore holds world flags — shared mutable state visible to all players -// (e.g. opened doors, quest state). Player-specific flags live on -// *player.Player.Flags instead. FlagStore is safe for concurrent use. -type FlagStore struct { +// GlobalFlagStore holds global flags — shared mutable state visible to all +// players (e.g. opened doors, quest state). Player-specific flags live on +// *player.Player.Flags instead. GlobalFlagStore is safe for concurrent use. +type GlobalFlagStore struct { mu sync.Mutex flags map[string]any - callbacks []FlagChangeCallback + callbacks []GlobalFlagChangeCallback } -func NewFlagStore() *FlagStore { - return &FlagStore{flags: make(map[string]any)} +func NewGlobalFlagStore() *GlobalFlagStore { + return &GlobalFlagStore{flags: make(map[string]any)} } -func (f *FlagStore) OnChange(cb FlagChangeCallback) { +func (f *GlobalFlagStore) OnChange(cb GlobalFlagChangeCallback) { f.mu.Lock() defer f.mu.Unlock() f.callbacks = append(f.callbacks, cb) } -func (f *FlagStore) Get(name string) (any, bool) { +func (f *GlobalFlagStore) Get(name string) (any, bool) { f.mu.Lock() defer f.mu.Unlock() v, ok := f.flags[name] return v, ok } -func (f *FlagStore) Set(name string, value any) { +func (f *GlobalFlagStore) Set(name string, value any) { f.mu.Lock() old, existed := f.flags[name] f.flags[name] = value @@ -46,7 +46,7 @@ func (f *FlagStore) Set(name string, value any) { } } -func (f *FlagStore) SetAll(m map[string]any) { +func (f *GlobalFlagStore) SetAll(m map[string]any) { f.mu.Lock() changed := make(map[string]any) for k, v := range m { @@ -66,13 +66,13 @@ func (f *FlagStore) SetAll(m map[string]any) { } } -func (f *FlagStore) Delete(name string) { +func (f *GlobalFlagStore) Delete(name string) { f.mu.Lock() defer f.mu.Unlock() delete(f.flags, name) } -func (f *FlagStore) All() map[string]any { +func (f *GlobalFlagStore) All() map[string]any { f.mu.Lock() defer f.mu.Unlock() out := make(map[string]any, len(f.flags)) diff --git a/internal/game/exit_discovery_test.go b/internal/game/exit_discovery_test.go index 3c0b360..4bf1023 100644 --- a/internal/game/exit_discovery_test.go +++ b/internal/game/exit_discovery_test.go @@ -28,7 +28,7 @@ func TestExitDiscoveredUndiscovered(t *testing.T) { } func TestExitDiscoveredAfterMark(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} p := &player.Player{} roomID := 42 dir := world.East @@ -54,7 +54,7 @@ func TestExitDiscoveredGodMode(t *testing.T) { } func TestExitDiscoveredDifferentRoom(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} p := &player.Player{} g.markExitDiscovered(p, 10, world.North) @@ -67,7 +67,7 @@ func TestExitDiscoveredDifferentRoom(t *testing.T) { } func TestExitDisplayState(t *testing.T) { - g := &Game{Flags: NewFlagStore()} + g := &Game{GlobalFlags: NewGlobalFlagStore()} const roomID = 7 dir := world.North diff --git a/internal/game/game.go b/internal/game/game.go index bf7bdc2..b9fb0af 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -44,13 +44,13 @@ type Deps struct { } // Game is the central orchestrator: it owns the data stores (via the embedded -// Deps), the shared mutable game state (flags, combat tracker, command queue, +// Deps), the shared mutable game state (global flags, combat tracker, command queue, // safespots), and the per-session runtime bookkeeping. type Game struct { Deps Hub *net.Hub - Flags *FlagStore + GlobalFlags *GlobalFlagStore Combat *combat.Tracker TriggerStore *world.TriggerStore queue *CommandQueue @@ -88,7 +88,7 @@ func New(dataDir string, colorConfig *config.ColorsConfig, valConfig config.Vali ColorConfig: colorConfig, DataDir: dataDir, }, - Flags: NewFlagStore(), + GlobalFlags: NewGlobalFlagStore(), Combat: combat.NewTracker(), TriggerStore: world.NewTriggerStore(), queue: NewCommandQueue(), @@ -127,8 +127,8 @@ func (g *Game) SetHub(hub *net.Hub) { } } }) - g.Flags.OnChange(func(name string, value any) { - g.TriggerStore.FireWorld(name, value) + g.GlobalFlags.OnChange(func(name string, value any) { + g.TriggerStore.FireGlobal(name, value) }) } diff --git a/internal/game/map_test.go b/internal/game/map_test.go index 159214c..2fe9c1e 100644 --- a/internal/game/map_test.go +++ b/internal/game/map_test.go @@ -29,10 +29,10 @@ func writeTempRoom(t *testing.T, dir string, id int, body string) { // links draw a bar, one-way links draw a directional arrow, outward-blocked // links draw a blocked 'X', and links with no traversable direction draw 'X'. func TestMapConnectorGlyphs(t *testing.T) { - const condEast = "name: One\nexits:\n east:\n room: 2\n condition:\n flag: gate_open\n" - const condSouth = "name: Three\nexits:\n south:\n room: 2\n condition:\n flag: gate_open\n" - const condNE = "name: One\nexits:\n northeast:\n room: 2\n condition:\n flag: gate_open\n" - const condSE = "name: One\nexits:\n southeast:\n room: 2\n condition:\n flag: gate_open\n" + const condEast = "name: One\nexits:\n east:\n room: 2\n condition:\n global_flag: gate_open\n" + const condSouth = "name: Three\nexits:\n south:\n room: 2\n condition:\n global_flag: gate_open\n" + const condNE = "name: One\nexits:\n northeast:\n room: 2\n condition:\n global_flag: gate_open\n" + const condSE = "name: One\nexits:\n southeast:\n room: 2\n condition:\n global_flag: gate_open\n" cases := []struct { name string @@ -161,9 +161,9 @@ func TestMapConnectorGlyphs(t *testing.T) { writeTempRoom(t, dir, 4, tc.room4) } - g := &Game{Deps: Deps{World: world.New(dir)}, Flags: NewFlagStore()} + g := &Game{Deps: Deps{World: world.New(dir)}, GlobalFlags: NewGlobalFlagStore()} if tc.flagOpen { - g.Flags.Set("gate_open", true) + g.GlobalFlags.Set("gate_open", true) } sess := &net.Session{Player: &player.Player{Flags: map[string]any{}}} @@ -401,7 +401,7 @@ func TestMap3DDisconnectedComponent(t *testing.T) { writeTempRoom(t, dir, 3, "name: Tower Two Base\nexits:\n up: 4\n west: 2\n") writeTempRoom(t, dir, 4, "name: Tower Two\nexits:\n down: 3\n") - g := &Game{Deps: Deps{World: world.New(dir)}, Flags: NewFlagStore()} + g := &Game{Deps: Deps{World: world.New(dir)}, GlobalFlags: NewGlobalFlagStore()} mg := mapGlyphsForPlayer(false) // Player has only visited tower 1. Tower 2 should appear but dimmed (unvisited). @@ -426,7 +426,7 @@ func TestMap3DDifferentZExcluded(t *testing.T) { writeTempRoom(t, dir, 1, "name: Ground\nexits:\n up: 2\n") writeTempRoom(t, dir, 2, "name: Upper\nexits:\n down: 1\n") - g := &Game{Deps: Deps{World: world.New(dir)}, Flags: NewFlagStore()} + g := &Game{Deps: Deps{World: world.New(dir)}, GlobalFlags: NewGlobalFlagStore()} mg := mapGlyphsForPlayer(false) sess := &net.Session{Player: &player.Player{ Stats: player.PlayerStats{RoomsVisited: map[int]bool{1: true, 2: true}}, diff --git a/internal/game/sys_triggers.go b/internal/game/sys_triggers.go index 7c77fc9..b542fdd 100644 --- a/internal/game/sys_triggers.go +++ b/internal/game/sys_triggers.go @@ -13,7 +13,7 @@ import ( func (g *Game) TriggerSeqTick() { g.processPlayerTriggerSequences() - g.processWorldTriggerSequences() + g.processGlobalTriggerSequences() } func (g *Game) TransientMobTick() { @@ -106,8 +106,8 @@ func (g *Game) processPlayerTriggerSequences() { } } -func (g *Game) processWorldTriggerSequences() { - seqs := g.TriggerStore.SnapshotWorldSeqs() +func (g *Game) processGlobalTriggerSequences() { + seqs := g.TriggerStore.SnapshotGlobalSeqs() for _, seq := range seqs { seq.Wait-- if seq.Wait > 0 { @@ -125,11 +125,11 @@ func (g *Game) processWorldTriggerSequences() { } for _, step := range jobs { - g.executeWorldTriggerStep(&step, seq.RoomID, seq.FlagValue) + g.executeGlobalTriggerStep(&step, seq.RoomID, seq.FlagValue) } if len(seq.Steps) == 0 { - g.TriggerStore.RemoveWorldSeq(seq.TriggerID) + g.TriggerStore.RemoveGlobalSeq(seq.TriggerID) } } } @@ -161,8 +161,8 @@ func (g *Game) executeTriggerStep(sess *net.Session, p *player.Player, step *wor } } } - if len(step.SetFlags) > 0 { - g.Flags.SetAll(step.SetFlags) + if len(step.SetGlobalFlags) > 0 { + g.GlobalFlags.SetAll(step.SetGlobalFlags) } if len(step.SetPlayerFlags) > 0 { for k, v := range step.SetPlayerFlags { @@ -204,7 +204,7 @@ func (g *Game) executeTriggerStep(sess *net.Session, p *player.Player, step *wor } } -func (g *Game) executeWorldTriggerStep(step *world.TriggerStep, roomID int, flagValue any) { +func (g *Game) executeGlobalTriggerStep(step *world.TriggerStep, roomID int, flagValue any) { if step.Broadcast != "" && g.Hub != nil { msg := expandTemplate(step.Broadcast, "", flagValue) broadcastSpec := g.resolveColor(nil, "broadcast") @@ -225,8 +225,8 @@ func (g *Game) executeWorldTriggerStep(step *world.TriggerStep, roomID int, flag } } } - if len(step.SetFlags) > 0 { - g.Flags.SetAll(step.SetFlags) + if len(step.SetGlobalFlags) > 0 { + g.GlobalFlags.SetAll(step.SetGlobalFlags) } if step.SpawnMob != nil { g.spawnWorldTriggerMob(step.SpawnMob, roomID) diff --git a/internal/player/player.go b/internal/player/player.go index 72eb455..65026e7 100644 --- a/internal/player/player.go +++ b/internal/player/player.go @@ -183,7 +183,7 @@ type Player struct { MoveTicks int `yaml:"-"` MoveDirection string `yaml:"-"` MoveTarget int `yaml:"-"` - MovePendingFlags map[string]any `yaml:"-"` + MovePendingGlobalFlags map[string]any `yaml:"-"` MovePendingPlayerFlags map[string]any `yaml:"-"` VisualTickCurrent int `yaml:"-"` AutotriggerMod string `yaml:"-"` @@ -219,7 +219,7 @@ func (p *Player) ClearMoveState() { p.MoveTicks = 0 p.MoveDirection = "" p.MoveTarget = 0 - p.MovePendingFlags = nil + p.MovePendingGlobalFlags = nil p.MovePendingPlayerFlags = nil } diff --git a/internal/world/grid_test.go b/internal/world/grid_test.go index 04d749c..9c2c7c6 100644 --- a/internal/world/grid_test.go +++ b/internal/world/grid_test.go @@ -117,11 +117,11 @@ func TestBuildGridConflictsHypotheticalInsert(t *testing.T) { copy.Exits = make(map[ExitDir]ExitDef, len(r.Exits)) for k, v := range r.Exits { if id == 1 && k == East { - copy.Exits[k] = ExitDef{Room: 5, Condition: v.Condition, BlockedMessage: v.BlockedMessage, SetFlags: v.SetFlags, SetPlayerFlags: v.SetPlayerFlags, Hidden: v.Hidden, AlwaysBlocked: v.AlwaysBlocked} + copy.Exits[k] = ExitDef{Room: 5, Condition: v.Condition, BlockedMessage: v.BlockedMessage, SetGlobalFlags: v.SetGlobalFlags, SetPlayerFlags: v.SetPlayerFlags, Hidden: v.Hidden, AlwaysBlocked: v.AlwaysBlocked} continue } if id == 2 && k == West { - copy.Exits[k] = ExitDef{Room: 5, Condition: v.Condition, BlockedMessage: v.BlockedMessage, SetFlags: v.SetFlags, SetPlayerFlags: v.SetPlayerFlags, Hidden: v.Hidden, AlwaysBlocked: v.AlwaysBlocked} + copy.Exits[k] = ExitDef{Room: 5, Condition: v.Condition, BlockedMessage: v.BlockedMessage, SetGlobalFlags: v.SetGlobalFlags, SetPlayerFlags: v.SetPlayerFlags, Hidden: v.Hidden, AlwaysBlocked: v.AlwaysBlocked} continue } copy.Exits[k] = v diff --git a/internal/world/insert_remove.go b/internal/world/insert_remove.go index 0811587..c55427c 100644 --- a/internal/world/insert_remove.go +++ b/internal/world/insert_remove.go @@ -20,7 +20,7 @@ func RewirePreserving(src ExitDef, newTarget int) ExitDef { Room: newTarget, Condition: src.Condition, BlockedMessage: src.BlockedMessage, - SetFlags: src.SetFlags, + SetGlobalFlags: src.SetGlobalFlags, SetPlayerFlags: src.SetPlayerFlags, Hidden: src.Hidden, AlwaysBlocked: src.AlwaysBlocked, diff --git a/internal/world/room.go b/internal/world/room.go index 29cce0b..2da40fb 100644 --- a/internal/world/room.go +++ b/internal/world/room.go @@ -78,7 +78,7 @@ type ExitDef struct { Room int `yaml:"room"` Condition *behavior.Condition `yaml:"condition,omitempty"` BlockedMessage string `yaml:"blocked_message,omitempty"` - SetFlags map[string]any `yaml:"set_flags,omitempty"` + SetGlobalFlags map[string]any `yaml:"set_global_flags,omitempty"` SetPlayerFlags map[string]any `yaml:"set_player_flags,omitempty"` Hidden bool `yaml:"hidden,omitempty"` AlwaysBlocked bool `yaml:"always_blocked,omitempty"` @@ -135,7 +135,7 @@ type EnterStep struct { Message string `yaml:"message"` Condition *behavior.Condition `yaml:"condition"` Delay int `yaml:"delay"` - SetFlags map[string]any `yaml:"set_flags"` + SetGlobalFlags map[string]any `yaml:"set_global_flags"` SetPlayerFlags map[string]any `yaml:"set_player_flags"` Broadcast string `yaml:"broadcast"` BroadcastGlobal string `yaml:"broadcast_global"` @@ -151,7 +151,7 @@ type EnterStep struct { // non-zero field means it needs per-tick scheduling rather than synchronous // printing). func (e EnterStep) IsTimed() bool { - return e.Delay > 0 || len(e.SetFlags) > 0 || len(e.SetPlayerFlags) > 0 || + return e.Delay > 0 || len(e.SetGlobalFlags) > 0 || len(e.SetPlayerFlags) > 0 || e.Message != "" || e.Broadcast != "" || e.BroadcastGlobal != "" || e.SpawnMob != nil || e.DespawnMob != "" || e.GiveItem != "" || e.TakeItem != "" || e.Teleport != 0 || e.Heal != 0 diff --git a/internal/world/room_migrate_test.go b/internal/world/room_migrate_test.go index b035172..5696a36 100644 --- a/internal/world/room_migrate_test.go +++ b/internal/world/room_migrate_test.go @@ -5,7 +5,7 @@ import "testing" func TestRoomRewriteRoomIDs(t *testing.T) { r := &Room{ Exits: map[ExitDir]ExitDef{ - North: {Room: 10, SetFlags: map[string]any{"last": 10}}, + North: {Room: 10, SetGlobalFlags: map[string]any{"last": 10}}, South: {Room: 99}, }, Triggers: []TriggerDef{ @@ -43,8 +43,8 @@ func TestRoomRewriteRoomIDs(t *testing.T) { // Author set_flags values are NOT structural room references and must not // be remapped (the old swapid regex wrongly rewrote these). - if v := r.Exits[North].SetFlags["last"]; v != 10 { - t.Errorf("set_flags value remapped: got %v, want 10", v) + if v := r.Exits[North].SetGlobalFlags["last"]; v != 10 { + t.Errorf("set_global_flags value remapped: got %v, want 10", v) } if r.Triggers[0].Room != 31 { diff --git a/internal/world/trigger.go b/internal/world/trigger.go index 8e74ff7..e31a5f9 100644 --- a/internal/world/trigger.go +++ b/internal/world/trigger.go @@ -7,7 +7,7 @@ import ( type TriggerDef struct { ID string `yaml:"id"` OnPlayerFlag string `yaml:"on_player_flag"` - OnFlag string `yaml:"on_flag"` + OnGlobalFlag string `yaml:"on_global_flag"` Value any `yaml:"value"` Room int `yaml:"room"` Steps []TriggerStep `yaml:"steps"` @@ -15,14 +15,14 @@ type TriggerDef struct { func (t *TriggerDef) IsPlayerFlagTrigger() bool { return t.OnPlayerFlag != "" } -func (t *TriggerDef) IsWorldFlagTrigger() bool { return t.OnFlag != "" } +func (t *TriggerDef) IsGlobalFlagTrigger() bool { return t.OnGlobalFlag != "" } type TriggerStep struct { Delay int `yaml:"delay"` Message string `yaml:"message"` Broadcast string `yaml:"broadcast"` BroadcastGlobal string `yaml:"broadcast_global"` - SetFlags map[string]any `yaml:"set_flags"` + SetGlobalFlags map[string]any `yaml:"set_global_flags"` SetPlayerFlags map[string]any `yaml:"set_player_flags"` SpawnMob *SpawnMobConfig `yaml:"spawn_mob"` GiveItem string `yaml:"give_item"` @@ -54,7 +54,7 @@ func (s *SpawnMobConfig) UnmarshalYAML(value *yaml.Node) error { } func (t TriggerStep) IsTimed() bool { - return t.Delay > 0 || len(t.SetFlags) > 0 || len(t.SetPlayerFlags) > 0 || + return t.Delay > 0 || len(t.SetGlobalFlags) > 0 || len(t.SetPlayerFlags) > 0 || t.Message != "" || t.Broadcast != "" || t.BroadcastGlobal != "" || t.SpawnMob != nil || t.GiveItem != "" || t.TakeItem != "" || t.Teleport != 0 || t.Heal != 0 || t.DespawnMob != "" diff --git a/internal/world/trigger_store.go b/internal/world/trigger_store.go index b5fac5b..e18ae80 100644 --- a/internal/world/trigger_store.go +++ b/internal/world/trigger_store.go @@ -14,12 +14,12 @@ type TriggerStore struct { mu sync.Mutex globalByPlayerFlag map[string][]*TriggerDef - globalByWorldFlag map[string][]*TriggerDef + globalByGlobalFlag map[string][]*TriggerDef roomByPlayerFlag map[int]map[string][]*TriggerDef - roomByWorldFlag map[int]map[string][]*TriggerDef + roomByGlobalFlag map[int]map[string][]*TriggerDef playerSeqs map[string]*PlayerTriggerSeq - worldSeqs map[string]*WorldTriggerSeq + globalSeqs map[string]*GlobalTriggerSeq } type PlayerTriggerSeq struct { @@ -32,7 +32,7 @@ type PlayerTriggerSeq struct { FlagValue any } -type WorldTriggerSeq struct { +type GlobalTriggerSeq struct { TriggerID string RoomID int Steps []TriggerStep @@ -43,11 +43,11 @@ type WorldTriggerSeq struct { func NewTriggerStore() *TriggerStore { return &TriggerStore{ globalByPlayerFlag: make(map[string][]*TriggerDef), - globalByWorldFlag: make(map[string][]*TriggerDef), + globalByGlobalFlag: make(map[string][]*TriggerDef), roomByPlayerFlag: make(map[int]map[string][]*TriggerDef), - roomByWorldFlag: make(map[int]map[string][]*TriggerDef), + roomByGlobalFlag: make(map[int]map[string][]*TriggerDef), playerSeqs: make(map[string]*PlayerTriggerSeq), - worldSeqs: make(map[string]*WorldTriggerSeq), + globalSeqs: make(map[string]*GlobalTriggerSeq), } } @@ -55,9 +55,9 @@ func (ts *TriggerStore) ClearTriggers() { ts.mu.Lock() defer ts.mu.Unlock() ts.globalByPlayerFlag = make(map[string][]*TriggerDef) - ts.globalByWorldFlag = make(map[string][]*TriggerDef) + ts.globalByGlobalFlag = make(map[string][]*TriggerDef) ts.roomByPlayerFlag = make(map[int]map[string][]*TriggerDef) - ts.roomByWorldFlag = make(map[int]map[string][]*TriggerDef) + ts.roomByGlobalFlag = make(map[int]map[string][]*TriggerDef) } func (ts *TriggerStore) LoadGlobal(dataDir string) error { @@ -110,13 +110,13 @@ func (ts *TriggerStore) SeedRoomTriggers(roomID int, triggers []TriggerDef) { ts.roomByPlayerFlag[roomID][t.OnPlayerFlag] = append( ts.roomByPlayerFlag[roomID][t.OnPlayerFlag], t) } - if t.IsWorldFlagTrigger() { - if ts.roomByWorldFlag[roomID] == nil { - ts.roomByWorldFlag[roomID] = make(map[string][]*TriggerDef) + if t.IsGlobalFlagTrigger() { + if ts.roomByGlobalFlag[roomID] == nil { + ts.roomByGlobalFlag[roomID] = make(map[string][]*TriggerDef) } t.Room = roomID - ts.roomByWorldFlag[roomID][t.OnFlag] = append( - ts.roomByWorldFlag[roomID][t.OnFlag], t) + ts.roomByGlobalFlag[roomID][t.OnGlobalFlag] = append( + ts.roomByGlobalFlag[roomID][t.OnGlobalFlag], t) } } } @@ -128,9 +128,9 @@ func (ts *TriggerStore) addGlobal(t *TriggerDef) { ts.globalByPlayerFlag[t.OnPlayerFlag] = append( ts.globalByPlayerFlag[t.OnPlayerFlag], t) } - if t.IsWorldFlagTrigger() { - ts.globalByWorldFlag[t.OnFlag] = append( - ts.globalByWorldFlag[t.OnFlag], t) + if t.IsGlobalFlagTrigger() { + ts.globalByGlobalFlag[t.OnGlobalFlag] = append( + ts.globalByGlobalFlag[t.OnGlobalFlag], t) } } @@ -184,23 +184,23 @@ func (ts *TriggerStore) FirePlayerInRoom(playerName string, roomID int, flagName return started } -func (ts *TriggerStore) FireWorld(flagName string, flagValue any) []*WorldTriggerSeq { +func (ts *TriggerStore) FireGlobal(flagName string, flagValue any) []*GlobalTriggerSeq { ts.mu.Lock() defer ts.mu.Unlock() - var started []*WorldTriggerSeq + var started []*GlobalTriggerSeq - for _, t := range ts.globalByWorldFlag[flagName] { + for _, t := range ts.globalByGlobalFlag[flagName] { if !ts.valueMatches(t.Value, flagValue) { continue } - seq := ts.startWorldSeqLocked(t, flagValue) + seq := ts.startGlobalSeqLocked(t, flagValue) if seq != nil { started = append(started, seq) } } - for roomID, roomFlags := range ts.roomByWorldFlag { + for roomID, roomFlags := range ts.roomByGlobalFlag { for _, t := range roomFlags[flagName] { if !ts.valueMatches(t.Value, flagValue) { continue @@ -208,7 +208,7 @@ func (ts *TriggerStore) FireWorld(flagName string, flagValue any) []*WorldTrigge if t.Room == 0 { t.Room = roomID } - seq := ts.startWorldSeqLocked(t, flagValue) + seq := ts.startGlobalSeqLocked(t, flagValue) if seq != nil { started = append(started, seq) } @@ -238,12 +238,12 @@ func (ts *TriggerStore) startPlayerSeqLocked(playerName string, t *TriggerDef, r return seq } -func (ts *TriggerStore) startWorldSeqLocked(t *TriggerDef, flagValue any) *WorldTriggerSeq { +func (ts *TriggerStore) startGlobalSeqLocked(t *TriggerDef, flagValue any) *GlobalTriggerSeq { key := t.ID - if _, exists := ts.worldSeqs[key]; exists { + if _, exists := ts.globalSeqs[key]; exists { return nil } - seq := &WorldTriggerSeq{ + seq := &GlobalTriggerSeq{ TriggerID: t.ID, RoomID: t.Room, Steps: make([]TriggerStep, len(t.Steps)), @@ -253,7 +253,7 @@ func (ts *TriggerStore) startWorldSeqLocked(t *TriggerDef, flagValue any) *World if len(seq.Steps) > 0 { seq.Wait = seq.Steps[0].Delay } - ts.worldSeqs[key] = seq + ts.globalSeqs[key] = seq return seq } @@ -274,11 +274,11 @@ func (ts *TriggerStore) SnapshotPlayerSeqs() []*PlayerTriggerSeq { return out } -func (ts *TriggerStore) SnapshotWorldSeqs() []*WorldTriggerSeq { +func (ts *TriggerStore) SnapshotGlobalSeqs() []*GlobalTriggerSeq { ts.mu.Lock() defer ts.mu.Unlock() - out := make([]*WorldTriggerSeq, 0, len(ts.worldSeqs)) - for _, s := range ts.worldSeqs { + out := make([]*GlobalTriggerSeq, 0, len(ts.globalSeqs)) + for _, s := range ts.globalSeqs { out = append(out, s) } return out @@ -291,10 +291,10 @@ func (ts *TriggerStore) RemovePlayerSeq(playerName, triggerID string) { delete(ts.playerSeqs, key) } -func (ts *TriggerStore) RemoveWorldSeq(triggerID string) { +func (ts *TriggerStore) RemoveGlobalSeq(triggerID string) { ts.mu.Lock() defer ts.mu.Unlock() - delete(ts.worldSeqs, triggerID) + delete(ts.globalSeqs, triggerID) } func (ts *TriggerStore) AllGlobalTriggers() []*TriggerDef { @@ -304,7 +304,7 @@ func (ts *TriggerStore) AllGlobalTriggers() []*TriggerDef { for _, triggers := range ts.globalByPlayerFlag { out = append(out, triggers...) } - for _, triggers := range ts.globalByWorldFlag { + for _, triggers := range ts.globalByGlobalFlag { out = append(out, triggers...) } return out @@ -340,7 +340,7 @@ func (ts *TriggerStore) AllRoomTriggers() map[int][]*TriggerDef { out[roomID] = append(out[roomID], triggers...) } } - for roomID, byFlag := range ts.roomByWorldFlag { + for roomID, byFlag := range ts.roomByGlobalFlag { for _, triggers := range byFlag { out[roomID] = append(out[roomID], triggers...) } -- cgit v1.2.3