neutral faction ui

This commit is contained in:
luis
2026-05-22 15:11:13 -03:00
parent bdd1d3681c
commit c8dfdfe960
11 changed files with 216 additions and 3 deletions
@@ -33875,3 +33875,9 @@ void Player::SendCtrOptions() const
ctrOptions.ChromieTimeExpansionMask = m_playerData->CtrOptions->ChromieTimeExpansionMask;
SendDirectMessage(ctrOptions.Write());
}
void Player::ShowNeutralPlayerFactionSelectUI()
{
WorldPackets::Misc::FactionSelectUI packet;
GetSession()->SendPacket(packet.Write());
}
+3
View File
@@ -2140,6 +2140,9 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits::TraitConfig const& newConfig, bool applyTraits, bool consumeCurrencies);
void RenameTraitConfig(int32 editedConfigId, std::string&& newName);
void DeleteTraitConfig(int32 deletedConfigId);
void ShowNeutralPlayerFactionSelectUI();
void ApplyTraitConfig(int32 configId, bool apply);
void ApplyTraitEntry(int32 traitNodeEntryId, int32 rank, int32 grantedRanks, bool apply);
void SetActiveCombatTraitConfigID(int32 traitConfigId) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ActiveCombatTraitConfigID), traitConfigId); }
+135
View File
@@ -1285,3 +1285,138 @@ void WorldSession::HandleCovenantRenownRequestCatchupState(WorldPackets::MajorFa
SendPacket(response.Write());
}
void WorldSession::HandleSelectFactionOpcode(WorldPackets::Misc::FactionSelect& selectFaction)
{
if (!_player)
return;
enum FactionSelection
{
JOIN_HORDE = 0,
JOIN_ALLIANCE = 1,
SPELL_TRIGGER_FACTION_CHOICE_ALLIANCE = 113244,
SPELL_TRIGGER_FACTION_CHOICE_HORDE = 113245
};
TC_LOG_INFO("entities.player", "HandleSelectFactionOpcode: Player {} (GUID: {}) attempting to select faction: {}",
_player ? _player->GetName() : "<null>",
_player ? _player->GetGUID().ToString() : "<null>",
selectFaction.FactionChoice);
if (_player->GetRace() != RACE_PANDAREN_NEUTRAL)
{
TC_LOG_WARN("entities.player", "HandleSelectFactionOpcode: Player {} (GUID: {}) is not neutral pandaren (race: {}), rejecting faction selection",
_player ? _player->GetName() : "<null>",
_player ? _player->GetGUID().ToString() : "<null>",
_player ? _player->GetRace() : 0);
// Send error result to client
WorldPackets::Character::NeutralPlayerFactionSelectResult result;
result.Success = false;
result.NewRaceID = _player ? _player->GetRace() : 0;
_player->GetSession()->SendPacket(result.Write());
return;
}
if (selectFaction.FactionChoice > JOIN_ALLIANCE)
{
TC_LOG_WARN("entities.player", "HandleSelectFactionOpcode: Player {} (GUID: {}) sent invalid faction choice: {}",
_player->GetName(), _player->GetGUID().ToString(), selectFaction.FactionChoice);
// Send error result to client
WorldPackets::Character::NeutralPlayerFactionSelectResult result;
result.Success = false;
result.NewRaceID = _player->GetRace();
_player->GetSession()->SendPacket(result.Write());
return;
}
// Additional validation: check if player already has a faction (shouldn't happen but safety check)
if (_player->GetRace() == RACE_PANDAREN_ALLIANCE || _player->GetRace() == RACE_PANDAREN_HORDE)
{
TC_LOG_WARN("entities.player", "HandleSelectFactionOpcode: Player {} (GUID: {}) already has faction (race: {}), rejecting faction selection",
_player->GetName(), _player->GetGUID().ToString(), _player->GetRace());
// Send error result to client
WorldPackets::Character::NeutralPlayerFactionSelectResult result;
result.Success = false;
result.NewRaceID = _player->GetRace();
_player->GetSession()->SendPacket(result.Write());
return;
}
Races newRace = RACE_NONE;
uint32 languageSpell1 = 0;
uint32 languageSpell2 = 0;
uint32 triggerSpell = 0;
switch (selectFaction.FactionChoice)
{
case JOIN_ALLIANCE:
newRace = RACE_PANDAREN_ALLIANCE;
languageSpell1 = SPELL_LEARN_LANGUAGE_COMMON;
languageSpell2 = SPELL_LEARN_LANGUAGE_PANDAREN_ALLIANCE;
triggerSpell = SPELL_TRIGGER_FACTION_CHOICE_ALLIANCE;
break;
case JOIN_HORDE:
newRace = RACE_PANDAREN_HORDE;
languageSpell1 = SPELL_LEARN_LANGUAGE_ORCISH;
languageSpell2 = SPELL_LEARN_LANGUAGE_PANDAREN_HORDE;
triggerSpell = SPELL_TRIGGER_FACTION_CHOICE_HORDE;
break;
default:
break;
}
_player->SetRace(newRace);
_player->SetFactionForRace(newRace);
_player->SaveToDB();
_player->LearnSpell(languageSpell1, false);
_player->LearnSpell(languageSpell2, false);
_player->CastSpell(_player, triggerSpell, true);
// Force client to refresh all reputation factions or sides
uint32 headerFactionId = (newRace == RACE_PANDAREN_ALLIANCE) ? 469 : 67;
for (FactionEntry const* fe : sFactionStore)
{
if (!fe->CanHaveReputation())
continue;
if (fe->ParentFactionID != headerFactionId)
continue;
_player->GetReputationMgr().SetVisible(fe);
int32 base = fe->ReputationBase[0];
// Apply the base reputation
_player->GetReputationMgr().SetOneFactionReputation(fe, base, false);
// Get the updated state
FactionState* fs = const_cast<FactionState*>(_player->GetReputationMgr().GetState(fe));
if (!fs)
continue;
// Mark for sending
fs->needSend = true;
// Trigger the system messages
fs->VisualStandingIncrease = base;
// Send the update
_player->GetReputationMgr().SendState(fs);
}
const char* sideName = (selectFaction.FactionChoice == 0) ? "Horde" : "Alliance";
TC_LOG_INFO("entities.player", "HandleSelectFactionOpcode: Player {} (GUID: {}) successfully joined {}",
_player->GetName(), _player->GetGUID().ToString(), sideName);
// Send success result to client
WorldPackets::Character::NeutralPlayerFactionSelectResult result;
result.Success = true;
result.NewRaceID = newRace;
_player->GetSession()->SendPacket(result.Write());
}
@@ -923,5 +923,14 @@ namespace WorldPackets::Character
_worldPacket >> SizedString::Data(group.Name);
}
}
WorldPacket const* NeutralPlayerFactionSelectResult::Write()
{
_worldPacket << NewRaceID;
_worldPacket >> Bits<1>(Success);
_worldPacket.FlushBits();
return &_worldPacket;
}
//WowCommunity
}
@@ -933,6 +933,17 @@ namespace WorldPackets
std::vector<WarbandGroupSetup> Groups;
};
class NeutralPlayerFactionSelectResult final : public ServerPacket
{
public:
NeutralPlayerFactionSelectResult() : ServerPacket(SMSG_NEUTRAL_PLAYER_FACTION_SELECT_RESULT, 4 + 1) {}
WorldPacket const* Write() override;
uint32 NewRaceID = 0;
bool Success = false;
};
}
}
@@ -924,4 +924,9 @@ WorldPacket const* SetCtrOptions::Write()
return &_worldPacket;
}
void WorldPackets::Misc::FactionSelect::Read()
{
_worldPacket >> FactionChoice;
}
}
@@ -1149,6 +1149,23 @@ namespace WorldPackets
uint32 ChromieTimeExpansionMask = 0;
};
class FactionSelect final : public ClientPacket
{
public:
FactionSelect(WorldPacket&& packet) : ClientPacket(CMSG_NEUTRAL_PLAYER_SELECT_FACTION, std::move(packet)) {}
void Read() override;
uint8 FactionChoice = 0;
};
class FactionSelectUI final : public ServerPacket
{
public:
FactionSelectUI() : ServerPacket(SMSG_SHOW_NEUTRAL_PLAYER_FACTION_SELECT_UI, 0) {}
WorldPacket const* Write() override { return &_worldPacket; }
};
}
}
+3 -3
View File
@@ -857,7 +857,7 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_NEIGHBORHOOD_REMOVE_SECONDARY_OWNER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNeighborhoodRemoveSecondaryOwner);
DEFINE_HANDLER(CMSG_NEIGHBORHOOD_SET_PUBLIC_FLAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNeighborhoodSetPublicFlag);
DEFINE_HANDLER(CMSG_NEIGHBORHOOD_UPDATE_NAME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNeighborhoodUpdateName);
DEFINE_HANDLER(CMSG_NEUTRAL_PLAYER_SELECT_FACTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_NEUTRAL_PLAYER_SELECT_FACTION, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSelectFactionOpcode);
DEFINE_HANDLER(CMSG_NEXT_CINEMATIC_CAMERA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNextCinematicCamera);
DEFINE_HANDLER(CMSG_NPC_CRAFTING_ORDER_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_OBJECT_UPDATE_FAILED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleObjectUpdateFailedOpcode);
@@ -2132,7 +2132,7 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEIGHBORHOOD_REMOVE_SECONDARY_OWNER_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEIGHBORHOOD_ROSTER_RESIDENT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEIGHBORHOOD_UPDATE_NAME_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEUTRAL_PLAYER_FACTION_SELECT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEUTRAL_PLAYER_FACTION_SELECT_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_DATA_BUILD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD, STATUS_NEVER, CONNECTION_TYPE_REALM);
@@ -2426,7 +2426,7 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHIPMENT_FACTION_UPDATE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_DELVES_COMPANION_CONFIGURATION_UI, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_DELVES_DISPLAY_UI, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_NEUTRAL_PLAYER_FACTION_SELECT_UI, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_NEUTRAL_PLAYER_FACTION_SELECT_UI, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_QUEST_COMPLETION_TEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_TAXI_NODES, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_TRADE_SKILL_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+2
View File
@@ -743,6 +743,7 @@ namespace WorldPackets
class RequestLatestSplashScreen;
class QueryCountdownTimer;
class SetCurrencyFlags;
class FactionSelect;
class RequestCurrencyDataForAccountCharacters;
class TransferCurrencyFromAccountCharacter;
class GetCharacterCurrencyTransferLog;
@@ -2241,6 +2242,7 @@ class TC_GAME_API WorldSession
void HandleKeyboundOverride(WorldPackets::Spells::KeyboundOverride& keyboundOverride);
void HandleQueryCountdownTimer(WorldPackets::Misc::QueryCountdownTimer& queryCountdownTimer);
void HandleSetCurrencyFlags(WorldPackets::Misc::SetCurrencyFlags const& setCurrenctFlags);
void HandleSelectFactionOpcode(WorldPackets::Misc::FactionSelect& selectFaction);
// Adventure Journal
void HandleAdventureJournalOpenQuest(WorldPackets::AdventureJournal::AdventureJournalOpenQuest& openQuest);
+8
View File
@@ -268,6 +268,14 @@ enum SpellFacingFlags
SPELL_FACING_FLAG_INFRONT = 0x0001
};
enum SpellLearnLanguage
{
SPELL_LEARN_LANGUAGE_COMMON = 668,
SPELL_LEARN_LANGUAGE_ORCISH = 669,
SPELL_LEARN_LANGUAGE_PANDAREN_ALLIANCE = 108130,
SPELL_LEARN_LANGUAGE_PANDAREN_HORDE = 108131
};
enum TriggerCastFlags : uint32
{
TRIGGERED_NONE = 0x00000000, //!< Not triggered
@@ -1669,6 +1669,22 @@ private:
};
}
// 108897 - Pandaren Faction Choice
class spell_pandaren_faction_choice : public SpellScript
{
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
if (caster->IsPlayer())
caster->ToPlayer()->ShowNeutralPlayerFactionSelectUI();
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_pandaren_faction_choice::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_zone_the_wandering_isle()
{
using namespace Scripts::Pandaria::TheWanderingIsle;
@@ -1708,4 +1724,5 @@ void AddSC_zone_the_wandering_isle()
RegisterSpellScript(spell_flying_shadow_kick);
RegisterCreatureAI(npc_delivery_cart);
RegisterSpellScript(spell_pandaren_faction_choice);
}