mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: implement WotLK quest POI query to show objective locations on minimap
Send CMSG_QUEST_POI_QUERY alongside each CMSG_QUEST_QUERY (WotLK only, gated by questLogStride == 5 and opcode availability). Parse the response to extract POI region centroids and add them as GossipPoi markers so the existing minimap rendering shows quest objective locations as cyan diamonds. Each quest POI region is reduced to its centroid point; markers for the current map only are shown. This gives players visual guidance for where to go for active quests directly on the minimap.
This commit is contained in:
parent
12aa5e01b6
commit
6f5bdb2e91
2 changed files with 78 additions and 0 deletions
|
|
@ -1618,6 +1618,7 @@ private:
|
|||
void handleGossipMessage(network::Packet& packet);
|
||||
void handleQuestgiverQuestList(network::Packet& packet);
|
||||
void handleGossipComplete(network::Packet& packet);
|
||||
void handleQuestPoiQueryResponse(network::Packet& packet);
|
||||
void handleQuestDetails(network::Packet& packet);
|
||||
void handleQuestRequestItems(network::Packet& packet);
|
||||
void handleQuestOfferReward(network::Packet& packet);
|
||||
|
|
|
|||
|
|
@ -5767,6 +5767,8 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
|||
case Opcode::SMSG_RESPOND_INSPECT_ACHIEVEMENTS:
|
||||
case Opcode::SMSG_PLAYER_SKINNED:
|
||||
case Opcode::SMSG_QUEST_POI_QUERY_RESPONSE:
|
||||
handleQuestPoiQueryResponse(packet);
|
||||
break;
|
||||
case Opcode::SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA:
|
||||
case Opcode::SMSG_RESET_RANGED_COMBAT_TIMER:
|
||||
case Opcode::SMSG_PROFILEDATA_RESPONSE:
|
||||
|
|
@ -14883,9 +14885,84 @@ bool GameHandler::requestQuestQuery(uint32_t questId, bool force) {
|
|||
pkt.writeUInt32(questId);
|
||||
socket->send(pkt);
|
||||
pendingQuestQueryIds_.insert(questId);
|
||||
|
||||
// WotLK supports CMSG_QUEST_POI_QUERY to get objective map locations.
|
||||
// Only send if the opcode is mapped (stride==5 means WotLK).
|
||||
if (packetParsers_ && packetParsers_->questLogStride() == 5) {
|
||||
const uint32_t wirePoiQuery = wireOpcode(Opcode::CMSG_QUEST_POI_QUERY);
|
||||
if (wirePoiQuery != 0xFFFF) {
|
||||
network::Packet poiPkt(static_cast<uint16_t>(wirePoiQuery));
|
||||
poiPkt.writeUInt32(1); // count = 1
|
||||
poiPkt.writeUInt32(questId);
|
||||
socket->send(poiPkt);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameHandler::handleQuestPoiQueryResponse(network::Packet& packet) {
|
||||
// WotLK 3.3.5a SMSG_QUEST_POI_QUERY_RESPONSE format:
|
||||
// uint32 questCount
|
||||
// per quest:
|
||||
// uint32 questId
|
||||
// uint32 poiCount
|
||||
// per poi:
|
||||
// uint32 poiId
|
||||
// int32 objIndex (-1 = no specific objective)
|
||||
// uint32 mapId
|
||||
// uint32 areaId
|
||||
// uint32 floorId
|
||||
// uint32 unk1
|
||||
// uint32 unk2
|
||||
// uint32 pointCount
|
||||
// per point: int32 x, int32 y
|
||||
if (packet.getSize() - packet.getReadPos() < 4) return;
|
||||
const uint32_t questCount = packet.readUInt32();
|
||||
for (uint32_t qi = 0; qi < questCount; ++qi) {
|
||||
if (packet.getSize() - packet.getReadPos() < 8) return;
|
||||
const uint32_t questId = packet.readUInt32();
|
||||
const uint32_t poiCount = packet.readUInt32();
|
||||
for (uint32_t pi = 0; pi < poiCount; ++pi) {
|
||||
if (packet.getSize() - packet.getReadPos() < 28) return;
|
||||
packet.readUInt32(); // poiId
|
||||
packet.readUInt32(); // objIndex (int32)
|
||||
const uint32_t mapId = packet.readUInt32();
|
||||
packet.readUInt32(); // areaId
|
||||
packet.readUInt32(); // floorId
|
||||
packet.readUInt32(); // unk1
|
||||
packet.readUInt32(); // unk2
|
||||
const uint32_t pointCount = packet.readUInt32();
|
||||
if (pointCount == 0) continue;
|
||||
if (packet.getSize() - packet.getReadPos() < pointCount * 8) return;
|
||||
// Compute centroid of the poi region to place a minimap marker.
|
||||
float sumX = 0.0f, sumY = 0.0f;
|
||||
for (uint32_t pt = 0; pt < pointCount; ++pt) {
|
||||
const int32_t px = static_cast<int32_t>(packet.readUInt32());
|
||||
const int32_t py = static_cast<int32_t>(packet.readUInt32());
|
||||
sumX += static_cast<float>(px);
|
||||
sumY += static_cast<float>(py);
|
||||
}
|
||||
// POI points in WotLK are zone-level coordinates.
|
||||
// Skip POIs for maps other than the player's current map.
|
||||
if (mapId != currentMapId_) continue;
|
||||
// Find the quest title for the marker label.
|
||||
std::string questTitle;
|
||||
for (const auto& q : questLog_) {
|
||||
if (q.questId == questId) { questTitle = q.title; break; }
|
||||
}
|
||||
// Add as a GossipPoi so the existing minimap code displays it.
|
||||
GossipPoi poi;
|
||||
poi.x = sumX / static_cast<float>(pointCount); // WoW canonical X (north)
|
||||
poi.y = sumY / static_cast<float>(pointCount); // WoW canonical Y (west)
|
||||
poi.icon = 6; // generic POI icon
|
||||
poi.name = questTitle.empty() ? "Quest objective" : questTitle;
|
||||
gossipPois_.push_back(std::move(poi));
|
||||
LOG_DEBUG("Quest POI: questId=", questId, " mapId=", mapId,
|
||||
" centroid=(", poi.x, ",", poi.y, ") title=", poi.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameHandler::handleQuestDetails(network::Packet& packet) {
|
||||
QuestDetailsData data;
|
||||
bool ok = packetParsers_ ? packetParsers_->parseQuestDetails(packet, data)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue