Route housing maps (2735/2736) to per-neighborhood instances instead of
falling through to shared world map path. This connects the existing
HousingMgr/NeighborhoodMgr backend to the actual map creation pipeline.
- Add MapEntry::IsNeighborhood() for MAP_HOUSE_NEIGHBORHOOD detection
- Add MapManager::CreateHousing() factory and housing branch in
CreateMap()/FindInstanceIdForPlayer() with auto-assignment via
FindOrCreateTutorialNeighborhood()
- Fix HousingMap GUID mismatch (HighGuid::Uniq -> HighGuid::Housing)
so LoadNeighborhoodData() resolves the neighborhood pointer correctly
- Make housing maps persistent (m_unloadTimer=0)
- Add AddPlayerToMap/RemovePlayerFromMap overrides for resident tracking
- Implement LoadGridObjects to dynamically spawn For Sale Sign (417487)
on empty plots and Cornerstone (457142) on owned plots
- Fix HandleNeighborhoodOpenCornerstoneUI stub with real neighborhood/
plot data lookup by matching cornerstone GO position to plot index
- Add 50% occupation expansion: auto-create new public neighborhoods
when all existing ones for a faction reach 28/55 plots occupied
- Replace hardcoded neighborhood names with GenerateNeighborhoodName()
- Remove static cornerstone SQL spawns (now dynamic per-neighborhood)
The GAMEOBJECT_TYPE_UI_LINK handler only mapped UILinkType values 0-3
to PlayerInteractionType via a hardcoded switch. UILinkType is deprecated
in favor of the PlayerInteractionType field (Data[7]) which allows
direct mapping to any PlayerInteractionType enum value.
When PlayerInteractionType (Data[7]) is set, send
SMSG_NPC_INTERACTION_OPEN_RESULT with the GO's GUID and the specified
interaction type. Also cast UILink.spell (Data[8]) when present, which
is required for interactions like Cornerstones that need a placement
spell to trigger the client UI.
Fixes Cornerstones (Data[7]=70, spell 1266097) and Bulletin Boards
(Data[7]=72) not opening their respective housing UIs.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
The client's IsSellAllJunkEnabled requires PlayerInteractionManager+48 to be
set to Merchant(5). NIOR(Merchant) case 5 queues a UI event that sets this
field, but it does not set it synchronously during packet processing. When
VendorInventory was sent in the same flush as NIOR, MerchantFrame opened
before the event fired, so PIM+48 was not yet 5 and IsSellAllJunkEnabled
returned false.
Fix: On gossip vendor click, send only NIOR(Merchant) and start the
interaction. The client event handler sets PIM+48, opens MerchantFrame,
which then sends CMSG_LIST_INVENTORY to fetch vendor data in a second
round-trip. Also handle direct CMSG_LIST_INVENTORY (non-gossip vendors)
by sending NIOR first if the interaction is not yet started.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
Send SMSG_NPC_INTERACTION_OPEN_RESULT with PlayerInteractionType::Merchant
from the gossip handler instead of from SendListInventory. This sets PIM+48
to the value the client expects for IsSellAllJunkEnabled() without causing
an infinite CMSG_LIST_INVENTORY loop (the client's MerchantFrame OnShow
re-requests the item list, which would re-trigger NIOR if placed inside
SendListInventory).
Also closes the gossip dialog before opening the vendor frame, matching
the PetitionVendor pattern.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
Adds the source code for the road network navigation system:
- RoadNetworkManager: Loads and manages road graph data per map
- RoadGraphPathfinder: A* pathfinding on the road graph with
spatial index acceleration for nearest-node lookups
- RoadSpatialIndex: Grid-based spatial index for fast node queries
- RoadNetworkTypes: Shared type definitions (nodes, edges, paths)
Companion to 41e62e15a4 which added the road network data files.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>