// get the number of free slots for team // works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const { //if BG is starting ... invite anyone if (GetStatus() == STATUS_WAIT_JOIN) return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0; //if BG is already started .. do not allow to join too much players of one faction uint32 otherTeam; uint32 otherIn; if (Team == ALLIANCE) { otherTeam = GetInvitedCount(HORDE); otherIn = GetPlayersCountByTeam(HORDE); } else { otherTeam = GetInvitedCount(ALLIANCE); otherIn = GetPlayersCountByTeam(ALLIANCE); } if (GetStatus() == STATUS_IN_PROGRESS) { // difference based on ppl invited (not necessarily entered battle) // default: allow 0 uint32 diff = 0; // allow join one person if the sides are equal (to fill up bg to minplayersperteam) if (otherTeam == GetInvitedCount(Team)) diff = 1; // allow join more ppl if the other side has more players else if(otherTeam > GetInvitedCount(Team)) diff = otherTeam - GetInvitedCount(Team); // difference based on max players per team (don't allow inviting more) uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0; // difference based on players who already entered // default: allow 0 uint32 diff3 = 0; // allow join one person if the sides are equal (to fill up bg minplayersperteam) if (otherIn == GetPlayersCountByTeam(Team)) diff3 = 1; // allow join more ppl if the other side has more players else if (otherIn > GetPlayersCountByTeam(Team)) diff3 = otherIn - GetPlayersCountByTeam(Team); // or other side has less than minPlayersPerTeam else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam()) diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1; // return the minimum of the 3 differences // min of diff and diff 2 diff = diff < diff2 ? diff : diff2; // min of diff, diff2 and diff3 return diff < diff3 ? diff : diff3 ; } return 0; }
/* this method should decide, if we can invite new player of certain team to BG, it is based on BATTLEGROUND_STATUS */ bool BattleGround::HasFreeSlotsForTeam(uint32 Team) const { //if BG is starting ... invite anyone: if (GetStatus() == STATUS_WAIT_JOIN) return GetInvitedCount(Team) < GetMaxPlayersPerTeam(); //if BG is already started .. do not allow to join too much players of one faction uint32 otherTeam; if (Team == ALLIANCE) otherTeam = GetInvitedCount(HORDE); else otherTeam = GetInvitedCount(ALLIANCE); if (GetStatus() == STATUS_IN_PROGRESS) return (GetInvitedCount(Team) <= otherTeam && GetInvitedCount(Team) < GetMaxPlayersPerTeam()); return false; }
// get the number of free slots for team // returns the number how many players can join battleground to MaxPlayersPerTeam uint32 BattleGround::GetFreeSlotsForTeam(Team team) const { // return free slot count to MaxPlayerPerTeam if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS) return (GetInvitedCount(team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(team) : 0; return 0; }
void BattleGround::Update(uint32 diff) { if (!GetPlayersSize()) { // BG is empty // if there are no players invited, delete BG // this will delete arena or bg object, where any player entered // [[ but if you use battleground object again (more battles possible to be played on 1 instance) // then this condition should be removed and code: // if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) // this->AddToFreeBGObjectsQueue(); // not yet implemented // should be used instead of current // ]] // BattleGround Template instance cannot be updated, because it would be deleted if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) delete this; return; } // remove offline players from bg after 5 minutes if (!m_OfflineQueue.empty()) { BattleGroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin())); if (itr != m_Players.end()) { if (itr->second.OfflineRemoveTime <= sWorld.GetGameTime()) { RemovePlayerAtLeave(itr->first, true, true);// remove player from BG m_OfflineQueue.pop_front(); // remove from offline queue // do not use itr for anything, because it is erased in RemovePlayerAtLeave() } } } /*********************************************************/ /*** BATTLEGROUND BALLANCE SYSTEM ***/ /*********************************************************/ // if less then minimum players are in on one side, then start premature finish timer if (GetStatus() == STATUS_IN_PROGRESS && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) { if (!m_PrematureCountDown) { m_PrematureCountDown = true; m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime(); } else if (m_PrematureCountDownTimer < diff) { // time's up! Team winner = TEAM_NONE; if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam()) winner = ALLIANCE; else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam()) winner = HORDE; EndBattleGround(winner); m_PrematureCountDown = false; } else if (!sBattleGroundMgr.isTesting()) { uint32 newtime = m_PrematureCountDownTimer - diff; // announce every minute if (newtime > (MINUTE * IN_MILLISECONDS)) { if (newtime / (MINUTE * IN_MILLISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILLISECONDS)) PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILLISECONDS))); } else { // announce every 15 seconds if (newtime / (15 * IN_MILLISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILLISECONDS)) PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / IN_MILLISECONDS)); } m_PrematureCountDownTimer = newtime; } } else if (m_PrematureCountDown) m_PrematureCountDown = false; /*********************************************************/ /*** BATTLEGROUND STARTING SYSTEM ***/ /*********************************************************/ if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) { ModifyStartDelayTime(diff); if (!(m_Events & BG_STARTING_EVENT_1)) { m_Events |= BG_STARTING_EVENT_1; StartingEventCloseDoors(); SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FIRST]); // first start warning - 2 or 1 minute, only if defined if (m_StartMessageIds[BG_STARTING_EVENT_FIRST]) SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL); } // After 1 minute or 30 seconds, warning is signalled else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2)) { m_Events |= BG_STARTING_EVENT_2; SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL); } // After 30 or 15 seconds, warning is signalled else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3)) { m_Events |= BG_STARTING_EVENT_3; SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL); } // delay expired (atfer 2 or 1 minute) else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4)) { m_Events |= BG_STARTING_EVENT_4; StartingEventOpenDoors(); SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL); SetStatus(STATUS_IN_PROGRESS); SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FOURTH]); { PlaySoundToAll(SOUND_BG_START); // Announce BG starting if (sWorld.getConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START)) { sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel()); } } } } /*********************************************************/ /*** BATTLEGROUND ENDING SYSTEM ***/ /*********************************************************/ if (GetStatus() == STATUS_WAIT_LEAVE) { // remove all players from battleground after 2 minutes m_EndTime -= diff; if (m_EndTime <= 0) { m_EndTime = 0; BattleGroundPlayerMap::iterator itr, next; for (itr = m_Players.begin(); itr != m_Players.end(); itr = next) { next = itr; ++next; // itr is erased here! RemovePlayerAtLeave(itr->first, true, true);// remove player from BG // do not change any battleground's private variables } } } // update start time m_StartTime += diff; }
void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket) { uint32 team = GetPlayerTeam(guid); bool participant = false; // Remove from lists/maps std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid); if(itr != m_Players.end()) { UpdatePlayersCountByTeam(team, true); // -1 player m_Players.erase(itr); // check if the player was a participant of the match, or only entered through gm command (goname) participant = true; } BattleGroundScoreMap::iterator itr2 = m_PlayerScores.find(guid); if(itr2 != m_PlayerScores.end()) { delete itr2->second; // delete player's score m_PlayerScores.erase(itr2); } Player *plr = sObjectMgr.GetPlayer(guid); // should remove spirit of redemption if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT); if(plr && !plr->isAlive()) // resurrect on exit { plr->ResurrectPlayer(1.0f); plr->SpawnCorpseBones(); } RemovePlayer(plr, guid); // BG subclass specific code if(plr) { if(participant) // if the player was a match participant, remove auras, calc rating, update queue { if(!team) team = plr->GetTeam(); BattleGroundTypeId bgTypeId = GetTypeID(); uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID()); WorldPacket data; if(SendPacket) { sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); } // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg plr->RemoveBattleGroundQueueId(bgQueueTypeId); DecreaseInvitedCount(team); //we should update battleground queue, but only if bg isn't ending if (GetBracketId() < MAX_BATTLEGROUND_BRACKETS) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetBracketId()); Group * group = plr->GetGroup(); // remove from raid group if exist if(group && group == GetBgRaid(team)) { if(!group->RemoveMember(guid, 0)) // group was disbanded { SetBgRaid(team, NULL); delete group; } } // Let others know sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr); SendPacketToTeam(team, &data, plr, false); } // Do next only if found in battleground plr->SetBattleGroundId(0); // We're not in BG. // reset destination bg team plr->SetBGTeam(0); if(Transport) plr->TeleportTo(plr->GetBattleGroundEntryPoint()); DETAIL_LOG("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName()); } if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) { // if no players left AND no invitees left, set this bg to delete in next update // direct deletion could cause crashes m_SetDeleteThis = true; // return to prevent addition to freeslotqueue return; } // a player exited the battleground, so there are free slots. add to queue this->AddToBGFreeSlotQueue(); }