bool OnGossipHello(Player* player, Creature* creature) { if (ArenaWatcherEnable && (!ArenaWatcherOnlyGM || player->isGameMaster())) { uint8 arenasCount[MAX_ARENA_SLOT] = {0, 0, 0}; for (uint8 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId) { if (!BattlegroundMgr::IsArenaType(BattlegroundTypeId(bgTypeId))) continue; if(BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(bgTypeId))){ if (!arenas || arenas->m_Battlegrounds.empty()) continue; for (BattlegroundContainer::const_iterator itr = arenas->m_Battlegrounds.begin(); itr != arenas->m_Battlegrounds.end(); ++itr) { if (!(itr->second->GetStatus() & 2)) continue; if (ArenaWatcherOnlyRated && !itr->second->isRated()) continue; if(itr->second->GetStatus()==STATUS_IN_PROGRESS) ++arenasCount[ArenaTeam::GetSlotByType(itr->second->GetArenaType())]; } } } for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i) { if (!arenasCount[i]) continue; char gossipTextFormat[50]; snprintf(gossipTextFormat, 50, sObjectMgr->GetTrinityStringForDBCLocale(STRING_ARENA_2v2 + i), arenasCount[i]); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, gossipTextFormat, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + i); } if (ArenaWatcherToPlayers) player->ADD_GOSSIP_ITEM_EXTENDED( GOSSIP_ICON_CHAT, sObjectMgr->GetTrinityStringForDBCLocale(STRING_FOLLOW), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4, "", 0, true ); } player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); return true; }
void WorldSession::HandleBattlefieldListOpcode(WorldPackets::Battleground::BattlefieldListRequest& battlefieldList) { BattlemasterListEntry const* battlemasterListEntry = sBattlemasterListStore.LookupEntry(battlefieldList.ListID); if (!battlemasterListEntry) { TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, %s) received.", battlefieldList.ListID, _player->GetName().c_str(), _player->GetGUID().ToString().c_str()); return; } sBattlegroundMgr->SendBattlegroundList(_player, ObjectGuid::Empty, BattlegroundTypeId(battlefieldList.ListID)); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint8 bgTypeId; recv_data >> bgTypeId; // id from DBC WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId)); SendPacket(&data); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recvData >> bgTypeId; // id from DBC BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId, _player->GetName().c_str(), _player->GetGUIDLow()); return; } WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId)); SendPacket(&data); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recv_data >> bgTypeId; // id from DBC BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId, _player->GetName(), _player->GetGUIDLow()); return; } WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId)); SendPacket(&data); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) { sLog->outDebug("WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recv_data >> bgTypeId; // id from DBC BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { sLog->outError("Battleground: invalid bgtype received."); return; } WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId)); SendPacket(&data); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recvData) { ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recvData >> bgTypeId; // id from DBC uint8 fromWhere; recvData >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) uint8 canGainXP; recvData >> canGainXP; // players with locked xp have their own bg queue on retail BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) return; WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId), fromWhere); SendPacket(&data); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recvData >> bgTypeId; // id from DBC uint8 fromWhere; recvData >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) uint8 canGainXP; recvData >> canGainXP; // players with locked xp have their own bg queue on retail BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { TC_LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId, _player->GetName().c_str(), _player->GetGUIDLow()); return; } WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, ObjectGuid::Empty, _player, BattlegroundTypeId(bgTypeId), fromWhere); SendPacket(&data); }
void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recv_data >> bgTypeId; // id from DBC uint8 fromWhere; recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) uint8 unk1; recv_data >> unk1; // Unknown 3.2.2 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { sLog->outError("Battleground: invalid bgtype received."); return; } WorldPacket data; sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId), fromWhere); SendPacket(&data); }
void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recv_data) { uint8 joinAsGroup; uint32 bgTypeId_; uint32 unk, unk2; bool isPremade = false; Group * grp = NULL; recv_data >> joinAsGroup; // join as group (join as group = 0x80, else 0x0) recv_data >> unk; // unk recv_data >> bgTypeId_; // battleground type id (DBC id) recv_data >> unk2; // unk if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog->outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u", bgTypeId_, _player->GetGUIDLow()); return; } if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) { ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); // can do this, since it's battleground, not arena BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); // ignore if player is already in BG if (_player->InBattleground()) return; // get bg template Battleground *bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; GroupJoinBattlegroundResult err; // check queue conditions if (!joinAsGroup) { if (GetPlayer()->isUsingLfg()) { // player is using dungeon finder or raid finder WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_LFG_CANT_USE_BATTLEGROUND); GetPlayer()->GetSession()->SendPacket(&data); return; } // check Deserter debuff if (!_player->CanJoinToBattleground()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data); return; } if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) { //player is already in random queue WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); _player->GetSession()->SendPacket(&data); return; } if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) { //player is already in queue, can't start random queue WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); _player->GetSession()->SendPacket(&data); return; } // check if already in queue if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) //player is already in this queue return; // check if has free queue slots if (!_player->HasFreeBattlegroundQueueId()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); _player->GetSession()->SendPacket(&data); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); // already checked if queueSlot is valid, now just get it uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); WorldPacket data; // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName()); } else { grp = _player->GetGroup(); // no group found, error if (!grp) return; if (grp->GetLeaderGUID() != _player->GetGUID()) return; err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; GroupQueueInfo * ginfo = NULL; uint32 avgTime = 0; if (err > 0) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: the following players are joining as group:"); ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); } for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); if (!member) continue; // this should never happen WorldPacket data; if (err <= 0) { sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); continue; } // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); member->GetSession()->SendPacket(&data); sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName()); } sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: group end"); } sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); uint8 action; // enter battle 128, leave queue 0 // then goes uint64 that we sent to client in SMSG_BATTLEFIELD_STATUS3 uint32 bgTypeId_; // type id from dbc uint32 type; // arenatype if arena recv_data >> action >> bgTypeId_ >> type; if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog->outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); return; } if (!_player->InBattlegroundQueue()) { sLog->outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow()); return; } //get GroupQueueInfo from BattlegroundQueue BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, (uint8)type); BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { sLog->outError("BattlegroundHandler: itrplayerstatus not found."); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { sLog->outError("BattlegroundHandler: instance not found."); return; } Battleground *bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet if (!bg && action == 0) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { sLog->outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (!_player->CanJoinToBattleground()) { //send bg command result to show nice message WorldPacket data2; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { sLog->outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; switch(action >> 7) { case 1: // port to battleground if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (!_player->InBattleground()) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->isAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground *currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player, team); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); break; case 0: // leave queue // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { ArenaTeam * at = sObjectMgr->GetArenaTeamById(ginfo.Team); if (at) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); at->SaveToDB(); } } _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); break; default: sLog->outError("Battleground port: unknown action %u", action); break; } }
void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recvData) { uint64 guid; uint32 bgTypeId_; uint32 instanceId; // sent to queue for particular bg from battlemaster's list, currently not used uint8 joinAsGroup; recvData >> guid; // battlemaster guid recvData >> bgTypeId_; // battleground type id (DBC id) recvData >> instanceId; // instance id, 0 if First Available selected recvData >> joinAsGroup; // join as group // entry not found if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) return; // chosen battleground type is disabled if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) { ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } // get queue typeid and random typeid to check if already queued for them BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); // safety check - bgQueueTypeId == BATTLEGROUND_QUEUE_NONE if tried to queue for arena using this function if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) return; // get bg template Battleground* bgt = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bgt) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgt->GetMapId(), _player->getLevel()); if (!bracketEntry) return; // pussywizard: if trying to queue for already queued // just remove from queue and it will requeue! uint32 qSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); if (qSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) { BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); if (bgQueue.IsPlayerInvitedToRatedArena(_player->GetGUID())) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED); SendPacket(&data); return; } bgQueue.RemovePlayer(_player->GetGUID(), false, qSlot); _player->RemoveBattlegroundQueueId(bgQueueTypeId); } // must have free queue slot if (!_player->HasFreeBattlegroundQueueId()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); SendPacket(&data); return; } // queue result (default ok) GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bgt->GetBgTypeID()); // check if player can queue: if (!joinAsGroup) { if (GetPlayer()->InBattleground()) // currently in battleground err = ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND; else if (GetPlayer()->isUsingLfg()) // using lfg system err = ERR_LFG_CANT_USE_BATTLEGROUND; else if (!_player->CanJoinToBattleground()) // has deserter debuff err = ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS; else if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom)) // queued for random bg, so can't queue for anything else err = ERR_IN_RANDOM_BG; else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random err = ERR_IN_NON_RANDOM_BG; else if (_player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_2v2) || _player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_3v3) || _player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_5v5)) // can't be already queued for arenas err = ERR_BATTLEGROUND_QUEUED_FOR_RATED; if (err <= 0) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); SendPacket(&data); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bracketEntry, false, false, 0, 0, 0); uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo); uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); // send status packet WorldPacket data; sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL); SendPacket(&data); } // check if group can queue: else { Group* grp = _player->GetGroup(); // no group or not a leader if (!grp || grp->GetLeaderGUID() != _player->GetGUID()) return; // pussywizard: for party members - remove queues for which leader is not queued to! std::set<uint32> leaderQueueTypeIds; for (uint32 i=0; i<PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) leaderQueueTypeIds.insert((uint32)_player->GetBattlegroundQueueTypeId(i)); for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) if (Player* member = itr->GetSource()) for (uint32 i=0; i<PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) if (BattlegroundQueueTypeId mqtid = member->GetBattlegroundQueueTypeId(i)) if (leaderQueueTypeIds.count((uint32)mqtid) == 0) { BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(mqtid); if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID())) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED); SendPacket(&data); return; } bgQueue.RemovePlayer(member->GetGUID(), false, i); member->RemoveBattlegroundQueueId(mqtid); } if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom)) // queued for random bg, so can't queue for anything else err = ERR_IN_RANDOM_BG; else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random err = ERR_IN_NON_RANDOM_BG; else if (_player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_2v2) || _player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_3v3) || _player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_5v5)) // can't be already queued for arenas err = ERR_BATTLEGROUND_QUEUED_FOR_RATED; if (err > 0) err = grp->CanJoinBattlegroundQueue(bgt, bgQueueTypeId, 0, bgt->GetMaxPlayersPerTeam(), false, 0); bool isPremade = (grp->GetMembersCount() >= bgt->GetMinPlayersPerTeam() && bgTypeId != BATTLEGROUND_RB); uint32 avgWaitTime = 0; if (err > 0) { BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, false, isPremade, 0, 0, 0); avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo); } WorldPacket data; for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* member = itr->GetSource(); if (!member) continue; if (err <= 0) { sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); continue; } uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); // send status packet sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL); member->GetSession()->SendPacket(&data); sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); } } }
void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recv_data) { uint64 guid; uint32 bgTypeId_; uint32 instanceId; uint8 joinAsGroup; bool isPremade = false; Group* grp = NULL; recv_data >> guid; // battlemaster guid recv_data >> bgTypeId_; // battleground type id (DBC id) recv_data >> instanceId; // instance id, 0 if First Available selected recv_data >> joinAsGroup; // join as group if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog->outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u", bgTypeId_, _player->GetGUIDLow()); return; } if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) { ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); // can do this since it's battleground BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId); // ignore if player is already in BG if (_player->InBattleground()) return; // get bg instance or bg template if instance not found Battleground* bg = NULL; if (instanceId) bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId); if (!bg) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; GroupJoinBattlegroundResult err; // check queue conditions if (!joinAsGroup) { // check Deserter debuff if (!_player->CanJoinToBattleground()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data); return; } // check if already in queue if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) return; // check if has free queue slots if (!_player->HasFreeBattlegroundQueueId()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); _player->GetSession()->SendPacket(&data); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, isPremade); uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); // already checked if queueSlot is valid, now just get it uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); WorldPacket data; // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0); SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName()); } else { grp = _player->GetGroup(); // no group found, error if (!grp) return; if (grp->GetLeaderGUID() != _player->GetGUID()) return; err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam()); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; GroupQueueInfo* ginfo = NULL; uint32 avgTime = 0; if (err > 0) { sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: the following players are joining as group:"); ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, isPremade); avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); } for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* member = itr->getSource(); if (!member) continue; // this should never happen WorldPacket data; if (err <= 0) { sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); continue; } // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0); member->GetSession()->SendPacket(&data); sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName()); } sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: group end"); } sBattlegroundMgr->ScheduleQueueUpdate(bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { uint8 type; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recvData >> type >> unk2 >> bgTypeId_ >> unk >> action; if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Invalid BgType!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } if (!_player->InBattlegroundQueue()) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player not in queue!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } //get GroupQueueInfo from BattlegroundQueue BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, type); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player not in queue (No player Group Info)!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player is not invited to any bg!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); return; } Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) { if (action) { TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Cant find BG with id %u!", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action, ginfo.IsInvitedToBGInstanceGUID); return; } bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) { TC_LOG_ERROR("network", "BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } } TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u.", GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue if (!_player->CanJoinToBattleground(bg)) { //send bg command result to show nice message WorldPacket data2; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; TC_LOG_DEBUG("bg.battleground", "Player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { TC_LOG_ERROR("network", "Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; if (action) { // check Freeze debuff if (_player->HasAura(9454)) return; if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) return; // cheating? if (!_player->InBattleground()) _player->SetBattlegroundEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if (_player->IsInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.Team); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new if (Battleground* currentBg = _player->GetBattleground()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player, team); TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); } else // leave queue { if (bg->isArena() && bg->GetStatus() > STATUS_WAIT_QUEUE) return; // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team); if (at) { TC_LOG_DEBUG("bg.battleground", "UPDATING memberLost's personal arena rating for %s by opponents rating: %u, because he has left queue!", _player->GetGUID().ToString().c_str(), ginfo.OpponentsTeamRating); at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); at->SaveToDB(); } } _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); SendPacket(&data); TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); } }
void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) { uint32 bgTypeId_; uint32 instanceId; uint8 asGroup; bool isPremade = false; Group* grp = NULL; ObjectGuid guid; recvData >> instanceId; // Instance Id guid[2] = recvData.ReadBit(); guid[0] = recvData.ReadBit(); guid[3] = recvData.ReadBit(); guid[1] = recvData.ReadBit(); guid[5] = recvData.ReadBit(); asGroup = recvData.ReadBit(); // As Group guid[4] = recvData.ReadBit(); guid[6] = recvData.ReadBit(); guid[7] = recvData.ReadBit(); recvData.ReadByteSeq(guid[2]); recvData.ReadByteSeq(guid[6]); recvData.ReadByteSeq(guid[4]); recvData.ReadByteSeq(guid[3]); recvData.ReadByteSeq(guid[7]); recvData.ReadByteSeq(guid[0]); recvData.ReadByteSeq(guid[5]); recvData.ReadByteSeq(guid[1]); //extract from guid bgTypeId_ = GUID_LOPART(guid); if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { TC_LOG_ERROR("network", "Battleground: invalid bgtype (%u) received. possible cheater? player guid %u", bgTypeId_, _player->GetGUIDLow()); return; } if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) { ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); //TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID:"UI64FMTD" TypeId:%u)", guid, bgTypeId_); // can do this, since it's battleground, not arena BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); // ignore if player is already in BG if (_player->InBattleground()) return; // get bg instance or bg template if instance not found Battleground* bg = NULL; if (instanceId) bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId); if (!bg) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE; // check queue conditions if (!asGroup) { if (GetPlayer()->isUsingLfg()) { WorldPacket data; sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_LFG_CANT_USE_BATTLEGROUND); GetPlayer()->GetSession()->SendPacket(&data); return; } // check Deserter debuff if (!_player->CanJoinToBattleground(bg)) { WorldPacket data; sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data); return; } if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) { // player is already in random queue WorldPacket data; sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_RANDOM_BG); _player->GetSession()->SendPacket(&data); return; } if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) { // player is already in queue, can't start random queue WorldPacket data; sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_NON_RANDOM_BG); _player->GetSession()->SendPacket(&data); return; } // check if already in queue if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is already in this queue return; // check if has free queue slots if (!_player->HasFreeBattlegroundQueueId()) { WorldPacket data; sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_BATTLEGROUND_TOO_MANY_QUEUES); _player->GetSession()->SendPacket(&data); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); // add joined time data _player->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime); WorldPacket data; // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, ginfo->ArenaType); SendPacket(&data); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName().c_str()); } else { grp = _player->GetGroup(); if (!grp) return; if (grp->GetLeaderGUID() != _player->GetGUID()) return; err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); GroupQueueInfo* ginfo = NULL; uint32 avgTime = 0; if (!err) { TC_LOG_DEBUG("bg.battleground", "Battleground: the following players are joining as group:"); ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); } for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* member = itr->GetSource(); if (!member) continue; // this should never happen if (err) { WorldPacket data; sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, err); member->GetSession()->SendPacket(&data); continue; } // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); // add joined time data member->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime); WorldPacket data; // send status packet (in queue) sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, member, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, ginfo->ArenaType); member->GetSession()->SendPacket(&data); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName().c_str()); } TC_LOG_DEBUG("bg.battleground", "Battleground: group end"); } sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); }
void WorldSession::HandleBattlemasterJoinOpcode(WorldPackets::Battleground::BattlemasterJoin& battlemasterJoin) { bool isPremade = false; Group* grp = NULL; uint32 bgTypeId_ = battlemasterJoin.QueueID & 0xFFFF; if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { TC_LOG_ERROR("network", "Battleground: invalid bgtype (%u) received. possible cheater? %s", bgTypeId_, _player->GetGUID().ToString().c_str()); return; } if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) { ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); // can do this, since it's battleground, not arena BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); // ignore if player is already in BG if (_player->InBattleground()) return; // get bg instance or bg template if instance not found Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE; // check queue conditions if (!battlemasterJoin.JoinAsGroup) { if (GetPlayer()->isUsingLfg()) { WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bg, _player, 0, 0, ERR_LFG_CANT_USE_BATTLEGROUND); SendPacket(battlefieldStatus.Write()); return; } // check Deserter debuff if (!_player->CanJoinToBattleground(bg)) { WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bg, _player, 0, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); SendPacket(battlefieldStatus.Write()); return; } if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) { // player is already in random queue WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bg, _player, 0, 0, ERR_IN_RANDOM_BG); SendPacket(battlefieldStatus.Write()); return; } if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) { // player is already in queue, can't start random queue WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bg, _player, 0, 0, ERR_IN_NON_RANDOM_BG); SendPacket(battlefieldStatus.Write()); return; } // check if already in queue if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is already in this queue return; // check if has free queue slots if (!_player->HasFreeBattlegroundQueueId()) { WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bg, _player, 0, 0, ERR_BATTLEGROUND_TOO_MANY_QUEUES); SendPacket(battlefieldStatus.Write()); return; } // check Freeze debuff if (_player->HasAura(9454)) return; BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusQueued(&battlefieldStatus, bg, _player, queueSlot, ginfo->JoinTime, avgTime, ginfo->ArenaType, false); SendPacket(battlefieldStatus.Write()); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u, %s, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUID().ToString().c_str(), _player->GetName().c_str()); } else { grp = _player->GetGroup(); if (!grp) return; if (grp->GetLeaderGUID() != _player->GetGUID()) return; ObjectGuid errorGuid; err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0, errorGuid); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); GroupQueueInfo* ginfo = NULL; uint32 avgTime = 0; if (!err) { TC_LOG_DEBUG("bg.battleground", "Battleground: the following players are joining as group:"); ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); } for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* member = itr->GetSource(); if (!member) continue; // this should never happen if (err) { WorldPackets::Battleground::BattlefieldStatusFailed battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusFailed(&battlefieldStatus, bg, _player, 0, 0, err, &errorGuid); member->SendDirectMessage(battlefieldStatus.Write()); continue; } // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); WorldPackets::Battleground::BattlefieldStatusQueued battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusQueued(&battlefieldStatus, bg, member, queueSlot, ginfo->JoinTime, avgTime, ginfo->ArenaType, true); member->SendDirectMessage(battlefieldStatus.Write()); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u, %s, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUID().ToString().c_str(), member->GetName().c_str()); } TC_LOG_DEBUG("bg.battleground", "Battleground: group end"); } sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { uint8 arenaType; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recvData >> arenaType >> unk2 >> bgTypeId_ >> unk >> action; // bgTypeId not valid if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) return; // player not in any queue, so can't really answer if (!_player->InBattlegroundQueue()) return; // get BattlegroundQueue for received BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenaType); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); // get group info from queue GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) return; // to accept, player must be invited to particular battleground id if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) return; Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID); // use template if leaving queue (instance might not be created yet) if (!bg && action == 0) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; // safety checks if (action == 1 && ginfo.ArenaType == 0) { // can't join with deserter, check it here right before joining to be sure if (!_player->CanJoinToBattleground()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); SendPacket(&data); action = 0; } if (_player->getLevel() > bg->GetMaxLevel()) action = 0; } // get player queue slot index for this bg (can be in up to 2 queues at the same time) uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; switch (action) { case 1: // accept { // set entry point if not in battleground if (!_player->InBattleground()) _player->SetEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // remove player from all bg queues for (uint32 qslot = 0; qslot < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qslot) if (BattlegroundQueueTypeId q = _player->GetBattlegroundQueueTypeId(qslot)) { BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(q); queue.RemovePlayer(_player->GetGUID(), (bgQueueTypeId == q), qslot); _player->RemoveBattlegroundQueueId(q); } // send status packet sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.teamId); SendPacket(&data); _player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, ginfo.teamId); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); } break; case 0: // leave queue { bgQueue.RemovePlayer(_player->GetGUID(), false, queueSlot); _player->RemoveBattlegroundQueueId(bgQueueTypeId); } break; default: break; } }
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { player->PlayerTalkClass->ClearMenus(); if (player->InBattlegroundQueue()) { player->CLOSE_GOSSIP_MENU(); creature->MonsterWhisper(MSG_HAS_BG_QUEUE, player->GetGUID()); return true; } if (!ArenaWatcherEnable && (!ArenaWatcherOnlyGM || player->isGameMaster())) return true; if (action <= GOSSIP_OFFSET) { bool bracketExists = false; uint8 playerCount = action - GOSSIP_ACTION_INFO_DEF; for (uint8 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId) { if (!BattlegroundMgr::IsArenaType(BattlegroundTypeId(bgTypeId))) continue; if(BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(bgTypeId))){ if (!arenas || arenas->m_Battlegrounds.empty()) continue; for (BattlegroundContainer::const_iterator itr = arenas->m_Battlegrounds.begin(); itr != arenas->m_Battlegrounds.end(); ++itr) { if (Map* map = itr->second->FindBgMap()){ if (!(itr->second->GetStatus() & 2)) { continue; } if (itr->second->GetArenaType() != GetArenaBySlot(playerCount)) continue; if (ArenaWatcherOnlyRated && !itr->second->isRated()) continue; if (itr->second->GetStatus() != STATUS_IN_PROGRESS) continue; if (itr->second->isRated()) { if(ArenaTeam* teamOne = sArenaTeamMgr->GetArenaTeamById(itr->second->GetArenaTeamIdByIndex(0))) { if(ArenaTeam* teamTwo = sArenaTeamMgr->GetArenaTeamById(itr->second->GetArenaTeamIdByIndex(1))) { if (teamOne && teamTwo) { char gossipTextFormat[100]; snprintf(gossipTextFormat, 100, "%s : %s (%u) vs. %s (%u)", map->GetMapName(), teamOne->GetName().c_str(), teamOne->GetRating(), teamTwo->GetName().c_str(), teamTwo->GetRating()); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, gossipTextFormat, GOSSIP_SENDER_MAIN + bgTypeId, itr->first + GOSSIP_OFFSET); } } } } else { char gossipTextFormat[100]; snprintf(gossipTextFormat, 100, "[%u] %s : %u vs. %u", itr->first, map->GetMapName(), playerCount, playerCount); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, gossipTextFormat, GOSSIP_SENDER_MAIN + bgTypeId, itr->first + GOSSIP_OFFSET); } bracketExists = true; } } } } if (bracketExists) player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); else { sCreatureTextMgr->SendChat(creature, SAY_NOT_FOUND_BRACKET, player->GetGUID()); player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); } } else { uint32 arenaId = action - GOSSIP_OFFSET; uint32 bgTypeId = sender - GOSSIP_SENDER_MAIN; if(BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(bgTypeId))){ if (!arenas || arenas->m_Battlegrounds.empty()) return false; if (arenas->m_Battlegrounds[arenaId]) { if(Battleground* bg = arenas->m_Battlegrounds[arenaId]){ if (bg->GetStatus() != STATUS_IN_PROGRESS) { sCreatureTextMgr->SendChat(creature, SAY_ARENA_NOT_IN_PROGRESS, player->GetGUID()); player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); return false; } float x = 0.0f, y = 0.0f, z = 0.0f; if(bg){ switch (bg->GetMapId()) { case 617: x = 1299.046f; y = 784.825f; z = 9.338f; break; case 618: x = 763.5f; y = -284; z = 28.276f; break; case 572: x = 1285.810547f; y = 1667.896851f; z = 39.957642f; break; case 562: x = 6238.930176f; y = 262.963470f; z = 0.889519f; break; case 559: x = 4055.504395f; y = 2919.660645f; z = 13.611241f; break; default: player->PlayerTalkClass->ClearMenus(); player->CLOSE_GOSSIP_MENU(); return false; } } if(bg){ if(bg->GetStatus()==STATUS_IN_PROGRESS){ player->SetSpectator(true); player->SetBattlegroundId(bg->GetInstanceID(), bg->GetTypeID()); player->SetBattlegroundEntryPoint(); ArenaWatcherStart(player); player->TeleportTo(bg->GetMapId(), x, y, z, player->GetOrientation()); ArenaWatcherAfterTeleport(player); } } } } } } return true; }
void ShowPage(Player* player, uint16 page, uint32 IsTop) { uint32 firstTeamId = 0; uint16 TypeOne = 0; uint16 TypeTwo = 0; uint16 TypeThree = 0; uint16 mmr = 0; uint16 mmrTwo = 0; bool haveNextPage = false; for (uint8 i = 0; i <= MAX_BATTLEGROUND_TYPE_ID; ++i) { if (!sBattlegroundMgr->IsArenaType(BattlegroundTypeId(i))) continue; //BattlegroundContainer arenas = sBattlegroundMgr->GetBattlegroundsByType((BattlegroundTypeId)i); BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(i)); if (!arenas || arenas->m_Battlegrounds.empty()) continue; for (BattlegroundContainer::const_iterator itr = arenas->m_Battlegrounds.begin(); itr != arenas->m_Battlegrounds.end(); ++itr) { Battleground* arena = itr->second; Player* target = ObjectAccessor::FindPlayer(GetFirstPlayerGuid(arena)); if (target && (target->HasAura(32728) || target->HasAura(32727))) continue; if (!arena->GetPlayersSize()) continue; if (arena->GetArenaType() == ARENA_TYPE_2v2) { mmr = arena->GetArenaMatchmakerRating(0); firstTeamId = target->GetArenaTeamId(0); Battleground::BattlegroundPlayerMap::const_iterator citr = arena->GetPlayers().begin(); for (; citr != arena->GetPlayers().end(); ++citr) if (Player* plrs = sObjectAccessor->FindPlayer(citr->first)) if (plrs->GetArenaTeamId(0) != firstTeamId) mmrTwo = arena->GetArenaMatchmakerRating(citr->second.Team); } else if (arena->GetArenaType() == ARENA_TYPE_3v3) { mmr = arena->GetArenaMatchmakerRating(1); firstTeamId = target->GetArenaTeamId(1); Battleground::BattlegroundPlayerMap::const_iterator citr = arena->GetPlayers().begin(); for (; citr != arena->GetPlayers().end(); ++citr) if (Player* plrs = sObjectAccessor->FindPlayer(citr->first)) if (plrs->GetArenaTeamId(1) != firstTeamId) mmrTwo = arena->GetArenaMatchmakerRating(citr->second.Team); } else if (arena->GetArenaType() == ARENA_TYPE_5v5 && arena->GetArenaType() == ARENA_TYPE_3v3_SOLO) { mmr = arena->GetArenaMatchmakerRating(2); firstTeamId = target->GetArenaTeamId(2); Battleground::BattlegroundPlayerMap::const_iterator citr = arena->GetPlayers().begin(); for (; citr != arena->GetPlayers().end(); ++citr) if (Player* plrs = sObjectAccessor->FindPlayer(citr->first)) if (plrs->GetArenaTeamId(2) != firstTeamId) mmrTwo = arena->GetArenaMatchmakerRating(citr->second.Team); } if (IsTop == 1 && arena->GetArenaType() == ARENA_TYPE_2v2) { TypeOne++; if (TypeOne > (page + 1) * GamesOnPage) { haveNextPage = true; break; } if (TypeOne >= page * GamesOnPage) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, GetGamesStringData(arena, mmr, mmrTwo), GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_SELECTED_PLAYER + GetFirstPlayerGuid(arena)); } else if (IsTop == 2 && arena->GetArenaType() == ARENA_TYPE_3v3) { TypeTwo++; if (TypeTwo > (page + 1) * GamesOnPage) { haveNextPage = true; break; } if (TypeTwo >= page * GamesOnPage) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, GetGamesStringData(arena, mmr, mmrTwo), GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_SELECTED_PLAYER + GetFirstPlayerGuid(arena)); } else if (IsTop == 3 && arena->GetArenaType() == ARENA_TYPE_5v5 && arena->GetArenaType() == ARENA_TYPE_3v3_SOLO) { TypeThree++; if (TypeThree > (page + 1) * GamesOnPage) { haveNextPage = true; break; } if (TypeThree >= page * GamesOnPage) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, GetGamesStringData(arena, mmr, mmrTwo), GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_SELECTED_PLAYER + GetFirstPlayerGuid(arena)); } } } if (page > 0) { player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "前一页..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_2V2_GAMES + page - 1); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "前一页..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_3V3_GAMES + page - 1); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "前一页..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_5V5_GAMES + page - 1); } if (haveNextPage) { player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "后一页..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_2V2_GAMES + page + 1); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "后一页..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_3V3_GAMES + page + 1); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "后一页..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_5V5_GAMES + page + 1); } }