diff options
| author | historia <[not public]> | 2026-06-30 03:57:52 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-30 03:57:52 -0400 |
| commit | 712072209ab5e3b3a14ebc0c770b020afe544560 (patch) | |
| tree | f5247fa8e03ed327ecb6cbff622bf6bdccb2066c | |
| parent | 7a4b91304061777e7b3365b505d1e74878043d35 (diff) | |
| download | thehouseoficarus-712072209ab5e3b3a14ebc0c770b020afe544560.tar.gz | |
feat: all admin mapping features working
| -rw-r--r-- | data/.admin_history.yaml | 2 | ||||
| -rw-r--r-- | data/rooms/intro/1001.yaml | 17 | ||||
| -rw-r--r-- | data/rooms/intro/1005.yaml | 4 | ||||
| -rw-r--r-- | data/rooms/intro/1006.yaml | 26 | ||||
| -rw-r--r-- | data/rooms/intro/1007.yaml | 17 | ||||
| -rw-r--r-- | data/rooms/intro/1008.yaml | 2 | ||||
| -rw-r--r-- | data/rooms/intro/1009.yaml | 16 | ||||
| -rw-r--r-- | data/rooms/intro/1013.yaml | 21 | ||||
| -rw-r--r-- | data/rooms/intro/1014.yaml | 23 | ||||
| -rw-r--r-- | data/rooms/intro/1015.yaml | 16 | ||||
| -rw-r--r-- | data/rooms/intro/1016.yaml | 2 | ||||
| -rw-r--r-- | data/rooms/intro/1018.yaml | 21 | ||||
| -rw-r--r-- | data/rooms/intro/1019.yaml | 14 | ||||
| -rw-r--r-- | data/rooms/intro/1020.yaml | 4 | ||||
| -rw-r--r-- | data/rooms/intro/2002.yaml | 12 | ||||
| -rw-r--r-- | data/rooms/intro/2004.yaml | 16 | ||||
| -rw-r--r-- | internal/admin/api_rooms.go | 177 | ||||
| -rw-r--r-- | internal/admin/api_search.go | 12 | ||||
| -rw-r--r-- | internal/admin/static/admin.css | 10 | ||||
| -rw-r--r-- | internal/admin/static/map.js | 263 | ||||
| -rw-r--r-- | internal/admin/templates/layout.html | 2 | ||||
| -rw-r--r-- | internal/admin/templates/map.html | 10 | ||||
| -rw-r--r-- | internal/world/mob.go | 1 |
23 files changed, 435 insertions, 253 deletions
diff --git a/data/.admin_history.yaml b/data/.admin_history.yaml index dd085f6..97f11d9 100644 --- a/data/.admin_history.yaml +++ b/data/.admin_history.yaml @@ -1 +1 @@ -{"history":[{"time":"2026-06-29T21:28:26-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:28:27-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1006\n north:\n room: 1008\n northeast:\n room: 1005\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: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1006\n north:\n room: 1008\n northeast:\n room: 1005\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-06-29T21:28:27-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:28:27-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:28:27-04:00","description":"update room 2003","file_path":"data/rooms/intro/2003.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1006\n north:\n room: 1008\n northeast:\n room: 1005\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: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1006\n north:\n room: 1008\n northeast:\n room: 1005\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-06-29T21:39:47-04:00","description":"update room 2001","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 south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:47-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:49-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 south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\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: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:49-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:55-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: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:55-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:57-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 south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\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: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:39:57-04:00","description":"update room 2002","file_path":"data/rooms/intro/2002.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n northwest:\n room: 1\n southeast:\n room: 2004\n west:\n room: 2001\nhazard: \"\"\nid: 2002\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:43:52-04:00","description":"update room 1008 (add exit north to 7)","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1008\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:43:52-04:00","description":"create room 7","file_path":"data/rooms/intro/7.yaml","old_content":"","new_content":"exits:\n south: 1008\nid: 7\nname: 'Room #7'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T21:44:39-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"id: 1008\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: 00FFFF\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:45:30-04:00","description":"update room 1016","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southeast:\n room: 1018\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nhazard: \"\"\nid: 1016\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:45:56-04:00","description":"update room 1005","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northeast:\n room: 1016\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nhazard: \"\"\nid: 1005\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:46:03-04:00","description":"update room 1009 (add exit northwest to 8)","file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n southwest:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1009\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T21:46:03-04:00","description":"create room 8","file_path":"data/rooms/intro/8.yaml","old_content":"","new_content":"exits:\n southeast: 1009\nid: 8\nname: 'Room #8'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T22:04:39-04:00","description":"link 1005 north 8","file_path":"data/rooms/intro/1005.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nhazard: \"\"\nid: 1005\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 8\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:39-04:00","description":"link 8 south 1005 (reverse)","file_path":"data/rooms/intro/8.yaml","old_content":"exits:\n southeast: 1009\nid: 8\nname: 'Room #8'\n","new_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1005\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:39-04:00","description":"unlink 8 south 1005","file_path":"data/rooms/intro/8.yaml","old_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1005\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:39-04:00","description":"unlink 1005 north 8 (reverse)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 8\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:40-04:00","description":"link 1005 north 8","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 8\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:40-04:00","description":"link 8 south 1005 (reverse)","file_path":"data/rooms/intro/8.yaml","old_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1005\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:41-04:00","description":"unlink 8 south 1005","file_path":"data/rooms/intro/8.yaml","old_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1005\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:41-04:00","description":"unlink 1005 north 8 (reverse)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 8\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:42-04:00","description":"link 1005 north 8","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 8\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:42-04:00","description":"link 8 south 1005 (reverse)","file_path":"data/rooms/intro/8.yaml","old_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1005\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:42-04:00","description":"unlink 8 south 1005","file_path":"data/rooms/intro/8.yaml","old_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1005\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 8\nname: 'Room #8'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:42-04:00","description":"unlink 1005 north 8 (reverse)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 8\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:45-04:00","description":"link 1005 east 1009","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:45-04:00","description":"link 1009 west 1005 (reverse)","file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1009\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:48-04:00","description":"link 1016 southwest 1005","file_path":"data/rooms/intro/1016.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nhazard: \"\"\nid: 1016\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:48-04:00","description":"link 1005 northeast 1016 (reverse)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:49-04:00","description":"unlink 1005 northeast 1016","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:49-04:00","description":"unlink 1016 southwest 1005 (reverse)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:51-04:00","description":"link 1016 southwest 1005","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:53-04:00","description":"link 1016 southwest 1005","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:04:53-04:00","description":"link 1005 northeast 1016 (reverse)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:05:39-04:00","description":"update room 1016","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nhazard: \"\"\nid: 1016\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:20:52-04:00","description":"update room 1007 (add exit east to 9)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 9\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:20:52-04:00","description":"create room 9","file_path":"data/rooms/intro/9.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 9\nname: 'Room #9'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T22:20:54-04:00","description":"unlink 9 west 1007","file_path":"data/rooms/intro/9.yaml","old_content":"exits:\n west: 1007\nid: 9\nname: 'Room #9'\n","new_content":"id: 9\nname: 'Room #9'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:20:54-04:00","description":"unlink 1007 east 9 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 9\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:21:00-04:00","description":"update room 1007 (add exit east to 10)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 10\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:21:00-04:00","description":"create room 10","file_path":"data/rooms/intro/10.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 10\nname: 'Room #10'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T22:21:04-04:00","description":"unlink 1007 east 10","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 10\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:21:04-04:00","description":"unlink 10 west 1007 (reverse)","file_path":"data/rooms/intro/10.yaml","old_content":"exits:\n west: 1007\nid: 10\nname: 'Room #10'\n","new_content":"id: 10\nname: 'Room #10'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:21:41-04:00","description":"update room 1007 (add exit up to 11)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:21:41-04:00","description":"create room 11","file_path":"data/rooms/intro/11.yaml","old_content":"","new_content":"exits:\n down: 1007\nid: 11\nname: 'Room #11'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T22:21:45-04:00","description":"update room 1007 (add exit down to 12)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T22:21:45-04:00","description":"create room 12","file_path":"data/rooms/intro/12.yaml","old_content":"","new_content":"exits:\n up: 1007\nid: 12\nname: 'Room #12'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T22:29:07-04:00","description":"delete room 11","file_path":"data/rooms/intro/11.yaml","old_content":"exits:\n down: 1007\nid: 11\nname: 'Room #11'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-29T22:29:12-04:00","description":"delete room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 0\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-29T22:29:22-04:00","description":"unlink 1012 west 1011","file_path":"data/rooms/intro/1012.yaml","old_content":"id: 1012\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1013\n west:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1012\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:02-04:00","description":"update room 1016 (add exit east to 11)","file_path":"data/rooms/intro/1016.yaml","old_content":"block_transport: false\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nhazard: \"\"\nid: 1016\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 11\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:02-04:00","description":"create room 11","file_path":"data/rooms/intro/11.yaml","old_content":"","new_content":"color: \"97\"\nexits:\n west: 1016\nid: 11\nname: 'Room #11'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T23:18:05-04:00","description":"update room 1016 (add exit east to 13)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 11\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 13\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:10-04:00","description":"update room 1016 (add exit east to 13)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 13\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 13\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:10-04:00","description":"create room 13","file_path":"data/rooms/intro/13.yaml","old_content":"","new_content":"color: \"97\"\nexits:\n west: 1016\nid: 13\nname: 'Room #13'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T23:18:11-04:00","description":"update room 13 (add exit east to 14)","file_path":"data/rooms/intro/13.yaml","old_content":"color: \"97\"\nexits:\n west: 1016\nid: 13\nname: 'Room #13'\n","new_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:11-04:00","description":"create room 14","file_path":"data/rooms/intro/14.yaml","old_content":"","new_content":"color: \"97\"\nexits:\n west: 13\nid: 14\nname: 'Room #14'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T23:18:12-04:00","description":"update room 14 (add exit north to 15)","file_path":"data/rooms/intro/14.yaml","old_content":"color: \"97\"\nexits:\n west: 13\nid: 14\nname: 'Room #14'\n","new_content":"id: 14\nname: 'Room #14'\ncolor: \"97\"\ndescription: []\nexits:\n north:\n room: 15\n west:\n room: 13\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:12-04:00","description":"create room 15","file_path":"data/rooms/intro/15.yaml","old_content":"","new_content":"color: \"97\"\nexits:\n south: 14\nid: 15\nname: 'Room #15'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T23:18:12-04:00","description":"update room 15 (add exit west to 16)","file_path":"data/rooms/intro/15.yaml","old_content":"color: \"97\"\nexits:\n south: 14\nid: 15\nname: 'Room #15'\n","new_content":"id: 15\nname: 'Room #15'\ncolor: \"97\"\ndescription: []\nexits:\n south:\n room: 14\n west:\n room: 16\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:12-04:00","description":"create room 16","file_path":"data/rooms/intro/16.yaml","old_content":"","new_content":"color: \"97\"\nexits:\n east: 15\nid: 16\nname: 'Room #16'\n","is_delete":false,"is_create":true},{"time":"2026-06-29T23:18:14-04:00","description":"link 16 south 13","file_path":"data/rooms/intro/16.yaml","old_content":"color: \"97\"\nexits:\n east: 15\nid: 16\nname: 'Room #16'\n","new_content":"id: 16\nname: 'Room #16'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 15\n south:\n room: 13\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:14-04:00","description":"link 13 north 16 (reverse)","file_path":"data/rooms/intro/13.yaml","old_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\n north:\n room: 16\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:16-04:00","description":"unlink 16 south 13","file_path":"data/rooms/intro/16.yaml","old_content":"id: 16\nname: 'Room #16'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 15\n south:\n room: 13\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 16\nname: 'Room #16'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 15\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:18:16-04:00","description":"unlink 13 north 16 (reverse)","file_path":"data/rooms/intro/13.yaml","old_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\n north:\n room: 16\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:19:56-04:00","description":"unlink 14 north 15","file_path":"data/rooms/intro/14.yaml","old_content":"id: 14\nname: 'Room #14'\ncolor: \"97\"\ndescription: []\nexits:\n north:\n room: 15\n west:\n room: 13\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 14\nname: 'Room #14'\ncolor: \"97\"\ndescription: []\nexits:\n west:\n room: 13\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:19:56-04:00","description":"unlink 15 south 14 (reverse)","file_path":"data/rooms/intro/15.yaml","old_content":"id: 15\nname: 'Room #15'\ncolor: \"97\"\ndescription: []\nexits:\n south:\n room: 14\n west:\n room: 16\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 15\nname: 'Room #15'\ncolor: \"97\"\ndescription: []\nexits:\n west:\n room: 16\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:19:59-04:00","description":"unlink 1016 east 13","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 13\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:19:59-04:00","description":"unlink 13 west 1016 (reverse)","file_path":"data/rooms/intro/13.yaml","old_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 13\nname: 'Room #13'\ncolor: \"97\"\ndescription: []\nexits:\n east:\n room: 14\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:40:49-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: 00FFFF\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:41:04-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:41:11-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:41:14-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\n - id: silver_rock\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:41:16-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\n - id: silver_rock\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-29T23:41:17-04:00","description":"update room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects:\n - id: silver_rock\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"33\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1005\n north:\n room: 7\n south:\n room: 2003\n southeast:\n room: 1006\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:45:22-04:00","description":"link 9999917 north 999997","file_path":"data/rooms/example_unused/town/9999917.yaml","old_content":"name: \"Bonfire\"\ndescription: \"A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\"\nexits:\n east: 9999918\n west: 9999916\n north: 99999200\nmobs:\n - id: scrap_bot\n - id: scrap_bot\n","new_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n north:\n room: 999997\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:45:22-04:00","description":"link 999997 south 9999917 (reverse)","file_path":"data/rooms/example_unused/town/999997.yaml","old_content":"name: \"Deep Mine\"\ndescription: \"A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\"\nexits:\n south: 999996\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\n","new_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits:\n south:\n room: 9999917\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:45:32-04:00","description":"link 9999917 south 999997","file_path":"data/rooms/example_unused/town/9999917.yaml","old_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n north:\n room: 999997\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n north:\n room: 999997\n south:\n room: 999997\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:45:32-04:00","description":"link 999997 north 9999917 (reverse)","file_path":"data/rooms/example_unused/town/999997.yaml","old_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits:\n south:\n room: 9999917\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits:\n north:\n room: 9999917\n south:\n room: 9999917\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:45:37-04:00","description":"unlink 9999917 north 999997","file_path":"data/rooms/example_unused/town/9999917.yaml","old_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n north:\n room: 999997\n south:\n room: 999997\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n south:\n room: 999997\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:45:37-04:00","description":"unlink 999997 south 9999917 (reverse)","file_path":"data/rooms/example_unused/town/999997.yaml","old_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits:\n north:\n room: 9999917\n south:\n room: 9999917\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits:\n north:\n room: 9999917\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:48:48-04:00","description":"unlink 9999917 south 999997","file_path":"data/rooms/example_unused/town/9999917.yaml","old_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n south:\n room: 999997\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 9999917\nname: Bonfire\ncolor: \"\"\ndescription:\n - text: A ring of stones surrounds a bed of ash. A few unlit logs wait nearby. A narrow passage leads north toward what sounds like echoing footsteps and clanging metal.\nexits:\n east:\n room: 9999918\n west:\n room: 9999916\nobjects: []\nitem_spawns: []\nmobs:\n - id: scrap_bot\n - id: scrap_bot\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:48:48-04:00","description":"unlink 999997 north 9999917 (reverse)","file_path":"data/rooms/example_unused/town/999997.yaml","old_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits:\n north:\n room: 9999917\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 999997\nname: Deep Mine\ncolor: \"\"\ndescription:\n - text: A deeper mine shaft. Higher quality ores can be found here. This area is not yet accessible.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs:\n - id: goblin\n - id: goblin\n - id: bandit\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:52:49-04:00","description":"unlink 1013 north 1012","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1012\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:52:49-04:00","description":"unlink 1012 south 1013 (reverse)","file_path":"data/rooms/intro/1012.yaml","old_content":"id: 1012\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1012\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:52:52-04:00","description":"unlink 1013 west 1010","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:52:52-04:00","description":"unlink 1010 east 1013 (reverse)","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1006\n east:\n room: 1013\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1010\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1006\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:53:57-04:00","description":"link 1014 south 1013","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1014\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n south:\n room: 1013\n up:\n room: 1015\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:53:58-04:00","description":"link 1013 north 1014 (reverse)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:54:48-04:00","description":"unlink 1018 northwest 1016","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 0\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1018\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:54:48-04:00","description":"unlink 1016 southeast 1018 (reverse)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:54:56-04:00","description":"link 1013 south 1018","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1013\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1014\n south:\n room: 1018\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T01:54:56-04:00","description":"link 1018 north 1013 (reverse)","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1018\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false}],"redo":null}
\ No newline at end of file +{"history":[{"time":"2026-06-30T03:16:23-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"26\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:16:24-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:16:25-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:20:00-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:20:04-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:20:07-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:28:54-04:00","description":"rename room 1014 to 1015","file_path":"data/rooms/intro/1014.yaml","new_file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:29:30-04:00","description":"rename room 1007 to 10070","file_path":"data/rooms/intro/1007.yaml","new_file_path":"data/rooms/intro/10070.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:30:46-04:00","description":"update room 10070","file_path":"data/rooms/intro/10070.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nhazard: \"\"\nid: 10070\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:39:51-04:00","description":"update room 2002 (add exit north to 1007)","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 north:\n room: 1013\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 north:\n room: 1007\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-06-30T03:39:51-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n south: 2002\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:39:56-04:00","description":"delete room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n south: 2002\nid: 1007\nname: 'Room #1007'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:40:02-04:00","description":"delete room 10070","file_path":"data/rooms/intro/10070.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nhazard: \"\"\nid: 10070\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:40:04-04:00","description":"delete room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:41:10-04:00","description":"update room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:11-04:00","description":"update room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:12-04:00","description":"update room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:16-04:00","description":"update room 1016 (add exit east to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:25-04:00","description":"update room 1016 (add exit southeast to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:37-04:00","description":"update room 1016 (add exit southeast to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:44-04:00","description":"update room 1016 (add exit southeast to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:57-04:00","description":"update room 1006 (add exit east to 1007)","file_path":"data/rooms/intro/1006.yaml","old_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:01-04:00","description":"update room 2004 (add exit south to 1007)","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 northwest:\n room: 2002\n south:\n room: 1007\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-06-30T03:42:01-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n north: 2004\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:20-04:00","description":"unlink 1016 east 1007","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:20-04:00","description":"unlink 1007 west 1016 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n north: 2004\nid: 1007\nname: 'Room #1007'\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:23-04:00","description":"unlink 1016 southeast 1007","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:23-04:00","description":"unlink 1007 northwest 1016 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:28-04:00","description":"unlink 1006 east 1007","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:28-04:00","description":"unlink 1007 west 1006 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:33-04:00","description":"unlink 2002 north 1007","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 north:\n room: 1007\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 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-06-30T03:42:33-04:00","description":"unlink 1007 south 2002 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:38-04:00","description":"unlink 1005 southeast 1007","file_path":"data/rooms/intro/1005.yaml","old_content":"block_transport: false\ncolor: CC\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nhazard: \"\"\nid: 1005\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: CC\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:38-04:00","description":"unlink 1007 northwest 1005 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:44-04:00","description":"update room 1007 (add exit south to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:44-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:44-04:00","description":"update room 1013 (add exit east to 1014)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1014\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:44-04:00","description":"create room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"","new_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:45-04:00","description":"update room 1014 (add exit east to 1015)","file_path":"data/rooms/intro/1014.yaml","old_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:45-04:00","description":"create room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"","new_content":"exits:\n west: 1014\nid: 1015\nname: 'Room #1015'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:48-04:00","description":"delete room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"exits:\n west: 1014\nid: 1015\nname: 'Room #1015'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:42:49-04:00","description":"delete room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:42:51-04:00","description":"delete room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1014\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:42:53-04:00","description":"update room 1007 (add exit east to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:53-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:23-04:00","description":"delete room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:43:24-04:00","description":"update room 1007 (add exit south to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:24-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:35-04:00","description":"unlink 1007 south 1013","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:35-04:00","description":"unlink 1013 north 1007 (reverse)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:39-04:00","description":"unlink 1007 east 1013","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:39-04:00","description":"unlink 1013 west 1007 (reverse)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:42-04:00","description":"delete room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:43:43-04:00","description":"update room 1007 (add exit south to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:43-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:44-04:00","description":"update room 1013 (add exit east to 1014)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1014\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:44-04:00","description":"create room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"","new_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:45-04:00","description":"update room 1014 (add exit north to 1015)","file_path":"data/rooms/intro/1014.yaml","old_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:45-04:00","description":"create room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"","new_content":"exits:\n south: 1014\nid: 1015\nname: 'Room #1015'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:46-04:00","description":"update room 1015 (add exit east to 1018)","file_path":"data/rooms/intro/1015.yaml","old_content":"exits:\n south: 1014\nid: 1015\nname: 'Room #1015'\n","new_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1018\n south:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:46-04:00","description":"create room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"","new_content":"exits:\n west: 1015\nid: 1018\nname: 'Room #1018'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:46-04:00","description":"update room 1018 (add exit south to 1019)","file_path":"data/rooms/intro/1018.yaml","old_content":"exits:\n west: 1015\nid: 1018\nname: 'Room #1018'\n","new_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1019\n west:\n room: 1015\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:46-04:00","description":"create room 1019","file_path":"data/rooms/intro/1019.yaml","old_content":"","new_content":"exits:\n north: 1018\nid: 1019\nname: 'Room #1019'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:47-04:00","description":"link 1019 west 1014","file_path":"data/rooms/intro/1019.yaml","old_content":"exits:\n north: 1018\nid: 1019\nname: 'Room #1019'\n","new_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1018\n west:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:47-04:00","description":"link 1014 east 1019 (reverse)","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1019\n north:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:50-04:00","description":"delete room 1019","file_path":"data/rooms/intro/1019.yaml","old_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1018\n west:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:46:51-04:00","description":"delete room 1018 (cleaned 1 exits)","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1019\n west:\n room: 1015\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:46:53-04:00","description":"delete room 1015 (cleaned 1 exits)","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:46:56-04:00","description":"delete room 1014 (cleaned 1 exits)","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1019\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:47:00-04:00","description":"delete room 1013 (cleaned 1 exits)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:47:04-04:00","description":"delete room 1007 (cleaned 1 exits)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:47:05-04:00","description":"update room 2004 (add exit east to 1007)","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 east:\n room: 1007\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-06-30T03:47:05-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n west: 2004\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:06-04:00","description":"update room 1007 (add exit east to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n west: 2004\nid: 1007\nname: 'Room #1007'\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n west:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:06-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:07-04:00","description":"update room 1013 (add exit northeast to 1014)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:07-04:00","description":"create room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"","new_content":"exits:\n southwest: 1013\nid: 1014\nname: 'Room #1014'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:08-04:00","description":"update room 1014 (add exit northeast to 1015)","file_path":"data/rooms/intro/1014.yaml","old_content":"exits:\n southwest: 1013\nid: 1014\nname: 'Room #1014'\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:08-04:00","description":"create room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"","new_content":"exits:\n southwest: 1014\nid: 1015\nname: 'Room #1015'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:09-04:00","description":"update room 1015 (add exit northwest to 1018)","file_path":"data/rooms/intro/1015.yaml","old_content":"exits:\n southwest: 1014\nid: 1015\nname: 'Room #1015'\n","new_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:09-04:00","description":"create room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"","new_content":"exits:\n southeast: 1015\nid: 1018\nname: 'Room #1018'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:09-04:00","description":"link 1018 west 1016","file_path":"data/rooms/intro/1018.yaml","old_content":"exits:\n southeast: 1015\nid: 1018\nname: 'Room #1018'\n","new_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:09-04:00","description":"link 1016 east 1018 (reverse)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1018\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:17-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:21-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:25-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:26-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: D0\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:33-04:00","description":"update room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:34-04:00","description":"update room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:36-04:00","description":"update room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:40-04:00","description":"update room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: 'Room #1014'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:41-04:00","description":"update room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: 'Room #1014'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: D5\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: 'Room #1014'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:45-04:00","description":"update room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nhazard: \"\"\nid: 1013\nitem_spawns: []\nmobs: []\nname: 'Room #1013'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:46-04:00","description":"update room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nhazard: \"\"\nid: 1013\nitem_spawns: []\nmobs: []\nname: 'Room #1013'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"72\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nhazard: \"\"\nid: 1013\nitem_spawns: []\nmobs: []\nname: 'Room #1013'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:57-04:00","description":"update room 2004 (add exit south to 1019)","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 east:\n room: 1007\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 east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n south:\n room: 1019\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-06-30T03:47:57-04:00","description":"create room 1019","file_path":"data/rooms/intro/1019.yaml","old_content":"","new_content":"exits:\n north: 2004\nid: 1019\nname: 'Room #1019'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:58-04:00","description":"update room 1019 (add exit south to 1020)","file_path":"data/rooms/intro/1019.yaml","old_content":"exits:\n north: 2004\nid: 1019\nname: 'Room #1019'\n","new_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1020\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:58-04:00","description":"create room 1020","file_path":"data/rooms/intro/1020.yaml","old_content":"","new_content":"exits:\n north: 1019\nid: 1020\nname: 'Room #1020'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:48:00-04:00","description":"unlink 2004 south 1019","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 east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n south:\n room: 1019\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 east:\n room: 1007\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-06-30T03:48:00-04:00","description":"unlink 1019 north 2004 (reverse)","file_path":"data/rooms/intro/1019.yaml","old_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1020\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1020\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false}],"redo":null}
\ No newline at end of file diff --git a/data/rooms/intro/1001.yaml b/data/rooms/intro/1001.yaml index 66e1908..98eebab 100644 --- a/data/rooms/intro/1001.yaml +++ b/data/rooms/intro/1001.yaml @@ -2,17 +2,10 @@ id: 1001 name: Inside Transport Shuttle color: "" description: - - text: 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. - condition: - flag: "" - value: null - not: true - player_flag: 1001_touchdown - has_item: "" - min_credits: 0 - all_of: [] - any_of: [] - - text: 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. + - text: |- + 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. + + 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. exits: down: room: 1002 @@ -28,8 +21,6 @@ exits: blocked_message: The piston-powered staircase is firmly closed. east: room: 2001 - up: - room: 6 objects: - name: framed sign hidden: true diff --git a/data/rooms/intro/1005.yaml b/data/rooms/intro/1005.yaml index 21c6633..5d34027 100644 --- a/data/rooms/intro/1005.yaml +++ b/data/rooms/intro/1005.yaml @@ -1,6 +1,6 @@ id: 1005 name: New Room -color: "" +color: CC description: - text: A featureless room. exits: @@ -10,8 +10,6 @@ exits: room: 1016 south: room: 1006 - southeast: - room: 1007 southwest: room: 2003 west: diff --git a/data/rooms/intro/1006.yaml b/data/rooms/intro/1006.yaml index e4929a9..4f8b9ef 100644 --- a/data/rooms/intro/1006.yaml +++ b/data/rooms/intro/1006.yaml @@ -1,21 +1,19 @@ id: 1006 name: New Room -color: "" +color: E2 description: - - text: A featureless room. + - text: A featureless room. exits: - east: - room: 1007 - north: - room: 1005 - northeast: - room: 1009 - northwest: - room: 1008 - up: - room: 1010 - west: - room: 2003 + north: + room: 1005 + northeast: + room: 1009 + northwest: + room: 1008 + up: + room: 1010 + west: + room: 2003 objects: [] item_spawns: [] mobs: [] diff --git a/data/rooms/intro/1007.yaml b/data/rooms/intro/1007.yaml index 4af0a79..3f40bc1 100644 --- a/data/rooms/intro/1007.yaml +++ b/data/rooms/intro/1007.yaml @@ -1,19 +1,12 @@ id: 1007 -name: New Room +name: 'Room #1007' color: "" -description: - - text: A featureless room. +description: [] exits: - down: - room: 12 - northwest: - room: 1005 - south: - room: 1014 - up: - room: 11 + east: + room: 1013 west: - room: 1006 + room: 2004 objects: [] item_spawns: [] mobs: [] diff --git a/data/rooms/intro/1008.yaml b/data/rooms/intro/1008.yaml index c3fab06..fe5956a 100644 --- a/data/rooms/intro/1008.yaml +++ b/data/rooms/intro/1008.yaml @@ -1,5 +1,5 @@ block_transport: false -color: "33" +color: A9 description: - text: A featureless room. exits: diff --git a/data/rooms/intro/1009.yaml b/data/rooms/intro/1009.yaml index 7a0886d..087a680 100644 --- a/data/rooms/intro/1009.yaml +++ b/data/rooms/intro/1009.yaml @@ -1,6 +1,5 @@ -id: 1009 -name: New Room -color: "" +block_transport: false +color: "27" description: - text: A featureless room. exits: @@ -12,10 +11,13 @@ exits: room: 1006 west: room: 1005 -objects: [] +hazard: "" +id: 1009 item_spawns: [] -mobs: [] +mobs: + - id: man + - id: man +name: New Room +objects: [] on_enter: [] -hazard: "" -block_transport: false triggers: [] diff --git a/data/rooms/intro/1013.yaml b/data/rooms/intro/1013.yaml index 8d83946..35e3757 100644 --- a/data/rooms/intro/1013.yaml +++ b/data/rooms/intro/1013.yaml @@ -1,17 +1,16 @@ -id: 1013 -name: New Room -color: "" -description: - - text: A featureless room. +block_transport: false +color: "72" +description: [] exits: - north: + northeast: room: 1014 - south: - room: 1018 -objects: [] + west: + room: 1007 +hazard: "" +id: 1013 item_spawns: [] mobs: [] +name: 'Room #1013' +objects: [] on_enter: [] -hazard: "" -block_transport: false triggers: [] diff --git a/data/rooms/intro/1014.yaml b/data/rooms/intro/1014.yaml index ce76c4c..a11adfd 100644 --- a/data/rooms/intro/1014.yaml +++ b/data/rooms/intro/1014.yaml @@ -1,19 +1,16 @@ -id: 1014 -name: New Room -color: "" -description: - - text: A featureless room. +block_transport: false +color: D5 +description: [] exits: - north: - room: 1007 - south: - room: 1013 - up: + northeast: room: 1015 -objects: [] + southwest: + room: 1013 +hazard: "" +id: 1014 item_spawns: [] mobs: [] +name: 'Room #1014' +objects: [] on_enter: [] -hazard: "" -block_transport: false triggers: [] diff --git a/data/rooms/intro/1015.yaml b/data/rooms/intro/1015.yaml new file mode 100644 index 0000000..eaec278 --- /dev/null +++ b/data/rooms/intro/1015.yaml @@ -0,0 +1,16 @@ +block_transport: false +color: 0C +description: [] +exits: + northwest: + room: 1018 + southwest: + room: 1014 +hazard: "" +id: 1015 +item_spawns: [] +mobs: [] +name: 'Room #1015' +objects: [] +on_enter: [] +triggers: [] diff --git a/data/rooms/intro/1016.yaml b/data/rooms/intro/1016.yaml index 3834f84..58eb906 100644 --- a/data/rooms/intro/1016.yaml +++ b/data/rooms/intro/1016.yaml @@ -6,6 +6,8 @@ description: exits: down: room: 1017 + east: + room: 1018 south: room: 1009 southwest: diff --git a/data/rooms/intro/1018.yaml b/data/rooms/intro/1018.yaml index 38540b5..a696922 100644 --- a/data/rooms/intro/1018.yaml +++ b/data/rooms/intro/1018.yaml @@ -1,15 +1,16 @@ -id: 1018 -name: New Room -color: "" -description: - - text: A featureless room. +block_transport: false +color: D0 +description: [] exits: - north: - room: 1013 -objects: [] + southeast: + room: 1015 + west: + room: 1016 +hazard: "" +id: 1018 item_spawns: [] mobs: [] +name: 'Room #1018' +objects: [] on_enter: [] -hazard: "" -block_transport: false triggers: [] diff --git a/data/rooms/intro/1019.yaml b/data/rooms/intro/1019.yaml new file mode 100644 index 0000000..3ea9771 --- /dev/null +++ b/data/rooms/intro/1019.yaml @@ -0,0 +1,14 @@ +id: 1019 +name: 'Room #1019' +color: "" +description: [] +exits: + south: + room: 1020 +objects: [] +item_spawns: [] +mobs: [] +on_enter: [] +hazard: "" +block_transport: false +triggers: [] diff --git a/data/rooms/intro/1020.yaml b/data/rooms/intro/1020.yaml new file mode 100644 index 0000000..256ea8b --- /dev/null +++ b/data/rooms/intro/1020.yaml @@ -0,0 +1,4 @@ +exits: + north: 1019 +id: 1020 +name: 'Room #1020' diff --git a/data/rooms/intro/2002.yaml b/data/rooms/intro/2002.yaml index 744fbb2..2ac6ef1 100644 --- a/data/rooms/intro/2002.yaml +++ b/data/rooms/intro/2002.yaml @@ -1,21 +1,19 @@ -block_transport: false +id: 2002 +name: Test Room color: "" description: - text: It's a test room exits: east: room: 2003 - northwest: - room: 1 southeast: room: 2004 west: room: 2001 -hazard: "" -id: 2002 +objects: [] item_spawns: [] mobs: [] -name: Test Room -objects: [] on_enter: [] +hazard: "" +block_transport: false triggers: [] diff --git a/data/rooms/intro/2004.yaml b/data/rooms/intro/2004.yaml index 33b41f3..e90d370 100644 --- a/data/rooms/intro/2004.yaml +++ b/data/rooms/intro/2004.yaml @@ -2,14 +2,16 @@ id: 2004 name: Test Room color: "" description: - - text: It's a test room + - text: It's a test room exits: - north: - room: 2003 - northwest: - room: 2002 - west: - room: 2005 + east: + room: 1007 + north: + room: 2003 + northwest: + room: 2002 + west: + room: 2005 objects: [] item_spawns: [] mobs: [] diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go index 4075534..b60aefc 100644 --- a/internal/admin/api_rooms.go +++ b/internal/admin/api_rooms.go @@ -228,8 +228,36 @@ func (s *AdminServer) handleRoomByID(w http.ResponseWriter, r *http.Request) { s.world.RebuildRoomIndex(s.dataDir) s.world.ClearRoomState(id) + allIDs, _ := listRoomIDs(s.dataDir) + var exitCleaned int + for _, otherID := range allIDs { + if otherID == id { + continue + } + otherRoom, loadErr := s.world.LoadRoom(otherID) + if loadErr != nil { + continue + } + changed := false + for _, dir := range world.ExitOrder { + exit, exists := otherRoom.Exits[dir] + if !exists || exit.Room != id { + continue + } + delete(otherRoom.Exits, dir) + changed = true + } + if changed { + otherPath, pathOk := s.world.GetRoomPath(otherID) + if pathOk { + writeYAMLFile(otherPath, otherRoom) + exitCleaned++ + } + } + } + s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("delete room %d", id), + Description: fmt.Sprintf("delete room %d (cleaned %d exits)", id, exitCleaned), FilePath: path, OldContent: oldContent, IsDelete: true, @@ -477,25 +505,29 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { roomA, errA := s.world.LoadRoom(body.From) roomB, errB := s.world.LoadRoom(body.To) - if errA != nil || errB != nil { - writeJSON(w, map[string]any{"error": "one or both rooms not found"}) + + if errA != nil && errB != nil { + writeJSON(w, map[string]any{"error": "both rooms not found"}) return } - if roomA == nil || roomB == nil { - writeJSON(w, map[string]any{"error": "one or both rooms not found"}) - return + if (errA != nil && roomA == nil) { + roomA = nil + } + if (errB != nil && roomB == nil) { + roomB = nil } var dir, oppDir world.ExitDir - for _, d := range world.ExitOrder { - if exit, ok := roomA.Exits[d]; ok && exit.Room == body.To { - dir = d - break + if roomA != nil { + for _, d := range world.ExitOrder { + if exit, ok := roomA.Exits[d]; ok && exit.Room == body.To { + dir = d + oppDir = world.OppositeExit[d] + break + } } } - if dir != "" { - oppDir = world.OppositeExit[dir] - } else { + if dir == "" && roomB != nil { for _, d := range world.ExitOrder { if exit, ok := roomB.Exits[d]; ok && exit.Room == body.From { oppDir = d @@ -505,49 +537,58 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { } } - if dir == "" && oppDir == "" { - writeJSONError(w, "no exit found between these rooms", http.StatusNotFound) - return - } - - if roomA.Exits != nil { + if roomA != nil && roomA.Exits != nil { delete(roomA.Exits, dir) } - if roomB.Exits != nil { + if roomB != nil && roomB.Exits != nil { delete(roomB.Exits, oppDir) } - pathA, okA2 := s.world.GetRoomPath(body.From) - pathB, okB2 := s.world.GetRoomPath(body.To) - if !okA2 || !okB2 { - writeJSON(w, map[string]any{"error": "room path not found"}) - return - } + var pushEntries []ChangeDesc - oldA, _ := snapshotFile(pathA) - oldB, _ := snapshotFile(pathB) - newA, err := writeYAMLFile(pathA, roomA) - if err != nil { - writeJSON(w, map[string]any{"error": "write A: " + err.Error()}) - return + if roomA != nil { + pathA, okA2 := s.world.GetRoomPath(body.From) + if !okA2 { + writeJSON(w, map[string]any{"error": "room A path not found"}) + return + } + oldA, _ := snapshotFile(pathA) + newA, err := writeYAMLFile(pathA, roomA) + if err != nil { + writeJSON(w, map[string]any{"error": "write A: " + err.Error()}) + return + } + pushEntries = append(pushEntries, ChangeDesc{ + Description: fmt.Sprintf("unlink %d %s %d", body.From, dir, body.To), + FilePath: pathA, + OldContent: oldA, + NewContent: newA, + }) + } + + if roomB != nil { + pathB, okB2 := s.world.GetRoomPath(body.To) + if !okB2 { + writeJSON(w, map[string]any{"error": "room B path not found"}) + return + } + oldB, _ := snapshotFile(pathB) + newB, err := writeYAMLFile(pathB, roomB) + if err != nil { + writeJSON(w, map[string]any{"error": "write B: " + err.Error()}) + return + } + pushEntries = append(pushEntries, ChangeDesc{ + Description: fmt.Sprintf("unlink %d %s %d (reverse)", body.To, oppDir, body.From), + FilePath: pathB, + OldContent: oldB, + NewContent: newB, + }) } - newB, err := writeYAMLFile(pathB, roomB) - if err != nil { - writeJSON(w, map[string]any{"error": "write B: " + err.Error()}) - return + + for _, entry := range pushEntries { + s.undoStack.Push(entry) } - s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("unlink %d %s %d", body.From, dir, body.To), - FilePath: pathA, - OldContent: oldA, - NewContent: newA, - }) - s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("unlink %d %s %d (reverse)", body.To, oppDir, body.From), - FilePath: pathB, - OldContent: oldB, - NewContent: newB, - }) writeJSON(w, map[string]any{"ok": true}) default: @@ -631,12 +672,19 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) { writeJSON(w, map[string]any{"error": "room not found"}) return } + + if _, ok := s.world.GetRoomPath(body.NewID); ok { + writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d already exists", body.NewID)}) + return + } + dir := filepath.Dir(oldPath) newPath := filepath.Join(dir, strconv.Itoa(body.NewID)+".yaml") if _, err := os.Stat(newPath); err == nil { writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d already exists", body.NewID)}) return } + data, err := os.ReadFile(oldPath) if err != nil { writeJSON(w, map[string]any{"error": "read: " + err.Error()}) @@ -650,10 +698,41 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) { writeJSON(w, map[string]any{"error": "remove old: " + err.Error()}) return } + s.world.RebuildRoomIndex(s.dataDir) s.world.ClearRoomState(body.ID) + + allIDs, _ := listRoomIDs(s.dataDir) + var exitUpdates int + for _, otherID := range allIDs { + if otherID == body.NewID { + continue + } + otherRoom, loadErr := s.world.LoadRoom(otherID) + if loadErr != nil { + continue + } + changed := false + for _, dir := range world.ExitOrder { + exit, exists := otherRoom.Exits[dir] + if !exists || exit.Room != body.ID { + continue + } + exit.Room = body.NewID + otherRoom.Exits[dir] = exit + changed = true + } + if changed { + otherPath, pathOk := s.world.GetRoomPath(otherID) + if pathOk { + writeYAMLFile(otherPath, otherRoom) + exitUpdates++ + } + } + } + s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("rename room %d to %d", body.ID, body.NewID), + Description: fmt.Sprintf("rename room %d to %d (updated %d exits)", body.ID, body.NewID, exitUpdates), FilePath: oldPath, NewFilePath: newPath, OldContent: data, diff --git a/internal/admin/api_search.go b/internal/admin/api_search.go index d47dc0e..3367a52 100644 --- a/internal/admin/api_search.go +++ b/internal/admin/api_search.go @@ -28,6 +28,7 @@ func (s *AdminServer) handleSearch(w http.ResponseWriter, r *http.Request) { Items []searchResult `json:"items"` Mobs []searchResult `json:"mobs"` Objects []searchResult `json:"objects"` + Hazards []searchResult `json:"hazards"` } var resp searchResponse @@ -78,5 +79,16 @@ func (s *AdminServer) handleSearch(w http.ResponseWriter, r *http.Request) { } } + hazardIDs, _ := listYAMLFiles(s.dataDir, "hazards") + for _, id := range hazardIDs { + h, err := s.world.LoadHazard(id) + if err != nil { + continue + } + if strings.Contains(strings.ToLower(h.Name), q) || strings.Contains(strings.ToLower(id), q) { + resp.Hazards = append(resp.Hazards, searchResult{ID: id, Name: h.Name}) + } + } + writeJSON(w, resp) } diff --git a/internal/admin/static/admin.css b/internal/admin/static/admin.css index 684a9c6..6a83664 100644 --- a/internal/admin/static/admin.css +++ b/internal/admin/static/admin.css @@ -8,16 +8,18 @@ body{font-family:monospace;background:var(--bg);color:var(--text);min-height:100 .nav .undo-bar button{padding:3px 8px;font-size:12px;border:1px solid var(--border);border-radius:3px;background:var(--input-bg);color:var(--text);cursor:pointer} .nav .undo-bar button:disabled{opacity:.4;cursor:default} .nav .undo-bar button:not(:disabled):hover{background:var(--accent)} -.nav .undo-bar span{color:#888} +.nav .undo-bar span{color:#888;flex:1;text-align:right;margin-right:8px} .layout{display:flex;height:calc(100vh - 38px)} -.main{flex:1;overflow:auto;position:relative} -.panel{width:580px;background:var(--panel);border-left:1px solid var(--border);overflow-y:auto;padding:16px;flex-shrink:0;position:relative} +.main{flex:1;overflow:auto;position:relative;user-select:none;-webkit-user-select:none} +.panel{width:800px;background:var(--panel);border-left:1px solid var(--border);overflow-y:auto;padding:16px;flex-shrink:0;position:relative} .panel-resize-handle{position:absolute;left:-3px;top:0;bottom:0;width:6px;cursor:col-resize;z-index:5;background:transparent} .panel-resize-handle:hover{background:rgba(255,255,255,.06)} .panel h2{font-size:15px;margin-bottom:12px;padding-bottom:6px;border-bottom:1px solid var(--border)} .form-group{margin-bottom:10px} .form-group label{display:block;font-size:11px;color:#aaa;margin-bottom:3px;text-transform:uppercase;letter-spacing:.5px} .form-group input,.form-group textarea,.form-group select{width:100%;padding:6px 8px;font-size:13px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:3px;font-family:monospace} +.form-group input[type=number]{-moz-appearance:textfield} +.form-group input[type=number]::-webkit-inner-spin-button,.form-group input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0} .form-group textarea{resize:vertical;min-height:60px} .form-group input[type=checkbox]{width:auto;margin-right:6px} .btn{padding:6px 14px;border:none;border-radius:3px;cursor:pointer;font-size:12px;font-weight:bold;font-family:monospace} @@ -124,6 +126,8 @@ g.ud-hover:hover text{font-weight:bold} .exit-row select{min-width:70px} .exit-add{display:flex;gap:4px;align-items:center;margin-top:6px} .exit-add select,.exit-add input{width:auto;flex:1;padding:3px 5px;font-size:11px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:2px;font-family:monospace} +.exit-add input[type=number]{-moz-appearance:textfield} +.exit-add input[type=number]::-webkit-inner-spin-button,.exit-add input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0} .exit-add .exit-add-btn{flex-shrink:0;padding:3px 8px;font-size:11px;background:var(--accent);color:var(--text);border:1px solid #1a5a8e;border-radius:2px;cursor:pointer;font-family:monospace} .exit-add .exit-add-btn:hover{background:var(--hover)}.panel-tab-content .entry-row{display:flex;gap:4px;align-items:flex-start;margin-bottom:6px;padding:4px;background:rgba(255,255,255,.02);border-radius:3px;border:1px solid transparent} .panel-tab-content .entry-row:hover{border-color:var(--border)} diff --git a/internal/admin/static/map.js b/internal/admin/static/map.js index ca454a0..cd53bed 100644 --- a/internal/admin/static/map.js +++ b/internal/admin/static/map.js @@ -127,23 +127,22 @@ function renderMap(data) { var txtColor = hexLuminance(fill) > 0.35 ? '#111' : '#fff'; var sel = selectedRoom === r.id; roomHTML += '<rect class="rm" x="'+x+'" y="'+y+'" width="'+w+'" height="'+h+'" rx="5" fill="'+fill+'" stroke="'+(sel?'#fff':fill)+'" stroke-width="'+(sel?3:1.5)+'" data-id="'+r.id+'" data-name="'+esc(r.name)+'"/>'; + var dimColor = hexLuminance(fill) > 0.35 ? 'rgba(0,0,0,0.45)' : 'rgba(255,255,255,0.4)'; - roomHTML += '<text x="'+(x+w/2)+'" y="'+(y+h/2-10)+'" text-anchor="middle" font-size="8" fill="'+dimColor+'" font-family="monospace" pointer-events="none">#'+r.id+'</text>'; - roomHTML += wrapText(r.name, x+w/2, y+h/2, w, txtColor); + roomHTML += '<text x="'+(x+w/2)+'" y="'+(y+14)+'" text-anchor="middle" font-size="8" fill="'+dimColor+'" font-family="monospace" pointer-events="none">#'+r.id+'</text>'; + roomHTML += wrapText(r.name, x+w/2, y+h/2+2, w, txtColor); - var btnY = y+h-4; - var topY = y+4; if (hasUp[r.id] && upTarget[r.id]) { - roomHTML += '<g class="ud-hover"><rect class="nav-btn-bg" x="'+(x+3)+'" y="'+(topY+2)+'" width="14" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="nav-btn" x="'+(x+10)+'" y="'+(topY+14)+'" text-anchor="middle" fill="'+txtColor+'" data-action="goto" data-dz="1" data-target="'+upTarget[r.id]+'" title="Go up to #'+upTarget[r.id]+'">\u2191</text></g>'; + roomHTML += '<g class="ud-hover"><rect class="nav-btn-bg" x="'+(x+2)+'" y="'+(y+2)+'" width="14" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="nav-btn" x="'+(x+9)+'" y="'+(y+12)+'" text-anchor="middle" fill="'+txtColor+'" data-action="goto" data-dz="1" data-target="'+upTarget[r.id]+'" title="Go up to #'+upTarget[r.id]+'">\u2191</text></g>'; } if (hasDown[r.id] && downTarget[r.id]) { - roomHTML += '<g class="ud-hover"><rect class="nav-btn-bg" x="'+(x+w-17)+'" y="'+(topY+2)+'" width="14" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="nav-btn" x="'+(x+w-10)+'" y="'+(topY+14)+'" text-anchor="middle" fill="'+txtColor+'" data-action="goto" data-dz="-1" data-target="'+downTarget[r.id]+'" title="Go down to #'+downTarget[r.id]+'">\u2193</text></g>'; + roomHTML += '<g class="ud-hover"><rect class="nav-btn-bg" x="'+(x+w-16)+'" y="'+(y+2)+'" width="14" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="nav-btn" x="'+(x+w-9)+'" y="'+(y+12)+'" text-anchor="middle" fill="'+txtColor+'" data-action="goto" data-dz="-1" data-target="'+downTarget[r.id]+'" title="Go down to #'+downTarget[r.id]+'">\u2193</text></g>'; } if (sel) { - var btnX = x + 6, btnBW = 18; - roomHTML += '<g class="ud-hover"><rect class="new-btn-bg" x="'+(btnX-2)+'" y="'+(btnY-12)+'" width="'+btnBW+'" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="ud-btn" x="'+(btnX+btnBW/2-2)+'" y="'+btnY+'" text-anchor="middle" font-size="10" fill="'+txtColor+'" data-dir="up" title="Create room up">+\u2191</text></g>'; - roomHTML += '<g class="ud-hover"><rect class="new-btn-bg" x="'+(x+w-20)+'" y="'+(btnY-12)+'" width="'+btnBW+'" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="ud-btn" x="'+(x+w-11)+'" y="'+btnY+'" text-anchor="middle" font-size="10" fill="'+txtColor+'" data-dir="down" title="Create room down">+\u2193</text></g>'; + var btnBW = 18; + roomHTML += '<g class="ud-hover"><rect class="new-btn-bg" x="'+(x+2)+'" y="'+(y+h-16)+'" width="'+btnBW+'" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="ud-btn" x="'+(x+2+btnBW/2)+'" y="'+(y+h-5)+'" text-anchor="middle" font-size="10" fill="'+txtColor+'" data-dir="up" title="Create room up">+\u2191</text></g>'; + roomHTML += '<g class="ud-hover"><rect class="new-btn-bg" x="'+(x+w-btnBW-2)+'" y="'+(y+h-16)+'" width="'+btnBW+'" height="14" rx="3" fill="'+txtColor+'" opacity="0.12" pointer-events="none"/><text class="ud-btn" x="'+(x+w-btnBW/2-2)+'" y="'+(y+h-5)+'" text-anchor="middle" font-size="10" fill="'+txtColor+'" data-dir="down" title="Create room down">+\u2193</text></g>'; } }); } @@ -163,8 +162,10 @@ function renderMap(data) { var innerHTML = g + roomHTML + ghostHTML; var vb = [(-panX - W/2)/scale, (-panY - H/2)/scale, W/scale, H/scale]; - var svgHTML = '<svg width="'+W+'" height="'+H+'" viewBox="'+vb.join(' ')+'" xmlns="'+svgNS+'"><g>'+innerHTML+'</g></svg>'; - svg.innerHTML = svgHTML; + svg.setAttribute('viewBox', vb.join(' ')); + svg.setAttribute('width', W); + svg.setAttribute('height', H); + svg.innerHTML = '<g>' + innerHTML + '</g>'; svg.addEventListener('contextmenu', function(e) { e.preventDefault(); }); @@ -292,18 +293,6 @@ function renderMap(data) { updateView(); }; - svg.querySelectorAll('rect.rm').forEach(function(r) { - r.addEventListener('mousemove', function(ev) { - var tip = $('#tooltip'); - tip.style.display = 'block'; - tip.style.left = (ev.clientX+12)+'px'; - tip.style.top = (ev.clientY+12)+'px'; - tip.textContent = '#'+r.getAttribute('data-id')+' '+r.getAttribute('data-name'); - }); - r.addEventListener('mouseleave', function() { - $('#tooltip').style.display = 'none'; - }); - }); } function wrapText(name, cx, cy, maxWidth, color) { @@ -311,10 +300,26 @@ function wrapText(name, cx, cy, maxWidth, color) { color = color || '#fff'; var charW = 6; var maxLen = Math.max(4, Math.floor((maxWidth - 4) / charW)); + var words = name.split(/\s+/); var lines = []; - for (var i = 0; i < name.length; i += maxLen) { - lines.push(name.substring(i, i + maxLen)); - } + var cur = ''; + words.forEach(function(w) { + if (w.length > maxLen) { + if (cur) { lines.push(cur); cur = ''; } + for (var j = 0; j < w.length; j += maxLen) { + lines.push(w.substring(j, j + maxLen)); + } + } else if (!cur) { + cur = w; + } else if ((cur + ' ' + w).length <= maxLen) { + cur += ' ' + w; + } else { + lines.push(cur); + cur = w; + } + }); + if (cur) lines.push(cur); + if (lines.length === 0) lines.push(''); if (lines.length > 3) lines = lines.slice(0, 3); var dy = -(lines.length - 1) * 6; return lines.map(function(l, i) { @@ -323,7 +328,7 @@ function wrapText(name, cx, cy, maxWidth, color) { } function updateView() { - var svg = document.querySelector('#mapSvg svg'); + var svg = $('#mapSvg'); if (!svg) return; var W = svg.parentElement.clientWidth; var H = svg.parentElement.clientHeight; @@ -332,6 +337,7 @@ function updateView() { } function selectRoom(id) { + if (saveTimer) { clearTimeout(saveTimer); saveTimer = null; } selectedRoom = id; loadMap(); API.get('/api/rooms/' + id).then(function(data) { @@ -361,18 +367,22 @@ function renderSidePanel(data) { var html = '<div class="panel-tabs">'; html += '<button class="panel-tab' + (currentPanelTab === 0 ? ' active' : '') + '" onclick="switchPanelTab(0)">Room</button>'; - html += '<button class="panel-tab' + (currentPanelTab === 1 ? ' active' : '') + '" onclick="switchPanelTab(1)">Local</button>'; - html += '<button class="panel-tab' + (currentPanelTab === 2 ? ' active' : '') + '" onclick="switchPanelTab(2)">Objects</button>'; - html += '<button class="panel-tab' + (currentPanelTab === 3 ? ' active' : '') + '" onclick="switchPanelTab(3)">Mobs</button>'; - html += '<button class="panel-tab' + (currentPanelTab === 4 ? ' active' : '') + '" onclick="switchPanelTab(4)">Items</button>'; + html += '<button class="panel-tab' + (currentPanelTab === 1 ? ' active' : '') + '" onclick="switchPanelTab(1)">Exits</button>'; + html += '<button class="panel-tab' + (currentPanelTab === 2 ? ' active' : '') + '" onclick="switchPanelTab(2)">Local</button>'; + html += '<button class="panel-tab' + (currentPanelTab === 3 ? ' active' : '') + '" onclick="switchPanelTab(3)">Objects</button>'; + html += '<button class="panel-tab' + (currentPanelTab === 4 ? ' active' : '') + '" onclick="switchPanelTab(4)">Mobs</button>'; + html += '<button class="panel-tab' + (currentPanelTab === 5 ? ' active' : '') + '" onclick="switchPanelTab(5)">Items</button>'; + html += '<button class="panel-tab' + (currentPanelTab === 6 ? ' active' : '') + '" onclick="switchPanelTab(6)">Hazard</button>'; html += '</div>'; html += '<div class="panel-tab-content">'; if (currentPanelTab === 0) html += renderRoomTab(r, file); - else if (currentPanelTab === 1) html += renderLocalTab(localObjs); - else if (currentPanelTab === 2) html += renderObjectsTab(refObjs); - else if (currentPanelTab === 3) html += renderMobsTab(mobs); - else if (currentPanelTab === 4) html += renderItemsTab(spawns); + else if (currentPanelTab === 1) html += renderExitsTab(r); + else if (currentPanelTab === 2) html += renderLocalTab(localObjs); + else if (currentPanelTab === 3) html += renderObjectsTab(refObjs); + else if (currentPanelTab === 4) html += renderMobsTab(mobs); + else if (currentPanelTab === 5) html += renderItemsTab(spawns); + else if (currentPanelTab === 6) html += renderHazardTab(r); html += '</div>'; panel.innerHTML = html; @@ -401,23 +411,61 @@ function renderSidePanel(data) { function renderRoomTab(r, file) { var html = '<div class="form-group"><label>File</label><span style="font-size:11px;color:#888">' + esc(file) + '</span></div>'; - html += '<div class="form-group"><label>ID</label><input id="roomID" type="number" value="' + r.id + '" onchange="autoSave()"></div>'; - html += '<div class="form-group"><label>Name</label><input id="roomName" value="' + escAttr(r.name || '') + '" oninput="autoSave()"></div>'; - html += '<div class="form-group color-field"><label>Color</label><span class="color-swatch" style="background:'+resolveColor(r.color)+'"></span><input id="roomColor" value="' + escAttr(r.color || '') + '" oninput="autoSave()"></div>'; - html += '<div class="form-group"><label>Directory</label><select id="roomDir" onchange="autoSave()"></select></div>'; + html += '<div class="form-group"><label>ID</label><input id="roomID" type="number" value="' + r.id + '" onchange="autoSave()" onblur="saveNow()"></div>'; + html += '<div class="form-group"><label>Name</label><input id="roomName" value="' + escAttr(r.name || '') + '" oninput="autoSave()" onblur="saveNow()"></div>'; + html += '<div class="form-group color-field"><label>Color</label><span class="color-swatch" style="background:'+resolveColor(r.color)+'"></span><input id="roomColor" value="' + escAttr(r.color || '') + '" oninput="autoSave()" onblur="saveNow()"></div>'; var descText = ''; if (Array.isArray(r.description)) { descText = r.description.map(function(d) { return d.text || ''; }).join('\n\n'); } else if (typeof r.description === 'string') { descText = r.description; } - html += '<div class="form-group"><label>Description</label><textarea id="roomDesc" rows="4" oninput="autoSave()">' + esc(descText) + '</textarea></div>'; - html += '<div class="form-group"><label>Hazard</label><input id="roomHazard" value="' + escAttr(r.hazard || '') + '" oninput="autoSave()"></div>'; - html += '<div class="form-group"><label><input type="checkbox" id="roomBlockTransport" onchange="autoSave()"' + (r.block_transport ? ' checked' : '') + '> Block Transport</label></div>'; - html += renderExitsSection(r); + html += '<div class="form-group"><label>Description</label><textarea id="roomDesc" rows="12" oninput="autoSave()" onblur="saveNow()">' + esc(descText) + '</textarea></div>'; + html += '<div class="form-group"><label><input type="checkbox" id="roomBlockTransport" onchange="updateRoomBlockTransport()"' + (r.block_transport ? ' checked' : '') + '> Block Transport</label></div>'; + html += '<div class="form-group"><label>Directory</label><select id="roomDir" onchange="autoSave()" onblur="saveNow()"></select></div>'; + return html; +} + +function renderExitsTab(r) { + return renderExitsSection(r); +} + +function renderHazardTab(r) { + var html = '<div class="section-search">'; + html += '<input type="text" class="search-input" placeholder="Search hazards..." oninput="searchHazards(this)">'; + html += '<div class="search-results" style="display:none"></div>'; + html += '</div>'; + var current = r.hazard || ''; + if (current) { + html += '<div class="entry-row"><div class="entry-fields"><span class="entry-id">' + esc(current) + '</span></div><button class="btn btn-sm btn-danger" onclick="clearHazard()">X</button></div>'; + } return html; } +function searchHazards(input) { + searchAndShow(input, 'hazards', function(r) { + addHazard(r.id); + }); +} +function addHazard(id) { + if (!currentRoomData || !currentRoomData.room) return; + currentRoomData.room.hazard = id; + saveNow(); + reRenderPanel(); +} +function clearHazard() { + if (!currentRoomData || !currentRoomData.room) return; + currentRoomData.room.hazard = ''; + saveNow(); + reRenderPanel(); +} + +function updateRoomBlockTransport() { + if (!currentRoomData || !currentRoomData.room) return; + currentRoomData.room.block_transport = $('#roomBlockTransport').checked; + saveNow(); +} + function getRoomDirFromFile(file) { var rel = (file || '').replace(/^data\/rooms\/?/, ''); var idx = rel.indexOf('/'); @@ -441,10 +489,12 @@ function switchPanelTab(idx) { var mobs = Array.isArray(r.mobs) ? r.mobs : []; var html = ''; if (idx === 0) html = renderRoomTab(r, file); - else if (idx === 1) html = renderLocalTab(localObjs); - else if (idx === 2) html = renderObjectsTab(refObjs); - else if (idx === 3) html = renderMobsTab(mobs); - else if (idx === 4) html = renderItemsTab(spawns); + else if (idx === 1) html = renderExitsTab(r); + else if (idx === 2) html = renderLocalTab(localObjs); + else if (idx === 3) html = renderObjectsTab(refObjs); + else if (idx === 4) html = renderMobsTab(mobs); + else if (idx === 5) html = renderItemsTab(spawns); + else if (idx === 6) html = renderHazardTab(r); var content = document.querySelector('.panel-tab-content'); if (content) content.innerHTML = html; var tabs = document.querySelectorAll('.panel-tab'); @@ -482,7 +532,7 @@ function renderLocalTab(localObjs) { h += '<div class="entry-row" data-idx="' + i + '">'; h += '<div class="entry-fields">'; h += '<input class="local-name" value="' + escAttr(obj.name || '') + '" placeholder="name" onchange="updateLocalObject(' + i + ')" style="font-weight:bold">'; - h += '<textarea class="local-desc" rows="2" placeholder="description (one per line)" onchange="updateLocalObject(' + i + ')">' + esc(descText) + '</textarea>'; + h += '<textarea class="local-desc" rows="4" placeholder="description (one per line)" onchange="updateLocalObject(' + i + ')">' + esc(descText) + '</textarea>'; h += '<input class="local-aliases" value="' + escAttr((obj.aliases || []).join(', ')) + '" placeholder="aliases (comma separated)" onchange="updateLocalObject(' + i + ')">'; h += '</div>'; h += '<button class="btn btn-sm btn-danger" onclick="removeLocalObject(' + i + ')">X</button>'; @@ -557,8 +607,9 @@ function renderExitsSection(r) { var bmsg = (typeof exit === 'object' && exit.blocked_message) ? exit.blocked_message : ''; var setFlags = (typeof exit === 'object' && exit.set_flags) ? exit.set_flags : null; var setPlayerFlags = (typeof exit === 'object' && exit.set_player_flags) ? exit.set_player_flags : null; + var isConditional = !!(cond || bmsg || setFlags || setPlayerFlags); h += '<div class="exit-row" data-dir="' + d + '">'; - h += '<span class="exit-dir">' + d + '</span>'; + h += '<span class="exit-dir"' + (isConditional ? ' style="color:#f55"' : '') + '>' + d + '</span>'; h += '<span class="exit-target" onclick="selectRoom(' + target + ')"># ' + target + '</span>'; if (bmsg) h += '<span class="exit-meta">Blocked: ' + esc(bmsg) + '</span>'; if (cond) h += '<span class="exit-meta">Conditional</span>'; @@ -601,12 +652,12 @@ function editExitCondition(dir) { overlay.className = 'cm-overlay exit-overlay'; var menu = document.createElement('div'); menu.className = 'cm-menu exit-modal'; - menu.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-width:420px;max-height:85vh;overflow-y:auto;padding:14px;z-index:201'; + menu.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-width:420px;max-width:90vw;max-height:85vh;overflow-y:auto;overflow-x:hidden;padding:14px;z-index:201'; var h = '<h3 style="margin-bottom:8px;font-size:13px">Exit: ' + esc(dir) + ' → #' + exit.room + '</h3>'; - h += '<div class="form-group"><label>Blocked Message</label><textarea id="exitBmsg" rows="2">' + esc(bmsg) + '</textarea></div>'; h += '<div class="form-group"><label>Set Flags (key=value, comma separated)</label><input id="exitFlags" value="' + escAttr(flagsStr) + '"></div>'; h += '<div class="form-group"><label>Set Player Flags (key=value, comma separated)</label><input id="exitPFlags" value="' + escAttr(pflagsStr) + '"></div>'; + h += '<div class="form-group"><label>Blocked Message</label><textarea id="exitBmsg" rows="2">' + esc(bmsg) + '</textarea></div>'; h += '<div style="margin-top:10px;border-top:1px solid var(--border);padding-top:8px">'; h += '<label style="font-size:11px;color:#aaa;text-transform:uppercase;letter-spacing:.5px">Conditions</label>'; @@ -857,7 +908,7 @@ function getRoomObjects() { function setRoomObjects(objs) { if (!currentRoomData || !currentRoomData.room) return; currentRoomData.room.objects = objs; - autoSave(); + saveNow(); } function getRoomSpawns() { @@ -870,7 +921,7 @@ function getRoomSpawns() { function setRoomSpawns(spawns) { if (!currentRoomData || !currentRoomData.room) return; currentRoomData.room.item_spawns = spawns; - autoSave(); + saveNow(); } function getRoomMobs() { @@ -883,7 +934,7 @@ function getRoomMobs() { function setRoomMobs(mobs) { if (!currentRoomData || !currentRoomData.room) return; currentRoomData.room.mobs = mobs; - autoSave(); + saveNow(); } function addLocalObject() { @@ -1012,6 +1063,7 @@ function searchAndShow(input, type, onSelect) { if (type === 'objects' && data.objects) items = data.objects; if (type === 'items' && data.items) items = data.items; if (type === 'mobs' && data.mobs) items = data.mobs; + if (type === 'hazards' && data.hazards) items = data.hazards; if (items.length === 0) { results.style.display = 'block'; results.innerHTML = '<div class="sr-item" style="color:#888">No results</div>'; @@ -1054,12 +1106,20 @@ function autoSave() { saveTimer = setTimeout(function() { doSavePanel(); }, 600); } +function saveNow() { + if (saveTimer) clearTimeout(saveTimer); + saveTimer = null; + doSavePanel(); +} + function doSavePanel() { var id = selectedRoom; if (!id) return; var save = function(r) { API.put('/api/rooms/' + id, r).then(function() { + notify('Room #' + id + ' saved', 'success'); updateUndoBar(); + loadMap(); }).catch(function(e) { notify('Save failed: '+e.message, 'error'); }); }; @@ -1069,7 +1129,6 @@ function doSavePanel() { var el = $('#roomName'); if (el) r.name = el.value; el = $('#roomColor'); if (el) r.color = el.value; el = $('#roomDesc'); if (el && el.value) r.description = [{text: el.value}]; - el = $('#roomHazard'); if (el) r.hazard = el.value; el = $('#roomBlockTransport'); if (el) r.block_transport = el.checked; if (currentRoomData && currentRoomData.room) { @@ -1077,13 +1136,16 @@ function doSavePanel() { r.item_spawns = currentRoomData.room.item_spawns; r.mobs = currentRoomData.room.mobs; r.exits = currentRoomData.room.exits; + r.hazard = currentRoomData.room.hazard || ''; + if (r.block_transport === undefined) r.block_transport = currentRoomData.room.block_transport; } - var newID = parseInt($('#roomID').value) || id; - var newDir = $('#roomDir').value; + var el = $('#roomID'); var newID = el ? parseInt(el.value) || id : id; + var dirEl = $('#roomDir'); + var newDir = dirEl ? dirEl.value : null; var currentDir = (data.file || '').replace(/^data\/rooms\/?/, '').split('/')[0] || ''; - if (newDir !== currentDir && newDir !== undefined) { + if (dirEl && newDir !== currentDir) { API.post('/api/rooms/move', {id: id, dir: newDir}).then(function() { if (newID !== id) { API.post('/api/rooms/rename', {id: id, new_id: newID}).then(function() { @@ -1094,9 +1156,13 @@ function doSavePanel() { } else if (newID !== id) { API.post('/api/rooms/rename', {id: id, new_id: newID}).then(function() { selectRoom(newID); - }).catch(function(e) { notify('Rename failed: '+e.message, 'error'); save(r); }); - } else { save(r); } - }); + }).catch(function(e) { + notify('Rename failed: '+e.message, 'error'); + var rid = $('#roomID'); if (rid) rid.value = id; + save(r); + }); + } else { save(r); } + }).catch(function(e) { notify('Save failed: '+e.message, 'error'); }); } function deleteRoom(id) { @@ -1190,7 +1256,7 @@ function showRoomContextMenu(x, y, id) { } function mouseToGrid(e) { - var svgEl = document.querySelector('#mapSvg svg'); + var svgEl = $('#mapSvg'); if (!svgEl) return null; var rect = svgEl.getBoundingClientRect(); var mx = e.clientX - rect.left; @@ -1257,7 +1323,7 @@ function applyGhostLinkHighlight(fromRoom, gx, gy) { fromEl.setAttribute('stroke', '#0ff'); fromEl.setAttribute('stroke-width', '3'); - var g = document.querySelector('#mapSvg svg g'); + var g = document.querySelector('#mapSvg g'); if (!g) return; var svgNS = 'http://www.w3.org/2000/svg'; var line = document.createElementNS(svgNS, 'line'); @@ -1287,7 +1353,7 @@ function applyLinkHighlight(fromId, toId) { toEl.setAttribute('stroke', '#f0f'); toEl.setAttribute('stroke-width', '3'); - var g = document.querySelector('#mapSvg svg g'); + var g = document.querySelector('#mapSvg g'); if (!g) return; var svgNS = 'http://www.w3.org/2000/svg'; var line = document.createElementNS(svgNS, 'line'); @@ -1375,7 +1441,7 @@ function applyDelHighlight(fromId, toId) { toEl.setAttribute('stroke', '#f55'); toEl.setAttribute('stroke-width', '3'); - var g = document.querySelector('#mapSvg svg g'); + var g = document.querySelector('#mapSvg g'); if (!g) return; var svgNS = 'http://www.w3.org/2000/svg'; var line = document.createElementNS(svgNS, 'line'); @@ -1412,24 +1478,6 @@ function clearDelHighlight() { } function deleteLink(fromId, toId) { - var orphanedRooms = []; - if (mapData && mapData.links) { - var checkOrphan = function(roomId, otherId) { - var otherLinks = mapData.links.filter(function(l) { - return (l.from === roomId || l.to === roomId) && !((l.from === roomId && l.to === otherId) || (l.from === otherId && l.to === roomId)); - }); - if (otherLinks.length === 0) { - orphanedRooms.push(roomId); - } - }; - checkOrphan(toId, fromId); - checkOrphan(fromId, toId); - if (orphanedRooms.length > 0) { - var names = orphanedRooms.map(function(id) { return '#'+id; }).join(', '); - if (!confirm('Deleting this link will also delete room(s) ' + names + ' because they have no other connections. Continue?')) return; - } - } - fetch('/api/rooms/link', { method: 'DELETE', headers: {'Content-Type': 'application/json'}, @@ -1439,20 +1487,8 @@ function deleteLink(fromId, toId) { if (!r.ok) throw new Error('unlink failed'); return r.json(); }).then(function() { - return Promise.all(orphanedRooms.map(function(id) { - return API.del('/api/rooms/' + id); - })); - }).then(function() { - var msg = 'Removed link #'+fromId+' '+toId; - if (orphanedRooms.length > 0) { - msg += ' and deleted room(s) ' + orphanedRooms.map(function(id) { return '#'+id; }).join(', '); - } - notify(msg, 'success'); + notify('Removed link #'+fromId+' '+toId, 'success'); updateUndoBar(); - if (orphanedRooms.indexOf(selectedRoom) !== -1) { - selectedRoom = null; - $('#panelContent').innerHTML = '<p style="color:#888;text-align:center;margin-top:40px">Room deleted</p>'; - } loadMap(); }).catch(function(e) { notify('Delete link failed: ' + e.message, 'error'); @@ -1471,13 +1507,44 @@ function renderDisconnectedList(data) { panel.style.display = 'flex'; dc.sort(function(a, b) { return a.id - b.id; }); list.innerHTML = dc.map(function(r) { - return '<div class="dc-item" onclick="selectRoom(' + r.id + ')" title="' + esc(r.name || '') + '">' + + return '<div class="dc-item" onclick="selectRoom(' + r.id + ')" oncontextmenu="event.preventDefault(); showDcContextMenu(event,' + r.id + ')" title="' + esc(r.name || '') + '">' + '<span class="dc-id">#' + r.id + '</span>' + '<span class="dc-name">' + esc(r.name || '') + '</span>' + '</div>'; }).join(''); } +function showDcContextMenu(e, id) { + var overlay = document.createElement('div'); + overlay.className = 'cm-overlay'; + overlay.onclick = function() { overlay.remove(); menu.remove(); }; + + var menu = document.createElement('div'); + menu.className = 'cm-menu'; + menu.style.left = e.clientX + 'px'; + menu.style.top = e.clientY + 'px'; + + var delBtn = document.createElement('button'); + delBtn.textContent = 'Delete Room'; + delBtn.className = 'danger'; + delBtn.onclick = function() { + overlay.remove(); menu.remove(); + deleteRoom(id); + }; + menu.appendChild(delBtn); + + var selBtn = document.createElement('button'); + selBtn.textContent = 'Room Details'; + selBtn.onclick = function() { + overlay.remove(); menu.remove(); + selectRoom(id); + }; + menu.appendChild(selBtn); + + document.body.appendChild(overlay); + document.body.appendChild(menu); +} + function initPanelResize() { var handle = document.createElement('div'); handle.className = 'panel-resize-handle'; @@ -1499,12 +1566,14 @@ function initPanelResize() { if (newW < 300) newW = 300; if (newW > 800) newW = 800; panel.style.width = newW + 'px'; + updateView(); } function onUp() { document.body.style.userSelect = ''; document.body.style.cursor = ''; document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); + updateView(); } } diff --git a/internal/admin/templates/layout.html b/internal/admin/templates/layout.html index 99c1f0d..ed939bd 100644 --- a/internal/admin/templates/layout.html +++ b/internal/admin/templates/layout.html @@ -23,9 +23,9 @@ <a href="/editor/dashboard" class="{{if eq .Page "dashboard"}}active{{end}}">Dashboard</a> <a href="/editor/files" class="{{if eq .Page "files"}}active{{end}}">Files</a> <div class="undo-bar"> + <span class="undo-label"></span> <button class="undo-btn" onclick="doUndo()" title="">⟲ Undo</button> <button class="redo-btn" onclick="doRedo()" title="">⟳ Redo</button> - <span class="undo-label"></span> </div> <span style="font-size:11px;color:#888">| {{.Account}}</span> <a href="/logout" style="font-size:11px">Logout</a> diff --git a/internal/admin/templates/map.html b/internal/admin/templates/map.html index 869ee67..6fd6261 100644 --- a/internal/admin/templates/map.html +++ b/internal/admin/templates/map.html @@ -11,10 +11,12 @@ <button onclick="changeZ(-1)">-</button> <span class="z-label" id="zLabel">Z=0</span> <button onclick="changeZ(1)">+</button> - <button onclick="changeZ(0)" style="width:auto;font-size:11px">Reset</button> - <select id="dirSelect" onchange="changeDir(this.value)" style="margin-left:8px;padding:3px 6px;font-size:11px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:3px;font-family:monospace"></select> - <button onclick="zoomIn()" title="Zoom in" style="margin-left:8px;width:auto;font-size:14px">➕</button> - <button onclick="zoomOut()" title="Zoom out" style="width:auto;font-size:14px">➖</button> + <button onclick="changeZ(0)" style="width:auto;font-size:11px;padding:0 10px;min-width:44px">Reset</button> + <span style="font-size:11px;color:#aaa;margin-left:8px">Area:</span> + <select id="dirSelect" onchange="changeDir(this.value)" style="padding:3px 6px;font-size:11px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:3px;font-family:monospace"></select> + <span style="font-size:11px;color:#aaa;margin-left:8px">Zoom:</span> + <button onclick="zoomIn()" title="Zoom in" style="width:auto;font-size:14px;padding:0 6px;min-width:32px">➕</button> + <button onclick="zoomOut()" title="Zoom out" style="width:auto;font-size:14px;padding:0 6px;min-width:32px">➖</button> </div> <svg id="mapSvg" style="width:100%;height:100%"></svg> <div class="room-tooltip" id="tooltip" style="display:none"></div> diff --git a/internal/world/mob.go b/internal/world/mob.go index e02da53..cc2d2b2 100644 --- a/internal/world/mob.go +++ b/internal/world/mob.go @@ -274,6 +274,7 @@ func (s *MobStore) LoadDef(id string) (*MobDef, error) { if err := yaml.Unmarshal(data, &def); err != nil { return nil, fmt.Errorf("parse mob %s: %w", id, err) } + def.ID = id s.mu.Lock() s.defs[id] = &def |
