## 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.
677 lines
18 KiB
JSON
677 lines
18 KiB
JSON
[
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "04236803-3dc7-426b-8a8d-d927b1bd0086",
|
|
"name": "Spawner (311)",
|
|
"location": [1279, 781, -80],
|
|
"map": "Ilshenar",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 5,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "Ridgeback", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "063240fa-7f32-4bad-b79e-bf9c8ca7b9b9",
|
|
"name": "Spawner (311)",
|
|
"location": [1108, 492, -80],
|
|
"map": "Ilshenar",
|
|
"count": 5,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 25,
|
|
"walkingRange": 25,
|
|
"entries": [
|
|
{ "name": "Hind", "maxCount": 2, "probability": 100 },
|
|
{ "name": "GreatHart", "maxCount": 1, "probability": 100 },
|
|
{ "name": "BlackBear", "maxCount": 1, "probability": 100 },
|
|
{ "name": "DireWolf", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "149dfca3-652c-4777-b005-a0cc95f30d9d",
|
|
"name": "Spawner (311)",
|
|
"location": [1517, 541, 11],
|
|
"map": "Ilshenar",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 20,
|
|
"entries": [
|
|
{ "name": "Lich", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "165f16c6-b66f-474a-aed6-0d6c2ee57123",
|
|
"name": "Spawner (311)",
|
|
"location": [1715, 228, 78],
|
|
"map": "Ilshenar",
|
|
"count": 6,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "StoneHarpy", "maxCount": 3, "probability": 100 },
|
|
{ "name": "StoneGargoyle", "maxCount": 2, "probability": 100 },
|
|
{ "name": "Balron", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "17243bc5-68af-437f-bb95-963913a05306",
|
|
"name": "Spawner (311)",
|
|
"location": [1191, 696, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "SavageRider", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1b101011-42fa-41b1-b15c-f15fdcaaf6ec",
|
|
"name": "Spawner (311)",
|
|
"location": [1517, 558, 5],
|
|
"map": "Ilshenar",
|
|
"count": 6,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 20,
|
|
"walkingRange": 35,
|
|
"entries": [
|
|
{ "name": "Skeleton", "maxCount": 6, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1e1dd613-72d1-4715-b899-1086679533ab",
|
|
"name": "Spawner (311)",
|
|
"location": [1665, 244, 93],
|
|
"map": "Ilshenar",
|
|
"count": 5,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 25,
|
|
"walkingRange": 25,
|
|
"entries": [
|
|
{ "name": "EarthElemental", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Drake", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1e2bfa6b-abe9-4dcd-b996-bc4dcdd17f9f",
|
|
"name": "Spawner (311)",
|
|
"location": [1234, 760, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "SavageShaman", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1f0236b1-b26e-4572-b03a-d53d94ab1a6a",
|
|
"name": "Spawner (311)",
|
|
"location": [1110, 542, -77],
|
|
"map": "Ilshenar",
|
|
"count": 5,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 25,
|
|
"walkingRange": 25,
|
|
"entries": [
|
|
{ "name": "Hind", "maxCount": 2, "probability": 100 },
|
|
{ "name": "GreatHart", "maxCount": 1, "probability": 100 },
|
|
{ "name": "BlackBear", "maxCount": 1, "probability": 100 },
|
|
{ "name": "DireWolf", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "26a0cc2e-3dfc-49d7-9274-d993fc0371db",
|
|
"name": "Spawner (311)",
|
|
"location": [1292, 755, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "34ad74fe-d7eb-4427-8c7e-e7658bd63156",
|
|
"name": "Spawner (311)",
|
|
"location": [1363, 1046, -13],
|
|
"map": "Ilshenar",
|
|
"count": 4,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 15,
|
|
"walkingRange": 30,
|
|
"entries": [
|
|
{ "name": "EtherealWarrior", "maxCount": 4, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "38614de6-1ed9-41a0-b30b-59ae8191316f",
|
|
"name": "Spawner (311)",
|
|
"location": [1213, 719, -80],
|
|
"map": "Ilshenar",
|
|
"count": 4,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SavageRider", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "3bfd2dc7-d6d7-4604-858f-246ed9b25d35",
|
|
"name": "Spawner (311)",
|
|
"location": [1203, 762, -80],
|
|
"map": "Ilshenar",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "4befab4e-1b1a-4290-ae76-6c176b48a18a",
|
|
"name": "Spawner (311)",
|
|
"location": [1046, 517, -80],
|
|
"map": "Ilshenar",
|
|
"count": 7,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 15,
|
|
"walkingRange": 15,
|
|
"entries": [
|
|
{ "name": "SavageRider", "maxCount": 3, "probability": 100 },
|
|
{ "name": "Savage", "maxCount": 4, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "56b2d766-8057-4400-913f-6c10a5155f98",
|
|
"name": "Spawner (311)",
|
|
"location": [1251, 703, -80],
|
|
"map": "Ilshenar",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "59ae00b4-1b69-42de-8faa-670350014ad7",
|
|
"name": "Spawner (311)",
|
|
"location": [1116, 527, -80],
|
|
"map": "Ilshenar",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 15,
|
|
"walkingRange": 15,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 },
|
|
{ "name": "SavageRidgeback", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "5a5f79c6-3813-428e-a5fe-00893d247556",
|
|
"name": "Spawner (311)",
|
|
"location": [1161, 668, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 5,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "5f1d23bd-e6c8-422e-b69e-a88d61fa61c0",
|
|
"name": "Spawner (311)",
|
|
"location": [1243, 732, -80],
|
|
"map": "Ilshenar",
|
|
"count": 5,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 },
|
|
{ "name": "SavageShaman", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SavageRider", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "64e33b76-ba88-4906-a91f-4b56dea52a81",
|
|
"name": "Spawner (311)",
|
|
"location": [1181, 691, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "6ac6b235-2d7c-4058-bc8d-d7f73cd17d5a",
|
|
"name": "Spawner (311)",
|
|
"location": [817, 1065, -30],
|
|
"map": "Ilshenar",
|
|
"count": 26,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 60,
|
|
"walkingRange": 70,
|
|
"entries": [
|
|
{ "name": "Ogre", "maxCount": 5, "probability": 100 },
|
|
{ "name": "OgreLord", "maxCount": 2, "probability": 100 },
|
|
{ "name": "Ratman", "maxCount": 10, "probability": 100 },
|
|
{ "name": "RatmanMage", "maxCount": 5, "probability": 100 },
|
|
{ "name": "RatmanArcher", "maxCount": 4, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "6c8f4381-39be-4530-bfc3-1478035c1aa5",
|
|
"name": "Spawner (311)",
|
|
"location": [1108, 492, -80],
|
|
"map": "Ilshenar",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 25,
|
|
"walkingRange": 25,
|
|
"entries": [
|
|
{ "name": "Bird", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "72ce5891-f2dd-4a3c-8019-199928c49dcc",
|
|
"name": "Spawner (311)",
|
|
"location": [1231, 694, -80],
|
|
"map": "Ilshenar",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 2, "probability": 100 },
|
|
{ "name": "SavageShaman", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "7f13f3fa-2330-4dd5-9985-164d8e240659",
|
|
"name": "Spawner (311)",
|
|
"location": [1180, 1188, -25],
|
|
"map": "Ilshenar",
|
|
"count": 5,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 15,
|
|
"walkingRange": 15,
|
|
"entries": [
|
|
{ "name": "Snake", "maxCount": 5, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "824d3710-eb67-4f27-8917-6debd7c8e2ca",
|
|
"name": "Spawner (311)",
|
|
"location": [1517, 552, 10],
|
|
"map": "Ilshenar",
|
|
"count": 6,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 15,
|
|
"walkingRange": 30,
|
|
"entries": [
|
|
{ "name": "Spectre", "maxCount": 6, "probability": 100 },
|
|
{ "name": "Shade", "maxCount": 6, "probability": 100 },
|
|
{ "name": "Wraith", "maxCount": 6, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "86ff8b56-5d0c-4218-80d4-749414e3f568",
|
|
"name": "Spawner (311)",
|
|
"location": [1191, 696, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 5,
|
|
"walkingRange": 7,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "88f2279d-e351-4611-8255-206a456394d6",
|
|
"name": "Spawner (311)",
|
|
"location": [1110, 542, -77],
|
|
"map": "Ilshenar",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 25,
|
|
"walkingRange": 25,
|
|
"entries": [
|
|
{ "name": "Bird", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "917aa704-acc1-49ce-81c6-401f0604b260",
|
|
"name": "Spawner (311)",
|
|
"location": [1274, 728, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "93476fd0-4859-4358-90ab-4371f8c1ac40",
|
|
"name": "Spawner (311)",
|
|
"location": [1181, 1189, -25],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 12,
|
|
"walkingRange": 12,
|
|
"entries": [
|
|
{ "name": "GiantSerpent", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "9b71629a-ede8-4fba-bd86-63a895c4c422",
|
|
"name": "Spawner (311)",
|
|
"location": [1214, 744, -80],
|
|
"map": "Ilshenar",
|
|
"count": 4,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 4, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "9d3ed0a0-e458-4fa9-bc94-008304706893",
|
|
"name": "Spawner (311)",
|
|
"location": [1516, 557, 4],
|
|
"map": "Ilshenar",
|
|
"count": 7,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 20,
|
|
"walkingRange": 35,
|
|
"entries": [
|
|
{ "name": "Ghoul", "maxCount": 2, "probability": 100 },
|
|
{ "name": "Zombie", "maxCount": 5, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "9fce7b2d-3671-4d8e-bf22-19c10ec5709f",
|
|
"name": "Spawner (311)",
|
|
"location": [1280, 770, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 7,
|
|
"walkingRange": 7,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "c4c688bb-cf62-4b3d-84bd-2633333c0242",
|
|
"name": "Spawner (311)",
|
|
"location": [1517, 552, 10],
|
|
"map": "Ilshenar",
|
|
"count": 6,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 15,
|
|
"walkingRange": 30,
|
|
"entries": [
|
|
{ "name": "SkeletalKnight", "maxCount": 3, "probability": 100 },
|
|
{ "name": "BoneKnight", "maxCount": 3, "probability": 100 },
|
|
{ "name": "SkeletalMage", "maxCount": 3, "probability": 100 },
|
|
{ "name": "BoneMagi", "maxCount": 3, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "c671596f-69b6-45df-a106-b8fce71aa156",
|
|
"name": "Spawner (311)",
|
|
"location": [1517, 541, 61],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "LichLord", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "e0710f4e-9d44-4e1e-be0d-3f560d5f52c6",
|
|
"name": "Spawner (311)",
|
|
"location": [1643, 310, 48],
|
|
"map": "Ilshenar",
|
|
"count": 21,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 30,
|
|
"walkingRange": 50,
|
|
"entries": [
|
|
{ "name": "Phoenix", "maxCount": 2, "probability": 100 },
|
|
{ "name": "FireElemental", "maxCount": 4, "probability": 100 },
|
|
{ "name": "HellHound", "maxCount": 5, "probability": 100 },
|
|
{ "name": "LavaSerpent", "maxCount": 4, "probability": 100 },
|
|
{ "name": "LavaLizard", "maxCount": 4, "probability": 100 },
|
|
{ "name": "Daemon", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "eb0f7637-62d3-483f-835e-248e48ffdc44",
|
|
"name": "Spawner (311)",
|
|
"location": [1187, 685, -80],
|
|
"map": "Ilshenar",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "ed8774de-7f1f-4f40-bb03-0ff9e7d1ff31",
|
|
"name": "Spawner (311)",
|
|
"location": [1262, 758, -80],
|
|
"map": "Ilshenar",
|
|
"count": 4,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 10,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Savage", "maxCount": 4, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "ef56cf38-1547-41ad-adc4-ba72aa156f87",
|
|
"name": "Spawner (311)",
|
|
"location": [1127, 1112, -34],
|
|
"map": "Ilshenar",
|
|
"count": 7,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 25,
|
|
"walkingRange": 35,
|
|
"entries": [
|
|
{ "name": "DireWolf", "maxCount": 7, "probability": 100 },
|
|
{ "name": "TimberWolf", "maxCount": 7, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "f216ee7b-bb49-415a-aace-924f1778e3cc",
|
|
"name": "Spawner (311)",
|
|
"location": [1643, 310, 48],
|
|
"map": "Ilshenar",
|
|
"count": 4,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 30,
|
|
"walkingRange": 50,
|
|
"entries": [
|
|
{ "name": "Succubus", "maxCount": 2, "probability": 100 },
|
|
{ "name": "Efreet", "maxCount": 2, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "fb0b433c-9d26-4a0f-b9a0-4ddb16ea1904",
|
|
"name": "Spawner (311)",
|
|
"location": [1046, 517, -80],
|
|
"map": "Ilshenar",
|
|
"count": 4,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 7,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "SavageShaman", "maxCount": 4, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "fb1de953-cfdd-46d6-aab9-68cbdfe60780",
|
|
"name": "Spawner (311)",
|
|
"location": [1203, 1138, -25],
|
|
"map": "Ilshenar",
|
|
"count": 16,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 40,
|
|
"walkingRange": 55,
|
|
"entries": [
|
|
{ "name": "MeerWarrior", "maxCount": 16, "probability": 100 },
|
|
{ "name": "MeerCaptain", "maxCount": 16, "probability": 100 },
|
|
{ "name": "MeerMage", "maxCount": 16, "probability": 100 },
|
|
{ "name": "MeerEternal", "maxCount": 16, "probability": 100 }
|
|
]
|
|
}
|
|
]
|