Fix Waygate Stone mesh orientation offset (+90 degrees baked into the model) Updated 1 week ago

mod-waygate-network

v1: a discover-as-you-explore fast travel network, in the spirit of FFXIV's Aetheryte system, built as a chat command rather than a spell. See PLAN.md for the roadmap and the reasoning behind the design, including two rounds of in-game-testing surprises this started as before landing here.

What it does

  • Destinations live in mod_waygate_network_locations (world DB) and are loaded once at startup (WaygateNetwork_World::OnLoadCustomDatabaseTable) โ€” adding one is a plain SQL insert + restart (or .waygate reload), not a code change. Ships with the 8 original capital cities (IDs 1-8), Shattrath City (Outland, ID 9) and Dalaran (Northrend, ID 10), and full Eastern Kingdoms, Kalimdor, Outland, and Northrend quest-hub batches (IDs 11-27, 28-45, 46-61, 62-74) โ€” see "Custom ID ranges" below.
  • Each destination has a real, physical Waygate Stone standing in the world at its exact location โ€” interacting with it attunes the destination (a row in mod_waygate_network_discovered), with a chat message confirming it plus a sound (WaygateNetwork.UnlockSoundId, see Config). Their very first-ever attunement also gets a one-line tip about .waygate and macro-binding it. Entering the destination's zone doesn't attune it on its own anymore โ€” see "Waygate Stones" below for why, and what it does instead.
  • Typing .waygate summons a short-lived, harmless "Waygate Portal" NPC next to you (entry 911001, despawns after 15s or as soon as you finish) and immediately opens a two-page gossip menu against it โ€” no wait yet: first a list of continents you have anything attuned in (see "Continent grouping" below), then โ€” after picking one โ€” the attuned destinations within it, each showing its gold/silver/copper cost (real coin icons via WoW's |T...|t inline texture markup). Picking a destination is where the wait happens (see "Cast time" below) โ€” hold still for a few seconds and it charges that cost and teleports you; picking a destination you can no longer afford just tells you so and does nothing. The portal despawns once you pick something; "ยซ Back" (destination page only) returns to the continent list; "I changed my mind..." (continent page only โ€” "ยซ Back" already covers backing out of the destination page) closes the menu and despawns the portal, free. Both pages always have 2+ options so there's never a single-choice list. See "Why a summoned NPC" below for why the portal exists at all, and "Travel cost" below for how the price is worked out.
  • WaygateNetwork.Enable disables the whole thing live โ€” both the command (HandleWaygateCommand) and the actual teleport (npc_waygate_portal::OnGossipSelect) re-check the flag, so flipping it off mid-session stops already-attuned characters from still traveling.
  • Deleting a character cleans up its mod_waygate_network_discovered rows (OnPlayerDeleteFromDB), so a recycled guid can't inherit a stranger's attunements.
  • Playerbots (mod-playerbots) are excluded entirely โ€” the command no-ops for them and they never attune destinations. Guarded with #ifdef MOD_PLAYERBOTS (compiles fine with or without that module present).
  • .waygate reload (GM-only) re-loads mod_waygate_network_locations without a full worldserver restart.
  • WaygateNetwork.Debug (GM-only regardless of the flag) makes .waygate list every known destination instead of just attuned ones, tagged [debug], and skips the attunement check on travel โ€” for reviewing/testing new locations without visiting each one first.
  • .waygate itself is gated behind a quest chain ("The Ley Wardens", see below) โ€” GM debug mode is the only bypass. Attunement keeps working regardless, so finishing the chain doesn't leave you staring at an empty menu.

Why a command, not a spell

v1 originally taught every class a self-cast spell, Call Waygate (910000), that opened the gossip menu on cast. In-game testing (2026-08-13) showed the spell was learned correctly server-side (confirmed in character_spell) but never appeared in the spellbook and couldn't be cast โ€” including via macro. Root cause: AzerothCore's spell_dbc SQL table is the server's internal spell data; it has no relationship to the client's own local Spell.dbc file. A from-scratch ID like 910000 has no entry in the client's copy, so the client has no name/icon/anything to render for it, no matter how correctly the server tracks that the character knows it. There's no client patch distributed here to fix that. See PLAN.md's "Deferred / rejected" section for what would actually be needed to make a real custom spell work, if that's ever worth revisiting.

The .waygate command sidesteps that problem โ€” chat commands are handled server-side only, so there's no client-DBC dependency.

Why a summoned NPC (not a menu sourced from the player directly)

The first version of the command opened the gossip menu using the player's own GUID as the gossip sender (the core's HandleGossipSelectOptionOpcode does explicitly support that โ€” see PLAN.md). This also failed in-game (2026-08-13, same session as the spell fix): no gossip window ever appeared, yet selecting still silently resolved to Ironforge. Every other gossip flow in the game is sourced from an actual Creature/GameObject the player has interacted with; a menu sourced from the player's own character, opened out of nowhere via a chat command, isn't something the client's Gossip UI seems to render correctly, even though the server-side protocol nominally allows it.

Fixed by summoning a real, if short-lived, NPC (npc_waygate_portal, entry 911001, faction 35 โ€” non-hostile to everyone) right next to the player and sourcing the gossip menu from it instead. This is the exhaustively-proven-working path (every vendor/questgiver in the game already validates it), so it carries no such uncertainty. The portal despawns itself after a destination is picked, or after 15 seconds as a safety net if the player never interacts with it (e.g. closes the window).

Waygate Stones

Attunement used to be entirely passive โ€” WaygateNetwork_Player::OnPlayerUpdateZone matched a character's current zone against mod_waygate_network_locations and auto-attuned it, no need to find or interact with anything. As of this version, that's replaced with a real, permanently-spawned Waygate Stone (gameobject_template entries 913001-913074, one per destination, entry = 913000 + destination id) standing at each destination's exact location โ€” a character has to actually find and interact with it (go_waygate_standing_stone::OnGossipHello) to attune, not just clip through the zone border. Fits the Ley Wardens lore tighter (the quest chain's own text already calls these things "standing stones") and makes attunement a deliberate, findable moment rather than an invisible side effect of exploring.

Travel destinations now match the stones' real positions (v1.24) โ€” v1.23's hand-tuned stone positions live in gameobject, but .waygate actually teleports players using mod_waygate_network_locations, which still held each destination's original coordinates. Corrected by setting each destination's position_x/y/z/orientation to a point 1 yard directly in front of its stone (along the stone's own orientation), facing back toward it on arrival โ€” computed directly from the stones' now-current positions, not re-walked by hand. Takes effect immediately via the existing .waygate reload GM command, no server restart needed (unlike stone position/rotation changes themselves, which do need one).

Stone orientation had a real mesh-offset bug, now fixed (v1.25) โ€” the "Ancient Stone Marker" model renders its own front 90 degrees ahead of whatever orientation is stored, confirmed by checking multiple stones after a restart ruled out stale data. Every stone's stored orientation is now offset -90 degrees to compensate, so the model's visual facing matches the direction originally intended by each .gps reading. The destination-offset math above deliberately keeps using the pre-correction direction (already confirmed correct on its own), not this cosmetic fix.

Model: displayId 7789, the real "Ancient Stone Marker" (gameobject_template entry 188469), type = 10 (GAMEOBJECT_TYPE_GOOBER). Two real bugs before landing here:

  1. The original pick โ€” the real "Caverns of Time Standing Stone," displayId 9501 โ€” turned out invalid on this server: .gobject add logged "have invalid displayId (9501), not spawned" for both our clone and the real, unmodified 19501 entry, confirming it wasn't a scripting bug but a missing DBC record โ€” this server's actual loaded GameObjectDisplayInfo.dbc is a reduced client build (~3790 of a normal ~9000+ display records), and 9501 isn't one of them.
  2. The immediate replacement, "Nightelf Stone Rune" (displayId 236), rendered fine but couldn't be interacted with at all โ€” because it's type = 5 (GAMEOBJECT_TYPE_GENERIC), and every real "click this object, run custom logic via OnGossipHello" GameObjectScript already in this codebase (go_southfury_moonstone, go_tele_to_dalaran_crystal, etc.) turned out to use type = 10 (GAMEOBJECT_TYPE_GOOBER) instead. GENERIC is plain, non-interactive scenery โ€” the client most likely never offers a "use" prompt for it at all, so OnGossipHello never had a chance to fire regardless of how correctly it was wired server-side.

Both fixed by "Ancient Stone Marker": displayId 7789 is confirmed present in this server's real DBC, type = 10 matches every real working precedent, and its one non-zero field (Data3 = autoCloseTime, a cosmetic 3-second "activated" reset) is irrelevant here since OnGossipHello returning true suppresses the default open/close behavior before it would ever run. A couple of thematically-tempting Titan-flavored alternates (Titan Relic, The Discs of Norgannon, Ulduar Teleporter) were also considered and rejected along the way โ€” all carry real hidden SmartGameObjectAI/spell-focus/quest-link behavior a plain override isn't guaranteed to fully suppress.

Each of the 74 gets its own dedicated template entry rather than sharing one: the same one-custom-ID-per-spawn pattern already used for this module's NPCs (901000, 911001, 911002-911006), so the C++ side can resolve which destination a given stone represents from its own template entry (go->GetEntry() - WAYGATE_STONE_ENTRY_BASE) rather than its spawn guid or position. Real gameobject.guid values in this client's local DB already run into the millions โ€” too real a collision risk to use as a deterministic per-destination lookup key the way this module's earlier NPC work could safely do with low, self-chosen ranges.

Positioning: every stone originally reused its destination's coordinates verbatim, which themselves were sourced by copying a real landmark NPC's exact position back in the v1.11-v1.14 continent batches โ€” so every stone spawned clipped inside/underneath an NPC, and in three spots (Echo of the Ley Wardens, Windcaller Tyese, The First Warden all sit at a destination's exact coordinates too) inside a Ley Wardens quest NPC as well. Fixed by nudging each stone 3 yards along its destination's own saved orientation, and the three affected quest NPCs 3 yards the opposite way โ€” the original landmark NPC stays exactly where it was, the stone and the quest NPC end up 6 yards apart on either side of it. That first pass was a heuristic, not individually terrain-verified (no vmap/LOS data available to this tooling) โ€” since superseded: every stone has since been individually walked and repositioned by hand in-game (2026-08-21, see "Known v1 limitations" below).

Successfully attuning also plays a one-shot cosmetic flash (SendPlaySpellVisual, WaygateNetwork.AttuneVisualKitId, default kit 3394 โ€” the same real Teleport-family visual kit's ImpactKit already relied on for the travel channel's kit 267, keeping the two moments visually related) plus a one-shot animation (HandleEmoteCommand(EMOTE_ONESHOT_USE_STANDING), the real generic "reach out and use a standing object" gesture) on the player, on top of the existing sound and chat message.

Stones are gated the same way .waygate itself is. Interacting with one before the Ley Wardens chain is complete doesn't attune anything โ€” it opens a gossip popup with in-world flavor text instead ("You feel it the moment your hand touches the stone...", npc_text 911012), pointing toward the Hillsbrad Foothills in a general sense without naming Aemos directly (the .waygate command's own dormant-network message already does that โ€” this is often a character's first hint that anything's going on, before they've ever typed the command, so it stays a level more mysterious). WaygateNetwork.RequireIntroQuest covers both gates together; GM debug mode is the only bypass for either.

OnPlayerUpdateZone still fires on zone-entry, but now only as a hint ("You sense a waygate stone somewhere nearby...") for an un-attuned destination โ€” a nudge, not a trigger. It still repeats every time an un-attuned character re-enters a different un-attuned zone on foot (intentional, not a bug), but two guards keep it from spamming (v1.21): skipped entirely while on a taxi (IsInFlight()) โ€” a single flight crossing several un-attuned destination zones back to back turned out to be the actual source of "several messages in a row" reports, not one zone re-triggering โ€” and deduped against the last destination actually hinted (Player::CustomData, session-scoped, not persisted), so re-entering the same zone doesn't repeat the message.

Continent grouping

Each destination has a continent column (ENUM('Eastern Kingdoms','Kalimdor','Outland','Northrend') in the world DB) that drives the two-page menu โ€” added once the list grew past the original 8 capitals, so a flat list wouldn't keep scaling. This is a curated label, not derived from the raw map column โ€” Exodar and Silvermoon share map = 530 with genuine Outland zones purely as a client-data quirk (their actual continents, Azuremyst Isle and Eversong Woods, got bundled onto that map ID by Blizzard), so grouping by raw map would put them in a nonsensical "Outland" bucket from a player's point of view. They're tagged Kalimdor and Eastern Kingdoms respectively instead โ€” set continent deliberately for any new destination, don't infer it from map.

Faction gating

Each destination also has a faction column (ENUM('Alliance','Horde','Neutral'), default Neutral) so a character can never end up dumped in the middle of an enemy capital just to get jumped by guards. WaygateFactionAllowed checks it against Player::GetTeamId() โ€” an Alliance/ Horde destination is filtered out of the menu (GetSelectableDestinations) and re-checked again in BeginWaygateChannel/FinishWaygateChannel (same "don't trust the gossip action alone" defense the attunement check already uses) for anyone not on that faction; Neutral destinations (the two sanctuary cities, Shattrath and Dalaran) are always open to everyone. The 8 original capitals are tagged Alliance (Stormwind, Ironforge, Darnassus, The Exodar) or Horde (Undercity, Orgrimmar, Thunder Bluff, Silvermoon City) accordingly โ€” set faction deliberately for any new destination, same as continent.

GM debug mode (WaygateNetwork.Debug) is the only override โ€” it already lists/travels to every destination regardless of attunement (see "Admin/debug tooling" in PLAN.md), and that bypass covers faction too, so a GM can still review or test an opposing-faction destination without needing a second character.

Intro quest chain: The Ley Wardens

.waygate doesn't do anything until a character completes a 5-quest chain, mostly dialogue but with one real combat objective. WaygateNetwork.RequireIntroQuest (default on) controls this; GM debug mode is the only other bypass. The check itself is a single guard clause in HandleWaygateCommand: player->GetQuestRewardStatus(QUEST_WAYGATE_REACTIVATION) โ€” no custom CreatureScript hooks needed anywhere in the chain, core's default gossip/quest UI handles a plain accept/turn-in questgiver entirely from creature_queststarter/creature_questender + quest_template*. The one exception is the kill-credit objective on quest 2 (RequiredNpcOrGo1/RequiredNpcOrGoCount1 on quest_template โ€” positive value = creature kill credit, still no custom C++ needed).

Redesigned (2026-08-16) to stay entirely within Eastern Kingdoms and Kalimdor, unlockable early (MinLevel = 15, QuestLevel = 20 โ€” paced so most characters finish around level 20), starting in a zone with both a real Alliance and Horde town nearby. Story: Aemos, a sentient stone construct โ€” the last surviving guardian of the network, newly and only partly reawakened โ€” is found in the Hillsbrad Foothills, the contested no-man's-land between Southshore and Tarren Mill. Deliberately not a member of either faction, so neither side "owns" the lore (AllowableRaces = 0 on every quest). Each quest is accepted from one NPC and turned in to the next leg's NPC rather than doubling back, so the chain is one long trip across the world rather than repeated out-and-back errands, closing with a return to Aemos for the reactivation itself:

  1. The Waygate Stirs โ€” Aemos (Hillsbrad Foothills) โ†’ Windcaller Tyese (Astranaar, Ashenvale)
  2. Roots Older Than the Circle โ€” Windcaller Tyese โ†’ Borin Ironquill (Uldaman, Badlands) โ€” kill The Ironbound Sentinel, a Titan-built earthen guardian that wakes to stop the old ley magic from being surfaced, along the way. The one combat leg in an otherwise dialogue-only chain, and where the "older than the Ley Wardens" reveal lands.
  3. What the Stone Remembers โ€” Borin Ironquill โ†’ The First Warden (Windshear Crag, Stonetalon Mountains)
  4. The Long Way Home โ€” The First Warden โ†’ Aemos (Hillsbrad Foothills)
  5. The Network Reborn โ€” Aemos โ†’ Aemos (the reactivation ritual; completing this grants the unlock)

Coordinates are real and DB-verified, not guessed: Aemos sits clear of the real levelled wildlife that already populates the Hillsbrad no-man's-land (Starving Mountain Lion/Vicious Gray Bear, both 20-23, an apt match for the chain's pace). Borin Ironquill sits a few yards from the real Explorers' League dig camp at Uldaman's entrance (High Explorer Magellas et al.) without overlapping any of them. Windcaller Tyese reuses Waygate destination 28's zone (Astranaar) but is offset ~4 yards from Innkeeper Kimlya, who sits at that destination's exact coordinates โ€” the same overlap this module already fixed once for the Waygate Stones (see "Waygate Stones" below). The First Warden sits a few yards from the real Horde outpost Windshear Crag (Innkeeper Jayka).

Borin Ironquill occupies the NPC slot originally used by "Echo of the Ley Wardens" โ€” repurposed, not newly added, since the "spectral echo" framing didn't fit revealing something older than the Ley Wardens themselves (an echo of the order wouldn't know that). The former fourth leg, "Nazrek the Bent" (the old Outland contact), is retired entirely with no replacement โ€” the new geography only needs three intermediate nodes. The Ironbound Sentinel's stats are modeled directly on Mor'Ladim (creature_template entry 522, Duskwood's real solo-able open-world elite) rather than invented โ€” same HealthModifier/DamageModifier/level/rank โ€” and its display (6026) is reused from the real "Earthen Guardian" creature, which only ever spawns inside the Uldaman instance, so there's no open-world collision risk.

Travel cost

An alternative to flight paths, not a replacement โ€” deliberately priced a bit above a comparable flight so flying is still the better deal for a route you can actually fly. Same-map trips cost WaygateNetwork.CostPerYard copper per yard of straight-line distance from the player's current position to the destination; cross-map trips (different continents) cost a flat WaygateNetwork.CrossMapCostCopper, since straight-line distance isn't meaningful across different coordinate spaces. WaygateNetwork.MinCostCopper is a floor so short hops still cost something.

The defaults are a starting point, not a precise calibration: this client's real TaxiPath.dbc was checked directly (not guessed) โ€” real flight prices range ~50c (Stormwind โ†” Ironforge) to ~12000c for the longest single-continent legs, and aren't a clean function of distance. The default CostPerYard (0.02) puts Stormwind โ†” Ironforge at ~84c, about 1.7x that real 50c price โ€” the one real anchor point actually available. Other routes will drift from that exact ratio. Tune the config values against what you observe in-game rather than trusting these as scientifically calibrated.

Debug mode (WaygateNetwork.Debug, GM-only) travels free โ€” it's for reviewing/testing locations, not for dodging the cost.

Cast time

Picking a destination starts a WaygateNetwork.ChannelMs-long wait (default 4 seconds) before you're actually charged and teleported โ€” no real spell involved at all. It's a plain, fully server-controlled wait: a chat message ("Hold still... the waygate reaches for you."), an optional one-shot cosmetic visual (SendPlaySpellVisual, WaygateNetwork.ChannelVisualKitId), and a looping "channeling" animation on the player (SetEmoteState(EMOTE_STATE_SPELL_CHANNEL_OMNI) โ€” Blizzard's own generic spell-channel stance, cleared unconditionally once the wait ends, success or not) โ€” all purely cosmetic, zero gameplay side effects โ€” plus a timer via the player's own event scheduler (player->m_Events.AddEventAtOffset, BeginWaygateChannel/FinishWaygateChannel). Move away from where the wait started (checked by straight-line distance, allowing 2 yards of slack, plus a same-map check) and it cancels with no charge; entering combat at either end blocks it too. Cost is only charged once the wait actually completes.

This replaced an earlier design that hijacked a real spell's cast bar (first the Mage Teleport: <City> family, then Hearthstone, ID 8690) purely to get a genuine cast bar/interrupt UI for free. It worked in principle โ€” real cast time pulled directly from this client's Spell.dbc, a conditional SpellScript gated on a pending-entry marker so a real cast of the donor spell was never touched โ€” but in-game testing found overriding the donor's actual effect (PreventHitEffect) wasn't reliable: the real Hearthstone "teleport home" effect and its ~30-minute cooldown still fired some of the time despite the guard, in a way that was hard to fully pin down or trust. See PLAN.md's "v1.7"/"v1.8" sections for the full blow-by-blow (including why generic monster "Teleport" spells and other "Casting"/"Channeling"-named spells were checked and ruled out earlier in that exploration). data/sql/db-world/updates/2026_08_15_03.sql removes the now-unused spell_script_names binding that approach had added to spell 8690.

Known v1 limitations

  • WaygateNetwork.ChannelVisualKitId defaults to 267 โ€” real data, not guessed: traced through this client's binary Spell.dbc -> SpellVisual.dbc -> SpellVisualKit.dbc, it's the Mage Teleport: family's actual sustained casting-loop visual (the glowing rune circle spun under the caster's feet while the cast bar fills), in-game confirmed to look right for this use. Preview any other kit in-game (GM-only) with .debug play visual <id> if you want to try alternatives.
  • The portal's model/visual (CreatureDisplayID 26484, reused from existing Alterac Valley Portal content) is a placeholder, not custom-built for this module.
  • No cooldown between attempts beyond the 10s cast time itself and the gold cost.
  • Discovery/menu queries hit acore_characters synchronously (CharacterDatabase.Query, not the async callback pattern) โ€” fine at this server's scale, but not the core's preferred pattern for a hot path.
  • Coin-icon markup (|T...|t) in gossip text hasn't actually been eyeballed in-game yet โ€” same "not verified against a real client" caveat as everything else in this module until you say otherwise.
  • The Ley Wardens quest chain and the Waygate Stones' rendering/interaction are confirmed working end-to-end in-game (2026-08-15).
  • All 74 Waygate Stones have been individually repositioned by hand in-game (2026-08-21, data/sql/db-world/updates/2026_08_21_02.sql) โ€” v1.17's blind 3-yard-offset heuristic is retired; every stone now sits at a real, walked-and-verified position rather than an estimate.

Custom ID ranges

  • Text/data ID 911000 (gossip header npc_text, no creature attached to it directly)
  • Creature ID 911001 (npc_waygate_portal, the summon-only Waygate Portal NPC)
  • Creature IDs 911002-911004, 911006 โ€” the 4 persistently-placed Ley Wardens quest-chain NPCs (Aemos, Borin Ironquill, Windcaller Tyese, The First Warden). 911003 originally held "Echo of the Ley Wardens," repurposed in place into Borin Ironquill rather than retired (see "Intro quest chain" above); 911005 ("Nazrek the Bent") is retired entirely and no longer in use. quest_greeting rows reuse these same entries directly (keyed by NPC entry, not a separate ID range).
  • Creature ID 911007 โ€” "The Ironbound Sentinel," the kill-credit objective on quest 912001.
  • Quest IDs 912000-912099 reserved for this module โ€” 912000-912004 are the five Ley Wardens quests (912005 retired in the 2026-08-16 redesign, not reused), leaving room for a future second chain without renumbering.
  • gameobject_template IDs 913001-913074 โ€” one Waygate Stone per destination (entry = 913000 + mod_waygate_network_locations.id), see "Waygate Stones" above.
  • Text/data ID 911012 (gossip flavor text shown when interacting with a stone before the Ley Wardens chain is complete), continuing the flat 911xxx text/data space alongside 911000.
  • mod_waygate_network_locations IDs 1-8 are reserved for the original capital cities, 9-10 for Shattrath City / Dalaran, 11-27 for the Eastern Kingdoms quest-hub batch, 28-45 for the Kalimdor batch, 46-61 for the Outland batch, 62-74 for the Northrend batch (all referenced by existing mod_waygate_network_discovered rows) โ€” new destinations should start at 75.

Spell ID 910000 (Call Waygate) is retired โ€” see "Why a command, not a spell" above. Its spell_dbc / spell_script_names rows are removed by data/sql/db-world/updates/2026_08_13_01.sql, and any character that had learned it gets it unlearned by data/sql/db-characters/updates/2026_08_13_01.sql. Don't reuse 910000 for anything else without checking those files.

This module doesn't use or reserve any real spell ID anymore โ€” see "Cast time" above for why the earlier Hearthstone-hijack approach (spell ID 8690) was dropped, and data/sql/db-world/updates/2026_08_15_03.sql for the cleanup of the binding it had added.

Config

See conf/mod_waygate_network.conf.dist:

  • WaygateNetwork.Enable (default 1) โ€” toggles the whole module: attuning destinations on zone-enter and the .waygate travel menu.
  • WaygateNetwork.Debug (default 0) โ€” GM-only "show all locations" mode, see above.
  • WaygateNetwork.UnlockSoundId (default 1519, TaxiNodeDiscovered) โ€” SoundEntries.dbc ID played on attunement. Real data, not guessed: traced through this client's binary SoundEntries.dbc, it's Blizzard's own sound for discovering a new flight point โ€” the closest real in-game equivalent to unlocking a new fast-travel destination.
  • WaygateNetwork.AttuneVisualKitId (default 3394) โ€” cosmetic SendPlaySpellVisual flash on attunement, see "Waygate Stones" above.
  • WaygateNetwork.CostPerYard (default 0.02), WaygateNetwork.CrossMapCostCopper (default 20000), WaygateNetwork.MinCostCopper (default 25) โ€” see "Travel cost" above.
  • WaygateNetwork.ChannelMs (default 4000), WaygateNetwork.ChannelVisualKitId (default 267) โ€” see "Cast time" above.
  • WaygateNetwork.RequireIntroQuest (default 1) โ€” gates both .waygate and the Waygate Stones themselves behind the Ley Wardens quest chain, see "Intro quest chain" and "Waygate Stones" above.