ModernUO/Distribution/Data/Spawns/shared/felucca/TownsPeople.json
Kamron Batman d8a64f3316
refactor(spawners): replace DynamicJson with typed SpawnerDto records (#2505)
## 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.
2026-06-25 23:24:45 -07:00

819 lines
22 KiB
JSON

[
{
"$type": "Spawner",
"guid": "01057a94-5e22-4609-8162-aa947144da30",
"name": "Spawner (223)",
"location": [7031, 409, 7],
"map": "Felucca",
"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": "017be0ee-b224-4daf-9626-6bcb46a4b433",
"name": "Spawner (223)",
"location": [3815, 1217, 0],
"map": "Felucca",
"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": "0f1fbc08-b932-424b-956a-f78082db8525",
"name": "Spawner (223)",
"location": [627, 864, 0],
"map": "Felucca",
"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": "0f9c22dd-0738-4b96-b652-3171ed867cbd",
"name": "Spawner (223)",
"location": [1829, 2811, 0],
"map": "Felucca",
"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": "1d916eb1-ed25-4d3b-a9cd-995e97630ed8",
"name": "Spawner (223)",
"location": [1662, 1611, 19],
"map": "Felucca",
"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": "23e949aa-940a-4b5a-9ce9-762db82b58a6",
"name": "Spawner (223)",
"location": [2884, 692, 0],
"map": "Felucca",
"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": "259cc674-14e4-4fe2-b8fa-10af4610ffbc",
"name": "Spawner (223)",
"location": [4398, 1049, -2],
"map": "Felucca",
"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": "34e31c96-47b7-4760-8446-d0a1f816d315",
"name": "Spawner (223)",
"location": [3652, 2619, 0],
"map": "Felucca",
"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": "380cd112-1791-4b59-8910-9ec257750d3e",
"name": "Spawner (223)",
"location": [2068, 2854, 0],
"map": "Felucca",
"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": "409f20ec-24eb-4ac4-9768-ee6467476f0c",
"name": "Spawner (223)",
"location": [1421, 1698, 0],
"map": "Felucca",
"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": "478d5bf8-5043-4d76-9a45-802677f0c30f",
"name": "Spawner (223)",
"location": [7010, 363, 0],
"map": "Felucca",
"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": "4de7c0e5-3203-4a68-a2d6-8e78652191fc",
"name": "Spawner (223)",
"location": [4451, 1153, 0],
"map": "Felucca",
"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": "5ed933bb-802f-444d-855d-c499926302ab",
"name": "Spawner (223)",
"location": [1813, 2834, 0],
"map": "Felucca",
"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": "6301492f-d4ed-4f24-afb2-cbbedb68afe6",
"name": "Spawner (223)",
"location": [3645, 2661, -2],
"map": "Felucca",
"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": "63416791-9505-4a1e-ab72-91c9438612df",
"name": "Spawner (223)",
"location": [1483, 1760, -2],
"map": "Felucca",
"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": "70250667-d0b4-488e-95e3-c660bcab2428",
"name": "Spawner (223)",
"location": [2254, 1207, 0],
"map": "Felucca",
"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": "710c1e19-1ae1-4131-99c6-184cb4636f03",
"name": "Spawner (223)",
"location": [3041, 827, -3],
"map": "Felucca",
"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": "81cb310e-ae13-4fca-bd6e-3bb693d0ef0a",
"name": "Spawner (223)",
"location": [1400, 1623, 28],
"map": "Felucca",
"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": "84f9a05f-e99b-4ece-9156-1978b789c47f",
"name": "Spawner (223)",
"location": [3721, 2161, 20],
"map": "Felucca",
"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": "8517bfc1-8190-42fb-bfec-f5a0a03488cc",
"name": "Spawner (223)",
"location": [5685, 3148, -4],
"map": "Felucca",
"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": "87354a42-802a-4607-92e9-cd39a5bac46d",
"name": "Spawner (223)",
"location": [3749, 1404, 0],
"map": "Felucca",
"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": "892bd9fc-6385-46b9-9c20-dd9eeb4dcdc8",
"name": "Spawner (223)",
"location": [7082, 367, 0],
"map": "Felucca",
"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": "8d5e0ca7-10d5-4475-9aa3-23bdc96210de",
"name": "Spawner (223)",
"location": [7053, 338, 0],
"map": "Felucca",
"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": "8e6761b5-a94e-4a95-90da-c08d5966aeb5",
"name": "Spawner (223)",
"location": [7063, 350, 0],
"map": "Felucca",
"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": "9119d23e-0857-4d0c-a03e-c345aafdd7fe",
"name": "Spawner (223)",
"location": [1399, 3743, -21],
"map": "Felucca",
"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": "92425d73-e98b-46d3-b391-77582cda9302",
"name": "Spawner (223)",
"location": [2891, 3474, 15],
"map": "Felucca",
"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": "9522412c-95ef-4067-9b3c-fd814717f9b4",
"name": "Spawner (223)",
"location": [1372, 3916, -2],
"map": "Felucca",
"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": "9c4d2d6b-56e8-4473-959d-9cc9199c11e1",
"name": "Spawner (223)",
"location": [2515, 557, 0],
"map": "Felucca",
"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": "a39b544b-76ab-424d-9f6d-a91cd55e3ed6",
"name": "Spawner (223)",
"location": [3674, 2291, -2],
"map": "Felucca",
"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": "a65b533b-cb58-4d72-8c9b-5375a7e7ad02",
"name": "Spawner (223)",
"location": [2895, 686, 0],
"map": "Felucca",
"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": "aac6fef9-46e2-44b2-9297-cd812c3b2c7b",
"name": "Spawner (223)",
"location": [2994, 3451, 16],
"map": "Felucca",
"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": "adee85c7-830f-4ef1-8539-77b5006da4f9",
"name": "Spawner (223)",
"location": [2874, 692, 0],
"map": "Felucca",
"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": "b4bb5474-dfc9-46a7-ba0d-9b117110cb0b",
"name": "Spawner (223)",
"location": [5290, 3987, 37],
"map": "Felucca",
"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": "b902cab2-6165-44ca-b583-814d9d3849a0",
"name": "Spawner (223)",
"location": [1400, 1628, 28],
"map": "Felucca",
"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": "b9f512c6-5b66-4f2a-9a03-6c0c99d7863f",
"name": "Spawner (223)",
"location": [7090, 387, 0],
"map": "Felucca",
"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": "ba1a481e-d5da-4445-af80-eee525b3e3c9",
"name": "Spawner (223)",
"location": [3773, 1308, 0],
"map": "Felucca",
"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": "bba7781a-c2fd-486f-8bfa-587c809347d5",
"name": "Spawner (223)",
"location": [573, 2246, 0],
"map": "Felucca",
"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": "c5d53f85-e6b8-4791-a77e-d241fab79d05",
"name": "Spawner (223)",
"location": [1914, 2687, 0],
"map": "Felucca",
"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": "c7251678-03dd-4030-8316-2529b932fecb",
"name": "Spawner (223)",
"location": [7048, 382, 0],
"map": "Felucca",
"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": "c9a63304-f0da-4144-9982-f8ce6d4c1914",
"name": "Spawner (223)",
"location": [6989, 342, 0],
"map": "Felucca",
"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": "cb794f47-6ae2-4f92-809d-27c34fbd0b7b",
"name": "Spawner (223)",
"location": [1126, 3688, -2],
"map": "Felucca",
"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": "d95bb2d0-7f44-4ff3-9c87-93d0ba887e86",
"name": "Spawner (223)",
"location": [631, 883, 0],
"map": "Felucca",
"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": "e134aa6f-68a5-48c8-819f-64e2806f8877",
"name": "Spawner (223)",
"location": [2875, 675, 0],
"map": "Felucca",
"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": "e284edef-ae7d-4ed1-8620-441dfb4618c9",
"name": "Spawner (223)",
"location": [1521, 1457, 15],
"map": "Felucca",
"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": "e97a4cd6-1170-4ab3-abf2-58b0c8e241bd",
"name": "Spawner (223)",
"location": [1525, 1457, 15],
"map": "Felucca",
"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": "ee30f8c4-8c52-4aaf-a974-2e4df4d0e28e",
"name": "Spawner (223)",
"location": [673, 2235, -3],
"map": "Felucca",
"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": "ee365839-216c-4690-89cc-f5d83845f669",
"name": "Spawner (223)",
"location": [1330, 3778, 0],
"map": "Felucca",
"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": "fa72d822-a3e5-43f5-9eb6-f800b3e49553",
"name": "Spawner (223)",
"location": [603, 2141, 0],
"map": "Felucca",
"count": 1,
"minDelay": "00:05:00",
"maxDelay": "00:10:00",
"team": 0,
"homeRange": 1,
"walkingRange": 5,
"entries": [
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
]
}
]