diff --git a/.gitignore b/.gitignore index 7dbed8f..c7cfe74 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ CMakeLists.txt.user *.BACKUP.* *.BASE.* *.LOCAL.* +*.zip +CFBG_GUIDE.txt diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 6e4ad7a..e16c79c 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -317,7 +317,7 @@ inline void Battleground::_CheckSafePositions(uint32 diff) if (Player* player = ObjectAccessor::FindPlayer(itr->first)) { player->GetPosition(&pos); - GetTeamStartLoc(player->GetBGTeam(), x, y, z, o); + GetTeamStartLoc(player->GetTeam(), x, y, z, o); if (pos.GetExactDistSq(x, y, z) > maxDist) { TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "BATTLEGROUND: Sending %s back to start location (map: %u) (possible exploit)", player->GetName().c_str(), GetMapId()); @@ -523,7 +523,7 @@ inline void Battleground::_ProcessJoin(uint32 diff) WorldPacket status; BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(m_TypeID, GetArenaType()); uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), player->GetTeam()); player->SendDirectMessage(&status); player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); @@ -704,12 +704,32 @@ void Battleground::RewardHonorToTeam(uint32 Honor, uint32 TeamID) UpdatePlayerScore(player, SCORE_BONUS_HONOR, Honor); } -void Battleground::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID) +void Battleground::RewardReputationToTeam(uint32 a_faction_id, uint32 h_faction_id, uint32 Reputation, uint32 teamId) { - if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id)) - for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - if (Player* player = _GetPlayerForTeam(TeamID, itr, "RewardReputationToTeam")) - player->GetReputationMgr().ModifyReputation(factionEntry, Reputation); + FactionEntry const* a_factionEntry = sFactionStore.LookupEntry(a_faction_id); + FactionEntry const* h_factionEntry = sFactionStore.LookupEntry(h_faction_id); + + if (!a_factionEntry || !h_factionEntry) + return; + + for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + if (itr->second.OfflineRemoveTime) + continue; + + Player* plr = ObjectAccessor::FindPlayer(itr->first); + + if (!plr) + { + sLog->outError(LOG_FILTER_GENERAL, "BattleGround:RewardReputationToTeam: %u not found!", itr->first); + continue; + } + + uint32 team = plr->GetTeam(); + + if (team == teamId) + plr->GetReputationMgr().ModifyReputation(plr->GetOTeam() == ALLIANCE ? a_factionEntry : h_factionEntry, Reputation); + } } void Battleground::UpdateWorldState(uint32 Field, uint32 Value) @@ -1016,7 +1036,7 @@ void Battleground::EndBattleground(uint32 winner) player->SendDirectMessage(&pvpLogData); WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), player->GetTeam()); player->SendDirectMessage(&data); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } @@ -1163,6 +1183,7 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac if (player) { + player->FitPlayerInTeam(false, this); // Do next only if found in battleground player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. // reset destination bg team @@ -1229,7 +1250,7 @@ void Battleground::AddPlayer(Player* player) // score struct must be created in inherited class uint64 guid = player->GetGUID(); - uint32 team = player->GetBGTeam(); + uint32 team = player->GetTeam(); BattlegroundPlayer bp; bp.OfflineRemoveTime = 0; @@ -1295,6 +1316,8 @@ void Battleground::AddPlayer(Player* player) // setup BG group membership PlayerAddedToBGCheckIfBGIsRunning(player); AddOrSetPlayerToCorrectBgGroup(player, team); + + player->FitPlayerInTeam(true, this); } // this method adds player to his team's bg group, or sets his correct group if player is already in bg group @@ -1364,8 +1387,8 @@ void Battleground::EventPlayerLoggedOut(Player* player) // 1 player is logging out, if it is the last, then end arena! if (isArena()) - if (GetAlivePlayersCountByTeam(player->GetBGTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetBGTeam()))) - EndBattleground(GetOtherTeam(player->GetBGTeam())); + if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam()))) + EndBattleground(GetOtherTeam(player->GetTeam())); } } @@ -1958,7 +1981,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player) sBattlegroundMgr->BuildPvpLogDataPacket(&data, this); player->SendDirectMessage(&data); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetTeam()); player->SendDirectMessage(&data); } diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 1f18054..67e0123 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -432,7 +432,7 @@ class Battleground void CastSpellOnTeam(uint32 SpellID, uint32 TeamID); void RemoveAuraOnTeam(uint32 SpellID, uint32 TeamID); void RewardHonorToTeam(uint32 Honor, uint32 TeamID); - void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID); + void RewardReputationToTeam(uint32 a_faction_id, uint32 h_faction_id, uint32 Reputation, uint32 teamId); void UpdateWorldState(uint32 Field, uint32 Value); void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player* player); void EndBattleground(uint32 winner); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index efd7e0f..f2a5409 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -282,7 +282,7 @@ void BattlegroundMgr::BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg) Player* player = ObjectAccessor::FindPlayer(itr2->first); uint32 team = bg->GetPlayerTeam(itr2->first); if (!team && player) - team = player->GetBGTeam(); + team = player->GetTeam(); *data << uint8(team == ALLIANCE ? 1 : 0); // green or yellow } *data << uint32(itr2->second->DamageDone); // damage done @@ -892,7 +892,7 @@ void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, Batt { float x, y, z, O; uint32 mapid = bg->GetMapId(); - uint32 team = player->GetBGTeam(); + uint32 team = player->GetTeam(); if (team == 0) team = player->GetTeam(); diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index e52d64a..904eac5 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -154,6 +154,10 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, Battlegr index += BG_TEAMS_COUNT; if (ginfo->Team == HORDE) index++; + + if (sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED) && ArenaType == 0) + index = BG_QUEUE_MIXED; // BG_QUEUE_*_* -> BG_QUEUE_MIXED + TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "Adding Group to BattlegroundQueue bgTypeId : %u, bracket_id : %u, index : %u", BgTypeId, bracketId, index); uint32 lastOnlineTime = getMSTime(); @@ -199,31 +203,56 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, Battlegr { if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(ginfo->BgTypeId)) { - char const* bgName = bg->GetName(); - uint32 MinPlayers = bg->GetMinPlayersPerTeam(); - uint32 qHorde = 0; - uint32 qAlliance = 0; - uint32 q_min_level = bracketEntry->minLevel; - uint32 q_max_level = bracketEntry->maxLevel; - GroupsQueueType::const_iterator itr; - for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr) - if (!(*itr)->IsInvitedToBGInstanceGUID) - qAlliance += (*itr)->Players.size(); - for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr) - if (!(*itr)->IsInvitedToBGInstanceGUID) - qHorde += (*itr)->Players.size(); - - // Show queue status to player only (when joining queue) - if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) + if (sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED)) { - ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level, - qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0); + char const* bgName = bg->GetName(); + uint32 MinPlayers = bg->GetMinPlayersPerTeam()*2; + uint32 qPlayers = 0; + uint32 q_min_level = bracketEntry->minLevel; + uint32 q_max_level = bracketEntry->maxLevel; + for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracketId][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_MIXED].end(); ++itr) + if (!(*itr)->IsInvitedToBGInstanceGUID) + qPlayers += (*itr)->Players.size(); + + if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) + { + ChatHandler(leader->GetSession()).PSendSysMessage("Queue status for %s (Lvl: %u to %u) Queued players: %u (Need at least %u more)", bgName, q_min_level, q_max_level, qPlayers, MinPlayers - qPlayers); + } + else + { + std::ostringstream ss; + ss << "|cffff0000[BG Queue Announcer]:|r " << bgName << " -- [" << q_min_level << "-" << q_max_level << "] " << qPlayers << "/" << MinPlayers; + sWorld->SendGlobalText(ss.str().c_str(), NULL); + } } - // System message else { - sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level, - qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0); + char const* bgName = bg->GetName(); + uint32 MinPlayers = bg->GetMinPlayersPerTeam(); + uint32 qHorde = 0; + uint32 qAlliance = 0; + uint32 q_min_level = bracketEntry->minLevel; + uint32 q_max_level = bracketEntry->maxLevel; + GroupsQueueType::const_iterator itr; + for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr) + if (!(*itr)->IsInvitedToBGInstanceGUID) + qAlliance += (*itr)->Players.size(); + for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr) + if (!(*itr)->IsInvitedToBGInstanceGUID) + qHorde += (*itr)->Players.size(); + + // Show queue status to player only (when joining queue) + if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) + { + ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level, + qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0); + } + // System message + else + { + sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level, + qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0); + } } } } @@ -310,7 +339,7 @@ void BattlegroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount) { //we must check premade and normal team's queue - because when players from premade are joining bg, //they leave groupinfo so we can't use its players size to find out index - for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_TEAMS_COUNT) + for (uint8 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j) { GroupsQueueType::iterator k = m_QueuedGroups[bracket_id_tmp][j].begin(); for (; k != m_QueuedGroups[bracket_id_tmp][j].end(); ++k) @@ -499,6 +528,10 @@ void BattlegroundQueue::FillPlayersToBG(Battleground* bg, BattlegroundBracketId int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE); int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE); + if (!bg->isArena()) + if (FillXPlayersToBG(bracket_id, bg, false)) + return; + //iterator for iterating through bg queue GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); //count of groups in queue - used to stop cycles @@ -747,7 +780,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp if (m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() && m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() && - m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty()) + m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty() && + m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].empty()) return; // battleground with free slot for player should be always in the beggining of the queue @@ -838,7 +872,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp { // if there are enough players in pools, start new battleground or non rated arena if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam) - || (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam))) + || (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam)) + || CheckCrossFactionMatch(bracket_id, bg_template)) { // we successfully created a pool Battleground* bg2 = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenaType, false); diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h index 0595d73..124b43b 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.h +++ b/src/server/game/Battlegrounds/BattlegroundQueue.h @@ -42,6 +42,7 @@ struct GroupQueueInfo // stores informatio { std::map Players; // player queue info map uint32 Team; // Player team (ALLIANCE/HORDE) + uint32 OTeam; // Player team (ALLIANCE/HORDE) BattlegroundTypeId BgTypeId; // battleground type id bool IsRated; // rated uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG @@ -60,9 +61,10 @@ enum BattlegroundQueueGroupTypes BG_QUEUE_PREMADE_ALLIANCE = 0, BG_QUEUE_PREMADE_HORDE = 1, BG_QUEUE_NORMAL_ALLIANCE = 2, - BG_QUEUE_NORMAL_HORDE = 3 + BG_QUEUE_NORMAL_HORDE = 3, + BG_QUEUE_MIXED = 4 }; -#define BG_QUEUE_GROUP_TYPES_COUNT 4 +#define BG_QUEUE_GROUP_TYPES_COUNT 5 class Battleground; class BattlegroundQueue @@ -74,6 +76,11 @@ class BattlegroundQueue void BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType = 0, bool isRated = false, uint32 minRating = 0); void UpdateEvents(uint32 diff); + bool FillXPlayersToBG(BattlegroundBracketId bracket_id, Battleground* bg, bool start = false); + typedef std::multimap QueuedGroupMap; + int32 PreAddPlayers(QueuedGroupMap m_PreGroupMap, int32 MaxAdd, uint32 MaxInTeam); + bool CheckCrossFactionMatch(BattlegroundBracketId bracket_id, Battleground* bg); + void FillPlayersToBG(Battleground* bg, BattlegroundBracketId bracket_id); bool CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam); bool CheckNormalMatch(Battleground* bg_template, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index da292d0..06bd8fa 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -123,7 +123,7 @@ void BattlegroundAB::PostUpdateImpl(uint32 diff) if (m_ReputationScoreTics[team] >= m_ReputationTics) { - (team == TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); + RewardReputationToTeam(509, 510, 10, team == ALLIANCE ? ALLIANCE : HORDE); m_ReputationScoreTics[team] -= m_ReputationTics; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index f8c9e88..afe5048 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -77,7 +77,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) if (entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) { CastSpellOnTeam(23658, HORDE); //this is a spell which finishes a quest where a player has to kill the boss - RewardReputationToTeam(729, BG_AV_REP_BOSS, HORDE); + RewardReputationToTeam(729, 730, BG_AV_REP_BOSS, killer->GetTeam() == ALLIANCE ? ALLIANCE : HORDE); RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS), HORDE); EndBattleground(HORDE); DelCreature(AV_CPLACE_TRIGGER17); @@ -85,7 +85,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) else if (entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) { CastSpellOnTeam(23658, ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss - RewardReputationToTeam(730, BG_AV_REP_BOSS, ALLIANCE); + RewardReputationToTeam(729, 730, BG_AV_REP_BOSS, killer->GetTeam() == ALLIANCE ? ALLIANCE : HORDE); RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS), ALLIANCE); EndBattleground(ALLIANCE); DelCreature(AV_CPLACE_TRIGGER19); @@ -98,7 +98,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) return; } m_CaptainAlive[0]=false; - RewardReputationToTeam(729, BG_AV_REP_CAPTAIN, HORDE); + RewardReputationToTeam(729, 730, BG_AV_REP_CAPTAIN, killer->GetTeam() == ALLIANCE ? ALLIANCE : HORDE); RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN), HORDE); UpdateScore(ALLIANCE, (-1)*BG_AV_RES_CAPTAIN); //spawn destroyed aura @@ -117,7 +117,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) return; } m_CaptainAlive[1]=false; - RewardReputationToTeam(730, BG_AV_REP_CAPTAIN, ALLIANCE); + RewardReputationToTeam(729, 730, BG_AV_REP_CAPTAIN, killer->GetTeam() == ALLIANCE ? ALLIANCE : HORDE); RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN), ALLIANCE); UpdateScore(HORDE, (-1)*BG_AV_RES_CAPTAIN); //spawn destroyed aura @@ -139,6 +139,7 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player) if (GetStatus() != STATUS_IN_PROGRESS) return;//maybe we should log this, cause this must be a cheater or a big bug uint8 team = GetTeamIndexByTeamId(player->GetTeam()); + uint8 oteam = GetTeamIndexByTeamId(GetOtherTeam(player->GetTeam())); /// @todo add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "BG_AV Quest %i completed", questid); switch (questid) @@ -163,21 +164,21 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player) case AV_QUEST_A_COMMANDER1: case AV_QUEST_H_COMMANDER1: m_Team_QuestStatus[team][1]++; - RewardReputationToTeam(team, 1, player->GetTeam()); + RewardReputationToTeam(team, oteam, 1, player->GetTeam()); if (m_Team_QuestStatus[team][1] == 30) TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "BG_AV Quest %i completed (need to implement some events here", questid); break; case AV_QUEST_A_COMMANDER2: case AV_QUEST_H_COMMANDER2: m_Team_QuestStatus[team][2]++; - RewardReputationToTeam(team, 1, player->GetTeam()); + RewardReputationToTeam(team, oteam, 1, player->GetTeam()); if (m_Team_QuestStatus[team][2] == 60) TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "BG_AV Quest %i completed (need to implement some events here", questid); break; case AV_QUEST_A_COMMANDER3: case AV_QUEST_H_COMMANDER3: m_Team_QuestStatus[team][3]++; - RewardReputationToTeam(team, 1, player->GetTeam()); + RewardReputationToTeam(team, oteam, 1, player->GetTeam()); if (m_Team_QuestStatus[team][3] == 120) TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "BG_AV Quest %i completed (need to implement some events here", questid); break; @@ -489,7 +490,7 @@ void BattlegroundAV::EndBattleground(uint32 winner) rep[i] += BG_AV_REP_SURVIVING_CAPTAIN; } if (rep[i] != 0) - RewardReputationToTeam(i == 0 ? 730 : 729, rep[i], i == 0 ? ALLIANCE : HORDE); + RewardReputationToTeam(729, 730, 10, i == ALLIANCE ? ALLIANCE : HORDE); if (kills[i] != 0) RewardHonorToTeam(GetBonusHonor(kills[i]), i == 0 ? ALLIANCE : HORDE); } @@ -608,7 +609,7 @@ void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) SpawnBGObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH + i + (tmp * 10), RESPAWN_IMMEDIATELY); UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, -1 * BG_AV_RES_TOWER); - RewardReputationToTeam(owner == ALLIANCE ? 730 : 729, BG_AV_REP_TOWER, owner); + RewardReputationToTeam(729, 730, BG_AV_REP_TOWER, owner); RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_TOWER), owner); SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp), RESPAWN_ONE_DAY); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 5e0cade..d0c9036 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -299,7 +299,6 @@ void BattlegroundWS::EventPlayerCapturedFlag(Player* player) if (GetTeamScore(TEAM_ALLIANCE) < BG_WS_MAX_TEAM_SCORE) AddPoint(ALLIANCE, 1); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); - RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE); } else { @@ -318,8 +317,8 @@ void BattlegroundWS::EventPlayerCapturedFlag(Player* player) if (GetTeamScore(TEAM_HORDE) < BG_WS_MAX_TEAM_SCORE) AddPoint(HORDE, 1); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); - RewardReputationToTeam(889, m_ReputationCapture, HORDE); } + RewardReputationToTeam(890, 889, m_ReputationCapture, player->GetTeam()); //for flag capture is reward 2 honorable kills RewardHonorToTeam(GetBonusHonorFromKill(2), player->GetTeam()); diff --git a/src/server/game/Cfbg/Cfbg.cpp b/src/server/game/Cfbg/Cfbg.cpp new file mode 100644 index 0000000..8e8ca47 --- /dev/null +++ b/src/server/game/Cfbg/Cfbg.cpp @@ -0,0 +1,339 @@ +#include "Cfbg.h" +#include "Battleground.h" +#include "BattlegroundMgr.h" +#include "Player.h" +#include "Chat.h" +#include "BattlegroundQueue.h" + +/*#################################################################################### +###############################CROSSFACTION BATTLEGROUNDS############################# +####################################################################################*/ + +uint8 Unit::getRace(bool forceoriginal) const +{ + if (GetTypeId() == TYPEID_PLAYER) + { + Player* pPlayer = ((Player*)this); + + if (forceoriginal) + return pPlayer->getORace(); + + if (pPlayer->InArena()) + return GetByteValue(UNIT_FIELD_BYTES_0, 0); + + if (!pPlayer->IsPlayingNative()) + return pPlayer->getFRace(); + } + + return GetByteValue(UNIT_FIELD_BYTES_0, 0); +} + +bool Player::SendRealNameQuery() +{ + if (IsPlayingNative()) + return false; + + WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 10)); + data.appendPackGUID(GetGUID()); // player guid + data << uint8(0); // added in 3.1; if > 1, then end of packet + data << GetName(); // played name + data << uint8(0); // realm name for cross realm BG usage + data << uint8(getORace()); + data << uint8(getGender()); + data << uint8(getClass()); + data << uint8(0); // is not declined + GetSession()->SendPacket(&data); + + return true; +} + +void Player::SetFakeRaceAndMorph() +{ + if (getClass() == CLASS_DRUID) + { + if (GetOTeam() == ALLIANCE) + { + m_FakeMorph = getGender() == GENDER_MALE ? FAKE_M_TAUREN : FAKE_F_TAUREN; + m_FakeRace = RACE_TAUREN; + } + else if (getGender() == GENDER_MALE) // HORDE PLAYER, ONLY HAVE MALE NELF ID + { + m_FakeMorph = FAKE_M_NELF; + m_FakeRace = RACE_NIGHTELF; + } + else + m_FakeRace = GetOTeam() == ALLIANCE ? RACE_BLOODELF : RACE_HUMAN; + } + else if (getClass() == CLASS_SHAMAN && GetOTeam() == HORDE && getGender() == GENDER_FEMALE) + { + m_FakeMorph = FAKE_F_DRANAEI; // Female Draenei + m_FakeRace = RACE_DRAENEI; + } + else + { + m_FakeRace = GetOTeam() == ALLIANCE ? RACE_BLOODELF : RACE_HUMAN; + + if (GetOTeam() == HORDE) + { + if (getGender() == GENDER_MALE) + m_FakeMorph = 19723; + else + m_FakeMorph = 19724; + } + else + { + if (getGender() == GENDER_MALE) + m_FakeMorph = 20578; + else + m_FakeMorph = 20579; + } + } +} + +bool Player::SendBattleGroundChat(uint32 msgtype, std::string message) +{ + // Select distance to broadcast to. + float distance = msgtype == CHAT_MSG_SAY ? sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY) : sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL); + + if (Battleground* pBattleGround = GetBattleground()) + { + if (pBattleGround->isArena()) // Only fake chat in BG's. CFBG should not interfere with arenas. + return false; + + for (Battleground::BattlegroundPlayerMap::const_iterator itr = pBattleGround->GetPlayers().begin(); itr != pBattleGround->GetPlayers().end(); ++itr) + { + if (Player* pPlayer = ObjectAccessor::FindPlayer(itr->first)) + { + if (GetDistance2d(pPlayer->GetPositionX(), pPlayer->GetPositionY()) <= distance) + { + WorldPacket data(SMSG_MESSAGECHAT, 200); + + if (GetTeam() == pPlayer->GetTeam()) + BuildPlayerChat(&data, msgtype, message, LANG_UNIVERSAL); + else if (msgtype != CHAT_MSG_EMOTE) + BuildPlayerChat(&data, msgtype, message, pPlayer->GetTeam() == ALLIANCE ? LANG_ORCISH : LANG_COMMON); + + pPlayer->GetSession()->SendPacket(&data); + } + } + } + return true; + } + else + return false; +} + +void Player::MorphFit(bool value) +{ + if (!IsPlayingNative() && value) + { + SetDisplayId(GetFakeMorph()); + SetNativeDisplayId(GetFakeMorph()); + } + else + InitDisplayIds(); +} + +void Player::FitPlayerInTeam(bool action, Battleground* pBattleGround) +{ + if (!pBattleGround) + pBattleGround = GetBattleground(); + + if ((!pBattleGround || pBattleGround->isArena()) && action) + return; + + if(!IsPlayingNative() && action) + setFactionForRace(getRace()); + else + setFactionForRace(getORace()); + + if (action) + SetForgetBGPlayers(true); + else + SetForgetInListPlayers(true); + + MorphFit(action); + + if (pBattleGround && action) + SendChatMessage("%sYou are playing for the %s%s in this %s", MSG_COLOR_WHITE, GetTeam() == ALLIANCE ? MSG_COLOR_DARKBLUE"alliance" : MSG_COLOR_RED"horde", MSG_COLOR_WHITE, pBattleGround->GetName()); +} + +void Player::DoForgetPlayersInList() +{ + // m_FakePlayers is filled from a vector within the battleground + // they were in previously so all players that have been in that BG will be invalidated. + for (FakePlayers::const_iterator itr = m_FakePlayers.begin(); itr != m_FakePlayers.end(); ++itr) + { + WorldPacket data(SMSG_INVALIDATE_PLAYER, 8); + data << *itr; + GetSession()->SendPacket(&data); + if (Player* pPlayer = ObjectAccessor::FindPlayer(*itr)) + GetSession()->SendNameQueryOpcode(pPlayer->GetGUID()); + } + m_FakePlayers.clear(); +} + +void Player::DoForgetPlayersInBG(Battleground* pBattleGround) +{ + for (Battleground::BattlegroundPlayerMap::const_iterator itr = pBattleGround->GetPlayers().begin(); itr != pBattleGround->GetPlayers().end(); ++itr) + { + // Here we invalidate players in the bg to the added player + WorldPacket data1(SMSG_INVALIDATE_PLAYER, 8); + data1 << itr->first; + GetSession()->SendPacket(&data1); + + if (Player* pPlayer = ObjectAccessor::FindPlayer(itr->first)) + { + GetSession()->SendNameQueryOpcode(pPlayer->GetGUID()); // Send namequery answer instantly if player is available + // Here we invalidate the player added to players in the bg + WorldPacket data2(SMSG_INVALIDATE_PLAYER, 8); + data2 << GetGUID(); + pPlayer->GetSession()->SendPacket(&data2); + pPlayer->GetSession()->SendNameQueryOpcode(GetGUID()); + } + } +} + +bool BattlegroundQueue::CheckCrossFactionMatch(BattlegroundBracketId bracket_id, Battleground* bg) +{ + if (!sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED) || bg->isArena()) + return false; // Only do this if crossbg's are enabled. + + // Here we will add all players to selectionpool, later we check if there are enough and launch a bg. + FillXPlayersToBG(bracket_id, bg, true); + + if (sBattlegroundMgr->isTesting() && (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[TEAM_HORDE].GetPlayerCount())) + return true; + + uint8 MPT = bg->GetMinPlayersPerTeam(); + if (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() < MPT || m_SelectionPools[TEAM_HORDE].GetPlayerCount() < MPT) + return false; + + return true; +} + +// This function will invite players in the least populated faction, which makes battleground queues much faster. +// This function will return true if cross faction battlegrounds are enabled, otherwise return false, +// which is useful in FillPlayersToBG. Because then we can interrupt the regular invitation if cross faction bg's are enabled. +bool BattlegroundQueue::FillXPlayersToBG(BattlegroundBracketId bracket_id, Battleground* bg, bool start) +{ + uint8 queuedPeople = 0; + for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].end(); ++itr) + if (!(*itr)->IsInvitedToBGInstanceGUID) + queuedPeople += (*itr)->Players.size(); + + if (sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED) && (sBattlegroundMgr->isTesting() || queuedPeople >= bg->GetMinPlayersPerTeam()*2 || !start)) + { + int32 aliFree = start ? bg->GetMaxPlayersPerTeam() : bg->GetFreeSlotsForTeam(ALLIANCE); + int32 hordeFree = start ? bg->GetMaxPlayersPerTeam() : bg->GetFreeSlotsForTeam(HORDE); + // Empty selection pools. They will be refilled from queued groups. + m_SelectionPools[TEAM_ALLIANCE].Init(); + m_SelectionPools[TEAM_HORDE].Init(); + int32 valiFree = aliFree; + int32 vhordeFree = hordeFree; + int32 diff = 0; + + + // Add teams to their own factions as far as possible. + if (start) + { + QueuedGroupMap m_PreGroupMap_a, m_PreGroupMap_h; + int32 m_SmallestOfTeams = 0; + int32 queuedAlliance = 0; + int32 queuedHorde = 0; + + for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].end(); ++itr) + { + if ((*itr)->IsInvitedToBGInstanceGUID) + continue; + + bool alliance = (*itr)->OTeam == ALLIANCE; + + if (alliance) + { + m_PreGroupMap_a.insert(std::make_pair((*itr)->Players.size(), *itr)); + queuedAlliance += (*itr)->Players.size(); + } + else + { + m_PreGroupMap_h.insert(std::make_pair((*itr)->Players.size(), *itr)); + queuedHorde += (*itr)->Players.size(); + } + } + + m_SmallestOfTeams = std::min(std::min(aliFree, queuedAlliance), std::min(hordeFree, queuedHorde)); + + valiFree -= PreAddPlayers(m_PreGroupMap_a, m_SmallestOfTeams, aliFree); + vhordeFree -= PreAddPlayers(m_PreGroupMap_h, m_SmallestOfTeams, hordeFree); + } + + QueuedGroupMap m_QueuedGroupMap; + + for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].end(); ++itr) + m_QueuedGroupMap.insert(std::make_pair((*itr)->Players.size(), *itr)); + + for (QueuedGroupMap::reverse_iterator itr = m_QueuedGroupMap.rbegin(); itr != m_QueuedGroupMap.rend(); ++itr) + { + GroupsQueueType allypool = m_SelectionPools[TEAM_ALLIANCE].SelectedGroups; + GroupsQueueType hordepool = m_SelectionPools[TEAM_HORDE].SelectedGroups; + + GroupQueueInfo* ginfo = itr->second; + + // If player already was invited via pre adding (add to own team first) or he was already invited to a bg, skip. + if (ginfo->IsInvitedToBGInstanceGUID || + std::find(allypool.begin(), allypool.end(), ginfo) != allypool.end() || + std::find(hordepool.begin(), hordepool.end(), ginfo) != hordepool.end() || + (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() >= bg->GetMinPlayersPerTeam() && + m_SelectionPools[TEAM_HORDE].GetPlayerCount() >= bg->GetMinPlayersPerTeam())) + continue; + + diff = abs(valiFree - vhordeFree); + bool moreAli = valiFree < vhordeFree; + + if (diff > 0) + ginfo->Team = moreAli ? HORDE : ALLIANCE; + + bool alliance = ginfo->Team == ALLIANCE; + + if (m_SelectionPools[alliance ? TEAM_ALLIANCE : TEAM_HORDE].AddGroup(ginfo, alliance ? aliFree : hordeFree)) + alliance ? valiFree -= ginfo->Players.size() : vhordeFree -= ginfo->Players.size(); + } + + return true; + } + return false; +} + +int32 BattlegroundQueue::PreAddPlayers(QueuedGroupMap m_PreGroupMap, int32 MaxAdd, uint32 MaxInTeam) +{ + int32 LeftToAdd = MaxAdd; + uint32 Added = 0; + + for (QueuedGroupMap::reverse_iterator itr = m_PreGroupMap.rbegin(); itr != m_PreGroupMap.rend(); ++itr) + { + int32 PlayerSize = itr->first; + bool alliance = itr->second->OTeam == ALLIANCE; + + if (PlayerSize <= LeftToAdd && m_SelectionPools[alliance ? TEAM_ALLIANCE : TEAM_HORDE].AddGroup(itr->second, MaxInTeam)) + LeftToAdd -= PlayerSize, Added -= PlayerSize; + } + + return LeftToAdd; +} + +void Player::SendChatMessage(const char *format, ...) +{ + if (!IsInWorld()) + return; + + if (format) + { + va_list ap; + char str [2048]; + va_start(ap, format); + vsnprintf(str, 2048, format, ap); + va_end(ap); + + ChatHandler(GetSession()).SendSysMessage(str); + } +} diff --git a/src/server/game/Cfbg/Cfbg.h b/src/server/game/Cfbg/Cfbg.h new file mode 100644 index 0000000..bda4199 --- /dev/null +++ b/src/server/game/Cfbg/Cfbg.h @@ -0,0 +1,44 @@ +#ifndef _CUSTOM_H +#define _CUSTOM_H + +#define MSG_COLOR_LIGHTRED "|cffff6060" +#define MSG_COLOR_LIGHTBLUE "|cff00ccff" +#define MSG_COLOR_ANN_GREEN "|c1f40af20" +#define MSG_COLOR_RED "|cffff0000" +#define MSG_COLOR_GOLD "|cffffcc00" +#define MSG_COLOR_SUBWHITE "|cffbbbbbb" +#define MSG_COLOR_MAGENTA "|cffff00ff" +#define MSG_COLOR_YELLOW "|cffffff00" +#define MSG_COLOR_CYAN "|cff00ffff" +#define MSG_COLOR_DARKBLUE "|cff0000ff" + +#define MSG_COLOR_GREY "|cff9d9d9d" +#define MSG_COLOR_WHITE "|cffffffff" +#define MSG_COLOR_GREEN "|cff1eff00" +#define MSG_COLOR_BLUE "|cff0080ff" +#define MSG_COLOR_PURPLE "|cffb048f8" +#define MSG_COLOR_ORANGE "|cffff8000" + +#define MSG_COLOR_DRUID "|cffff7d0a" +#define MSG_COLOR_HUNTER "|cffabd473" +#define MSG_COLOR_MAGE "|cff69ccf0" +#define MSG_COLOR_PALADIN "|cfff58cba" +#define MSG_COLOR_PRIEST "|cffffffff" +#define MSG_COLOR_ROGUE "|cfffff569" +#define MSG_COLOR_SHAMAN "|cff0070de" +#define MSG_COLOR_WARLOCK "|cff9482c9" +#define MSG_COLOR_WARRIOR "|cffc79c6e" +#define MSG_COLOR_DEATH_KNIGHT "|cffc41f3b" +#define MSG_COLOR_MONK "|cff00ff96" + +#define LIMIT_UINT32 2147483647 + +enum FakeMorphs +{ + FAKE_F_TAUREN = 20584, + FAKE_M_TAUREN = 20585, + FAKE_M_NELF = 20318, + FAKE_F_DRANAEI = 20323, +}; + +#endif \ No newline at end of file diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index d0cd8bb..68fc152 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -48,6 +48,7 @@ file(GLOB_RECURSE sources_Tickets Tickets/*.cpp Tickets/*.h) file(GLOB_RECURSE sources_Warden Warden/*.cpp Warden/*.h) file(GLOB_RECURSE sources_Weather Weather/*.cpp Weather/*.h) file(GLOB_RECURSE sources_World World/*.cpp World/*.h) +file(GLOB_RECURSE sources_Cfbg Cfbg/*.cpp Cfbg/*.h) # Create game-libary @@ -98,6 +99,7 @@ set(game_STAT_SRCS ${sources_Warden} ${sources_Weather} ${sources_World} + ${sources_Cfbg} ) include_directories( diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 120c2d8..c65066a 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -650,6 +650,12 @@ Player::Player(WorldSession* session): Unit(true) #pragma warning(default:4355) #endif + m_FakeRace = 0; + m_RealRace = 0; + m_FakeMorph = 0; + m_ForgetBGPlayers = false; + m_ForgetInListPlayers = false; + m_speakTime = 0; m_speakCount = 0; @@ -979,6 +985,12 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16); SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24))); + + SetORace(); + m_team = TeamForRace(getORace()); + SetFakeRaceAndMorph(); // m_team must be set before this can be used. + setFactionForRace(getORace()); + InitDisplayIds(); if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP) { @@ -3032,7 +3044,7 @@ void Player::GiveLevel(uint8 level) guild->UpdateMemberData(this, GUILD_MEMBER_DATA_LEVEL, level); PlayerLevelInfo info; - sObjectMgr->GetPlayerLevelInfo(getRace(), getClass(), level, &info); + sObjectMgr->GetPlayerLevelInfo(getORace(), getClass(), level, &info); PlayerClassLevelInfo classInfo; sObjectMgr->GetPlayerClassLevelInfo(getClass(), level, &classInfo); @@ -3170,7 +3182,7 @@ void Player::InitStatsForLevel(bool reapplyMods) sObjectMgr->GetPlayerClassLevelInfo(getClass(), getLevel(), &classInfo); PlayerLevelInfo info; - sObjectMgr->GetPlayerLevelInfo(getRace(), getClass(), getLevel(), &info); + sObjectMgr->GetPlayerLevelInfo(getORace(), getClass(), getLevel(), &info); SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); SetUInt32Value(PLAYER_NEXT_LEVEL_XP, sObjectMgr->GetXPForLevel(getLevel())); @@ -5249,7 +5261,7 @@ void Player::CreateCorpse() return; } - _uf = GetUInt32Value(UNIT_FIELD_BYTES_0); + _uf = getORace(); _pb = GetUInt32Value(PLAYER_BYTES); _pb2 = GetUInt32Value(PLAYER_BYTES_2); @@ -6921,10 +6933,10 @@ uint32 Player::TeamForRace(uint8 race) void Player::setFactionForRace(uint8 race) { - m_team = TeamForRace(race); + SetBGTeam(TeamForRace(race)); ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race); - setFaction(rEntry ? rEntry->FactionID : 0); + setFaction(rEntry ? rEntry->FactionID : getFaction()); } ReputationRank Player::GetReputationRank(uint32 faction) const @@ -7022,6 +7034,27 @@ void Player::RewardReputation(Unit* victim, float rate) if (!Rep) return; + uint32 repfaction1 = Rep->RepFaction1; + uint32 repfaction2 = Rep->RepFaction2; + + if (!IsPlayingNative()) + { + if (GetOTeam() == ALLIANCE) + { + if (repfaction1 == 729) + repfaction1 = 730; + if (repfaction2 == 729) + repfaction2 = 730; + } + else + { + if (repfaction1 == 730) + repfaction1 = 729; + if (repfaction2 == 730) + repfaction2 = 729; + } + } + uint32 ChampioningFaction = 0; if (GetChampioningFaction()) @@ -7036,23 +7069,23 @@ void Player::RewardReputation(Unit* victim, float rate) uint32 team = GetTeam(); - if (Rep->RepFaction1 && (!Rep->TeamDependent || team == ALLIANCE)) + if (repfaction1 && (!Rep->TeamDependent || team == ALLIANCE)) { - int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); + int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : repfaction1); donerep1 = int32(donerep1 * rate); - FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); + FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : repfaction1); uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1); if (factionEntry1 && current_reputation_rank1 <= Rep->ReputationMaxCap1) GetReputationMgr().ModifyReputation(factionEntry1, donerep1); } - if (Rep->RepFaction2 && (!Rep->TeamDependent || team == HORDE)) + if (repfaction2 && (!Rep->TeamDependent || team == HORDE)) { - int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); + int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : repfaction2); donerep2 = int32(donerep2 * rate); - FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); + FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : repfaction2); uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2); if (factionEntry2 && current_reputation_rank2 <= Rep->ReputationMaxCap2) GetReputationMgr().ModifyReputation(factionEntry2, donerep2); @@ -7145,7 +7178,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto if (!victim || victim == this || victim->GetTypeId() != TYPEID_PLAYER) return false; - if (GetBGTeam() == victim->ToPlayer()->GetBGTeam()) + if (GetTeam() == victim->ToPlayer()->GetTeam()) return false; return true; @@ -11949,13 +11982,13 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const if (proto) { - if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetTeam() != HORDE) + if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetOTeam() != HORDE) return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; - if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && GetTeam() != ALLIANCE) + if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && GetOTeam() != ALLIANCE) return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; - if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) + if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getORaceMask()) == 0) return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; if (proto->RequiredSkill != 0) @@ -17043,6 +17076,11 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) bytes0 |= Gender << 16; // gender SetUInt32Value(UNIT_FIELD_BYTES_0, bytes0); + SetORace(); + m_team = TeamForRace(getORace()); + SetFakeRaceAndMorph(); // m_team must be set before this can be used. + setFactionForRace(getORace());//Need to call it to initialize m_team (m_team can be calculated from race) + SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(PLAYER_XP, fields[7].GetUInt32()); @@ -17089,10 +17127,6 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) TC_LOG_DEBUG(LOG_FILTER_PLAYER_LOADING, "Load Basic value of player %s is: ", m_name.c_str()); outDebugValues(); - //Need to call it to initialize m_team (m_team can be calculated from race) - //Other way is to saves m_team into characters table. - setFactionForRace(getRace()); - // load home bind and check in same time class/race pair, it used later for restore broken positions if (!_LoadHomeBind(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND))) return false; @@ -17332,7 +17366,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) map = sMapMgr->CreateMap(mapId, this); if (!map) { - PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); + PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getORace(), getClass()); mapId = info->mapId; Relocate(info->positionX, info->positionY, info->positionZ, 0.0f); TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", guid, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); @@ -18978,7 +19012,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, GetGUIDLow()); stmt->setUInt32(index++, GetSession()->GetAccountId()); stmt->setString(index++, GetName()); - stmt->setUInt8(index++, getRace()); + stmt->setUInt8(index++, getORace()); stmt->setUInt8(index++, getClass()); stmt->setUInt8(index++, getGender()); stmt->setUInt8(index++, getLevel()); @@ -19075,7 +19109,7 @@ void Player::SaveToDB(bool create /*=false*/) // Update query stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER); stmt->setString(index++, GetName()); - stmt->setUInt8(index++, getRace()); + stmt->setUInt8(index++, getORace()); stmt->setUInt8(index++, getClass()); stmt->setUInt8(index++, getGender()); stmt->setUInt8(index++, getLevel()); @@ -21320,22 +21354,26 @@ void Player::InitDataForForm(bool reapplyMods) void Player::InitDisplayIds() { - PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); + PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getORace(), getClass()); if (!info) { TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player %u has incorrect race/class pair. Can't init display ids.", GetGUIDLow()); return; } + bool isMorphed = GetNativeDisplayId() != GetDisplayId(); + uint8 gender = getGender(); switch (gender) { case GENDER_FEMALE: - SetDisplayId(info->displayId_f); + if (!isMorphed) + SetDisplayId(info->displayId_f); SetNativeDisplayId(info->displayId_f); break; case GENDER_MALE: - SetDisplayId(info->displayId_m); + if (!isMorphed) + SetDisplayId(info->displayId_m); SetNativeDisplayId(info->displayId_m); break; default: @@ -22046,11 +22084,6 @@ void Player::SetBGTeam(uint32 team) SetByteValue(PLAYER_BYTES_3, 3, uint8(team == ALLIANCE ? 1 : 0)); } -uint32 Player::GetBGTeam() const -{ - return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam(); -} - void Player::LeaveBattleground(bool teleportToEntryPoint) { if (Battleground* bg = GetBattleground()) @@ -22126,7 +22159,7 @@ void Player::ReportedAfkBy(Player* reporter) WorldLocation Player::GetStartPosition() const { - PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); + PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getORace(), getClass()); uint32 mapId = info->mapId; if (getClass() == CLASS_DEATH_KNIGHT && HasSpell(50977)) mapId = 0; @@ -22817,7 +22850,7 @@ void Player::learnDefaultSpells() for (PlayerCreateInfoSpells::const_iterator itr = info->spell.begin(); itr != info->spell.end(); ++itr) { uint32 tspell = *itr; - TC_LOG_DEBUG(LOG_FILTER_PLAYER_LOADING, "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getRace()), tspell); + TC_LOG_DEBUG(LOG_FILTER_PLAYER_LOADING, "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getORace()), tspell); if (!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add addSpell(tspell, true, true, true, false); else // but send in normal spell in game learn case diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2a5602f..e2cc091 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1066,6 +1066,36 @@ class Player : public Unit, public GridObject explicit Player(WorldSession* session); ~Player(); + private: + bool m_ForgetBGPlayers; + bool m_ForgetInListPlayers; + uint8 m_FakeRace; + uint8 m_RealRace; + uint32 m_FakeMorph; + public: + typedef std::vector FakePlayers; + void SendChatMessage(const char *format, ...); + void FitPlayerInTeam(bool action, Battleground* pBattleGround = NULL); + void DoForgetPlayersInList(); + void DoForgetPlayersInBG(Battleground* pBattleGround); + uint8 getORace() const { return m_RealRace; } + void SetORace() { m_RealRace = GetByteValue(UNIT_FIELD_BYTES_0, 0); }; // SHOULD ONLY BE CALLED ON LOGIN + void SetFakeRace(); // SHOULD ONLY BE CALLED ON LOGIN + void SetFakeRaceAndMorph(); // SHOULD ONLY BE CALLED ON LOGIN + uint32 GetFakeMorph() { return m_FakeMorph; }; + uint8 getFRace() const { return m_FakeRace; } + void SetForgetBGPlayers(bool value) { m_ForgetBGPlayers = value; } + bool ShouldForgetBGPlayers() { return m_ForgetBGPlayers; } + void SetForgetInListPlayers(bool value) { m_ForgetInListPlayers = value; } + bool ShouldForgetInListPlayers() { return m_ForgetInListPlayers; } + bool SendBattleGroundChat(uint32 msgtype, std::string message); + void MorphFit(bool value); + bool IsPlayingNative() const { return GetTeam() == m_team; } + uint32 GetOTeam() const { return m_team; } + uint32 GetTeam() const { return m_bgData.bgTeam && GetBattleground() ? m_bgData.bgTeam : m_team; } + bool SendRealNameQuery(); + FakePlayers m_FakePlayers; + public: uint32 selectedSlotID; Loot* selectedInterface; @@ -1122,7 +1152,7 @@ class Player : public Unit, public GridObject PlayerSocial *GetSocial() { return m_social; } PlayerTaxi m_taxi; - void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); } + void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getORace(), getClass(), getLevel()); } bool ActivateTaxiPathTo(std::vector const& nodes, Creature* npc = NULL, uint32 spellid = 0); bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0); void CleanupAfterTaxiFlight(); @@ -1887,8 +1917,7 @@ class Player : public Unit, public GridObject void CheckAreaExploreAndOutdoor(void); static uint32 TeamForRace(uint8 race); - uint32 GetTeam() const { return m_team; } - TeamId GetTeamId() const { return m_team == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; } + TeamId GetTeamId() const { return GetTeam() == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; } void setFactionForRace(uint8 race); void InitDisplayIds(); @@ -2031,7 +2060,6 @@ class Player : public Unit, public GridObject void SetBattlegroundEntryPoint(); void SetBGTeam(uint32 team); - uint32 GetBGTeam() const; void LeaveBattleground(bool teleportToEntryPoint = true); bool CanJoinToBattleground(Battleground const* bg) const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 7e67a9e..75e8819 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -15905,7 +15905,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) void Unit::RestoreFaction() { if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->setFactionForRace(getRace()); + ToPlayer()->setFactionForRace(ToPlayer()->getRace()); else { if (HasUnitTypeMask(UNIT_MASK_MINION)) @@ -16654,6 +16654,21 @@ uint32 Unit::GetModelForTotem(PlayerTotemType totemType) } break; } + default: // One standard for other races. + { // THANKS L30m4nc3r for this + switch (totemType) + { + case SUMMON_TYPE_TOTEM_FIRE: // fire + return 4589; + case SUMMON_TYPE_TOTEM_EARTH: // earth + return 4588; + case SUMMON_TYPE_TOTEM_WATER: // water + return 4587; + case SUMMON_TYPE_TOTEM_AIR: // air + return 4590; + } + break; + } } return 0; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index c90357a..08dc0cb 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1341,8 +1341,10 @@ class Unit : public WorldObject uint8 getLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); } uint8 getLevelForTarget(WorldObject const* /*target*/) const { return getLevel(); } void SetLevel(uint8 lvl); - uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); } + uint8 getRace(bool forceoriginal = false) const; + uint8 getORace() { return getRace(true); } uint32 getRaceMask() const { return 1 << (getRace()-1); } + uint32 getORaceMask() const { return 1 << (getRace(true) - 1); } uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); } uint32 getClassMask() const { return 1 << (getClass()-1); } uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); } diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index db96c50..0410edd 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -35,6 +35,8 @@ #include "DisableMgr.h" #include "Group.h" +#include "Cfbg/Cfbg.h" + void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recvData) { uint64 guid; @@ -543,7 +545,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) { // this line is checked, i only don't know if GetStartTime is changing itself after bg end! // send status in Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType, _player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType, _player->GetTeam()); SendPacket(&data); continue; } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 0554820..2ae4e3d 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1024,6 +1024,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) sScriptMgr->OnPlayerLogin(pCurrChar); delete holder; + + if (pCurrChar->GetTeam() != pCurrChar->GetOTeam()) + pCurrChar->FitPlayerInTeam(pCurrChar->GetBattleground() && !pCurrChar->GetBattleground()->isArena() ? true : false, pCurrChar->GetBattleground()); } void WorldSession::HandleSetFactionAtWar(WorldPacket& recvData) diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 4ebccc5..19e52b6 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -48,6 +48,18 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) recvData >> type; recvData >> lang; + if (sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED) && lang != LANG_ADDON) + { + switch (type) + { + case CHAT_MSG_BATTLEGROUND: + case CHAT_MSG_BATTLEGROUND_LEADER: + lang = LANG_UNIVERSAL; + default: + break; + } + } + if (type >= MAX_CHAT_MSG_TYPE) { TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "CHAT: Wrong message type received: %u", type); @@ -248,6 +260,10 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } + if (!GetPlayer()->IsGameMaster()) + if (GetPlayer()->SendBattleGroundChat(type, msg)) + return; + if (type == CHAT_MSG_SAY) sender->Say(msg, lang); else if (type == CHAT_MSG_EMOTE) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index c55ccdc..58f0b72 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1424,6 +1424,21 @@ void WorldSession::HandleSetTitleOpcode(WorldPacket& recvData) void WorldSession::HandleTimeSyncResp(WorldPacket& recvData) { + Battleground* bg = _player->GetBattleground(); + if (bg) + { + if (_player->ShouldForgetBGPlayers() && bg) + { + _player->DoForgetPlayersInBG(bg); + _player->SetForgetBGPlayers(false); + } + } + else if (_player->ShouldForgetInListPlayers()) + { + _player->DoForgetPlayersInList(); + _player->SetForgetInListPlayers(false); + } + TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "CMSG_TIME_SYNC_RESP"); uint32 counter, clientTicks; diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 5a94d5b..11d4166 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -48,7 +48,7 @@ void WorldSession::SendNameQueryOpcode(uint64 guid) data << uint8(0); // name known data << nameData->m_name; // played name data << uint8(0); // realm name - only set for cross realm interaction (such as Battlegrounds) - data << uint8(nameData->m_race); + data << uint8(player ? player->getRace() : nameData->m_race); data << uint8(nameData->m_gender); data << uint8(nameData->m_class); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 748da85..60ae2d6 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1040,6 +1040,8 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetBoolDefault("OffhandCheckAtSpellUnlearn", true); + m_bool_configs[BATTLEGROUND_CROSSFACTION_ENABLED] = sConfigMgr->GetBoolDefault("CrossfactionBG.enable", true); + if (int32 clientCacheId = sConfigMgr->GetIntDefault("ClientCacheVersion", 0)) { // overwrite DB/old value diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index bc28049..bfc1f39 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -85,6 +85,7 @@ enum WorldTimers enum WorldBoolConfigs { CONFIG_DURABILITY_LOSS_IN_PVP = 0, + BATTLEGROUND_CROSSFACTION_ENABLED, CONFIG_ADDON_CHANNEL, CONFIG_ALLOW_PLAYER_COMMANDS, CONFIG_CLEAN_CHARACTER_DB, diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 48e58cc..a6cda44 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -2814,3 +2814,15 @@ Rate.Reputation.Gain.VIP = 1 # ################################################################################################### + +################################################################################################### +# +# CROSSFACTION BG CONFIG +# +# CrossfactionBG.enable = 1 - Mixed battleground enabled. +# CrossfactionBG.enable = 0 - Mixed battleground disabled. + +CrossfactionBG.enable = 1 + +# +################################################################################################### \ No newline at end of file