refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
#include "cli_help.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
|
|
|
|
namespace wowee {
|
|
|
|
|
|
namespace editor {
|
|
|
|
|
|
namespace cli {
|
|
|
|
|
|
|
|
|
|
|
|
void printUsage(const char* argv0) {
|
|
|
|
|
|
std::printf("Usage: %s --data <path> [options]\n\n", argv0);
|
|
|
|
|
|
std::printf("Options:\n");
|
|
|
|
|
|
std::printf(" --data <path> Path to extracted WoW data (manifest.json)\n");
|
|
|
|
|
|
std::printf(" --adt <map> <x> <y> Load an ADT tile on startup\n");
|
|
|
|
|
|
std::printf(" --convert-m2 <path> Convert M2 model to WOM open format (no GUI)\n");
|
|
|
|
|
|
std::printf(" --convert-m2-batch <srcDir>\n");
|
|
|
|
|
|
std::printf(" Bulk M2→WOM conversion across every .m2 in <srcDir> (per-file pass/fail summary)\n");
|
|
|
|
|
|
std::printf(" --convert-wmo <path> Convert WMO building to WOB open format (no GUI)\n");
|
|
|
|
|
|
std::printf(" --convert-wmo-batch <srcDir>\n");
|
|
|
|
|
|
std::printf(" Bulk WMO→WOB conversion across every .wmo in <srcDir> (skips _NNN group files)\n");
|
|
|
|
|
|
std::printf(" --convert-dbc-batch <srcDir>\n");
|
|
|
|
|
|
std::printf(" Bulk DBC→JSON conversion across every .dbc in <srcDir> (sidecars next to source)\n");
|
|
|
|
|
|
std::printf(" --migrate-data-tree <srcDir>\n");
|
|
|
|
|
|
std::printf(" Run all four bulk converters (m2/wmo/blp/dbc) end-to-end on an extracted Data tree\n");
|
|
|
|
|
|
std::printf(" --info-data-tree <srcDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-format migration-progress report (m2 vs wom, wmo vs wob, blp vs png, dbc vs json)\n");
|
|
|
|
|
|
std::printf(" --strip-data-tree <srcDir> [--dry-run]\n");
|
|
|
|
|
|
std::printf(" Delete proprietary files (.m2/.wmo/.blp/.dbc) that already have an open sidecar\n");
|
|
|
|
|
|
std::printf(" --audit-data-tree <srcDir>\n");
|
|
|
|
|
|
std::printf(" CI gate: exit 1 if any proprietary file lacks an open sidecar (100%% migration check)\n");
|
|
|
|
|
|
std::printf(" --bench-migrate-data-tree <srcDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Time each step of --migrate-data-tree (m2/wmo/blp/dbc) and report wall-clock per step\n");
|
|
|
|
|
|
std::printf(" --list-data-tree-largest <srcDir> [N]\n");
|
|
|
|
|
|
std::printf(" Top-N largest proprietary files (.m2/.wmo/.blp/.dbc) for migration prioritization\n");
|
|
|
|
|
|
std::printf(" --export-data-tree-md <srcDir> [out.md]\n");
|
|
|
|
|
|
std::printf(" Markdown migration-progress report (per-pair table, share %%, recommended next steps)\n");
|
|
|
|
|
|
std::printf(" --gen-texture <out.png> <colorHex|pattern> [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize a placeholder texture (solid hex color or 'checker'/'grid'); default 256x256\n");
|
|
|
|
|
|
std::printf(" --gen-texture-gradient <out.png> <fromHex> <toHex> [vertical|horizontal] [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize a linear gradient PNG (default vertical, 256x256)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-noise <out.png> [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize a smooth value-noise PNG (deterministic from seed; default 256x256)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-noise-color <out.png> <colorAHex> <colorBHex> [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Same noise pattern but blended between two colors instead of grayscale\n");
|
|
|
|
|
|
std::printf(" --gen-texture-radial <out.png> <centerHex> <edgeHex> [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize a radial gradient PNG (center→edge, smooth distance-based blend)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-stripes <out.png> <colorAHex> <colorBHex> [stripePx] [diagonal|horizontal|vertical] [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize a two-color stripe pattern (default 16px diagonal, 256x256)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-dots <out.png> <bgHex> <dotHex> [dotRadius] [spacing] [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize a polka-dot pattern (default radius 8, spacing 32, 256x256)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-rings <out.png> <colorAHex> <colorBHex> [ringPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize concentric ring pattern (target/seal style; default 16px rings, 256x256)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-checker <out.png> <colorAHex> <colorBHex> [cellPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Synthesize checkerboard with custom colors (gen-texture's checker is BW only)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-brick <out.png> <brickHex> <mortarHex> [brickW] [brickH] [mortarPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Brick wall pattern with offset rows + mortar lines (default 64×24, 4px mortar)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-wood <out.png> <lightHex> <darkHex> [grainSpacing] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Wood grain pattern with vertical streaks + knots (default spacing 12px, seed 1)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-grass <out.png> <baseHex> <bladeHex> [density] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Tiling grass texture with random blade highlights (default density=0.15, seed=1)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-fabric <out.png> <warpHex> <weftHex> [threadPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Woven fabric pattern with alternating warp/weft threads (default thread=4px)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-cobble <out.png> <stoneHex> <mortarHex> [stonePx] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Cobblestone street pattern: irregular packed stones (default stone=24px, seed 1)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-marble <out.png> <baseHex> <veinHex> [seed] [veinSharpness] [W H]\n");
|
|
|
|
|
|
std::printf(" Marble pattern with sinusoidal veining (default seed 1, sharpness 8)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-metal <out.png> <baseHex> [seed] [orientation] [W H]\n");
|
|
|
|
|
|
std::printf(" Brushed metal: directional anisotropic noise (orientation: horizontal|vertical)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-leather <out.png> <baseHex> [seed] [grainSize] [W H]\n");
|
|
|
|
|
|
std::printf(" Leather grain: irregular pebbled bumps via cellular noise (default grain=4px)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-sand <out.png> <baseHex> [seed] [rippleSpacing] [W H]\n");
|
|
|
|
|
|
std::printf(" Sand dunes: per-pixel grain noise + sinusoidal ripple bands (default ripple=24px)\n");
|
|
|
|
|
|
std::printf(" --gen-texture-snow <out.png> <baseHex> [seed] [sparkleDensity] [W H]\n");
|
|
|
|
|
|
std::printf(" Snow: soft cool-white base + scattered bright sparkle pixels (default density=0.005)\n");
|
2026-05-08 20:33:45 -07:00
|
|
|
|
std::printf(" --gen-texture-lava <out.png> <darkHex> <hotHex> [seed] [crackScale] [W H]\n");
|
|
|
|
|
|
std::printf(" Lava: dark cooled crust with bright glowing cracks via Worley cell boundaries\n");
|
2026-05-08 22:01:31 -07:00
|
|
|
|
std::printf(" --gen-texture-tile <out.png> <tileHex> <groutHex> [tilePx] [groutPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Square stone tiles with grout grid (default 32px tiles, 2px grout)\n");
|
2026-05-08 23:15:03 -07:00
|
|
|
|
std::printf(" --gen-texture-bark <out.png> <baseHex> <crackHex> [seed] [crackDensity] [W H]\n");
|
|
|
|
|
|
std::printf(" Tree bark: vertical wavy streaks + dark vertical cracks (default density=0.04)\n");
|
2026-05-09 00:20:14 -07:00
|
|
|
|
std::printf(" --gen-texture-clouds <out.png> <skyHex> <cloudHex> [seed] [coverage] [W H]\n");
|
|
|
|
|
|
std::printf(" Sky with puffy clouds: multi-octave noise thresholded by coverage (default 0.5)\n");
|
2026-05-09 01:32:08 -07:00
|
|
|
|
std::printf(" --gen-texture-stars <out.png> <bgHex> <starHex> [seed] [density] [W H]\n");
|
|
|
|
|
|
std::printf(" Night sky with scattered stars (varied brightness, density 0..1, default 0.005)\n");
|
2026-05-09 02:37:06 -07:00
|
|
|
|
std::printf(" --gen-texture-vines <out.png> <wallHex> <vineHex> [seed] [vineCount] [W H]\n");
|
|
|
|
|
|
std::printf(" Wall with climbing vines: meandering vertical paths via random walk (default 8 vines)\n");
|
2026-05-09 03:23:01 -07:00
|
|
|
|
std::printf(" --gen-texture-mosaic <out.png> <colorAHex> <colorBHex> <colorCHex> [tilePx] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" 3-color mosaic: small square tiles with random color picks + grout (default 16px)\n");
|
2026-05-09 04:01:49 -07:00
|
|
|
|
std::printf(" --gen-texture-rust <out.png> <metalHex> <rustHex> [seed] [coverage] [W H]\n");
|
|
|
|
|
|
std::printf(" Metal with rust patches: noise blob threshold + per-pixel grain (default coverage=0.4)\n");
|
2026-05-09 04:42:31 -07:00
|
|
|
|
std::printf(" --gen-texture-circuit <out.png> <pcbHex> <traceHex> [seed] [traceCount] [W H]\n");
|
|
|
|
|
|
std::printf(" Sci-fi PCB pattern: orthogonal traces with right-angle turns + via dots (default 24 traces)\n");
|
2026-05-09 05:11:40 -07:00
|
|
|
|
std::printf(" --gen-texture-coral <out.png> <waterHex> <coralHex> [seed] [branchCount] [W H]\n");
|
|
|
|
|
|
std::printf(" Coral reef: branching tree shapes via random angle walks (default 12 branches)\n");
|
2026-05-09 05:38:18 -07:00
|
|
|
|
std::printf(" --gen-texture-flame <out.png> <darkHex> <hotHex> [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Flame: vertical color gradient from dark base to hot top with noise flicker\n");
|
2026-05-09 06:02:13 -07:00
|
|
|
|
std::printf(" --gen-texture-tartan <out.png> <colorAHex> <colorBHex> <colorCHex> [bandPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Tartan plaid: 3-color crossing bands forming Scottish-style overlap pattern\n");
|
2026-05-09 06:29:16 -07:00
|
|
|
|
std::printf(" --gen-texture-argyle <out.png> <colorAHex> <colorBHex> <stitchHex> [cellPx] [W H]\n");
|
|
|
|
|
|
std::printf(" Argyle: 45-rotated lozenge checkerboard with diagonal stitch lines (sweater knit)\n");
|
2026-05-09 06:49:29 -07:00
|
|
|
|
std::printf(" --gen-texture-herringbone <out.png> <bgHex> <lineHex> [stripH] [lineSpacing] [lineWidth] [W H]\n");
|
|
|
|
|
|
std::printf(" Herringbone: slanted parallel lines that flip direction every strip (chevron / fish-bone)\n");
|
2026-05-09 07:06:29 -07:00
|
|
|
|
std::printf(" --gen-texture-scales <out.png> <bgHex> <scaleHex> <rimHex> [cellW] [cellH] [W H]\n");
|
|
|
|
|
|
std::printf(" Scales: half-row-staggered overlapping circles forming fish/dragon/chain-mail look\n");
|
2026-05-09 07:19:02 -07:00
|
|
|
|
std::printf(" --gen-texture-stained-glass <out.png> <leadHex> <colorAHex> <colorBHex> <colorCHex> [cells] [W H]\n");
|
|
|
|
|
|
std::printf(" Stained glass: Voronoi cells in 3-color rotation, separated by dark lead lines\n");
|
2026-05-09 07:30:50 -07:00
|
|
|
|
std::printf(" --gen-texture-shingles <out.png> <baseHex> <shadowHex> <seamHex> [shingleW] [shingleH] [shadowH] [W H]\n");
|
|
|
|
|
|
std::printf(" Roof shingles: half-offset rows of rectangular tiles with shadow band + vertical seams\n");
|
2026-05-09 07:41:17 -07:00
|
|
|
|
std::printf(" --gen-texture-frost <out.png> <bgHex> <iceHex> [seeds] [rayLen] [W H]\n");
|
|
|
|
|
|
std::printf(" Frost: scattered crystal nuclei with 6-spike rosettes that fade with distance\n");
|
2026-05-09 07:52:29 -07:00
|
|
|
|
std::printf(" --gen-texture-parquet <out.png> <woodAHex> <woodBHex> <gapHex> [cellSize] [gapW] [W H]\n");
|
|
|
|
|
|
std::printf(" Parquet: basket-weave wood floor pattern with checkered horizontal/vertical plank pairs\n");
|
2026-05-09 08:03:54 -07:00
|
|
|
|
std::printf(" --gen-texture-bubbles <out.png> <bgHex> <fillHex> <rimHex> [count] [minR] [maxR] [rimW] [W H]\n");
|
|
|
|
|
|
std::printf(" Bubbles: scattered overlapping circles with bright rims (foam, water, magic)\n");
|
2026-05-09 08:14:04 -07:00
|
|
|
|
std::printf(" --gen-texture-spider-web <out.png> <bgHex> <webHex> [spokes] [rings] [W H]\n");
|
|
|
|
|
|
std::printf(" Spider web: N radial spokes + M concentric polygonal rings centered on the image\n");
|
2026-05-09 08:24:12 -07:00
|
|
|
|
std::printf(" --gen-texture-gingham <out.png> <bgHex> <stripeHex> <crossHex> [spacing] [width] [W H]\n");
|
|
|
|
|
|
std::printf(" Gingham: 3-tone fabric — bg + perpendicular stripes + darker color where they cross\n");
|
2026-05-09 08:40:14 -07:00
|
|
|
|
std::printf(" --gen-texture-lattice <out.png> <bgHex> <lineHex> [spacing] [width] [W H]\n");
|
|
|
|
|
|
std::printf(" Lattice: ±45° diagonal grid forming diamond openings (garden trellis / mesh fence)\n");
|
2026-05-09 08:49:51 -07:00
|
|
|
|
std::printf(" --gen-texture-honeycomb <out.png> <fillHex> <borderHex> [hexSide] [W H]\n");
|
|
|
|
|
|
std::printf(" Honeycomb: hexagonal cells via Voronoi over a triangular seed lattice\n");
|
2026-05-09 09:06:56 -07:00
|
|
|
|
std::printf(" --gen-texture-cracked <out.png> <bgHex> <crackHex> [seeds] [maxLength] [W H]\n");
|
|
|
|
|
|
std::printf(" Cracked: branching random walks form fissures (mud / glass / dry earth)\n");
|
2026-05-09 09:42:10 -07:00
|
|
|
|
std::printf(" --gen-texture-runes <out.png> <bgHex> <runeHex> [gridSpacing] [W H]\n");
|
|
|
|
|
|
std::printf(" Runes: scattered angular glyphs of 3-5 strokes each (8 cardinal/diagonal angles)\n");
|
2026-05-09 09:51:58 -07:00
|
|
|
|
std::printf(" --gen-texture-leopard <out.png> <bgHex> <spotHex> [count] [radius] [W H]\n");
|
|
|
|
|
|
std::printf(" Leopard: irregular spots (4 sub-circles each) for animal-print fabric/fur\n");
|
2026-05-09 10:03:27 -07:00
|
|
|
|
std::printf(" --gen-texture-zebra <out.png> <bgHex> <stripeHex> [period] [amplitude] [wavelength] [W H]\n");
|
|
|
|
|
|
std::printf(" Zebra: wavy parallel stripes via sinusoidal y-shift (animal-print stripes)\n");
|
2026-05-09 10:18:22 -07:00
|
|
|
|
std::printf(" --gen-texture-knit <out.png> <bgHex> <stitchHex> [cellW] [cellH] [strokeW] [W H]\n");
|
|
|
|
|
|
std::printf(" Knit: V-stitch chevron-zigzag pattern reading as knitted fabric stitches\n");
|
2026-05-09 10:34:02 -07:00
|
|
|
|
std::printf(" --gen-texture-chainmail <out.png> <bgHex> <ringHex> [cellW] [cellH] [ringR] [strokeW] [W H]\n");
|
|
|
|
|
|
std::printf(" Chainmail: brick-offset ring outlines for armor/mail textures (interlocking metal rings)\n");
|
2026-05-09 10:44:13 -07:00
|
|
|
|
std::printf(" --gen-texture-planks <out.png> <bgHex> <seamHex> [plankH] [grains/plank] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Planks: horizontal floor boards with per-plank tint, grain streaks, and stagger seams\n");
|
2026-05-09 10:50:46 -07:00
|
|
|
|
std::printf(" --gen-texture-corrugated <out.png> <bgHex> <hiHex> [period] [v|h] [W H]\n");
|
|
|
|
|
|
std::printf(" Corrugated: smooth cosine ridges between bg and hi (sheet-metal roofing / siding)\n");
|
2026-05-09 11:03:33 -07:00
|
|
|
|
std::printf(" --gen-texture-rope <out.png> <bgHex> <ropeHex> [period] [strandW] [W H]\n");
|
|
|
|
|
|
std::printf(" Rope: two interleaved sinusoidal strands with cylindrical highlight (twisted cordage)\n");
|
2026-05-09 11:12:28 -07:00
|
|
|
|
std::printf(" --gen-texture-caustics <out.png> <bgHex> <hiHex> [period] [W H]\n");
|
|
|
|
|
|
std::printf(" Caustics: 4 superimposed sine waves (x/y/x+y/x-y) producing diamond-mesh water shimmer\n");
|
2026-05-09 11:20:31 -07:00
|
|
|
|
std::printf(" --gen-texture-starburst <out.png> <bgHex> <rayHex> [rays] [beamWidth] [W H]\n");
|
|
|
|
|
|
std::printf(" Starburst: N rays radiating from center with linear falloff (sun / holy symbol / mosaic hub)\n");
|
2026-05-09 11:31:27 -07:00
|
|
|
|
std::printf(" --gen-texture-studs <out.png> <bgHex> <studHex> [stride] [studR] [W H]\n");
|
|
|
|
|
|
std::printf(" Studs: rivet grid with derived inner highlight (3D rivet/stud appearance for armor + leather)\n");
|
2026-05-09 11:38:03 -07:00
|
|
|
|
std::printf(" --gen-texture-moss <out.png> <bgHex> <mossHex> [stride] [density 0-100] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Moss: irregular spots scattered on a hash-jittered grid (forest floor / weathered stone / swamp)\n");
|
2026-05-09 11:44:33 -07:00
|
|
|
|
std::printf(" --gen-texture-woodgrain <out.png> <lightHex> <darkHex> [spacing] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Woodgrain: concentric annual rings centered off-image with per-ring jitter (end-cut wood)\n");
|
2026-05-09 11:49:20 -07:00
|
|
|
|
std::printf(" --gen-texture-carbon <out.png> <bgHex> <fiberHex> [cellSize] [W H]\n");
|
|
|
|
|
|
std::printf(" Carbon-fiber: 2x2 alternating-orientation weave with sin² fiber highlights (sci-fi/tech panels)\n");
|
2026-05-09 11:56:01 -07:00
|
|
|
|
std::printf(" --gen-texture-pinstripe <out.png> <bgHex> <lineHex> [stride] [lineW] [featureEvery] [W H]\n");
|
|
|
|
|
|
std::printf(" Pinstripe: thin vertical lines at every stride; every Nth stripe is doubled-thick feature line\n");
|
2026-05-09 12:01:11 -07:00
|
|
|
|
std::printf(" --gen-texture-camo <out.png> <aHex> <bHex> [cellSize] [threshold] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Camouflage: 2-octave value noise thresholded into hard bg/fg blobs (woodland disruption pattern)\n");
|
2026-05-09 12:08:11 -07:00
|
|
|
|
std::printf(" --gen-texture-snake-skin <out.png> <bgHex> <scaleHex> [cellW] [cellH] [outlineW] [W H]\n");
|
|
|
|
|
|
std::printf(" Snake skin: brick-offset diamond scales (L1 metric) with derived dark outline (reptile / dragon hide)\n");
|
2026-05-09 12:14:10 -07:00
|
|
|
|
std::printf(" --gen-texture-mesh-screen <out.png> <bgHex> <wireHex> [stride] [wireW] [W H]\n");
|
|
|
|
|
|
std::printf(" Mesh-screen: orthogonal H+V wire grid (window screen / chain-link / sci-fi grille)\n");
|
2026-05-09 12:20:11 -07:00
|
|
|
|
std::printf(" --gen-texture-bamboo <out.png> <bgHex> <bambooHex> [stalkW] [nodeY] [nodeBand] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Bamboo: vertical stalks with sin² shading + horizontal node bands (jungle / asian-themed)\n");
|
2026-05-09 12:27:15 -07:00
|
|
|
|
std::printf(" --gen-texture-blueprint <out.png> <bgHex> <lineHex> [minorStride] [majorEvery] [minorW] [majorW] [W H]\n");
|
|
|
|
|
|
std::printf(" Blueprint: minor + major grid lines (technical drawing / drafting paper / engineer's table)\n");
|
2026-05-09 12:33:25 -07:00
|
|
|
|
std::printf(" --gen-texture-rust-streaks <out.png> <bgHex> <rustHex> [streakCount] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Rust streaks: vertical drip bands fading down from hash-jittered tops (weathered metal / hull stains)\n");
|
2026-05-09 12:39:38 -07:00
|
|
|
|
std::printf(" --gen-texture-plaid <out.png> <bgHex> <bandHex> [stride] [bandW] [W H]\n");
|
|
|
|
|
|
std::printf(" Plaid: 2 sets of crossed translucent bands; intersections darken via combined half-alpha\n");
|
2026-05-09 12:47:28 -07:00
|
|
|
|
std::printf(" --gen-texture-diamond-grid <out.png> <bgHex> <fillHex> [cellW] [cellH] [fillFrac] [W H]\n");
|
|
|
|
|
|
std::printf(" Diamond grid: axis-aligned solid diamonds in cells with bg gaps (clean tile / mosaic / floor inlay)\n");
|
2026-05-09 12:52:31 -07:00
|
|
|
|
std::printf(" --gen-texture-houndstooth <out.png> <toothHex> <bgHex> [cellSize] [W H]\n");
|
|
|
|
|
|
std::printf(" Houndstooth: classic textile broken-check pattern via seamless 8x8 motif (Scottish weave)\n");
|
2026-05-09 12:57:47 -07:00
|
|
|
|
std::printf(" --gen-texture-chevron <out.png> <bgHex> <lineHex> [period] [stride] [lineW] [W H]\n");
|
|
|
|
|
|
std::printf(" Chevron: stack of V-shape stripes with sharp seams (military / sportswear / heraldic banners)\n");
|
2026-05-09 13:03:00 -07:00
|
|
|
|
std::printf(" --gen-texture-dunes <out.png> <bgHex> <lineHex> [verticalSpacing] [period] [amp] [lineW] [W H]\n");
|
|
|
|
|
|
std::printf(" Dunes: stack of parallel sinusoidal curves (desert ground / shallow-water sand / wave ripples)\n");
|
2026-05-09 13:08:07 -07:00
|
|
|
|
std::printf(" --gen-texture-swirl <out.png> <bgHex> <armHex> [armCount] [spiralFactor] [armWidth] [W H]\n");
|
|
|
|
|
|
std::printf(" Swirl: N-arm logarithmic spiral (magic sigils / summoning circles / ritual floor markings)\n");
|
2026-05-09 13:14:18 -07:00
|
|
|
|
std::printf(" --gen-texture-ironbark <out.png> <baseHex> <crackHex> [streakSpacing] [plateY] [crackW] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Ironbark: vertical wood streaks + horizontal plate bands (mature hardwood / sycamore / ironwood)\n");
|
2026-05-09 13:19:30 -07:00
|
|
|
|
std::printf(" --gen-texture-mold <out.png> <bgHex> <moldHex> [stride] [thresholdFrac] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Mold: Worley-noise field patches (cellars / dungeon walls / sewer overflow / fungal growth)\n");
|
2026-05-09 13:25:41 -07:00
|
|
|
|
std::printf(" --gen-texture-embroidery <out.png> <bgHex> <threadHex> [cellSize] [strokeW] [W H]\n");
|
|
|
|
|
|
std::printf(" Embroidery: grid of cross-stitch X marks (counted-thread textile / sampler / folk-art trim)\n");
|
2026-05-09 13:30:57 -07:00
|
|
|
|
std::printf(" --gen-texture-lightbeam <out.png> <bgHex> <beamHex> [beamHalfW] [vFadeFrac] [u|d] [W H]\n");
|
|
|
|
|
|
std::printf(" Lightbeam: vertical sun-ray gradient fading horizontally + vertically (sunbeam / holy radiance)\n");
|
feat(editor): add --gen-texture-dewdrops scattered-droplets
75th procedural texture: N small water droplets at hash-
derived (cx, cy, R) positions blended onto bg via radial
brightness — bright at the drop center fading to bg at its
edge. Where drops overlap they accumulate brighter
(max-of-individual-contributions, not additive — so the
result stays inside the [bg, drop] color range).
Each drop gets a hash-derived radius in the [maxR/4, maxR]
range so the surface has a natural mix of small and large
droplets. Two-pass (compute brightness map, then write
pixels) so overlap accumulation works correctly.
Useful for morning-grass blades, wet-glass overlays, leaf
surfaces after rain, magic-pool fizz, snake-fountain
splash zones, dragon-breath-aftermath ground.
2026-05-09 13:36:39 -07:00
|
|
|
|
std::printf(" --gen-texture-dewdrops <out.png> <bgHex> <dropHex> [dropCount] [maxR] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Dewdrops: scattered translucent water drops with radial brightness (grass / glass / leaf surfaces)\n");
|
2026-05-09 13:41:40 -07:00
|
|
|
|
std::printf(" --gen-texture-pinwheel <out.png> <aHex> <bHex> [sectors] [W H]\n");
|
|
|
|
|
|
std::printf(" Pinwheel: alternating colored triangular wedges radiating from center (mandala / wind-rose / wheel inlay)\n");
|
2026-05-09 13:46:11 -07:00
|
|
|
|
std::printf(" --gen-texture-scratched-metal <out.png> <baseHex> <scratchHex> [scratchCount] [maxLen] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Scratched metal: base color overlaid with N angled hash-derived line segments (worn armor / blades)\n");
|
2026-05-09 13:56:41 -07:00
|
|
|
|
std::printf(" --gen-texture-crackle <out.png> <baseHex> <crackHex> [stride] [crackW] [seed] [W H]\n");
|
|
|
|
|
|
std::printf(" Crackle: fine Voronoi cell-boundary cracks (dried mud / parched earth / aged leather)\n");
|
2026-05-09 14:03:07 -07:00
|
|
|
|
std::printf(" --gen-texture-star <out.png> <bgHex> <starHex> [points] [innerFrac] [W H]\n");
|
|
|
|
|
|
std::printf(" Star: solid N-pointed star polygon centered (medallions / shields / religious symbols)\n");
|
2026-05-09 14:12:04 -07:00
|
|
|
|
std::printf(" --gen-texture-halftone <out.png> <bgHex> <dotHex> [stride] [maxR] [v|h|r] [W H]\n");
|
|
|
|
|
|
std::printf(" Halftone: grid of dots whose radii grow with a v/h/r gradient (comic / newspaper print look)\n");
|
2026-05-09 14:20:02 -07:00
|
|
|
|
std::printf(" --gen-texture-bayer <out.png> <aHex> <bHex> [cellSize] [W H]\n");
|
|
|
|
|
|
std::printf(" Bayer: 4x4 ordered-dither matrix tiled (retro / 8-bit / monochrome-CRT effects)\n");
|
2026-05-09 14:26:57 -07:00
|
|
|
|
std::printf(" --gen-texture-moon <out.png> <bgHex> <moonHex> [moonR] [phase] [W H]\n");
|
|
|
|
|
|
std::printf(" Moon disc with optional crescent shadow (phase 0=full, =moonR=half, >moonR=crescent)\n");
|
2026-05-09 14:42:23 -07:00
|
|
|
|
std::printf(" --gen-texture-damask <out.png> <bgHex> <fgHex> [cell] [W H]\n");
|
|
|
|
|
|
std::printf(" Damask: 4-petal floral motif tiled per cell (palace wallpaper / noble-faction tapestry)\n");
|
feat(editor): add --gen-texture-snowflake 6-fold ice crystal
84th procedural texture: 6-fold symmetric snowflake stamp
tiled per cell. Built by computing polar (r, theta) from
the cell center and folding theta into a [0, pi/6] wedge,
so a single arm-shape definition replicates 12 times via
mirror + 60-degree rotation.
Each arm is a thin sliver (sin-based perpendicular distance
test) thickened at two perpendicular knobs at r = 0.40 and
0.70 of the cell-half radius — the knobs provide the
classic "branched ice crystal" silhouette without needing
a separate per-arm subdivision pass.
A small filled center dot anchors the motif at small cell
sizes where the knobs vanish.
Useful for: arctic / winter zones, frost spell effects,
frost-mage themed gear icons, holiday-event decoration,
crystal-shrine backdrops, snowstorm overlays.
Distinct from --gen-texture-snow (random tiny dots, not a
patterned crystal) and --gen-texture-frost (spider-web
crackle, not radial). The first 6-fold-symmetric texture in
the catalogue.
2026-05-09 15:06:32 -07:00
|
|
|
|
std::printf(" --gen-texture-snowflake <out.png> <bgHex> <fgHex> [cell] [W H]\n");
|
|
|
|
|
|
std::printf(" Snowflake: 6-fold symmetric ice crystal stamped per cell (winter zones / frost spell effects)\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" --add-texture-to-zone <zoneDir> <png-path> [renameTo]\n");
|
|
|
|
|
|
std::printf(" Copy an existing PNG into <zoneDir> (optionally renaming it on the way in)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh <wom-base> <cube|plane|sphere|cylinder|torus|cone|ramp> [size]\n");
|
|
|
|
|
|
std::printf(" Synthesize a procedural WOM primitive with proper normals, UVs, and bounds\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-textured <wom-base> <cube|plane|sphere|cylinder|torus|cone|ramp> <colorHex|pattern> [size]\n");
|
|
|
|
|
|
std::printf(" Compose a procedural mesh + matching PNG texture wired into the WOM's batch\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-stairs <wom-base> <steps> [stepHeight] [stepDepth] [width]\n");
|
|
|
|
|
|
std::printf(" Procedural straight staircase along +X with N steps (default 5 / 0.2 / 0.3 / 1.0)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-grid <wom-base> <subdivisions> [size]\n");
|
|
|
|
|
|
std::printf(" Subdivided flat plane on XY (NxN cells, 2N² triangles); useful for LOD demos\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-disc <wom-base> [radius] [segments]\n");
|
|
|
|
|
|
std::printf(" Flat circular disc on XY centered at origin (default radius 1.0, 32 segments)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-tube <wom-base> [outerRadius] [innerRadius] [height] [segments]\n");
|
|
|
|
|
|
std::printf(" Hollow cylinder/pipe along Y axis (default 1.0/0.7/2.0, 24 segments)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-capsule <wom-base> [radius] [cylHeight] [segments] [stacks]\n");
|
|
|
|
|
|
std::printf(" Capsule along Y axis: cylinder body with hemispherical caps (default 0.5/1.0/16/8)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-arch <wom-base> [openingWidth] [openingHeight] [thickness] [depth] [segments]\n");
|
|
|
|
|
|
std::printf(" Doorway arch: two columns + semicircular top (default 1.0/1.5/0.2/0.3, 12 segs)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-pyramid <wom-base> [sides] [baseRadius] [height]\n");
|
|
|
|
|
|
std::printf(" N-sided polygonal pyramid with apex at +Y (default 4 sides, 1.0/1.0)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-fence <wom-base> [posts] [postSpacing] [postHeight] [railThick]\n");
|
|
|
|
|
|
std::printf(" Repeating fence: N posts along +X with two horizontal rails between\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-tree <wom-base> [trunkRadius] [trunkHeight] [foliageRadius]\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-rock <wom-base> [radius] [roughness] [subdiv] [seed]\n");
|
|
|
|
|
|
std::printf(" Procedural boulder via subdivided octahedron + smooth noise displacement\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-pillar <wom-base> [radius] [height] [flutes] [capScale]\n");
|
|
|
|
|
|
std::printf(" Fluted classical column with concave flutes + flared cap/base (default 12 flutes)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-bridge <wom-base> [length] [width] [planks] [railHeight]\n");
|
|
|
|
|
|
std::printf(" Plank bridge with two side rails (default 6 planks across, rails on)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-tower <wom-base> [radius] [height] [battlements] [battlementH]\n");
|
|
|
|
|
|
std::printf(" Round castle tower with crenellated battlements (default 8 teeth, 0.5m tall)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-house <wom-base> [width] [depth] [height] [roofHeight]\n");
|
|
|
|
|
|
std::printf(" Simple house: cube body + pyramid roof (default 4×4×3 with 2m roof)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-fountain <wom-base> [basinRadius] [basinHeight] [spoutRadius] [spoutHeight]\n");
|
|
|
|
|
|
std::printf(" Round basin + center spout column (default 1.5/0.5 basin, 0.2/1.5 spout)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-statue <wom-base> [pedestalSize] [bodyHeight] [headRadius]\n");
|
|
|
|
|
|
std::printf(" Humanoid placeholder: pedestal block + tall body cylinder + head sphere\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-altar <wom-base> [topRadius] [topHeight] [steps] [stepStride]\n");
|
|
|
|
|
|
std::printf(" Round altar: stacked stepped discs descending from a flat top (default 3 steps)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-portal <wom-base> [width] [height] [postThickness] [lintelHeight]\n");
|
|
|
|
|
|
std::printf(" Doorway frame: two side posts + top lintel (default 2.5w × 4h)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-archway <wom-base> [width] [pillarHeight] [thickness] [archSegs]\n");
|
|
|
|
|
|
std::printf(" Semicircular arched doorway: two pillars + curved keystone vault (default 12 segs)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-barrel <wom-base> [topRadius] [midRadius] [height] [hoopThickness]\n");
|
|
|
|
|
|
std::printf(" Tapered barrel: bulges in middle + 2 rim hoops (default 0.4/0.5/1.0/0.06)\n");
|
2026-05-08 21:19:51 -07:00
|
|
|
|
std::printf(" --gen-mesh-chest <wom-base> [width] [depth] [bodyHeight] [lidHeight]\n");
|
|
|
|
|
|
std::printf(" Treasure chest: body box + lid box + 3 iron bands + lock plate (default 1.4×0.9×0.9)\n");
|
2026-05-08 22:37:47 -07:00
|
|
|
|
std::printf(" --gen-mesh-anvil <wom-base> [length] [width] [hornLength] [bodyHeight]\n");
|
|
|
|
|
|
std::printf(" Blacksmith anvil: stepped pedestal + flat work surface + horn taper (default 1.0×0.4×0.5×0.5)\n");
|
2026-05-08 23:48:03 -07:00
|
|
|
|
std::printf(" --gen-mesh-mushroom <wom-base> [stalkRadius] [stalkHeight] [capRadius]\n");
|
|
|
|
|
|
std::printf(" Mushroom: cylindrical stalk + hemispherical cap (default 0.1/0.6/0.4)\n");
|
2026-05-09 00:52:13 -07:00
|
|
|
|
std::printf(" --gen-mesh-cart <wom-base> [bedLength] [bedWidth] [bedHeight] [wheelRadius]\n");
|
|
|
|
|
|
std::printf(" Wooden cart: rectangular bed + 2 cylindrical wheels (default 1.6/0.8/0.5/0.35)\n");
|
2026-05-09 02:10:23 -07:00
|
|
|
|
std::printf(" --gen-mesh-banner <wom-base> [poleHeight] [poleRadius] [flagWidth] [flagHeight]\n");
|
|
|
|
|
|
std::printf(" Banner: vertical pole + rectangular hanging flag (default 3.0/0.05/0.8/1.2)\n");
|
2026-05-09 03:00:19 -07:00
|
|
|
|
std::printf(" --gen-mesh-grave <wom-base> [tabletWidth] [tabletHeight] [tabletThickness] [baseWidth]\n");
|
|
|
|
|
|
std::printf(" Tombstone: low rectangular base + vertical tablet (default 0.6/1.0/0.15/0.8)\n");
|
2026-05-09 03:43:11 -07:00
|
|
|
|
std::printf(" --gen-mesh-bench <wom-base> [length] [seatHeight] [seatThickness] [seatWidth]\n");
|
|
|
|
|
|
std::printf(" Wooden bench: seat plank + 2 leg slabs (default 1.5/0.5/0.06/0.4)\n");
|
2026-05-09 04:25:52 -07:00
|
|
|
|
std::printf(" --gen-mesh-shrine <wom-base> [size] [pillarHeight] [pillarRadius] [roofThickness]\n");
|
|
|
|
|
|
std::printf(" Small canopy: square base + 4 corner pillars + flat roof slab (default 1.5/2/0.1/0.15)\n");
|
feat(editor): add --gen-mesh-totem stacked carved totem primitive
Stack of N square blocks with alternating widths: even-indexed
blocks (0, 2, 4...) get full base width, odd blocks (1, 3, 5...)
get 70% — gives the carved-segment look characteristic of
totem poles.
Defaults: baseW=0.5, 5 segments, segH=0.5. Useful for tribal
zones, druid groves, fairgrounds, primitive village markers.
Brings the procedural mesh primitive set to 35.
2026-05-09 04:57:33 -07:00
|
|
|
|
std::printf(" --gen-mesh-totem <wom-base> [width] [segments] [segmentHeight]\n");
|
|
|
|
|
|
std::printf(" Tribal totem: stack of N alternating-width carved blocks (default w=0.5, 5 segs, h=0.5)\n");
|
2026-05-09 05:25:39 -07:00
|
|
|
|
std::printf(" --gen-mesh-cage <wom-base> [width] [height] [barsPerSide] [barRadius]\n");
|
|
|
|
|
|
std::printf(" Cage: top/bottom frames + 4 corner posts + N bars per side (default 1.5×2.0, 5 bars)\n");
|
2026-05-09 05:50:23 -07:00
|
|
|
|
std::printf(" --gen-mesh-throne <wom-base> [seatWidth] [seatHeight] [backHeight] [pedestalSize]\n");
|
|
|
|
|
|
std::printf(" Throne: pedestal + seat + backrest + 2 armrests (default 0.8/0.5/1.5/1.2)\n");
|
2026-05-09 06:18:42 -07:00
|
|
|
|
std::printf(" --gen-mesh-coffin <wom-base> [length] [width] [height]\n");
|
|
|
|
|
|
std::printf(" Hexagonal coffin: narrow head + wide shoulder + tapered foot prism (default 2.0/0.8/0.6)\n");
|
2026-05-09 06:39:39 -07:00
|
|
|
|
std::printf(" --gen-mesh-bookshelf <wom-base> [width] [height] [depth] [shelves]\n");
|
|
|
|
|
|
std::printf(" Bookshelf: 5-panel cabinet with N-1 shelves and rows of varied book boxes (default 1.5/2.0/0.4/4)\n");
|
2026-05-09 10:25:38 -07:00
|
|
|
|
std::printf(" --gen-mesh-tent <wom-base> [length] [width] [height] [doorH] [doorW]\n");
|
|
|
|
|
|
std::printf(" Tent: A-frame canvas tent — ridge along X, two sloped roof panels, two gables, door notch on +X (default 1.6/1.0/0.9/0.5/0.4)\n");
|
2026-05-09 10:37:37 -07:00
|
|
|
|
std::printf(" --gen-mesh-firepit <wom-base> [ringR] [stones] [stoneSize] [logLen] [logThick]\n");
|
|
|
|
|
|
std::printf(" Firepit: ring of N stone cubes around 2 crossed log boxes (default 0.5/8/0.10/0.45/0.05)\n");
|
2026-05-09 10:47:21 -07:00
|
|
|
|
std::printf(" --gen-mesh-woodpile <wom-base> [logR] [logLen] [sides]\n");
|
|
|
|
|
|
std::printf(" Woodpile: 6 cylindrical logs in a 3-2-1 pyramid stack along Z axis (default 0.10/0.80/12)\n");
|
2026-05-09 10:59:05 -07:00
|
|
|
|
std::printf(" --gen-mesh-canopy <wom-base> [width] [depth] [height] [postR] [panelT] [drape]\n");
|
|
|
|
|
|
std::printf(" Canopy: 4-post awning with flat top panel and optional drape lips (default 1.6/1.2/2.0/0.05/0.03/0.15)\n");
|
2026-05-09 11:08:39 -07:00
|
|
|
|
std::printf(" --gen-mesh-haystack <wom-base> [baseR] [height] [layers] [sides]\n");
|
|
|
|
|
|
std::printf(" Haystack: terraced stack of N frustums tapering to an apex point (default 0.6/0.9/3/12)\n");
|
2026-05-09 11:17:28 -07:00
|
|
|
|
std::printf(" --gen-mesh-dock <wom-base> [length] [width] [height] [pilings/side] [pilingW] [deckT]\n");
|
|
|
|
|
|
std::printf(" Dock: flat plank deck on N pairs of square pilings (default 3.0/1.0/0.6/3/0.10/0.10)\n");
|
2026-05-09 11:26:15 -07:00
|
|
|
|
std::printf(" --gen-mesh-pergola <wom-base> [length] [width] [height] [postR] [beamT] [crossbeams]\n");
|
|
|
|
|
|
std::printf(" Pergola: 4 corner posts + 2 perimeter beams + N cross beams (open lattice top, no panel)\n");
|
2026-05-09 11:34:24 -07:00
|
|
|
|
std::printf(" --gen-mesh-chimney <wom-base> [width] [depth] [height] [capH] [capExtra]\n");
|
|
|
|
|
|
std::printf(" Chimney: rectangular brick shaft topped by a slightly wider rain-cap (default 0.45/0.45/1.8/0.10/0.05)\n");
|
2026-05-09 11:39:33 -07:00
|
|
|
|
std::printf(" --gen-mesh-bedroll <wom-base> [length] [radius] [sides] [pillowSize]\n");
|
|
|
|
|
|
std::printf(" Bedroll: horizontal closed cylinder along Z axis with optional pillow box at +Z (camp set dressing)\n");
|
2026-05-09 11:46:05 -07:00
|
|
|
|
std::printf(" --gen-mesh-workbench <wom-base> [length] [depth] [height] [legR] [topT] [viseSize] [trayH]\n");
|
|
|
|
|
|
std::printf(" Workbench: 4-legged top slab with optional vise at +X end and back tool tray (blacksmith / crafter)\n");
|
2026-05-09 11:52:20 -07:00
|
|
|
|
std::printf(" --gen-mesh-crate-stack <wom-base> [crateSize] [columns] [rows] [layers] [gap]\n");
|
|
|
|
|
|
std::printf(" Crate stack: N×M×K cube grid with small gap between crates (warehouses, cargo holds, dockyards)\n");
|
2026-05-09 11:57:38 -07:00
|
|
|
|
std::printf(" --gen-mesh-watchpost <wom-base> [postH] [postW] [platformSize] [platformT] [railingH] [railingW]\n");
|
|
|
|
|
|
std::printf(" Watchpost: tall pole + square platform + 4 corner railing posts (sentry / scout outpost)\n");
|
2026-05-09 12:02:35 -07:00
|
|
|
|
std::printf(" --gen-mesh-water-trough <wom-base> [length] [width] [height] [wallT]\n");
|
|
|
|
|
|
std::printf(" Water trough: 4-walled rectangular basin with flat floor (stable / farm / tavern set dressing)\n");
|
2026-05-09 12:09:36 -07:00
|
|
|
|
std::printf(" --gen-mesh-training-dummy <wom-base> [baseH] [postW] [torsoSize] [armSpan] [armT] [headSize]\n");
|
|
|
|
|
|
std::printf(" Training dummy: post + cubic torso + cross-bar arms + optional head (sparring / drill yard)\n");
|
feat(editor): add --gen-mesh-hitching-post stable fixture
67th procedural mesh primitive. Standard town/stable
hitching post:
• two vertical posts separated by `span`
• horizontal cross-bar at upper-post height (length =
span - postW so it tucks INSIDE the post inner faces,
matching real fence joinery)
• optional decorative caps on each post — set capH=0
for a bare working-yard post
All axis-aligned boxes, exercises every shared helper
(stripExt, initWomDefaults, addFlatBox,
finalizeAsSingleBatch, saveWomOrError). Watertight under
weld (verified 90 manifold edges, 0 boundary, 0
non-manifold).
Useful for stables, taverns with mount parking, town
squares, frontier outposts, ranger camps, post-and-rail
fence segments.
2026-05-09 12:15:41 -07:00
|
|
|
|
std::printf(" --gen-mesh-hitching-post <wom-base> [span] [height] [postW] [barT] [capH]\n");
|
|
|
|
|
|
std::printf(" Hitching post: 2 vertical posts + horizontal cross-bar + optional decorative caps (stable / town square)\n");
|
2026-05-09 12:24:00 -07:00
|
|
|
|
std::printf(" --gen-mesh-outhouse <wom-base> [width] [depth] [height] [doorH] [doorW] [roofOverhang] [roofT]\n");
|
|
|
|
|
|
std::printf(" Outhouse: solid body + inset door slab on +Z + overhanging roof slab (privy / tool shed)\n");
|
2026-05-09 12:29:09 -07:00
|
|
|
|
std::printf(" --gen-mesh-forge <wom-base> [width] [depth] [baseH] [hoodH] [hoodInset] [chimneyH] [chimneyW]\n");
|
|
|
|
|
|
std::printf(" Blacksmith forge: stone hearth + smaller hood + optional chimney (smithy / armorer set dressing)\n");
|
2026-05-09 12:35:15 -07:00
|
|
|
|
std::printf(" --gen-mesh-archery-target <wom-base> [faceR] [faceT] [sides] [postH] [postW] [beamT]\n");
|
|
|
|
|
|
std::printf(" Archery target: round face cylinder on a 2-post stand with cross-beam (training yard / fair scene)\n");
|
feat(editor): add --gen-mesh-gravel-pile rubble heap
71st procedural mesh primitive. Hash-distributed pile of
stone cubes in a roughly conical heap. Each stone gets:
• polar position (radial, theta) with sqrt(rand) on radial
so stones aren't bunched at center
• height limited by yMax = pileH * (1 - radial/baseR), so
larger / more numerous stones land near the base and
smaller ones perch on top — natural gravel-pile profile
• size in the 40-100% range of maxStoneSize
The second multi-box "scene" composite primitive (after
--gen-mesh-crate-stack), but using irregular hashed
placement instead of a regular N×M×K grid. Deterministic
from seed: re-running with same args reproduces the
identical pile.
Useful for mine entrances, construction sites, quarries,
ruined walls, abandoned-fort rubble, pirate-cove stash
mounds. Default 24 stones at 0.6 m base radius gives a
reasonable medium-pile.
Uses every shared helper introduced this batch (printWomWrote,
printWomMeshStats, setCenteredBoundsXZ, addFlatBox,
saveWomOrError, parseOpt*, stripExt).
2026-05-09 12:43:03 -07:00
|
|
|
|
std::printf(" --gen-mesh-gravel-pile <wom-base> [stoneCount] [baseR] [pileH] [maxStoneSize] [seed]\n");
|
|
|
|
|
|
std::printf(" Gravel pile: hash-distributed stone cubes in a conical heap (mining / construction / rubble)\n");
|
2026-05-09 12:48:55 -07:00
|
|
|
|
std::printf(" --gen-mesh-stone-bench <wom-base> [length] [depth] [seatH] [seatT] [supportW] [supportInset]\n");
|
|
|
|
|
|
std::printf(" Stone bench: long seat slab on 2 block supports near the ends (park / temple / ruined city)\n");
|
2026-05-09 12:54:17 -07:00
|
|
|
|
std::printf(" --gen-mesh-mine-cart <wom-base> [length] [width] [bodyH] [wallT] [wheelR] [wheelInset]\n");
|
|
|
|
|
|
std::printf(" Mine cart: open-top bin (5-piece basin) on 4 wheel boxes (mines / dwarven forges / junk yards)\n");
|
2026-05-09 12:59:16 -07:00
|
|
|
|
std::printf(" --gen-mesh-hitching-rail <wom-base> [length] [height] [posts] [postW] [barT]\n");
|
|
|
|
|
|
std::printf(" Hitching rail: long horizontal bar on N evenly-spaced posts (taverns / stockyards / market days)\n");
|
2026-05-09 13:04:55 -07:00
|
|
|
|
std::printf(" --gen-mesh-pillar-row <wom-base> [count] [span] [height] [pillarW] [capH] [capExtra]\n");
|
|
|
|
|
|
std::printf(" Pillar row: N evenly-spaced rectangular pillars with optional square caps (colonnade / temple ruin)\n");
|
2026-05-09 13:11:08 -07:00
|
|
|
|
std::printf(" --gen-mesh-statue-base <wom-base> [bodyW] [bodyH] [plinthExtra] [plinthH] [capitalExtra] [capitalH]\n");
|
|
|
|
|
|
std::printf(" Statue base: 3-tier pedestal (plinth + body + capital) for monuments / hero memorials\n");
|
2026-05-09 13:16:06 -07:00
|
|
|
|
std::printf(" --gen-mesh-bird-bath <wom-base> [stemR] [stemH] [basinR] [basinH] [sides]\n");
|
|
|
|
|
|
std::printf(" Bird bath: thin cylindrical stem topped by a wide shallow basin disc (small garden water feature)\n");
|
2026-05-09 13:21:03 -07:00
|
|
|
|
std::printf(" --gen-mesh-planter-box <wom-base> [length] [width] [height] [wallT] [soilTopFrac]\n");
|
|
|
|
|
|
std::printf(" Planter box: long open-top wood basin + visible soil-fill block (window sills / kitchen / balcony)\n");
|
feat(editor): add --gen-mesh-urn 4-tier pottery vessel
79th procedural mesh primitive. Vertical urn built from 4
stacked tiers using the new addClosedCylinderY helper:
• foot — wide short cylinder (the ground-meeting base)
• body — tall main cylinder (the storage volume)
• neck — narrow constriction
• lip — slightly wider rim cap
Each tier is an independent watertight Y-axis cylinder with
its own ±Y end caps; they're stacked vertically with each
sitting on the previous tier's top.
Useful for temple offerings, mausoleum interiors, kitchen
storage, alchemist labs, funerary scenes, witch-hut detail.
First handler to consume the new addClosedCylinderY helper —
demonstrates the pattern for future cylindrical primitives
(candle, lantern, scroll case, well-pail, etc.).
Watertight under weld (verified 432 manifold edges, 0
boundary, 0 non-manifold).
2026-05-09 13:27:06 -07:00
|
|
|
|
std::printf(" --gen-mesh-urn <wom-base> [bodyR] [bodyH] [footR] [footH] [neckR] [neckH] [lipR] [lipH] [sides]\n");
|
|
|
|
|
|
std::printf(" Urn: 4-tier vertical pottery vessel (foot + body + neck + lip) — temple / mausoleum / kitchen storage\n");
|
2026-05-09 13:32:43 -07:00
|
|
|
|
std::printf(" --gen-mesh-candle <wom-base> [waxR] [waxH] [saucerR] [saucerH] [sides]\n");
|
|
|
|
|
|
std::printf(" Candle: thin wax pillar on optional saucer base (set saucerR=0 to skip) — chapels / vigil scenes\n");
|
2026-05-09 13:38:06 -07:00
|
|
|
|
std::printf(" --gen-mesh-lantern <wom-base> [baseR] [baseH] [globeR] [globeH] [neckR] [neckH] [capR] [capH] [sides]\n");
|
|
|
|
|
|
std::printf(" Lantern: 4-tier base + glass-globe + neck + cap stack (hand lantern / oil lamp silhouette)\n");
|
2026-05-09 13:42:58 -07:00
|
|
|
|
std::printf(" --gen-mesh-chalice <wom-base> [footR] [footH] [stemR] [stemH] [bowlR] [bowlH] [sides]\n");
|
|
|
|
|
|
std::printf(" Chalice: ceremonial 3-tier foot + stem + bowl goblet (chapel / treasure / ritual scene)\n");
|
2026-05-09 13:47:37 -07:00
|
|
|
|
std::printf(" --gen-mesh-standing-torch <wom-base> [postR] [postH] [bowlR] [bowlH] [sides]\n");
|
|
|
|
|
|
std::printf(" Standing torch: tall thin post + wider fire-bowl on top (hall lining / dungeon entry / ceremony path)\n");
|
2026-05-09 13:58:22 -07:00
|
|
|
|
std::printf(" --gen-mesh-scroll-case <wom-base> [bodyR] [bodyH] [capR] [capH] [sides]\n");
|
|
|
|
|
|
std::printf(" Scroll case: thin tall cylinder + optional wider cap (set capR=0 to skip) — libraries / mage scenes\n");
|
2026-05-09 14:15:14 -07:00
|
|
|
|
std::printf(" --gen-mesh-stove <wom-base> [bodyR] [bodyH] [chimneyR] [chimneyH] [sides]\n");
|
|
|
|
|
|
std::printf(" Pot-bellied stove: round cylindrical body + thin chimney column on top (cottage / workshop heating)\n");
|
2026-05-09 14:23:23 -07:00
|
|
|
|
std::printf(" --gen-mesh-well-pail <wom-base> [bodyR] [bodyH] [handleW] [handleT] [handleArc] [sides]\n");
|
|
|
|
|
|
std::printf(" Wooden well-pail: closed cylindrical body + thin horizontal handle bar above (water-haul / mop-bucket prop)\n");
|
2026-05-09 14:30:18 -07:00
|
|
|
|
std::printf(" --gen-mesh-mug <wom-base> [bodyR] [bodyH] [handleW] [handleH] [handleArm] [sides]\n");
|
|
|
|
|
|
std::printf(" Drinking mug / tankard: closed cylinder body + side handle slab (tavern / banquet / inn dressing)\n");
|
2026-05-09 14:43:21 -07:00
|
|
|
|
std::printf(" --gen-mesh-mortar-pestle <wom-base> [bowlR] [bowlH] [pestleR] [pestleH] [sides]\n");
|
|
|
|
|
|
std::printf(" Mortar + pestle: wide squat cylinder (bowl) + thin tall cylinder rising from inside (alchemy / kitchen)\n");
|
2026-05-09 16:21:35 -07:00
|
|
|
|
std::printf(" --gen-mesh-rune-stone <wom-base> [baseW] [baseD] [baseH] [stoneW] [stoneD] [stoneH]\n");
|
|
|
|
|
|
std::printf(" Rune stone: wide flat base block + tall narrow monolith (druid grove / witch shrine / ancient ruins)\n");
|
2026-05-09 12:22:37 -07:00
|
|
|
|
std::printf(" --gen-camp-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit tent + firepit + bedroll + canopy + woodpile + haystack into outDir as 6 .wom files\n");
|
2026-05-09 12:31:34 -07:00
|
|
|
|
std::printf(" --gen-blacksmith-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit forge + anvil + workbench + water-trough + crate-stack + hitching-post into outDir\n");
|
2026-05-09 12:45:25 -07:00
|
|
|
|
std::printf(" --gen-village-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit house + outhouse + chimney + hitching-post + well + signpost + haystack into outDir\n");
|
2026-05-09 12:51:10 -07:00
|
|
|
|
std::printf(" --gen-temple-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit altar + shrine + brazier + pillar + statue + portal + podium into outDir\n");
|
2026-05-09 12:55:50 -07:00
|
|
|
|
std::printf(" --gen-graveyard-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit grave + tombstone + coffin + statue + stone-bench + gravel-pile + cage into outDir\n");
|
2026-05-09 13:01:21 -07:00
|
|
|
|
std::printf(" --gen-garden-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit pergola + fountain + stone-bench + shrine + beehive + scarecrow + well into outDir\n");
|
2026-05-09 13:06:37 -07:00
|
|
|
|
std::printf(" --gen-dock-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit dock + crate-stack + barrel + canopy + bench + signpost + hitching-post into outDir\n");
|
2026-05-09 13:17:49 -07:00
|
|
|
|
std::printf(" --gen-tavern-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit house + chimney + table + bench + barrel + bookshelf + signpost into outDir\n");
|
2026-05-09 13:40:18 -07:00
|
|
|
|
std::printf(" --gen-mining-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit gravel-pile + crate-stack + mine-cart + pillar-row + lantern + workbench + hitching-post\n");
|
2026-05-09 13:44:48 -07:00
|
|
|
|
std::printf(" --gen-arena-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit training-dummy + archery-target + workbench + crate-stack + bench + water-trough + hitching-rail\n");
|
feat(editor): add --gen-kitchen-pack composite (11th themed pack)
Tavern back-of-house / cookhouse scene composite. Pairs
naturally with --gen-tavern-pack (front-of-house common
room) for a complete inn setup.
Emits 7 .wom files into outDir:
• stove — pot-bellied cookfire stove
• cauldron — large hanging pot
• prep-table — flat work surface
• stool — cook's seat
• barrel — water / ale / flour storage
• mug — drink ready for the inn customer
• mortar — herb / spice grinding tool
This is the 11th themed pack (camp, blacksmith, village,
temple, graveyard, garden, dock, tavern, mining, arena,
kitchen). Notable for being the first pack that uses the
two recently-added drinking-vessel + alchemy primitives
(mug from batch 111, mortar-pestle from batch 113), proving
out the "build small primitives, then compose into themed
packs" workflow.
All 7 emitted primitives pass --validate-wom on first
generation. 468 kArgRequired entries total.
2026-05-09 14:53:01 -07:00
|
|
|
|
std::printf(" --gen-kitchen-pack <outDir>\n");
|
|
|
|
|
|
std::printf(" Convenience: emit stove + cauldron + prep-table + stool + barrel + mug + mortar (tavern back-of-house)\n");
|
2026-05-09 06:58:38 -07:00
|
|
|
|
std::printf(" --gen-mesh-table <wom-base> [width] [depth] [height] [legThick] [topThick]\n");
|
|
|
|
|
|
std::printf(" Table: flat top slab on 4 corner legs (default 1.6/1.0/0.85/0.10/0.06)\n");
|
2026-05-09 07:12:46 -07:00
|
|
|
|
std::printf(" --gen-mesh-lamppost <wom-base> [poleH] [poleT] [baseSize] [lanternSize] [lanternH]\n");
|
|
|
|
|
|
std::printf(" Lamppost: square base + tall pole + lantern body + cap (default 3.0/0.12/0.4/0.35/0.5)\n");
|
2026-05-09 07:25:11 -07:00
|
|
|
|
std::printf(" --gen-mesh-bed <wom-base> [length] [width] [legH] [matThick] [headH] [footH]\n");
|
|
|
|
|
|
std::printf(" Bed: 4 legs + mattress + headboard + footboard + pillow (default 2.0/1.2/0.30/0.20/1.0/0.4)\n");
|
2026-05-09 07:36:02 -07:00
|
|
|
|
std::printf(" --gen-mesh-ladder <wom-base> [height] [width] [rungs] [railThick] [rungThick]\n");
|
|
|
|
|
|
std::printf(" Ladder: 2 vertical rails + N evenly-spaced horizontal rungs (default 3.0/0.6/8/0.06/0.04)\n");
|
2026-05-09 07:47:15 -07:00
|
|
|
|
std::printf(" --gen-mesh-well <wom-base> [outerSize] [wallH] [wallT] [postH] [postT]\n");
|
|
|
|
|
|
std::printf(" Well: 4 stone walls in a hollow square + 2 roof posts + cross beam (default 1.4/0.8/0.15/1.6/0.12)\n");
|
2026-05-09 07:58:45 -07:00
|
|
|
|
std::printf(" --gen-mesh-signpost <wom-base> [poleH] [poleT] [baseSize] [signWidth] [signHeight]\n");
|
|
|
|
|
|
std::printf(" Signpost: base + pole + sign board + cap (default 2.5/0.10/0.30/0.80/0.35)\n");
|
2026-05-09 08:08:37 -07:00
|
|
|
|
std::printf(" --gen-mesh-mailbox <wom-base> [postH] [postT] [boxL] [boxW] [boxH]\n");
|
|
|
|
|
|
std::printf(" Mailbox: post + horizontal box + side flag (default 1.10/0.08/0.45/0.20/0.20)\n");
|
2026-05-09 08:19:04 -07:00
|
|
|
|
std::printf(" --gen-mesh-tombstone <wom-base> [width] [height] [depth] [baseScale]\n");
|
|
|
|
|
|
std::printf(" Tombstone: base plinth + tall slab + decorative crown (default 0.60/1.10/0.18/1.45)\n");
|
2026-05-09 08:28:53 -07:00
|
|
|
|
std::printf(" --gen-mesh-crate <wom-base> [size] [postRadius]\n");
|
|
|
|
|
|
std::printf(" Crate: cube body + 4 corner reinforcement posts (default 0.80/0.05)\n");
|
2026-05-09 08:44:51 -07:00
|
|
|
|
std::printf(" --gen-mesh-stool <wom-base> [seatSize] [seatThick] [legHeight] [legThick]\n");
|
|
|
|
|
|
std::printf(" Stool: small backless seat on 4 corner legs (default 0.36/0.04/0.45/0.04)\n");
|
2026-05-09 08:54:27 -07:00
|
|
|
|
std::printf(" --gen-mesh-cauldron <wom-base> [rimWidth] [bodyHeight] [legHeight]\n");
|
|
|
|
|
|
std::printf(" Cauldron: 4 legs + narrow bottom + wider mid + widest rim tiers (default 0.80/0.70/0.10)\n");
|
2026-05-09 09:02:04 -07:00
|
|
|
|
std::printf(" --gen-mesh-gate <wom-base> [openingWidth] [postHeight] [postT] [railT]\n");
|
|
|
|
|
|
std::printf(" Gate: 2 vertical posts + 3 horizontal rails (default 1.80/1.30/0.10/0.06)\n");
|
2026-05-09 09:11:36 -07:00
|
|
|
|
std::printf(" --gen-mesh-beehive <wom-base> [baseWidth] [height] [plateH]\n");
|
|
|
|
|
|
std::printf(" Beehive (skep): 4 tapered tiers + entrance notch on +Z face (default 0.70/0.85/0.05)\n");
|
2026-05-09 09:20:08 -07:00
|
|
|
|
std::printf(" --gen-mesh-weathervane <wom-base> [postH] [postT] [baseSize] [armLen] [arrowLen]\n");
|
|
|
|
|
|
std::printf(" Weathervane: base + post + N-S/E-W cross arms + arrow with tail (default 1.50/0.05/0.30/0.40/0.55)\n");
|
2026-05-09 09:27:56 -07:00
|
|
|
|
std::printf(" --gen-mesh-scarecrow <wom-base> [bodyH] [armSpan] [postT] [headSize] [hatSize]\n");
|
|
|
|
|
|
std::printf(" Scarecrow: cruciform body + cross arms + head + brimmed hat (default 1.80/1.40/0.06/0.22/0.32)\n");
|
2026-05-09 09:37:13 -07:00
|
|
|
|
std::printf(" --gen-mesh-sundial <wom-base> [baseSize] [baseH] [gnomonH] [gnomonT]\n");
|
|
|
|
|
|
std::printf(" Sundial: square base + central gnomon slab + 4 cardinal hour markers (default 0.80/0.06/0.35/0.04)\n");
|
2026-05-09 09:46:59 -07:00
|
|
|
|
std::printf(" --gen-mesh-podium <wom-base> [baseSize] [stepH] [steps] [lecternSize]\n");
|
|
|
|
|
|
std::printf(" Podium: stepped pyramid + lectern at back of top platform (default 1.60/0.20/3/0.30)\n");
|
2026-05-09 09:56:38 -07:00
|
|
|
|
std::printf(" --gen-mesh-brazier <wom-base> [bowlSize] [stemH] [stemT] [baseSize]\n");
|
|
|
|
|
|
std::printf(" Brazier: base + stem + bowl + 3 flame boxes for fire-pit lighting (default 0.55/0.80/0.10/0.35)\n");
|
2026-05-09 10:11:24 -07:00
|
|
|
|
std::printf(" --gen-mesh-archway-double <wom-base> [openingW] [openingH] [postT] [lintelT]\n");
|
|
|
|
|
|
std::printf(" Double archway: 3 posts + 2 lintels for twin-opening passages (default 1.40/2.40/0.18/0.20)\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" Procedural tree: cylindrical trunk + spherical foliage (default 0.1/2.0/0.7)\n");
|
|
|
|
|
|
std::printf(" --displace-mesh <wom-base> <heightmap.png> [scale]\n");
|
|
|
|
|
|
std::printf(" Offset each vertex along its normal by heightmap brightness × scale (default 1.0)\n");
|
|
|
|
|
|
std::printf(" --gen-mesh-from-heightmap <wom-base> <heightmap.png> [scaleXZ] [scaleY]\n");
|
|
|
|
|
|
std::printf(" Convert a grayscale PNG into a heightmap mesh (W×H verts, 2(W-1)(H-1) tris)\n");
|
|
|
|
|
|
std::printf(" --export-mesh-heightmap <wom-base> <out.png> <W> <H>\n");
|
|
|
|
|
|
std::printf(" Extract a grayscale heightmap PNG from a row-major W×H heightmap mesh\n");
|
|
|
|
|
|
std::printf(" --add-texture-to-mesh <wom-base> <png-path> [batchIdx]\n");
|
|
|
|
|
|
std::printf(" Bind an existing PNG into a WOM's texturePaths and point batchIdx (default 0) at it\n");
|
|
|
|
|
|
std::printf(" --scale-mesh <wom-base> <factor>\n");
|
|
|
|
|
|
std::printf(" Uniformly scale every vertex and bounds by <factor> (factor > 0)\n");
|
|
|
|
|
|
std::printf(" --translate-mesh <wom-base> <dx> <dy> <dz>\n");
|
|
|
|
|
|
std::printf(" Offset every vertex and bounds by (dx, dy, dz)\n");
|
|
|
|
|
|
std::printf(" --strip-mesh <wom-base> [--bones] [--anims] [--all]\n");
|
|
|
|
|
|
std::printf(" Drop bones / animations from a WOM in place (smaller file, static-only use)\n");
|
|
|
|
|
|
std::printf(" --rotate-mesh <wom-base> <x|y|z> <degrees>\n");
|
|
|
|
|
|
std::printf(" Rotate every vertex + normal around the chosen axis by <degrees>\n");
|
|
|
|
|
|
std::printf(" --center-mesh <wom-base>\n");
|
|
|
|
|
|
std::printf(" Translate so the bounds center lands at origin (no scale/rotation change)\n");
|
|
|
|
|
|
std::printf(" --flip-mesh-normals <wom-base>\n");
|
|
|
|
|
|
std::printf(" Invert every vertex normal (use for inside-out meshes or two-sided pre-flip)\n");
|
|
|
|
|
|
std::printf(" --mirror-mesh <wom-base> <x|y|z>\n");
|
|
|
|
|
|
std::printf(" Mirror every vertex + normal across the chosen axis (also flips winding)\n");
|
|
|
|
|
|
std::printf(" --smooth-mesh-normals <wom-base>\n");
|
|
|
|
|
|
std::printf(" Recompute per-vertex normals as area-weighted averages of incident face normals\n");
|
|
|
|
|
|
std::printf(" --merge-meshes <a-base> <b-base> <out-base>\n");
|
|
|
|
|
|
std::printf(" Combine two WOMs into one (vertex/index buffers concatenated, batches preserved)\n");
|
|
|
|
|
|
std::printf(" --add-item <zoneDir> <name> [id] [quality] [displayId] [itemLevel]\n");
|
|
|
|
|
|
std::printf(" Append one item entry to <zoneDir>/items.json (auto-creates the file)\n");
|
|
|
|
|
|
std::printf(" --random-populate-zone <zoneDir> [--seed N] [--creatures N] [--objects N]\n");
|
|
|
|
|
|
std::printf(" Add random creatures/objects to a zone (seeded for reproducibility)\n");
|
|
|
|
|
|
std::printf(" --random-populate-items <zoneDir> [--seed N] [--count N] [--max-quality Q]\n");
|
|
|
|
|
|
std::printf(" Generate random items.json entries (seeded; quality cap defaults to epic=4)\n");
|
|
|
|
|
|
std::printf(" --gen-zone-texture-pack <zoneDir> [--seed N]\n");
|
|
|
|
|
|
std::printf(" Drop a starter texture pack (grass/dirt/stone/brick/wood/water) into <zoneDir>/textures/\n");
|
|
|
|
|
|
std::printf(" --gen-zone-mesh-pack <zoneDir> [--seed N]\n");
|
|
|
|
|
|
std::printf(" Drop a starter WOM mesh pack (rock/tree/fence) into <zoneDir>/meshes/\n");
|
|
|
|
|
|
std::printf(" --gen-zone-starter-pack <zoneDir> [--seed N]\n");
|
|
|
|
|
|
std::printf(" Run both texture-pack + mesh-pack in one pass — full open-format bootstrap\n");
|
|
|
|
|
|
std::printf(" --gen-project-starter-pack <projectDir> [--seed N]\n");
|
|
|
|
|
|
std::printf(" Run starter-pack + audio-pack across every zone — full project-scope bootstrap\n");
|
|
|
|
|
|
std::printf(" --info-zone-summary <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" One-glance health digest for a zone: pack counts/bytes + audit pass/fail\n");
|
|
|
|
|
|
std::printf(" --info-zone-deps <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Find textures referenced by WOMs but missing from <zoneDir>/textures/ (broken-ref audit)\n");
|
|
|
|
|
|
std::printf(" --info-project-deps <projectDir>\n");
|
|
|
|
|
|
std::printf(" Run --info-zone-deps across every zone; reports per-zone PASS/FAIL + grand total\n");
|
|
|
|
|
|
std::printf(" --info-project-summary <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" One-glance status table per zone in a project (BOOTSTRAPPED/PARTIAL/EMPTY)\n");
|
|
|
|
|
|
std::printf(" --gen-zone-readme <zoneDir> [--out <path>]\n");
|
|
|
|
|
|
std::printf(" Auto-generate README.md from zone.json + asset inventory (writes README.md by default)\n");
|
|
|
|
|
|
std::printf(" --gen-project-readme <projectDir> [--out <path>]\n");
|
|
|
|
|
|
std::printf(" Auto-generate PROJECT.md with per-zone status + asset count rollup\n");
|
|
|
|
|
|
std::printf(" --validate-zone-pack <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Audit a zone's open-format asset pack: textures/meshes/audio counts + WOM validity\n");
|
|
|
|
|
|
std::printf(" --validate-project-packs <projectDir>\n");
|
|
|
|
|
|
std::printf(" Run validate-zone-pack across every zone in a project; exits 1 if any fails\n");
|
|
|
|
|
|
std::printf(" --gen-audio-tone <out.wav> <freqHz> <durationSec> [sampleRate] [waveform]\n");
|
|
|
|
|
|
std::printf(" Synthesize a procedural WAV (PCM-16 mono). Waveform: sine|square|triangle|saw\n");
|
|
|
|
|
|
std::printf(" --gen-audio-noise <out.wav> <durationSec> [sampleRate] [color] [seed] [amplitude]\n");
|
|
|
|
|
|
std::printf(" Synthesize procedural noise WAV. Color: white|pink|brown (default white, amp 0.5)\n");
|
|
|
|
|
|
std::printf(" --gen-audio-sweep <out.wav> <startHz> <endHz> <durationSec> [sampleRate] [shape]\n");
|
|
|
|
|
|
std::printf(" Synthesize frequency sweep (chirp) WAV. Shape: linear|exp (default linear)\n");
|
|
|
|
|
|
std::printf(" --gen-zone-audio-pack <zoneDir>\n");
|
|
|
|
|
|
std::printf(" Drop a starter WAV pack (drone/chime/click/alert) into <zoneDir>/audio/\n");
|
|
|
|
|
|
std::printf(" --gen-random-zone <name> [tx ty] [--seed N] [--creatures N] [--objects N] [--items N]\n");
|
|
|
|
|
|
std::printf(" End-to-end: scaffold-zone + random-populate-zone + random-populate-items\n");
|
|
|
|
|
|
std::printf(" --gen-random-project <count> [--prefix N] [--seed N] [--creatures N] [--objects N] [--items N]\n");
|
|
|
|
|
|
std::printf(" Generate <count> random zones at once (names like Zone1, Zone2...; tile coords step)\n");
|
|
|
|
|
|
std::printf(" --info-zone-audio <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Print zone audio config (music + ambience tracks, volumes)\n");
|
|
|
|
|
|
std::printf(" --info-project-audio <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Audio config table across every zone (which zones have music/ambience set)\n");
|
|
|
|
|
|
std::printf(" --snap-zone-to-ground <zoneDir>\n");
|
|
|
|
|
|
std::printf(" Re-snap every creature/object in a zone to actual terrain height\n");
|
|
|
|
|
|
std::printf(" --audit-zone-spawns <zoneDir> [--threshold yards]\n");
|
|
|
|
|
|
std::printf(" List spawns whose Z is more than <threshold> yards off from the terrain (default 5)\n");
|
|
|
|
|
|
std::printf(" --list-zone-spawns <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Combined creature+object listing for a zone (kind, name, position, key fields)\n");
|
|
|
|
|
|
std::printf(" --diff-zone-spawns <aZoneDir> <bZoneDir>\n");
|
|
|
|
|
|
std::printf(" Compare two zones' creature+object lists (added/removed/moved)\n");
|
|
|
|
|
|
std::printf(" --info-spawn <zoneDir> <creature|object> <index> [--json]\n");
|
|
|
|
|
|
std::printf(" Detailed view of a single creature/object spawn by index\n");
|
|
|
|
|
|
std::printf(" --list-project-spawns <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Combined creature+object listing across every zone (zone column added)\n");
|
|
|
|
|
|
std::printf(" --audit-project-spawns <projectDir> [--threshold yards]\n");
|
|
|
|
|
|
std::printf(" Run --audit-zone-spawns across every zone (per-zone summary + total)\n");
|
|
|
|
|
|
std::printf(" --snap-project-to-ground <projectDir>\n");
|
|
|
|
|
|
std::printf(" Run --snap-zone-to-ground across every zone (per-zone summary + totals)\n");
|
|
|
|
|
|
std::printf(" --list-items <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Print every item in <zoneDir>/items.json with quality colors and key fields\n");
|
|
|
|
|
|
std::printf(" --export-zone-items-md <zoneDir> [out.md]\n");
|
|
|
|
|
|
std::printf(" Render items.json as a Markdown table grouped by quality (rare/epic/etc.)\n");
|
|
|
|
|
|
std::printf(" --export-project-items-md <projectDir> [out.md]\n");
|
|
|
|
|
|
std::printf(" Project-wide items markdown: per-zone sections, project quality histogram\n");
|
|
|
|
|
|
std::printf(" --export-project-items-csv <projectDir> [out.csv]\n");
|
|
|
|
|
|
std::printf(" Single CSV with every item across every zone (zone column added for grouping)\n");
|
|
|
|
|
|
std::printf(" --info-item <zoneDir> <id|index> [--json]\n");
|
|
|
|
|
|
std::printf(" Detail view for one item (lookup by id, or by index if prefixed with '#')\n");
|
|
|
|
|
|
std::printf(" --set-item <zoneDir> <id|#index> [--name S] [--quality N] [--displayId N] [--itemLevel N] [--stackable N]\n");
|
|
|
|
|
|
std::printf(" Edit fields on an existing item in place; only specified flags are changed\n");
|
|
|
|
|
|
std::printf(" --remove-item <zoneDir> <index>\n");
|
|
|
|
|
|
std::printf(" Remove item at given 0-based index from <zoneDir>/items.json\n");
|
|
|
|
|
|
std::printf(" --copy-zone-items <fromZoneDir> <toZoneDir> [--merge]\n");
|
|
|
|
|
|
std::printf(" Copy items from one zone to another (default replaces; --merge appends with re-id)\n");
|
|
|
|
|
|
std::printf(" --clone-item <zoneDir> <index> [newName]\n");
|
|
|
|
|
|
std::printf(" Duplicate the item at index, assign next free id (and optional name override)\n");
|
|
|
|
|
|
std::printf(" --validate-items <zoneDir>\n");
|
|
|
|
|
|
std::printf(" Schema check on items.json: duplicate ids, quality range, required fields\n");
|
|
|
|
|
|
std::printf(" --validate-project-items <projectDir>\n");
|
|
|
|
|
|
std::printf(" Run --validate-items across every zone (per-zone PASS/FAIL + aggregate)\n");
|
|
|
|
|
|
std::printf(" --info-project-items <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate item counts and quality histogram across every zone in a project\n");
|
|
|
|
|
|
std::printf(" --convert-dbc-json <dbc-path> [out.json]\n");
|
|
|
|
|
|
std::printf(" Convert one DBC file to wowee JSON sidecar format\n");
|
|
|
|
|
|
std::printf(" --convert-json-dbc <json-path> [out.dbc]\n");
|
|
|
|
|
|
std::printf(" Convert a wowee JSON DBC back to binary DBC for private-server compat\n");
|
|
|
|
|
|
std::printf(" --convert-blp-png <blp-path> [out.png]\n");
|
|
|
|
|
|
std::printf(" Convert one BLP texture to PNG sidecar\n");
|
|
|
|
|
|
std::printf(" --convert-blp-batch <srcDir>\n");
|
|
|
|
|
|
std::printf(" Bulk BLP→PNG conversion across every .blp in <srcDir> (sidecars next to source)\n");
|
|
|
|
|
|
std::printf(" --migrate-wom <wom-base> [out-base]\n");
|
|
|
|
|
|
std::printf(" Upgrade an older WOM (v1/v2) to WOM3 with a default single-batch entry\n");
|
|
|
|
|
|
std::printf(" --migrate-zone <zoneDir>\n");
|
|
|
|
|
|
std::printf(" Run --migrate-wom in-place on every WOM under <zoneDir>\n");
|
|
|
|
|
|
std::printf(" --migrate-project <projectDir>\n");
|
|
|
|
|
|
std::printf(" Run --migrate-zone across every zone in <projectDir>\n");
|
|
|
|
|
|
std::printf(" --migrate-jsondbc <path> [out.json]\n");
|
|
|
|
|
|
std::printf(" Auto-fix a JSON DBC sidecar: add missing format/source, sync recordCount\n");
|
|
|
|
|
|
std::printf(" --list-zones [--json] List discovered custom zones and exit\n");
|
|
|
|
|
|
std::printf(" --zone-stats <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate counts across every zone in <projectDir>\n");
|
|
|
|
|
|
std::printf(" --info-tilemap <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" ASCII-render the 64x64 WoW ADT grid showing tile claims by zone\n");
|
|
|
|
|
|
std::printf(" --list-project-orphans <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Find .wom/.wob files in zones not referenced by any objects.json or doodad list\n");
|
|
|
|
|
|
std::printf(" --remove-project-orphans <projectDir> [--dry-run]\n");
|
|
|
|
|
|
std::printf(" Delete the orphan .wom/.wob files surfaced by --list-project-orphans\n");
|
|
|
|
|
|
std::printf(" --list-zone-deps <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" List external M2/WMO model paths a zone references (objects + WOB doodads)\n");
|
|
|
|
|
|
std::printf(" --export-zone-deps-md <zoneDir> [out.md]\n");
|
|
|
|
|
|
std::printf(" Markdown dep table for a zone (with on-disk presence column)\n");
|
|
|
|
|
|
std::printf(" --export-zone-spawn-png <zoneDir> [out.png]\n");
|
|
|
|
|
|
std::printf(" Top-down PNG of creature + object spawn positions (per-tile-bounded)\n");
|
|
|
|
|
|
std::printf(" --check-zone-refs <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify every referenced model/quest NPC actually exists; exit 1 on missing refs\n");
|
|
|
|
|
|
std::printf(" --check-project-refs <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Run --check-zone-refs across every zone in <projectDir>\n");
|
|
|
|
|
|
std::printf(" --check-zone-content <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Sanity-check creature/object/quest fields for plausible values\n");
|
|
|
|
|
|
std::printf(" --check-project-content <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Run --check-zone-content across every zone in <projectDir>\n");
|
|
|
|
|
|
std::printf(" --for-each-zone <projectDir> -- <cmd...>\n");
|
|
|
|
|
|
std::printf(" Run <cmd...> for every zone in <projectDir>; '{}' in cmd is replaced with the zone path\n");
|
|
|
|
|
|
std::printf(" --for-each-tile <zoneDir> -- <cmd...>\n");
|
|
|
|
|
|
std::printf(" Run <cmd...> for every tile in <zoneDir>; '{}' replaced with the tile-base path\n");
|
|
|
|
|
|
std::printf(" --scaffold-zone <name> [tx ty] Create a blank zone in custom_zones/<name>/ and exit\n");
|
|
|
|
|
|
std::printf(" --mvp-zone <name> [tx ty]\n");
|
|
|
|
|
|
std::printf(" Scaffold + add a creature + object + quest (with objective+reward) for quick demos\n");
|
|
|
|
|
|
std::printf(" --add-tile <zoneDir> <tx> <ty> [baseHeight]\n");
|
|
|
|
|
|
std::printf(" Add a new ADT tile to an existing zone (extends the manifest's tiles list)\n");
|
|
|
|
|
|
std::printf(" --remove-tile <zoneDir> <tx> <ty>\n");
|
|
|
|
|
|
std::printf(" Remove a tile from a zone (drops manifest entry + deletes WHM/WOT/WOC files)\n");
|
|
|
|
|
|
std::printf(" --list-tiles <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" List every tile in a zone manifest with on-disk file presence\n");
|
|
|
|
|
|
std::printf(" --add-creature <zoneDir> <name> <x> <y> <z> [displayId] [level]\n");
|
|
|
|
|
|
std::printf(" Append one creature spawn to <zoneDir>/creatures.json and exit\n");
|
|
|
|
|
|
std::printf(" --add-object <zoneDir> <m2|wmo> <gamePath> <x> <y> <z> [scale]\n");
|
|
|
|
|
|
std::printf(" Append one object placement to <zoneDir>/objects.json and exit\n");
|
|
|
|
|
|
std::printf(" --add-quest <zoneDir> <title> [giverId] [turnInId] [xp] [level]\n");
|
|
|
|
|
|
std::printf(" Append one quest to <zoneDir>/quests.json and exit\n");
|
|
|
|
|
|
std::printf(" --add-quest-objective <zoneDir> <questIdx> <kill|collect|talk|explore|escort|use> <targetName> [count]\n");
|
|
|
|
|
|
std::printf(" Append one objective to a quest by index\n");
|
|
|
|
|
|
std::printf(" --remove-quest-objective <zoneDir> <questIdx> <objIdx>\n");
|
|
|
|
|
|
std::printf(" Remove the objective at given 0-based index from a quest\n");
|
|
|
|
|
|
std::printf(" --clone-quest <zoneDir> <questIdx> [newTitle]\n");
|
|
|
|
|
|
std::printf(" Duplicate a quest (with all objectives + rewards) and append it\n");
|
|
|
|
|
|
std::printf(" --clone-creature <zoneDir> <idx> [newName] [dx dy dz]\n");
|
|
|
|
|
|
std::printf(" Duplicate a creature spawn (defaults: '<orig> (copy)' offset by 5 yards)\n");
|
|
|
|
|
|
std::printf(" --clone-object <zoneDir> <idx> [dx dy dz]\n");
|
|
|
|
|
|
std::printf(" Duplicate an object placement (defaults: offset by 5 yards X)\n");
|
|
|
|
|
|
std::printf(" --add-quest-reward-item <zoneDir> <questIdx> <itemPath> [more...]\n");
|
|
|
|
|
|
std::printf(" Append item reward(s) to a quest's reward.itemRewards list\n");
|
|
|
|
|
|
std::printf(" --set-quest-reward <zoneDir> <questIdx> [--xp N] [--gold N] [--silver N] [--copper N]\n");
|
|
|
|
|
|
std::printf(" Update XP/coin reward fields on a quest by index\n");
|
|
|
|
|
|
std::printf(" --remove-creature <zoneDir> <index>\n");
|
|
|
|
|
|
std::printf(" Remove creature at given 0-based index from <zoneDir>/creatures.json\n");
|
|
|
|
|
|
std::printf(" --remove-object <zoneDir> <index>\n");
|
|
|
|
|
|
std::printf(" Remove object at given 0-based index from <zoneDir>/objects.json\n");
|
|
|
|
|
|
std::printf(" --remove-quest <zoneDir> <index>\n");
|
|
|
|
|
|
std::printf(" Remove quest at given 0-based index from <zoneDir>/quests.json\n");
|
|
|
|
|
|
std::printf(" --copy-zone <srcDir> <newName>\n");
|
|
|
|
|
|
std::printf(" Duplicate a zone to custom_zones/<slug>/ with renamed slug-prefixed files\n");
|
|
|
|
|
|
std::printf(" --rename-zone <srcDir> <newName>\n");
|
|
|
|
|
|
std::printf(" In-place rename (zone.json + slug-prefixed files + dir); no copy\n");
|
|
|
|
|
|
std::printf(" --remove-zone <zoneDir> [--confirm]\n");
|
|
|
|
|
|
std::printf(" Delete a zone directory entirely (requires --confirm to actually delete)\n");
|
|
|
|
|
|
std::printf(" --clear-zone-content <zoneDir> [--creatures] [--objects] [--quests] [--all]\n");
|
|
|
|
|
|
std::printf(" Wipe one or more content files (terrain + manifest preserved)\n");
|
|
|
|
|
|
std::printf(" --strip-zone <zoneDir> [--dry-run]\n");
|
|
|
|
|
|
std::printf(" Remove derived outputs (.glb/.obj/.stl/.html/.dot/.csv/ZONE.md/DEPS.md)\n");
|
|
|
|
|
|
std::printf(" --strip-project <projectDir> [--dry-run]\n");
|
|
|
|
|
|
std::printf(" Run --strip-zone across every zone (per-zone counts + aggregate freed bytes)\n");
|
|
|
|
|
|
std::printf(" --gen-makefile <zoneDir> [out.mk]\n");
|
|
|
|
|
|
std::printf(" Generate a Makefile that rebuilds every derived output for a zone\n");
|
|
|
|
|
|
std::printf(" --gen-project-makefile <projectDir> [out.mk]\n");
|
|
|
|
|
|
std::printf(" Generate a top-level Makefile that delegates to each zone's per-zone Makefile\n");
|
|
|
|
|
|
std::printf(" --repair-project <projectDir> [--dry-run]\n");
|
|
|
|
|
|
std::printf(" Run --repair-zone across every zone (manifest drift fixes, per-zone summary)\n");
|
|
|
|
|
|
std::printf(" --repair-zone <zoneDir> [--dry-run]\n");
|
|
|
|
|
|
std::printf(" Auto-fix manifest/disk drift (missing tiles in manifest, hasCreatures flag)\n");
|
|
|
|
|
|
std::printf(" --build-woc <wot-base> Generate a WOC collision mesh from WHM/WOT and exit\n");
|
|
|
|
|
|
std::printf(" --regen-collision <zoneDir> Rebuild every WOC under a zone dir and exit\n");
|
|
|
|
|
|
std::printf(" --fix-zone <zoneDir> Re-parse + re-save zone JSONs to apply latest scrubs/caps and exit\n");
|
|
|
|
|
|
std::printf(" --export-png <wot-base> Render heightmap, normal-map, and zone-map PNG previews\n");
|
|
|
|
|
|
std::printf(" --export-obj <wom-base> [out.obj]\n");
|
|
|
|
|
|
std::printf(" Convert a WOM model to Wavefront OBJ for use in Blender/MeshLab\n");
|
|
|
|
|
|
std::printf(" --export-glb <wom-base> [out.glb]\n");
|
|
|
|
|
|
std::printf(" Convert a WOM model to glTF 2.0 binary (.glb) — modern industry standard\n");
|
|
|
|
|
|
std::printf(" --export-stl <wom-base> [out.stl]\n");
|
|
|
|
|
|
std::printf(" Convert a WOM model to ASCII STL — works with any 3D printer slicer\n");
|
|
|
|
|
|
std::printf(" --import-stl <stl-path> [wom-base]\n");
|
|
|
|
|
|
std::printf(" Convert an ASCII STL back into WOM (round-trips with --export-stl)\n");
|
|
|
|
|
|
std::printf(" --export-wob-glb <wob-base> [out.glb]\n");
|
|
|
|
|
|
std::printf(" Convert a WOB building to glTF 2.0 binary (one mesh, per-group primitives)\n");
|
|
|
|
|
|
std::printf(" --export-whm-glb <wot-base> [out.glb]\n");
|
|
|
|
|
|
std::printf(" Convert WHM heightmap to glTF 2.0 binary terrain mesh (per-chunk primitives)\n");
|
|
|
|
|
|
std::printf(" --bake-zone-glb <zoneDir> [out.glb]\n");
|
|
|
|
|
|
std::printf(" Bake every WHM tile in a zone into one glTF (one node per tile)\n");
|
|
|
|
|
|
std::printf(" --bake-zone-stl <zoneDir> [out.stl]\n");
|
|
|
|
|
|
std::printf(" Bake every WHM tile in a zone into one STL for 3D-printing the terrain\n");
|
|
|
|
|
|
std::printf(" --bake-zone-obj <zoneDir> [out.obj]\n");
|
|
|
|
|
|
std::printf(" Bake every WHM tile in a zone into one Wavefront OBJ (one g-block per tile)\n");
|
|
|
|
|
|
std::printf(" --bake-project-obj <projectDir> [out.obj]\n");
|
|
|
|
|
|
std::printf(" Bake every zone in a project into one Wavefront OBJ (one g-block per zone)\n");
|
|
|
|
|
|
std::printf(" --bake-project-stl <projectDir> [out.stl]\n");
|
|
|
|
|
|
std::printf(" Bake every zone in a project into one ASCII STL for full-project printing\n");
|
|
|
|
|
|
std::printf(" --bake-project-glb <projectDir> [out.glb]\n");
|
|
|
|
|
|
std::printf(" Bake every zone in a project into one glTF 2.0 (one mesh per zone)\n");
|
2026-05-09 11:01:45 -07:00
|
|
|
|
std::printf(" --bake-wom-collision <wom-base> [out.woc] [--weld <eps>] [--steep <deg>]\n");
|
|
|
|
|
|
std::printf(" Convert a WOM into a WOC collision file (raycast / walkability mesh) with optional vertex weld\n");
|
2026-05-09 11:19:09 -07:00
|
|
|
|
std::printf(" --bake-wob-collision <wob-base> [out.woc] [--weld <eps>] [--steep <deg>]\n");
|
|
|
|
|
|
std::printf(" Convert a multi-group WOB building into a single WOC collision file (weld is per-group)\n");
|
2026-05-09 11:36:38 -07:00
|
|
|
|
std::printf(" --bake-zone-collision <zoneDir> [out.woc] [--weld <eps>] [--steep <deg>]\n");
|
|
|
|
|
|
std::printf(" Walk every .wom + .wob under zoneDir, weld each independently, append to one shared WOC\n");
|
2026-05-09 13:09:28 -07:00
|
|
|
|
std::printf(" --audit-watertight <zoneDir|projectDir> [--weld <eps>] [--json] [--summary]\n");
|
|
|
|
|
|
std::printf(" Walk every .wom under root, run welded watertight check; --summary prints a one-line rollup\n");
|
2026-05-09 13:12:42 -07:00
|
|
|
|
std::printf(" --audit-watertight-wob <zoneDir|projectDir> [--weld <eps>] [--json] [--summary]\n");
|
|
|
|
|
|
std::printf(" Walk every .wob, check that EVERY group is closed (per-group weld); --summary prints one-line rollup\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" --import-obj <obj-path> [wom-base]\n");
|
|
|
|
|
|
std::printf(" Convert a Wavefront OBJ back into WOM (round-trips with --export-obj)\n");
|
|
|
|
|
|
std::printf(" --export-wob-obj <wob-base> [out.obj]\n");
|
|
|
|
|
|
std::printf(" Convert a WOB building to Wavefront OBJ (one group per WOB group)\n");
|
|
|
|
|
|
std::printf(" --import-wob-obj <obj-path> [wob-base]\n");
|
|
|
|
|
|
std::printf(" Convert a Wavefront OBJ back into WOB (round-trips with --export-wob-obj)\n");
|
|
|
|
|
|
std::printf(" --export-woc-obj <woc-path> [out.obj]\n");
|
|
|
|
|
|
std::printf(" Convert a WOC collision mesh to OBJ for visualization (per-flag color groups)\n");
|
|
|
|
|
|
std::printf(" --export-whm-obj <wot-base> [out.obj]\n");
|
|
|
|
|
|
std::printf(" Convert a WHM heightmap to OBJ terrain mesh (9x9 outer grid per chunk)\n");
|
|
|
|
|
|
std::printf(" --validate <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Score zone open-format completeness and exit\n");
|
|
|
|
|
|
std::printf(" --validate-wom <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Deep-check a WOM file for index/bone/batch/bound invariants\n");
|
|
|
|
|
|
std::printf(" --validate-wob <wob-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Deep-check a WOB file for group/portal/doodad invariants\n");
|
|
|
|
|
|
std::printf(" --validate-woc <woc-path> [--json]\n");
|
|
|
|
|
|
std::printf(" Deep-check a WOC collision mesh for finite verts and degeneracy\n");
|
|
|
|
|
|
std::printf(" --validate-whm <wot-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Deep-check a WHM/WOT terrain pair for NaN heights and bad placements\n");
|
|
|
|
|
|
std::printf(" --validate-all <dir> [--json]\n");
|
|
|
|
|
|
std::printf(" Recursively run all per-format validators on every file\n");
|
|
|
|
|
|
std::printf(" --validate-project <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Run --validate-all on every zone in <projectDir>; exit 1 if any zone fails\n");
|
|
|
|
|
|
std::printf(" --bench-validate-project <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Time --validate-project per zone; report avg/min/max latency\n");
|
|
|
|
|
|
std::printf(" --bench-bake-project <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Time WHM/WOT load per zone (proxy for bake cost); report timings\n");
|
|
|
|
|
|
std::printf(" --validate-glb <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify a glTF 2.0 binary's structure (magic, chunks, JSON, accessors)\n");
|
|
|
|
|
|
std::printf(" --check-glb-bounds <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify position accessor min/max in a .glb actually matches the data\n");
|
|
|
|
|
|
std::printf(" --validate-stl <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify an ASCII STL's structure (solid framing, facet/vertex shape, no NaN)\n");
|
|
|
|
|
|
std::printf(" --validate-png <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify a PNG's structure (signature, chunks, CRC, IHDR/IDAT/IEND order)\n");
|
|
|
|
|
|
std::printf(" --validate-blp <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify a BLP texture (magic, dimensions, mip offsets within file)\n");
|
|
|
|
|
|
std::printf(" --validate-jsondbc <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Verify a JSON DBC sidecar's full schema (per-cell types, row width, format tag)\n");
|
|
|
|
|
|
std::printf(" --info-glb <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print glTF 2.0 binary metadata (chunks, mesh/primitive counts, accessors)\n");
|
|
|
|
|
|
std::printf(" --info-glb-bytes <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-section + per-bufferView byte breakdown of a .glb file\n");
|
|
|
|
|
|
std::printf(" --info-glb-tree <path>\n");
|
|
|
|
|
|
std::printf(" Render glTF structure as a tree (scenes/nodes/meshes/primitives)\n");
|
|
|
|
|
|
std::printf(" --zone-summary <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" One-shot validate + creature/object/quest counts and exit\n");
|
|
|
|
|
|
std::printf(" --info-zone-tree <zoneDir>\n");
|
|
|
|
|
|
std::printf(" Render a hierarchical tree view of a zone's contents (no --json)\n");
|
|
|
|
|
|
std::printf(" --info-project-tree <projectDir>\n");
|
|
|
|
|
|
std::printf(" Tree view of every zone in a project with quick counts (no --json)\n");
|
|
|
|
|
|
std::printf(" --info-project-bytes <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-zone byte rollup with proprietary-vs-open category split (size audit)\n");
|
|
|
|
|
|
std::printf(" --validate-project-open-only <projectDir>\n");
|
|
|
|
|
|
std::printf(" Exit 1 if any proprietary Blizzard assets (.m2/.wmo/.blp/.dbc) remain — release gate\n");
|
|
|
|
|
|
std::printf(" --audit-project <projectDir>\n");
|
|
|
|
|
|
std::printf(" Run validate-project + open-only + check-project-refs together; one PASS/FAIL\n");
|
|
|
|
|
|
std::printf(" --bench-audit-project <projectDir>\n");
|
|
|
|
|
|
std::printf(" Time each --audit-project sub-step; shows where the slow ones are\n");
|
|
|
|
|
|
std::printf(" --info-zone-bytes <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-file size breakdown grouped by category, sorted largest-first\n");
|
|
|
|
|
|
std::printf(" --info-project-extents <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Combined spatial bounding box across every zone (per-zone table + project union)\n");
|
|
|
|
|
|
std::printf(" --info-zone-extents <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Compute the zone's bounding box (XY tile range, Z height min/max)\n");
|
|
|
|
|
|
std::printf(" --info-project-water <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate water-layer stats across every zone (per-zone breakdown + project totals)\n");
|
|
|
|
|
|
std::printf(" --info-zone-water <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate water-layer stats across all tiles (layer count, types, area)\n");
|
|
|
|
|
|
std::printf(" --info-project-density <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-zone content density rollup (creatures/objects/quests per tile, project totals)\n");
|
|
|
|
|
|
std::printf(" --info-zone-density <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-tile density (creatures/objects/quests per tile + overall avg)\n");
|
|
|
|
|
|
std::printf(" --export-zone-summary-md <zoneDir> [out.md]\n");
|
|
|
|
|
|
std::printf(" Render a markdown documentation page for a zone (manifest + content)\n");
|
|
|
|
|
|
std::printf(" --export-zone-csv <zoneDir> [outDir]\n");
|
|
|
|
|
|
std::printf(" Emit creatures.csv / objects.csv / quests.csv / items.csv for spreadsheet workflows\n");
|
|
|
|
|
|
std::printf(" --export-zone-checksum <zoneDir> [out.sha256]\n");
|
|
|
|
|
|
std::printf(" Emit a SHA-256 manifest of every source file in a zone (for integrity checks)\n");
|
|
|
|
|
|
std::printf(" --export-project-checksum <projectDir> [out.sha256]\n");
|
|
|
|
|
|
std::printf(" Project-wide SHA-256 manifest (paths are zone-relative) + single project fingerprint\n");
|
|
|
|
|
|
std::printf(" --validate-project-checksum <projectDir> [in.sha256]\n");
|
|
|
|
|
|
std::printf(" Verify PROJECT_SHA256SUMS in-tool (cross-platform, no sha256sum dependency)\n");
|
|
|
|
|
|
std::printf(" --export-zone-html <zoneDir> [out.html]\n");
|
|
|
|
|
|
std::printf(" Emit a single-file HTML viewer next to the zone .glb (model-viewer based)\n");
|
|
|
|
|
|
std::printf(" --export-project-html <projectDir> [out.html]\n");
|
|
|
|
|
|
std::printf(" Generate an index.html linking to every zone's HTML viewer in <projectDir>\n");
|
|
|
|
|
|
std::printf(" --export-project-md <projectDir> [out.md]\n");
|
|
|
|
|
|
std::printf(" Generate a README.md indexing every zone with counts + viewer/bake status\n");
|
|
|
|
|
|
std::printf(" --export-quest-graph <zoneDir> [out.dot]\n");
|
|
|
|
|
|
std::printf(" Render quest-chain DAG as Graphviz DOT (pipe to `dot -Tpng -o quests.png`)\n");
|
|
|
|
|
|
std::printf(" --info <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOM file metadata (version, counts) and exit\n");
|
|
|
|
|
|
std::printf(" --info-batches <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-batch breakdown of a WOM3 (index range, texture, blend mode, flags)\n");
|
|
|
|
|
|
std::printf(" --info-textures <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" List every texture path referenced by a WOM (with on-disk presence)\n");
|
|
|
|
|
|
std::printf(" --info-doodads <wob-base> [--json]\n");
|
|
|
|
|
|
std::printf(" List every doodad placement in a WOB (model path, position, rotation, scale)\n");
|
|
|
|
|
|
std::printf(" --info-attachments <m2-path> [--json]\n");
|
|
|
|
|
|
std::printf(" List M2 attachment points (weapon mounts, etc.) with bone + offset\n");
|
|
|
|
|
|
std::printf(" --info-particles <m2-path> [--json]\n");
|
|
|
|
|
|
std::printf(" List M2 particle + ribbon emitters (texture, blend, bone)\n");
|
|
|
|
|
|
std::printf(" --info-sequences <m2-path> [--json]\n");
|
|
|
|
|
|
std::printf(" List M2 animation sequences (id, duration, flags)\n");
|
|
|
|
|
|
std::printf(" --info-bones <m2-path> [--json]\n");
|
|
|
|
|
|
std::printf(" List M2 bones with parent tree, key-bone IDs, pivot offsets\n");
|
|
|
|
|
|
std::printf(" --export-bones-dot <wom-base> [out.dot]\n");
|
|
|
|
|
|
std::printf(" Render WOM bone hierarchy as Graphviz DOT (pipe to `dot -Tpng -o bones.png`)\n");
|
|
|
|
|
|
std::printf(" --list-project-meshes <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Project-wide WOM inventory across every zone (vert/tri totals + per-zone breakdown)\n");
|
|
|
|
|
|
std::printf(" --list-project-audio <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Project-wide WAV inventory across every zone (duration/bytes per zone + grand total)\n");
|
|
|
|
|
|
std::printf(" --list-project-textures <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate texture refs across every WOM in a project (deduped, with zone breakdown)\n");
|
|
|
|
|
|
std::printf(" --list-zone-meshes <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" List every WOM in <zoneDir> with vert/tri/bone/anim/batch counts and file size\n");
|
|
|
|
|
|
std::printf(" --list-zone-audio <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" List every WAV under <zoneDir>/audio/ with format/duration/sample-rate/size\n");
|
|
|
|
|
|
std::printf(" --list-zone-textures <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate texture refs across all WOM models in a zone (deduped)\n");
|
|
|
|
|
|
std::printf(" --info-zone-models-total <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate WOM/WOB stats across a zone (verts, tris, bones, batches, doodads)\n");
|
|
|
|
|
|
std::printf(" --list-zone-meshes-detail <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-mesh listing of every .wom in a zone, sorted by triangle count\n");
|
|
|
|
|
|
std::printf(" --info-mesh <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Single-mesh detail: bounds, version, batches, bones, textures, attachments in one view\n");
|
|
|
|
|
|
std::printf(" --info-mesh-storage-budget <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Estimated bytes-per-category breakdown for a single WOM (vertices/indices/bones/...)\n");
|
2026-05-09 10:41:58 -07:00
|
|
|
|
std::printf(" --info-mesh-stats <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Geometric stats: total surface area, triangle area histogram, edge use, watertight check\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" --list-project-meshes-detail <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-mesh listing across every zone in a project (sorted by triangle count)\n");
|
|
|
|
|
|
std::printf(" --info-project-models-total <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" Aggregate WOM/WOB stats across an entire project (per-zone breakdown + totals)\n");
|
|
|
|
|
|
std::printf(" --info-wob <wob-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOB building metadata (groups, portals, doodads) and exit\n");
|
2026-05-09 10:57:22 -07:00
|
|
|
|
std::printf(" --info-wob-stats <wob-base> [--weld <eps>] [--json]\n");
|
|
|
|
|
|
std::printf(" Per-group + aggregate geometric stats (surface area, edges, watertight) for a WOB building\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" --info-woc <woc-path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOC collision metadata (triangle counts, bounds) and exit\n");
|
2026-05-09 13:52:07 -07:00
|
|
|
|
std::printf(" --info-wol <wol-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOL lighting keyframes (zone name + per-time-of-day ambient/directional/fog) and exit\n");
|
feat(pipeline): add WOL validation + time-of-day sampling
Three additions to the Wowee Open Light format that landed
last commit:
• WoweeLightLoader::sampleAtTime(light, timeMin) returns
the linearly-interpolated keyframe at any time-of-day,
correctly handling wrap-around between the last keyframe
and the first (e.g. 21:00 blends from dusk toward
midnight by going forward through 00:00).
• --validate-wol <wol-base> [--json] walks every keyframe
and reports structural problems: time bounds (must be
[0, 1440)), strict-ascending sort order, fogEnd >
fogStart, finite color components. Exit code 0 PASS /
1 FAIL — CI-friendly.
• --info-wol-at <wol-base> <HH:MM|minutes> samples the
interpolated state at a specific time of day. Useful
for previewing what the renderer would feed in at a
given moment, debugging keyframe gaps, or previewing
a sub-range of the cycle.
Smoke-tested: dawn-to-midnight blend at 03:00 yields a
plausible mid-fade ambient (0.18, 0.16, 0.15) and dusk-to-
midnight wrap at 21:00 yields the symmetric (0.19, 0.145,
0.14). The default 4-keyframe day/night cycle from
makeDefaultDayNight passes --validate-wol cleanly.
2026-05-09 13:54:57 -07:00
|
|
|
|
std::printf(" --info-wol-at <wol-base> <HH:MM|minutes>\n");
|
|
|
|
|
|
std::printf(" Sample the WOL's interpolated lighting at a specific time-of-day (linear blend between keyframes)\n");
|
|
|
|
|
|
std::printf(" --validate-wol <wol-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Walk every keyframe; check time bounds + sort order + fogEnd > fogStart + finite color components\n");
|
2026-05-09 13:52:07 -07:00
|
|
|
|
std::printf(" --gen-light <wol-base> [zoneName]\n");
|
|
|
|
|
|
std::printf(" Emit a starter .wol with the canonical 4-keyframe day/night cycle (midnight + dawn + noon + dusk)\n");
|
2026-05-09 14:01:26 -07:00
|
|
|
|
std::printf(" --gen-light-cave <wol-base> [zoneName]\n");
|
|
|
|
|
|
std::printf(" Emit a single-keyframe .wol with dim cool ambient + heavy short-range fog (cave / mine interior)\n");
|
|
|
|
|
|
std::printf(" --gen-light-dungeon <wol-base> [zoneName]\n");
|
|
|
|
|
|
std::printf(" Emit a single-keyframe .wol with warm torchlit ambient + medium fog (dungeon / crypt interior)\n");
|
|
|
|
|
|
std::printf(" --gen-light-night <wol-base> [zoneName]\n");
|
|
|
|
|
|
std::printf(" Emit a single-keyframe .wol with moonlit directional + far fog (always-night zone / shadow realm)\n");
|
2026-05-09 14:18:14 -07:00
|
|
|
|
std::printf(" --export-wol-json <wol-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wol to a human-editable JSON sidecar (defaults to <base>.wol.json)\n");
|
|
|
|
|
|
std::printf(" --import-wol-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wol.json sidecar back into binary .wol (round-trip with --export-wol-json)\n");
|
2026-05-09 14:25:41 -07:00
|
|
|
|
std::printf(" --export-wow-json <wow-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wow to a human-editable JSON sidecar (defaults to <base>.wow.json)\n");
|
|
|
|
|
|
std::printf(" --import-wow-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wow.json sidecar back into binary .wow (accepts type-name string OR typeId int)\n");
|
feat(pipeline): add Wowee Open Weather (.wow) zone schedule
8th open-format addition to the Wowee pipeline. Replaces
WoW's WeatherTypes.dbc / WeatherEffect logic with a single
binary file holding a list of weather states for one zone,
each tagged with intensity bounds, a probability weight,
and duration bounds. The renderer / runtime samples one
entry at a time using weighted-random selection, drives
it for a uniform-random duration in [min, max] sec, then
re-rolls.
• Types: Clear / Rain / Snow / Storm / Sandstorm / Fog /
Blizzard (extensible enum).
• Binary format: magic "WOWA", version 1, name, N entries
each storing (typeId, minIntensity, maxIntensity, weight,
minDurationSec, maxDurationSec).
CLI:
• --info-wow <wow-base> [--json] — inspect a WOW
• --gen-weather-temperate — clear + rain + fog (forest)
• --gen-weather-arctic — snow + blizzard + fog (tundra)
• --gen-weather-desert — clear + sandstorm (dunes)
• --gen-weather-stormy — rain + storm + occasional clear
The 8th open format complementing the rest:
M2 → WOM | WMO → WOB | WMO collision → WOC | ADT → WOT
DBC → JsonDBC | BLP → PNG | Light.dbc → WOL | WeatherTypes.dbc → WOW
Smoke-tested all 4 presets + JSON output. Each preset reads
back identically with the expected entry count and weight
distribution.
2026-05-09 14:10:13 -07:00
|
|
|
|
std::printf(" --info-wow <wow-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOW weather entries (zone + per-state type / intensity / weight / duration) and exit\n");
|
2026-05-09 14:13:30 -07:00
|
|
|
|
std::printf(" --validate-wow <wow-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Walk every WOW entry; check typeId / intensity bounds [0,1] / weight > 0 / duration min ≤ max\n");
|
2026-05-09 14:34:22 -07:00
|
|
|
|
std::printf(" --validate-wom <wom-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static sanity checks on .wom: index range, bone refs, bound box, batch coverage, animation track count\n");
|
2026-05-09 14:38:05 -07:00
|
|
|
|
std::printf(" --gen-world-map <womx-base> [mapName]\n");
|
|
|
|
|
|
std::printf(" Emit .womx world-tile manifest: 64x64 continent grid with all tiles present (open WDT replacement)\n");
|
|
|
|
|
|
std::printf(" --gen-world-map-instance <womx-base> [mapName]\n");
|
|
|
|
|
|
std::printf(" Emit .womx world-tile manifest: 4x4 instance grid (small-world / dungeon scale)\n");
|
|
|
|
|
|
std::printf(" --gen-world-map-arena <womx-base> [mapName]\n");
|
|
|
|
|
|
std::printf(" Emit .womx world-tile manifest: 1x1 single-tile arena (smallest valid world)\n");
|
|
|
|
|
|
std::printf(" --info-womx <womx-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOMX manifest (worldType / gridSize / tilesPresent / defaultLightId / defaultWeatherId)\n");
|
|
|
|
|
|
std::printf(" --validate-womx <womx-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks on .womx: gridSize 1..128, worldType in range, tileBitmap matches expected size\n");
|
feat(editor): add WOMX JSON round-trip authoring workflow
Mirrors the WOL/WOW JSON pair from earlier batches: gives
hand-editable access to .womx world-map manifests for
quick tile-bitmap edits without writing a binary patcher.
Tile bitmap is represented as a JSON array of '1'/'0' row
strings — one string per row of the grid. Visual layout
makes missing-row patterns obvious at a glance:
"tiles": [
"10000001",
"01000010",
"00100100",
"00011000",
...
]
Sparse [[x,y]] pair arrays were considered but rejected:
4× larger for a full continent (4096 tiles), and the dense
visual layout is far easier to spot-read for typical
edits like "carve out a hole in this region".
The importer tolerates missing optional fields (uses
WoweeWorldMap defaults), and accepts either worldType
int or worldTypeName string so JSON can be authored by
hand or by tools.
Verified byte-identical round-trip on a 4x4 instance and
a hand-authored 8x8 sparse continent (16/64 tiles, both
defaultLightId and defaultWeatherId preserved through the
JSON layer).
Adds 2 flags to reach 458 documented kArgRequired entries.
All 9 open formats now have established CLI tooling — WOM,
WOB, WOC, WOT, JsonDBC, PNG, WOL, WOW, and WOMX.
2026-05-09 14:39:47 -07:00
|
|
|
|
std::printf(" --export-womx-json <womx-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .womx to a human-editable JSON sidecar (rows of '1'/'0' strings, easy to hand-edit)\n");
|
|
|
|
|
|
std::printf(" --import-womx-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .womx.json sidecar back into binary .womx (round-trip with --export-womx-json)\n");
|
feat(pipeline): add WSND (Wowee Sound Catalog) format
Novel open replacement for Blizzard's SoundEntries.dbc +
SoundEntriesAdvanced.dbc. The 10th open format added to the
editor — covers the audio-metadata gap (the previous 9 cover
geometry, terrain, atmosphere, and world manifests, but no
sound metadata).
Format:
• magic "WSND", version 1, little-endian
• catalogName + entry count
• per entry: soundId / kind / flags / volume /
minDistance / maxDistance / filePath / label
Kind enum (7 categories):
sfx, music, ambient, ui, voice, spell, combat
Flags packed (3 bits used, rest reserved):
loop (0x01), 3d (0x02), stream (0x04)
API: WoweeSoundLoader::save / load / exists; presets
makeStarter (one entry per kind), makeAmbient (wilderness
loops + footsteps), makeTavern (fire + crowd + drink + door
+ lute).
CLI added (5 flags, 465 documented total now):
--gen-sound-catalog <base> [name]
--gen-sound-catalog-ambient <base> [name]
--gen-sound-catalog-tavern <base> [name]
--info-wsnd <base> [--json]
--validate-wsnd <base> [--json]
Validator catches: out-of-range kind, NaN/inf volume or
distances, 3D sounds with bad min/max, duplicate sound IDs,
empty filePaths.
All 3 presets verified: save / load / validate clean
on first run. Variable-length string fields use length-
prefixed encoding with a 1 MiB sanity cap on read to
prevent corrupted-file allocation blowups.
2026-05-09 14:47:16 -07:00
|
|
|
|
std::printf(" --gen-sound-catalog <wsnd-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wsnd starter catalog (one entry per kind: sfx/music/ambient/ui/voice/spell/combat)\n");
|
|
|
|
|
|
std::printf(" --gen-sound-catalog-ambient <wsnd-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wsnd wilderness catalog: looped birds + wind + 3 footstep variants\n");
|
|
|
|
|
|
std::printf(" --gen-sound-catalog-tavern <wsnd-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wsnd tavern catalog: fire-crackle + crowd murmur + drink-clink + door-creak + lute music\n");
|
|
|
|
|
|
std::printf(" --info-wsnd <wsnd-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WSND catalog entries (id / kind / flags / volume / 3D distances / file path / label)\n");
|
|
|
|
|
|
std::printf(" --validate-wsnd <wsnd-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: kind in 0..6, finite distances, 3D needs max>min>=0, no duplicate sound IDs\n");
|
feat(editor): add WSND JSON round-trip authoring workflow
Closes the WSND open-format loop with --export-wsnd-json /
--import-wsnd-json, mirroring the WOL/WOW/WOMX JSON pairs
from earlier batches.
Each entry round-trips all 9 fields:
soundId, kind (int + kindName string), flags (int +
flagsList string array), volume, minDistance, maxDistance,
filePath, label.
Both kind and flags are emitted in dual form (int + named):
• kind : 2,
kindName : "ambient",
• flags : 3,
flagsList: ["loop", "3d"]
The importer accepts either form per field, so a hand-author
can write only the named string forms and skip the integer
boilerplate. Missing optional fields fall back to
WoweeSound::Entry defaults.
Verified byte-identical round-trip on the tavern preset
(5 entries with mixed flags and 3D distances).
Adds 2 flags (467 kArgRequired entries total). All 4 binary
formats added in recent batches now have full JSON round-trip:
WOL, WOW, WOMX, WSND.
2026-05-09 14:51:44 -07:00
|
|
|
|
std::printf(" --export-wsnd-json <wsnd-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wsnd to a human-editable JSON sidecar (defaults to <base>.wsnd.json)\n");
|
|
|
|
|
|
std::printf(" --import-wsnd-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wsnd.json sidecar back into binary .wsnd (accepts either kind int OR kindName string)\n");
|
feat(pipeline): add WSPN (Wowee Spawn Point catalog) format
Novel open replacement for AzerothCore-style scattered
creature_template / gameobject SQL spawn tables PLUS the
ADT MDDF / MODF doodad-placement chunks. The 11th open
format, and the first that covers the live world-content
side (atmosphere + sounds + spawns now form the runtime
"what fills this zone" picture).
A WSPN file holds all spawn points for a zone in a single
table, with kind discriminating creature vs game object
vs static doodad. The same format powers:
• server runtime — knows what NPCs / objects to spawn
• editor — draws spawn markers
• renderer — reads the doodad subset directly to
draw static props without going
through a server roundtrip
Format:
• magic "WSPN", version 1, little-endian
• per entry: kind / entryId / position(3f) / rotation(3f)
/ scale / flags / respawnSec / factionId /
questIdRequired / wanderRadius / label
Flags packed: disabled (0x01), event-only (0x02),
quest-phased (0x04). Reserved bits for future per-entry
encoding extensions.
API: WoweeSpawnsLoader::save / load / exists; presets
makeStarter (1 each kind), makeCamp (4-bandit ring +
chest + 2 tents), makeVillage (6 NPCs + 2 signs + 4
corner trees).
CLI added (5 flags, 473 documented total now):
--gen-spawns / --gen-spawns-camp / --gen-spawns-village
--info-wspn / --validate-wspn
Validator catches: out-of-range kind, NaN/inf coords,
non-positive scale, doodad with non-zero respawn (static
prop misuse), creature with respawn=0 (won't respawn after
kill), entryId=0 (orphan reference).
All 3 presets save / load / re-validate clean. Doodad and
game-object entries explicitly set wanderRadius=0 so the
generated catalogs are noise-free.
2026-05-09 14:57:53 -07:00
|
|
|
|
std::printf(" --gen-spawns <wspn-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wspn starter spawn catalog: 1 creature + 1 game object + 1 doodad near origin\n");
|
|
|
|
|
|
std::printf(" --gen-spawns-camp <wspn-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wspn bandit-camp catalog: 4 creatures around a wander ring + 1 chest + 2 tents\n");
|
|
|
|
|
|
std::printf(" --gen-spawns-village <wspn-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wspn village catalog: 6 friendly NPCs (mixed roles) + 2 signs + 4 corner trees\n");
|
|
|
|
|
|
std::printf(" --info-wspn <wspn-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WSPN spawn entries (kind / entryId / position / respawn / wander radius / label)\n");
|
|
|
|
|
|
std::printf(" --validate-wspn <wspn-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: kind 0..2, finite position/scale/wander, doodads have respawn=0, no orphan entryId=0\n");
|
feat(editor): add WSPN JSON round-trip authoring workflow
Closes the WSPN open-format loop with --export-wspn-json /
--import-wspn-json, mirroring the WOL/WOW/WOMX/WSND JSON
pairs from earlier batches. All 5 binary formats added in
recent batches now have full JSON round-trip authoring.
Each entry round-trips all 12 fields:
kind (int + kindName string), entryId, position[3],
rotation[3], scale, flags (int + flagsList string array),
respawnSec, factionId, questIdRequired, wanderRadius,
label.
Vector fields are emitted as 3-element arrays for natural
JSON layout. Both kind and flags are emitted in dual form
(int + named) so a hand-author can write the named string
forms and skip the integer boilerplate. Missing optional
fields fall back to WoweeSpawns::Entry defaults.
Verified byte-identical round-trip on the village preset
(12 entries: 6 creature + 2 object + 4 doodad). The
position vec3 round-trips through floats with no precision
loss for the typical small-coordinate test cases.
Adds 2 flags (475 kArgRequired entries total).
2026-05-09 14:59:48 -07:00
|
|
|
|
std::printf(" --export-wspn-json <wspn-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wspn to a human-editable JSON sidecar (defaults to <base>.wspn.json)\n");
|
|
|
|
|
|
std::printf(" --import-wspn-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wspn.json sidecar back into binary .wspn (accepts either kind int OR kindName string)\n");
|
feat(pipeline): add WIT (Wowee Item Template) format
Novel open replacement for Blizzard's Item.dbc +
ItemDisplayInfo.dbc + the SQL item_template tables that
AzerothCore-style servers store item definitions in. The
12th open format added to the editor.
A WIT file holds the catalog of all items in a content
pack: weapons, armor, consumables, quest items, trade
goods. Each entry pairs gameplay metadata (stats, level
reqs, flags, weapon damage / speed) with display metadata
(displayId for icon / model, quality color), so the
runtime can render inventory tooltips and equip slots
from a single load.
Format:
• magic "WITM", version 1, little-endian
• per item: itemId / displayId / quality / itemClass /
itemSubClass / inventoryType / flags / requiredLevel /
itemLevel / sellPrice / buyPrice / maxStack / durability
/ damageMin / damageMax / attackSpeedMs /
statCount + stats[] / name / description
Enums:
• Quality: Poor..Heirloom (8 levels)
• Class: Consumable, Weapon, Armor, Quest, ... (13)
• InventoryType: Head..Cloak..Weapon2H (18 slots)
• Flags: Unique, BoP, BoE, QuestItem, Conjured, ...
• StatType: Stamina, Strength, Intellect, Defense, ...
API: WoweeItemLoader::save / load / exists / findById;
presets makeStarter (4-item demo), makeWeapons (5 items
common -> legendary), makeArmor (6-piece mail set with
BoE flag).
CLI added (5 flags, 480 documented total now):
--gen-items / --gen-items-weapons / --gen-items-armor
--info-wit / --validate-wit
Validator catches: itemId=0, duplicate itemIds, weapons
with 0 damage or attackSpeed, weapons with non-weapon
slot, equippables with durability=0 or maxStack>1, sell
price >= buy price (vendor would lose money), out-of-range
quality.
All 3 presets save / load / re-validate clean. Info-table
output includes a gold/silver/copper price formatter for
hand-readability.
2026-05-09 15:04:48 -07:00
|
|
|
|
std::printf(" --gen-items <wit-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wit starter item catalog: 1 weapon + 1 chest + 1 potion + 1 quest item\n");
|
|
|
|
|
|
std::printf(" --gen-items-weapons <wit-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wit weapon catalog: 5 entries spanning common -> legendary, both 1H and 2H\n");
|
|
|
|
|
|
std::printf(" --gen-items-armor <wit-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wit full mail-armor set: head + chest + legs + feet + hands + cloak (BoE)\n");
|
|
|
|
|
|
std::printf(" --info-wit <wit-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WIT item entries (id / ilvl / quality / class / slot / buy price / name)\n");
|
|
|
|
|
|
std::printf(" --validate-wit <wit-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: itemId>0 + unique, weapon damage>0 + min<=max, equippable durability>0, sell<buy\n");
|
2026-05-09 15:13:26 -07:00
|
|
|
|
std::printf(" --export-wit-json <wit-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wit to a human-editable JSON sidecar (defaults to <base>.wit.json)\n");
|
|
|
|
|
|
std::printf(" --import-wit-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wit.json sidecar back into binary .wit (accepts quality/class/slot int OR name string)\n");
|
feat(pipeline): add WLOT (Wowee Loot Table) format
Novel open replacement for AzerothCore-style
creature_loot_template / gameobject_loot_template SQL
tables. The 13th open format added to the editor.
Pairs naturally with the WIT item catalog from the
preceding commit: each loot drop's itemId references an
entry in a WIT file, so a content pack ships both the
item definitions and the loot tables that reference them.
The runtime composes WIT + WLOT + WSPN to drive the full
"creature dies, drops items" flow without any SQL.
Format:
• magic "WLOT", version 1, little-endian
• per table: creatureId / flags / dropCount /
moneyMin..Max / itemDropCount + drops[]
• per drop: itemId / chancePercent (float, 0..100) /
minQty / maxQty / drop_flags
Table flags: QuestOnly, GroupOnly, Pickpocket
Drop flags: QuestRequired, GroupRollOnly, AlwaysDrop
dropCount is the slot budget — how many distinct drops
to roll per kill. Each item drop is rolled independently
against its chancePercent (so dropCount=2 with 4 candidate
drops at varying chances gives the classic "up to 2 distinct
items per kill" behavior). Drops with the AlwaysDrop flag
bypass the slot budget — used for guaranteed quest items.
API: WoweeLootLoader::save / load / exists /
findByCreatureId; presets makeStarter (1 table, 1 drop),
makeBandit (4 candidates, dropCount=2, matches the camp
spawns from WSPN at creatureId=1000), makeBoss (6 candidates
including guaranteed quest item via AlwaysDrop and a
group-only epic at 5%).
CLI added (5 flags, 486 documented total now):
--gen-loot / --gen-loot-bandit / --gen-loot-boss
--info-wlot / --validate-wlot
Validator catches: creatureId=0, duplicates, chance not in
0..100, NaN chance, money min > max, minQty > maxQty,
dropCount=0 with non-empty drops list (silent dead config).
All 3 presets save / load / re-validate clean. The bandit
table's creatureId=1000 deliberately matches WSPN's
makeCamp creatureId so the open-format demo content pack
already has working cross-references.
2026-05-09 15:11:08 -07:00
|
|
|
|
std::printf(" --gen-loot <wlot-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wlot starter loot catalog: 1 creature with 1 drop slot, 1 item @ 50%%, 0..50 copper\n");
|
|
|
|
|
|
std::printf(" --gen-loot-bandit <wlot-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wlot bandit loot table: dropCount=2, 4 candidate items, 5..50 copper\n");
|
|
|
|
|
|
std::printf(" --gen-loot-boss <wlot-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wlot elite boss table: dropCount=4, 6 candidates incl. quest item + group-only epic, 50..200 silver\n");
|
|
|
|
|
|
std::printf(" --info-wlot <wlot-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WLOT loot tables (creatureId / dropCount / money range / per-drop chance + qty + flags)\n");
|
|
|
|
|
|
std::printf(" --validate-wlot <wlot-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: creatureId>0 + unique, chance in 0..100, minQty<=maxQty, money min<=max\n");
|
feat(editor): add WLOT JSON round-trip authoring workflow
Closes the WLOT open-format loop with --export-wlot-json /
--import-wlot-json, mirroring the WOL/WOW/WOMX/WSND/WSPN/WIT
JSON pairs. All 7 binary formats added since WOL now have
full JSON round-trip authoring.
Each loot table round-trips:
• table-level: creatureId, flags (int + flagsList strings),
dropCount, money min/max (copper)
• per-drop: itemId, chancePercent (float),
minQty / maxQty, flags (int + flagsList)
Both flag fields emit dual int + named string-array forms.
A hand-author can write ["quest", "always"] instead of
having to remember that QuestRequired|AlwaysDrop = 5.
Verified byte-identical round-trip on the boss preset
(6 drops including the QuestRequired+AlwaysDrop combo on
the guaranteed quest item, group-only epic at 5%, mass-loot
trade goods at 90%).
Adds 2 flags (495 documented total now).
2026-05-09 15:20:05 -07:00
|
|
|
|
std::printf(" --export-wlot-json <wlot-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wlot to a human-editable JSON sidecar (defaults to <base>.wlot.json)\n");
|
|
|
|
|
|
std::printf(" --import-wlot-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wlot.json sidecar back into binary .wlot (accepts flag int OR flagsList strings)\n");
|
feat(pipeline): add WCRT (Wowee Creature Template) format
Novel open replacement for the AzerothCore-style
creature_template SQL table PLUS the Blizzard
CreatureTemplate / CreatureFamily / CreatureType.dbc trio.
The 14th open format added to the editor.
This is the canonical metadata side of creatures shared
across every spawn instance: HP, level range, faction,
behavior flags, NPC role bits (vendor / trainer /
quest-giver / innkeeper), base damage, equipped gear
references.
Cross-references with the previously-added formats:
WSPN.entry.entryId -> WCRT.entry.creatureId
WLOT.entry.creatureId -> WCRT.entry.creatureId
WCRT.entry.equipped* -> WIT.entry.itemId
The 4-format set (WIT + WLOT + WSPN + WCRT) now lets a
content pack define a complete RPG zone's creature
ecosystem: what creatures are, where they spawn, what they
drop, and what gear they carry — entirely in open formats
with no SQL dependencies.
Format:
• magic "WCRT", version 1, little-endian
• per entry: creatureId / displayId / name / subname /
minLevel..maxLevel / baseHealth + healthPerLevel /
baseMana + manaPerLevel / factionId / npcFlags /
typeId / familyId / damageMin..Max / attackSpeedMs /
baseArmor / walkSpeed + runSpeed / gossipId /
equippedMain + equippedOffhand + equippedRanged /
aiFlags
Enums:
• TypeId: Beast / Dragon / Demon / Elemental / Giant /
Undead / Humanoid / Critter / Mechanical
• FamilyId: Wolf / Cat / Bear / Boar / Raptor / Hyena /
Spider / Gorilla / Crab (for Beast types)
• NpcFlags: Vendor / QuestGiver / Trainer / Banker /
Innkeeper / FlightMaster / Auctioneer /
Repair / Stable
• Behavior: Passive / Aggressive / FleeLowHp / CallHelp /
NoLeash
API: WoweeCreatureLoader::save / load / exists /
findById; presets makeStarter (1 innkeeper),
makeBandit (creatureId=1000 matches WSPN/WLOT bandit
references, equips WIT itemId=1001 sword), makeMerchants
(creatureIds 4001/4002/4003 match WSPN village labels).
CLI added (5 flags, 493 documented total):
--gen-creatures / --gen-creatures-bandit / --gen-creatures-merchants
--info-wcrt / --validate-wcrt
Validator catches: creatureId=0, duplicates, level=0,
minLevel>maxLevel, baseHealth=0, damageMin>damageMax,
attackSpeed=0, non-positive walk/runSpeed, behavior flag
contradictions (passive+aggressive), vendor with
aggressive behavior (player can't trade).
2026-05-09 15:18:44 -07:00
|
|
|
|
std::printf(" --gen-creatures <wcrt-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wcrt starter creature template: 1 friendly innkeeper (vendor + repair flags)\n");
|
|
|
|
|
|
std::printf(" --gen-creatures-bandit <wcrt-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wcrt bandit (creatureId=1000, matches WSPN camp + WLOT bandit table, equips WIT sword)\n");
|
|
|
|
|
|
std::printf(" --gen-creatures-merchants <wcrt-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wcrt 3-NPC village set (innkeeper / smith / alchemist, matches WSPN village creatureIds)\n");
|
|
|
|
|
|
std::printf(" --info-wcrt <wcrt-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WCRT entries (id / level / hp / type / faction / npc-flags / name + subname)\n");
|
|
|
|
|
|
std::printf(" --validate-wcrt <wcrt-base> [--json]\n");
|
feat(pipeline): add WQT (Wowee Quest Template) format
Novel open replacement for AzerothCore-style quest_template
SQL tables PLUS the Blizzard Quest.dbc / QuestObjective.dbc
trio. The 15th open format added to the editor — and the
last gameplay-graph piece the catalog needed.
Cross-references with previously-added formats:
WQT.giverCreatureId -> WCRT.entry.creatureId
WQT.turninCreatureId -> WCRT.entry.creatureId
WQT.objective.targetId -> WCRT (kill) / WIT (collect) /
WOB (interact)
WQT.rewardItem.itemId -> WIT.entry.itemId
WQT.prevQuestId -> WQT.entry.questId (intra-format)
WQT.nextQuestId -> WQT.entry.questId
Together with WIT / WCRT / WLOT / WSPN / WOMX / WOL / WOW /
WSND, a content pack can now ship a complete RPG zone
(terrain + props + atmosphere + sounds + creatures + items
+ loot + spawns + quests) entirely in open formats with no
SQL or .dbc dependencies. 15 of 15 expected slots filled.
Format:
• magic "WQTM", version 1, little-endian
• per quest: questId / title / objective / description /
minLevel..maxLevel + questLevel / requiredClass+RaceMask /
prev+nextQuestId / giver+turninCreatureId /
objectives[] / xpReward + moneyCopperReward /
rewardItems[] / flags
Per-objective:
kind (kill/collect/interact/visit/escort/cast),
targetId, quantity
Per-reward:
itemId, qty, pickFlags (AutoGiven / PlayerChoice)
Quest flags: Daily / Weekly / Raid / Group / AutoComplete /
AutoAccept / Repeatable / ClassQuest / Pvp
API: WoweeQuestLoader::save / load / exists / findById;
presets makeStarter (1 simple kill quest, references the
bandit creatureId=1000), makeChain (3-quest chain with
prev/next links + AutoComplete bridge + player-choice
rewards), makeDaily (Daily+Repeatable+AutoAccept combo).
CLI added (5 flags, 500 documented total — round milestone):
--gen-quests / --gen-quests-chain / --gen-quests-daily
--info-wqt / --validate-wqt
Validator catches: questId=0+duplicates, level=0,
maxLevel<minLevel, empty title, no objectives without
AutoComplete (player can't finish), no rewards at all,
Daily without Repeatable (incoherent), targetId=0,
quantity=0, unknown objective kind, reward itemId=0 or qty=0.
The 3-quest chain demo exercises every major feature:
• multiple objective kinds (visit / collect / kill)
• prev/next chain links
• AutoComplete dialogue-bridge quest
• PlayerChoice reward (1 of 2 weapons)
2026-05-09 15:25:02 -07:00
|
|
|
|
std::printf(" Static checks: creatureId>0+unique, level/hp>0, min<=max, attackSpeed>0, behavior flag conflicts\n");
|
2026-05-09 15:27:12 -07:00
|
|
|
|
std::printf(" --export-wcrt-json <wcrt-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wcrt to a human-editable JSON sidecar (defaults to <base>.wcrt.json)\n");
|
|
|
|
|
|
std::printf(" --import-wcrt-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wcrt.json sidecar back into binary .wcrt (accepts type/family/flag int OR name forms)\n");
|
feat(pipeline): add WQT (Wowee Quest Template) format
Novel open replacement for AzerothCore-style quest_template
SQL tables PLUS the Blizzard Quest.dbc / QuestObjective.dbc
trio. The 15th open format added to the editor — and the
last gameplay-graph piece the catalog needed.
Cross-references with previously-added formats:
WQT.giverCreatureId -> WCRT.entry.creatureId
WQT.turninCreatureId -> WCRT.entry.creatureId
WQT.objective.targetId -> WCRT (kill) / WIT (collect) /
WOB (interact)
WQT.rewardItem.itemId -> WIT.entry.itemId
WQT.prevQuestId -> WQT.entry.questId (intra-format)
WQT.nextQuestId -> WQT.entry.questId
Together with WIT / WCRT / WLOT / WSPN / WOMX / WOL / WOW /
WSND, a content pack can now ship a complete RPG zone
(terrain + props + atmosphere + sounds + creatures + items
+ loot + spawns + quests) entirely in open formats with no
SQL or .dbc dependencies. 15 of 15 expected slots filled.
Format:
• magic "WQTM", version 1, little-endian
• per quest: questId / title / objective / description /
minLevel..maxLevel + questLevel / requiredClass+RaceMask /
prev+nextQuestId / giver+turninCreatureId /
objectives[] / xpReward + moneyCopperReward /
rewardItems[] / flags
Per-objective:
kind (kill/collect/interact/visit/escort/cast),
targetId, quantity
Per-reward:
itemId, qty, pickFlags (AutoGiven / PlayerChoice)
Quest flags: Daily / Weekly / Raid / Group / AutoComplete /
AutoAccept / Repeatable / ClassQuest / Pvp
API: WoweeQuestLoader::save / load / exists / findById;
presets makeStarter (1 simple kill quest, references the
bandit creatureId=1000), makeChain (3-quest chain with
prev/next links + AutoComplete bridge + player-choice
rewards), makeDaily (Daily+Repeatable+AutoAccept combo).
CLI added (5 flags, 500 documented total — round milestone):
--gen-quests / --gen-quests-chain / --gen-quests-daily
--info-wqt / --validate-wqt
Validator catches: questId=0+duplicates, level=0,
maxLevel<minLevel, empty title, no objectives without
AutoComplete (player can't finish), no rewards at all,
Daily without Repeatable (incoherent), targetId=0,
quantity=0, unknown objective kind, reward itemId=0 or qty=0.
The 3-quest chain demo exercises every major feature:
• multiple objective kinds (visit / collect / kill)
• prev/next chain links
• AutoComplete dialogue-bridge quest
• PlayerChoice reward (1 of 2 weapons)
2026-05-09 15:25:02 -07:00
|
|
|
|
std::printf(" --gen-quests <wqt-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wqt starter quest: 'Kill 10 Defias Bandits' giver=4001 (matches WCRT village innkeeper)\n");
|
|
|
|
|
|
std::printf(" --gen-quests-chain <wqt-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wqt 3-quest chain: Investigate -> Recover -> Report (chained via prev/next questId)\n");
|
|
|
|
|
|
std::printf(" --gen-quests-daily <wqt-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wqt daily repeatable quest with the Daily + Repeatable + AutoAccept flag combo\n");
|
|
|
|
|
|
std::printf(" --info-wqt <wqt-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WQT entries (questId / level / giver / objectives / rewards / chain links)\n");
|
|
|
|
|
|
std::printf(" --validate-wqt <wqt-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: questId>0+unique, level>0+min<=max, title not empty, no rewards warning, daily needs repeatable\n");
|
feat(editor): add WQT JSON round-trip authoring workflow
Closes the WQT open-format loop with --export-wqt-json /
--import-wqt-json, mirroring the WOL/WOW/WOMX/WSND/WSPN/
WIT/WLOT/WCRT JSON pairs. All 9 binary formats added since
WOL now have full JSON round-trip authoring.
Each quest round-trips:
• 13 scalar fields (id, level range, masks, chain links,
giver/turnin, xp + money reward, flags)
• 3 string fields (title, objective, description)
• objectives array with dual int + name kindName
• rewardItems array with dual int + name pickFlagsList
The flag bitset emits string-array form so a hand-author can
write ["daily", "repeatable", "auto-accept"] instead of
having to remember the bit math. The objective kindName
makes "visit/collect/kill" obvious without needing to know
that kind=3 means VisitArea.
Verified byte-identical round-trip on the 3-quest chain
preset (full feature exercise: prev/next chain links,
mixed objective kinds, AutoComplete bridge quest, player-
choice rewards). Adds 2 flags (509 documented total now).
2026-05-09 15:33:21 -07:00
|
|
|
|
std::printf(" --export-wqt-json <wqt-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wqt to a human-editable JSON sidecar (defaults to <base>.wqt.json)\n");
|
|
|
|
|
|
std::printf(" --import-wqt-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wqt.json sidecar back into binary .wqt (accepts kind/flag int OR name forms)\n");
|
feat(pipeline): add WGOT (Wowee Game Object Template) format
Novel open replacement for AzerothCore-style
gameobject_template SQL tables PLUS the Blizzard
GameObjectDisplayInfo.dbc / GameObject types metadata. The
16th open format added to the editor.
Game objects are the non-creature interactable scenery:
chests (with loot), doors, buttons, mailboxes, herb / ore
gathering nodes, fishing pools, signposts, mounts. Each
has a displayId for the model, a typeId driving its
interaction logic, and optional cross-references to a lock
(future WLCK) and loot table (existing WLOT).
Cross-references with previously-added formats:
WSPN.entry.entryId (kind=GameObject) -> WGOT.entry.objectId
WGOT.entry.lootTableId -> WLOT.entry.creatureId
(loot tables are
universal — chests
and creatures both
key by ID)
The dungeon preset's Bandit Strongbox uses lootTableId=2000
to match WLOT's bandit chest table id, so the demo content
stack already wires together: spawn (WSPN object kind 2000)
-> object template (WGOT 2000) -> loot table (WLOT 2000).
Format:
• magic "WGOT", version 1, little-endian
• per object: objectId / displayId / name / typeId /
size / castBarCaption / requiredSkill +
requiredSkillValue / lockId / lootTableId /
minOpenTimeMs..maxOpenTimeMs / flags
Enums:
• TypeId (16): Door / Button / Chest / Container /
QuestGiver / Text / Trap / Goober / Transport /
Mailbox / MineralNode / HerbNode / FishingNode /
Mount / Sign / Bonfire
• Flags: Disabled / ScriptOnly / UsableFromMount /
Despawn / Frozen / QuestGated
API: WoweeGameObjectLoader::save / load / exists /
findById; presets makeStarter (chest + mailbox + sign),
makeDungeon (door + button + 2 chests + trap with proper
WLOT cross-references), makeGather (Peacebloom herb +
Tin Vein ore + fishing pool with skill requirements).
CLI added (5 flags, 507 documented total now):
--gen-objects / --gen-objects-dungeon / --gen-objects-gather
--info-wgot / --validate-wgot
Validator catches: objectId=0 + duplicates, size<=0,
minOpenTime>maxOpenTime, gathering node without skill
requirement (anyone can harvest — usually a typo), chest
without loot table (script must populate), requiredSkillValue
set without requiredSkill (incoherent).
2026-05-09 15:31:49 -07:00
|
|
|
|
std::printf(" --gen-objects <wgot-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wgot starter object catalog: 1 chest + 1 mailbox + 1 sign\n");
|
|
|
|
|
|
std::printf(" --gen-objects-dungeon <wgot-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wgot dungeon set: door + button + 2 chests (bandit + boss) + spike trap (cross-refs WLOT)\n");
|
|
|
|
|
|
std::printf(" --gen-objects-gather <wgot-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wgot gathering nodes: Peacebloom (herb) + Tin Vein (ore) + Schools of Fish, with skill reqs\n");
|
|
|
|
|
|
std::printf(" --info-wgot <wgot-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WGOT entries (objectId / type / lock / loot / required skill / name)\n");
|
|
|
|
|
|
std::printf(" --validate-wgot <wgot-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: objectId>0+unique, size>0, time min<=max, gathering needs skill, chest warns on no loot\n");
|
2026-05-09 15:39:50 -07:00
|
|
|
|
std::printf(" --export-wgot-json <wgot-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wgot to a human-editable JSON sidecar (defaults to <base>.wgot.json)\n");
|
|
|
|
|
|
std::printf(" --import-wgot-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wgot.json sidecar back into binary .wgot (accepts type/flag int OR name forms)\n");
|
feat(pipeline): add WFAC (Wowee Faction Catalog) format
Novel open replacement for Blizzard's Faction.dbc +
FactionTemplate.dbc + the AzerothCore-style
reputation_reward / reputation_spillover SQL tables. The
17th open format added to the editor.
Combines the "displayable Faction" (player-facing name +
reputation thresholds for friendly/honored/revered/exalted)
with the "FactionTemplate matrix" (which factions are
hostile to which) into one entry. The runtime walks the
catalog to answer two questions:
• "Will faction A attack faction B on sight?" -> enemy list
• "What rep tier is the player with X?" -> thresholds
Cross-references with previously-added formats:
WCRT.entry.factionId -> WFAC.entry.factionId
WFAC.entry.parentFactionId -> WFAC.entry.factionId
WFAC.entry.enemies[] -> WFAC.entry.factionId
WFAC.entry.friends[] -> WFAC.entry.factionId
The starter preset's factionId 35 (Friendly) and 14
(Hostile) deliberately match the WCRT preset defaults, so
the demo content stack is consistent: WCRT.makeBandit's
factionId=14 has a real entry in WFAC.makeStarter that
declares it hostile to friendly NPCs (35) and players (1).
Format:
• magic "WFAC", version 1, little-endian
• per faction: factionId / parentFactionId / name /
description / reputationFlags / baseReputation /
7 ascending tier thresholds (hostile..exalted) /
enemies[] / friends[]
Enums:
• ReputationFlags: VisibleOnTab / AtWarDefault / Hidden /
NoReputation / IsHeader (group label)
• Tier (canonical): Hated / Hostile / Unfriendly /
Neutral / Friendly / Honored /
Revered / Exalted
API: WoweeFactionLoader::save / load / exists / findById +
WoweeFaction::isHostile(a, b); presets makeStarter (3-faction
demo matching WCRT defaults), makeAlliance (header +
Stormwind / Darnassus / Ironforge with reciprocal friend
lists + Defias enemy), makeWildlife (4 beast factions, each
hostile to player but ignoring other beasts).
CLI added (5 flags, 514 documented total now):
--gen-factions / --gen-factions-alliance / --gen-factions-wildlife
--info-wfac / --validate-wfac
Validator catches: factionId=0 + duplicates, empty name,
threshold ordering violations (hostile must be < unfriendly
< neutral < ... < exalted), self-listed as enemy or friend,
faction in both enemies and friends (incoherent).
2026-05-09 15:37:59 -07:00
|
|
|
|
std::printf(" --gen-factions <wfac-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wfac starter: 3 factions (Friendly id=35 / Hostile id=14 / Player id=1) matching WCRT defaults\n");
|
|
|
|
|
|
std::printf(" --gen-factions-alliance <wfac-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wfac Alliance set: header + Stormwind + Darnassus + Ironforge (reciprocal friends) + Defias enemy\n");
|
|
|
|
|
|
std::printf(" --gen-factions-wildlife <wfac-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wfac wildlife: wolves + bears + spiders + kobolds (each hostile to player, ignores other beasts)\n");
|
|
|
|
|
|
std::printf(" --info-wfac <wfac-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WFAC entries (id / parent / flags / enemy + friend counts / name)\n");
|
|
|
|
|
|
std::printf(" --validate-wfac <wfac-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: factionId>0+unique, name not empty, threshold ordering, no self-enemy, no enemy/friend overlap\n");
|
2026-05-09 15:45:58 -07:00
|
|
|
|
std::printf(" --export-wfac-json <wfac-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wfac to a human-editable JSON sidecar (defaults to <base>.wfac.json)\n");
|
|
|
|
|
|
std::printf(" --import-wfac-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wfac.json sidecar back into binary .wfac (accepts flag int OR flagsList strings)\n");
|
feat(pipeline): add WLCK (Wowee Lock Template) format
Novel open replacement for Blizzard's Lock.dbc. The 18th
open format added to the editor. Closes the cross-reference
gap from WGOT.entry.lockId — until now that field pointed
to a format that didn't exist yet.
A lock is a multi-channel security check. Each lock has up
to 5 independent channels; a player can open the lock by
satisfying ANY ONE channel:
• Item — requires a specific key item (WIT cross-ref)
• Lockpick — requires the lockpicking skill at minimum rank
(rogue / engineering profession)
• Spell — requires casting a specific spell
• Damage — can be forced open with attack damage
Cross-references with previously-added formats:
WGOT.entry.lockId -> WLCK.entry.lockId
WLCK.channel.targetId (Item) -> WIT.entry.itemId
WLCK.channel.targetId (Lockpick) -> future WSKL skillId
WLCK.channel.targetId (Spell) -> future WSPL spellId
The starter and dungeon presets' lockIds (1 and 2)
deliberately match WGOT.makeDungeon's iron-door lockId=1
and bandit-strongbox lockId=2, so the demo content stack
already wires together: WSPN spawn -> WGOT object template
-> WLCK lock template -> WIT key items.
Format:
• magic "WLCK", version 1, little-endian
• per lock: lockId / name / flags / 5 fixed channel slots
• per channel: kind / skillRequired / targetId
• all 5 slots written even when unused (kind=None +
zeroed fields), keeping the per-entry size constant for
fast random access
Enums:
• ChannelKind: None / Item / Lockpick / Spell / Damage
• Flags: DestructOnOpen / RespawnOnKey / TrapOnFail
API: WoweeLockLoader::save / load / exists / findById;
presets makeStarter (Iron Door + Wooden Chest), makeDungeon
(matches WGOT cross-references; light/heavy lockpicks +
boss-key-only seal), makeProfessions (4-tier rogue lockpick
progression at ranks 1/100/175/250).
CLI added (5 flags, 521 documented total now):
--gen-locks / --gen-locks-dungeon / --gen-locks-professions
--info-wlck / --validate-wlck
Validator catches: lockId=0 + duplicates, all-None channels
(lock can never open), Item/Spell/Lockpick channels with
targetId=0 (no resource referenced), unknown channel kind,
skillRequired set on non-Lockpick channel (silently ignored
at runtime — flag as warning).
2026-05-09 15:44:26 -07:00
|
|
|
|
std::printf(" --gen-locks <wlck-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wlck starter: 2 locks (Iron Door key+force, Wooden Chest force-only) — lockId=1 matches WGOT\n");
|
|
|
|
|
|
std::printf(" --gen-locks-dungeon <wlck-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wlck dungeon set: light/heavy lockpicks (lockId=2 matches WGOT bandit chest), boss-key seal\n");
|
|
|
|
|
|
std::printf(" --gen-locks-professions <wlck-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wlck profession-keyed locks at lockpick rank 1/100/175/250 (junkbox tier progression)\n");
|
|
|
|
|
|
std::printf(" --info-wlck <wlck-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WLCK lock entries with per-channel detail (kind / target / required skill rank)\n");
|
|
|
|
|
|
std::printf(" --validate-wlck <wlck-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: lockId>0+unique, at least 1 active channel, item/spell/lockpick need targetId\n");
|
2026-05-09 15:52:20 -07:00
|
|
|
|
std::printf(" --export-wlck-json <wlck-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wlck to a human-editable JSON sidecar (defaults to <base>.wlck.json)\n");
|
|
|
|
|
|
std::printf(" --import-wlck-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wlck.json sidecar back into binary .wlck (accepts kind/flag int OR name forms)\n");
|
feat(pipeline): add WSKL (Wowee Skill Catalog) format
Novel open replacement for Blizzard's SkillLine.dbc +
SkillLineCategory.dbc + the AzerothCore-style player skill
base tables. The 19th open format added to the editor.
Defines every player-trackable skill: weapon proficiencies
(Swords, Axes, Bows), professions (Mining, Alchemy,
Cooking), languages (Common, Dwarvish), class
specializations (Fire, Frost, Holy, Protection), armor
proficiencies (Mail, Plate), and secondary skills (First
Aid, Lockpicking, Riding).
Cross-references with previously-added formats:
WLCK.channel.targetId (kind=Lockpick) -> WSKL.entry.skillId
WGOT.entry.requiredSkill -> WSKL.entry.skillId
The starter preset's skillIds 186 (Mining) and 633
(Lockpicking) deliberately match the canonical IDs already
referenced by WGOT.makeGather and WLCK.makeDungeon —
so the demo content stack now wires together end-to-end:
WGOT herb-node requires skill 186 -> WSKL Mining at rank 1+;
WLCK bandit-strongbox channel requires skill 633 -> WSKL
Lockpicking at rank 1+.
Format:
• magic "WSKL", version 1, little-endian
• per skill: skillId / name / description / categoryId /
canTrain / maxRank / rankPerLevel / iconPath
Enums:
• CategoryId (8): Weapon / Class / Profession /
SecondaryProfession / Language / ArmorProficiency /
Riding / WeaponSpec
API: WoweeSkillLoader::save / load / exists / findById;
presets makeStarter (5-skill demo with cross-referenced
canonical IDs), makeProfessions (12 classic professions:
9 primary + 3 secondary), makeWeapons (16 weapon skills
with canonical SkillLine IDs and rankPerLevel=5 auto-grow).
CLI added (5 flags, 528 documented total now):
--gen-skills / --gen-skills-professions / --gen-skills-weapons
--info-wskl / --validate-wskl
Validator catches: skillId=0 + duplicates, empty name,
maxRank=0, unknown categoryId, suspicious maxRank=1 on
non-Language skill (only languages cap at 1), weapon skill
with rankPerLevel=0 (won't auto-grow on use).
2026-05-09 15:50:25 -07:00
|
|
|
|
std::printf(" --gen-skills <wskl-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wskl starter: Swords + Common + First Aid + Mining (id=186) + Lockpicking (id=633) — matches WGOT/WLCK\n");
|
|
|
|
|
|
std::printf(" --gen-skills-professions <wskl-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wskl 12 classic professions (9 primary + 3 secondary) with canonical SkillLine IDs\n");
|
|
|
|
|
|
std::printf(" --gen-skills-weapons <wskl-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wskl all 16 weapon skills with rankPerLevel=5 auto-grow (use-trained, not trainer-trained)\n");
|
|
|
|
|
|
std::printf(" --info-wskl <wskl-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WSKL entries (id / category / max rank / per-level grow / trainer-required / name)\n");
|
|
|
|
|
|
std::printf(" --validate-wskl <wskl-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: skillId>0+unique, name not empty, maxRank>0, weapon needs rankPerLevel>0\n");
|
2026-05-09 15:59:20 -07:00
|
|
|
|
std::printf(" --export-wskl-json <wskl-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wskl to a human-editable JSON sidecar (defaults to <base>.wskl.json)\n");
|
|
|
|
|
|
std::printf(" --import-wskl-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wskl.json sidecar back into binary .wskl (accepts category int OR categoryName string)\n");
|
feat(pipeline): add WSPL (Wowee Spell Catalog) format
Novel open replacement for Blizzard's Spell.dbc +
SpellEffect.dbc + the AzerothCore-style spell_dbc /
spell_proc tables. The 20th open format added to the
editor — completes the canonical-data side of the gameplay
graph.
Each entry holds the metadata side of a spell: name,
description, school, range, mana / cast / cooldown times,
plus a single primary effect. The simplified effect model
(one effectKind + min/max value + misc field) covers the
common cases (damage / heal / buff / debuff / teleport /
summon / dispel) without needing to reproduce the full
multi-effect graph that classic Spell.dbc carries.
Cross-references with previously-added formats:
WLCK.channel.targetId (kind=Spell) -> WSPL.entry.spellId
WQT.objective.targetId (kind=SpellCast) -> WSPL.entry.spellId
WCRT.equippedMain (item with on-use) -> WIT -> WSPL
Format:
• magic "WSPL", version 1, little-endian
• per spell: spellId / name / description / iconPath /
school / targetType / effectKind / cast & cooldown &
GCD ms / manaCost / range min..max / minLevel /
maxStacks / durationMs / effectValueMin..Max /
effectMisc / flags
Enums:
• School (7): Physical / Holy / Fire / Nature / Frost /
Shadow / Arcane
• TargetType (6): Self / Single / Cone / AoeFromSelf /
Line / Ground
• EffectKind (7): Damage / Heal / Buff / Debuff / Teleport /
Summon / Dispel
• Flags: Passive / Hidden / Channeled / Ranged /
AreaOfEffect / Triggered / UnitTargetOnly /
FriendlyOnly / HostileOnly
API: WoweeSpellLoader::save / load / exists / findById;
presets makeStarter (Strike + Lesser Heal + Power Word:
Fortitude + Hearthstone, one per major effect kind),
makeMage (Frostbolt 116 + Fireball 133 + Arcane Intellect
1459 + Blink 1953, canonical Classic spellIds), makeWarrior
(Heroic Strike 78 + Thunder Clap 6343 + Battle Shout 6673 +
Mortal Strike 12294).
CLI added (5 flags, 535 documented total now):
--gen-spells / --gen-spells-mage / --gen-spells-warrior
--info-wspl / --validate-wspl
Validator catches: spellId=0 + duplicates, empty name,
school out of range, effectKind out of range, NaN range,
range/value min>max, FriendlyOnly+HostileOnly conflict
(incoherent), friendly-only with damage/debuff effect
(incoherent), hostile-only with heal/buff effect, buff/debuff
effect with durationMs=0 (instant fade — almost certainly
authoring oversight).
The validator caught a real preset-emitter authoring error
during initial smoke testing — buff spells were setting
effectValueMin without effectValueMax (validator's range
check immediately flagged it), prompting an in-batch fix
to set both fields. This is exactly the catch-the-typo
purpose validators serve.
2026-05-09 15:58:09 -07:00
|
|
|
|
std::printf(" --gen-spells <wspl-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wspl starter spell catalog: 4 spells covering damage / heal / buff / teleport effect kinds\n");
|
|
|
|
|
|
std::printf(" --gen-spells-mage <wspl-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wspl mage spell set: Frostbolt + Fireball + Arcane Intellect + Blink (canonical IDs 116/133/1459/1953)\n");
|
|
|
|
|
|
std::printf(" --gen-spells-warrior <wspl-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wspl warrior spell set: Heroic Strike + Thunder Clap + Battle Shout + Mortal Strike\n");
|
|
|
|
|
|
std::printf(" --info-wspl <wspl-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WSPL spell entries (id / school / effect / cast/cd / mana / range / damage range / name)\n");
|
|
|
|
|
|
std::printf(" --validate-wspl <wspl-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: spellId>0+unique, name not empty, school 0..6, range/value min<=max, friendly+hostile incoherent\n");
|
2026-05-09 16:06:29 -07:00
|
|
|
|
std::printf(" --export-wspl-json <wspl-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wspl to a human-editable JSON sidecar (defaults to <base>.wspl.json)\n");
|
|
|
|
|
|
std::printf(" --import-wspl-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wspl.json sidecar back into binary .wspl (accepts school/target/effect/flag int OR name forms)\n");
|
feat(pipeline): add WACH (Wowee Achievement Catalog) format
Novel open replacement for Blizzard's Achievement.dbc +
AchievementCriteria.dbc + AchievementCategory.dbc + the
AzerothCore-style character_achievement /
character_achievement_progress SQL tables. The 21st open
format added to the editor.
Each achievement carries display metadata (name, description,
icon, points, faction restriction) plus a list of criteria
the player must satisfy. Criteria mirror the WQT objective
model (kind + targetId + quantity), so the runtime can
reuse the same progress-tracking machinery for both quests
and achievements.
Cross-references with previously-added formats — every
criterion kind has a real format target:
WACH.criteria.targetId (kind=KillCreature) -> WCRT.creatureId
WACH.criteria.targetId (kind=CompleteQuest) -> WQT.questId
WACH.criteria.targetId (kind=LootItem) -> WIT.itemId
WACH.criteria.targetId (kind=CastSpell) -> WSPL.spellId
WACH.criteria.targetId (kind=ReachSkillLevel) -> WSKL.skillId
WACH.criteria.targetId (kind=EarnReputation) -> WFAC.factionId
WACH.criteria.targetId (kind=CompleteAchievement) -> WACH.achievementId
(meta-achievements)
Format:
• magic "WACH", version 1, little-endian
• per achievement: id / categoryId / name / description /
iconPath / titleReward / points / minLevel / faction /
flags / criteria[]
• per criterion: criteriaId / kind / targetId / quantity /
description
Enums:
• CriteriaKind (9): KillCreature / CompleteQuest / LootItem /
ReachLevel / EarnReputation / CastSpell /
ReachSkillLevel / VisitArea /
CompleteAchievement
• Faction: Both / Alliance / Horde
• Flags: HiddenUntilEarned / ServerFirst / RealmFirst /
Tracking / Counter / Account
API: WoweeAchievementLoader::save / load / exists /
findById; presets makeStarter (3 simple kill/quest/level
demos), makeBandit (3 with WCRT/WGOT/WQT cross-refs),
makeMeta (3 base + 1 meta-achievement granting "the
Versatile" title, exercising CompleteAchievement criterion
kind that lets achievements depend on other achievements).
CLI added (5 flags, 542 documented total now):
--gen-achievements / --gen-achievements-bandit / --gen-achievements-meta
--info-wach / --validate-wach
Validator catches: achievementId=0 + duplicates, empty name,
faction out of range, no criteria (achievement can never
be earned), criterion quantity=0, unknown criterion kind,
targetId=0 on criterion kinds that need a real resource
reference (everything except ReachLevel which uses the
quantity field for the level number).
The bandit preset's cross-references close the gameplay
graph end-to-end: kill 50 creatureId=1000 (matches WCRT/
WSPN/WLOT bandit), loot objectId=2000 (matches WGOT bandit
strongbox), complete questId=1 (matches WQT Bandit Trouble).
The meta preset closes a separate loop: 3 sub-achievements
covering Mining (skillId=186), Lockpicking (skillId=633),
and Frostbolt cast count (spellId=116) — each pointing at
a real WSKL/WSPL entry that already exists in the demo
content stack.
2026-05-09 16:04:30 -07:00
|
|
|
|
std::printf(" --gen-achievements <wach-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wach starter: 3 achievements (First Blood / Helping Hand / Coming of Age)\n");
|
|
|
|
|
|
std::printf(" --gen-achievements-bandit <wach-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wach bandit-themed: 3 achievements with cross-refs to WCRT/WGOT/WQT bandit IDs\n");
|
|
|
|
|
|
std::printf(" --gen-achievements-meta <wach-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wach 3 base achievements + 1 meta-achievement (Jack of All Trades, title 'the Versatile')\n");
|
|
|
|
|
|
std::printf(" --info-wach <wach-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WACH entries (id / points / faction / flags / criteria with kind+target+qty)\n");
|
|
|
|
|
|
std::printf(" --validate-wach <wach-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: id>0+unique, name not empty, faction 0..2, criteria need targetId+quantity>0\n");
|
feat(editor): add WACH JSON round-trip authoring workflow
Closes the WACH open-format loop with --export-wach-json /
--import-wach-json, mirroring the JSON pairs added for
every other novel binary format. All 15 binary formats
added since WOL now have full JSON round-trip authoring.
Each achievement round-trips:
• 11 scalar fields (id, categoryId, name, description,
icon, titleReward, points, minLevel, faction, flags)
• criteria array with full per-criterion fields
Three enum-typed fields emit dual int + name forms so a
hand-author can use either:
• criterion.kind (kill/quest/loot/level/rep/cast/skill/visit/meta)
• faction (both/alliance/horde)
• flags (hidden/server-first/realm-first/tracking/...)
Verified byte-identical round-trip on the meta preset (4
achievements, 6 criteria including the 3 CompleteAchievement
criteria that wire the meta-achievement to its prerequisites).
Adds 2 flags (546 documented total now).
2026-05-09 16:07:53 -07:00
|
|
|
|
std::printf(" --export-wach-json <wach-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wach to a human-editable JSON sidecar (defaults to <base>.wach.json)\n");
|
|
|
|
|
|
std::printf(" --import-wach-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wach.json sidecar back into binary .wach (accepts kind/faction/flag int OR name forms)\n");
|
feat(pipeline): add WTRN (Wowee Trainer / Vendor catalog) format
Novel open replacement for AzerothCore-style npc_trainer +
npc_vendor SQL tables PLUS the Blizzard TrainerSpells.dbc
family. The 22nd open format added to the editor.
Unifies trainer spell lists and vendor item inventories
into one per-NPC entry. A creature flagged Trainer or
Vendor in WCRT references a WTRN entry that lists what they
teach / sell. The same NPC can be both — kindMask is a
bitmask covering the Trainer (0x01) and Vendor (0x02) kinds.
This format closes a major cross-format gap: WCRT.npcFlags
already had Vendor / Trainer bits, but until now there was
no format defining what a vendor sells or what a trainer
teaches. Now an NPC marked Vendor in WCRT has a real
inventory, and an NPC marked Trainer has a real spell list.
Cross-references — every WTRN field has a real format target:
WTRN.entry.npcId -> WCRT.entry.creatureId
WTRN.spell.spellId -> WSPL.entry.spellId
WTRN.spell.requiredSkillId -> WSKL.entry.skillId
WTRN.item.itemId -> WIT.entry.itemId
Format:
• magic "WTRN", version 1, little-endian
• per NPC: npcId / kindMask / greeting + spells[] + items[]
• per spell offer: spellId / moneyCostCopper /
requiredSkillId / requiredSkillRank / requiredLevel
• per item offer: itemId / stockCount (0xFFFFFFFF =
unlimited) / restockSec / extendedCost / moneyCostCopper
(0 = inherit from WIT.buyPrice)
API: WoweeTrainerLoader::save / load / exists / findByNpc;
presets makeStarter (innkeeper 4001 as both trainer +
vendor: teaches First Aid + sells starter items),
makeMageTrainer (NPC 4003 teaches the WSPL mage spells
at scaling cost), makeWeaponVendor (NPC 4002 sells WIT
weapons with mixed unlimited/finite stock + restock timers).
CLI added (5 flags, 551 documented total now):
--gen-trainers / --gen-trainers-mage / --gen-trainers-weapons
--info-wtrn / --validate-wtrn
Validator catches: npcId=0 + duplicates, kindMask=0 (NPC
offers nothing), Trainer flag without spells, Vendor flag
without items, spells/items present without the matching
kind bit (silently ignored at runtime), spellId=0 / itemId=0
in offers, finite stock with restockSec=0 (single-fill —
usually intentional but worth surfacing).
The 3 presets deliberately use npcIds matching WCRT village
merchants (4001/4002/4003) so the demo content stack is
self-consistent: WCRT 4001 has the Vendor + Trainer flag,
and WTRN 4001 actually defines what they sell and teach.
2026-05-09 16:12:58 -07:00
|
|
|
|
std::printf(" --gen-trainers <wtrn-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtrn starter: 1 NPC (innkeeper 4001) acting as both vendor + trainer with WSKL/WIT cross-refs\n");
|
|
|
|
|
|
std::printf(" --gen-trainers-mage <wtrn-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtrn mage trainer (npcId=4003): teaches Frostbolt/Fireball/Arcane Intellect/Blink at scaling cost\n");
|
|
|
|
|
|
std::printf(" --gen-trainers-weapons <wtrn-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtrn weapon vendor (npcId=4002): 5 weapons with mixed unlimited/finite stock + restock timers\n");
|
|
|
|
|
|
std::printf(" --info-wtrn <wtrn-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WTRN entries (npc / kind / spells with skill+level reqs / items with stock + restock)\n");
|
|
|
|
|
|
std::printf(" --validate-wtrn <wtrn-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: npcId>0+unique, kindMask>0, Trainer needs spells, Vendor needs items, no orphan offers\n");
|
2026-05-09 16:14:50 -07:00
|
|
|
|
std::printf(" --export-wtrn-json <wtrn-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wtrn to a human-editable JSON sidecar (defaults to <base>.wtrn.json)\n");
|
|
|
|
|
|
std::printf(" --import-wtrn-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wtrn.json sidecar back into binary .wtrn (accepts kindMask int OR kindList string array)\n");
|
feat(pipeline): add WGSP (Wowee Gossip Menu) format
Novel open replacement for AzerothCore-style gossip_menu +
gossip_menu_option + npc_text SQL tables PLUS the Blizzard
NpcText.dbc family. The 23rd open format added to the
editor.
An NPC's dialogue tree: a menu of options the player can
pick from when right-clicking the NPC. Each option may
bridge to another menu, trigger a vendor / trainer
interaction, offer a quest, etc. The simplified per-option
model (kind + actionTarget + flags + moneyCost) covers the
common cases without needing separate npc_text condition
tables.
Closes a major cross-format gap: WCRT.entry.gossipId has
existed since batch 116 (when WCRT was added) but pointed
to a format that didn't exist yet. The innkeeper preset's
menuId=4001 deliberately matches WCRT's Bartleby NPC so
the demo content stack can wire WCRT.gossipId = 4001 once
that field is plumbed through the runtime.
Cross-references:
WCRT.entry.gossipId -> WGSP.entry.menuId
WGSP.option.actionTarget (Submenu) -> WGSP.entry.menuId
WGSP.option.actionTarget (Vendor / Trainer)
-> WTRN.entry.npcId
WGSP.option.actionTarget (Quest) -> WQT.entry.questId
Format:
• magic "WGSP", version 1, little-endian
• per menu: menuId / titleText + options[]
• per option: optionId / text / kind / actionTarget /
requiredFlags / moneyCostCopper
Enums:
• OptionKind (13): Close / Submenu / Vendor / Trainer /
Quest / Tabard / Banker / Innkeeper /
FlightMaster / TextOnly / Script /
Battlemaster / Auctioneer
• OptionFlags: AllianceOnly / HordeOnly / Coinpouch /
QuestGated / Closes
API: WoweeGossipLoader::save / load / exists / findById;
presets makeStarter (1 menu with vendor + trainer + close),
makeInnkeeper (2-menu tree: main menu 4001 with hearth /
vendor / flight / submenu options + lore submenu 4002 that
links back), makeQuestGiver (1 menu with 2 quest options
referencing WQT 1 and 100, plus a paid respec script
exercising the Coinpouch flag with a 10g cost).
CLI added (5 flags, 558 documented total now):
--gen-gossip / --gen-gossip-innkeeper / --gen-gossip-questgiver
--info-wgsp / --validate-wgsp
Validator catches: menuId=0 + duplicates, empty title /
options, unknown option kind, empty option text, Submenu
options pointing at non-existent menuIds (intra-format
cross-reference resolution), Coinpouch flag without
moneyCost (misleading UI), AllianceOnly+HordeOnly conflict.
2026-05-09 16:20:07 -07:00
|
|
|
|
std::printf(" --gen-gossip <wgsp-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wgsp starter: 1 menu with greeting + 3 options (vendor / trainer / close)\n");
|
|
|
|
|
|
std::printf(" --gen-gossip-innkeeper <wgsp-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wgsp 2-menu innkeeper tree (menuId=4001 closes WCRT.gossipId gap; submenu 4002 area lore)\n");
|
|
|
|
|
|
std::printf(" --gen-gossip-questgiver <wgsp-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wgsp questgiver menu: 2 quest options + bank + paid respec (Coinpouch flag, 10g)\n");
|
|
|
|
|
|
std::printf(" --info-wgsp <wgsp-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WGSP entries (menuId / title / per-option kind / target / cost / flags)\n");
|
|
|
|
|
|
std::printf(" --validate-wgsp <wgsp-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: menuId>0+unique, options non-empty, Submenu actionTarget exists, Coinpouch needs cost, faction conflict\n");
|
2026-05-09 16:28:12 -07:00
|
|
|
|
std::printf(" --export-wgsp-json <wgsp-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wgsp to a human-editable JSON sidecar (defaults to <base>.wgsp.json)\n");
|
|
|
|
|
|
std::printf(" --import-wgsp-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wgsp.json sidecar back into binary .wgsp (accepts kind/flag int OR name forms)\n");
|
2026-05-09 16:26:27 -07:00
|
|
|
|
std::printf(" --gen-taxi <wtax-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtax starter: 2 nodes (Stormwind / Goldshire) + 2 paths (round-trip, 50s each, 3 waypoints)\n");
|
|
|
|
|
|
std::printf(" --gen-taxi-region <wtax-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtax 4-node region: NW/NE/SE/SW outposts on a 500m square + 4-path directed ring\n");
|
|
|
|
|
|
std::printf(" --gen-taxi-continent <wtax-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtax 6-node hub-spoke continent: central crossroads + 5 outliers + 3 perimeter shortcuts (8 paths)\n");
|
|
|
|
|
|
std::printf(" --info-wtax <wtax-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WTAX nodes (id / map / position / name) + paths (id / from->to / cost / waypoint count)\n");
|
|
|
|
|
|
std::printf(" --validate-wtax <wtax-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: ids>0+unique, finite positions, paths reference real nodes, no self-loop, non-negative delays\n");
|
2026-05-09 16:35:01 -07:00
|
|
|
|
std::printf(" --export-wtax-json <wtax-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wtax to a human-editable JSON sidecar (defaults to <base>.wtax.json)\n");
|
|
|
|
|
|
std::printf(" --import-wtax-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wtax.json sidecar back into binary .wtax (round-trip with --export-wtax-json)\n");
|
feat(pipeline): add WTAL (Wowee Talent catalog) format
Novel open replacement for Blizzard's TalentTab.dbc +
Talent.dbc + the AzerothCore-style talent_progression SQL
tables. The 25th open format added to the editor.
Defines class talent specialization trees: per-class set
of named tabs (Arms / Fury / Protection for warrior, Fire
/ Frost / Arcane for mage), each with talents arranged in
a row/column grid, each talent having up to 5 ranks and
an optional prerequisite chain.
Cross-references with previously-added formats:
WTAL.talent.prereqTalentId -> WTAL.talent.talentId
(intra-format chain)
WTAL.talent.rankSpellIds[] -> WSPL.entry.spellId
(spell granted at each rank)
Format:
• magic "WTAL", version 1, little-endian
• per tree: treeId / name / iconPath / requiredClassMask /
talents[] (row, col, maxRank, prereqTalentId+rank,
rankSpellIds[5] zero-padded for unused ranks)
Enums:
• ClassMask: bit positions match canonical CharClasses.dbc
classIds — Warrior / Paladin / Hunter / Rogue / Priest /
DK / Shaman / Mage / Warlock / Druid
API: WoweeTalentLoader::save / load / exists +
WoweeTalent::findTree / findTalent (global lookup across
all trees in the catalog).
Three preset emitters showcase tree shapes:
• makeStarter — 1 small tree (3-talent vertical chain)
• makeWarrior — 3 trees (Arms 4 / Fury 4 / Protection 3)
with WSPL cross-refs at capstones
(Mortal Strike -> WSPL 12294, Battle Shout
-> WSPL 6673, Thunder Clap -> WSPL 6343)
• makeMage — 3 trees (Arcane / Fire / Frost) with
capstones referencing Frostbolt 116 /
Fireball 133 / Blink 1953 from WSPL
CLI added (5 flags, 571 documented total now):
--gen-talents / --gen-talents-warrior / --gen-talents-mage
--info-wtal / --validate-wtal
Validator catches: tree+talent ids=0 or duplicates, empty
tree name, requiredClassMask=0 (every class would see this
tree — usually a typo), maxRank not in 1..5, talent listing
itself as prerequisite, prereqTalentId pointing at a
talent that doesn't exist in this catalog (intra-format
cross-reference resolution), prereqRank=0 or > the prereq
talent's maxRank (catches off-by-one references), gaps in
rankSpellIds progression (rank N has spell but rank N-1
doesn't — usually a typo).
The validator caught a real authoring bug in the makeMage /
makeWarrior presets during smoke testing — initial check
was comparing prereqRank against the WRONG talent's maxRank
(this talent's rather than the prereq's). Fixed in the same
commit by hoisting the check into the cross-reference
resolution pass where the prereq talent is in hand.
2026-05-09 16:33:45 -07:00
|
|
|
|
std::printf(" --gen-talents <wtal-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtal starter: 1 small tree (3 talents in chain) for class warrior\n");
|
|
|
|
|
|
std::printf(" --gen-talents-warrior <wtal-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtal warrior trees: Arms (4 talents) + Fury (4) + Protection (3) with WSPL spell cross-refs\n");
|
|
|
|
|
|
std::printf(" --gen-talents-mage <wtal-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wtal mage trees: Arcane (3 talents) + Fire (3) + Frost (3) with WSPL Frostbolt/Fireball/Blink refs\n");
|
|
|
|
|
|
std::printf(" --info-wtal <wtal-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WTAL trees + per-talent grid position / max rank / prereq chain / rank-1 spellId\n");
|
|
|
|
|
|
std::printf(" --validate-wtal <wtal-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: tree+talent ids>0+unique, maxRank 1..5, prereq references resolve, no self-prereq\n");
|
2026-05-09 16:41:37 -07:00
|
|
|
|
std::printf(" --export-wtal-json <wtal-base> [out.json]\n");
|
|
|
|
|
|
std::printf(" Export binary .wtal to a human-editable JSON sidecar (defaults to <base>.wtal.json)\n");
|
|
|
|
|
|
std::printf(" --import-wtal-json <json-path> [out-base]\n");
|
|
|
|
|
|
std::printf(" Import a .wtal.json sidecar back into binary .wtal (round-trip with --export-wtal-json)\n");
|
feat(pipeline): add WMS (Wowee Map / Area) catalog format
Novel open replacement for Blizzard's Map.dbc + AreaTable.dbc
+ the AzerothCore-style world_zone SQL tables. The 26th open
format added to the editor.
Defines two related kinds of locator in one catalog:
• Maps — top-level worlds (continents / instances / raids /
battlegrounds / arenas) with a friendly name,
type, expansion tag, and player-count cap.
• Areas — sub-zones within maps with friendly names, parent-
area chain, recommended level range, faction-
territory marker (alliance / horde / contested /
both), exploration XP, and an ambient-sound
cross-reference into WSND.
The runtime uses Areas for minimap labels, location strings
under the player frame, "Discover Sub-zone" XP gains, and
ambient-music selection on zone entry.
Cross-references with previously-added formats:
WMS.area.ambienceSoundId -> WSND.entry.soundId
WMS.area.parentAreaId -> WMS.area.areaId (intra-format
sub-zone hierarchy)
WSPN entries are tied to WMS.area boundaries by
world position (no direct ID — the runtime resolves
position -> area at lookup time)
Format:
• magic "WMSX", version 1, little-endian
• maps[] (each): mapId / name / shortName / mapType /
expansionId / maxPlayers
• areas[] (each): areaId / mapId / parentAreaId / name /
minLevel..maxLevel / factionGroup / explorationXP /
ambienceSoundId
Enums:
• MapType (5): Continent / Instance / Raid / Battleground / Arena
• ExpansionId (5): Classic / Tbc / Wotlk / Cata / Mop
• FactionGroup: Both / Alliance / Horde / Contested
(PvP-flagging zone)
API: WoweeMapsLoader::save / load / exists +
WoweeMaps::findMap / findArea.
Three preset emitters showcase the catalog shape:
• makeStarter — 1 continent + 3 areas with parent chain
(Goldshire is a sub-zone of Elwynn Forest)
• makeClassic — 2 continents + Deadmines instance + 6
areas (Stormwind/Elwynn/Goldshire/Westfall/
Duskwood/Teldrassil/Deadmines) with WSND
ambient-sound refs
• makeBgArena — Alterac Valley (40-player BG) + Nagrand
Arena (5v5 with maxPlayers=10)
CLI added (5 flags, 578 documented total now):
--gen-maps / --gen-maps-classic / --gen-maps-bgarena
--info-wms / --validate-wms
Validator catches: empty map name, unknown mapType / expansion,
BG/Arena with maxPlayers=0 (no participant cap), area ids=0
+ duplicates, empty area name, maxLevel < minLevel, areas
referencing non-existent maps, parentAreaId chains crossing
maps (sub-zones must be on the same world), self-parent.
2026-05-09 16:40:00 -07:00
|
|
|
|
std::printf(" --gen-maps <wms-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wms starter: 1 map (Eastern Kingdoms) + 3 areas (Stormwind / Elwynn / Goldshire) with parent chain\n");
|
|
|
|
|
|
std::printf(" --gen-maps-classic <wms-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wms classic set: 2 continents + Deadmines instance + 6 areas with sub-zone parent chains + WSND refs\n");
|
|
|
|
|
|
std::printf(" --gen-maps-bgarena <wms-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wms PvP maps: Alterac Valley (40-player BG) + Nagrand Arena (5v5)\n");
|
|
|
|
|
|
std::printf(" --info-wms <wms-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WMS maps (id / type / expansion / max players) + areas (id / map / parent / level / faction / xp)\n");
|
|
|
|
|
|
std::printf(" --validate-wms <wms-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: ids unique, areas reference real maps, parent areas exist + same map, BG/Arena needs maxPlayers\n");
|
feat(pipeline): add WCHC (Wowee Character Classes/Races) format
Novel open replacement for Blizzard's CharClasses.dbc +
CharRaces.dbc + CharStartOutfit.dbc trio. The 27th open
format added to the editor — completes the foundational
character-creation surface.
One file holds three flat arrays:
• classes — playable classes (Warrior / Mage / etc.) with
power type (mana/rage/focus/energy/runic),
base HP+power scaling, faction availability
• races — playable races with faction (Alliance/Horde/
Neutral), starting map+zone, default language
spell, base stats, racial mount spell
• outfits — starting gear loadout per (class, race, gender)
triple, listing item IDs and display slots
Cross-references with previously-added formats:
WCHC.race.startingMapId -> WMS.map.mapId
WCHC.race.startingZoneAreaId -> WMS.area.areaId
WCHC.race.defaultLanguageSpellId -> WSPL.entry.spellId
WCHC.race.mountSpellId -> WSPL.entry.spellId
WCHC.outfit.items.itemId -> WIT.entry.itemId
The starter preset's outfits use real WIT itemIds (1=Worn
Shortsword, 2=Linen Vest, 3=Healing Potion) so the demo
content stack is consistent: a freshly created Human Warrior
in WCHC starts with WIT items 1/2/3, drops them on death
into a WLOT-tracked corpse loot, and can be respawned via
WSPN, etc.
Format:
• magic "WCHC", version 1, little-endian
• classes[]: classId / name / icon / powerType / display /
baseHP+perLevel / basePower+perLevel / factionAvailability
• races[]: raceId / name / icon / factionId / male+female
displayId / 5 base stats / startingMap+zone /
defaultLanguage+mount spell IDs
• outfits[]: classId+raceId+gender + items[]
(each: itemId + displaySlot)
Enums:
• PowerType (6): Mana / Rage / Focus / Energy / RunicPower / Runes
• RaceFaction (3): Alliance / Horde / Neutral
• Gender: Male / Female
• FactionAvailability bitmask: AvailableAlliance, AvailableHorde
API: WoweeCharsLoader::save / load / exists +
WoweeChars::findClass / findRace / findOutfit (by class+race+gender).
CLI added (5 flags, 585 documented total now):
--gen-chars / --gen-chars-alliance / --gen-chars-allraces
--info-wchc / --validate-wchc
Validator catches: ids unique, baseHealth=0 (instant-death
character), factionAvailability=0 (no faction can pick),
empty names, factionId out of range, outfit references to
non-existent class/race ids (cross-format resolution),
gender > 1, outfit items with itemId=0, outfit with no
items (warning — naked character).
2026-05-09 16:47:04 -07:00
|
|
|
|
std::printf(" --gen-chars <wchc-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wchc starter: 2 classes (Warrior + Mage) + 2 races (Human + Orc) + 4 outfits with WIT cross-refs\n");
|
|
|
|
|
|
std::printf(" --gen-chars-alliance <wchc-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wchc Alliance set: 4 classes (Warrior/Paladin/Rogue/Mage) + 4 races (Human/Dwarf/NightElf/Gnome)\n");
|
|
|
|
|
|
std::printf(" --gen-chars-allraces <wchc-base> [name]\n");
|
|
|
|
|
|
std::printf(" Emit .wchc all 8 classic races (4 Alliance + 4 Horde) + 9 classes (no DK)\n");
|
|
|
|
|
|
std::printf(" --info-wchc <wchc-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WCHC classes (id / power / hp scaling) + races (faction / starting zone) + outfit item lists\n");
|
|
|
|
|
|
std::printf(" --validate-wchc <wchc-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Static checks: class+race ids unique, baseHealth>0, faction availability set, outfit refs resolve\n");
|
feat(pipeline): add Wowee Open Weather (.wow) zone schedule
8th open-format addition to the Wowee pipeline. Replaces
WoW's WeatherTypes.dbc / WeatherEffect logic with a single
binary file holding a list of weather states for one zone,
each tagged with intensity bounds, a probability weight,
and duration bounds. The renderer / runtime samples one
entry at a time using weighted-random selection, drives
it for a uniform-random duration in [min, max] sec, then
re-rolls.
• Types: Clear / Rain / Snow / Storm / Sandstorm / Fog /
Blizzard (extensible enum).
• Binary format: magic "WOWA", version 1, name, N entries
each storing (typeId, minIntensity, maxIntensity, weight,
minDurationSec, maxDurationSec).
CLI:
• --info-wow <wow-base> [--json] — inspect a WOW
• --gen-weather-temperate — clear + rain + fog (forest)
• --gen-weather-arctic — snow + blizzard + fog (tundra)
• --gen-weather-desert — clear + sandstorm (dunes)
• --gen-weather-stormy — rain + storm + occasional clear
The 8th open format complementing the rest:
M2 → WOM | WMO → WOB | WMO collision → WOC | ADT → WOT
DBC → JsonDBC | BLP → PNG | Light.dbc → WOL | WeatherTypes.dbc → WOW
Smoke-tested all 4 presets + JSON output. Each preset reads
back identically with the expected entry count and weight
distribution.
2026-05-09 14:10:13 -07:00
|
|
|
|
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");
|
|
|
|
|
|
std::printf(" Emit .wow weather schedule: snow-dominant + blizzard + fog (tundra / glacier)\n");
|
|
|
|
|
|
std::printf(" --gen-weather-desert <wow-base> [zoneName]\n");
|
|
|
|
|
|
std::printf(" Emit .wow weather schedule: clear-dominant + sandstorm (dunes / wasteland)\n");
|
|
|
|
|
|
std::printf(" --gen-weather-stormy <wow-base> [zoneName]\n");
|
|
|
|
|
|
std::printf(" Emit .wow weather schedule: heavy rain + storm + occasional clear (coastal / monsoon)\n");
|
2026-05-09 14:21:55 -07:00
|
|
|
|
std::printf(" --gen-zone-atmosphere <zoneDir> [--name <zoneName>] [--preset default|arctic|desert|stormy|cave]\n");
|
|
|
|
|
|
std::printf(" Convenience: drop both atmosphere.wol + atmosphere.wow into <zoneDir> using a paired light/weather preset\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" --info-wot <wot-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WOT/WHM terrain metadata (tile, chunks, height range) and exit\n");
|
|
|
|
|
|
std::printf(" --info-extract <dir> [--json]\n");
|
|
|
|
|
|
std::printf(" Walk extracted asset tree and report open-format coverage and exit\n");
|
|
|
|
|
|
std::printf(" --info-extract-tree <dir>\n");
|
|
|
|
|
|
std::printf(" Hierarchical view of an extracted asset tree grouped by top-level dir + format\n");
|
|
|
|
|
|
std::printf(" --info-extract-budget <dir> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-extension byte breakdown of an extract dir (sized largest-first)\n");
|
|
|
|
|
|
std::printf(" --info-png <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print PNG header (width, height, channels, bit depth) and exit\n");
|
|
|
|
|
|
std::printf(" --info-blp <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print BLP texture header (format, compression, mips, dimensions) and exit\n");
|
|
|
|
|
|
std::printf(" --info-m2 <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print proprietary M2 model metadata (verts, bones, anims, particles)\n");
|
|
|
|
|
|
std::printf(" --info-wmo <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print proprietary WMO building metadata (groups, portals, doodads)\n");
|
|
|
|
|
|
std::printf(" --info-adt <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print proprietary ADT terrain metadata (chunks, placements, textures)\n");
|
|
|
|
|
|
std::printf(" --info-jsondbc <path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print JSON DBC sidecar metadata (records, fields, source) and exit\n");
|
|
|
|
|
|
std::printf(" --list-missing-sidecars <dir> [--json]\n");
|
|
|
|
|
|
std::printf(" List proprietary files lacking open-format sidecars (one per line)\n");
|
|
|
|
|
|
std::printf(" --info-zone <dir|json> [--json]\n");
|
|
|
|
|
|
std::printf(" Print zone.json fields (manifest, tiles, audio, flags) and exit\n");
|
|
|
|
|
|
std::printf(" --info-zone-overview <zoneDir> [--json]\n");
|
|
|
|
|
|
std::printf(" One-line compact zone summary (tiles, biome, counts, audio status)\n");
|
|
|
|
|
|
std::printf(" --info-project-overview <projectDir> [--json]\n");
|
|
|
|
|
|
std::printf(" One-line summary per zone in a project (single-page health check)\n");
|
|
|
|
|
|
std::printf(" --copy-project <fromDir> <toDir>\n");
|
|
|
|
|
|
std::printf(" Recursively copy a project tree (every zone subdir + manifests)\n");
|
|
|
|
|
|
std::printf(" --info-creatures <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Print creatures.json summary (counts, behaviors) and exit\n");
|
|
|
|
|
|
std::printf(" --info-creatures-by-faction <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Histogram of creature counts grouped by faction id\n");
|
|
|
|
|
|
std::printf(" --info-creatures-by-level <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Distribution of creature levels (min/max/avg + per-level counts)\n");
|
|
|
|
|
|
std::printf(" --info-objects-by-path <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Histogram of object placements grouped by model path (most-used first)\n");
|
|
|
|
|
|
std::printf(" --info-objects-by-type <p> [--json]\n");
|
|
|
|
|
|
std::printf(" M2 vs WMO breakdown plus scale distribution (min/max/avg)\n");
|
|
|
|
|
|
std::printf(" --info-objects <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Print objects.json summary (counts, types, scale range) and exit\n");
|
|
|
|
|
|
std::printf(" --info-quests <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Print quests.json summary (counts, rewards, chain errors) and exit\n");
|
|
|
|
|
|
std::printf(" --info-quests-by-level <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Distribution of required levels across quests (min/max/avg + bar chart)\n");
|
|
|
|
|
|
std::printf(" --info-quests-by-xp <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Distribution of XP rewards (min/max/avg + per-bucket histogram)\n");
|
|
|
|
|
|
std::printf(" --list-creatures <p> [--json]\n");
|
|
|
|
|
|
std::printf(" List every creature with index, name, position, level (for --remove-creature)\n");
|
|
|
|
|
|
std::printf(" --list-objects <p> [--json]\n");
|
|
|
|
|
|
std::printf(" List every object with index, type, path, position\n");
|
|
|
|
|
|
std::printf(" --list-quests <p> [--json]\n");
|
|
|
|
|
|
std::printf(" List every quest with index, title, giver, XP\n");
|
|
|
|
|
|
std::printf(" --list-quest-objectives <p> <questIdx> [--json]\n");
|
|
|
|
|
|
std::printf(" List every objective on a quest (for --remove-quest-objective)\n");
|
|
|
|
|
|
std::printf(" --list-quest-rewards <p> <questIdx> [--json]\n");
|
|
|
|
|
|
std::printf(" List XP/coin/item rewards on a quest\n");
|
|
|
|
|
|
std::printf(" --info-quest-graph-stats <p> [--json]\n");
|
|
|
|
|
|
std::printf(" Analyze quest chain graph (roots, leaves, depths, cycles, orphans)\n");
|
|
|
|
|
|
std::printf(" --info-creature <p> <idx> [--json]\n");
|
|
|
|
|
|
std::printf(" Print every field for one creature spawn (stats, behavior, AI, flags)\n");
|
|
|
|
|
|
std::printf(" --info-quest <p> <idx> [--json]\n");
|
|
|
|
|
|
std::printf(" Print every field for one quest (objectives + reward + chain in one shot)\n");
|
|
|
|
|
|
std::printf(" --info-object <p> <idx> [--json]\n");
|
|
|
|
|
|
std::printf(" Print every field for one object placement (type, path, transform)\n");
|
|
|
|
|
|
std::printf(" --info-wcp <wcp-path> [--json]\n");
|
|
|
|
|
|
std::printf(" Print WCP archive metadata (name, files) and exit\n");
|
|
|
|
|
|
std::printf(" --info-pack-budget <wcp-path> [--json]\n");
|
|
|
|
|
|
std::printf(" Per-extension byte breakdown of a WCP archive (sized largest-first)\n");
|
|
|
|
|
|
std::printf(" --info-pack-tree <wcp-path>\n");
|
|
|
|
|
|
std::printf(" Render a tree view of a WCP's directory structure with byte sizes\n");
|
|
|
|
|
|
std::printf(" --list-wcp <wcp-path> Print every file inside a WCP archive (sorted by path) and exit\n");
|
|
|
|
|
|
std::printf(" --diff-wcp <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two WCPs file-by-file; exit 0 if identical, 1 otherwise\n");
|
|
|
|
|
|
std::printf(" --diff-zone <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two zone dirs (creatures/objects/quests/manifest); exit 0 if identical\n");
|
|
|
|
|
|
std::printf(" --diff-glb <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two glTF 2.0 binaries structurally; exit 0 if identical\n");
|
|
|
|
|
|
std::printf(" --diff-wom <a-base> <b-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two WOM models (verts, indices, bones, anims, batches, bounds)\n");
|
|
|
|
|
|
std::printf(" --diff-wob <a-base> <b-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two WOB buildings (groups, portals, doodads, totals)\n");
|
|
|
|
|
|
std::printf(" --diff-whm <a-base> <b-base> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two WHM/WOT terrain pairs (chunks, height range, placements)\n");
|
|
|
|
|
|
std::printf(" --diff-woc <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two WOC collision meshes (triangles, walkable/steep counts, tile)\n");
|
|
|
|
|
|
std::printf(" --diff-jsondbc <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two JSON DBC sidecars (format/source/recordCount/fieldCount)\n");
|
|
|
|
|
|
std::printf(" --diff-extract <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Compare two extracted asset directories (per-extension file count + bytes)\n");
|
|
|
|
|
|
std::printf(" --diff-checksum <a> <b> [--json]\n");
|
|
|
|
|
|
std::printf(" Diff two SHA256SUMS files; report added/removed/changed entries\n");
|
|
|
|
|
|
std::printf(" --pack-wcp <zone> [dst] Pack a zone dir/name into a .wcp archive and exit\n");
|
|
|
|
|
|
std::printf(" --unpack-wcp <wcp> [dst] Extract a WCP archive (default dst=custom_zones/) and exit\n");
|
|
|
|
|
|
std::printf(" --list-commands Print every recognized --flag, one per line, and exit\n");
|
2026-05-09 12:25:51 -07:00
|
|
|
|
std::printf(" --list-primitives [--mesh|--texture] [--json]\n");
|
|
|
|
|
|
std::printf(" Filtered list of just procedural primitive flags (--gen-mesh-*, --gen-texture-*)\n");
|
2026-05-09 12:51:10 -07:00
|
|
|
|
std::printf(" --list-packs Print every --gen-*-pack composite flag (camp, blacksmith, village, temple…)\n");
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
|
std::printf(" --info-cli-stats [--json]\n");
|
|
|
|
|
|
std::printf(" Meta-stats on the CLI surface (command count by category prefix)\n");
|
|
|
|
|
|
std::printf(" --info-cli-categories\n");
|
|
|
|
|
|
std::printf(" Group every --flag by verb prefix (gen/info/list/...) for discovery\n");
|
|
|
|
|
|
std::printf(" --info-cli-help <pattern>\n");
|
|
|
|
|
|
std::printf(" Substring-search the help text and print matching command lines\n");
|
|
|
|
|
|
std::printf(" --validate-cli-help [--json]\n");
|
|
|
|
|
|
std::printf(" Self-check: every kArgRequired flag must appear in the help text\n");
|
|
|
|
|
|
std::printf(" --gen-completion <bash|zsh>\n");
|
|
|
|
|
|
std::printf(" Print a shell-completion script for wowee_editor (source it from your rc file)\n");
|
|
|
|
|
|
std::printf(" --version Show version and format info\n\n");
|
|
|
|
|
|
std::printf("Wowee World Editor v1.0.0 — by Kelsi Davis\n");
|
|
|
|
|
|
std::printf("Novel open formats: WOT/WHM/WOM/WOB/WOC/WCP + PNG/JSON\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace cli
|
|
|
|
|
|
} // namespace editor
|
|
|
|
|
|
} // namespace wowee
|