ModernUO/Distribution/Data/Spawns/shared/felucca/Ice.json
Kamron Batman 2f8a7afa57 chore(spawners): migrate spawn data to $type discriminator
- Rename "type" -> "$type" (first key, required for STJ polymorphism) in
  all 109 spawn JSON files (5,612 records).
- Convert "homeRange" + "location" -> "spawnBounds" object, dropping homeRange.
  Runtime keeps reading homeRange so un-migrated/external files still load.
- Add BoundsEquivalenceTests (hr=0/1/3/7) validating that the script's toBounds
  formula produces the same Rectangle3D as the runtime homeRange path.
- Add MigratedDataLoadTests loading a real migrated file as List<SpawnerDto>
  and round-tripping each DTO through ToSpawner().
- Add tools/spawner-json-migrate/migrate.mjs (offline Node script).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:17:35 -07:00

1196 lines
21 KiB
JSON

[
{
"$type": "Spawner",
"guid": "03498749-3218-4779-8864-b854b36c79f7",
"name": "Spawner (210)",
"location": [
5839,
159,
0
],
"map": "Felucca",
"count": 5,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5824,
"y1": 144,
"z1": -128,
"x2": 5855,
"y2": 175,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "FrostOoze",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostSpider",
"maxCount": 1,
"probability": 100
},
{
"name": "IceElemental",
"maxCount": 1,
"probability": 100
},
{
"name": "SnowElemental",
"maxCount": 1,
"probability": 100
},
{
"name": "IceSnake",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostTroll",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "0614ccac-5ffc-4223-8348-cbb5a0f0cc2d",
"name": "Spawner (210)",
"location": [
5785,
161,
-6
],
"map": "Felucca",
"count": 5,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5767,
"y1": 143,
"z1": -128,
"x2": 5804,
"y2": 180,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "FrostOoze",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostSpider",
"maxCount": 1,
"probability": 100
},
{
"name": "IceElemental",
"maxCount": 1,
"probability": 100
},
{
"name": "SnowElemental",
"maxCount": 1,
"probability": 100
},
{
"name": "IceSnake",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostTroll",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "1cf83838-f5d3-42f9-8390-f445a01ac889",
"name": "Spawner (210)",
"location": [
5754,
211,
-6
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5753,
"y1": 210,
"z1": -128,
"x2": 5756,
"y2": 213,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "33003603-a1fc-43a4-b9d7-2408eb2e5e50",
"name": "Spawner (210)",
"location": [
5848,
226,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5847,
"y1": 225,
"z1": -128,
"x2": 5850,
"y2": 228,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel2",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "3bf7b937-9eb6-45fc-81e6-d907910ca62a",
"name": "Spawner (210)",
"location": [
5758,
139,
5
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5757,
"y1": 138,
"z1": -128,
"x2": 5760,
"y2": 141,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "3d3f7414-5249-4ee4-9602-c842af0da38c",
"name": "Spawner (210)",
"location": [
5799,
188,
-6
],
"map": "Felucca",
"count": 6,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5789,
"y1": 178,
"z1": -128,
"x2": 5810,
"y2": 199,
"z2": 128
},
"walkingRange": 25,
"entries": [
{
"name": "IceSerpent",
"maxCount": 2,
"probability": 100
},
{
"name": "SnowElemental",
"maxCount": 1,
"probability": 100
},
{
"name": "Ratman",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostTroll",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostSpider",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "479095c0-02ab-4651-9edc-362d77a65a65",
"name": "Spawner (210)",
"location": [
5763,
187,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5762,
"y1": 186,
"z1": -128,
"x2": 5765,
"y2": 189,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "4ab984eb-913e-4b21-a9b2-5242726ae03f",
"name": "Spawner (210)",
"location": [
5731,
176,
-5
],
"map": "Felucca",
"count": 18,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5706,
"y1": 151,
"z1": -128,
"x2": 5757,
"y2": 202,
"z2": 128
},
"walkingRange": 35,
"entries": [
{
"name": "IceSerpent",
"maxCount": 9,
"probability": 100
},
{
"name": "SnowElemental",
"maxCount": 9,
"probability": 100
},
{
"name": "IceElemental",
"maxCount": 9,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "4b8dd28c-f72f-45c5-afc4-84dc637c1e0a",
"name": "Spawner (210)",
"location": [
5684,
181,
-5
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5683,
"y1": 180,
"z1": -128,
"x2": 5686,
"y2": 183,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "51445c30-3ef8-4c0e-95bc-b12e643e39ba",
"name": "Spawner (210)",
"location": [
5669,
330,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5659,
"y1": 320,
"z1": -128,
"x2": 5680,
"y2": 341,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "IceFiend",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "57c38552-9c17-4451-9e53-3a8d2048d2f6",
"name": "Spawner (210)",
"location": [
5666,
331,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5665,
"y1": 330,
"z1": -128,
"x2": 5668,
"y2": 333,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "5a62f325-4e00-49c3-8576-fdd9fcf330e5",
"name": "Spawner (210)",
"location": [
5771,
224,
-2
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5761,
"y1": 214,
"z1": -128,
"x2": 5782,
"y2": 235,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "ArcticOgreLord",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "61e8233d-f991-4429-9e4e-c7e0d24201d0",
"name": "Spawner (210)",
"location": [
5757,
213,
-7
],
"map": "Felucca",
"count": 10,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5742,
"y1": 198,
"z1": -128,
"x2": 5773,
"y2": 229,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "IceSerpent",
"maxCount": 3,
"probability": 100
},
{
"name": "Ratman",
"maxCount": 1,
"probability": 100
},
{
"name": "SnowElemental",
"maxCount": 4,
"probability": 100
},
{
"name": "IceElemental",
"maxCount": 4,
"probability": 100
},
{
"name": "FrostTroll",
"maxCount": 2,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "72473a5f-3d9b-4f69-b3f9-0d266291468a",
"name": "Spawner (210)",
"location": [
5824,
363,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5823,
"y1": 362,
"z1": -128,
"x2": 5826,
"y2": 365,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "7b080104-77b8-491b-b8f9-44cec8ecbb65",
"name": "Spawner (210)",
"location": [
5680,
306,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5670,
"y1": 296,
"z1": -128,
"x2": 5691,
"y2": 317,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "IceFiend",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "89792e6b-89bb-4c0a-8f45-259ab52f6844",
"name": "Spawner (210)",
"location": [
5676,
331,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5675,
"y1": 330,
"z1": -128,
"x2": 5678,
"y2": 333,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "8aba961b-8ce4-49ba-9ec8-7861204815c4",
"name": "Spawner (210)",
"location": [
5831,
358,
-1
],
"map": "Felucca",
"count": 24,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5816,
"y1": 343,
"z1": -128,
"x2": 5847,
"y2": 374,
"z2": 128
},
"walkingRange": 25,
"entries": [
{
"name": "Ratman",
"maxCount": 12,
"probability": 100
},
{
"name": "RatmanArcher",
"maxCount": 7,
"probability": 100
},
{
"name": "RatmanMage",
"maxCount": 5,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "9b93a6e4-67e5-4d22-aa51-ff84ea98bb72",
"name": "Spawner (210)",
"location": [
5751,
140,
10
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5750,
"y1": 139,
"z1": -128,
"x2": 5753,
"y2": 142,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "a3c447a5-c7bb-4826-a5ae-81d8b3863130",
"name": "Spawner (210)",
"location": [
5854,
227,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5853,
"y1": 226,
"z1": -128,
"x2": 5856,
"y2": 229,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "b8a2691a-996a-4c38-834f-897b972bfe2f",
"name": "Spawner (210)",
"location": [
5867,
218,
-4
],
"map": "Felucca",
"count": 4,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5852,
"y1": 203,
"z1": -128,
"x2": 5883,
"y2": 234,
"z2": 128
},
"walkingRange": 25,
"entries": [
{
"name": "FrostSpider",
"maxCount": 1,
"probability": 100
},
{
"name": "FrostOoze",
"maxCount": 2,
"probability": 100
},
{
"name": "IceSnake",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "b96eb341-ef4c-4b7e-ba01-6fb487be56a7",
"name": "Spawner (210)",
"location": [
5721,
147,
-1
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5720,
"y1": 146,
"z1": -128,
"x2": 5723,
"y2": 149,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "bca4ab21-15b1-4b04-b698-05d4f8df1f6c",
"name": "Spawner (210)",
"location": [
5838,
355,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5837,
"y1": 354,
"z1": -128,
"x2": 5840,
"y2": 357,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel2",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "cb37f510-fff9-4c76-8c51-2d59ddd8f715",
"name": "Spawner (210)",
"location": [
5683,
197,
-4
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5682,
"y1": 196,
"z1": -128,
"x2": 5685,
"y2": 199,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "cdb2ea29-4ee5-48c3-9444-018c5003afbd",
"name": "Spawner (210)",
"location": [
5837,
245,
-5
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5836,
"y1": 244,
"z1": -128,
"x2": 5839,
"y2": 247,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "d31d21b1-8768-4d45-a962-182e67f5a5c0",
"name": "Spawner (210)",
"location": [
5850,
219,
-3
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5840,
"y1": 209,
"z1": -128,
"x2": 5861,
"y2": 230,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "RatmanMage",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "d5ca5e49-cbb2-4079-81f1-c8679fcecb46",
"name": "Spawner (210)",
"location": [
5696,
303,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5695,
"y1": 302,
"z1": -128,
"x2": 5698,
"y2": 305,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "d7d771c1-605a-4253-965e-dec048f72502",
"name": "Spawner (210)",
"location": [
5752,
144,
9
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5742,
"y1": 134,
"z1": -128,
"x2": 5763,
"y2": 155,
"z2": 128
},
"walkingRange": 10,
"entries": [
{
"name": "WhiteWyrm",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "d8d3fc0f-231c-4d04-b0a3-7191cc4512b2",
"name": "Spawner (210)",
"location": [
5681,
191,
-6
],
"map": "Felucca",
"count": 9,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5666,
"y1": 176,
"z1": -128,
"x2": 5697,
"y2": 207,
"z2": 128
},
"walkingRange": 20,
"entries": [
{
"name": "IceSerpent",
"maxCount": 3,
"probability": 100
},
{
"name": "SnowElemental",
"maxCount": 4,
"probability": 100
},
{
"name": "IceElemental",
"maxCount": 4,
"probability": 100
},
{
"name": "FrostTroll",
"maxCount": 1,
"probability": 100
},
{
"name": "Ratman",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "e111cb63-9804-4eac-96ad-290a0b963c8f",
"name": "Spawner (210)",
"location": [
5814,
237,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5799,
"y1": 222,
"z1": -128,
"x2": 5830,
"y2": 253,
"z2": 128
},
"walkingRange": 15,
"entries": [
{
"name": "ArcticOgreLord",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "e89bcb09-65c3-4474-bded-50e62ce3c153",
"name": "Spawner (210)",
"location": [
5712,
145,
-34
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5711,
"y1": 144,
"z1": -128,
"x2": 5714,
"y2": 147,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "ed18e76c-c568-42fe-9c98-8482c467ff61",
"name": "Spawner (210)",
"location": [
5756,
203,
-2
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5755,
"y1": 202,
"z1": -128,
"x2": 5758,
"y2": 205,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "f2eb3f17-d5f4-4c58-a248-825e46a8a0f8",
"name": "Spawner (210)",
"location": [
5772,
188,
-3
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5771,
"y1": 187,
"z1": -128,
"x2": 5774,
"y2": 190,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "f522aee5-3ff7-427c-a3f1-31b162a65fbe",
"name": "Spawner (210)",
"location": [
5682,
314,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5681,
"y1": 313,
"z1": -128,
"x2": 5684,
"y2": 316,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "fe1657a5-a11c-4fe6-9544-a7ed0d2059b2",
"name": "Spawner (210)",
"location": [
5833,
242,
-2
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 5832,
"y1": 241,
"z1": -128,
"x2": 5835,
"y2": 244,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
}
]