## Summary Removes the dated `DynamicJson` JSON helper and migrates spawner JSON (de)serialization to a polymorphic `record SpawnerDto` hierarchy. `DynamicJson` was the last remaining consumer (regions moved off it in #1400). The key correctness improvement: **System.Text.Json deserializes plain DTO records, never a live `Item`.** Previously, deserializing directly into an `Item` meant STJ constructed world-registered objects *before* the data was validated — a malformed/hand-edited spawn file could leave orphaned spawner Items in the world save. Now a parse failure is GC-only; `dto.ToSpawner()` constructs the spawner only from a fully-validated DTO and self-cleans on failure. ## What changed - **New:** `SpawnerDto` (abstract) + `SpawnerDataDto` / `RegionSpawnerDto` / `ProximitySpawnerDto`, each marked with a reusable `[JsonDiscoverableType]` opt-in attribute. Auto-discovered at the `Configure` phase — no manual registration list (avoids the regions `Register<T>()` footgun), open to custom spawner subtypes. - **Symmetric mapping:** `BaseSpawner.ToDto()` (export) ⇄ `SpawnerDto.ToSpawner()` (import). `ToSpawner()` deletes-and-rethrows on any failure, so the importer can never orphan an Item. - **`SpawnerJsonSerializer`** wires `$type` polymorphism on the `SpawnerDto` root with loud collision/constructibility validation. - **Import/export commands** rewired to the typed DTO path (reflection `FindTypeByName`/`CreateInstance` removed). - **Data migration:** the 109 `Distribution/Data/Spawns/**` files moved from `"type"`→`"$type"` and legacy `homeRange`→`spawnBounds`. The runtime still *reads* legacy `homeRange` for external files. The `homeRange→spawnBounds` formula is proven equivalent to the runtime conversion (`BoundsEquivalenceTests`, hr=0/1/3/7). - **Deleted:** `Projects/Server/Json/DynamicJson.cs`. Sparse export output matches the legacy `ToJson` (nullable DTO properties + `WhenWritingNull`). Binary world-save serialization is untouched. ## Tests - DTO round-trip per spawner type; sparse-default omission; legacy `homeRange` read; export/import file round-trip. - `Import_MalformedFile_LeaksNoWorldItems` — proves a mid-array parse failure constructs zero world Items. - `AllSpawnFilesLoadTests` — every migrated spawn file deserializes and builds. - Duplicate-discriminator validation. - UOContent.Tests 485/485, Server.Tests 710/710, build clean. ## Follow-up (not in this PR) `Rectangle3DConverter.Write` (in `Projects/Server/`) omits `z1/z2` when `Start.Z == -128`, so a future server-side export of a `homeRange`-style spawner round-trips depth 256→255. Pre-existing and out of scope here (Server change); the migrated data reads correctly. Worth a separate small converter PR.
819 lines
22 KiB
JSON
819 lines
22 KiB
JSON
[
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "0cd9c91b-ab80-4dbd-8594-ace0132a0fc8",
|
|
"name": "Spawner (123)",
|
|
"location": [1521, 1457, 15],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 1,
|
|
"entries": [
|
|
{ "name": "ChaosGuard", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "112087fa-8961-4d69-a729-19390bb722c5",
|
|
"name": "Spawner (123)",
|
|
"location": [1126, 3688, -2],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "17960040-e115-49e8-a1f3-f14583d9517f",
|
|
"name": "Spawner (123)",
|
|
"location": [603, 2141, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1de05315-2afe-4cc6-8b83-22fe3ebab00e",
|
|
"name": "Spawner (123)",
|
|
"location": [2994, 3451, 16],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "26a2621e-6b2c-47ef-b957-4d5630091661",
|
|
"name": "Spawner (123)",
|
|
"location": [1399, 3743, -21],
|
|
"map": "Trammel",
|
|
"count": 10,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "HireBard", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireBardArcher", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireBeggar", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireFighter", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireMage", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireRanger", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireRangerArcher", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireSailor", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HireThief", "maxCount": 5, "probability": 100 },
|
|
{ "name": "HirePaladin", "maxCount": 5, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "2b35dd52-619d-448f-86d1-8aaa6f146ac7",
|
|
"name": "Spawner (123)",
|
|
"location": [1829, 2811, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "2e006ab7-3370-4b4e-8fbc-cfa849b3d0c5",
|
|
"name": "Spawner (123)",
|
|
"location": [7082, 367, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Olaeni", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "31d1057e-9886-428e-82ef-4c08bf202117",
|
|
"name": "Spawner (123)",
|
|
"location": [3815, 1217, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "3203a756-0011-4741-9fae-8a1c92166c45",
|
|
"name": "Spawner (123)",
|
|
"location": [3749, 1404, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "34473f72-e1ae-4968-97aa-0388ead486b9",
|
|
"name": "Spawner (123)",
|
|
"location": [3773, 1308, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "36bf73a1-cc52-4776-8b8b-99088d86d03c",
|
|
"name": "Spawner (123)",
|
|
"location": [627, 864, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "37d7e7c7-3ef0-4b63-bc92-87b172a02533",
|
|
"name": "Spawner (123)",
|
|
"location": [7053, 338, 0],
|
|
"map": "Trammel",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 6,
|
|
"walkingRange": 6,
|
|
"entries": [
|
|
{ "name": "aneen", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Bird", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "4258947f-59d2-4fbb-98e7-11b65f16d8a9",
|
|
"name": "Spawner (123)",
|
|
"location": [7063, 350, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Bolaevin", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Bird", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "46dc4d43-91c1-4d09-a0e0-9d2e89804977",
|
|
"name": "Spawner (123)",
|
|
"location": [7090, 387, 0],
|
|
"map": "Trammel",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 8,
|
|
"walkingRange": 8,
|
|
"entries": [
|
|
{ "name": "Aluniol", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Rebinil", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "56ff4f2b-88cc-44ce-bc5c-cadd416e069d",
|
|
"name": "Spawner (123)",
|
|
"location": [3721, 2161, 20],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "64802440-be2d-4b3e-babb-d8612ae85e90",
|
|
"name": "Spawner (123)",
|
|
"location": [2875, 675, 0],
|
|
"map": "Trammel",
|
|
"count": 6,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 2,
|
|
"walkingRange": 2,
|
|
"entries": [
|
|
{ "name": "TreasureChestLevel1", "maxCount": 6, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "65e4866a-41f4-47ec-8f26-aa92f48aac80",
|
|
"name": "Spawner (123)",
|
|
"location": [2895, 686, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "756f5e4b-690b-4d80-a775-3ff67397e700",
|
|
"name": "Spawner (123)",
|
|
"location": [2891, 3474, 15],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "76bb7e24-7ad9-4dc2-97c8-f575ff05a259",
|
|
"name": "Spawner (123)",
|
|
"location": [1914, 2687, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "79236906-51cd-4390-86c5-36b5ea71f943",
|
|
"name": "Spawner (123)",
|
|
"location": [2874, 692, 0],
|
|
"map": "Trammel",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 1,
|
|
"entries": [
|
|
{ "name": "TreasureChestLevel1", "maxCount": 1, "probability": 100 },
|
|
{ "name": "TreasureChestLevel2", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "81d50c82-2e5a-41d8-b572-f50a66302d6e",
|
|
"name": "Spawner (123)",
|
|
"location": [2254, 1207, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "81e6cbf7-1e74-4547-b10f-024a75b64d40",
|
|
"name": "Spawner (123)",
|
|
"location": [2068, 2854, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "81ee4607-e452-45ca-ac26-7c5a8d47f201",
|
|
"name": "Spawner (123)",
|
|
"location": [1662, 1611, 19],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "82760905-485e-4bbe-83b6-56ccc903665a",
|
|
"name": "Spawner (123)",
|
|
"location": [1372, 3916, -2],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "852fdf43-a6c6-4fb9-acd9-35b1943f4d11",
|
|
"name": "Spawner (123)",
|
|
"location": [1483, 1760, -2],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "86739b8d-2726-43ff-aeaa-562873cee364",
|
|
"name": "Spawner (123)",
|
|
"location": [1813, 2834, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 2,
|
|
"walkingRange": 2,
|
|
"entries": [
|
|
{ "name": "TreasureChestLevel3", "maxCount": 1, "probability": 100 },
|
|
{ "name": "TreasureChestLevel4", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "88ba3663-c0bb-4d49-bcb5-cc4b6490b9cf",
|
|
"name": "Spawner (123)",
|
|
"location": [673, 2235, -3],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "8b75bcf8-7b83-4d94-8573-92aff88cd41f",
|
|
"name": "Spawner (123)",
|
|
"location": [3652, 2619, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "8d746f23-5e37-467c-9b8c-2af3b1ba0882",
|
|
"name": "Spawner (123)",
|
|
"location": [5685, 3148, -4],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "8d7c52fa-6f53-40ae-8f24-1daf0a7ce571",
|
|
"name": "Spawner (123)",
|
|
"location": [1400, 1628, 28],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 1,
|
|
"entries": [
|
|
{ "name": "OrderGuard", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "93c7a59d-449b-4993-b89d-8261edf96f2d",
|
|
"name": "Spawner (123)",
|
|
"location": [2515, 557, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "995f4053-0947-4757-8665-98cdac36ca2b",
|
|
"name": "Spawner (123)",
|
|
"location": [6989, 342, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 8,
|
|
"walkingRange": 8,
|
|
"entries": [
|
|
{ "name": "Tyeelor", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "99c8e802-f37a-4f2e-b5d5-23239e0ba219",
|
|
"name": "Spawner (123)",
|
|
"location": [7048, 382, 0],
|
|
"map": "Trammel",
|
|
"count": 6,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 12,
|
|
"walkingRange": 12,
|
|
"entries": [
|
|
{ "name": "abbein", "maxCount": 1, "probability": 100 },
|
|
{ "name": "taellia", "maxCount": 1, "probability": 100 },
|
|
{ "name": "vicaie", "maxCount": 1, "probability": 100 },
|
|
{ "name": "mallew", "maxCount": 1, "probability": 100 },
|
|
{ "name": "jothan", "maxCount": 1, "probability": 100 },
|
|
{ "name": "alethanian", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "9e077b7d-aea5-4e45-9435-4cce0aaa6962",
|
|
"name": "Spawner (123)",
|
|
"location": [4398, 1049, -2],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "9f7c934c-8e02-433d-a88f-4c8769a02081",
|
|
"name": "Spawner (123)",
|
|
"location": [7031, 409, 7],
|
|
"map": "Trammel",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Alelle", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Daelas", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "a1fec8b0-aeb0-4cfe-bedb-a630f60f483b",
|
|
"name": "Spawner (123)",
|
|
"location": [1400, 1623, 28],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 1,
|
|
"entries": [
|
|
{ "name": "OrderGuard", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "bc65ad16-fde0-4172-b5c9-df90020f5ed5",
|
|
"name": "Spawner (123)",
|
|
"location": [3674, 2291, -2],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "c26e2162-6a56-4eeb-b6ec-300b0ef5ed0f",
|
|
"name": "Spawner (123)",
|
|
"location": [1330, 3778, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "ce3d7ff4-6411-4a30-914a-6b2bd1b9c752",
|
|
"name": "Spawner (123)",
|
|
"location": [3645, 2661, -2],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "d351ad8d-c82c-43b5-a10c-b7d42d47cc9f",
|
|
"name": "Spawner (123)",
|
|
"location": [1421, 1698, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "d9dbef7c-e798-47c8-8939-7bbb74d297a9",
|
|
"name": "Spawner (123)",
|
|
"location": [573, 2246, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "e1071149-0c52-45c8-a0db-75da33c0a77e",
|
|
"name": "Spawner (123)",
|
|
"location": [631, 883, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "ea87d9c8-52d9-492a-9a5f-9b32bf2ee832",
|
|
"name": "Spawner (123)",
|
|
"location": [3041, 827, -3],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "EscortableMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SeekerOfAdventure", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Noble", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "f539d13c-6972-46fe-bce6-a09531c3473a",
|
|
"name": "Spawner (123)",
|
|
"location": [2884, 692, 0],
|
|
"map": "Trammel",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 1,
|
|
"entries": [
|
|
{ "name": "TreasureChestLevel2", "maxCount": 2, "probability": 100 },
|
|
{ "name": "TreasureChestLevel3", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "faa84300-0e93-40c1-a328-863f8ed209fe",
|
|
"name": "Spawner (123)",
|
|
"location": [5290, 3987, 37],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "fc87ea0f-7cd3-413a-a409-d1b304ec5299",
|
|
"name": "Spawner (123)",
|
|
"location": [1525, 1457, 15],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 1,
|
|
"entries": [
|
|
{ "name": "ChaosGuard", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "fd8c35db-5081-4db5-9859-2873a070fbac",
|
|
"name": "Spawner (123)",
|
|
"location": [7010, 363, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 8,
|
|
"walkingRange": 8,
|
|
"entries": [
|
|
{ "name": "athialon", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "ffaf3446-ee45-4f0f-9020-7508409e7da0",
|
|
"name": "Spawner (123)",
|
|
"location": [4451, 1153, 0],
|
|
"map": "Trammel",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 1,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
}
|
|
]
|