mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: implement petition signing flow for guild charter creation
Parse SMSG_PETITION_QUERY_RESPONSE, SMSG_PETITION_SHOW_SIGNATURES, and SMSG_PETITION_SIGN_RESULTS. Add UI to view signatures, sign petitions, and turn in completed charters. Send CMSG_PETITION_SIGN and CMSG_TURN_IN_PETITION packets.
This commit is contained in:
parent
41e15349c5
commit
d149255c58
3 changed files with 197 additions and 1 deletions
|
|
@ -609,6 +609,26 @@ public:
|
|||
uint32_t getPetitionCost() const { return petitionCost_; }
|
||||
uint64_t getPetitionNpcGuid() const { return petitionNpcGuid_; }
|
||||
|
||||
// Petition signatures (guild charter signing flow)
|
||||
struct PetitionSignature {
|
||||
uint64_t playerGuid = 0;
|
||||
std::string playerName; // resolved later or empty
|
||||
};
|
||||
struct PetitionInfo {
|
||||
uint64_t petitionGuid = 0;
|
||||
uint64_t ownerGuid = 0;
|
||||
std::string guildName;
|
||||
uint32_t signatureCount = 0;
|
||||
uint32_t signaturesRequired = 9; // guild default; arena teams differ
|
||||
std::vector<PetitionSignature> signatures;
|
||||
bool showUI = false;
|
||||
};
|
||||
const PetitionInfo& getPetitionInfo() const { return petitionInfo_; }
|
||||
bool hasPetitionSignaturesUI() const { return petitionInfo_.showUI; }
|
||||
void clearPetitionSignaturesUI() { petitionInfo_.showUI = false; }
|
||||
void signPetition(uint64_t petitionGuid);
|
||||
void turnInPetition(uint64_t petitionGuid);
|
||||
|
||||
// Guild name lookup for other players' nameplates
|
||||
// Returns the guild name for a given guildId, or empty if unknown.
|
||||
// Automatically queries the server for unknown guild IDs.
|
||||
|
|
@ -2375,6 +2395,9 @@ private:
|
|||
void handleGuildInvite(network::Packet& packet);
|
||||
void handleGuildCommandResult(network::Packet& packet);
|
||||
void handlePetitionShowlist(network::Packet& packet);
|
||||
void handlePetitionQueryResponse(network::Packet& packet);
|
||||
void handlePetitionShowSignatures(network::Packet& packet);
|
||||
void handlePetitionSignResults(network::Packet& packet);
|
||||
void handlePetSpells(network::Packet& packet);
|
||||
void handleTurnInPetitionResults(network::Packet& packet);
|
||||
|
||||
|
|
@ -2999,6 +3022,7 @@ private:
|
|||
bool showPetitionDialog_ = false;
|
||||
uint32_t petitionCost_ = 0;
|
||||
uint64_t petitionNpcGuid_ = 0;
|
||||
PetitionInfo petitionInfo_;
|
||||
|
||||
uint64_t activeCharacterGuid_ = 0;
|
||||
Race playerRace_ = Race::HUMAN;
|
||||
|
|
|
|||
|
|
@ -7630,9 +7630,13 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
|||
break;
|
||||
}
|
||||
case Opcode::SMSG_PETITION_QUERY_RESPONSE:
|
||||
handlePetitionQueryResponse(packet);
|
||||
break;
|
||||
case Opcode::SMSG_PETITION_SHOW_SIGNATURES:
|
||||
handlePetitionShowSignatures(packet);
|
||||
break;
|
||||
case Opcode::SMSG_PETITION_SIGN_RESULTS:
|
||||
packet.setReadPos(packet.getSize());
|
||||
handlePetitionSignResults(packet);
|
||||
break;
|
||||
|
||||
// ---- Pet system ----
|
||||
|
|
@ -19742,6 +19746,118 @@ void GameHandler::handlePetitionShowlist(network::Packet& packet) {
|
|||
LOG_INFO("Petition showlist: cost=", data.cost);
|
||||
}
|
||||
|
||||
void GameHandler::handlePetitionQueryResponse(network::Packet& packet) {
|
||||
// SMSG_PETITION_QUERY_RESPONSE (3.3.5a):
|
||||
// uint32 petitionEntry, uint64 petitionGuid, string guildName,
|
||||
// string bodyText (empty), uint32 flags, uint32 minSignatures,
|
||||
// uint32 maxSignatures, ...plus more fields we can skip
|
||||
auto rem = [&]() { return packet.getSize() - packet.getReadPos(); };
|
||||
if (rem() < 12) return;
|
||||
|
||||
/*uint32_t entry =*/ packet.readUInt32();
|
||||
uint64_t petGuid = packet.readUInt64();
|
||||
std::string guildName = packet.readString();
|
||||
/*std::string body =*/ packet.readString();
|
||||
|
||||
// Update petition info if it matches our current petition
|
||||
if (petitionInfo_.petitionGuid == petGuid) {
|
||||
petitionInfo_.guildName = guildName;
|
||||
}
|
||||
|
||||
LOG_INFO("SMSG_PETITION_QUERY_RESPONSE: guid=", petGuid, " name=", guildName);
|
||||
packet.setReadPos(packet.getSize()); // skip remaining fields
|
||||
}
|
||||
|
||||
void GameHandler::handlePetitionShowSignatures(network::Packet& packet) {
|
||||
// SMSG_PETITION_SHOW_SIGNATURES (3.3.5a):
|
||||
// uint64 itemGuid (petition item in inventory)
|
||||
// uint64 ownerGuid
|
||||
// uint32 petitionGuid (low part / entry)
|
||||
// uint8 signatureCount
|
||||
// For each signature:
|
||||
// uint64 playerGuid
|
||||
// uint32 unk (always 0)
|
||||
auto rem = [&]() { return packet.getSize() - packet.getReadPos(); };
|
||||
if (rem() < 21) return;
|
||||
|
||||
petitionInfo_ = PetitionInfo{};
|
||||
petitionInfo_.petitionGuid = packet.readUInt64();
|
||||
petitionInfo_.ownerGuid = packet.readUInt64();
|
||||
/*uint32_t petEntry =*/ packet.readUInt32();
|
||||
uint8_t sigCount = packet.readUInt8();
|
||||
|
||||
petitionInfo_.signatureCount = sigCount;
|
||||
petitionInfo_.signatures.reserve(sigCount);
|
||||
|
||||
for (uint8_t i = 0; i < sigCount; ++i) {
|
||||
if (rem() < 12) break;
|
||||
PetitionSignature sig;
|
||||
sig.playerGuid = packet.readUInt64();
|
||||
/*uint32_t unk =*/ packet.readUInt32();
|
||||
petitionInfo_.signatures.push_back(sig);
|
||||
}
|
||||
|
||||
petitionInfo_.showUI = true;
|
||||
LOG_INFO("SMSG_PETITION_SHOW_SIGNATURES: petGuid=", petitionInfo_.petitionGuid,
|
||||
" owner=", petitionInfo_.ownerGuid,
|
||||
" sigs=", sigCount);
|
||||
}
|
||||
|
||||
void GameHandler::handlePetitionSignResults(network::Packet& packet) {
|
||||
// SMSG_PETITION_SIGN_RESULTS (3.3.5a):
|
||||
// uint64 petitionGuid, uint64 playerGuid, uint32 result
|
||||
auto rem = [&]() { return packet.getSize() - packet.getReadPos(); };
|
||||
if (rem() < 20) return;
|
||||
|
||||
uint64_t petGuid = packet.readUInt64();
|
||||
uint64_t playerGuid = packet.readUInt64();
|
||||
uint32_t result = packet.readUInt32();
|
||||
|
||||
switch (result) {
|
||||
case 0: // PETITION_SIGN_OK
|
||||
addSystemChatMessage("Petition signed successfully.");
|
||||
// Increment local count
|
||||
if (petitionInfo_.petitionGuid == petGuid) {
|
||||
petitionInfo_.signatureCount++;
|
||||
PetitionSignature sig;
|
||||
sig.playerGuid = playerGuid;
|
||||
petitionInfo_.signatures.push_back(sig);
|
||||
}
|
||||
break;
|
||||
case 1: // PETITION_SIGN_ALREADY_SIGNED
|
||||
addSystemChatMessage("You have already signed that petition.");
|
||||
break;
|
||||
case 2: // PETITION_SIGN_ALREADY_IN_GUILD
|
||||
addSystemChatMessage("You are already in a guild.");
|
||||
break;
|
||||
case 3: // PETITION_SIGN_CANT_SIGN_OWN
|
||||
addSystemChatMessage("You cannot sign your own petition.");
|
||||
break;
|
||||
default:
|
||||
addSystemChatMessage("Cannot sign petition (error " + std::to_string(result) + ").");
|
||||
break;
|
||||
}
|
||||
LOG_INFO("SMSG_PETITION_SIGN_RESULTS: pet=", petGuid, " player=", playerGuid,
|
||||
" result=", result);
|
||||
}
|
||||
|
||||
void GameHandler::signPetition(uint64_t petitionGuid) {
|
||||
if (!socket || state != WorldState::IN_WORLD) return;
|
||||
network::Packet pkt(wireOpcode(Opcode::CMSG_PETITION_SIGN));
|
||||
pkt.writeUInt64(petitionGuid);
|
||||
pkt.writeUInt8(0); // unk
|
||||
socket->send(pkt);
|
||||
LOG_INFO("Signing petition: ", petitionGuid);
|
||||
}
|
||||
|
||||
void GameHandler::turnInPetition(uint64_t petitionGuid) {
|
||||
if (!socket || state != WorldState::IN_WORLD) return;
|
||||
network::Packet pkt(wireOpcode(Opcode::CMSG_TURN_IN_PETITION));
|
||||
pkt.writeUInt64(petitionGuid);
|
||||
socket->send(pkt);
|
||||
LOG_INFO("Turning in petition: ", petitionGuid);
|
||||
}
|
||||
|
||||
void GameHandler::handleTurnInPetitionResults(network::Packet& packet) {
|
||||
uint32_t result = 0;
|
||||
if (!TurnInPetitionResultsParser::parse(packet, result)) return;
|
||||
|
|
|
|||
|
|
@ -13942,6 +13942,62 @@ void GameScreen::renderGuildRoster(game::GameHandler& gameHandler) {
|
|||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Petition signatures window (shown when a petition item is used or offered)
|
||||
if (gameHandler.hasPetitionSignaturesUI()) {
|
||||
ImGui::OpenPopup("PetitionSignatures");
|
||||
gameHandler.clearPetitionSignaturesUI();
|
||||
}
|
||||
if (ImGui::BeginPopupModal("PetitionSignatures", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
const auto& pInfo = gameHandler.getPetitionInfo();
|
||||
if (!pInfo.guildName.empty())
|
||||
ImGui::Text("Guild Charter: %s", pInfo.guildName.c_str());
|
||||
else
|
||||
ImGui::Text("Guild Charter");
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Signatures: %u / %u", pInfo.signatureCount, pInfo.signaturesRequired);
|
||||
ImGui::Spacing();
|
||||
|
||||
if (!pInfo.signatures.empty()) {
|
||||
for (size_t i = 0; i < pInfo.signatures.size(); ++i) {
|
||||
const auto& sig = pInfo.signatures[i];
|
||||
// Try to resolve name from entity manager
|
||||
std::string sigName;
|
||||
if (sig.playerGuid != 0) {
|
||||
auto entity = gameHandler.getEntityManager().getEntity(sig.playerGuid);
|
||||
if (entity) {
|
||||
auto* unit = dynamic_cast<game::Unit*>(entity.get());
|
||||
if (unit) sigName = unit->getName();
|
||||
}
|
||||
}
|
||||
if (sigName.empty())
|
||||
sigName = "Player " + std::to_string(i + 1);
|
||||
ImGui::BulletText("%s", sigName.c_str());
|
||||
}
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
// If we're not the owner, show Sign button
|
||||
bool isOwner = (pInfo.ownerGuid == gameHandler.getPlayerGuid());
|
||||
if (!isOwner) {
|
||||
if (ImGui::Button("Sign", ImVec2(120, 0))) {
|
||||
gameHandler.signPetition(pInfo.petitionGuid);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
} else if (pInfo.signatureCount >= pInfo.signaturesRequired) {
|
||||
// Owner with enough sigs — turn in
|
||||
if (ImGui::Button("Turn In", ImVec2(120, 0))) {
|
||||
gameHandler.turnInPetition(pInfo.petitionGuid);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
if (ImGui::Button("Close", ImVec2(120, 0)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (!showGuildRoster_) return;
|
||||
|
||||
// Get zone manager for name lookup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue