From a5d4ead1795882d25da7eda53680d2a84590693d Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Fri, 3 Jul 2026 20:53:00 -0400 Subject: feat: admin map can add new and rename areas. works with empty directories now. --- AGENTS.md | 2 +- Makefile | 2 +- README.md | 2 +- cmd/mud/main.go | 139 -------------------- cmd/thoi/main.go | 139 ++++++++++++++++++++ data/.admin_history.json | 2 +- data/rooms/1001.yaml | 85 ------------ data/rooms/example_unused/agility/99999200.yaml | 7 - data/rooms/example_unused/agility/99999201.yaml | 8 -- data/rooms/example_unused/agility/99999202.yaml | 8 -- data/rooms/example_unused/agility/99999203.yaml | 8 -- data/rooms/example_unused/agility/99999204.yaml | 8 -- data/rooms/example_unused/agility/99999205.yaml | 8 -- data/rooms/example_unused/agility/99999210.yaml | 8 -- data/rooms/example_unused/agility/99999211.yaml | 8 -- data/rooms/example_unused/agility/99999212.yaml | 8 -- data/rooms/example_unused/agility/99999213.yaml | 8 -- data/rooms/example_unused/agility/99999214.yaml | 8 -- data/rooms/example_unused/agility/99999215.yaml | 8 -- data/rooms/example_unused/agility/99999220.yaml | 8 -- data/rooms/example_unused/agility/99999221.yaml | 8 -- data/rooms/example_unused/agility/99999222.yaml | 8 -- data/rooms/example_unused/agility/99999223.yaml | 8 -- data/rooms/example_unused/agility/99999224.yaml | 8 -- data/rooms/example_unused/agility/99999225.yaml | 8 -- data/rooms/example_unused/agility/99999226.yaml | 8 -- data/rooms/example_unused/agility2/99999200.yaml | 7 + data/rooms/example_unused/agility2/99999201.yaml | 8 ++ data/rooms/example_unused/agility2/99999202.yaml | 8 ++ data/rooms/example_unused/agility2/99999203.yaml | 8 ++ data/rooms/example_unused/agility2/99999204.yaml | 8 ++ data/rooms/example_unused/agility2/99999205.yaml | 8 ++ data/rooms/example_unused/agility2/99999210.yaml | 8 ++ data/rooms/example_unused/agility2/99999211.yaml | 8 ++ data/rooms/example_unused/agility2/99999212.yaml | 8 ++ data/rooms/example_unused/agility2/99999213.yaml | 8 ++ data/rooms/example_unused/agility2/99999214.yaml | 8 ++ data/rooms/example_unused/agility2/99999215.yaml | 8 ++ data/rooms/example_unused/agility2/99999220.yaml | 8 ++ data/rooms/example_unused/agility2/99999221.yaml | 8 ++ data/rooms/example_unused/agility2/99999222.yaml | 8 ++ data/rooms/example_unused/agility2/99999223.yaml | 8 ++ data/rooms/example_unused/agility2/99999224.yaml | 8 ++ data/rooms/example_unused/agility2/99999225.yaml | 8 ++ data/rooms/example_unused/agility2/99999226.yaml | 8 ++ .../example_unused/player_housing/99999300.yaml | 17 ++- data/rooms/example_unused/underground/9999950.yaml | 6 - data/rooms/example_unused/underground/9999951.yaml | 9 -- data/rooms/example_unused/underground/9999952.yaml | 8 -- data/rooms/example_unused/underground/9999953.yaml | 8 -- data/rooms/example_unused/underground/9999954.yaml | 8 -- data/rooms/example_unused/underground/9999955.yaml | 11 -- data/rooms/example_unused/underground/9999956.yaml | 8 -- data/rooms/example_unused/underground/9999957.yaml | 7 - data/rooms/example_unused/underground/9999958.yaml | 7 - data/rooms/example_unused/underground/9999959.yaml | 8 -- data/rooms/example_unused/underground/9999960.yaml | 7 - data/rooms/example_unused/underground/9999961.yaml | 6 - data/rooms/example_unused/underground/9999962.yaml | 7 - data/rooms/example_unused/underground/9999963.yaml | 7 - data/rooms/example_unused/underground/9999964.yaml | 7 - data/rooms/example_unused/underground/9999965.yaml | 7 - data/rooms/example_unused/underground/9999966.yaml | 7 - data/rooms/example_unused/underground/9999967.yaml | 7 - data/rooms/example_unused/underground/9999968.yaml | 6 - .../rooms/example_unused/underground2/9999950.yaml | 16 +++ .../rooms/example_unused/underground2/9999951.yaml | 9 ++ .../rooms/example_unused/underground2/9999952.yaml | 8 ++ .../rooms/example_unused/underground2/9999953.yaml | 8 ++ .../rooms/example_unused/underground2/9999954.yaml | 8 ++ .../rooms/example_unused/underground2/9999955.yaml | 11 ++ .../rooms/example_unused/underground2/9999956.yaml | 8 ++ .../rooms/example_unused/underground2/9999957.yaml | 7 + .../rooms/example_unused/underground2/9999958.yaml | 7 + .../rooms/example_unused/underground2/9999959.yaml | 8 ++ .../rooms/example_unused/underground2/9999960.yaml | 7 + .../rooms/example_unused/underground2/9999961.yaml | 6 + .../rooms/example_unused/underground2/9999962.yaml | 7 + .../rooms/example_unused/underground2/9999963.yaml | 7 + .../rooms/example_unused/underground2/9999964.yaml | 7 + .../rooms/example_unused/underground2/9999965.yaml | 7 + .../rooms/example_unused/underground2/9999966.yaml | 7 + .../rooms/example_unused/underground2/9999967.yaml | 7 + .../rooms/example_unused/underground2/9999968.yaml | 6 + data/rooms/test222/1.yaml | 2 + internal/admin/api_map.go | 12 ++ internal/admin/api_rooms.go | 145 +++++++++++++++++++-- internal/admin/server.go | 18 ++- internal/admin/static/admin.css | 7 +- internal/admin/static/admin.js | 4 +- internal/admin/static/map.js | 119 +++++++++++++++++ internal/admin/templates/duplicate-rooms.html | 5 +- internal/admin/templates/map.html | 46 +++++-- internal/admin/undo.go | 9 ++ internal/validate/checks.go | 33 +++++ 95 files changed, 826 insertions(+), 556 deletions(-) delete mode 100644 cmd/mud/main.go create mode 100644 cmd/thoi/main.go delete mode 100644 data/rooms/1001.yaml delete mode 100644 data/rooms/example_unused/agility/99999200.yaml delete mode 100644 data/rooms/example_unused/agility/99999201.yaml delete mode 100644 data/rooms/example_unused/agility/99999202.yaml delete mode 100644 data/rooms/example_unused/agility/99999203.yaml delete mode 100644 data/rooms/example_unused/agility/99999204.yaml delete mode 100644 data/rooms/example_unused/agility/99999205.yaml delete mode 100644 data/rooms/example_unused/agility/99999210.yaml delete mode 100644 data/rooms/example_unused/agility/99999211.yaml delete mode 100644 data/rooms/example_unused/agility/99999212.yaml delete mode 100644 data/rooms/example_unused/agility/99999213.yaml delete mode 100644 data/rooms/example_unused/agility/99999214.yaml delete mode 100644 data/rooms/example_unused/agility/99999215.yaml delete mode 100644 data/rooms/example_unused/agility/99999220.yaml delete mode 100644 data/rooms/example_unused/agility/99999221.yaml delete mode 100644 data/rooms/example_unused/agility/99999222.yaml delete mode 100644 data/rooms/example_unused/agility/99999223.yaml delete mode 100644 data/rooms/example_unused/agility/99999224.yaml delete mode 100644 data/rooms/example_unused/agility/99999225.yaml delete mode 100644 data/rooms/example_unused/agility/99999226.yaml create mode 100644 data/rooms/example_unused/agility2/99999200.yaml create mode 100644 data/rooms/example_unused/agility2/99999201.yaml create mode 100644 data/rooms/example_unused/agility2/99999202.yaml create mode 100644 data/rooms/example_unused/agility2/99999203.yaml create mode 100644 data/rooms/example_unused/agility2/99999204.yaml create mode 100644 data/rooms/example_unused/agility2/99999205.yaml create mode 100644 data/rooms/example_unused/agility2/99999210.yaml create mode 100644 data/rooms/example_unused/agility2/99999211.yaml create mode 100644 data/rooms/example_unused/agility2/99999212.yaml create mode 100644 data/rooms/example_unused/agility2/99999213.yaml create mode 100644 data/rooms/example_unused/agility2/99999214.yaml create mode 100644 data/rooms/example_unused/agility2/99999215.yaml create mode 100644 data/rooms/example_unused/agility2/99999220.yaml create mode 100644 data/rooms/example_unused/agility2/99999221.yaml create mode 100644 data/rooms/example_unused/agility2/99999222.yaml create mode 100644 data/rooms/example_unused/agility2/99999223.yaml create mode 100644 data/rooms/example_unused/agility2/99999224.yaml create mode 100644 data/rooms/example_unused/agility2/99999225.yaml create mode 100644 data/rooms/example_unused/agility2/99999226.yaml delete mode 100644 data/rooms/example_unused/underground/9999950.yaml delete mode 100644 data/rooms/example_unused/underground/9999951.yaml delete mode 100644 data/rooms/example_unused/underground/9999952.yaml delete mode 100644 data/rooms/example_unused/underground/9999953.yaml delete mode 100644 data/rooms/example_unused/underground/9999954.yaml delete mode 100644 data/rooms/example_unused/underground/9999955.yaml delete mode 100644 data/rooms/example_unused/underground/9999956.yaml delete mode 100644 data/rooms/example_unused/underground/9999957.yaml delete mode 100644 data/rooms/example_unused/underground/9999958.yaml delete mode 100644 data/rooms/example_unused/underground/9999959.yaml delete mode 100644 data/rooms/example_unused/underground/9999960.yaml delete mode 100644 data/rooms/example_unused/underground/9999961.yaml delete mode 100644 data/rooms/example_unused/underground/9999962.yaml delete mode 100644 data/rooms/example_unused/underground/9999963.yaml delete mode 100644 data/rooms/example_unused/underground/9999964.yaml delete mode 100644 data/rooms/example_unused/underground/9999965.yaml delete mode 100644 data/rooms/example_unused/underground/9999966.yaml delete mode 100644 data/rooms/example_unused/underground/9999967.yaml delete mode 100644 data/rooms/example_unused/underground/9999968.yaml create mode 100644 data/rooms/example_unused/underground2/9999950.yaml create mode 100644 data/rooms/example_unused/underground2/9999951.yaml create mode 100644 data/rooms/example_unused/underground2/9999952.yaml create mode 100644 data/rooms/example_unused/underground2/9999953.yaml create mode 100644 data/rooms/example_unused/underground2/9999954.yaml create mode 100644 data/rooms/example_unused/underground2/9999955.yaml create mode 100644 data/rooms/example_unused/underground2/9999956.yaml create mode 100644 data/rooms/example_unused/underground2/9999957.yaml create mode 100644 data/rooms/example_unused/underground2/9999958.yaml create mode 100644 data/rooms/example_unused/underground2/9999959.yaml create mode 100644 data/rooms/example_unused/underground2/9999960.yaml create mode 100644 data/rooms/example_unused/underground2/9999961.yaml create mode 100644 data/rooms/example_unused/underground2/9999962.yaml create mode 100644 data/rooms/example_unused/underground2/9999963.yaml create mode 100644 data/rooms/example_unused/underground2/9999964.yaml create mode 100644 data/rooms/example_unused/underground2/9999965.yaml create mode 100644 data/rooms/example_unused/underground2/9999966.yaml create mode 100644 data/rooms/example_unused/underground2/9999967.yaml create mode 100644 data/rooms/example_unused/underground2/9999968.yaml create mode 100644 data/rooms/test222/1.yaml diff --git a/AGENTS.md b/AGENTS.md index a2eb532..bbf1469 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ The House of Icarus — a sci-fi MUD in Go. YAML-driven, no database. "Technolog ## Build & Run ``` -make build # go build -o thoi ./cmd/mud +make build # go build -o thoi ./cmd/thoi make run # build + run with DATA_DIR=./data make test # DATA_DIR=$(PWD)/data go test ./... -timeout 60s make vet # go vet ./... diff --git a/Makefile b/Makefile index fb15282..872bccc 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ BINARY=thoi DATA_DIR=$(PWD)/data build: - go build -o $(BINARY) ./cmd/mud + go build -o $(BINARY) ./cmd/thoi run: build DATA_DIR=$(DATA_DIR) ./$(BINARY) diff --git a/README.md b/README.md index cb23503..4c6caed 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Install Go then ``` git clone https://codeberg.org/historia/thehouseoficarus cd thehouseoficarus -go build -o thoi ./cmd/mud +go build -o thoi ./cmd/thoi ./thoi ``` diff --git a/cmd/mud/main.go b/cmd/mud/main.go deleted file mode 100644 index 23a2ca4..0000000 --- a/cmd/mud/main.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "os" - "os/signal" - "syscall" - - "thehouseoficarus/internal/admin" - "thehouseoficarus/internal/behavior" - "thehouseoficarus/internal/config" - "thehouseoficarus/internal/game" - "thehouseoficarus/internal/net" -) - -func main() { - configPath := flag.String("config", "config.yaml", "path to config file") - flag.Parse() - - dataDir := os.Getenv("DATA_DIR") - if dataDir == "" { - dataDir = "data" - } - - cfg, err := config.Load(*configPath) - if err != nil { - if os.IsNotExist(err) { - log.Printf("config file %s not found, creating with defaults", *configPath) - if err := config.SaveDefault(*configPath); err != nil { - log.Fatalf("failed to create config: %v", err) - } - cfg = config.Default() - } else { - log.Fatalf("failed to load config: %v", err) - } - } - - if cfg.GameConstants.ShopDefaultRestock > 0 { - behavior.ShopDefaultRestock = cfg.GameConstants.ShopDefaultRestock - } - - g := game.New(dataDir, &cfg.DefaultColors, cfg.StartupValidation, cfg.StartingRoom) - g.Ticks.Start(cfg.TickLength) - defer g.Ticks.Stop() - - g.Ticks.Subscribe(1, func() bool { - g.MoveTick() - g.ProcessQueuedCommands() - g.EnterSeqTick() - g.TriggerSeqTick() - g.TransientMobTick() - g.World.Tick() - g.MobStore.Tick() - g.RegenTick() - g.DisconnectTick() - g.WanderTick() - g.SharedDepletionTick() - g.FireTick() - g.AdvanceActions() - g.TechTick() - g.ConsumeTick() - g.BroadcastRespawns() - g.VisualTick() - g.SneakTick() - g.FarmTick() - g.BuffTick() - g.SafespotTick() - g.HazardTick() - return true - }) - - server, err := net.NewServer(cfg) - if err != nil { - log.Fatalf("failed to start server: %v", err) - } - g.SetHub(server.Hub()) - - junkItems := []string{"solarjunk", "ecojunk", "hydrojunk", "biojunk", "chaosjunk", - "cosmicjunk", "naturejunk", "bloodjunk", "deathjunk", "lawjunk", "scrap"} - for _, j := range junkItems { - g.World.AddGroundItem(1, j, 500) - } - - if cfg.AdminHTTP.Enabled { - adminSrv, err := admin.NewServer(cfg, false, g.AccountStore, g.World, g.ItemStore, g.ObjectStore, g.MobStore, dataDir) - if err != nil { - log.Fatalf("failed to start admin HTTP server: %v", err) - } - go func() { - if err := adminSrv.ListenAndServe(); err != nil { - log.Printf("admin HTTP server error: %v", err) - } - }() - log.Printf("Admin HTTP listening on :%d", cfg.AdminHTTP.Port) - } - - if cfg.AdminHTTPS.Enabled { - adminSrv, err := admin.NewServer(cfg, true, g.AccountStore, g.World, g.ItemStore, g.ObjectStore, g.MobStore, dataDir) - if err != nil { - log.Fatalf("failed to start admin HTTPS server: %v", err) - } - go func() { - if err := adminSrv.ListenAndServe(); err != nil { - log.Printf("admin HTTPS server error: %v", err) - } - }() - log.Printf("Admin HTTPS listening on :%d", cfg.AdminHTTPS.Port) - } - - if cfg.Telnet.Enabled { - log.Printf("Telnet listening on :%d", cfg.Telnet.Port) - } - if cfg.TelnetTLS.Enabled { - log.Printf("Telnet+TLS listening on :%d", cfg.TelnetTLS.Port) - } - if cfg.HTTP.Enabled { - log.Printf("HTTP listening on :%d", cfg.HTTP.Port) - } - if cfg.HTTPS.Enabled { - log.Printf("HTTPS listening on :%d", cfg.HTTPS.Port) - } - fmt.Println() // blank line after log prefixes - - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - - go func() { - <-sigCh - log.Println("Shutting down...") - g.Ticks.Stop() - os.Exit(0) - }() - - if err := server.ListenAndServe(g.HandleSession); err != nil { - log.Fatalf("server error: %v", err) - } -} diff --git a/cmd/thoi/main.go b/cmd/thoi/main.go new file mode 100644 index 0000000..23a2ca4 --- /dev/null +++ b/cmd/thoi/main.go @@ -0,0 +1,139 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "os/signal" + "syscall" + + "thehouseoficarus/internal/admin" + "thehouseoficarus/internal/behavior" + "thehouseoficarus/internal/config" + "thehouseoficarus/internal/game" + "thehouseoficarus/internal/net" +) + +func main() { + configPath := flag.String("config", "config.yaml", "path to config file") + flag.Parse() + + dataDir := os.Getenv("DATA_DIR") + if dataDir == "" { + dataDir = "data" + } + + cfg, err := config.Load(*configPath) + if err != nil { + if os.IsNotExist(err) { + log.Printf("config file %s not found, creating with defaults", *configPath) + if err := config.SaveDefault(*configPath); err != nil { + log.Fatalf("failed to create config: %v", err) + } + cfg = config.Default() + } else { + log.Fatalf("failed to load config: %v", err) + } + } + + if cfg.GameConstants.ShopDefaultRestock > 0 { + behavior.ShopDefaultRestock = cfg.GameConstants.ShopDefaultRestock + } + + g := game.New(dataDir, &cfg.DefaultColors, cfg.StartupValidation, cfg.StartingRoom) + g.Ticks.Start(cfg.TickLength) + defer g.Ticks.Stop() + + g.Ticks.Subscribe(1, func() bool { + g.MoveTick() + g.ProcessQueuedCommands() + g.EnterSeqTick() + g.TriggerSeqTick() + g.TransientMobTick() + g.World.Tick() + g.MobStore.Tick() + g.RegenTick() + g.DisconnectTick() + g.WanderTick() + g.SharedDepletionTick() + g.FireTick() + g.AdvanceActions() + g.TechTick() + g.ConsumeTick() + g.BroadcastRespawns() + g.VisualTick() + g.SneakTick() + g.FarmTick() + g.BuffTick() + g.SafespotTick() + g.HazardTick() + return true + }) + + server, err := net.NewServer(cfg) + if err != nil { + log.Fatalf("failed to start server: %v", err) + } + g.SetHub(server.Hub()) + + junkItems := []string{"solarjunk", "ecojunk", "hydrojunk", "biojunk", "chaosjunk", + "cosmicjunk", "naturejunk", "bloodjunk", "deathjunk", "lawjunk", "scrap"} + for _, j := range junkItems { + g.World.AddGroundItem(1, j, 500) + } + + if cfg.AdminHTTP.Enabled { + adminSrv, err := admin.NewServer(cfg, false, g.AccountStore, g.World, g.ItemStore, g.ObjectStore, g.MobStore, dataDir) + if err != nil { + log.Fatalf("failed to start admin HTTP server: %v", err) + } + go func() { + if err := adminSrv.ListenAndServe(); err != nil { + log.Printf("admin HTTP server error: %v", err) + } + }() + log.Printf("Admin HTTP listening on :%d", cfg.AdminHTTP.Port) + } + + if cfg.AdminHTTPS.Enabled { + adminSrv, err := admin.NewServer(cfg, true, g.AccountStore, g.World, g.ItemStore, g.ObjectStore, g.MobStore, dataDir) + if err != nil { + log.Fatalf("failed to start admin HTTPS server: %v", err) + } + go func() { + if err := adminSrv.ListenAndServe(); err != nil { + log.Printf("admin HTTPS server error: %v", err) + } + }() + log.Printf("Admin HTTPS listening on :%d", cfg.AdminHTTPS.Port) + } + + if cfg.Telnet.Enabled { + log.Printf("Telnet listening on :%d", cfg.Telnet.Port) + } + if cfg.TelnetTLS.Enabled { + log.Printf("Telnet+TLS listening on :%d", cfg.TelnetTLS.Port) + } + if cfg.HTTP.Enabled { + log.Printf("HTTP listening on :%d", cfg.HTTP.Port) + } + if cfg.HTTPS.Enabled { + log.Printf("HTTPS listening on :%d", cfg.HTTPS.Port) + } + fmt.Println() // blank line after log prefixes + + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) + + go func() { + <-sigCh + log.Println("Shutting down...") + g.Ticks.Stop() + os.Exit(0) + }() + + if err := server.ListenAndServe(g.HandleSession); err != nil { + log.Fatalf("server error: %v", err) + } +} diff --git a/data/.admin_history.json b/data/.admin_history.json index 6aac68c..c68eab4 100644 --- a/data/.admin_history.json +++ b/data/.admin_history.json @@ -1 +1 @@ -{"history":[{"time":"2026-07-01T04:08:26-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:08:32-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - id: tree\n - aliases: []\n description:\n - text: \"\"\n hidden: false\n name: \"\"\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:08:37-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - id: tree\n - aliases: []\n description:\n - text: \"\"\n hidden: false\n name: \"\"\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - aliases: []\n description: []\n hidden: false\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:08:43-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - aliases: []\n description: []\n hidden: false\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - aliases: []\n description:\n - text: YOU FOUND HIM\n hidden: false\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:08:44-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - aliases: []\n description:\n - text: YOU FOUND HIM\n hidden: false\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - aliases: []\n description:\n - text: YOU FOUND HIM\n hidden: true\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:41-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"id: 2003\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:41-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:44-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:44-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:47-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:47-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:49-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:49-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:51-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:53-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:55-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:56-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:58-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:09:58-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:10:01-04:00","description":"update room 2003 (add exit northeast to 1005)","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nhazard: \"\"\nid: 2003\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n northeast:\n room: 1005\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:10:01-04:00","description":"create room 1005","file_path":"data/rooms/intro/1005.yaml","old_content":"","new_content":"color: A5\nexits:\n southwest: 2003\nid: 1005\nname: 'Room #1005'\n","is_delete":false,"is_create":true},{"time":"2026-07-01T04:10:03-04:00","description":"delete room 1005 (cleaned 1 exits)","file_path":"data/rooms/intro/1005.yaml","old_content":"color: A5\nexits:\n southwest: 2003\nid: 1005\nname: 'Room #1005'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/intro/2003.yaml","old_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n northeast:\n room: 1005\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-01T04:11:43-04:00","description":"update room 2003 (add exit north to 1005)","file_path":"data/rooms/intro/2003.yaml","old_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 1005\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:22:38-04:00","description":"Update drop credit_stick_drop","file_path":"data/drops/credit_stick_drop.yaml","old_content":"drops:\n - item_id: credits\n weight: 40\n quantity: 15\n - item_id: credits\n weight: 30\n quantity: 30\n - item_id: credits\n weight: 20\n quantity: 50\n - item_id: credits\n weight: 8\n quantity: 100\n - item_id: credits\n weight: 2\n quantity: 250","new_content":"drops:\n - item_id: credits\n quantity: 14\n weight: 40\n - item_id: credits\n quantity: 30\n weight: 30\n - item_id: credits\n quantity: 50\n weight: 20\n - item_id: credits\n quantity: 100\n weight: 8\n - item_id: credits\n quantity: 250\n weight: 2\nid: credit_stick_drop\n","is_delete":false,"is_create":false},{"time":"2026-07-01T04:22:42-04:00","description":"Update drop credit_stick_drop","file_path":"data/drops/credit_stick_drop.yaml","old_content":"drops:\n - item_id: credits\n quantity: 14\n weight: 40\n - item_id: credits\n quantity: 30\n weight: 30\n - item_id: credits\n quantity: 50\n weight: 20\n - item_id: credits\n quantity: 100\n weight: 8\n - item_id: credits\n quantity: 250\n weight: 2\nid: credit_stick_drop\n","new_content":"drops:\n - item_id: credits\n quantity: 15\n weight: 40\n - item_id: credits\n quantity: 30\n weight: 30\n - item_id: credits\n quantity: 50\n weight: 20\n - item_id: credits\n quantity: 100\n weight: 8\n - item_id: credits\n quantity: 250\n weight: 2\nid: credit_stick_drop\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:06:32-04:00","description":"Create mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"","new_content":"id: flight_attendant_copy\n","is_delete":false,"is_create":true},{"time":"2026-07-01T13:06:32-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"id: flight_attendant_copy\n","new_content":"description: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nname: flight attendant\nprotected: true\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - text: '\"Thank you.\"'\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:07:46-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"description: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nname: flight attendant\nprotected: true\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - text: '\"Thank you.\"'\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n sequence:\n - Test\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - text: '\"Thank you.\"'\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:08:04-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n sequence:\n - Test\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - text: '\"Thank you.\"'\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n sequence:\n - Test\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - text: '\"Thank you.\"'\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:09:12-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n sequence:\n - Test\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - text: '\"Thank you.\"'\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - goto: Test\n text: '\"Thank you.\"'\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:16:15-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - goto: Test\n text: '\"Thank you.\"'\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n sequence:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n message: '\"Hi there, how can I help?\"'\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n thanks:\n message: '\"Thank for flying with Denali. Watch your step on the way out please.\"'\n options:\n - goto: Test\n text: '\"Thank you.\"'\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:16:46-04:00","description":"Update item adamant_arrow","file_path":"data/items/ammo/adamant_arrow.yaml","old_content":"color: \"78\"\ncraft:\n ingredients:\n - items:\n - headless_arrow\n quantity: 15\n - items:\n - adamant_arrowtips\n quantity: 15\n level: 60\n output_qty: 15\n type: fletching\n ticks_per_cycle: 2\n xp: 10\ndescription: An adamant-tipped arrow.\nequipment:\n other:\n ranged: 31\n slot: ammo\n type: ammo\nname: adamant arrow\nrecoverable: true\nstackable: true\nvalue: 20\n","new_content":"color: \"78\"\ncraft:\n - end_message: \"\"\n fail: \"\"\n ingredients:\n - items:\n - headless_arrow\n quantity: 15\n - items:\n - adamant_arrowtips\n quantity: 15\n level: 60\n output_qty: 15\n start_message: \"\"\n station: []\n subtype: \"\"\n success_message: \"\"\n ticks_per_cycle: 2\n tool: \"\"\n type: fletching\n xp: 10\ndescription: An adamant-tipped arrow.2\nequipment:\n other:\n ranged: 31\n slot: ammo\n type: ammo\nid: adamant_arrow\nmax_quality: 0\nname: adamant arrow\nquality: 0\nrecoverable: true\nstackable: true\nvalue: 20\n","is_delete":false,"is_create":false},{"time":"2026-07-01T13:16:50-04:00","description":"Update item adamant_arrow","file_path":"data/items/ammo/adamant_arrow.yaml","old_content":"color: \"78\"\ncraft:\n - end_message: \"\"\n fail: \"\"\n ingredients:\n - items:\n - headless_arrow\n quantity: 15\n - items:\n - adamant_arrowtips\n quantity: 15\n level: 60\n output_qty: 15\n start_message: \"\"\n station: []\n subtype: \"\"\n success_message: \"\"\n ticks_per_cycle: 2\n tool: \"\"\n type: fletching\n xp: 10\ndescription: An adamant-tipped arrow.2\nequipment:\n other:\n ranged: 31\n slot: ammo\n type: ammo\nid: adamant_arrow\nmax_quality: 0\nname: adamant arrow\nquality: 0\nrecoverable: true\nstackable: true\nvalue: 20\n","new_content":"color: \"78\"\ncraft:\n - end_message: \"\"\n fail: \"\"\n ingredients:\n - items:\n - headless_arrow\n quantity: 15\n - items:\n - adamant_arrowtips\n quantity: 15\n level: 60\n output_qty: 15\n start_message: \"\"\n station: []\n subtype: \"\"\n success_message: \"\"\n ticks_per_cycle: 2\n tool: \"\"\n type: fletching\n xp: 10\ndescription: An adamant-tipped arrow.\nequipment:\n other:\n ranged: 31\n slot: ammo\n type: ammo\nid: adamant_arrow\nmax_quality: 0\nname: adamant arrow\nquality: 0\nrecoverable: true\nstackable: true\nvalue: 20\n","is_delete":false,"is_create":false},{"time":"2026-07-01T15:41:47-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n sign_reminder:\n messages:\n - '\"Yeah, just us two! Not a lot of people heading into the belt these days.\"'\n - '\"But we''ll be landing shortly! Please be sure {0B bold}look{/} at the information {0B bold}sign{/} so you''ll be all set for your final destination.\"'\n start:\n condition:\n not: true\n player_flag: 1001_look_sign\n goto: thanks\n messages: ['\"Hi there, how can I help?\"']\n options:\n - goto: sign_reminder\n text: '\"Oh, nothing... Small crowd on this ship. Just looking for conversation.\"'\n - text: '\"Goodbye.\"'\n thanks:\n messages: ['\"Thank for flying with Denali. Watch your step on the way out please.\"']\n options:\n - goto: Test\n text: '\"Thank you.\"'\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - condition:\n min_credits: 500000\n goto: \"\"\n text: 500000!!\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T15:41:55-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: flight attendant\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - condition:\n min_credits: 500000\n goto: \"\"\n text: 500000!!\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - condition:\n min_credits: 500000\n goto: \"\"\n text: 500000!!\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T15:42:56-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\nname: Test Room\nobjects:\n - aliases: []\n description:\n - text: YOU FOUND HIM\n hidden: true\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\n - id: flight_attendant_copy\nname: Test Room\nobjects:\n - aliases: []\n description:\n - text: YOU FOUND HIM\n hidden: true\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-01T15:47:02-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - condition:\n min_credits: 500000\n goto: \"\"\n text: 500000!!\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - action:\n shop:\n items:\n - buy_price: 1\n item_id: bronze_pickaxe\n sell_price: 1\n message: SHOP SHOP\n goto: \"\"\n text: 500000!!\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T15:47:37-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - action:\n shop:\n items:\n - buy_price: 1\n item_id: bronze_pickaxe\n sell_price: 1\n message: SHOP SHOP\n goto: \"\"\n text: 500000!!\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\n - action:\n shop:\n items:\n - buy_price: 1\n item_id: bronze_pickaxe\n sell_price: 1\n message: SHOP SHOP\n goto: \"\"\n text: 500000!!\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T17:16:00-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\nshop:\n message: SHOP SHOP\n items:\n - item_id: bronze_pickaxe\n stock: 5\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\nshop:\n buy_percentage: 0\n buys_anything: false\n change_percentage: 0\n items:\n - item_id: bronze_pickaxe\n restock_ticks: 0\n stock: 5\n message: SHOP SHOP\n restock_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T17:16:36-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\nshop:\n buy_percentage: 0\n buys_anything: false\n change_percentage: 0\n items:\n - item_id: bronze_pickaxe\n restock_ticks: 0\n stock: 5\n message: SHOP SHOP\n restock_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\nunique: false\n","new_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\nshop:\n buy_percentage: 0\n buys_anything: true\n change_percentage: 0\n items:\n - item_id: bronze_pickaxe\n restock_ticks: 0\n stock: 5\n message: SHOP SHOP\n restock_ticks: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T18:04:00-04:00","description":"Update mob flight_attendant_copy","file_path":"data/mobs/flight_attendant_copy.yaml","old_content":"aggressive: false\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nrespawn_ticks: 0\nshop:\n message: SHOP SHOP\n items:\n - item_id: bronze_pickaxe\n stock: 5\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\nunique: false\n","new_content":"aggressive: false\nattack: 0\nbonuses:\n attack_bonus: 0\n attack_type: stab\n strength_bonus: 0\ndefense: 0\ndefenses:\n crush_defense: 0\n ranged_defense: 0\n science_defense: 0\n slash_defense: 0\n stab_defense: 0\ndescription: A smiling flight attendant in a crisp uniform, ready to assist passengers.\nhp: 0\nid: flight_attendant_copy\nidle_descriptions:\n - adjusts her name badge\n - smiles politely at you\nkind: combat\nname: Credit Checker!\nprotected: true\nranged: 0\nrespawn_ticks: 0\nscience: 0\nshop:\n buy_percentage: 0\n buys_anything: true\n change_percentage: 0\n items:\n - item_id: bronze_pickaxe\n restock_ticks: 0\n stock: 5\n message: SHOP SHOP\nspeed: 0\nstrength: 0\ntalk:\n nodes:\n start:\n options:\n - goto: \"\"\n text: None!\n - text: None\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T18:37:34-04:00","description":"Update mob bandit","file_path":"data/mobs/examples/bandit.yaml","old_content":"name: bandit\ndescription: \"A scrappy outlaw with a cybernetic arm and patched armor. He eyes you with predatory intent.\"\nattack: 10\nstrength: 12\ndefense: 12\nhp: 28\nspeed: 5\naggressive: true\nrespawn_ticks: 30\nattack_type: slash\nattack_bonus: 5\nstrength_bonus: 5\nstab_defense: 10\nslash_defense: 15\ncrush_defense: 8\nscience_defense: -5\nranged_defense: 12\nidle_descriptions:\n - \"scans the horizon for targets\"\n - \"wipes a blade on his sleeve\"\n - \"spits on the ground\"\n - \"adjusts a cybernetic knuckle\"\ncombat_descriptions:\n - \"slashes at %s with a serrated blade\"\n - \"delivers a crushing punch with a cybernetic fist\"\n - \"lunges at %s with a battle cry\"\nsize: medium\ndrops:\n remains: bones\n loot:\n - item_id: credits\n weight: 70\n quantity: 30\n - item_id: credits\n weight: 20\n quantity: 80\n - table: herb_table_low\n weight: 10\n","new_content":"aggressive: true\nassassin_level: 0\nattack: 10\nbonuses:\n attack_bonus: 0\n attack_type: stab\n strength_bonus: 0\ncombat_descriptions:\n - slashes at %s with a serrated blade\n - delivers a crushing punch with a cybernetic fist\n - lunges at %s with a battle cry\ndefense: 12\ndefenses:\n crush_defense: 0\n ranged_defense: 0\n science_defense: 0\n slash_defense: 0\n stab_defense: 0\ndescription: A scrappy outlaw with a cybernetic arm and patched armor. He eyes you with predatory intent.\ndrops:\n loot:\n - item_id: credits\n quantity: 30\n weight: 70\n - item_id: credits\n quantity: 80\n weight: 20\n - quantity: 0\n table: herb_table_low\n weight: 10\n remains: bones\nhp: 28\nid: bandit\nidle_descriptions:\n - scans the horizon for targets\n - wipes a blade on his sleeve\n - spits on the ground\n - adjusts a cybernetic knuckle\nkind: combat\nname: bandit\nprotected: false\nranged: 0\nrespawn_ticks: 30\nscience: 0\nsize: medium\nspeed: 5\nstrength: 12\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-01T18:39:27-04:00","description":"Update mob bandit","file_path":"data/mobs/examples/bandit.yaml","old_content":"aggressive: true\nassassin_level: 0\nattack: 10\nbonuses:\n attack_bonus: 0\n attack_type: stab\n strength_bonus: 0\ncombat_descriptions:\n - slashes at %s with a serrated blade\n - delivers a crushing punch with a cybernetic fist\n - lunges at %s with a battle cry\ndefense: 12\ndefenses:\n crush_defense: 0\n ranged_defense: 0\n science_defense: 0\n slash_defense: 0\n stab_defense: 0\ndescription: A scrappy outlaw with a cybernetic arm and patched armor. He eyes you with predatory intent.\ndrops:\n loot:\n - item_id: credits\n quantity: 30\n weight: 70\n - item_id: credits\n quantity: 80\n weight: 20\n - quantity: 0\n table: herb_table_low\n weight: 10\n remains: bones\nhp: 28\nid: bandit\nidle_descriptions:\n - scans the horizon for targets\n - wipes a blade on his sleeve\n - spits on the ground\n - adjusts a cybernetic knuckle\nkind: combat\nname: bandit\nprotected: false\nranged: 0\nrespawn_ticks: 30\nscience: 0\nsize: medium\nspeed: 5\nstrength: 12\nunique: false\n","new_content":"aggressive: true\nassassin_level: 0\nattack: 10\nbonuses:\n attack_bonus: 0\n attack_type: stab\n strength_bonus: 0\ncombat_descriptions:\n - slashes at %s with a serrated blade\n - delivers a crushing punch with a cybernetic fist\n - lunges at %s with a battle cry\ndefense: 12\ndefenses:\n crush_defense: 0\n ranged_defense: 0\n science_defense: 0\n slash_defense: 0\n stab_defense: 0\ndescription: A scrappy outlaw with a cybernetic arm and patched armor. He eyes you with predatory intent.\ndrops:\n loot:\n - item_id: credits\n quantity: 30\n weight: 70\n - item_id: credits\n quantity: 80\n weight: 20\n - quantity: 0\n table: herb_table_low\n weight: 10\n remains: bones\nhp: 28\nid: bandit\nidle_descriptions:\n - scans the horizon for targets\n - wipes a blade on his sleeve\n - spits on the ground\n - adjusts a cybernetic knuckle\nkind: task\nname: bandit\nprotected: false\nranged: 0\nrespawn_ticks: 30\nscience: 0\nsize: medium\nspeed: 5\nstrength: 12\nunique: false\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:51:59-04:00","description":"unlink 2003 north 1005","file_path":"data/rooms/intro/2003.yaml","old_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 1005\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2003\nname: Test Room\ncolor: A5\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:52:31-04:00","description":"unlink 999991 up 9999930","file_path":"data/rooms/example_unused/town/999991.yaml","old_content":"name: \"Town Square\"\ndescription: \"The central square of Lumbridge. A fountain gurgles peacefully in the center. Paths lead west toward the gathering grounds and east toward the production district.\"\nexits:\n east: 999992\n west: 9999922\n up: 9999930\n down: 9999931\nobjects:\n - id: lumby_fountain\n - id: charging_station\n - id: bank_booth\n - id: aps_tower\nmobs:\n - \"newbie_trainer\"\n - \"general_store_clerk\"\nitem_spawns:\n - id: cape_of_agility\n quantity: 1\n respawn_ticks: 60\n - id: graceful_hat\n quantity: 1\n respawn_ticks: 60\n - id: graceful_torso\n quantity: 1\n respawn_ticks: 60\n - id: graceful_legs\n quantity: 1\n respawn_ticks: 60\n - id: graceful_gloves\n quantity: 1\n respawn_ticks: 60\n - id: graceful_boots\n quantity: 1\n respawn_ticks: 60\n - id: graceful_cape\n quantity: 1\n respawn_ticks: 60\n - id: basic_deck\n quantity: 1\n respawn_ticks: 60\n - id: solar_identifier\n quantity: 1\n respawn_ticks: 60\n - id: hydro_identifier\n quantity: 1\n respawn_ticks: 60\n - id: cosmic_identifier\n quantity: 1\n respawn_ticks: 60\n - id: eco_identifier\n quantity: 1\n respawn_ticks: 60\n - id: chaos_identifier\n quantity: 1\n respawn_ticks: 60\n - id: bio_identifier\n quantity: 1\n respawn_ticks: 60\n - id: nature_identifier\n quantity: 1\n respawn_ticks: 60\n - id: law_identifier\n quantity: 1\n respawn_ticks: 60\n - id: death_identifier\n quantity: 1\n respawn_ticks: 60\n - id: blood_identifier\n quantity: 1\n respawn_ticks: 60\n - id: grimy_guam\n quantity: 5\n respawn_ticks: 60\n - id: vial_of_water\n quantity: 5\n respawn_ticks: 60\n - id: eye_of_newt\n quantity: 5\n respawn_ticks: 60\n","new_content":"id: 999991\nname: Town Square\ncolor: \"\"\ndescription:\n - text: The central square of Lumbridge. A fountain gurgles peacefully in the center. Paths lead west toward the gathering grounds and east toward the production district.\nexits:\n down:\n room: 9999931\n east:\n room: 999992\n west:\n room: 9999922\nobjects:\n - id: lumby_fountain\n - id: charging_station\n - id: bank_booth\n - id: aps_tower\nitem_spawns:\n - id: cape_of_agility\n quantity: 1\n respawn_ticks: 60\n - id: graceful_hat\n quantity: 1\n respawn_ticks: 60\n - id: graceful_torso\n quantity: 1\n respawn_ticks: 60\n - id: graceful_legs\n quantity: 1\n respawn_ticks: 60\n - id: graceful_gloves\n quantity: 1\n respawn_ticks: 60\n - id: graceful_boots\n quantity: 1\n respawn_ticks: 60\n - id: graceful_cape\n quantity: 1\n respawn_ticks: 60\n - id: basic_deck\n quantity: 1\n respawn_ticks: 60\n - id: solar_identifier\n quantity: 1\n respawn_ticks: 60\n - id: hydro_identifier\n quantity: 1\n respawn_ticks: 60\n - id: cosmic_identifier\n quantity: 1\n respawn_ticks: 60\n - id: eco_identifier\n quantity: 1\n respawn_ticks: 60\n - id: chaos_identifier\n quantity: 1\n respawn_ticks: 60\n - id: bio_identifier\n quantity: 1\n respawn_ticks: 60\n - id: nature_identifier\n quantity: 1\n respawn_ticks: 60\n - id: law_identifier\n quantity: 1\n respawn_ticks: 60\n - id: death_identifier\n quantity: 1\n respawn_ticks: 60\n - id: blood_identifier\n quantity: 1\n respawn_ticks: 60\n - id: grimy_guam\n quantity: 5\n respawn_ticks: 60\n - id: vial_of_water\n quantity: 5\n respawn_ticks: 60\n - id: eye_of_newt\n quantity: 5\n respawn_ticks: 60\nmobs:\n - id: newbie_trainer\n - id: general_store_clerk\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:52:31-04:00","description":"unlink 9999930 down 999991 (reverse)","file_path":"data/rooms/example_unused/town/9999930.yaml","old_content":"name: \"Above Town Square\"\ndescription: \"The central square of Lumbridge. A fountain gurgles peacefully in the center. Paths lead west toward the gathering grounds and east toward the production district.\"\nexits:\n down: 999991\n","new_content":"id: 9999930\nname: Above Town Square\ncolor: \"\"\ndescription:\n - text: The central square of Lumbridge. A fountain gurgles peacefully in the center. Paths lead west toward the gathering grounds and east toward the production district.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:52:44-04:00","description":"unlink 99999150 north 15","file_path":"data/rooms/example_unused/wilderness/99999150.yaml","old_content":"name: \"Hydroponics Bay\"\ndescription: \"A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\"\nexits:\n north: 15\n east: 151\n south: 152\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\n","new_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits:\n east:\n room: 151\n south:\n room: 152\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:52:50-04:00","description":"unlink 99999151 west 150","file_path":"data/rooms/example_unused/wilderness/99999151.yaml","old_content":"name: \"Herb Garden\"\ndescription: \"A dedicated section of the hydroponics bay for growing herbs. {28}Herb patches{/} are arranged in two rows under specialized grow lights. The air here smells faintly of fresh vegetation.\"\nexits:\n west: 150\nobjects:\n - id: herb_patch\n - id: herb_patch\n - id: herb_patch\n - id: herb_patch\n","new_content":"id: 99999151\nname: Herb Garden\ncolor: \"\"\ndescription:\n - text: A dedicated section of the hydroponics bay for growing herbs. {28}Herb patches{/} are arranged in two rows under specialized grow lights. The air here smells faintly of fresh vegetation.\nexits: {}\nobjects:\n - id: herb_patch\n - id: herb_patch\n - id: herb_patch\n - id: herb_patch\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:53:08-04:00","description":"unlink 9999915 south 99999150","file_path":"data/rooms/example_unused/town/9999915.yaml","old_content":"name: \"Pharmacy Lab\"\ndescription: \"Shelves lined with glass vials, dried herbs, and bubbling cauldrons. This area is not yet accessible.\"\nexits:\n east: 9999916\n west: 9999914\n south: 99999150\nmobs:\n - id: lesser_drone\n - id: lesser_drone\n","new_content":"id: 9999915\nname: Pharmacy Lab\ncolor: \"\"\ndescription:\n - text: Shelves lined with glass vials, dried herbs, and bubbling cauldrons. This area is not yet accessible.\nexits:\n east:\n room: 9999916\n west:\n room: 9999914\nobjects: []\nitem_spawns: []\nmobs:\n - id: lesser_drone\n - id: lesser_drone\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:53:08-04:00","description":"unlink 99999150 north 9999915 (reverse)","file_path":"data/rooms/example_unused/wilderness/99999150.yaml","old_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits:\n east:\n room: 151\n south:\n room: 152\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits:\n east:\n room: 151\n south:\n room: 152\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:53:30-04:00","description":"unlink 99999170 south 16","file_path":"data/rooms/example_unused/wilderness/99999170.yaml","old_content":"name: \"Local Neighborhood\"\ndescription: \"A quiet cul-de-sac of modest homes, each with a small garden plot. An estate directory terminal glows in the center, listing residents and property information.\"\nexits:\n south: 16\nobjects:\n - id: estate_directory\n","new_content":"id: 99999170\nname: Local Neighborhood\ncolor: \"\"\ndescription:\n - text: A quiet cul-de-sac of modest homes, each with a small garden plot. An estate directory terminal glows in the center, listing residents and property information.\nexits: {}\nobjects:\n - id: estate_directory\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:53:33-04:00","description":"unlink 99999171 west 16","file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"name: \"Lumberyard\"\ndescription: \"Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\"\nexits:\n west: 16\nmobs:\n - id: sawmill_operator\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:57:05-04:00","description":"create room 1005","file_path":"data/rooms/intro/1005.yaml","old_content":"","new_content":"exits:\n south: 2001\nid: 1005\nname: 'Room #1005'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\n - id: flight_attendant_copy\nname: Test Room\nobjects:\n - aliases: []\n description:\n - text: YOU FOUND HIM\n hidden: true\n name: hidden guy\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"id: 2001\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n north:\n room: 1005\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nobjects:\n - name: hidden guy\n hidden: true\n description:\n - text: YOU FOUND HIM\n - id: tree\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\n - id: flight_attendant_copy\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T16:57:06-04:00","description":"delete room 1005 (cleaned 1 exits)","file_path":"data/rooms/intro/1005.yaml","old_content":"exits:\n south: 2001\nid: 1005\nname: 'Room #1005'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/intro/2001.yaml","old_content":"id: 2001\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n north:\n room: 1005\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nobjects:\n - name: hidden guy\n hidden: true\n description:\n - text: YOU FOUND HIM\n - id: tree\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\n - id: flight_attendant_copy\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2001\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nobjects:\n - name: hidden guy\n hidden: true\n description:\n - text: YOU FOUND HIM\n - id: tree\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 1\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 1\nmobs:\n - id: man\n - id: flight_attendant_copy\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T16:57:08-04:00","description":"unlink 2004 northwest 2002","file_path":"data/rooms/intro/2004.yaml","old_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:57:08-04:00","description":"unlink 2002 southeast 2004 (reverse)","file_path":"data/rooms/intro/2002.yaml","old_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n southeast:\n room: 2004\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:57:09-04:00","description":"link 2004 northwest 2002","file_path":"data/rooms/intro/2004.yaml","old_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:57:09-04:00","description":"link 2002 southeast 2004 (reverse)","file_path":"data/rooms/intro/2002.yaml","old_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n southeast:\n room: 2004\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:58:04-04:00","description":"unlink 999994 north 999995","file_path":"data/rooms/example_unused/town/999994.yaml","old_content":"name: \"Woodcutting Glade\"\ndescription: \"A sunny glade at the edge of the forest. A sturdy tree stands here, perfect for practicing woodcutting. A solid rock formation near the edge of the glade looks like it could provide cover.\"\nexits:\n east: 999996\n north: 999995\n west: 999992\nobjects:\n - id: tree\n - id: tree\n - id: tree\n - id: tree\n - id: simple_rock\n - id: tutorial_lever\nmobs:\n - id: rat\n - id: rat\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 60\n - id: matches\n quantity: 100\n respawn_ticks: 120\n - id: firesteel\n quantity: 1\n respawn_ticks: 120\n - id: lighter\n quantity: 1\n respawn_ticks: 120\n - id: shortbow\n quantity: 1\n respawn_ticks: 60\n - id: bronze_arrow\n quantity: 100\n respawn_ticks: 60\n","new_content":"id: 999994\nname: Woodcutting Glade\ncolor: \"\"\ndescription:\n - text: A sunny glade at the edge of the forest. A sturdy tree stands here, perfect for practicing woodcutting. A solid rock formation near the edge of the glade looks like it could provide cover.\nexits:\n east:\n room: 999996\n west:\n room: 999992\nobjects:\n - id: tree\n - id: tree\n - id: tree\n - id: tree\n - id: simple_rock\n - id: tutorial_lever\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 60\n - id: matches\n quantity: 100\n respawn_ticks: 120\n - id: firesteel\n quantity: 1\n respawn_ticks: 120\n - id: lighter\n quantity: 1\n respawn_ticks: 120\n - id: shortbow\n quantity: 1\n respawn_ticks: 60\n - id: bronze_arrow\n quantity: 100\n respawn_ticks: 60\nmobs:\n - id: rat\n - id: rat\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:58:04-04:00","description":"unlink 999995 south 999994 (reverse)","file_path":"data/rooms/example_unused/town/999995.yaml","old_content":"name: \"Oak Grove\"\ndescription: \"A stand of young oak trees. The wood here is tougher but more valuable.\"\nexits:\n south: 999994\nobjects:\n - id: oak_tree\nitem_spawns:\n - id: iron_axe\n quantity: 1\n respawn_ticks: 60\n","new_content":"id: 999995\nname: Oak Grove\ncolor: \"\"\ndescription:\n - text: A stand of young oak trees. The wood here is tougher but more valuable.\nexits: {}\nobjects:\n - id: oak_tree\nitem_spawns:\n - id: iron_axe\n quantity: 1\n respawn_ticks: 60\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:58:18-04:00","description":"link 999995 south 999994","file_path":"data/rooms/example_unused/town/999995.yaml","old_content":"id: 999995\nname: Oak Grove\ncolor: \"\"\ndescription:\n - text: A stand of young oak trees. The wood here is tougher but more valuable.\nexits: {}\nobjects:\n - id: oak_tree\nitem_spawns:\n - id: iron_axe\n quantity: 1\n respawn_ticks: 60\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 999995\nname: Oak Grove\ncolor: \"\"\ndescription:\n - text: A stand of young oak trees. The wood here is tougher but more valuable.\nexits:\n south:\n room: 999994\nobjects:\n - id: oak_tree\nitem_spawns:\n - id: iron_axe\n quantity: 1\n respawn_ticks: 60\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:58:18-04:00","description":"link 999994 north 999995 (reverse)","file_path":"data/rooms/example_unused/town/999994.yaml","old_content":"id: 999994\nname: Woodcutting Glade\ncolor: \"\"\ndescription:\n - text: A sunny glade at the edge of the forest. A sturdy tree stands here, perfect for practicing woodcutting. A solid rock formation near the edge of the glade looks like it could provide cover.\nexits:\n east:\n room: 999996\n west:\n room: 999992\nobjects:\n - id: tree\n - id: tree\n - id: tree\n - id: tree\n - id: simple_rock\n - id: tutorial_lever\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 60\n - id: matches\n quantity: 100\n respawn_ticks: 120\n - id: firesteel\n quantity: 1\n respawn_ticks: 120\n - id: lighter\n quantity: 1\n respawn_ticks: 120\n - id: shortbow\n quantity: 1\n respawn_ticks: 60\n - id: bronze_arrow\n quantity: 100\n respawn_ticks: 60\nmobs:\n - id: rat\n - id: rat\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 999994\nname: Woodcutting Glade\ncolor: \"\"\ndescription:\n - text: A sunny glade at the edge of the forest. A sturdy tree stands here, perfect for practicing woodcutting. A solid rock formation near the edge of the glade looks like it could provide cover.\nexits:\n east:\n room: 999996\n north:\n room: 999995\n west:\n room: 999992\nobjects:\n - id: tree\n - id: tree\n - id: tree\n - id: tree\n - id: simple_rock\n - id: tutorial_lever\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 60\n - id: matches\n quantity: 100\n respawn_ticks: 120\n - id: firesteel\n quantity: 1\n respawn_ticks: 120\n - id: lighter\n quantity: 1\n respawn_ticks: 120\n - id: shortbow\n quantity: 1\n respawn_ticks: 60\n - id: bronze_arrow\n quantity: 100\n respawn_ticks: 60\nmobs:\n - id: rat\n - id: rat\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T16:58:57-04:00","description":"create room 99999153","file_path":"data/rooms/example_unused/wilderness/99999153.yaml","old_content":"","new_content":"exits:\n north: 99999171\nid: 99999153\nname: 'Room #99999153'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n south:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T16:58:58-04:00","description":"delete room 99999153 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999153.yaml","old_content":"exits:\n north: 99999171\nid: 99999153\nname: 'Room #99999153'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n south:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:27:58-04:00","description":"create room 99999153","file_path":"data/rooms/example_unused/wilderness/99999153.yaml","old_content":"","new_content":"exits:\n west: 99999171\nid: 99999153\nname: 'Room #99999153'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:28:04-04:00","description":"create room 99999154","file_path":"data/rooms/example_unused/wilderness/99999154.yaml","old_content":"","new_content":"exits:\n southeast: 99999153\nid: 99999154\nname: 'Room #99999154'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999153.yaml","old_content":"exits:\n west: 99999171\nid: 99999153\nname: 'Room #99999153'\n","new_content":"id: 99999153\nname: 'Room #99999153'\ncolor: \"\"\ndescription: []\nexits:\n northwest:\n room: 99999154\n west:\n room: 99999171\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:31:35-04:00","description":"unlink 99999154 southeast 99999153","file_path":"data/rooms/example_unused/wilderness/99999154.yaml","old_content":"exits:\n southeast: 99999153\nid: 99999154\nname: 'Room #99999154'\n","new_content":"id: 99999154\nname: 'Room #99999154'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:31:35-04:00","description":"unlink 99999153 northwest 99999154 (reverse)","file_path":"data/rooms/example_unused/wilderness/99999153.yaml","old_content":"id: 99999153\nname: 'Room #99999153'\ncolor: \"\"\ndescription: []\nexits:\n northwest:\n room: 99999154\n west:\n room: 99999171\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999153\nname: 'Room #99999153'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 99999171\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:33:11-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:33:13-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:34:04-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:34:06-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:41:30-04:00","description":"rename duplicate room data/rooms/1002.yaml to ID 123","file_path":"/home/workhorse/projects/thehouseoficarus/data/rooms/1002.yaml","new_file_path":"/home/workhorse/projects/thehouseoficarus/data/rooms/123.yaml","old_content":"name: \"Landing Pad\"\ndescription:\n - condition:\n player_flag: 1002_intro_done\n not: true\n text: \"A large, circular, concrete landing pad sits in the middle of a blue ocean with a transport shuttle taking up nearly all of the walkable area. A crowd of perhaps a dozen people are shambling out of a squat, doorless building to the north. A sign above the entryway reads \\\"Processing\\\"\"\n - text: \"A large, circular, concrete landing pad sits empty in the middle of a blue ocean that stretches to the horizon. North is a concrete path through a squat, doorless building with sign above the entryway reading \\\"Processing\\\"\"\nobjects:\n - name: crowd of people\n aliases: [line, group, passengers]\n hidden: true\n description:\n - condition:\n all_of:\n - player_flag: 1002_intro_done\n not: true\n - player_flag: 1002_lined_up\n text: \"A mass of people still onto the crowded platform, blocking your exit!\"\n - condition:\n all_of:\n - player_flag: 1002_intro_done\n not: true\n - player_flag: 1002_lined_up\n not: true\n text: \"A dozen or so passengers ready to leave, all with luggage. Their eyes are a mix of impatience, anxiety, and perhaps suspicion.\"\n - name: landing craft\n aliases: [shuttle, ship]\n hidden: true\n description:\n - condition:\n player_flag: 1002_intro_done\n not: true\n text: \"The small white craft has short, cute wings, a wide snub-nosed cockpit, and the rear hatch opened into a staircase. The low hum of its power plant vibrates the platform as it idles. You might guess it's a 95 ton Type-QS Passenger Shuttle. Just a guess though.\"\n - name: pilot\n hidden: true\n description:\n - condition:\n all_of:\n - player_flag: 1002_intro_done\n not: true\n - player_flag: 1002_lined_up\n text: \"The pilot stands straight as if about to escort royalty looking down his nose a bit at the passengers. He is quickly and professionally checking tickets.\"\n - name: building\n aliases: [processing]\n description: \"A building with no door on this side that looks like a giant cup of tea spilled towards you. It's built from large chunks of gray rock that must've come from the surface of Vesta.\"\n - name: sign\n description: \"The sign simply says 'Processing' in bold red letters. Beneath in smaller text it says 'Welcome to Vesta', seemingly added afterwards to try to give the sign some warmth.\"\nexits:\n up:\n room: 1001\n condition:\n player_flag: always_false\n blocked_message: \"You have no ticket, or reason, to leave Vesta.\"\n north:\n room: 1003\n condition:\n player_flag: 1002_lined_up\n blocked_message: \"A mass of people is still pouring out of the building!\"\n set_player_flags:\n 1002_intro_done: true\non_enter:\n - condition:\n player_flag: 1002_lined_up\n not: true\n delay: 7\n message: \"A young boy the crowd openly look you up and down a little bemused, as if you're heading the wrong direction.\"\n - condition:\n player_flag: 1002_lined_up\n not: true\n delay: 7\n message: \"The pilot pops out of the hatch of the craft and calls out \\\"Shuttle to Passenger Barge Denali. Tickets out, please! Nice and orderly!\\\"\"\n - condition:\n player_flag: 1002_lined_up\n not: true\n delay: 7\n message: \"The people all shuffle into a line, dragging their luggage out of the path to clear the way for you.\"\n set_player_flags:\n 1002_lined_up: true\n","new_content":"description:\n - condition:\n not: true\n player_flag: 1002_intro_done\n text: A large, circular, concrete landing pad sits in the middle of a blue ocean with a transport shuttle taking up nearly all of the walkable area. A crowd of perhaps a dozen people are shambling out of a squat, doorless building to the north. A sign above the entryway reads \"Processing\"\n - text: A large, circular, concrete landing pad sits empty in the middle of a blue ocean that stretches to the horizon. North is a concrete path through a squat, doorless building with sign above the entryway reading \"Processing\"\nexits:\n north:\n blocked_message: A mass of people is still pouring out of the building!\n condition:\n player_flag: 1002_lined_up\n room: 1003\n set_player_flags:\n 1002_intro_done: true\n up:\n blocked_message: You have no ticket, or reason, to leave Vesta.\n condition:\n player_flag: always_false\n room: 1001\nid: 123\nname: Landing Pad\nobjects:\n - aliases:\n - line\n - group\n - passengers\n description:\n - condition:\n all_of:\n - not: true\n player_flag: 1002_intro_done\n - player_flag: 1002_lined_up\n text: A mass of people still onto the crowded platform, blocking your exit!\n - condition:\n all_of:\n - not: true\n player_flag: 1002_intro_done\n - not: true\n player_flag: 1002_lined_up\n text: A dozen or so passengers ready to leave, all with luggage. Their eyes are a mix of impatience, anxiety, and perhaps suspicion.\n hidden: true\n name: crowd of people\n - aliases:\n - shuttle\n - ship\n description:\n - condition:\n not: true\n player_flag: 1002_intro_done\n text: The small white craft has short, cute wings, a wide snub-nosed cockpit, and the rear hatch opened into a staircase. The low hum of its power plant vibrates the platform as it idles. You might guess it's a 95 ton Type-QS Passenger Shuttle. Just a guess though.\n hidden: true\n name: landing craft\n - description:\n - condition:\n all_of:\n - not: true\n player_flag: 1002_intro_done\n - player_flag: 1002_lined_up\n text: The pilot stands straight as if about to escort royalty looking down his nose a bit at the passengers. He is quickly and professionally checking tickets.\n hidden: true\n name: pilot\n - aliases:\n - processing\n description: A building with no door on this side that looks like a giant cup of tea spilled towards you. It's built from large chunks of gray rock that must've come from the surface of Vesta.\n name: building\n - description: The sign simply says 'Processing' in bold red letters. Beneath in smaller text it says 'Welcome to Vesta', seemingly added afterwards to try to give the sign some warmth.\n name: sign\non_enter:\n - condition:\n not: true\n player_flag: 1002_lined_up\n delay: 7\n message: A young boy the crowd openly look you up and down a little bemused, as if you're heading the wrong direction.\n - condition:\n not: true\n player_flag: 1002_lined_up\n delay: 7\n message: The pilot pops out of the hatch of the craft and calls out \"Shuttle to Passenger Barge Denali. Tickets out, please! Nice and orderly!\"\n - condition:\n not: true\n player_flag: 1002_lined_up\n delay: 7\n message: The people all shuffle into a line, dragging their luggage out of the path to clear the way for you.\n set_player_flags:\n 1002_lined_up: true\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:41:44-04:00","description":"delete duplicate room file data/rooms/1001.yaml","file_path":"/home/workhorse/projects/thehouseoficarus/data/rooms/1001.yaml","old_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n credits: 0\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: true\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-07-03T17:43:10-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:43:15-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:43:37-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:43:38-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:45:07-04:00","description":"unlink 99999150 south 152","file_path":"data/rooms/example_unused/wilderness/99999150.yaml","old_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits:\n east:\n room: 151\n south:\n room: 152\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits:\n east:\n room: 151\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:45:09-04:00","description":"unlink 99999150 east 151","file_path":"data/rooms/example_unused/wilderness/99999150.yaml","old_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits:\n east:\n room: 151\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999150\nname: Hydroponics Bay\ncolor: \"\"\ndescription:\n - text: A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas.\nexits: {}\nobjects:\n - id: tool_shed\nitem_spawns:\n - id: rake\n quantity: 1\n respawn_ticks: 120\n - id: spade\n quantity: 1\n respawn_ticks: 120\n - id: watering_can\n quantity: 1\n respawn_ticks: 120\n - id: plant_cure\n quantity: 3\n respawn_ticks: 200\n - id: guam_seed\n quantity: 5\n respawn_ticks: 300\n - id: potato_seed\n quantity: 10\n respawn_ticks: 300\n - id: onion_seed\n quantity: 10\n respawn_ticks: 300\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:51:12-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:51:13-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n north: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\n south:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T17:59:42-04:00","description":"unlink 99999170 99999171","file_path":"data/rooms/example_unused/wilderness/99999170.yaml","old_content":"id: 99999170\nname: Local Neighborhood\ncolor: \"\"\ndescription:\n - text: A quiet cul-de-sac of modest homes, each with a small garden plot. An estate directory terminal glows in the center, listing residents and property information.\nexits: {}\nobjects:\n - id: estate_directory\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999170\nname: Local Neighborhood\ncolor: \"\"\ndescription:\n - text: A quiet cul-de-sac of modest homes, each with a small garden plot. An estate directory terminal glows in the center, listing residents and property information.\nexits: {}\nobjects:\n - id: estate_directory\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:59:42-04:00","description":"unlink 99999171 99999170 (reverse)","file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:59:43-04:00","description":"unlink 99999171 east 99999153","file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999153\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T17:59:43-04:00","description":"unlink 99999153 west 99999171 (reverse)","file_path":"data/rooms/example_unused/wilderness/99999153.yaml","old_content":"id: 99999153\nname: 'Room #99999153'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 99999171\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999153\nname: 'Room #99999153'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T18:28:11-04:00","description":"create room 1000000","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"","new_content":"exits:\n southeast: 999993\nid: 1000000\nname: 'Room #1000000'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/town/999993.yaml","old_content":"name: \"Fly Fishing Pool\"\ndescription: \"A calm pool where insects hover over the water. Perfect for fly fishing.\"\nexits:\n south: 999992\nobjects:\n - id: fly_fishing_spot\nitem_spawns:\n - id: fly_fishing_rod\n quantity: 1\n respawn_ticks: 30\n - id: feather\n quantity: 15\n respawn_ticks: 60\n","new_content":"id: 999993\nname: Fly Fishing Pool\ncolor: \"\"\ndescription:\n - text: A calm pool where insects hover over the water. Perfect for fly fishing.\nexits:\n northwest:\n room: 1000000\n south:\n room: 999992\nobjects:\n - id: fly_fishing_spot\nitem_spawns:\n - id: fly_fishing_rod\n quantity: 1\n respawn_ticks: 30\n - id: feather\n quantity: 15\n respawn_ticks: 60\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:28:23-04:00","description":"delete room 1000000 (cleaned 1 exits)","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"exits:\n southeast: 999993\nid: 1000000\nname: 'Room #1000000'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/town/999993.yaml","old_content":"id: 999993\nname: Fly Fishing Pool\ncolor: \"\"\ndescription:\n - text: A calm pool where insects hover over the water. Perfect for fly fishing.\nexits:\n northwest:\n room: 1000000\n south:\n room: 999992\nobjects:\n - id: fly_fishing_spot\nitem_spawns:\n - id: fly_fishing_rod\n quantity: 1\n respawn_ticks: 30\n - id: feather\n quantity: 15\n respawn_ticks: 60\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 999993\nname: Fly Fishing Pool\ncolor: \"\"\ndescription:\n - text: A calm pool where insects hover over the water. Perfect for fly fishing.\nexits:\n south:\n room: 999992\nobjects:\n - id: fly_fishing_spot\nitem_spawns:\n - id: fly_fishing_rod\n quantity: 1\n respawn_ticks: 30\n - id: feather\n quantity: 15\n respawn_ticks: 60\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:28:32-04:00","description":"create room 1000000","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"","new_content":"exits:\n north: 9999914\nid: 1000000\nname: 'Room #1000000'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/town/9999914.yaml","old_content":"name: \"Fletching Bench\"\ndescription: \"A workbench covered in wood shavings, feathers, and arrowheads. Racks of unfinished bows line the walls, and a pile of bowstrings sits in the corner.\"\nexits:\n east: 9999915\n west: 9999913\nmobs:\n - id: moss_giant\nitem_spawns:\n - id: bowstring\n quantity: 5\n respawn_ticks: 50\n - id: knife\n quantity: 1\n respawn_ticks: 50\n - id: chisel\n quantity: 1\n respawn_ticks: 50\n","new_content":"id: 9999914\nname: Fletching Bench\ncolor: \"\"\ndescription:\n - text: A workbench covered in wood shavings, feathers, and arrowheads. Racks of unfinished bows line the walls, and a pile of bowstrings sits in the corner.\nexits:\n east:\n room: 9999915\n south:\n room: 1000000\n west:\n room: 9999913\nobjects: []\nitem_spawns:\n - id: bowstring\n quantity: 5\n respawn_ticks: 50\n - id: knife\n quantity: 1\n respawn_ticks: 50\n - id: chisel\n quantity: 1\n respawn_ticks: 50\nmobs:\n - id: moss_giant\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:28:35-04:00","description":"delete room 1000000 (cleaned 1 exits)","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"exits:\n north: 9999914\nid: 1000000\nname: 'Room #1000000'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/town/9999914.yaml","old_content":"id: 9999914\nname: Fletching Bench\ncolor: \"\"\ndescription:\n - text: A workbench covered in wood shavings, feathers, and arrowheads. Racks of unfinished bows line the walls, and a pile of bowstrings sits in the corner.\nexits:\n east:\n room: 9999915\n south:\n room: 1000000\n west:\n room: 9999913\nobjects: []\nitem_spawns:\n - id: bowstring\n quantity: 5\n respawn_ticks: 50\n - id: knife\n quantity: 1\n respawn_ticks: 50\n - id: chisel\n quantity: 1\n respawn_ticks: 50\nmobs:\n - id: moss_giant\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999914\nname: Fletching Bench\ncolor: \"\"\ndescription:\n - text: A workbench covered in wood shavings, feathers, and arrowheads. Racks of unfinished bows line the walls, and a pile of bowstrings sits in the corner.\nexits:\n east:\n room: 9999915\n west:\n room: 9999913\nobjects: []\nitem_spawns:\n - id: bowstring\n quantity: 5\n respawn_ticks: 50\n - id: knife\n quantity: 1\n respawn_ticks: 50\n - id: chisel\n quantity: 1\n respawn_ticks: 50\nmobs:\n - id: moss_giant\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:28:38-04:00","description":"unlink 99999170 99999171","file_path":"data/rooms/example_unused/wilderness/99999170.yaml","old_content":"id: 99999170\nname: Local Neighborhood\ncolor: \"\"\ndescription:\n - text: A quiet cul-de-sac of modest homes, each with a small garden plot. An estate directory terminal glows in the center, listing residents and property information.\nexits: {}\nobjects:\n - id: estate_directory\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999170\nname: Local Neighborhood\ncolor: \"\"\ndescription:\n - text: A quiet cul-de-sac of modest homes, each with a small garden plot. An estate directory terminal glows in the center, listing residents and property information.\nexits: {}\nobjects:\n - id: estate_directory\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T18:28:38-04:00","description":"unlink 99999171 99999170 (reverse)","file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-07-03T18:29:14-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n south: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n north:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:17-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n south: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n north:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:17-04:00","description":"create room 99999155","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"","new_content":"exits:\n west: 99999171\nid: 99999155\nname: 'Room #99999155'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:18-04:00","description":"delete room 99999155 (cleaned 1 exits)","file_path":"data/rooms/example_unused/wilderness/99999155.yaml","old_content":"exits:\n west: 99999171\nid: 99999155\nname: 'Room #99999155'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/wilderness/99999171.yaml","old_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits:\n east:\n room: 99999155\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 99999171\nname: Lumberyard\ncolor: \"\"\ndescription:\n - text: Stacks of fresh-cut timber fill the air with the scent of pine. A massive industrial sawmill hums in the background, operated by a burly worker.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: sawmill_operator\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:20-04:00","description":"create room 1000000","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"","new_content":"exits:\n south: 9999911\nid: 1000000\nname: 'Room #1000000'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/town/9999911.yaml","old_content":"name: \"Kitchen\"\ndescription: \"A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\"\nexits:\n east: 9999912\n west: 9999910\nobjects:\n - id: cooking_range\nmobs:\n - id: zombie\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\n","new_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n north:\n room: 1000000\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:21-04:00","description":"delete room 1000000 (cleaned 1 exits)","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"exits:\n south: 9999911\nid: 1000000\nname: 'Room #1000000'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/town/9999911.yaml","old_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n north:\n room: 1000000\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:23-04:00","description":"create room 1000000","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"","new_content":"exits:\n south: 9999911\nid: 1000000\nname: 'Room #1000000'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/example_unused/town/9999911.yaml","old_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n north:\n room: 1000000\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]},{"time":"2026-07-03T18:29:24-04:00","description":"delete room 1000000 (cleaned 1 exits)","file_path":"data/rooms/example_unused/town/1000000.yaml","old_content":"exits:\n south: 9999911\nid: 1000000\nname: 'Room #1000000'\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/example_unused/town/9999911.yaml","old_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n north:\n room: 1000000\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999911\nname: Kitchen\ncolor: \"\"\ndescription:\n - text: A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients.\nexits:\n east:\n room: 9999912\n west:\n room: 9999910\nobjects:\n - id: cooking_range\nitem_spawns:\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 200\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 200\nmobs:\n - id: zombie\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n"}]}],"redo":null} \ No newline at end of file +{"history":[{"time":"2026-07-03T20:51:13-04:00","description":"create room 2","file_path":"data/rooms/22222/2.yaml","old_content":"","new_content":"description: An empty room.\nname: New Room\n","is_delete":false,"is_create":true},{"time":"2026-07-03T20:51:15-04:00","description":"delete room 2 (cleaned 0 exits)","file_path":"data/rooms/22222/2.yaml","old_content":"description: An empty room.\nname: New Room\n","new_content":"","is_delete":true,"is_create":false}],"redo":null} \ No newline at end of file diff --git a/data/rooms/1001.yaml b/data/rooms/1001.yaml deleted file mode 100644 index 6403b12..0000000 --- a/data/rooms/1001.yaml +++ /dev/null @@ -1,85 +0,0 @@ -description: - - condition: - not: true - player_flag: 1002_intro_done - text: A large, circular, concrete landing pad sits in the middle of a blue ocean with a transport shuttle taking up nearly all of the walkable area. A crowd of perhaps a dozen people are shambling out of a squat, doorless building to the north. A sign above the entryway reads "Processing" - - text: A large, circular, concrete landing pad sits empty in the middle of a blue ocean that stretches to the horizon. North is a concrete path through a squat, doorless building with sign above the entryway reading "Processing" -exits: - north: - blocked_message: A mass of people is still pouring out of the building! - condition: - player_flag: 1002_lined_up - room: 1003 - set_player_flags: - 1002_intro_done: true - up: - blocked_message: You have no ticket, or reason, to leave Vesta. - condition: - player_flag: always_false - room: 1001 -id: 123 -name: Landing Pad -objects: - - aliases: - - line - - group - - passengers - description: - - condition: - all_of: - - not: true - player_flag: 1002_intro_done - - player_flag: 1002_lined_up - text: A mass of people still onto the crowded platform, blocking your exit! - - condition: - all_of: - - not: true - player_flag: 1002_intro_done - - not: true - player_flag: 1002_lined_up - text: A dozen or so passengers ready to leave, all with luggage. Their eyes are a mix of impatience, anxiety, and perhaps suspicion. - hidden: true - name: crowd of people - - aliases: - - shuttle - - ship - description: - - condition: - not: true - player_flag: 1002_intro_done - text: The small white craft has short, cute wings, a wide snub-nosed cockpit, and the rear hatch opened into a staircase. The low hum of its power plant vibrates the platform as it idles. You might guess it's a 95 ton Type-QS Passenger Shuttle. Just a guess though. - hidden: true - name: landing craft - - description: - - condition: - all_of: - - not: true - player_flag: 1002_intro_done - - player_flag: 1002_lined_up - text: The pilot stands straight as if about to escort royalty looking down his nose a bit at the passengers. He is quickly and professionally checking tickets. - hidden: true - name: pilot - - aliases: - - processing - description: A building with no door on this side that looks like a giant cup of tea spilled towards you. It's built from large chunks of gray rock that must've come from the surface of Vesta. - name: building - - description: The sign simply says 'Processing' in bold red letters. Beneath in smaller text it says 'Welcome to Vesta', seemingly added afterwards to try to give the sign some warmth. - name: sign -on_enter: - - condition: - not: true - player_flag: 1002_lined_up - delay: 7 - message: A young boy the crowd openly look you up and down a little bemused, as if you're heading the wrong direction. - - condition: - not: true - player_flag: 1002_lined_up - delay: 7 - message: The pilot pops out of the hatch of the craft and calls out "Shuttle to Passenger Barge Denali. Tickets out, please! Nice and orderly!" - - condition: - not: true - player_flag: 1002_lined_up - delay: 7 - message: The people all shuffle into a line, dragging their luggage out of the path to clear the way for you. - set_player_flags: - 1002_lined_up: true diff --git a/data/rooms/example_unused/agility/99999200.yaml b/data/rooms/example_unused/agility/99999200.yaml deleted file mode 100644 index 7397d5d..0000000 --- a/data/rooms/example_unused/agility/99999200.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Agility Training Grounds" -description: "A cavernous space beneath the asteroid's surface, repurposed as a training facility. Scaffolding, pipes, and platforms fill the chamber. Signs point to three courses of increasing difficulty: {33}Ventilation Shaft{/} (beginner), {214}Rooftop{/} (intermediate), and {196}Reactor{/} (advanced)." -exits: - south: 9999917 - north: 99999201 - east: 99999210 - west: 99999220 diff --git a/data/rooms/example_unused/agility/99999201.yaml b/data/rooms/example_unused/agility/99999201.yaml deleted file mode 100644 index fcc25c1..0000000 --- a/data/rooms/example_unused/agility/99999201.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Ventilation Shaft - Corroded Wall" -description: "A towering wall of corroded ventilation panels rises before you. Rust-eaten handholds and buckled seams offer a treacherous path upward. The air smells of old metal and recycled atmosphere." -on_enter: - - message: "Type 'scramble' to climb the wall." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999202.yaml b/data/rooms/example_unused/agility/99999202.yaml deleted file mode 100644 index 7b4c6f9..0000000 --- a/data/rooms/example_unused/agility/99999202.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Ventilation Shaft - Coolant Pipe Walkway" -description: "A narrow coolant pipe stretches across a dark chasm. Condensation drips from its surface, making it slick. Far below, you can hear the distant hum of machinery." -on_enter: - - message: "Type 'balance' to cross the pipe." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999203.yaml b/data/rooms/example_unused/agility/99999203.yaml deleted file mode 100644 index f1d1a7f..0000000 --- a/data/rooms/example_unused/agility/99999203.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Ventilation Shaft - Shaft Gap" -description: "The ventilation shaft floor is missing here -- a jagged gap drops into darkness. The far side is just barely within jumping distance. Exposed wiring sparks intermittently below." -on_enter: - - message: "Type 'jump' to leap across the gap." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999204.yaml b/data/rooms/example_unused/agility/99999204.yaml deleted file mode 100644 index 1555dbc..0000000 --- a/data/rooms/example_unused/agility/99999204.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Ventilation Shaft - Narrow Vent" -description: "The passage narrows dramatically here, becoming a tight rectangular vent barely wide enough to fit through. Scratches on the metal walls suggest others have squeezed through before you." -on_enter: - - message: "Type 'crawl' to squeeze through the vent." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999205.yaml b/data/rooms/example_unused/agility/99999205.yaml deleted file mode 100644 index 2fc75c2..0000000 --- a/data/rooms/example_unused/agility/99999205.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Ventilation Shaft - Emergency Chute" -description: "A smooth metal chute angles steeply downward, polished by countless slides. An old emergency evacuation sign hangs crookedly on the wall. This is the final obstacle -- the chute leads back to the training grounds." -on_enter: - - message: "Type 'slide' to descend the chute." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999210.yaml b/data/rooms/example_unused/agility/99999210.yaml deleted file mode 100644 index de1d928..0000000 --- a/data/rooms/example_unused/agility/99999210.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Rooftop Course - Hab Block Wall" -description: "The exterior wall of Hab Block 7 rises three stories above the street. Rough permacrete and maintenance handholds provide a challenging climb. The city spreads out below, neon signs flickering in the perpetual twilight." -on_enter: - - message: "Type 'climb' to scale the wall." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999211.yaml b/data/rooms/example_unused/agility/99999211.yaml deleted file mode 100644 index 88fa6a9..0000000 --- a/data/rooms/example_unused/agility/99999211.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Rooftop Course - Building Gap" -description: "You stand on the edge of Hab Block 7's roof. Across a three-meter gap, the roof of Hab Block 8 awaits. The street below is a dizzying drop. A few old bootprints mark the takeoff point." -on_enter: - - message: "Type 'jump' to leap to the next building." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999212.yaml b/data/rooms/example_unused/agility/99999212.yaml deleted file mode 100644 index 2477956..0000000 --- a/data/rooms/example_unused/agility/99999212.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Rooftop Course - Cable Array" -description: "A tangle of power cables and data lines stretches between two antenna towers. One thick cable hangs low enough to grab. The gap below drops to a dark alleyway between hab blocks." -on_enter: - - message: "Type 'swing' to cross on the cable." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999213.yaml b/data/rooms/example_unused/agility/99999213.yaml deleted file mode 100644 index 8918dbe..0000000 --- a/data/rooms/example_unused/agility/99999213.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Rooftop Course - Narrow Beam" -description: "A structural I-beam extends across the gap between two buildings, no wider than your foot. It sways slightly in the recycled air currents. Someone has scratched tally marks into the near end." -on_enter: - - message: "Type 'balance' to cross the beam." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999214.yaml b/data/rooms/example_unused/agility/99999214.yaml deleted file mode 100644 index 13f759a..0000000 --- a/data/rooms/example_unused/agility/99999214.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Rooftop Course - Maintenance Railing" -description: "A high maintenance railing blocks the path forward, topped with sensor equipment and warning labels. It's too high to step over but the right technique could clear it. Beyond the railing, the course continues." -on_enter: - - message: "Type 'vault' to clear the railing." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999215.yaml b/data/rooms/example_unused/agility/99999215.yaml deleted file mode 100644 index 062d4a1..0000000 --- a/data/rooms/example_unused/agility/99999215.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Rooftop Course - Rooftop Edge" -description: "The final jump. The gap here is wider than any before -- a full four meters of empty air between you and the landing platform. Far below, the streets of the asteroid colony pulse with dim light. This is the last obstacle." -on_enter: - - message: "Type 'leap' to make the final jump." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999220.yaml b/data/rooms/example_unused/agility/99999220.yaml deleted file mode 100644 index 7fa4b8d..0000000 --- a/data/rooms/example_unused/agility/99999220.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Scaffolding" -description: "Massive metal scaffolding surrounds the outer reactor housing. The structure vibrates with the reactor's pulse. Heat radiates from every surface, and warning klaxons sound periodically in the distance." -on_enter: - - message: "Type 'climb' to ascend the scaffolding." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999221.yaml b/data/rooms/example_unused/agility/99999221.yaml deleted file mode 100644 index 010bd44..0000000 --- a/data/rooms/example_unused/agility/99999221.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Coolant Chain" -description: "A heavy chain hangs from an overhead crane, suspended above the reactor cooling pit. The pit glows with an eerie blue-green light. The chain is your only way across -- the gantry ahead is the landing zone." -on_enter: - - message: "Type 'swing' to cross on the chain." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999222.yaml b/data/rooms/example_unused/agility/99999222.yaml deleted file mode 100644 index 0f8f4b9..0000000 --- a/data/rooms/example_unused/agility/99999222.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Steam Pipe" -description: "An enormous steam pipe, two meters in diameter, stretches across the reactor chamber. Steam vents periodically blast from pressure valves along its length. The pipe's surface is warm but not scalding -- yet." -on_enter: - - message: "Type 'balance' to traverse the pipe." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999223.yaml b/data/rooms/example_unused/agility/99999223.yaml deleted file mode 100644 index 5eccf14..0000000 --- a/data/rooms/example_unused/agility/99999223.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Platform Gap" -description: "A section of the reactor maintenance platform has collapsed into the void below. Emergency barriers block the edges, but someone has moved them aside here. The gap is intimidating but clearable." -on_enter: - - message: "Type 'jump' to clear the gap." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999224.yaml b/data/rooms/example_unused/agility/99999224.yaml deleted file mode 100644 index 274c425..0000000 --- a/data/rooms/example_unused/agility/99999224.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Service Conduit" -description: "A narrow service conduit leads through the reactor shielding. Radiation warning symbols are painted on every surface. Damaged wiring hangs from the ceiling, sparking occasionally. It's the only way forward." -on_enter: - - message: "Type 'crawl' to enter the conduit." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999225.yaml b/data/rooms/example_unused/agility/99999225.yaml deleted file mode 100644 index e4aa70e..0000000 --- a/data/rooms/example_unused/agility/99999225.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Radiation Barrier" -description: "A containment barrier hums with energy, its surface shimmering with a faint purple glow. It pulses on and off in a regular cycle. Beyond it, the final stretch of the course is visible." -on_enter: - - message: "Type 'vault' to clear the barrier." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility/99999226.yaml b/data/rooms/example_unused/agility/99999226.yaml deleted file mode 100644 index 6c35e88..0000000 --- a/data/rooms/example_unused/agility/99999226.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Reactor Course - Reactor Chasm" -description: "The final obstacle. A massive chasm separates you from the exit platform, the reactor's coolant pool churning far below in shades of luminous green. A narrow runway of grating leads to the edge. This is the longest leap on the course." -on_enter: - - message: "Type 'leap' to make the final jump." -exits: - down: - room: 99999200 - blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999200.yaml b/data/rooms/example_unused/agility2/99999200.yaml new file mode 100644 index 0000000..7397d5d --- /dev/null +++ b/data/rooms/example_unused/agility2/99999200.yaml @@ -0,0 +1,7 @@ +name: "Agility Training Grounds" +description: "A cavernous space beneath the asteroid's surface, repurposed as a training facility. Scaffolding, pipes, and platforms fill the chamber. Signs point to three courses of increasing difficulty: {33}Ventilation Shaft{/} (beginner), {214}Rooftop{/} (intermediate), and {196}Reactor{/} (advanced)." +exits: + south: 9999917 + north: 99999201 + east: 99999210 + west: 99999220 diff --git a/data/rooms/example_unused/agility2/99999201.yaml b/data/rooms/example_unused/agility2/99999201.yaml new file mode 100644 index 0000000..fcc25c1 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999201.yaml @@ -0,0 +1,8 @@ +name: "Ventilation Shaft - Corroded Wall" +description: "A towering wall of corroded ventilation panels rises before you. Rust-eaten handholds and buckled seams offer a treacherous path upward. The air smells of old metal and recycled atmosphere." +on_enter: + - message: "Type 'scramble' to climb the wall." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999202.yaml b/data/rooms/example_unused/agility2/99999202.yaml new file mode 100644 index 0000000..7b4c6f9 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999202.yaml @@ -0,0 +1,8 @@ +name: "Ventilation Shaft - Coolant Pipe Walkway" +description: "A narrow coolant pipe stretches across a dark chasm. Condensation drips from its surface, making it slick. Far below, you can hear the distant hum of machinery." +on_enter: + - message: "Type 'balance' to cross the pipe." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999203.yaml b/data/rooms/example_unused/agility2/99999203.yaml new file mode 100644 index 0000000..f1d1a7f --- /dev/null +++ b/data/rooms/example_unused/agility2/99999203.yaml @@ -0,0 +1,8 @@ +name: "Ventilation Shaft - Shaft Gap" +description: "The ventilation shaft floor is missing here -- a jagged gap drops into darkness. The far side is just barely within jumping distance. Exposed wiring sparks intermittently below." +on_enter: + - message: "Type 'jump' to leap across the gap." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999204.yaml b/data/rooms/example_unused/agility2/99999204.yaml new file mode 100644 index 0000000..1555dbc --- /dev/null +++ b/data/rooms/example_unused/agility2/99999204.yaml @@ -0,0 +1,8 @@ +name: "Ventilation Shaft - Narrow Vent" +description: "The passage narrows dramatically here, becoming a tight rectangular vent barely wide enough to fit through. Scratches on the metal walls suggest others have squeezed through before you." +on_enter: + - message: "Type 'crawl' to squeeze through the vent." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999205.yaml b/data/rooms/example_unused/agility2/99999205.yaml new file mode 100644 index 0000000..2fc75c2 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999205.yaml @@ -0,0 +1,8 @@ +name: "Ventilation Shaft - Emergency Chute" +description: "A smooth metal chute angles steeply downward, polished by countless slides. An old emergency evacuation sign hangs crookedly on the wall. This is the final obstacle -- the chute leads back to the training grounds." +on_enter: + - message: "Type 'slide' to descend the chute." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999210.yaml b/data/rooms/example_unused/agility2/99999210.yaml new file mode 100644 index 0000000..de1d928 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999210.yaml @@ -0,0 +1,8 @@ +name: "Rooftop Course - Hab Block Wall" +description: "The exterior wall of Hab Block 7 rises three stories above the street. Rough permacrete and maintenance handholds provide a challenging climb. The city spreads out below, neon signs flickering in the perpetual twilight." +on_enter: + - message: "Type 'climb' to scale the wall." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999211.yaml b/data/rooms/example_unused/agility2/99999211.yaml new file mode 100644 index 0000000..88fa6a9 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999211.yaml @@ -0,0 +1,8 @@ +name: "Rooftop Course - Building Gap" +description: "You stand on the edge of Hab Block 7's roof. Across a three-meter gap, the roof of Hab Block 8 awaits. The street below is a dizzying drop. A few old bootprints mark the takeoff point." +on_enter: + - message: "Type 'jump' to leap to the next building." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999212.yaml b/data/rooms/example_unused/agility2/99999212.yaml new file mode 100644 index 0000000..2477956 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999212.yaml @@ -0,0 +1,8 @@ +name: "Rooftop Course - Cable Array" +description: "A tangle of power cables and data lines stretches between two antenna towers. One thick cable hangs low enough to grab. The gap below drops to a dark alleyway between hab blocks." +on_enter: + - message: "Type 'swing' to cross on the cable." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999213.yaml b/data/rooms/example_unused/agility2/99999213.yaml new file mode 100644 index 0000000..8918dbe --- /dev/null +++ b/data/rooms/example_unused/agility2/99999213.yaml @@ -0,0 +1,8 @@ +name: "Rooftop Course - Narrow Beam" +description: "A structural I-beam extends across the gap between two buildings, no wider than your foot. It sways slightly in the recycled air currents. Someone has scratched tally marks into the near end." +on_enter: + - message: "Type 'balance' to cross the beam." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999214.yaml b/data/rooms/example_unused/agility2/99999214.yaml new file mode 100644 index 0000000..13f759a --- /dev/null +++ b/data/rooms/example_unused/agility2/99999214.yaml @@ -0,0 +1,8 @@ +name: "Rooftop Course - Maintenance Railing" +description: "A high maintenance railing blocks the path forward, topped with sensor equipment and warning labels. It's too high to step over but the right technique could clear it. Beyond the railing, the course continues." +on_enter: + - message: "Type 'vault' to clear the railing." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999215.yaml b/data/rooms/example_unused/agility2/99999215.yaml new file mode 100644 index 0000000..062d4a1 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999215.yaml @@ -0,0 +1,8 @@ +name: "Rooftop Course - Rooftop Edge" +description: "The final jump. The gap here is wider than any before -- a full four meters of empty air between you and the landing platform. Far below, the streets of the asteroid colony pulse with dim light. This is the last obstacle." +on_enter: + - message: "Type 'leap' to make the final jump." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999220.yaml b/data/rooms/example_unused/agility2/99999220.yaml new file mode 100644 index 0000000..7fa4b8d --- /dev/null +++ b/data/rooms/example_unused/agility2/99999220.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Scaffolding" +description: "Massive metal scaffolding surrounds the outer reactor housing. The structure vibrates with the reactor's pulse. Heat radiates from every surface, and warning klaxons sound periodically in the distance." +on_enter: + - message: "Type 'climb' to ascend the scaffolding." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999221.yaml b/data/rooms/example_unused/agility2/99999221.yaml new file mode 100644 index 0000000..010bd44 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999221.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Coolant Chain" +description: "A heavy chain hangs from an overhead crane, suspended above the reactor cooling pit. The pit glows with an eerie blue-green light. The chain is your only way across -- the gantry ahead is the landing zone." +on_enter: + - message: "Type 'swing' to cross on the chain." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999222.yaml b/data/rooms/example_unused/agility2/99999222.yaml new file mode 100644 index 0000000..0f8f4b9 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999222.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Steam Pipe" +description: "An enormous steam pipe, two meters in diameter, stretches across the reactor chamber. Steam vents periodically blast from pressure valves along its length. The pipe's surface is warm but not scalding -- yet." +on_enter: + - message: "Type 'balance' to traverse the pipe." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999223.yaml b/data/rooms/example_unused/agility2/99999223.yaml new file mode 100644 index 0000000..5eccf14 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999223.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Platform Gap" +description: "A section of the reactor maintenance platform has collapsed into the void below. Emergency barriers block the edges, but someone has moved them aside here. The gap is intimidating but clearable." +on_enter: + - message: "Type 'jump' to clear the gap." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999224.yaml b/data/rooms/example_unused/agility2/99999224.yaml new file mode 100644 index 0000000..274c425 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999224.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Service Conduit" +description: "A narrow service conduit leads through the reactor shielding. Radiation warning symbols are painted on every surface. Damaged wiring hangs from the ceiling, sparking occasionally. It's the only way forward." +on_enter: + - message: "Type 'crawl' to enter the conduit." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999225.yaml b/data/rooms/example_unused/agility2/99999225.yaml new file mode 100644 index 0000000..e4aa70e --- /dev/null +++ b/data/rooms/example_unused/agility2/99999225.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Radiation Barrier" +description: "A containment barrier hums with energy, its surface shimmering with a faint purple glow. It pulses on and off in a regular cycle. Beyond it, the final stretch of the course is visible." +on_enter: + - message: "Type 'vault' to clear the barrier." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/agility2/99999226.yaml b/data/rooms/example_unused/agility2/99999226.yaml new file mode 100644 index 0000000..6c35e88 --- /dev/null +++ b/data/rooms/example_unused/agility2/99999226.yaml @@ -0,0 +1,8 @@ +name: "Reactor Course - Reactor Chasm" +description: "The final obstacle. A massive chasm separates you from the exit platform, the reactor's coolant pool churning far below in shades of luminous green. A narrow runway of grating leads to the edge. This is the longest leap on the course." +on_enter: + - message: "Type 'leap' to make the final jump." +exits: + down: + room: 99999200 + blocked_message: "" diff --git a/data/rooms/example_unused/player_housing/99999300.yaml b/data/rooms/example_unused/player_housing/99999300.yaml index 986d1dd..ae9cbf9 100644 --- a/data/rooms/example_unused/player_housing/99999300.yaml +++ b/data/rooms/example_unused/player_housing/99999300.yaml @@ -1,7 +1,16 @@ -name: "Player House: Entrance Hall" -description: "A cozy entrance hall with polished floors and warm lighting. A welcome mat greets visitors at the door." +id: 99999300 +name: 'Player House: Entrance Hall' +color: "" +description: + - text: A cozy entrance hall with polished floors and warm lighting. A welcome mat greets visitors at the door. exits: - south: 99999170 - north: 99999301 + north: + room: 99999301 objects: - id: charging_station +item_spawns: [] +mobs: [] +on_enter: [] +hazard: "" +block_transport: false +triggers: [] diff --git a/data/rooms/example_unused/underground/9999950.yaml b/data/rooms/example_unused/underground/9999950.yaml deleted file mode 100644 index 8701533..0000000 --- a/data/rooms/example_unused/underground/9999950.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: "The Assassin's Den" -description: "A dimly lit basement accessible through a trapdoor. Tactical maps and bounty posters line the walls. The air smells of gun oil and burnt ozone. {141}The Client{/} sits behind a reinforced desk." -exits: - up: 9999931 -mobs: - - "client" diff --git a/data/rooms/example_unused/underground/9999951.yaml b/data/rooms/example_unused/underground/9999951.yaml deleted file mode 100644 index 9c7707a..0000000 --- a/data/rooms/example_unused/underground/9999951.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: "Sewer Tunnels" -description: "Dark, damp tunnels beneath the settlement. The floor is slick with moisture and something {82}slimy{/}. The smell is indescribable." -exits: - north: 9999950 - south: 9999952 -mobs: - - "slug" - - "slug" - - "slug" diff --git a/data/rooms/example_unused/underground/9999952.yaml b/data/rooms/example_unused/underground/9999952.yaml deleted file mode 100644 index 40c89a9..0000000 --- a/data/rooms/example_unused/underground/9999952.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Abandoned Sector" -description: "A decommissioned sector of the asteroid's infrastructure. Broken monitors flicker and exposed wiring {214}sparks{/} dangerously." -exits: - north: 9999951 - south: 9999953 -mobs: - - "drone" - - "drone" diff --git a/data/rooms/example_unused/underground/9999953.yaml b/data/rooms/example_unused/underground/9999953.yaml deleted file mode 100644 index 4396cfb..0000000 --- a/data/rooms/example_unused/underground/9999953.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Deep Tunnels" -description: "The tunnels descend deeper into the asteroid's core. Strange chitinous scraping echoes from the darkness. The walls are scarred with {130}claw marks{/}." -exits: - north: 9999952 - south: 9999954 -mobs: - - "crawler" - - "crawler" diff --git a/data/rooms/example_unused/underground/9999954.yaml b/data/rooms/example_unused/underground/9999954.yaml deleted file mode 100644 index 8348801..0000000 --- a/data/rooms/example_unused/underground/9999954.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "The Void Chamber" -description: "A vast cavern where reality seems to thin. The air shimmers with {141}spectral energy{/} and strange whispers fill your mind." -exits: - north: 9999953 - down: 9999955 -mobs: - - "phantom" - - "phantom" diff --git a/data/rooms/example_unused/underground/9999955.yaml b/data/rooms/example_unused/underground/9999955.yaml deleted file mode 100644 index 2cce00a..0000000 --- a/data/rooms/example_unused/underground/9999955.yaml +++ /dev/null @@ -1,11 +0,0 @@ -name: "The Deeper Tunnels" -description: "A junction deep beneath the void chamber. The walls here are reinforced with pre-regression alloys. Several passages branch off into the darkness, and you can hear the sounds of machinery echoing from all directions. A steep shaft descends further into the depths." -exits: - up: 9999954 - north: 9999956 - east: 9999957 - south: 9999958 - west: 9999960 - down: 9999962 -mobs: - - id: security_turret diff --git a/data/rooms/example_unused/underground/9999956.yaml b/data/rooms/example_unused/underground/9999956.yaml deleted file mode 100644 index b5996ae..0000000 --- a/data/rooms/example_unused/underground/9999956.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Irradiated Sector" -description: "Warning symbols cover every surface, their paint long since faded. A faint green glow emanates from cracks in the walls. The air is thick with the taste of old radiation." -exits: - south: 9999955 -mobs: - - id: ghoul - - id: ghoul - - id: corrupted_scientist diff --git a/data/rooms/example_unused/underground/9999957.yaml b/data/rooms/example_unused/underground/9999957.yaml deleted file mode 100644 index be20359..0000000 --- a/data/rooms/example_unused/underground/9999957.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Drone Assembly" -description: "A long-abandoned drone manufacturing bay. Conveyor belts lie still, and half-assembled drone chassis hang from the ceiling. A few of them still twitch with residual power." -exits: - west: 9999955 -mobs: - - id: war_drone - - id: war_drone diff --git a/data/rooms/example_unused/underground/9999958.yaml b/data/rooms/example_unused/underground/9999958.yaml deleted file mode 100644 index 09bd869..0000000 --- a/data/rooms/example_unused/underground/9999958.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Security Checkpoint" -description: "A fortified security station with blast shields and a decommissioned weapons locker. Scorch marks on the walls tell the story of a last stand." -exits: - north: 9999955 - south: 9999959 -mobs: - - id: enforcer_bot diff --git a/data/rooms/example_unused/underground/9999959.yaml b/data/rooms/example_unused/underground/9999959.yaml deleted file mode 100644 index 29ca4fc..0000000 --- a/data/rooms/example_unused/underground/9999959.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Plasma Core" -description: "A massive plasma containment chamber with cracked magnetic coils lining the walls. Streams of superheated gas leak from the containment vessel, forming shimmering wraith-like shapes in the air." -exits: - north: 9999958 -mobs: - - id: plasma_wraith - - id: plasma_wraith - - id: feral_cyborg diff --git a/data/rooms/example_unused/underground/9999960.yaml b/data/rooms/example_unused/underground/9999960.yaml deleted file mode 100644 index 56cca24..0000000 --- a/data/rooms/example_unused/underground/9999960.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Heavy Mech Bay" -description: "An enormous maintenance bay built to house assault mechs. A gantry crane hangs overhead, and hydraulic lifts dot the floor. The bay's occupant is still active — and it has noticed you." -exits: - east: 9999955 - west: 9999961 -mobs: - - id: heavy_mech diff --git a/data/rooms/example_unused/underground/9999961.yaml b/data/rooms/example_unused/underground/9999961.yaml deleted file mode 100644 index 2d1e75c..0000000 --- a/data/rooms/example_unused/underground/9999961.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: "Synth Lab" -description: "A sterile laboratory where combat androids were designed and assembled. White panels line the walls, some splattered with old coolant stains. Diagnostic screens flicker with corrupted data." -exits: - east: 9999960 -mobs: - - id: elite_synth diff --git a/data/rooms/example_unused/underground/9999962.yaml b/data/rooms/example_unused/underground/9999962.yaml deleted file mode 100644 index b5b89c4..0000000 --- a/data/rooms/example_unused/underground/9999962.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Abandoned Bunker" -description: "A fortified bunker from some forgotten conflict. Sandbags are piled in the corners and spent shell casings litter the floor. A solitary figure stands watch over the remains." -exits: - up: 9999955 - down: 9999963 -mobs: - - id: veteran_merc diff --git a/data/rooms/example_unused/underground/9999963.yaml b/data/rooms/example_unused/underground/9999963.yaml deleted file mode 100644 index fca468e..0000000 --- a/data/rooms/example_unused/underground/9999963.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Magma Conduit" -description: "A geothermal vent has been tapped and routed through industrial conduits. The heat is oppressive, and molten rivulets course through channels in the floor. Something moves within the glowing flow." -exits: - up: 9999962 - down: 9999964 -mobs: - - id: molten_elemental diff --git a/data/rooms/example_unused/underground/9999964.yaml b/data/rooms/example_unused/underground/9999964.yaml deleted file mode 100644 index 4e74383..0000000 --- a/data/rooms/example_unused/underground/9999964.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "The Foundry" -description: "A vast smelting facility where sentinels were once forged. Massive crucibles hang from chains, and rivers of cooled slag form a maze-like floor. A single iron sentinel stands guard over the dormant machinery." -exits: - up: 9999963 - down: 9999965 -mobs: - - id: iron_sentinel diff --git a/data/rooms/example_unused/underground/9999965.yaml b/data/rooms/example_unused/underground/9999965.yaml deleted file mode 100644 index 424a4cd..0000000 --- a/data/rooms/example_unused/underground/9999965.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Titan's Rest" -description: "A colossal vault built to house something immense. The ceiling vanishes into darkness above, and the walls are etched with maintenance schematics for a machine of staggering proportions. At the center, a titan sentinel awakens." -exits: - up: 64 - down: 66 -mobs: - - id: titan_sentinel diff --git a/data/rooms/example_unused/underground/9999966.yaml b/data/rooms/example_unused/underground/9999966.yaml deleted file mode 100644 index a876453..0000000 --- a/data/rooms/example_unused/underground/9999966.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Psionic Nexus" -description: "Reality grows thin here. The walls are covered in strange geometric patterns that hurt to look at directly. A low hum vibrates through your skull, and the air seems to bend around a central point of unseen pressure." -exits: - up: 65 - down: 67 -mobs: - - id: psionic_entity diff --git a/data/rooms/example_unused/underground/9999967.yaml b/data/rooms/example_unused/underground/9999967.yaml deleted file mode 100644 index 494fe9e..0000000 --- a/data/rooms/example_unused/underground/9999967.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Ancient Chamber" -description: "A perfectly spherical room carved from an unknown black metal. Glowing runes spiral across every surface in patterns that predate the asteroid itself. At the center, an ancient construct stirs from its eons-long vigil." -exits: - up: 66 - down: 68 -mobs: - - id: ancient_construct diff --git a/data/rooms/example_unused/underground/9999968.yaml b/data/rooms/example_unused/underground/9999968.yaml deleted file mode 100644 index 6fe1aa0..0000000 --- a/data/rooms/example_unused/underground/9999968.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: "The Void" -description: "The bottom of the world. Light itself seems to hesitate before entering this place. The floor is unnaturally smooth black glass, and the only sound is the beating of your own heart. Something waits in the darkness — something that was here before the asteroid, before the colony, before anything." -exits: - up: 67 -mobs: - - id: void_reaper diff --git a/data/rooms/example_unused/underground2/9999950.yaml b/data/rooms/example_unused/underground2/9999950.yaml new file mode 100644 index 0000000..3d01f72 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999950.yaml @@ -0,0 +1,16 @@ +id: 9999950 +name: The Assassin's Den +color: "" +description: + - text: A dimly lit basement accessible through a trapdoor. Tactical maps and bounty posters line the walls. The air smells of gun oil and burnt ozone. {141}The Client{/} sits behind a reinforced desk. +exits: + up: + room: 9999931 +objects: [] +item_spawns: [] +mobs: + - id: client +on_enter: [] +hazard: "" +block_transport: false +triggers: [] diff --git a/data/rooms/example_unused/underground2/9999951.yaml b/data/rooms/example_unused/underground2/9999951.yaml new file mode 100644 index 0000000..9c7707a --- /dev/null +++ b/data/rooms/example_unused/underground2/9999951.yaml @@ -0,0 +1,9 @@ +name: "Sewer Tunnels" +description: "Dark, damp tunnels beneath the settlement. The floor is slick with moisture and something {82}slimy{/}. The smell is indescribable." +exits: + north: 9999950 + south: 9999952 +mobs: + - "slug" + - "slug" + - "slug" diff --git a/data/rooms/example_unused/underground2/9999952.yaml b/data/rooms/example_unused/underground2/9999952.yaml new file mode 100644 index 0000000..40c89a9 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999952.yaml @@ -0,0 +1,8 @@ +name: "Abandoned Sector" +description: "A decommissioned sector of the asteroid's infrastructure. Broken monitors flicker and exposed wiring {214}sparks{/} dangerously." +exits: + north: 9999951 + south: 9999953 +mobs: + - "drone" + - "drone" diff --git a/data/rooms/example_unused/underground2/9999953.yaml b/data/rooms/example_unused/underground2/9999953.yaml new file mode 100644 index 0000000..4396cfb --- /dev/null +++ b/data/rooms/example_unused/underground2/9999953.yaml @@ -0,0 +1,8 @@ +name: "Deep Tunnels" +description: "The tunnels descend deeper into the asteroid's core. Strange chitinous scraping echoes from the darkness. The walls are scarred with {130}claw marks{/}." +exits: + north: 9999952 + south: 9999954 +mobs: + - "crawler" + - "crawler" diff --git a/data/rooms/example_unused/underground2/9999954.yaml b/data/rooms/example_unused/underground2/9999954.yaml new file mode 100644 index 0000000..8348801 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999954.yaml @@ -0,0 +1,8 @@ +name: "The Void Chamber" +description: "A vast cavern where reality seems to thin. The air shimmers with {141}spectral energy{/} and strange whispers fill your mind." +exits: + north: 9999953 + down: 9999955 +mobs: + - "phantom" + - "phantom" diff --git a/data/rooms/example_unused/underground2/9999955.yaml b/data/rooms/example_unused/underground2/9999955.yaml new file mode 100644 index 0000000..2cce00a --- /dev/null +++ b/data/rooms/example_unused/underground2/9999955.yaml @@ -0,0 +1,11 @@ +name: "The Deeper Tunnels" +description: "A junction deep beneath the void chamber. The walls here are reinforced with pre-regression alloys. Several passages branch off into the darkness, and you can hear the sounds of machinery echoing from all directions. A steep shaft descends further into the depths." +exits: + up: 9999954 + north: 9999956 + east: 9999957 + south: 9999958 + west: 9999960 + down: 9999962 +mobs: + - id: security_turret diff --git a/data/rooms/example_unused/underground2/9999956.yaml b/data/rooms/example_unused/underground2/9999956.yaml new file mode 100644 index 0000000..b5996ae --- /dev/null +++ b/data/rooms/example_unused/underground2/9999956.yaml @@ -0,0 +1,8 @@ +name: "Irradiated Sector" +description: "Warning symbols cover every surface, their paint long since faded. A faint green glow emanates from cracks in the walls. The air is thick with the taste of old radiation." +exits: + south: 9999955 +mobs: + - id: ghoul + - id: ghoul + - id: corrupted_scientist diff --git a/data/rooms/example_unused/underground2/9999957.yaml b/data/rooms/example_unused/underground2/9999957.yaml new file mode 100644 index 0000000..be20359 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999957.yaml @@ -0,0 +1,7 @@ +name: "Drone Assembly" +description: "A long-abandoned drone manufacturing bay. Conveyor belts lie still, and half-assembled drone chassis hang from the ceiling. A few of them still twitch with residual power." +exits: + west: 9999955 +mobs: + - id: war_drone + - id: war_drone diff --git a/data/rooms/example_unused/underground2/9999958.yaml b/data/rooms/example_unused/underground2/9999958.yaml new file mode 100644 index 0000000..09bd869 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999958.yaml @@ -0,0 +1,7 @@ +name: "Security Checkpoint" +description: "A fortified security station with blast shields and a decommissioned weapons locker. Scorch marks on the walls tell the story of a last stand." +exits: + north: 9999955 + south: 9999959 +mobs: + - id: enforcer_bot diff --git a/data/rooms/example_unused/underground2/9999959.yaml b/data/rooms/example_unused/underground2/9999959.yaml new file mode 100644 index 0000000..29ca4fc --- /dev/null +++ b/data/rooms/example_unused/underground2/9999959.yaml @@ -0,0 +1,8 @@ +name: "Plasma Core" +description: "A massive plasma containment chamber with cracked magnetic coils lining the walls. Streams of superheated gas leak from the containment vessel, forming shimmering wraith-like shapes in the air." +exits: + north: 9999958 +mobs: + - id: plasma_wraith + - id: plasma_wraith + - id: feral_cyborg diff --git a/data/rooms/example_unused/underground2/9999960.yaml b/data/rooms/example_unused/underground2/9999960.yaml new file mode 100644 index 0000000..56cca24 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999960.yaml @@ -0,0 +1,7 @@ +name: "Heavy Mech Bay" +description: "An enormous maintenance bay built to house assault mechs. A gantry crane hangs overhead, and hydraulic lifts dot the floor. The bay's occupant is still active — and it has noticed you." +exits: + east: 9999955 + west: 9999961 +mobs: + - id: heavy_mech diff --git a/data/rooms/example_unused/underground2/9999961.yaml b/data/rooms/example_unused/underground2/9999961.yaml new file mode 100644 index 0000000..2d1e75c --- /dev/null +++ b/data/rooms/example_unused/underground2/9999961.yaml @@ -0,0 +1,6 @@ +name: "Synth Lab" +description: "A sterile laboratory where combat androids were designed and assembled. White panels line the walls, some splattered with old coolant stains. Diagnostic screens flicker with corrupted data." +exits: + east: 9999960 +mobs: + - id: elite_synth diff --git a/data/rooms/example_unused/underground2/9999962.yaml b/data/rooms/example_unused/underground2/9999962.yaml new file mode 100644 index 0000000..b5b89c4 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999962.yaml @@ -0,0 +1,7 @@ +name: "Abandoned Bunker" +description: "A fortified bunker from some forgotten conflict. Sandbags are piled in the corners and spent shell casings litter the floor. A solitary figure stands watch over the remains." +exits: + up: 9999955 + down: 9999963 +mobs: + - id: veteran_merc diff --git a/data/rooms/example_unused/underground2/9999963.yaml b/data/rooms/example_unused/underground2/9999963.yaml new file mode 100644 index 0000000..fca468e --- /dev/null +++ b/data/rooms/example_unused/underground2/9999963.yaml @@ -0,0 +1,7 @@ +name: "Magma Conduit" +description: "A geothermal vent has been tapped and routed through industrial conduits. The heat is oppressive, and molten rivulets course through channels in the floor. Something moves within the glowing flow." +exits: + up: 9999962 + down: 9999964 +mobs: + - id: molten_elemental diff --git a/data/rooms/example_unused/underground2/9999964.yaml b/data/rooms/example_unused/underground2/9999964.yaml new file mode 100644 index 0000000..4e74383 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999964.yaml @@ -0,0 +1,7 @@ +name: "The Foundry" +description: "A vast smelting facility where sentinels were once forged. Massive crucibles hang from chains, and rivers of cooled slag form a maze-like floor. A single iron sentinel stands guard over the dormant machinery." +exits: + up: 9999963 + down: 9999965 +mobs: + - id: iron_sentinel diff --git a/data/rooms/example_unused/underground2/9999965.yaml b/data/rooms/example_unused/underground2/9999965.yaml new file mode 100644 index 0000000..424a4cd --- /dev/null +++ b/data/rooms/example_unused/underground2/9999965.yaml @@ -0,0 +1,7 @@ +name: "Titan's Rest" +description: "A colossal vault built to house something immense. The ceiling vanishes into darkness above, and the walls are etched with maintenance schematics for a machine of staggering proportions. At the center, a titan sentinel awakens." +exits: + up: 64 + down: 66 +mobs: + - id: titan_sentinel diff --git a/data/rooms/example_unused/underground2/9999966.yaml b/data/rooms/example_unused/underground2/9999966.yaml new file mode 100644 index 0000000..a876453 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999966.yaml @@ -0,0 +1,7 @@ +name: "Psionic Nexus" +description: "Reality grows thin here. The walls are covered in strange geometric patterns that hurt to look at directly. A low hum vibrates through your skull, and the air seems to bend around a central point of unseen pressure." +exits: + up: 65 + down: 67 +mobs: + - id: psionic_entity diff --git a/data/rooms/example_unused/underground2/9999967.yaml b/data/rooms/example_unused/underground2/9999967.yaml new file mode 100644 index 0000000..494fe9e --- /dev/null +++ b/data/rooms/example_unused/underground2/9999967.yaml @@ -0,0 +1,7 @@ +name: "Ancient Chamber" +description: "A perfectly spherical room carved from an unknown black metal. Glowing runes spiral across every surface in patterns that predate the asteroid itself. At the center, an ancient construct stirs from its eons-long vigil." +exits: + up: 66 + down: 68 +mobs: + - id: ancient_construct diff --git a/data/rooms/example_unused/underground2/9999968.yaml b/data/rooms/example_unused/underground2/9999968.yaml new file mode 100644 index 0000000..6fe1aa0 --- /dev/null +++ b/data/rooms/example_unused/underground2/9999968.yaml @@ -0,0 +1,6 @@ +name: "The Void" +description: "The bottom of the world. Light itself seems to hesitate before entering this place. The floor is unnaturally smooth black glass, and the only sound is the beating of your own heart. Something waits in the darkness — something that was here before the asteroid, before the colony, before anything." +exits: + up: 67 +mobs: + - id: void_reaper diff --git a/data/rooms/test222/1.yaml b/data/rooms/test222/1.yaml new file mode 100644 index 0000000..e110b2e --- /dev/null +++ b/data/rooms/test222/1.yaml @@ -0,0 +1,2 @@ +description: An empty room. +name: New Room diff --git a/internal/admin/api_map.go b/internal/admin/api_map.go index e0476b3..7759029 100644 --- a/internal/admin/api_map.go +++ b/internal/admin/api_map.go @@ -28,6 +28,18 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) { if dir != "" { if low, ok := findLowestLoadableRoom(s, dir); ok { seed = low + } else { + writeJSON(w, map[string]any{ + "rooms": []any{}, + "links": []any{}, + "upLinks": []any{}, + "downLinks": []any{}, + "dir": dir, + "seed": 0, + "disconnected": []any{}, + "bounds": map[string]int{"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, + }) + return } } diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go index d1193f0..b7f7d0e 100644 --- a/internal/admin/api_rooms.go +++ b/internal/admin/api_rooms.go @@ -318,22 +318,85 @@ func (s *AdminServer) handleRoomDirs(w http.ResponseWriter, r *http.Request) { if err != nil || !d.IsDir() || path == base { return nil } - entries, rdErr := os.ReadDir(path) - if rdErr != nil { - return nil - } - for _, e := range entries { - if !e.IsDir() && filepath.Ext(e.Name()) == ".yaml" { - rel, _ := filepath.Rel(base, path) - dirs = append(dirs, rel) - return nil - } - } + rel, _ := filepath.Rel(base, path) + dirs = append(dirs, rel) return nil }) writeJSON(w, dirs) } +func (s *AdminServer) handleRenameRoomDir(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + var body struct { + Dir string `json:"dir"` + NewName string `json:"new_name"` + } + if err := readJSON(r, &body); err != nil || body.NewName == "" { + writeJSON(w, map[string]any{"error": "invalid"}) + return + } + if body.Dir == "" { + writeJSON(w, map[string]any{"error": "cannot rename root"}) + return + } + newName := strings.TrimSpace(body.NewName) + if newName == "" || strings.ContainsAny(newName, "/\\") || newName == "." || newName == ".." { + writeJSON(w, map[string]any{"error": "invalid directory name"}) + return + } + base := filepath.Join(s.dataDir, "rooms") + parent := filepath.Dir(body.Dir) + oldPath := filepath.Join(base, body.Dir) + newRel := filepath.Join(parent, newName) + newPath := filepath.Join(base, newRel) + if _, err := os.Stat(oldPath); os.IsNotExist(err) { + writeJSON(w, map[string]any{"error": "directory not found"}) + return + } + if _, err := os.Stat(newPath); err == nil { + writeJSON(w, map[string]any{"error": "directory already exists: " + newRel}) + return + } + if err := os.Rename(oldPath, newPath); err != nil { + writeJSON(w, map[string]any{"error": "rename failed: " + err.Error()}) + return + } + s.world.RebuildRoomIndex(s.dataDir) + writeJSON(w, map[string]any{"ok": true, "new_dir": newRel}) +} + +func (s *AdminServer) handleCreateRoomDir(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + var body struct { + Name string `json:"name"` + } + if err := readJSON(r, &body); err != nil { + writeJSON(w, map[string]any{"error": "invalid"}) + return + } + name := strings.TrimSpace(body.Name) + if name == "" || strings.ContainsAny(name, "/\\") || name == "." || name == ".." { + writeJSON(w, map[string]any{"error": "invalid directory name"}) + return + } + newPath := filepath.Join(s.dataDir, "rooms", name) + if _, err := os.Stat(newPath); err == nil { + writeJSON(w, map[string]any{"error": "directory already exists"}) + return + } + if err := os.Mkdir(newPath, 0755); err != nil { + writeJSON(w, map[string]any{"error": "create failed: " + err.Error()}) + return + } + writeJSON(w, map[string]any{"ok": true, "name": name}) +} + func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodPost: @@ -844,3 +907,63 @@ func (s *AdminServer) handleResolveDuplicate(w http.ResponseWriter, r *http.Requ writeJSON(w, map[string]any{"error": "unknown action: " + body.Action}) } } + +func (s *AdminServer) handleCreateEmptyRoom(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) + return + } + var body struct { + Dir string `json:"dir"` + } + if err := readJSON(r, &body); err != nil { + writeJSON(w, map[string]any{"error": "invalid"}) + return + } + base := filepath.Join(s.dataDir, "rooms") + targetDir := base + if body.Dir != "" { + targetDir = filepath.Join(base, body.Dir) + if _, err := os.Stat(targetDir); os.IsNotExist(err) { + writeJSON(w, map[string]any{"error": "directory not found"}) + return + } + } + + used := map[int]bool{} + filepath.WalkDir(base, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || filepath.Ext(d.Name()) != ".yaml" { + return nil + } + name := d.Name() + id, convErr := strconv.Atoi(name[:len(name)-5]) + if convErr == nil && id > 0 { + used[id] = true + } + return nil + }) + + id := 1 + for used[id] { + id++ + } + + path := filepath.Join(targetDir, strconv.Itoa(id)+".yaml") + m := map[string]any{ + "name": "New Room", + "description": "An empty room.", + } + newContent, writeErr := writeMapAsYAML(path, m) + if writeErr != nil { + writeJSON(w, map[string]any{"error": "write room: " + writeErr.Error()}) + return + } + s.world.RebuildRoomIndex(s.dataDir) + s.undoStack.Push(ChangeDesc{ + Description: fmt.Sprintf("create room %d", id), + FilePath: path, + NewContent: newContent, + IsCreate: true, + }) + writeJSON(w, map[string]any{"room": map[string]any{"id": id, "name": "New Room"}}) +} diff --git a/internal/admin/server.go b/internal/admin/server.go index 227201b..ef95e73 100644 --- a/internal/admin/server.go +++ b/internal/admin/server.go @@ -109,10 +109,13 @@ func NewServer(cfg *config.Config, useTLS bool, accountStore *player.AccountStor apiMux := http.NewServeMux() apiMux.HandleFunc("/api/map", s.handleMap) apiMux.HandleFunc("/api/room-dirs", s.handleRoomDirs) + apiMux.HandleFunc("/api/room-dirs/rename", s.handleRenameRoomDir) + apiMux.HandleFunc("/api/room-dirs/create", s.handleCreateRoomDir) apiMux.HandleFunc("/api/rooms/link", s.handleRoomLink) apiMux.HandleFunc("/api/rooms/move", s.handleRoomMove) apiMux.HandleFunc("/api/rooms/rename", s.handleRoomRename) apiMux.HandleFunc("/api/rooms", s.handleRooms) + apiMux.HandleFunc("/api/rooms/new-empty", s.handleCreateEmptyRoom) apiMux.HandleFunc("/api/rooms/", s.handleRoomByID) apiMux.HandleFunc("/api/objects", s.handleObjects) apiMux.HandleFunc("/api/objects/", s.handleObjectByID) @@ -306,6 +309,7 @@ func (s *AdminServer) handleLogin(w http.ResponseWriter, r *http.Request) { } s.setAuthCookie(w, account) + s.undoStack.Clear() http.Redirect(w, r, "/", http.StatusFound) } @@ -430,7 +434,12 @@ func (s *AdminServer) doUndo(w http.ResponseWriter, r *http.Request) { return } s.rebuildAfterUndo(change) - writeJSON(w, map[string]any{"message": "Undid: " + change.ShortDesc()}) + resp := map[string]any{"message": "Undid: " + change.ShortDesc()} + dups := behavior.CheckDuplicateIDs(filepath.Join(s.dataDir, "rooms")) + if len(dups) > 0 { + resp["has_duplicates"] = true + } + writeJSON(w, resp) } func (s *AdminServer) doRedo(w http.ResponseWriter, r *http.Request) { @@ -444,7 +453,12 @@ func (s *AdminServer) doRedo(w http.ResponseWriter, r *http.Request) { return } s.rebuildAfterUndo(change) - writeJSON(w, map[string]any{"message": "Redid: " + change.ShortDesc()}) + resp := map[string]any{"message": "Redid: " + change.ShortDesc()} + dups := behavior.CheckDuplicateIDs(filepath.Join(s.dataDir, "rooms")) + if len(dups) > 0 { + resp["has_duplicates"] = true + } + writeJSON(w, resp) } func (s *AdminServer) rebuildAfterUndo(change *ChangeDesc) { diff --git a/internal/admin/static/admin.css b/internal/admin/static/admin.css index 8c3ee8e..f068207 100644 --- a/internal/admin/static/admin.css +++ b/internal/admin/static/admin.css @@ -41,10 +41,15 @@ body{font-family:monospace;background:var(--bg);color:var(--text);min-height:100 .search-bar input{width:100%;padding:6px 8px;font-size:13px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:3px} .login{max-width:360px;margin:80px auto;background:var(--panel);padding:30px;border:1px solid var(--border);border-radius:6px} .login h1{font-size:18px;margin-bottom:20px;text-align:center} -.z-controls{position:absolute;top:12px;left:12px;display:flex;gap:6px;align-items:center;background:var(--panel);padding:6px 10px;border-radius:4px;border:1px solid var(--border);z-index:10} +.z-controls-wrapper{position:absolute;top:12px;left:12px;z-index:10} +.z-controls{position:relative;display:flex;gap:6px;align-items:center;background:var(--panel);padding:6px 10px;border-radius:4px;border:1px solid var(--border)} .z-controls button{width:28px;height:28px;font-size:16px;line-height:1;background:var(--input-bg);color:var(--text);border:1px solid var(--border);border-radius:3px;cursor:pointer} .z-controls button:hover{background:var(--accent)} .z-controls .z-label{font-size:13px;min-width:40px;text-align:center;font-weight:bold} +.z-controls .z-text-btn{width:auto} +.z-controls .z-text-btn.active{background:var(--accent);border-color:#1a5a8e} +.z-controls .z-sep{width:1px;height:20px;background:var(--border);flex-shrink:0} +.z-dir-form{display:none;position:absolute;left:0;top:calc(100% + 4px);background:var(--panel);border:1px solid var(--border);border-radius:4px;padding:8px 10px;z-index:11;gap:6px;align-items:center;white-space:nowrap} .room-tooltip{position:absolute;background:var(--panel);border:1px solid var(--border);padding:6px 10px;border-radius:3px;font-size:11px;pointer-events:none;z-index:20;white-space:nowrap} .notification{position:fixed;bottom:16px;right:16px;background:var(--panel);border:1px solid var(--border);padding:10px 16px;border-radius:4px;font-size:12px;z-index:100;animation:fadeIn .2s} .notification.error{border-color:var(--danger)} diff --git a/internal/admin/static/admin.js b/internal/admin/static/admin.js index cce3bc9..f8e9d13 100644 --- a/internal/admin/static/admin.js +++ b/internal/admin/static/admin.js @@ -31,11 +31,11 @@ window.updateUndoBar = function() { }; window.doUndo = function() { - API.post('/api/undo/undo').then(function(r) { notify(r.message || 'Undo complete', 'success'); updateUndoBar(); if(window.refreshPage)refreshPage(); }).catch(function(e) { notify('Undo failed: '+e.message, 'error'); }); + API.post('/api/undo/undo').then(function(r) { notify(r.message || 'Undo complete', 'success'); updateUndoBar(); if(r.has_duplicates) { window.location = '/'; return; } if(window.refreshPage)refreshPage(); }).catch(function(e) { notify('Undo failed: '+e.message, 'error'); }); }; window.doRedo = function() { - API.post('/api/undo/redo').then(function(r) { notify(r.message || 'Redo complete', 'success'); updateUndoBar(); if(window.refreshPage)refreshPage(); }).catch(function(e) { notify('Redo failed: '+e.message, 'error'); }); + API.post('/api/undo/redo').then(function(r) { notify(r.message || 'Redo complete', 'success'); updateUndoBar(); if(r.has_duplicates) { window.location = '/'; return; } if(window.refreshPage)refreshPage(); }).catch(function(e) { notify('Redo failed: '+e.message, 'error'); }); }; window.addEventListener('keydown', function(e) { diff --git a/internal/admin/static/map.js b/internal/admin/static/map.js index 6acec47..740edf3 100644 --- a/internal/admin/static/map.js +++ b/internal/admin/static/map.js @@ -135,6 +135,13 @@ function loadMap() { } renderMap(data); renderDisconnectedList(data); + var newRoomBtn = $('#newRoomBtn'); + var newRoomSep = $('#newRoomSep'); + if (newRoomBtn && newRoomSep) { + var empty = !data.rooms || data.rooms.length === 0; + newRoomBtn.style.display = empty ? '' : 'none'; + newRoomSep.style.display = empty ? '' : 'none'; + } if (wasDirChange && data.seed) { selectRoom(data.seed); } @@ -1716,4 +1723,116 @@ function updateDirSelect() { } } +function showRenameDir() { + if (currentDir === '') { notify('Cannot rename root', 'error'); return; } + hideNewDir(); + $('#renameDirBtn').classList.add('active'); + var form = $('#renameDirForm'); + form.style.display = 'flex'; + var base = currentDir.includes('/') ? currentDir.split('/').pop() : currentDir; + var input = $('#renameDirInput'); + input.placeholder = base; + input.value = ''; + input.focus(); +} + +function cancelRenameDir() { + $('#renameDirForm').style.display = 'none'; + $('#renameDirBtn').classList.remove('active'); +} + +function confirmRenameDir() { + var newName = $('#renameDirInput').value.trim(); + if (!newName) { notify('Enter a directory name', 'error'); return; } + if (newName.indexOf('/') !== -1 || newName.indexOf('\\') !== -1 || newName === '.' || newName === '..') { notify('Invalid directory name', 'error'); return; } + API.post('/api/room-dirs/rename', {dir: currentDir, new_name: newName}).then(function(r) { + if (r.error) { notify(r.error, 'error'); return; } + notify('Renamed to ' + newName, 'success'); + cancelRenameDir(); + currentDir = r.new_dir; + reloadRoomDirs(function() { + changeDir(r.new_dir); + }); + }).catch(function(e) { notify('Rename failed: ' + e.message, 'error'); }); +} + +function showNewDir() { + hideRenameDir(); + $('#newDirBtn').classList.add('active'); + var form = $('#newDirForm'); + form.style.display = 'flex'; + var input = $('#newDirInput'); + input.value = ''; + input.focus(); +} + +function cancelNewDir() { + $('#newDirForm').style.display = 'none'; + $('#newDirBtn').classList.remove('active'); +} + +function confirmNewDir() { + var name = $('#newDirInput').value.trim(); + if (!name) { notify('Enter a directory name', 'error'); return; } + if (name.indexOf('/') !== -1 || name.indexOf('\\') !== -1 || name === '.' || name === '..') { notify('Invalid directory name', 'error'); return; } + API.post('/api/room-dirs/create', {name: name}).then(function(r) { + if (r.error) { notify(r.error, 'error'); return; } + notify('Created ' + name, 'success'); + cancelNewDir(); + currentDir = name; + reloadRoomDirs(function() { + changeDir(name); + }); + }).catch(function(e) { notify('Create failed: ' + e.message, 'error'); }); +} + +function onDirInputKey(event, type) { + if (event.key === 'Enter') { + event.preventDefault(); + if (type === 'rename') confirmRenameDir(); + else if (type === 'new') confirmNewDir(); + } else if (event.key === 'Escape') { + event.preventDefault(); + if (type === 'rename') cancelRenameDir(); + else if (type === 'new') cancelNewDir(); + } +} + +function createEmptyRoom() { + API.post('/api/rooms/new-empty', {dir: currentDir}).then(function(r) { + if (r.error) { notify(r.error, 'error'); return; } + notify('Created room ' + r.room.id, 'success'); + loadMap().then(function() { + if (r.room && r.room.id) selectRoom(r.room.id); + }); + }).catch(function(e) { notify('Create room failed: ' + e.message, 'error'); }); +} + +function hideRenameDir() { + $('#renameDirForm').style.display = 'none'; + $('#renameDirBtn').classList.remove('active'); +} + +function hideNewDir() { + $('#newDirForm').style.display = 'none'; + $('#newDirBtn').classList.remove('active'); +} + +function reloadRoomDirs(cb) { + API.get('/api/room-dirs').then(function(dirs) { + var sel = $('#dirSelect'); + if (sel) { + sel.innerHTML = ''; + dirs.forEach(function(d) { + var opt = document.createElement('option'); + opt.value = d; + opt.textContent = d || '(root)'; + sel.appendChild(opt); + }); + } + updateDirSelect(); + if (cb) cb(dirs); + }); +} + document.addEventListener('DOMContentLoaded', function() { loadRoomDirs(function() { loadMap(); }); initPanelResize(); }); diff --git a/internal/admin/templates/duplicate-rooms.html b/internal/admin/templates/duplicate-rooms.html index 4e603bb..9533460 100644 --- a/internal/admin/templates/duplicate-rooms.html +++ b/internal/admin/templates/duplicate-rooms.html @@ -64,9 +64,9 @@ function checkDups() { } function deleteDupFile(path) { - if (!confirm('Delete this file?\n\n' + path)) return; API.post('/api/rooms/resolve-duplicate', {path: path, action: 'delete'}).then(function() { notify('Deleted', 'success'); + updateUndoBar(); checkDups(); }).catch(function(e) { notify('Delete failed: ' + e.message, 'error'); @@ -77,9 +77,9 @@ function renameDupFile(path, inputId) { var el = document.getElementById(inputId); var newID = parseInt(el.value, 10); if (!newID || newID <= 0) { notify('Enter a valid new room ID', 'error'); return; } - if (!confirm('Rename this file to ID ' + newID + '?\n\n' + path)) return; API.post('/api/rooms/resolve-duplicate', {path: path, action: 'rename', new_id: newID}).then(function() { notify('Renamed to ' + newID, 'success'); + updateUndoBar(); checkDups(); }).catch(function(e) { notify('Rename failed: ' + e.message, 'error'); @@ -89,5 +89,6 @@ function renameDupFile(path, inputId) { function esc(s) { return String(s || '').replace(/&/g,'&').replace(//g,'>'); } function escAttr(s) { return String(s || '').replace(/&/g,'&').replace(/"/g,'"'); } checkDups(); +window.refreshPage = checkDups; {{end}} diff --git a/internal/admin/templates/map.html b/internal/admin/templates/map.html index 3bcbb30..1e45f8e 100644 --- a/internal/admin/templates/map.html +++ b/internal/admin/templates/map.html @@ -7,20 +7,38 @@
-
- - Z=0 - - - Area: - - Zoom: - - - +
+
+ Area: + + + + + + + + Z=0 + + + Zoom: + + + + +
+ + + +
+
+ + + +
+
diff --git a/internal/admin/undo.go b/internal/admin/undo.go index fb91a15..f69fd9f 100644 --- a/internal/admin/undo.go +++ b/internal/admin/undo.go @@ -330,3 +330,12 @@ func (us *UndoStack) load() { us.history = fromEntries(saveData.History) log.Printf("undo: loaded %d history entries", len(us.history)) } + +func (us *UndoStack) Clear() { + us.mu.Lock() + defer us.mu.Unlock() + us.history = nil + us.redo = nil + os.Remove(us.filePath) + log.Printf("undo: cleared history") +} diff --git a/internal/validate/checks.go b/internal/validate/checks.go index ccf996c..974998a 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -1024,6 +1024,39 @@ func validateRoomGrid(s Source) []Issue { } } + onConf := func(origin int) func(c world.GridConflict) { + return func(c world.GridConflict) { + switch c.Kind { + case "twist": + issues = append(issues, Issue{ + Level: "ERROR", + Type: "integrity", + Message: fmt.Sprintf( + "Grid twist: room %d (via %d %s) maps to (%d,%d,%d) but was already placed at (%d,%d,%d) [origin %d]", + c.Target, c.From, c.Dir, c.Want[0], c.Want[1], c.Want[2], c.Existing[0], c.Existing[1], c.Existing[2], origin), + }) + case "overlap": + issues = append(issues, Issue{ + Level: "ERROR", + Type: "integrity", + Message: fmt.Sprintf( + "Grid overlap: room %d (via %d %s) wants (%d,%d,%d), already used by room %d [origin %d]", + c.Target, c.From, c.Dir, c.Want[0], c.Want[1], c.Want[2], c.Occupier, origin), + }) + } + } + } + + for id := range roomIndex { + if placed[id] { + continue + } + grid := world.BuildGrid(id, load, include, onConf(id)) + for rid := range grid.Coord { + placed[rid] = true + } + } + return issues } -- cgit v1.2.3