ModernUO/Distribution/Data/Spawns/shared/felucca/PrismOfLight.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

698 lines
12 KiB
JSON

[
{
"$type": "Spawner",
"guid": "3ccfb405-2b18-4397-9d18-5b37302d62e4",
"name": "Spawner (216)",
"location": [
6521,
139,
-20
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6517,
"y1": 135,
"z1": -128,
"x2": 6526,
"y2": 144,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "Wisp",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "49f09e2e-fb04-42a9-96e2-d930c04f729f",
"name": "Spawner (216)",
"location": [
6530,
139,
-20
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6526,
"y1": 135,
"z1": -128,
"x2": 6535,
"y2": 144,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "Wisp",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "4e01097c-b1f4-4d22-ad9b-dcd117eeaeec",
"name": "Spawner (216)",
"location": [
6566,
120,
0
],
"map": "Felucca",
"count": 7,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6551,
"y1": 105,
"z1": -128,
"x2": 6582,
"y2": 136,
"z2": 128
},
"walkingRange": 15,
"entries": [
{
"name": "CrystalVortex",
"maxCount": 7,
"probability": 100
},
{
"name": "IceElemental",
"maxCount": 7,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "50809274-807a-49ee-b9f9-6c13693a56d0",
"name": "Spawner (216)",
"location": [
6572,
89,
0
],
"map": "Felucca",
"count": 2,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6568,
"y1": 85,
"z1": -128,
"x2": 6577,
"y2": 94,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "CrystalHydra",
"maxCount": 2,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "539ddfd6-d1ad-4e3f-b9cf-414a6dc0553a",
"name": "Spawner (216)",
"location": [
6509,
176,
0
],
"map": "Felucca",
"count": 2,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6505,
"y1": 172,
"z1": -128,
"x2": 6514,
"y2": 181,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "UnfrozenMummy",
"maxCount": 2,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "6912561a-5610-4441-8c64-16f4bd9f73f8",
"name": "Spawner (216)",
"location": [
6510,
171,
0
],
"map": "Felucca",
"count": 3,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6502,
"y1": 163,
"z1": -128,
"x2": 6519,
"y2": 180,
"z2": 128
},
"walkingRange": 8,
"entries": [
{
"name": "Protector",
"maxCount": 3,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "84ae0146-70ef-44e4-9159-db9a045c14c9",
"name": "Spawner (216)",
"location": [
6536,
79,
-10
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6532,
"y1": 75,
"z1": -128,
"x2": 6541,
"y2": 84,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "CrystalDaemon",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "8f88efe1-68b8-478e-8166-b03984e956e1",
"name": "Spawner (216)",
"location": [
6504,
181,
0
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6503,
"y1": 180,
"z1": -128,
"x2": 6506,
"y2": 183,
"z2": 128
},
"walkingRange": 1,
"entries": [
{
"name": "TreasureChestLevel4",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "8fe6c0c3-9fcb-4725-b6b2-ee89df036d80",
"name": "Spawner (216)",
"location": [
6532,
79,
-10
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6528,
"y1": 75,
"z1": -128,
"x2": 6537,
"y2": 84,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "CrystalDaemon",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "93922052-811a-473e-b3b2-eddf5380829a",
"name": "Spawner (216)",
"location": [
6475,
101,
-44
],
"map": "Felucca",
"count": 5,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6470,
"y1": 96,
"z1": -128,
"x2": 6481,
"y2": 107,
"z2": 128
},
"walkingRange": 5,
"entries": [
{
"name": "ShadowWisp",
"maxCount": 5,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "9c7afc30-19c5-4034-a344-8b75e52b6b40",
"name": "Spawner (216)",
"location": [
6547,
91,
-10
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6543,
"y1": 87,
"z1": -128,
"x2": 6552,
"y2": 96,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "CrystalDaemon",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "9ce6b636-4bca-44d7-adf2-5ef841d08a61",
"name": "Spawner (216)",
"location": [
6535,
179,
0
],
"map": "Felucca",
"count": 6,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6520,
"y1": 164,
"z1": -128,
"x2": 6551,
"y2": 195,
"z2": 128
},
"walkingRange": 15,
"entries": [
{
"name": "CrystalWisp",
"maxCount": 5,
"probability": 100
},
{
"name": "CrystalLatticeSeeker",
"maxCount": 5,
"probability": 100
},
{
"name": "TreasureChestLevel2",
"maxCount": 5,
"probability": 100
},
{
"name": "TreasureChestLevel2",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "9dc74009-4df1-4872-874f-fcc908ec105b",
"name": "Spawner (216)",
"location": [
6534,
178,
0
],
"map": "Felucca",
"count": 2,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6530,
"y1": 174,
"z1": -128,
"x2": 6539,
"y2": 183,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "CrystalWisp",
"maxCount": 2,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "adf86a17-213e-408b-be55-3cb37b9a1a36",
"name": "Spawner (216)",
"location": [
6502,
120,
-10
],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6502,
"y1": 120,
"z1": -10,
"x2": 6503,
"y2": 121,
"z2": -10
},
"walkingRange": 0,
"entries": [
{
"name": "TreasureChestLevel3",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "b87b2fe5-b1dc-46b1-9c35-f1627c33ad04",
"name": "Spawner (216)",
"location": [
6553,
157,
0
],
"map": "Felucca",
"count": 3,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6545,
"y1": 149,
"z1": -128,
"x2": 6562,
"y2": 166,
"z2": 128
},
"walkingRange": 8,
"entries": [
{
"name": "CrystalLatticeSeeker",
"maxCount": 3,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "c04125c7-bad1-4747-8e55-7664e9797a6d",
"name": "Spawner (216)",
"location": [
6474,
74,
-34
],
"map": "Felucca",
"count": 9,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6470,
"y1": 70,
"z1": -128,
"x2": 6479,
"y2": 79,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "Rat",
"maxCount": 9,
"probability": 100
},
{
"name": "IceSnake",
"maxCount": 9,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "c66d4bde-6308-44bb-80fe-f6f0070beda7",
"name": "Spawner (216)",
"location": [
6478,
174,
4
],
"map": "Felucca",
"count": 6,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6468,
"y1": 164,
"z1": -128,
"x2": 6489,
"y2": 185,
"z2": 128
},
"walkingRange": 10,
"entries": [
{
"name": "Wisp",
"maxCount": 6,
"probability": 100
},
{
"name": "CrystalWisp",
"maxCount": 6,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "e82c7115-8675-4d30-b321-c5e6a3b43ea0",
"name": "Spawner (216)",
"location": [
6507,
151,
0
],
"map": "Felucca",
"count": 3,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6502,
"y1": 146,
"z1": -128,
"x2": 6513,
"y2": 157,
"z2": 128
},
"walkingRange": 5,
"entries": [
{
"name": "Protector",
"maxCount": 3,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "ed613a4e-b19f-422e-943c-c94a29411ff8",
"name": "Spawner (216)",
"location": [
6578,
183,
31
],
"map": "Felucca",
"count": 2,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6573,
"y1": 178,
"z1": -128,
"x2": 6584,
"y2": 189,
"z2": 128
},
"walkingRange": 5,
"entries": [
{
"name": "Ferret",
"maxCount": 2,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "f083b3bb-c6c8-4774-a9d7-65d6b2cfc831",
"name": "Spawner (216)",
"location": [
6552,
155,
0
],
"map": "Felucca",
"count": 6,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6537,
"y1": 140,
"z1": -128,
"x2": 6568,
"y2": 171,
"z2": 128
},
"walkingRange": 15,
"entries": [
{
"name": "Wisp",
"maxCount": 5,
"probability": 100
},
{
"name": "CrystalWisp",
"maxCount": 5,
"probability": 100
},
{
"name": "TreasureChestLevel2",
"maxCount": 5,
"probability": 100
},
{
"name": "TreasureChestLevel2",
"maxCount": 1,
"probability": 100
}
]
},
{
"$type": "Spawner",
"guid": "f620b501-c242-4301-a813-b4d7a44e141f",
"name": "Spawner (216)",
"location": [
6576,
91,
0
],
"map": "Felucca",
"count": 2,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"spawnBounds": {
"x1": 6572,
"y1": 87,
"z1": -128,
"x2": 6581,
"y2": 96,
"z2": 128
},
"walkingRange": 4,
"entries": [
{
"name": "CrystalSeaSerpent",
"maxCount": 2,
"probability": 100
}
]
}
]