diff options
Diffstat (limited to 'src/game/BattleGround.cpp')
-rw-r--r-- | src/game/BattleGround.cpp | 485 |
1 files changed, 399 insertions, 86 deletions
diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 589b4175049..72366764af7 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -24,6 +24,7 @@ #include "Language.h" #include "Chat.h" #include "SpellAuras.h" +#include "ArenaTeam.h" #include "World.h" #include "Util.h" @@ -47,6 +48,8 @@ BattleGround::BattleGround() m_Name = ""; m_LevelMin = 0; m_LevelMax = 0; + m_InBGFreeSlotQueue = false; + m_SetDeleteThis = false; m_MaxPlayersPerTeam = 0; m_MaxPlayers = 0; @@ -67,21 +70,54 @@ BattleGround::BattleGround() m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocO[BG_TEAM_HORDE] = 0; + m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0; + m_ArenaTeamIds[BG_TEAM_HORDE] = 0; + + m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0; + m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0; + m_BgRaids[BG_TEAM_ALLIANCE] = NULL; m_BgRaids[BG_TEAM_HORDE] = NULL; m_PlayersCount[BG_TEAM_ALLIANCE] = 0; m_PlayersCount[BG_TEAM_HORDE] = 0; + + m_PrematureCountDown = false; + m_PrematureCountDown = 0; } BattleGround::~BattleGround() { + // remove objects and creatures + // (this is done automatically in mapmanager update, when the instance is reset after the reset time) + int size = m_BgCreatures.size(); + for(int i = 0; i < size; ++i) + { + DelCreature(i); + } + size = m_BgObjects.size(); + for(int i = 0; i < size; ++i) + { + DelObject(i); + } + // delete creature and go respawn times + WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID()); + WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID()); + // delete instance from db + CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID()); + // remove from battlegrounds + sBattleGroundMgr.RemoveBattleGround(GetInstanceID()); + // unload map + if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) + if(map->IsBattleGroundOrArena()) + ((BattleGroundMap*)map)->SetUnload(); + // remove from bg free slot queue + this->RemoveFromBGFreeSlotQueue(); } void BattleGround::Update(time_t diff) { - if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize()) //BG is empty return; @@ -188,6 +224,33 @@ void BattleGround::Update(time_t diff) m_ResurrectQueue.clear(); } + // if less then minimum players are in on one side, then start premature finish timer + if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) + { + if(!m_PrematureCountDown) + { + m_PrematureCountDown = true; + m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime(); + SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING); + } + else if(m_PrematureCountDownTimer < diff) + { + // time's up! + EndBattleGround(0); // noone wins + m_PrematureCountDown = false; + } + else + { + uint32 newtime = m_PrematureCountDownTimer - diff; + // announce every minute + if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000) + SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING); + m_PrematureCountDownTimer = newtime; + } + } + else if (m_PrematureCountDown) + m_PrematureCountDown = false; + if(GetStatus() == STATUS_WAIT_LEAVE) { // remove all players from battleground after 2 minutes @@ -239,7 +302,9 @@ void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player * if(!self && sender == plr) continue; - if(plr->GetTeam() == TeamID) + uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID()); + + if(team == TeamID) plr->GetSession()->SendPacket(packet); } } @@ -265,7 +330,9 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID) continue; } - if(plr->GetTeam() == TeamID) + uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID()); + + if(team == TeamID) { sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID); plr->GetSession()->SendPacket(&data); @@ -285,7 +352,9 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID) continue; } - if(plr->GetTeam() == TeamID) + uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID()); + + if(team == TeamID) plr->CastSpell(plr, SpellID, true); } } @@ -302,7 +371,9 @@ void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID) continue; } - if(plr->GetTeam() == TeamID) + uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID()); + + if(team == TeamID) UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor); } } @@ -324,7 +395,9 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, continue; } - if(plr->GetTeam() == TeamID) + uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID()); + + if(team == TeamID) plr->ModifyFactionReputation(factionEntry, Reputation); } } @@ -345,30 +418,87 @@ void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player void BattleGround::EndBattleGround(uint32 winner) { + // battleground finished, remove from the running bg's list + this->RemoveFromBGFreeSlotQueue(); + + ArenaTeam * winner_arena_team = NULL; + ArenaTeam * loser_arena_team = NULL; + uint32 loser_rating = 0; + uint32 winner_rating = 0; WorldPacket data; Player *Source = NULL; const char *winmsg = ""; if(winner == ALLIANCE) { - winmsg = GetMangosString(LANG_BG_A_WINS); + if(isBattleGround()) + winmsg = GetMangosString(LANG_BG_A_WINS); + else + winmsg = GetMangosString(LANG_ARENA_GOLD_WINS); PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound SetWinner(WINNER_ALLIANCE); } - else + else if(winner == HORDE) { - winmsg = GetMangosString(LANG_BG_H_WINS); + if(isBattleGround()) + winmsg = GetMangosString(LANG_BG_H_WINS); + else + winmsg = GetMangosString(LANG_ARENA_GREEN_WINS); PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound SetWinner(WINNER_HORDE); } + else + { + SetWinner(3); + } SetStatus(STATUS_WAIT_LEAVE); m_EndTime = 0; + // arena rating calculation + if(isArena() && isRated()) + { + if(winner == ALLIANCE) + { + winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); + loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); + } + else if(winner == HORDE) + { + winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); + loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); + } + if(winner_arena_team && loser_arena_team) + { + loser_rating = loser_arena_team->GetStats().rating; + winner_rating = winner_arena_team->GetStats().rating; + float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating); + float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating); + int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance); + int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance); + sLog.outDebug("--- %u ; %u ; %d ; %d ; %u ; %u ---",winner_rating,loser_rating,winner_chance,loser_chance,winner_change,loser_change); + if(winner == ALLIANCE) + { + SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change); + SetArenaTeamRatingChangeForTeam(HORDE, loser_change); + } + else + { + SetArenaTeamRatingChangeForTeam(HORDE, winner_change); + SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change); + } + } + else + { + SetArenaTeamRatingChangeForTeam(ALLIANCE, 0); + SetArenaTeamRatingChangeForTeam(HORDE, 0); + } + } + for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -378,13 +508,29 @@ void BattleGround::EndBattleGround(uint32 winner) continue; } + // should remove spirit of redemption + if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) + plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT); + if(!plr->isAlive()) { plr->ResurrectPlayer(1.0f); plr->SpawnCorpseBones(); } - if(plr->GetTeam() == winner) + uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID()); + if(!team) team = plr->GetTeam(); + + // per player calculation + if(isArena() && isRated() && winner_arena_team && loser_arena_team) + { + if(team == winner) + winner_arena_team->MemberWon(plr,loser_rating); + else + loser_arena_team->MemberLost(plr,winner_rating); + } + + if(team == winner) { if(!Source) Source = plr; @@ -404,10 +550,28 @@ void BattleGround::EndBattleGround(uint32 winner) sBattleGroundMgr.BuildPvpLogDataPacket(&data, this); plr->GetSession()->SendPacket(&data); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); + uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); plr->GetSession()->SendPacket(&data); } + if(isArena() && isRated() && winner_arena_team && loser_arena_team) + { + // update arena points only after increasing the player's match count! + winner_arena_team->UpdateArenaPointsHelper(); + loser_arena_team->UpdateArenaPointsHelper(); + // save the stat changes + winner_arena_team->SaveToDB(); + loser_arena_team->SaveToDB(); + // send updated arena team stats to players + // this way all arena team members will get notified, not only the ones who participated in this match + winner_arena_team->NotifyStatsChanged(); + loser_arena_team->NotifyStatsChanged(); + } + + // inform invited players about the removal + sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); + if(Source) { ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg); @@ -558,12 +722,16 @@ void BattleGround::BlockMovement(Player *plr) 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(itr->second.Team, true); // -1 player + 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; } std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid); @@ -577,6 +745,10 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac Player *plr = objmgr.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); @@ -589,66 +761,106 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac { plr->ClearAfkReports(); - if(isArena()) + if(participant) // if the player was a match participant, remove auras, calc rating, update queue { - if(!sWorld.IsFFAPvPRealm()) - plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); - } + if(!team) team = plr->GetTeam(); - WorldPacket data; - if(SendPacket) - { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0); - plr->GetSession()->SendPacket(&data); - } + uint32 bgTypeId = GetTypeID(); + uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType()); + // if arena, remove the specific arena auras + if(isArena()) + { + plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out + bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing) - // 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(m_TypeID); + // summon old pet if there was one and there isn't a current pet + if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber()) + { + Pet* NewPet = new Pet; + if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true)) + delete NewPet; - DecreaseInvitedCount(plr->GetTeam()); - //we should update battleground queue, but only if bg isn't ending - if (GetQueueType() < MAX_BATTLEGROUND_QUEUES) - sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType()); + (plr)->SetTemporaryUnsummonedPetNumber(0); + } - if(!plr->GetBattleGroundId()) - return; + if(isRated() && GetStatus() == STATUS_IN_PROGRESS) + { + //left a rated match while the encounter was in progress, consider as loser + ArenaTeam * winner_arena_team = 0; + ArenaTeam * loser_arena_team = 0; + if(team == HORDE) + { + winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); + loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); + } + else + { + winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); + loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); + } + if(winner_arena_team && loser_arena_team) + { + loser_arena_team->MemberLost(plr,winner_arena_team->GetRating()); + } + } + } - Group * group = plr->GetGroup(); + WorldPacket data; + if(SendPacket) + { + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0); + plr->GetSession()->SendPacket(&data); + } - // remove from raid group if exist - if(group && group == GetBgRaid(plr->GetTeam())) - { - if(!group->RemoveMember(guid, 0)) // group was disbanded + // 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 (GetQueueType() < MAX_BATTLEGROUND_QUEUES) + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType()); + + Group * group = plr->GetGroup(); + // remove from raid group if exist + if(group && group == GetBgRaid(team)) { - SetBgRaid(plr->GetTeam(), NULL); - delete group; + 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. - - // Let others know - sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr); - SendPacketToTeam(plr->GetTeam(), &data, plr, false); + // reset destination bg team + plr->SetBGTeam(0); if(Transport) { plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO()); - //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O); } // Log sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName()); } - /// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist - // we always should check if BG is in that queue before adding.. - - if(!GetPlayersSize()) + if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) { - Reset(); + // 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(); } // this method is called when no players remains in battleground @@ -660,6 +872,8 @@ void BattleGround::Reset() SetStartTime(0); SetEndTime(0); SetLastResurrectTime(0); + SetArenaType(0); + SetRated(false); m_Events = 0; @@ -668,11 +882,12 @@ void BattleGround::Reset() m_InvitedAlliance = 0; m_InvitedHorde = 0; + m_InBGFreeSlotQueue = false; m_Players.clear(); m_PlayerScores.clear(); - // reset BGSubclass + // reset BGSubclass (this cleans up creatures and gos as well) this->ResetBGSubclass(); } @@ -698,16 +913,19 @@ void BattleGround::AddPlayer(Player *plr) // Add to list/maps m_Players[guid] = bp; - UpdatePlayersCountByTeam(team, false); // +1 player + UpdatePlayersCountByTeam(team, false); // +1 player WorldPacket data; sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr); SendPacketToTeam(team, &data, plr, false); + // add arena specific auras if(isArena()) { + // remove auras first, only then reset spell cooldowns + // this is to prevent bugging amp. curse, combustion, etc. like spells + plr->RemoveArenaAuras(); plr->RemoveArenaSpellCooldowns(); - //plr->RemoveArenaAuras(); plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT); if(team == ALLIANCE && plr->GetTeam() == ALLIANCE) plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true); @@ -719,6 +937,17 @@ void BattleGround::AddPlayer(Player *plr) plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true); plr->DestroyConjuredItems(true); + Pet* pet = plr->GetPet(); + if(pet) + { + if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET) + { + (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); + (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); + } + (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); + } + if(GetStatus() == STATUS_WAIT_JOIN) // not started yet { plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true); @@ -733,9 +962,6 @@ void BattleGround::AddPlayer(Player *plr) plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells. } - if(isArena()) - plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); - // Log sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName()); } @@ -743,13 +969,20 @@ void BattleGround::AddPlayer(Player *plr) /* This method should be called only once ... it adds pointer to queue */ void BattleGround::AddToBGFreeSlotQueue() { - sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this); + // make sure to add only once + if(!m_InBGFreeSlotQueue) + { + sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this); + m_InBGFreeSlotQueue = true; + } } /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/ void BattleGround::RemoveFromBGFreeSlotQueue() { - /* uncomment this code when battlegrounds will work like instances + // set to be able to re-add if needed + m_InBGFreeSlotQueue = false; + // uncomment this code when battlegrounds will work like instances for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr) { if ((*itr)->GetInstanceID() == m_InstanceID) @@ -757,30 +990,66 @@ void BattleGround::RemoveFromBGFreeSlotQueue() sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr); return; } - }*/ + } } -/* -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 +// 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(); + 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) - return (GetInvitedCount(Team) <= otherTeam && GetInvitedCount(Team) < GetMaxPlayersPerTeam()); + { + // 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); + + // 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 false; + return 0; } -/* this method isn't called already, it will be useful when more battlegrounds of one type will be available */ bool BattleGround::HasFreeSlots() const { return GetPlayersSize() < GetMaxPlayers(); @@ -806,9 +1075,13 @@ void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) itr->second->HonorableKills += value; break; case SCORE_BONUS_HONOR: // Honor bonus - // reward honor instantly - if(Source->RewardHonor(NULL, 1, value)) - itr->second->BonusHonor += value; + // do not add honor in arenas + if(isBattleGround()) + { + // reward honor instantly + if(Source->RewardHonor(NULL, 1, value)) + itr->second->BonusHonor += value; + } break; //used only in EY, but in MSG_PVP_LOG_DATA opcode case SCORE_DAMAGE_DONE: // Damage Done @@ -864,15 +1137,26 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid) bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime) { - GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry); - if(!goinfo) + Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); + if(!map) + return false; + + // must be created this way, adding to godatamap would add it to the base map of the instance + // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created + // so we must create it specific for this instance + GameObject * go = new GameObject; + if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1)) { sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry); + sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry); + delete go; return false; } +/* + uint32 guid = go->GetGUIDLow(); - uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT); - + // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata + // iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed GameObjectData& data = objmgr.NewGOData(guid); data.id = entry; @@ -886,13 +1170,13 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float data.rotation2 = rotation2; data.rotation3 = rotation3; data.spawntimesecs = respawnTime; + data.spawnMask = 1; data.animprogress = 100; data.go_state = 1; - data.spawnMask = 1; - objmgr.AddGameobjectToGrid(guid, &data); - - m_BgObjects[type] = MAKE_NEW_GUID(guid, entry, HIGHGUID_GAMEOBJECT); - +*/ + // add to world, so it can be later looked up from HashMapHolder + go->AddToWorld(); + m_BgObjects[type] = go->GetGUID(); return true; } @@ -934,6 +1218,9 @@ void BattleGround::DoorOpen(uint32 type) void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) { + Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); + if(!map) + return; if( respawntime == 0 ) { GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); @@ -942,30 +1229,27 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again if( obj->getLootState() == GO_JUST_DEACTIVATED ) obj->SetLootState(GO_READY); - obj->Respawn(); + obj->SetRespawnTime(0); + map->Add(obj); } - else - objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0); } else { GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); if(obj) { + map->Add(obj); obj->SetRespawnTime(respawntime); obj->SetLootState(GO_JUST_DEACTIVATED); } - else - objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, time(NULL) + respawntime); } } -Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o) +Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime) { - // note: this should normally be FindMap - // but it's a hack to allow the battlegrounds to initialize at server startup - Map * map = MapManager::Instance().GetMap(GetMapId(), 0); - if(!map) return NULL; + Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); + if(!map) + return NULL; Creature* pCreature = new Creature; if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval)) @@ -989,6 +1273,7 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f map->Add(pCreature); m_BgCreatures[type] = pCreature->GetGUID(); + return pCreature; } @@ -1072,8 +1357,11 @@ void BattleGround::SendMessageToAll(int32 entry) void BattleGround::EndNow() { + RemoveFromBGFreeSlotQueue(); SetStatus(STATUS_WAIT_LEAVE); SetEndTime(TIME_TO_AUTOREMOVE); + // inform invited players about the removal + sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); } // Battleground messages are localized using the dbc lang, they are not client language dependent @@ -1151,3 +1439,28 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) // to be able to remove insignia player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE ); } + +// return the player's team based on battlegroundplayer info +// used in same faction arena matches mainly +uint32 BattleGround::GetPlayerTeam(uint64 guid) +{ + std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid); + if(itr!=m_Players.end()) + return itr->second.Team; + return 0; +} + +uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const +{ + int count = 0; + for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + if(itr->second.Team == Team) + { + Player * pl = objmgr.GetPlayer(itr->first); + if(pl && pl->isAlive()) + ++count; + } + } + return count; +} |