feat(editor): add WCMR (Creature Patrol Path) — 90th open format milestone

Open replacement for AzerothCore's creature_movement / waypoints
SQL tables plus the per-spawn waypoint arrays. Defines named
waypoint paths that creatures patrol along: Stormwind guards
walking the city perimeter, AQ40 trash rotating through the
chamber, ICC patrols circling the spire.

Each entry binds a creatureGuid to a sequence of (x, y, z,
delayMs) waypoints. The pathKind controls cycling behavior
(Loop / OneShot / Reverse / Random) and moveType controls the
locomotion kind (Walk / Run / Fly / Swim) — a flying patrol
ignores ground geometry, a swimming patrol stays underwater.

This is the first open format with truly variable-length
per-entry payload. Earlier formats with multi-slot fields
(WSPR's 8-reagent slots, WPSP's 4-item arrays) used fixed-size
caps padded with zeros. WCMR instead uses an inline
length-prefixed waypoint array — entries can be 4 waypoints or
4000, with the loader advancing through the file by reading the
count first then count*16 bytes of waypoint data. Cap of 64K
waypoints per path keeps a corrupted file from allocating
gigabytes.

pathLengthYards(pathId) is the engine helper that sums segment
distances between consecutive waypoints (closing the loop for
Loop kind). Tested across 12-point and 16-point circular paths
that geometrically resolve to the expected ~25y radius and
~60y radius totals.

Cross-references back to WCRT — creatureGuid points at the
spawned creature instance whose behavior mode follows this
patrol.

Three preset emitters: --gen-cmr (3 small paths showing each
pathKind variant), --gen-cmr-city (4 capital-city guard 6-point
loops with 2.0-2.5s waypoint dwell), --gen-cmr-boss (3 long
raid-zone patrols up to 16 waypoints, demonstrating that
variable-length payloads scale).

Validation enforces id+name+creatureGuid+waypoints presence,
pathKind 0..3, moveType 0..3, no duplicate ids; warns on
1-waypoint paths (creature would idle in place) and Loop with
fewer than 3 waypoints (degenerate — indistinguishable from
Reverse).

This is the 90th open format milestone. Wired through the
cross-format table; WCMR appears in all 18 cross-format
utilities. Format count 89 -> 90; CLI flag count 1048 -> 1053.
This commit is contained in:
Kelsi 2026-05-09 23:38:59 -07:00
parent 16d004c742
commit 7d3b80e1f7
10 changed files with 785 additions and 0 deletions

View file

@ -2013,6 +2013,16 @@ void printUsage(const char* argv0) {
std::printf(" Export binary .wsps to a human-editable JSON sidecar (defaults to <base>.wsps.json)\n");
std::printf(" --import-wsps-json <json-path> [out-base]\n");
std::printf(" Import a .wsps.json sidecar back into binary .wsps (procFlags accepts int OR pipe-separated label string)\n");
std::printf(" --gen-cmr <wcmr-base> [name]\n");
std::printf(" Emit .wcmr 3 small patrols showing each pathKind (4-pt Loop guard / 6-pt OneShot run / 8-pt Random tiger)\n");
std::printf(" --gen-cmr-city <wcmr-base> [name]\n");
std::printf(" Emit .wcmr 4 capital-city guard routes (Stormwind / Orgrimmar / Ironforge / Thunder Bluff) with 6-point loops\n");
std::printf(" --gen-cmr-boss <wcmr-base> [name]\n");
std::printf(" Emit .wcmr 3 raid-zone patrols (AQ40 12-pt Loop / Naxx 8-pt OneShot / ICC 16-pt Random) demonstrating long-path support\n");
std::printf(" --info-wcmr <wcmr-base> [--json]\n");
std::printf(" Print WCMR entries (id / creatureGuid / pathKind / moveType / waypoint count / total path length yards / name)\n");
std::printf(" --validate-wcmr <wcmr-base> [--json]\n");
std::printf(" Static checks: id+name+creatureGuid+waypoints required, pathKind 0..3, moveType 0..3, no duplicate ids; warns on 1-waypoint paths (idle), Loop with <3 waypoints (degenerate)\n");
std::printf(" --gen-weather-temperate <wow-base> [zoneName]\n");
std::printf(" Emit .wow weather schedule: clear-dominant + occasional rain + fog (forest / grassland)\n");
std::printf(" --gen-weather-arctic <wow-base> [zoneName]\n");