rendered paste body'Index: configure.ac
===================================================================
--- configure.ac (revision 5447)
+++ configure.ac (working copy)
@@ -228,7 +228,10 @@
src/mangosd/Makefile
src/mangosd/mangosd.conf
src/bindings/Makefile
- src/bindings/universal/Makefile
+ src/bindings/ScriptDev2/Makefile
+ src/bindings/ScriptDev2/config.h
+ src/bindings/ScriptDev2/sql/Makefile
+ src/bindings/ScriptDev2/sql/Updates/Makefile
])
## Disabled Makefiles, until they are ready for a successful make and
Index: src/bindings/Makefile.am
===================================================================
--- src/bindings/Makefile.am (revision 5447)
+++ src/bindings/Makefile.am (working copy)
@@ -14,4 +14,4 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-SUBDIRS = universal
+SUBDIRS = ScriptDev2
Index: src/game/ArenaTeam.cpp
===================================================================
--- src/game/ArenaTeam.cpp (revision 5447)
+++ src/game/ArenaTeam.cpp (working copy)
@@ -51,7 +51,7 @@
if(objmgr.GetArenaTeamByName(ArenaTeamName)) // arena team with this name already exist
return false;
- sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid));
+ sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));
CaptainGuid = captainGuid;
Name = ArenaTeamName;
@@ -130,6 +130,7 @@
newmember.played_week = 0;
newmember.wons_season = 0;
newmember.wons_week = 0;
+ newmember.points_to_add = 0;
members.push_back(newmember);
CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));
@@ -138,10 +139,14 @@
{
pl->SetInArenaTeam(Id, GetSlot());
pl->SetArenaTeamIdInvited(0);
+ // personal rating
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);
}
else
{
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id, PlayerGuid);
+ // personal rating
+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500, PlayerGuid);
}
// hide promote/remove buttons
@@ -207,7 +212,7 @@
{
Field *fields;
- QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
if(!result)
return;
@@ -221,6 +226,7 @@
newmember.wons_week = fields[2].GetUInt32();
newmember.played_season = fields[3].GetUInt32();
newmember.wons_season = fields[4].GetUInt32();
+ newmember.points_to_add = fields[5].GetUInt32();
members.push_back(newmember);
}while( result->NextRow() );
delete result;
@@ -279,13 +285,22 @@
{
player->SetInArenaTeam(0, GetSlot());
player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
+ // delete all info regarding this team
+ for(int i = 0; i < 6; ++i)
+ {
+ player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);
+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0, guid);
+ }
}
else
{
- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid);
+ // delete all info regarding this team
+ for(int i = 0; i < 6; ++i)
+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0, guid);
}
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));
+ // only delete from this arena team!
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid));
}
void ArenaTeam::Disband(WorldSession *session)
@@ -312,6 +327,7 @@
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id);
CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
CharacterDatabase.CommitTransaction();
objmgr.RemoveArenaTeam(this);
@@ -390,6 +406,18 @@
session->SendPacket(&data);
}
+void ArenaTeam::NotifyStatsChanged()
+{
+ // this is called after a rated match ended
+ // updates arena team stats for every member of the team (not only the ones who participated!)
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ Player * plr=objmgr.GetPlayer(itr->guid);
+ if(plr)
+ Stats(plr->GetSession());
+ }
+}
+
void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
{
WorldPacket data(MSG_INSPECT_ARENA_STATS, 8+1+4*6);
@@ -397,10 +425,20 @@
data << uint8(GetSlot()); // slot (0...2)
data << uint32(GetId()); // arena team id
data << uint32(stats.rating); // rating
- data << uint32(stats.games); // games
- data << uint32(stats.wins); // wins
- data << uint32(stats.played); // played (count of all games, that played...)
- data << uint32(0); // unk, 2.3.3
+ data << uint32(stats.played); // season played
+ data << uint32(stats.wins2); // season wins
+ uint32 participated = 0;
+ for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr)
+ {
+ if(itr->guid == guid)
+ {
+ participated = itr->played_season;
+ break;
+ }
+ }
+ data << uint32(participated); // played (count of all games, that the inspected member participated...)
+ data << uint32(0); // unk, 2.3.3 (personal rating?)
+
session->SendPacket(&data);
}
@@ -478,24 +516,204 @@
}
}
+uint32 ArenaTeam::GetPoints()
+{
+ // returns how many points would be awarded with this team type with this rating
+ float points;
+
+ if(stats.rating<=1500)
+ {
+ points = (float)stats.rating * 0.22f + 14.0f;
+ }
+ else
+ {
+ points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)stats.rating));
+ }
+
+ // type penalties for <5v5 teams
+ if(Type == ARENA_TEAM_2v2)
+ points *= 0.76f;
+ else if(Type == ARENA_TEAM_3v3)
+ points *= 0.88f;
+
+ return (uint32) points;
+}
+
+float ArenaTeam::GetChanceAgainst(uint32 rating)
+{
+ // returns the chance to win against a team with the given rating, used in the rating adjustment calculation
+ // ELO system
+ return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f));
+}
+
+int32 ArenaTeam::WonAgainstChance(float chance)
+{
+ // called when the team has won, and had 'chance' calculated chance to beat the opponent
+ // calculate the rating modification (ELO system with k=32)
+ int32 mod = (int32)(32.0f * (1.0f - chance));
+ // modify the team stats accordingly
+ stats.rating += mod;
+ stats.games += 1;
+ stats.wins += 1;
+ stats.played += 1;
+ stats.wins2 += 1;
+/* this should be done in .flusharenapoints; not a breaker though.
+ uint32 higher_rank = 0;
+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
+ if(result)
+ {
+ higher_rank = result->Fetch()->GetUInt32();
+ delete result;
+ }
+ stats.rank = higher_rank + 1;*/
+ // return the rating change, used to display it on the results screen
+ return mod;
+}
+
+int32 ArenaTeam::LostAgainstChance(float chance)
+{
+ // called when the team has lost, and had 'chance' calculated chance to beat the opponent
+ // calculate the rating modification (ELO system with k=32)
+ int32 mod = (int32)(32.0f * (0.0f - chance));
+ // modify the team stats accordingly
+ stats.rating += mod;
+ stats.games += 1;
+ stats.played += 1;
+/* uint32 higher_rank = 0;
+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
+ if(result)
+ {
+ higher_rank = result->Fetch()->GetUInt32();
+ delete result;
+ }
+ stats.rank = higher_rank + 1;*/
+ // return the rating adjustment for display
+ return mod;
+}
+
+void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)
+{
+ // called for each participant of a match after losing
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if(itr->guid == plr->GetGUID())
+ {
+ // update personal rating
+ int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
+ int32 mod = (int32)(32.0f * (0.0f - chance));
+ personalrating += mod;
+ if(personalrating < 0)
+ personalrating = 0;
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
+ // update personal played stats
+ itr->played_week +=1;
+ itr->played_season +=1;
+ // update the unit fields
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
+ return;
+ }
+ }
+}
+
+void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)
+{
+ // called for each participant after winning a match
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if(itr->guid == plr->GetGUID())
+ {
+ // update personal rating
+ int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
+ int32 mod = (int32)(32.0f * (1.0f - chance));
+ personalrating += mod;
+ if(personalrating < 0)
+ personalrating = 0;
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
+ // update personal stats
+ itr->played_week +=1;
+ itr->played_season +=1;
+ itr->wons_season += 1;
+ itr->wons_week += 1;
+ // update unit fields
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
+ return;
+ }
+ }
+}
+
+uint32 ArenaTeam::GetMemberPoints(uint64 guid)
+{
+ // get the points a member should be awarded
+ // called from arena point distribution (.flusharenapoints command)
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if(itr->guid == guid)
+ {
+ return itr->points_to_add;
+ }
+ }
+ return 0;
+}
+
+void ArenaTeam::UpdateArenaPointsHelper()
+{
+ // called after a match has ended and the stats are already modified
+ // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
+ // 10 played games per week is a minimum
+ if(stats.games < 10)
+ return;
+ // to get points, a player has to participate in at least 30% of the matches
+ uint32 min_plays = stats.games * 0.3;
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ // the player participated in enough games, update his points
+ if(itr->played_week >= min_plays)
+ {
+ // it's enough to set the points in memory, the saving is done in separate function
+ itr->points_to_add = GetPoints();
+ // CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->points_to_add,Id, itr->guid);
+ }
+ // the player failed to participate in enough games, so no points for him
+ else
+ {
+ itr->points_to_add = 0;
+ }
+ }
+}
+
+void ArenaTeam::SaveToDB()
+{
+ // save team and member stats to db
+ // called after a match has ended
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games, stats.played, stats.rank, stats.wins, stats.wins2, GetId());
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, itr->points_to_add, Id, itr->guid);
+ }
+}
+
/*
arenateam fields (id from 2.3.3 client):
1414 - arena team id 2v2
1415 - 0=captain, 1=member
-1416 - played this season
-1417 - played this week
+1416 - played this week
+1417 - played this season
1418 - unk
-1419 - unk
+1419 - personal arena rating
1420 - arena team id 3v3
1421 - 0=captain, 1=member
-1422 - played this season
-1423 - played this week
+1422 - played this week
+1423 - played this season
1424 - unk
-1425 - unk
+1425 - personal arena rating
1426 - arena team id 5v5
1427 - 0=captain, 1=member
-1428 - played this season
-1429 - played this week
+1428 - played this week
+1429 - played this season
1430 - unk
-1431 - unk
+1431 - personal arena rating
*/
Index: src/game/ArenaTeam.h
===================================================================
--- src/game/ArenaTeam.h (revision 5447)
+++ src/game/ArenaTeam.h (working copy)
@@ -92,6 +92,7 @@
uint32 wons_week;
uint32 played_season;
uint32 wons_season;
+ uint32 points_to_add;
};
struct ArenaTeamStats
@@ -145,6 +146,8 @@
void LoadStatsFromDB(uint32 ArenaTeamId);
void LoadPlayerStats(ArenaTeamMember* member);
+ void SaveToDB();
+
void BroadcastPacket(WorldPacket *packet);
void Roster(WorldSession *session);
@@ -152,6 +155,18 @@
void Stats(WorldSession *session);
void InspectStats(WorldSession *session, uint64 guid);
+ uint32 GetPoints();
+ float GetChanceAgainst(uint32 rating);
+ int32 WonAgainstChance(float chance);
+ void MemberWon(Player * plr, uint32 againstrating);
+ int32 LostAgainstChance(float chance);
+ void MemberLost(Player * plr, uint32 againstrating);
+
+ void UpdateArenaPointsHelper();
+ uint32 GetMemberPoints(uint64 guid);
+
+ void NotifyStatsChanged();
+
protected:
uint32 Id;
Index: src/game/BattleGround.cpp
===================================================================
--- src/game/BattleGround.cpp (revision 5447)
+++ src/game/BattleGround.cpp (working copy)
@@ -24,6 +24,7 @@
#include "Language.h" // for chat messages
#include "Chat.h"
#include "SpellAuras.h"
+#include "ArenaTeam.h"
#include "World.h"
BattleGround::BattleGround()
@@ -45,6 +46,8 @@
m_Name = "";
m_LevelMin = 0;
m_LevelMax = 0;
+ m_InBGFreeSlotQueue = false;
+ m_SetDeleteThis = false;
m_MaxPlayersPerTeam = 0;
m_MaxPlayers = 0;
@@ -65,6 +68,12 @@
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;
@@ -74,12 +83,34 @@
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 bound char instances (this should have been already deleted?)
+ CharacterDatabase.PExecute("DELETE FROM `character_instance` WHERE `instance` = '%u'", GetInstanceID());
+ // 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());
+ // remove from bg free slot queue
+ this->RemoveFromBGFreeSlotQueue();
}
void BattleGround::Update(time_t diff)
{
-
if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
//BG is empty
return;
@@ -236,7 +267,10 @@
if(!self && sender == plr)
continue;
- if(plr->GetTeam() == TeamID)
+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ if(!team) team = plr->GetTeam();
+
+ if(team == TeamID)
plr->GetSession()->SendPacket(packet);
}
}
@@ -262,7 +296,10 @@
continue;
}
- if(plr->GetTeam() == TeamID)
+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ if(!team) team = plr->GetTeam();
+
+ if(team == TeamID)
{
sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
plr->GetSession()->SendPacket(&data);
@@ -282,7 +319,10 @@
continue;
}
- if(plr->GetTeam() == TeamID)
+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ if(!team) team = plr->GetTeam();
+
+ if(team == TeamID)
plr->CastSpell(plr, SpellID, true);
}
}
@@ -299,7 +339,10 @@
continue;
}
- if(plr->GetTeam() == TeamID)
+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ if(!team) team = plr->GetTeam();
+
+ if(team == TeamID)
UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
}
}
@@ -321,7 +364,10 @@
continue;
}
- if(plr->GetTeam() == TeamID)
+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ if(!team) team = plr->GetTeam();
+
+ if(team == TeamID)
plr->ModifyFactionReputation(factionEntry, Reputation);
}
}
@@ -335,13 +381,22 @@
void BattleGround::EndBattleGround(uint32 winner)
{
+ 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
@@ -349,7 +404,10 @@
}
else
{
- 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
@@ -359,6 +417,47 @@
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
+ {
+ 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);
+ if(winner == ALLIANCE)
+ {
+ SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
+ SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
+ }
+ else
+ {
+ SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
+ SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
+ }
+ winner_arena_team->UpdateArenaPointsHelper();
+ loser_arena_team->UpdateArenaPointsHelper();
+ }
+ else
+ {
+ SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
+ SetArenaTeamRatingChangeForTeam(HORDE, 0);
+ }
+ }
+
uint32 mark = 0;
for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
@@ -370,14 +469,30 @@
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;
switch(GetTypeID())
@@ -428,10 +543,25 @@
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)
+ {
+ // 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_GLOBAL, Source->GetGUID(), winmsg);
@@ -448,11 +578,12 @@
void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
{
+ uint32 team = GetPlayerTeam(guid);
// 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);
}
@@ -467,6 +598,10 @@
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);
@@ -477,41 +612,103 @@
if(plr)
{
+ if(!team) team = plr->GetTeam();
+
+ uint32 bgTypeId = GetTypeID();
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
+ // if arena, remove the specific arena auras
if(isArena())
{
- if(!sWorld.IsFFAPvPRealm())
- plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
+ plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
+ plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
+ plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_GOLD_FLAG);
+ plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_GREEN_FLAG);
+ plr->RemoveAurasDueToSpell(SPELL_HORDE_GOLD_FLAG);
+ plr->RemoveAurasDueToSpell(SPELL_HORDE_GREEN_FLAG);
+ bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
- plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
+ Pet* NewPet = new Pet(plr);
+ if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetOldPetNumber(), true))
+ delete NewPet;
+
+ (plr)->SetOldPetNumber(0);
+ 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());
+ }
+ }
}
WorldPacket data;
if(SendPacket)
{
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
+ 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(m_TypeID);
+ plr->RemoveBattleGroundQueueId(bgQueueTypeId);
- DecreaseInvitedCount(plr->GetTeam());
+ DecreaseInvitedCount(team);
//we should update battleground queue, but only if bg isn't ending
if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
- sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType());
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
if(!plr->GetBattleGroundId())
return;
Group * group = plr->GetGroup();
-
// remove from raid group if exist
- if(group && group == GetBgRaid(plr->GetTeam()))
+ if(group && group == GetBgRaid(team))
{
+ uint32 groupSize = group->GetMembersCount();
+ GroupReference * grpRef = group->GetFirstMember();
+ Player * grpGuy = grpRef->getSource();
+ // get a member of the group, will be used if the group is disbanded
+ // if the one we got is the player, get another
+ if(grpGuy->GetGUID()==guid)
+ {
+ if(grpRef->hasNext())
+ {
+ grpRef = grpRef->next();
+ grpGuy = grpRef->getSource();
+ }
+ else if(grpRef->hasPrev())
+ {
+ grpRef = (GroupReference*)grpRef->prev();
+ grpGuy = grpRef->getSource();
+ }
+ else
+ grpGuy = NULL;
+ }
if(!group->RemoveMember(guid, 0)) // group was disbanded
{
- SetBgRaid(plr->GetTeam(), NULL);
+ SetBgRaid(team, NULL);
delete group;
+ if(groupSize >= 2 && grpGuy != 0) // someone's still left in the bg, recreate group for him
+ {
+ group = new Group;
+ SetBgRaid(team, group);
+ group->ConvertToRaid();
+ group->AddMember(grpGuy->GetGUID(), grpGuy->GetName());
+ group->ChangeLeader(grpGuy->GetGUID());
+ // we don't have to add other players, since the group is only disbanded if the player count before the leave was exactly 2
+ }
}
}
@@ -520,11 +717,12 @@
// Let others know
sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
- SendPacketToTeam(plr->GetTeam(), &data, plr, false);
+ SendPacketToTeam(team, &data, plr, false);
if(Transport)
{
plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO(), true, false);
+ //plr->SetInstanceId(plr->GetBattleGroundEntryPointInstanceId());
//sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);
}
@@ -532,13 +730,29 @@
sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
}
+ // remove player from bg instance!
+ CharacterDatabase.PExecute("DELETE FROM `character_instance` WHERE `guid` = '%u' AND `instance` = '%u'", guid, GetInstanceID());
+
+ if(plr)
+ {
+ // remove player from bg instance!!!
+ plr->m_BoundInstances.erase(GetMapId());
+ }
+
/// 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
@@ -550,6 +764,8 @@
SetStartTime(0);
SetEndTime(0);
SetLastResurrectTime(0);
+ SetArenaType(0);
+ SetRated(false);
m_Events = 0;
@@ -558,11 +774,12 @@
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();
}
@@ -575,52 +792,64 @@
WorldPacket data;
BattleGround *bg = NULL;
-
- /// this code seems not correct:
- if(GetTypeID() == BATTLEGROUND_AA)
- {
- // we must select one of running arena
- uint8 arenas[3] = { BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL };
- uint8 arena_type = arenas[urand(0, 2)];
-
- bg = sBattleGroundMgr.GetBattleGround(arena_type);
- if(!bg)
- return;
-
- bg->SetStatus(STATUS_WAIT_JOIN);
-
- bg->SetStartTime(0);
- bg->SetLastResurrectTime(0);
- }
}
-void BattleGround::AddPlayer(Player *plr)
+void BattleGround::AddPlayer(Player *plr, uint32 team)
{
// score struct must be created in inherited class
+ if(team==0)
+ team = plr->GetTeam();
uint64 guid = plr->GetGUID();
BattleGroundPlayer bp;
bp.LastOnlineTime = 0;
- bp.Team = plr->GetTeam();
+ bp.Team = team;
// Add to list/maps
m_Players[guid] = bp;
- UpdatePlayersCountByTeam(plr->GetTeam(), false); // +1 player
+ UpdatePlayersCountByTeam(team, false); // +1 player
WorldPacket data;
sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
- SendPacketToTeam(plr->GetTeam(), &data, plr, false);
+ SendPacketToTeam(team, &data, plr, false);
+ // add arena specific auras
if(isArena())
{
+ plr->RemoveArenaSpellCooldowns();
+ plr->RemoveArenaAuras();
+ if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)
+ plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);
+ else if(team == HORDE && plr->GetTeam() == ALLIANCE)
+ plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);
+ else if(team == ALLIANCE && plr->GetTeam() == HORDE)
+ plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);
+ else
+ 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)->SetOldPetNumber(pet->GetCharmInfo()->GetPetNumber());
+ (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
+ }
+ (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
+ }
+ else
+ (plr)->SetOldPetNumber(0);
+
if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
{
- // temporary disabled
- //plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
+ plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
+
+ plr->SetHealth(plr->GetMaxHealth());
+ plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
}
- plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
}
// Log
@@ -630,13 +859,20 @@
/* 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)
@@ -644,7 +880,7 @@
sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
return;
}
- }*/
+ }
}
/*
@@ -667,6 +903,31 @@
return false;
}
+// get the number of free slots for team
+// works in similar way that HasFreeSlotsForTeam
+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;
+ if (Team == ALLIANCE)
+ otherTeam = GetInvitedCount(HORDE);
+ else
+ otherTeam = GetInvitedCount(ALLIANCE);
+ if (GetStatus() == STATUS_IN_PROGRESS)
+ {
+ uint32 diff = (otherTeam <= GetInvitedCount(Team)) ? 0 : otherTeam - GetInvitedCount(Team);
+
+ uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
+
+ return diff < diff2 ? diff : diff2 ;
+ }
+
+ 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
{
@@ -693,7 +954,9 @@
itr->second->HonorableKills += value;
break;
case SCORE_BONUS_HONOR: // Honor bonus
- itr->second->BonusHonor += value;
+ // do not add honor in arenas
+ if(isBattleGround())
+ itr->second->BonusHonor += value;
break;
//used only in EY, but in MSG_PVP_LOG_DATA opcode
case SCORE_DAMAGE_DONE: // Damage Done
@@ -747,49 +1010,30 @@
bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 spawntime)
{
- GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
- if(!goinfo)
+ GameObject * go = new GameObject(NULL);
+ go->SetInstanceId(GetInstanceID());
+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, GetMapId(),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 = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
-
- GameObjectData& data = objmgr.NewGOData(guid);
-
- data.id = entry;
- data.mapid = GetMapId();
- data.posX = x;
- data.posY = y;
- data.posZ = z;
- data.orientation = o;
- data.rotation0 = rotation0;
- data.rotation1 = rotation1;
- data.rotation2 = rotation2;
- data.rotation3 = rotation3;
- data.spawntimesecs = spawntime;
- data.animprogress = 100;
- data.go_state = 1;
- objmgr.AddGameobjectToGrid(guid, &data);
-
- m_BgObjects[type] = MAKE_GUID(guid, HIGHGUID_GAMEOBJECT);
-
+ m_BgObjects[type] = go;
return true;
}
void BattleGround::DoorOpen(uint32 type)
{
- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
+ GameObject *obj = m_BgObjects[type];
if(obj)
{
obj->SetUInt32Value(GAMEOBJECT_FLAGS,33);
obj->SetUInt32Value(GAMEOBJECT_STATE,0);
- //obj->SetLootState(GO_CLOSED);
}
else
{
- sLog.outError("Object not found");
+ sLog.outError("Battleground: DoorOpen: Object not found");
}
}
@@ -797,32 +1041,31 @@
{
if(respawntime == 0)
{
- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
+ GameObject *obj = m_BgObjects[type];
if(obj)
{
//obj->Respawn(); // bugged
obj->SetRespawnTime(0);
- objmgr.SaveGORespawnTime(obj->GetGUIDLow(), 0, 0);
+ objmgr.SaveGORespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);
}
- else
- objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0);
}
else
{
- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
+ GameObject *obj = m_BgObjects[type];
if(obj)
{
obj->SetRespawnTime(respawntime);
obj->SetLootState(GO_LOOTED);
+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);
}
- 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)
{
Creature* pCreature = new Creature(NULL);
+ pCreature->SetInstanceId(GetInstanceID());
if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMapId(), x, y, z, o, entry, teamval))
{
sLog.outError("Can't create creature entry: %u",entry);
@@ -833,17 +1076,42 @@
pCreature->AIM_Initialize();
//pCreature->SetDungeonDifficulty(0);
- MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);
- m_BgCreatures[type] = pCreature->GetGUID();
+ m_BgCreatures[type] = pCreature;
+
return pCreature;
}
+void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
+{
+ if(respawntime == 0)
+ {
+ Creature *obj = m_BgCreatures[type];
+ if(obj)
+ {
+ //obj->Respawn(); // bugged
+ obj->SetRespawnTime(0);
+ objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);
+ }
+ }
+ else
+ {
+ Creature *obj = m_BgCreatures[type];
+ if(obj)
+ {
+ obj->setDeathState(DEAD);
+ obj->SetRespawnTime(respawntime);
+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);
+ }
+ }
+}
+
bool BattleGround::DelCreature(uint32 type)
{
- Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
+ Creature *cr = m_BgCreatures[type];
if(!cr)
{
- sLog.outError("Can't find creature guid: %u",m_BgCreatures[type]);
+ sLog.outError("Can't find creature.");
return false;
}
cr->CleanupsBeforeDelete();
@@ -854,10 +1122,10 @@
bool BattleGround::DelObject(uint32 type)
{
- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
+ GameObject *obj = m_BgObjects[type];
if(!obj)
{
- sLog.outError("Can't find gobject guid: %u",m_BgObjects[type]);
+ sLog.outError("Can't find gobject.");
return false;
}
obj->SetRespawnTime(0); // not save respawn time
@@ -948,3 +1216,28 @@
if(uint32 spellId = obj->GetGOInfo()->trap.spellId)
source->CastSpell(source, spellId, true);
}
+
+// 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;
+}
Index: src/game/BattleGround.h
===================================================================
--- src/game/BattleGround.h (revision 5447)
+++ src/game/BattleGround.h (working copy)
@@ -51,7 +51,11 @@
SPELL_SPIRIT_HEAL_CHANNEL = 22011,
SPELL_SPIRIT_HEAL = 22012,
SPELL_RESURRECTION_VISUAL = 24171,
- SPELL_ARENA_PREPARATION = 32727
+ SPELL_ARENA_PREPARATION = 32728, // use this one, 32727 causes problems with creature visibility updates, thus client crashes.
+ SPELL_ALLIANCE_GOLD_FLAG = 32724,
+ SPELL_ALLIANCE_GREEN_FLAG = 32725,
+ SPELL_HORDE_GOLD_FLAG = 35774,
+ SPELL_HORDE_GREEN_FLAG = 35775
};
enum BattleGroundTimeIntervals
@@ -115,6 +119,18 @@
BATTLEGROUND_RL = 8
};
+// handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time
+enum BattleGroundQueueTypeId
+{
+ BATTLEGROUND_QUEUE_AV = 1,
+ BATTLEGROUND_QUEUE_WS = 2,
+ BATTLEGROUND_QUEUE_AB = 3,
+ BATTLEGROUND_QUEUE_EY = 4,
+ BATTLEGROUND_QUEUE_2v2 = 5,
+ BATTLEGROUND_QUEUE_3v3 = 6,
+ BATTLEGROUND_QUEUE_5v5 = 7,
+};
+
enum ScoreType
{
SCORE_KILLING_BLOWS = 1,
@@ -194,6 +210,7 @@
public:
/* Construction */
BattleGround();
+ /*BattleGround(const BattleGround& bg);*/
virtual ~BattleGround();
virtual void Update(time_t diff); // must be implemented in BG subclass of BG specific update code, but must in begginning call parent version
virtual bool SetupBattleGround() // must be implemented in BG subclass
@@ -263,6 +280,7 @@
}
bool HasFreeSlotsForTeam(uint32 Team) const;
bool HasFreeSlots() const;
+ uint32 GetFreeSlotsForTeam(uint32 Team) const;
bool isArena() const { return m_IsArena; }
bool isBattleGround() const { return !m_IsArena; }
@@ -328,6 +346,7 @@
uint8 GetTeamIndexByTeamId(uint32 Team) const { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; }
uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; }
+ uint32 GetAlivePlayersCountByTeam(uint32 Team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases
void UpdatePlayersCountByTeam(uint32 Team, bool remove)
{
if(remove)
@@ -336,6 +355,12 @@
++m_PlayersCount[GetTeamIndexByTeamId(Team)];
}
+ // used for rated arena battles
+ void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[ Team == ALLIANCE ? 0 : 1] = ArenaTeamId; }
+ uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[ Team == ALLIANCE ? 0 : 1]; }
+ void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 ArenaTeamId) { m_ArenaTeamRatingChanges[ Team == ALLIANCE ? 0 : 1] = ArenaTeamId; }
+ uint32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[ Team == ALLIANCE ? 0 : 1]; }
+
/* Triggers handle */
// must be implemented in BG subclass
virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}
@@ -344,17 +369,18 @@
// must be implemented in BG subclass if need
virtual void HandleDropFlag(Player* /*player*/) {}
- virtual void AddPlayer(Player *plr); // must be implemented in BG subclass
+ virtual void AddPlayer(Player *plr, uint32 team = 0); // must be implemented in BG subclass
virtual void RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket);
// can be extended in in BG subclass
// TODO: make this protected:
- typedef std::vector<uint64> BGObjects;
- typedef std::vector<uint64> BGCreatures;
+ typedef std::vector<GameObject*> BGObjects;
+ typedef std::vector<Creature*> BGCreatures;
BGObjects m_BgObjects;
BGCreatures m_BgCreatures;
void SpawnBGObject(uint32 type, uint32 respawntime);
+ void SpawnBGCreature(uint32 type, uint32 respawntime);
bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawntime = 0);
- Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o);
+ Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime = 0);
bool DelCreature(uint32 type);
bool DelObject(uint32 type);
bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team);
@@ -362,6 +388,11 @@
void DoorOpen(uint32 type);
const char *GetMangosString(uint32 entry);
+ // since arenas can be AvA or Hvh, we have to get the "temporary" team of a player
+ uint32 GetPlayerTeam(uint64 guid);
+
+ void SetDeleteThis() {m_SetDeleteThis = true;}
+
protected:
//this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround
void EndNow();
@@ -392,6 +423,8 @@
uint32 m_LastResurrectTime;
uint32 m_Queue_type;
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
+ bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque
+ bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
// this variable is not used .... it can be found in many other ways... but to store it in BG object instance is useless
//uint8 m_BattleGroundType; // 3=BG, 4=arena
//instead of uint8 (in previous line) is bool used
@@ -417,6 +450,11 @@
/* Players count by team */
uint32 m_PlayersCount[2];
+ /* Arena team ids by team */
+ uint32 m_ArenaTeamIds[2];
+
+ int32 m_ArenaTeamRatingChanges[2];
+
/* Limits */
uint32 m_LevelMin;
uint32 m_LevelMax;
Index: src/game/BattleGroundAA.cpp
===================================================================
--- src/game/BattleGroundAA.cpp (revision 5447)
+++ src/game/BattleGroundAA.cpp (working copy)
@@ -35,9 +35,9 @@
BattleGround::Update(diff);
}
-void BattleGroundAA::AddPlayer(Player *plr)
+void BattleGroundAA::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr,team);
//create score and add it to map, default values are set in constructor
BattleGroundAAScore* sc = new BattleGroundAAScore;
Index: src/game/BattleGroundAA.h
===================================================================
--- src/game/BattleGroundAA.h (revision 5447)
+++ src/game/BattleGroundAA.h (working copy)
@@ -38,7 +38,7 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
Index: src/game/BattleGroundAB.cpp
===================================================================
--- src/game/BattleGroundAB.cpp (revision 5447)
+++ src/game/BattleGroundAB.cpp (working copy)
@@ -36,6 +36,33 @@
BattleGroundAB::~BattleGroundAB()
{
+ // despawn objects / creatures here too, maybe the BG ends when the last not-ported invitee leaves the queue
+ sLog.outDebug("Arathi Basin: BG ended, objects despawning...");
+
+ // delete everything (for times, when BG will instanced)
+ for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++)
+ if (m_bgobjects[i])
+ {
+ m_bgobjects[i]->SetRespawnTime(0);
+ m_bgobjects[i]->Delete();
+ m_bgobjects[i] = NULL;
+ }
+
+ for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++)
+ if (m_bgbuffobjects[node].object)
+ {
+ m_bgbuffobjects[node].object->SetRespawnTime(0);
+ m_bgbuffobjects[node].object->Delete();
+ m_bgbuffobjects[node].object = NULL;
+ }
+
+ for(uint32 node = 0; node < 7; node++)
+ if (m_spiritGuides[node])
+ {
+ m_spiritGuides[node]->CleanupsBeforeDelete();
+ ObjectAccessor::Instance().AddObjectToRemoveList(m_spiritGuides[node]);
+ m_spiritGuides[node] = NULL;
+ }
}
void BattleGroundAB::Update(time_t diff)
@@ -205,6 +232,7 @@
{
uint8 buff = urand(0, 2);
m_bgbuffobjects[node].object = new GameObject(NULL);
+ m_bgbuffobjects[node].object->SetInstanceId(GetInstanceID());
if (!m_bgbuffobjects[node].object->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_BuffObjects[buff][0], GetMapId(), BG_AB_BuffPositions[node][0], BG_AB_BuffPositions[node][1], BG_AB_BuffPositions[node][2], BG_AB_BuffPositions[node][3], 0, 0, sin(BG_AB_BuffPositions[node][3]/2), cos(BG_AB_BuffPositions[node][3]/2), 0, 0))
ASSERT(0);
m_bgbuffobjects[node].spellId = BG_AB_BuffObjects[buff][1];
@@ -226,6 +254,7 @@
if (spell)
plr->CastSpell(plr, spell, true, 0);
m_bgbuffobjects[node].timer = BG_AB_BUFF_RESPAWN_TIME;
+ m_bgbuffobjects[node].object->SetRespawnTime(0);
m_bgbuffobjects[node].object->Delete();
m_bgbuffobjects[node].object = NULL;
break;
@@ -237,9 +266,9 @@
}
}
-void BattleGroundAB::AddPlayer(Player *plr)
+void BattleGroundAB::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map, default values are set in the constructor
BattleGroundABScore* sc = new BattleGroundABScore;
@@ -249,7 +278,7 @@
void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
{
- if(GetPlayersSize()==0)
+ if(GetPlayersSize()==0 && GetInvitedCount(ALLIANCE)==0 && GetInvitedCount(HORDE)==0)
{
sLog.outDebug("Arathi Basin: BG ended, objects despawning...");
@@ -257,6 +286,7 @@
for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++)
if (m_bgobjects[i])
{
+ m_bgobjects[i]->SetRespawnTime(0);
m_bgobjects[i]->Delete();
m_bgobjects[i] = NULL;
}
@@ -264,6 +294,7 @@
for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++)
if (m_bgbuffobjects[node].object)
{
+ m_bgbuffobjects[node].object->SetRespawnTime(0);
m_bgbuffobjects[node].object->Delete();
m_bgbuffobjects[node].object = NULL;
}
@@ -276,9 +307,10 @@
m_spiritGuides[node] = NULL;
}
+ // no use, the bg will be deleted soonish
// re-setup
- Reset();
- SetupBattleGround();
+ // Reset();
+ // SetupBattleGround();
// Only change back to STATUS_WAIT_QUEUE if successfully re-setuped
}
}
@@ -342,6 +374,7 @@
else goId = BG_AB_OBJECTID_BANNER_H;
m_bgobjects[obj] = new GameObject(NULL);
+ m_bgobjects[obj]->SetInstanceId(GetInstanceID());
m_bgobjects[obj]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), goId, GetMapId(), BG_AB_NodePositions[node][0], BG_AB_NodePositions[node][1], BG_AB_NodePositions[node][2], BG_AB_NodePositions[node][3], 0, 0, sin(BG_AB_NodePositions[node][3]/2), cos(BG_AB_NodePositions[node][3]/2), 100, 1);
MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]);
@@ -349,7 +382,8 @@
if (!type)
return;
obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7);
- MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]);
+ if(m_bgobjects[obj])
+ MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]);
}
void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
@@ -357,13 +391,16 @@
uint8 obj = node*8 + type + teamIndex;
if (!m_bgobjects[obj])
return;
+
+ m_bgobjects[obj]->SetRespawnTime(0);
m_bgobjects[obj]->Delete();
m_bgobjects[obj] = NULL;
// handle aura with banner
if (!type) return;
obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7);
- MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false);
+ if(m_bgobjects[obj])
+ MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false);
}
const char* BattleGroundAB::_GetNodeName(uint8 node)
@@ -463,6 +500,7 @@
if (m_spiritGuides[node])
return;
m_spiritGuides[node] = new Creature(NULL);
+ m_spiritGuides[node]->SetInstanceId(GetInstanceID());
if (!m_spiritGuides[node]->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), 529, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], (node>4)?BG_AB_SpiritGuideId[node-5]:BG_AB_SpiritGuideId[m_Nodes[node]-3], (node>4)?BG_AB_SpiritGuideTeamId[node-5]:BG_AB_SpiritGuideTeamId[m_Nodes[node]-3]))
ASSERT(0);
m_spiritGuides[node]->setDeathState(DEAD);
@@ -506,6 +544,7 @@
// despawn buff object
if ((node < BG_AB_NODES_COUNT) && (m_bgbuffobjects[node].object))
{
+ m_bgbuffobjects[node].object->SetRespawnTime(0);
m_bgbuffobjects[node].object->Delete();
m_bgbuffobjects[node].object = NULL;
}
@@ -626,6 +665,7 @@
for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
{
m_bgobjects[banner] = new GameObject(NULL);
+ m_bgobjects[banner]->SetInstanceId(GetInstanceID());
if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_NODE_BANNER_0+i, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 100, 1))
return false;
}
@@ -634,27 +674,32 @@
for (int banner = BG_AB_OBJECT_AURA_ALLY, i = 0; i < 5; banner += 8, ++i)
{
m_bgobjects[banner] = new GameObject(NULL);
+ m_bgobjects[banner]->SetInstanceId(GetInstanceID());
if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_A, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0))
return false;
}
for (int banner = BG_AB_OBJECT_AURA_HORDE, i = 0; i < 5; banner += 8, ++i)
{
m_bgobjects[banner] = new GameObject(NULL);
+ m_bgobjects[banner]->SetInstanceId(GetInstanceID());
if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_H, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0))
return false;
}
for (int banner = BG_AB_OBJECT_AURA_CONTESTED, i = 0; i < 5; banner += 8, ++i)
{
m_bgobjects[banner] = new GameObject(NULL);
+ m_bgobjects[banner]->SetInstanceId(GetInstanceID());
if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_C, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0))
return false;
}
// Starting gates
m_bgobjects[BG_AB_OBJECT_GATE_A] = new GameObject(NULL);
+ m_bgobjects[BG_AB_OBJECT_GATE_A]->SetInstanceId(GetInstanceID());
if(!m_bgobjects[BG_AB_OBJECT_GATE_A]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_A, GetMapId(), BG_AB_DoorPositions[0][0], BG_AB_DoorPositions[0][1], BG_AB_DoorPositions[0][2], BG_AB_DoorPositions[0][3], BG_AB_DoorPositions[0][4], BG_AB_DoorPositions[0][5], BG_AB_DoorPositions[0][6], BG_AB_DoorPositions[0][7], 100, 1))
return false;
m_bgobjects[BG_AB_OBJECT_GATE_H] = new GameObject(NULL);
+ m_bgobjects[BG_AB_OBJECT_GATE_H]->SetInstanceId(GetInstanceID());
if(!m_bgobjects[BG_AB_OBJECT_GATE_H]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_H, GetMapId(), BG_AB_DoorPositions[1][0], BG_AB_DoorPositions[1][1], BG_AB_DoorPositions[1][2], BG_AB_DoorPositions[1][3], BG_AB_DoorPositions[1][4], BG_AB_DoorPositions[1][5], BG_AB_DoorPositions[1][6], BG_AB_DoorPositions[1][7], 100, 1))
return false;
@@ -757,3 +802,5 @@
+
+
Index: src/game/BattleGroundAB.h
===================================================================
--- src/game/BattleGroundAB.h (revision 5447)
+++ src/game/BattleGroundAB.h (working copy)
@@ -222,7 +222,7 @@
~BattleGroundAB();
void Update(time_t diff);
- void AddPlayer(Player *plr);
+ void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr,uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
virtual bool SetupBattleGround();
Index: src/game/BattleGroundAV.cpp
===================================================================
--- src/game/BattleGroundAV.cpp (revision 5447)
+++ src/game/BattleGroundAV.cpp (working copy)
@@ -39,9 +39,9 @@
BattleGround::Update(diff);
}
-void BattleGroundAV::AddPlayer(Player *plr)
+void BattleGroundAV::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map, default values are set in constructor
BattleGroundAVScore* sc = new BattleGroundAVScore;
Index: src/game/BattleGroundAV.h
===================================================================
--- src/game/BattleGroundAV.h (revision 5447)
+++ src/game/BattleGroundAV.h (working copy)
@@ -45,7 +45,7 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr,uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
Index: src/game/BattleGroundBE.cpp
===================================================================
--- src/game/BattleGroundBE.cpp (revision 5447)
+++ src/game/BattleGroundBE.cpp (working copy)
@@ -89,6 +89,10 @@
if(plr)
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
}
+ if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
}
}
@@ -98,9 +102,9 @@
}*/
}
-void BattleGroundBE::AddPlayer(Player *plr)
+void BattleGroundBE::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map, default values are set in constructor
BattleGroundBEScore* sc = new BattleGroundBEScore;
@@ -109,7 +113,13 @@
void BattleGroundBE::RemovePlayer(Player *plr, uint64 guid)
{
+ if(GetStatus() == STATUS_WAIT_LEAVE)
+ return;
+ if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
}
void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)
@@ -123,14 +133,15 @@
return;
}
- uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
-
- ++m_TeamKills[killer_team_index]; // add kills to killer's team
-
- if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))
+ if(!GetAlivePlayersCountByTeam(ALLIANCE))
+ {
+ // all opponents killed
+ EndBattleGround(HORDE);
+ }
+ else if(!GetAlivePlayersCountByTeam(HORDE))
{
// all opponents killed
- EndBattleGround(killer->GetTeam());
+ EndBattleGround(ALLIANCE);
}
}
@@ -141,14 +152,14 @@
return;
uint32 SpellId = 0;
- uint64 buff_guid = 0;
+ GameObject* obj = 0;
switch(Trigger)
{
case 4538: // buff trigger?
- buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_1];
+ obj = m_BgObjects[BG_BE_OBJECT_BUFF_1];
break;
case 4539: // buff trigger?
- buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_2];
+ obj = m_BgObjects[BG_BE_OBJECT_BUFF_2];
break;
default:
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
@@ -156,14 +167,13 @@
break;
}
- if(buff_guid)
- HandleTriggerBuff(buff_guid,Source);
+ if(obj)
+ HandleTriggerBuff(obj->GetGUID(),Source);
}
void BattleGroundBE::ResetBGSubclass()
{
- m_TeamKills[BG_TEAM_ALLIANCE] = 0;
- m_TeamKills[BG_TEAM_HORDE] = 0;
+
}
bool BattleGroundBE::SetupBattleGround()
Index: src/game/BattleGroundBE.h
===================================================================
--- src/game/BattleGroundBE.h (revision 5447)
+++ src/game/BattleGroundBE.h (working copy)
@@ -58,7 +58,7 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
@@ -68,8 +68,5 @@
/* Scorekeeping */
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
-
- private:
- uint32 m_TeamKills[2]; // count of kills for each team
};
#endif
Index: src/game/BattleGroundEY.cpp
===================================================================
--- src/game/BattleGroundEY.cpp (revision 5447)
+++ src/game/BattleGroundEY.cpp (working copy)
@@ -39,9 +39,9 @@
BattleGround::Update(diff);
}
-void BattleGroundEY::AddPlayer(Player *plr)
+void BattleGroundEY::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map
BattleGroundEYScore* sc = new BattleGroundEYScore;
Index: src/game/BattleGroundEY.h
===================================================================
--- src/game/BattleGroundEY.h (revision 5447)
+++ src/game/BattleGroundEY.h (working copy)
@@ -39,7 +39,7 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr,uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
Index: src/game/BattleGroundHandler.cpp
===================================================================
--- src/game/BattleGroundHandler.cpp (revision 5447)
+++ src/game/BattleGroundHandler.cpp (working copy)
@@ -26,9 +26,12 @@
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Object.h"
+#include "Chat.h"
+#include "Language.h"
#include "BattleGroundMgr.h"
#include "BattleGroundWS.h"
#include "BattleGround.h"
+#include "ArenaTeam.h"
void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
{
@@ -78,8 +81,17 @@
recv_data >> instanceId; // instance id, 0 if First Available selected
recv_data >> joinAsGroup; // join as group
+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ {
+ sLog.outError("bgport: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());
+ return;
+ }
+
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid);
+ // can do this, since it's battleground, not arena
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, 0);
+
// ignore if we already in BG or BG queue
if(_player->InBattleGround())
return;
@@ -100,19 +112,39 @@
return;
}
- // check existence
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
- if(!bg)
+ // get bg instance or bg template if instance not found
+ BattleGround * bg = 0;
+ if(instanceId)
+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
+
+ if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
+ {
+ sLog.outError("Battleground: no available bg / template found");
return;
+ }
if(joinAsGroup && _player->GetGroup())
{
Group *grp = _player->GetGroup();
+ if(grp->GetMembersCount() > bg->GetMaxPlayersPerTeam())
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_BG_GROUP_TOO_LARGE), NULL);
+ SendPacket(&data);
+ return;
+ }
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
if(!member) continue;
+ if( member->GetBattleGroundQueueIdFromLevel() != _player->GetBattleGroundQueueIdFromLevel() )
+ continue;
+
+ if( member->GetTeam() != _player->GetTeam() )
+ continue;
+
if( !member->CanJoinToBattleground() )
{
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
@@ -120,12 +152,12 @@
_player->GetSession()->SendPacket(&data);
continue;
}
- if (member->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ if (member->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
continue;
WorldPacket data;
- uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId); // add to queue
+ uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
// fill data packet
@@ -134,22 +166,23 @@
}
// store entry point coords (same as leader entry point)
- member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+ member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
// send status packet (in queue)
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
member->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(member, bgTypeId);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
}
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
}
else
{
- if (_player->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
return;
- uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);
+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
WorldPacket data;
@@ -159,13 +192,16 @@
}
// store entry point coords
- _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
WorldPacket data;
// send status packet (in queue)
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
SendPacket(&data);
- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, bgTypeId);
+
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
}
}
@@ -247,6 +283,12 @@
uint32 bgTypeId;
recv_data >> bgTypeId; // id from DBC
+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ {
+ sLog.outError("Battleground: invalid bgtype received.");
+ return;
+ }
+
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
if(!bl)
@@ -263,39 +305,151 @@
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
- uint8 unk1;
+ uint8 type; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
+ uint32 instanceId;
uint32 bgTypeId; // type id from dbc
uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0
- recv_data >> unk1 >> unk2 >> bgTypeId >> unk >> action;
+ recv_data >> type >> unk2 >> bgTypeId >> unk >> action;
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ {
+ sLog.outError("Battleground: invalid bgtype received.");
+ // update battleground slots for the player to fix his UI and sent data.
+ // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
+ // it usually happens with extremely high latency (if debugging / stepping in the code for example)
+ if(_player->InBattleGroundQueue())
+ {
+ // update all queues, send invitation info if player is invited, queue info if queued
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ uint32 queue_id = _player->GetBattleGroundQueueId(i);
+ if(!queue_id)
+ continue;
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ // if the player is not in queue, contine
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ continue;
+
+ // no group information, this should never happen
+ if(!itrPlayerStatus->second.GroupInfo)
+ continue;
+
+ BattleGround * bg = NULL;
+
+ // get possibly needed data from groupinfo
+ bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId;
+ uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
+ uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;
+ uint8 status = 0;
+
+
+ if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
+ {
+ // not invited to bg, get template
+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ status = STATUS_WAIT_QUEUE;
+ }
+ else
+ {
+ // get the bg we're invited to
+ BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID);
+ status = STATUS_WAIT_JOIN;
+ }
+
+ // if bg not found, then continue
+ if(!bg)
+ continue;
+
+ // don't invite if already in the instance
+ if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())
+ continue;
+
+ // re - invite player with proper data
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted);
+ SendPacket(&data);
+ }
+ }
+ return;
+ }
+
+ uint32 bgQueueTypeId = 0;
+ // get the bg what we were invited to
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus;
+ bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId,type);
+ itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ {
+ sLog.outError("Battleground: itrplayerstatus not found.");
+ return;
+ }
+ instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
+
+ // if action == 1, then instanceId is _required_
+ if(!instanceId && action == 1)
+ {
+ sLog.outError("Battleground: instance not found.");
+ return;
+ }
+
+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
+
+ // 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("Battleground: bg not found.");
+ return;
+ }
+
+ bgTypeId = bg->GetTypeID();
if(bg)
{
if(_player->InBattleGroundQueue())
{
uint32 queueSlot = 0;
+ uint32 team = 0;
+ uint32 arenatype = 0;
+ uint32 israted = 0;
+ // get the team info from the queue
+ BattleGroundQueue::QueuedPlayersMap::iterator pitr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ if(pitr !=sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end()
+ && pitr->second.GroupInfo )
+ {
+ team = pitr->second.GroupInfo->Team;
+ arenatype = pitr->second.GroupInfo->ArenaType;
+ israted = pitr->second.GroupInfo->IsRated;
+ }
+ else
+ {
+ sLog.outError("Battleground: Invalid player queue info!");
+ return;
+ }
WorldPacket data;
switch(action)
{
case 1: // port to battleground
_player->RemoveFromGroup();
- queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
+ queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
_player->GetSession()->SendPacket(&data);
// remove battleground queue status from BGmgr
- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);
- // check if player is not deserter
- if( !_player->CanJoinToBattleground() )
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
+ // check if player is not deserter -- check in signup, not here!
+ /*if( !_player->CanJoinToBattleground() )
{
WorldPacket data2;
data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data2 << (uint32) 0xFFFFFFFE;
SendPacket(&data2);
return;
- }
+ }*/
// if player is in battleground already, remove him and port him to new battleground
if ( _player->InBattleGround() )
{
@@ -303,15 +457,15 @@
if (currentBg)
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
}
- _player->SetBattleGroundId(bg->GetTypeID());
- sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);
- bg->AddPlayer(_player);
+ _player->SetBattleGroundId(bg->GetInstanceID());
+ sBattleGroundMgr.SendToBattleGround(_player, instanceId, team);
+ bg->AddPlayer(_player,team);
break;
case 0: // leave queue
- queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
- _player->RemoveBattleGroundQueueId(bgTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
+ queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
+ _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
SendPacket(&data);
break;
default:
@@ -350,7 +504,8 @@
BattleGround *bg = _player->GetBattleGround();
if(bg)
{
- uint32 queueSlot = _player->GetBattleGroundQueueIndex(bg->GetTypeID());
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
if((bg->GetStatus() <= STATUS_IN_PROGRESS))
{
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
@@ -358,15 +513,25 @@
}
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
- uint32 queue_id = _player->GetBattleGroundQueueId(i);
- if (i == queueSlot || !queue_id)
+ uint32 queue_id = _player->GetBattleGroundQueueId(i); // battlegroundqueueid stores the type id, not the instance id, so this is definitely wrong
+ uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
+ uint8 isRated = 0;
+ if (i == queueSlot || !queue_id) // we need to get the instance ids
continue;
- BattleGround *bg2 = sBattleGroundMgr.GetBattleGround(queue_id);
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ continue;
+ if(itrPlayerStatus->second.GroupInfo)
+ {
+ arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
+ isRated = itrPlayerStatus->second.GroupInfo->IsRated;
+ }
+ BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(sBattleGroundMgr.BGTemplateId(queue_id)); // try this
if(bg2)
{
//in this call is small bug, this call should be filled by player's waiting time in queue
//this call nulls all timers for client :
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated);
SendPacket(&data);
}
}
@@ -378,18 +543,34 @@
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
uint32 queue_id = _player->GetBattleGroundQueueId(i);
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id);
+ if(!queue_id)
+ continue;
+ uint32 bgTypeId = sBattleGroundMgr.BGTemplateId(queue_id);
+ uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
+ uint8 isRated = 0;
+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ continue;
+ if(itrPlayerStatus->second.GroupInfo)
+ {
+ arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
+ isRated = itrPlayerStatus->second.GroupInfo->IsRated;
+ }
if(bg && queue_id)
{
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
SendPacket(&data);
}
}
}
- /*else // not sure if it needed...
+/* else // not sure if it needed...
{
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(), STATUS_NONE, 0, 0);
- SendPacket(&data);
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);
+ SendPacket(&data);
+ }
}*/
}
@@ -453,7 +634,7 @@
recv_data.hexlike();
// ignore if we already in BG or BG queue
- if(_player->InBattleGround() || _player->InBattleGroundQueue())
+ if(_player->InBattleGround())
return;
uint64 guid; // arena Battlemaster guid
@@ -470,6 +651,7 @@
return;
uint8 arenatype = 0;
+ uint32 arenaRating = 0;
switch(type)
{
@@ -487,23 +669,72 @@
break;
}
- if(isRated && !_player->GetArenaTeamId(type)) // player not in arena team of that size
+ if(isRated) // player not in arena team of that size
{
- _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
- return;
+ uint32 ateamId = _player->GetArenaTeamId(type);
+ if(!ateamId)
+ {
+ _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
+ return;
+ }
+ ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
+ if(!at)
+ {
+ _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
+ return;
+ }
+ arenaRating = at->GetRating();
+ Group *grp = _player->GetGroup();
+ if(grp)
+ {
+ for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *member = itr->getSource();
+
+ // offline member or not in team -> err
+ if(!member || member->GetArenaTeamId(type) != ateamId)
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_YOUR_TEAM_ONLY), NULL);
+ SendPacket(&data);
+ return;
+ }
+ }
+ if(grp->GetMembersCount() < arenatype)
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_NOT_ENOUGH_PLAYERS), NULL);
+ SendPacket(&data);
+ return;
+ }
+ }
}
if(asGroup && !_player->GetGroup()) // player not in group
return;
- // check existence
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);
- if(!bg)
+ //check existance
+ BattleGround* bg = NULL;
+ if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )
+ {
+ sLog.outError("Battleground: template bg (all arenas) not found");
return;
+ }
+ uint8 bgTypeId = bg->GetTypeID();
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
+
if(asGroup && _player->GetGroup())
{
Group *grp = _player->GetGroup();
+ if(grp->GetMembersCount() > arenatype)
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_GROUP_TOO_LARGE), NULL);
+ SendPacket(&data);
+ return;
+ }
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
@@ -513,11 +744,19 @@
//player has deserter aura .. do nothing
*/
- if (member->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ if( member->GetBattleGroundQueueIdFromLevel() != _player->GetBattleGroundQueueIdFromLevel() )
+ continue;
+
+ if( member->GetTeam() != _player->GetTeam() )
+ continue;
+
+ if (member->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ {
//player is already in this queue
continue;
+ }
- uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);// add to queue
+ uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
WorldPacket data;
@@ -527,16 +766,17 @@
}
// store entry point coords (same as leader entry point)
- member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+ member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
WorldPacket data;
// send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, BATTLEGROUND_AA);
+ sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(member, BATTLEGROUND_AA);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
}
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
}
else
{
@@ -544,11 +784,13 @@
//player has deserter aura .. do nothing
*/
- if (_player->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ {
//player is already in this queue
return;
+ }
- uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);
+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
WorldPacket data;
@@ -558,12 +800,14 @@
}
// store entry point coords
- _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
WorldPacket data;
// send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
SendPacket(&data);
- sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(_player, BATTLEGROUND_AA);
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
}
}
Index: src/game/BattleGroundMgr.cpp
===================================================================
--- src/game/BattleGroundMgr.cpp (revision 5447)
+++ src/game/BattleGroundMgr.cpp (working copy)
@@ -30,9 +30,11 @@
#include "SharedDefines.h"
#include "Policies/SingletonImp.h"
#include "MapManager.h"
+#include "MapInstanced.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "World.h"
+#include "ArenaTeam.h"
INSTANTIATE_SINGLETON_1( BattleGroundMgr );
@@ -43,12 +45,12 @@
BattleGroundQueue::BattleGroundQueue()
{
//queues are empty, we don't have to call clear()
- for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
- {
- m_QueuedPlayers[i].Horde = 0;
- m_QueuedPlayers[i].Alliance = 0;
- //m_QueuedPlayers[i].AverageTime = 0;
- }
+/* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ //m_QueuedPlayers[i].Horde = 0;
+ //m_QueuedPlayers[i].Alliance = 0;
+ //m_QueuedPlayers[i].AverageTime = 0;
+ }*/
}
BattleGroundQueue::~BattleGroundQueue()
@@ -56,35 +58,188 @@
for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
{
m_QueuedPlayers[i].clear();
+ for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
+ {
+ delete (*itr);
+ }
+ m_QueuedGroups[i].clear();
}
}
-void BattleGroundQueue::AddPlayer(Player *plr, uint32 bgTypeId)
+// initialize eligible groups from the given source matching the given specifications
+void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime)
+ {
+ // clear from prev initialization
+ clear();
+ BattleGroundQueue::QueuedGroupsList::iterator itr, next;
+ // iterate through the source
+ for(itr = source->begin(); itr!= source->end(); itr = next)
+ {
+ next = itr;
+ ++next;
+ if( (*itr)->BgTypeId == BgTypeId &&
+ (*itr)->ArenaType == ArenaType &&
+ (*itr)->IsRated == IsRated &&
+ (*itr)->IsInvitedToBGInstanceGUID == 0 &&
+ (*itr)->Team == side &&
+ (*itr)->Players.size() <= MaxPlayers &&
+ ((*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
+ || (*itr)->ArenaTeamRating == 0 // pass if no rating info
+ || ((*itr)->ArenaTeamRating >= MinRating
+ && ((*itr)->ArenaTeamRating <= MaxRating))) ) // pass if matches the rating range
+ {
+ // the group matches the conditions
+ // insert it in order of groupsize, and join time
+ uint32 size = (*itr)->Players.size();
+ uint32 jointime = (*itr)->JoinTime;
+ bool inserted = false;
+
+ for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)
+ {
+ // if the next one's size is smaller, then insert
+ // also insert if the next one's size is equal, but it joined the queue later
+ if( ((*elig_itr)->Players.size()<size) ||
+ ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )
+ {
+ insert(elig_itr,(*itr));
+ inserted = true;
+ break;
+ }
+ }
+ // if not inserted -> this is the smallest group -> push_back
+ if(!inserted)
+ {
+ push_back((*itr));
+ }
+ }
+ }
+}
+
+// remove group from eligible groups
+// used when building selection pools
+void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)
+
{
+ for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)
+ {
+ if((*itr)==ginfo)
+ {
+ erase(itr);
+ return;
+ }
+ }
+}
+
+// selection pool initialization, used to clean up from prev selection
+void BattleGroundQueue::SelectionPool::Init()
+{
+ SelectedGroups.clear();
+ MaxGroup = 0;
+ PlayerCount = 0;
+}
+
+// get the maximal group from the selection pool
+// used when building the pool, and have to remove the largest
+GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()
+{
+ if(SelectedGroups.empty())
+ {
+ sLog.outError("Getting max group when selection pool is empty, this should never happen.");
+ MaxGroup = NULL;
+ return 0;
+ }
+ // actually select the max group if it's not set
+ if(MaxGroup==0 && !SelectedGroups.empty())
+ {
+ uint32 max_size = 0;
+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
+ {
+ if(max_size<(*itr)->Players.size())
+ {
+ MaxGroup =(*itr);
+ max_size = MaxGroup->Players.size();
+ }
+ }
+ }
+ return MaxGroup;
+}
+
+// remove group info from selection pool
+// used when building selection pools and have to remove maximal group
+void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
+{
+ // uninitiate max group info if needed
+ if(MaxGroup == ginfo)
+ MaxGroup = 0;
+ // find what to remove
+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
+ {
+ if((*itr)==ginfo)
+ {
+ SelectedGroups.erase(itr);
+ // decrease selected players count
+ PlayerCount -= ginfo->Players.size();
+ return;
+ }
+ }
+}
+
+// add group to selection
+// used when building selection pools
+void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
+{
+ SelectedGroups.push_back(ginfo);
+ // increase selected players count
+ PlayerCount+=ginfo->Players.size();
+ if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())
+ {
+ // update max group info if needed
+ MaxGroup = ginfo;
+ }
+}
+
+// add group to bg queue with the given leader and bg specifications
+GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating)
+{
+ uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
+
+ // create new ginfo
+ // cannot use the method like in addplayer, because that could modify an in-queue group's stats
+ // (e.g. leader leaving queue then joining as individual again)
+ GroupQueueInfo* ginfo = new GroupQueueInfo;
+ ginfo->BgTypeId = BgTypeId;
+ ginfo->ArenaType = ArenaType;
+ ginfo->IsRated = isRated;
+ ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
+ ginfo->JoinTime = getMSTime();
+ ginfo->Team = leader->GetTeam();
+
+ if(sBattleGroundMgr.GetMaxRatingDifference()) // if max difference is set, then store rating info for queue
+ ginfo->ArenaTeamRating = arenaRating;
+ else
+ ginfo->ArenaTeamRating = 0; // don't if it doesn't matter
+
+ ginfo->Players.clear();
+
+ m_QueuedGroups[queue_id].push_back(ginfo);
+
+ // return ginfo, because it is needed to add players to this group info
+ return ginfo;
+}
+
+void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
+{
uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
//if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
info.InviteTime = 0;
- info.IsInvitedToBGInstanceGUID = 0;
info.LastInviteTime = 0;
info.LastOnlineTime = getMSTime();
- info.Team = plr->GetTeam();
+ info.GroupInfo = ginfo;
- //add player to waiting order queue
- m_PlayersSortedByWaitTime[queue_id].push_back(plr->GetGUID());
-
- if(plr->GetTeam() == ALLIANCE)
- ++m_QueuedPlayers[queue_id].Alliance;
- else
- ++m_QueuedPlayers[queue_id].Horde;
-
- /* temporary BG queue status message
- std::ostringstream str;
- str << "Battleground queue invited status: horde: " << m_QueuedPlayers[queue_id].Horde << ", aliance: " << m_QueuedPlayers[queue_id].Alliance;
- plr->Say(str.str(), LANG_UNIVERSAL);*/
-
- this->Update(bgTypeId, queue_id);
+ // add the pinfo to ginfo's list
+ ginfo->Players[plr->GetGUID()] = &info;
}
void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
@@ -93,11 +248,22 @@
uint32 queue_id = 0;
QueuedPlayersMap::iterator itr;
+ GroupQueueInfo * group;
+ QueuedGroupsList::iterator group_itr;
bool IsSet = false;
- if(!plr)
- { //player is offline, we need to find him somewhere in queues
- /// there is something wrong if this code is run, because we have in queue only online players!
- sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
+ if(plr)
+ {
+ queue_id = plr->GetBattleGroundQueueIdFromLevel();
+
+ itr = m_QueuedPlayers[queue_id].find(guid);
+ if(itr != m_QueuedPlayers[queue_id].end())
+ IsSet = true;
+ }
+
+ if(!IsSet)
+ {
+ // either player is offline, or he levelled up to another queue category
+ // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
{
itr = m_QueuedPlayers[i].find(guid);
@@ -109,44 +275,227 @@
}
}
}
- else
- { //player is online, we have his level, so we can find exact queue from his level
- queue_id = plr->GetBattleGroundQueueIdFromLevel();
- itr = m_QueuedPlayers[queue_id].find(guid);
- IsSet = true;
+ // couldn't find the player in bg queue, return
+ if(!IsSet)
+ {
+ sLog.outError("Battleground: couldn't find player to remove.");
+ return;
}
- //all variables are set, so remove player
- //remove player from time queue
- m_PlayersSortedByWaitTime[queue_id].remove(guid);
+ group = itr->second.GroupInfo;
- if (IsSet && itr != m_QueuedPlayers[queue_id].end())
+ for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
{
- if (!itr->second.IsInvitedToBGInstanceGUID)
+ if(group == (GroupQueueInfo*)(*group_itr))
+ break;
+ }
+
+ // variables are set (what about leveling up when in queue????)
+ // remove player from group
+ // if only player there, remove group
+
+ // remove player queue info from group queue info
+ std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
+
+ if(pitr != group->Players.end())
+ group->Players.erase(pitr);
+
+ // check for iterator correctness
+ if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
+ {
+ // used when player left the queue, NOT used when porting to bg
+ if (decreaseInvitedCount)
{
- if(itr->second.Team == ALLIANCE)
- --m_QueuedPlayers[queue_id].Alliance;
- else
- --m_QueuedPlayers[queue_id].Horde;
- }
- else
- {
- if (decreaseInvitedCount)
+ // if invited to bg, and should decrease invited count, then do it
+ if(group->IsInvitedToBGInstanceGUID)
{
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
if (bg)
- bg->DecreaseInvitedCount(itr->second.Team);
+ bg->DecreaseInvitedCount(group->Team);
+ if (!bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
+ {
+ // no more players on battleground, set delete it
+ bg->SetDeleteThis();
+ }
}
+ // update the join queue, maybe now the player's group fits in a queue!
+ // not yet implemented (should store bgTypeId in group queue info?)
}
+ // remove player queue info
m_QueuedPlayers[queue_id].erase(itr);
+ // remove group queue info if needed
+ if(group->Players.empty())
+ {
+ m_QueuedGroups[queue_id].erase(group_itr);
+ delete group;
+ }
}
}
+bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
+{
+ // set side if needed
+ if(side)
+ ginfo->Team = side;
+ if(!ginfo->IsInvitedToBGInstanceGUID)
+ {
+ // not yet invited
+ // set invitation
+ ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ // loop through the players
+ for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
+ {
+ // set status
+ itr->second->InviteTime = getMSTime();
+ itr->second->LastInviteTime = getMSTime();
+
+ // get the player
+ Player* plr = objmgr.GetPlayer(itr->first);
+ // if offline, skip him
+ if(!plr)
+ continue;
+
+ // invite the player
+ sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
+
+ WorldPacket data;
+
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
+
+ sLog.outDebug("Battleground: invite plr %u queueindex %u bgtype %u",plr->GetGUIDLow(),queueSlot,bg->GetTypeID());
+
+ // send status packet
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
+ plr->GetSession()->SendPacket(&data);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+// this function is responsible for the selection of queued groups when trying to create new battlegrounds
+bool BattleGroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime)
+{
+ uint32 side;
+ switch(mode)
+ {
+ case NORMAL_ALLIANCE:
+ case ONESIDE_ALLIANCE_TEAM1:
+ case ONESIDE_ALLIANCE_TEAM2:
+ side = ALLIANCE;
+ break;
+ case NORMAL_HORDE:
+ case ONESIDE_HORDE_TEAM1:
+ case ONESIDE_HORDE_TEAM2:
+ side = HORDE;
+ break;
+ default:
+ //unknown mode, return false
+ sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
+ return false;
+ break;
+ }
+
+ // inititate the groups eligible to create the bg
+ m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime);
+ // init the selected groups (clear)
+ m_SelectionPools[mode].Init();
+ while(!(m_EligibleGroups.empty()))
+ {
+ sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");
+ // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players
+ for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)
+ {
+ // get the maximal not yet checked group
+ GroupQueueInfo * MaxGroup = (*itr);
+ // if it fits in the maxplayer size, add it
+ if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )
+ {
+ m_SelectionPools[mode].AddGroup(MaxGroup);
+ }
+ }
+ if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)
+ {
+ // the selection pool is set, return
+ sLog.outDebug("pool build succeeded, return true");
+ return true;
+ }
+ // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.
+ GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();
+ m_EligibleGroups.RemoveGroup(MaxGroup);
+ m_SelectionPools[mode].RemoveGroup(MaxGroup);
+ }
+ // failed to build a selection pool matching the given values
+ return false;
+}
+
+// used to remove the Enter Battle window if the battle has already, but someone still has it
+// (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
+void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
+{
+ uint32 queue_id = bg->GetQueueType();
+ uint32 bgInstanceId = bg->GetInstanceID();
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ QueuedGroupsList::iterator itr, next;
+ for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
+ {
+ // must do this way, because the groupinfo will be deleted when all playerinfos are removed
+ GroupQueueInfo * ginfo = (*itr);
+ next = itr;
+ ++next;
+ // if group was invited to this bg instance, then remove all references
+ if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
+ {
+ // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
+ uint32 to_remove = ginfo->Players.size();
+ uint32 team = ginfo->Team;
+ for(int i = 0; i < to_remove; ++i)
+ {
+ // always remove the first one in the group
+ std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
+ if(itr2 == ginfo->Players.end())
+ {
+ sLog.outError("Empty Players in ginfo, this should never happen!");
+ return;
+ }
+
+ // get the player
+ Player * plr = objmgr.GetPlayer(itr2->first);
+ if(!plr)
+ {
+ sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
+ continue;
+ }
+
+ // get the queueslot
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
+ if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ {
+ plr->RemoveBattleGroundQueueId(bgQueueTypeId);
+ // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
+ RemovePlayer(itr2->first, true);
+ // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
+ // but updateing the queue can't hurt
+ Update(bgQueueTypeId, bg->GetQueueType());
+ // send info to client
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
+ plr->GetSession()->SendPacket(&data);
+ }
+ }
+ }
+ }
+}
+
+
/*
-this method is called when player is inserted, or removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
-add method calls this by itself, the remove method could works in other way, so you have to call this method from other code after calling remove method
+this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
+it must be called after fully adding the members of a group to ensure group joining
+should be called after removeplayer functions in some cases
*/
-void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id)
+void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
{
if (queue_id >= MAX_BATTLEGROUND_QUEUES)
{
@@ -156,158 +505,299 @@
}
//if no players in queue ... do nothing
- if (this->m_QueuedPlayers[queue_id].Alliance == 0 && this->m_QueuedPlayers[queue_id].Horde == 0)
+ if (this->m_QueuedGroups[queue_id].size() == 0)
return;
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
//battleground with free slot for player should be always the last in this queue
- BGFreeSlotQueueType::iterator itr;
- for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); ++itr)
+ BGFreeSlotQueueType::iterator itr, next;
+ for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
{
+ next = itr;
+ ++next;
// battleground is running, so if:
// DO NOT allow queue manager to invite new player to running arena
- if ((*itr)->isBattleGround() && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
+ if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
{
//we must check both teams
BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
// and iterator is invalid
- //check if there are some players in queue
- if (m_QueuedPlayers[queue_id].Alliance > 0 || m_QueuedPlayers[queue_id].Horde > 0)
+ for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
{
- for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)
- {
- Player* plr = objmgr.GetPlayer(*itr2);
- if (!plr)
- {
- //something is wrong!, kick player from queue
- sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");
- uint64 oldval = *itr2;
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
- this->RemovePlayer(oldval, true);
- continue;
- }
+ // did the group join for this bg type?
+ if((*itr)->BgTypeId != bgTypeId)
+ continue;
+ // if so, check if fits in
+ if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
+ {
+ // if group fits in, invite it
+ InviteGroupToBG((*itr),bg,(*itr)->Team);
+ }
+ }
- // player will be invited, if in bg there is a free slot for him
- if (bg->HasFreeSlotsForTeam(plr->GetTeam()))
- {
- // iterator to player's queue status
- QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);
+ if (!bg->HasFreeSlots())
+ {
+ //remove BG from BGFreeSlotQueue
+ bg->RemoveFromBGFreeSlotQueue();
+ }
+ }
+ }
+
+ // finished iterating through the bgs with free slots, maybe we need to create a new bg
- // remove him from time queue
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
+ BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ if(!bg_template)
+ {
+ sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
+ return;
+ }
- // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and pls report it)
- if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())
- continue;
+ // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
+ uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
+ uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
+ if(bg_template->isArena())
+ {
+ switch(arenatype)
+ {
+ case ARENA_TYPE_2v2:
+ MaxPlayersPerTeam = 2;
+ MinPlayersPerTeam = 2;
+ break;
+ case ARENA_TYPE_3v3:
+ MaxPlayersPerTeam = 3;
+ MinPlayersPerTeam = 3;
+ break;
+ case ARENA_TYPE_5v5:
+ MaxPlayersPerTeam = 5;
+ MinPlayersPerTeam = 5;
+ break;
+ }
+ }
- // check if player is not already invited
- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)
- {
- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg->GetInstanceID();
- itrPlayerStatus->second.InviteTime = getMSTime();
- itrPlayerStatus->second.LastInviteTime = getMSTime();
- if(itrPlayerStatus->second.Team == ALLIANCE)
- --m_QueuedPlayers[queue_id].Alliance;
- else
- --m_QueuedPlayers[queue_id].Horde;
- sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID());
+ uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
+ uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
+ uint32 discardTime = 0;
+ if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
+ discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
- WorldPacket data;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
- plr->GetSession()->SendPacket(&data);
- }
- }
- else
- ++itr2;
+ // try to build the selection pools
+ bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
+ if(bAllyOK)
+ sLog.outDebug("Battleground: ally pool succesfully build");
+ else
+ sLog.outDebug("Battleground: ally pool wasn't created");
+ bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
+ if(bHordeOK)
+ sLog.outDebug("Battleground: horde pool succesfully built");
+ else
+ sLog.outDebug("Battleground: horde pool wasn't created");
- //if battleground is FULL, then it is removed from free slot queue - not yet implemented!
- if (!bg->HasFreeSlots())
- {
- //if bg is full, there is no need to invite other players, so break
- break;
- //remove BG from BGFreeSlotQueue - not used now, in this system we don't remove BGs from free queue
- //bg->RemoveFromBGFreeSlotQueue() --- do not uncomment this - not yet implemented
- }
- }
+ // if selection pools are ready, create the new bg
+ if (bAllyOK && bHordeOK)
+ {
+ BattleGround * bg2 = 0;
+ // special handling for arenas
+ if(bg_template->isArena())
+ {
+ // Find a random arena, that can be created
+ uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
+ uint32 arena_num = urand(0,2);
+ if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
+ {
+ sLog.outError("Battleground: couldn't create arena");
+ return;
}
+
+ // set the MaxPlayersPerTeam values based on arenatype
+ // setting the min player values isn't needed, since we won't be using that value later on.
+ switch(arenatype)
+ {
+ case ARENA_TYPE_2v2:
+ bg2->SetMaxPlayersPerTeam(2);
+ bg2->SetMaxPlayers(4);
+ break;
+ case ARENA_TYPE_3v3:
+ bg2->SetMaxPlayersPerTeam(3);
+ bg2->SetMaxPlayers(6);
+ break;
+ case ARENA_TYPE_5v5:
+ bg2->SetMaxPlayersPerTeam(5);
+ bg2->SetMaxPlayers(10);
+ break;
+ default:
+ break;
+ }
}
- }
+ else
+ {
+ // create new battleground
+ bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
+ }
- /* THIS IS A CASE THAT IN QUEUE THERE IS ENOUGHT PLAYERS TO START NEW BG */
- //itr->end is the last BG - template, which is not already started!
+ if(!bg2)
+ {
+ sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
+ return;
+ }
- /* here will be a most of change, when we create battlegrounds instanciated */
- /* if (there is enought players to start new BG)
- Battleground* newbg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId)
- - that function will use the COPY constructor on BattleGround class ( in bg manager we should have one battleground as a template
- (battleground template will be used only to create new BGs, it will be an instance of BG class, but it won't ever start) */
-
- /* folowing code is working with current Battleground system and it should be removed, when BGs will work like instances */
- BattleGround* bg2 = sBattleGroundMgr.GetBattleGround(bgTypeId);
- if (bg2->GetQueueType() != MAX_BATTLEGROUND_QUEUES || bg2->GetStatus() != STATUS_WAIT_QUEUE)
- return;
- if (m_QueuedPlayers[queue_id].Alliance >= bg2->GetMinPlayersPerTeam() && m_QueuedPlayers[queue_id].Horde >= bg2->GetMinPlayersPerTeam())
- {
+ // start the joining of the bg
bg2->SetStatus(STATUS_WAIT_JOIN);
bg2->SetQueueType(queue_id);
+ // initialize arena / rating info
+ bg2->SetArenaType(arenatype);
+ // set rating
+ bg2->SetRated(isRated);
- for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)
+ std::list<GroupQueueInfo* >::iterator itr;
+
+ // invite groups from horde selection pool
+ for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
+ {
+ InviteGroupToBG((*itr),bg2,HORDE);
+ }
+
+ // invite groups from ally selection pools
+ for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
{
- Player* plr = objmgr.GetPlayer(*itr2);
- if (!plr)
+ InviteGroupToBG((*itr),bg2,ALLIANCE);
+ }
+
+ // start the battleground
+ bg2->StartBattleGround(0);
+ }
+
+ // there weren't enough players for a "normal" match
+ // if arena, enable horde versus horde or alliance versus alliance teams here
+
+ else if(bg_template->isArena())
+ {
+ bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
+ bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
+ bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
+ if(bOneSideHordeTeam1)
+ {
+ // one team has been selected, find out if other can be selected too
+ std::list<GroupQueueInfo* >::iterator itr;
+ // temporarily change the team side to enable building the next pool excluding the already selected groups
+ for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
+ (*itr)->Team=ALLIANCE;
+
+ bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
+
+ // change back the team to horde
+ for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
+ (*itr)->Team=HORDE;
+
+ if(!bOneSideHordeTeam2)
+ bOneSideHordeTeam1 = false;
+ }
+ if(!bOneSideHordeTeam1)
+ {
+ // check for one sided ally
+ bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
+ if(bOneSideAllyTeam1)
+
{
- //something is wrong!, kick player from queue
- sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");
- uint64 oldval = *itr2;
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
- this->RemovePlayer(oldval, true);
- continue;
+ // one team has been selected, find out if other can be selected too
+ std::list<GroupQueueInfo* >::iterator itr;
+ // temporarily change the team side to enable building the next pool excluding the already selected groups
+ for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
+ (*itr)->Team=HORDE;
+
+ bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
+
+ // change back the team to ally
+ for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
+ (*itr)->Team=ALLIANCE;
}
- /* TODO: (i'm not sure this code will be useful:
- here should be some condition like if (bg2->isArena() && bg2->isRated())
+ if(!bOneSideAllyTeam2)
+ bOneSideAllyTeam1 = false;
+ }
+ // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
+ if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
+ (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
+ {
+ // create random arena
+ uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
+ uint32 arena_num = urand(0,2);
+ BattleGround* bg2 = NULL;
+ if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
{
- invite players from 1 certain group on each faction to play arena match
- } else if ....and existing code
- */
- // player will be invited, if in bg there is a free slot for him
- if (bg2->HasFreeSlotsForTeam(plr->GetTeam()))
+ sLog.outError("Could not create arena.");
+ return;
+ }
+
+ sLog.outDebug("Arena created.");
+ // init stats
+ switch(arenatype)
{
- // iterator to player's queue status
- QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);
+ case ARENA_TYPE_2v2:
+ bg2->SetMaxPlayersPerTeam(2);
+ bg2->SetMaxPlayers(4);
+ break;
+ case ARENA_TYPE_3v3:
+ bg2->SetMaxPlayersPerTeam(3);
+ bg2->SetMaxPlayers(6);
+ break;
+ case ARENA_TYPE_5v5:
+ bg2->SetMaxPlayersPerTeam(5);
+ bg2->SetMaxPlayers(10);
+ break;
+ default:
+ break;
+ }
- // remove him from time queue
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
+ bg2->SetRated(isRated);
+ // which side has enough players?
+ uint32 side = 0;
+ SelectionPoolBuildMode mode1, mode2;
+ // find out what pools are we using
+ if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
+ {
+ side = ALLIANCE;
+ mode1 = ONESIDE_ALLIANCE_TEAM1;
+ mode2 = ONESIDE_ALLIANCE_TEAM2;
+ }
+ else
+ {
+ side = HORDE;
+ mode1 = ONESIDE_HORDE_TEAM1;
+ mode2 = ONESIDE_HORDE_TEAM2;
+ }
+ // assigned team of the other group
+ uint32 other_side;
+ if(side == ALLIANCE)
+ other_side = HORDE;
+ else
+ other_side = ALLIANCE;
- // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and report it)
- if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())
- continue;
+ // start the joining of the bg
+ bg2->SetStatus(STATUS_WAIT_JOIN);
+ bg2->SetQueueType(queue_id);
+ // initialize arena / rating info
+ bg2->SetArenaType(arenatype);
- //check if player is not already invited
- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)
- {
- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID();
- itrPlayerStatus->second.InviteTime = getMSTime();
- itrPlayerStatus->second.LastInviteTime = getMSTime();
+ std::list<GroupQueueInfo* >::iterator itr;
- if(itrPlayerStatus->second.Team == ALLIANCE)
- --m_QueuedPlayers[queue_id].Alliance;
- else
- --m_QueuedPlayers[queue_id].Horde;
+ // invite players from the first group as horde players (actually green team)
+ for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
+ {
+ InviteGroupToBG((*itr),bg2,HORDE);
+ }
+ // invite players from the second group as ally players (actually gold team)
+ for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
+ {
+ InviteGroupToBG((*itr),bg2,ALLIANCE);
+ }
+ bg2->StartBattleGround(0);
- sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());
-
- WorldPacket data;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
- plr->GetSession()->SendPacket(&data);
- }
- }
- else
- ++itr2;
}
- bg2->StartBattleGround(0);
}
}
@@ -330,16 +820,17 @@
BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
if (bg)
{
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
{
// check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
- BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
+ BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
- if (qItr != qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
+ if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
{
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, BG_REMIND_INVITE_TIME, 0);
plr->GetSession()->SendPacket(&data);
}
}
@@ -366,17 +857,18 @@
BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
if (bg)
{
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
{
// check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
- if (sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid)->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
+ if (sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid)->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
{
- plr->RemoveBattleGroundQueueId(bg->GetTypeID());
- sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].RemovePlayer(m_PlayerGuid, true);
- sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].Update(bg->GetTypeID(), bg->GetQueueType());
+ plr->RemoveBattleGroundQueueId(bgQueueTypeId);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
plr->GetSession()->SendPacket(&data);
}
}
@@ -398,22 +890,77 @@
BattleGroundMgr::BattleGroundMgr()
{
m_BattleGrounds.clear();
+ m_AutoDistributePoints = (bool)sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS);
+ m_MaxRatingDifference = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
+ m_RatingDiscardTimer = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
+ m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
+ m_AutoDistributionTimeChecker = 0;
}
BattleGroundMgr::~BattleGroundMgr()
{
- for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
- delete itr->second;
+ BattleGroundSet::iterator itr, next;
+ for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ {
+ next = itr;
+ ++next;
+ BattleGround * bg = itr->second;
+ m_BattleGrounds.erase(itr);
+ delete bg;
+ }
m_BattleGrounds.clear();
}
void BattleGroundMgr::Update(time_t diff)
{
- for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
+ BattleGroundSet::iterator itr, next;
+ for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ {
+ next = itr;
+ ++next;
itr->second->Update(diff);
+ // use the SetDeleteThis variable
+ // direct deletion caused crashes
+ if(itr->second->m_SetDeleteThis)
+ {
+ BattleGround * bg = itr->second;
+ m_BattleGrounds.erase(itr);
+ delete bg;
+ }
+ }
+ // if rating difference counts, maybe force-update queues
+ if(m_MaxRatingDifference)
+ {
+ // it's time to force update
+ if(m_NextRatingDiscardUpdate < diff)
+ {
+ // forced update for level 70 rated arenas
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
+ m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
+ }
+ else
+ m_NextRatingDiscardUpdate -= diff;
+ }
+ if(m_AutoDistributePoints)
+ {
+ if(m_AutoDistributionTimeChecker < diff)
+ {
+ if(time(NULL) > m_NextAutoDistributionTime)
+ {
+ DistributeArenaPoints();
+ m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK;
+ CharacterDatabase.PExecute("UPDATE `saved_variables` SET `NextArenaPointDistributionTime` = FROM_UNIXTIME('"I64FMTD"')",(uint64)m_NextAutoDistributionTime);
+ }
+ m_AutoDistributionTimeChecker = 600000; // check 10 minutes
+ }
+ else
+ m_AutoDistributionTimeChecker -= diff;
+ }
}
-void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2)
+void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
{
// we can be in 3 queues in same time...
if(StatusID == 0)
@@ -427,7 +974,7 @@
data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
*data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
- *data << uint8(bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas
+ *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
switch(bg->GetTypeID()) // value depends on bg id
{
case BATTLEGROUND_AV:
@@ -460,9 +1007,9 @@
}
if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
- *data << uint32(BATTLEGROUND_AA); // all arenas
+ *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
else
- *data << uint32(bg->GetTypeID()); // BG id from DBC
+ *data << uint32(bg->GetTypeID()); // BG id from DBC
*data << uint16(0x1F90); // unk value 8080
*data << uint32(bg->GetInstanceID()); // instance id
@@ -470,8 +1017,7 @@
if(bg->isBattleGround())
*data << uint8(bg->GetTeamIndexByTeamId(team)); // team
else
- *data << uint8(bg->isRated()); // is rated battle
-
+ *data << uint8(israted?israted:bg->isRated()); // is rated battle
*data << uint32(StatusID); // status
switch(StatusID)
{
@@ -505,7 +1051,7 @@
{
for(uint8 i = 0; i < 2; i++)
{
- *data << uint32(3000+1+i); // rating change: showed value - 3000
+ *data << uint32(3000+bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000
*data << uint8(0); // string
}
}
@@ -536,11 +1082,13 @@
{
// that part probably wrong
Player *plr = objmgr.GetPlayer(itr->first);
+ uint32 team = bg->GetPlayerTeam(plr->GetGUID());
+ if(!team) team = plr->GetTeam();
if(plr)
{
- if(plr->GetTeam() == HORDE)
+ if(team == HORDE)
*data << uint8(0);
- else if(plr->GetTeam() == ALLIANCE)
+ else if(team == ALLIANCE)
*data << uint8(1);
else
*data << uint8(0);
@@ -624,20 +1172,135 @@
*data << uint64(plr->GetGUID());
}
-void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID)
+void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
{
// set invited player counters:
BattleGround* bg = this->GetBattleGround(bgInstanceGUID);
- bg->IncreaseInvitedCount(plr->GetTeam());
+ bg->IncreaseInvitedCount(team);
+
+ // set the arena teams for rated matches
+ if(bg->isArena() && bg->isRated())
+ {
+ switch(bg->GetArenaType())
+ {
+ case ARENA_TYPE_2v2:
+ bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
+ break;
+ case ARENA_TYPE_3v3:
+ bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
+ break;
+ case ARENA_TYPE_5v5:
+ bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
+ break;
+ default:
+ break;
+ }
+ }
+
// create invite events:
//add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
- BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, plr->GetTeam());
+ BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
}
+BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)
+{
+ return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
+}
+
+// create a new battleground that will really be used to play
+BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
+{
+ BattleGround *bg = NULL;
+
+ // get the template BG
+ BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
+
+ if(!bg_template)
+ {
+ sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
+ return 0;
+ }
+
+ // create a copy of the BG template
+ switch(bgTypeId)
+ {
+ case BATTLEGROUND_AV:
+ bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
+ break;
+ case BATTLEGROUND_WS:
+ bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
+ break;
+ case BATTLEGROUND_AB:
+ bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
+ break;
+ case BATTLEGROUND_NA:
+ bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
+ break;
+ case BATTLEGROUND_BE:
+ bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
+ break;
+ case BATTLEGROUND_AA:
+ bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
+ break;
+ case BATTLEGROUND_EY:
+ bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
+ break;
+ case BATTLEGROUND_RL:
+ bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
+ break;
+ default:
+ //bg = new BattleGround;
+ return 0;
+ break; // placeholder for non implemented BG
+ }
+
+ // generate a new instance id
+ bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
+
+/* UNCOMMENT THIS IF MAP SYSTEM IS UPDATED
+ // get the map
+ Map * m = MapManager::Instance().GetMap(bg->GetMapId(),NULL);
+ if(!m)
+ {
+ // no map found, delete bg and return null
+ delete bg;
+ return 0;
+ }
+
+ // create new instance if the map is instanceable
+ if(m->Instanceable())
+ {
+ // generate a new instance id
+ bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
+ ((MapInstanced*)m)->CreateInstance(bg->GetInstanceID(),m);
+ }
+*/
+
+ // reset the new bg (set status to status_wait_queue from status_none)
+ bg->Reset();
+
+ if(!(bg->SetupBattleGround()))
+ {
+ sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
+ delete bg;
+ return 0;
+ }
+
+ // add BG to free slot queue
+ bg->AddToBGFreeSlotQueue();
+
+ // add bg to update list
+ AddBattleGround(bg->GetInstanceID(), bg);
+
+ return bg;
+}
+
+// used to create the BG templates
+
uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
{
// Create the BG
@@ -672,7 +1335,7 @@
}
bg->SetTypeID(bgTypeId);
- bg->SetInstanceID(bgTypeId); // temporary
+ bg->SetInstanceID(0); // template bg, instance id is 0
bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
bg->SetMinPlayers(MinPlayersPerTeam*2);
@@ -684,9 +1347,10 @@
//add BaggleGround instance to FreeSlotQueue
bg->AddToBGFreeSlotQueue();
- AddBattleGround(bg->GetInstanceID(), bg);
- //sLog.outDetail("BattleGroundMgr: Created new battleground: %u %s (Map %u, %u players per team, Levels %u-%u)", bg_TypeID, bg->m_Name, bg->m_MapId, bg->m_MaxPlayersPerTeam, bg->m_LevelMin, bg->m_LevelMax);
- return bg->GetInstanceID();
+ // do NOT add to update list, since this is a template battleground!
+
+ // return some not-null value, bgTypeId is good enough for me
+ return bgTypeId;
}
void BattleGroundMgr::CreateInitialBattleGrounds()
@@ -805,7 +1469,86 @@
sLog.outString();
sLog.outString( ">> Loaded %u battlegrounds", count );
}
+void BattleGroundMgr::InitAutomaticArenaPointDistribution()
+{
+ if(m_AutoDistributePoints)
+ {
+ sLog.outDebug("Initializing Automatic Arena Point Distribution");
+ QueryResult * result = CharacterDatabase.Query("SELECT UNIX_TIMESTAMP(`NextArenaPointDistributionTime`) FROM `saved_variables`");
+ if(!result)
+ {
+ sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
+ m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK;
+ CharacterDatabase.PExecute("INSERT INTO `saved_variables` (`NextArenaPointDistributionTime`) VALUES ( FROM_UNIXTIME('"I64FMTD"') )",(uint64)m_NextAutoDistributionTime);
+ }
+ else
+ {
+ m_NextAutoDistributionTime = (*result)[0].GetUInt64();
+ delete result;
+ }
+ sLog.outDebug("Automatic Arena Point Distribution initialized.");
+ }
+}
+void BattleGroundMgr::DistributeArenaPoints()
+{
+ // used to distribute arena points based on last week's stats
+ sWorld.SendWorldText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);
+
+ sWorld.SendWorldText("Distributing arena points to online players...", NULL);
+
+ //TODO: Guard Player map
+ HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ {
+ uint64 guid = itr->second->GetGUID();
+ Player * pl = itr->second;
+ if(!pl)
+ continue;
+ uint32 mod = 0;
+ for(int i=0; i<3; ++i)
+ {
+ ArenaTeam * at = objmgr.GetArenaTeamById(pl->GetArenaTeamId(i));
+ if(at && mod < at->GetMemberPoints(guid))
+ mod = at->GetMemberPoints(guid);
+ // reset weekly played match count for team
+ if(at)
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * at->GetSlot() + 2, 0);
+
+ }
+ mod += pl->GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY);
+ if(mod > 5000)
+ mod = 5000;
+
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, mod);
+
+ CharacterDatabase.PExecute("UPDATE `arena_team_member` SET `points_to_add` = '0' WHERE `guid` = '%u'",guid);
+ }
+
+ sWorld.SendWorldText("Finished distributing arena points to online players. Now saving... ", NULL);
+
+ ObjectAccessor::Instance().SaveAllPlayers();
+
+ sWorld.SendWorldText("Online players saved.", NULL);
+
+ sWorld.SendWorldText("Distributing arena points to offline players...", NULL);
+
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("UPDATE `characters` b, `arena_team_member` a SET b.`data` = CONCAT( SUBSTRING_INDEX(b.`data`, ' ', '%u'),' ', CAST( IF ( ((CAST( SUBSTRING( b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(c.`points_to_add`) FROM `arena_team_member` c WHERE c.`guid` = b.`guid` GROUP BY c.`guid`) ) < '5000'), CAST(SUBSTRING(b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(d.`points_to_add`) FROM `arena_team_member` d WHERE d.`guid` = b.`guid` GROUP BY d.`guid`), '5000') AS CHAR),' ',SUBSTRING(b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2))) WHERE b.`guid` = a.`guid`",PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1);
+ for(int i=0; i<3; ++i)
+ {
+ // reset weekly played matches
+ uint32 position = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * i + 2;
+ CharacterDatabase.PExecute("UPDATE `characters` SET `data` = CONCAT( SUBSTRING_INDEX(`data`,' ','%u'),' ','0',' ',SUBSTRING(`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(`data`,' ','%u')) + 2)))",position, position + 1);
+ }
+ CharacterDatabase.Execute("UPDATE `arena_team_member` SET `points_to_add` = '0', `played_week` = '0', `wons_week` = '0'");
+ CharacterDatabase.Execute("UPDATE `arena_team_stats` SET `games` = '0', `wins` = '0'");
+ CharacterDatabase.CommitTransaction();
+
+ sWorld.SendWorldText("Finished distributing arena points to offline players.", NULL);
+ sWorld.SendWorldText("Done flushing Arena points.", NULL);
+}
+
void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId)
{
uint32 PlayerLevel = 10;
@@ -841,18 +1584,27 @@
}
}
-void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 bgTypeId)
+void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, uint32 team)
{
- BattleGround *bg = GetBattleGround(bgTypeId);
+ BattleGround *bg = GetBattleGround(instanceId);
if(bg)
{
uint32 mapid = bg->GetMapId();
float x, y, z, O;
- bg->GetTeamStartLoc(pl->GetTeam(), x, y, z, O);
+ if(team==0)
+ team = pl->GetTeam();
+ bg->GetTeamStartLoc(team, x, y, z, O);
sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
- pl->TeleportTo(mapid, x, y, z, O);
+ pl->SetInstanceId(instanceId);
+ pl->m_BoundInstances[mapid]=std::pair<uint32,uint32>(instanceId, pl->GetGUIDLow());
+ // teleport as gm command
+ pl->TeleportTo(mapid, x, y, z, O, true, true, false, true);
}
+ else
+ {
+ sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
+ }
}
void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)
@@ -864,3 +1616,91 @@
data << guid << time_;
pl->GetSession()->SendPacket(&data);
}
+
+void BattleGroundMgr::RemoveBattleGround(uint32 instanceID)
+{
+ BattleGroundSet::iterator itr = m_BattleGrounds.find(instanceID);
+ if(itr!=m_BattleGrounds.end())
+ m_BattleGrounds.erase(itr);
+}
+
+bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const
+{
+ return ( bgTypeId == BATTLEGROUND_AA ||
+ bgTypeId == BATTLEGROUND_BE ||
+ bgTypeId == BATTLEGROUND_NA ||
+ bgTypeId == BATTLEGROUND_RL );
+}
+
+bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const
+{
+ return !IsArenaType(bgTypeId);
+}
+
+uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const
+{
+ switch(bgTypeId)
+ {
+ case BATTLEGROUND_WS:
+ return BATTLEGROUND_QUEUE_WS;
+ case BATTLEGROUND_AB:
+ return BATTLEGROUND_QUEUE_AB;
+ case BATTLEGROUND_AV:
+ return BATTLEGROUND_QUEUE_AV;
+ case BATTLEGROUND_EY:
+ return BATTLEGROUND_QUEUE_EY;
+ case BATTLEGROUND_AA:
+ case BATTLEGROUND_NA:
+ case BATTLEGROUND_RL:
+ case BATTLEGROUND_BE:
+ switch(arenaType)
+ {
+ case ARENA_TYPE_2v2:
+ return BATTLEGROUND_QUEUE_2v2;
+ case ARENA_TYPE_3v3:
+ return BATTLEGROUND_QUEUE_3v3;
+ case ARENA_TYPE_5v5:
+ return BATTLEGROUND_QUEUE_5v5;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const
+{
+ switch(bgQueueTypeId)
+ {
+ case BATTLEGROUND_QUEUE_WS:
+ return BATTLEGROUND_WS;
+ case BATTLEGROUND_QUEUE_AB:
+ return BATTLEGROUND_AB;
+ case BATTLEGROUND_QUEUE_AV:
+ return BATTLEGROUND_AV;
+ case BATTLEGROUND_QUEUE_EY:
+ return BATTLEGROUND_EY;
+ case BATTLEGROUND_QUEUE_2v2:
+ case BATTLEGROUND_QUEUE_3v3:
+ case BATTLEGROUND_QUEUE_5v5:
+ return BATTLEGROUND_AA;
+ default:
+ return 0;
+ }
+}
+
+uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId) const
+{
+ switch(bgQueueTypeId)
+ {
+ case BATTLEGROUND_QUEUE_2v2:
+ return ARENA_TYPE_2v2;
+ case BATTLEGROUND_QUEUE_3v3:
+ return ARENA_TYPE_3v3;
+ case BATTLEGROUND_QUEUE_5v5:
+ return ARENA_TYPE_5v5;
+ default:
+ return 0;
+ }
+}
Index: src/game/BattleGroundMgr.h
===================================================================
--- src/game/BattleGroundMgr.h (revision 5447)
+++ src/game/BattleGroundMgr.h (working copy)
@@ -34,51 +34,99 @@
#define MAX_BATTLEGROUND_TYPES 9 // each BG type will be in array
-struct PlayerQueueInfo
+#define MAX_BATTLEGROUND_QUEUE_TYPES 8
+
+#define BG_REMIND_INVITE_TIME 60000 // when this time pass, player get invitation request again
+
+#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK 604800 // seconds in a week
+
+struct GroupQueueInfo; // type predefinition
+struct PlayerQueueInfo // stores information for players in queue
{
uint32 InviteTime; // first invite time
uint32 LastInviteTime; // last invite time
- uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG
uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes
- uint32 Team; // Player team (ALLIANCE/HORDE)
- bool IsRated;
- bool AsGroup; // uint32 GroupId;
- uint8 ArenaType;
+ GroupQueueInfo * GroupInfo; // pointer to the associated groupqueueinfo
};
-struct PlayersCount
+struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!)
{
- uint32 Alliance;
- uint32 Horde;
+ std::map<uint64, PlayerQueueInfo*> Players; // player queue info map
+ uint32 Team; // Player team (ALLIANCE/HORDE)
+ bool IsRated; // rated
+ uint32 BgTypeId; // battleground type id
+ uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG
+ uint32 JoinTime; // time when group was added
+ uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG
+ uint32 ArenaTeamRating; // if rated match, inited to the rating of the team
};
-template<class _Kty, class _Ty> class bgqueue: public std::map<_Kty, _Ty>
-{
- public:
- uint32 Alliance;
- uint32 Horde;
- //bool Ready; // not used now
- //uint32 AverageTime; //not already implemented (it should be average time in queue for last 10 players)
-};
-
+class BattleGround;
class BattleGroundQueue
{
public:
BattleGroundQueue();
~BattleGroundQueue();
-/*
- uint32 GetType();
- void SetType(uint32 type);*/
- void Update(uint32 bgTypeId, uint32 queue_id);
+ void Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype = 0, bool isRated = false, uint32 minRating = 0);
- void AddPlayer(Player *plr, uint32 bgTypeId);
+ GroupQueueInfo * AddGroup(Player * leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating);
+ void AddPlayer(Player *plr, GroupQueueInfo * ginfo);
void RemovePlayer(uint64 guid, bool decreaseInvitedCount);
+ void DecreaseGroupLength(uint32 queueId, uint32 AsGroup);
+ void BGEndedRemoveInvites(BattleGround * bg);
- typedef bgqueue<uint64, PlayerQueueInfo> QueuedPlayersMap;
+ typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap;
QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES];
- typedef std::list<uint64> PlayerGuidsSortedByTimeQueue;
- PlayerGuidsSortedByTimeQueue m_PlayersSortedByWaitTime[MAX_BATTLEGROUND_QUEUES];
+
+ typedef std::list<GroupQueueInfo*> QueuedGroupsList;
+ QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES];
+
+ // class to hold pointers to the groups eligible for a specific selection pool building mode
+ class EligibleGroups : public std::list<GroupQueueInfo *>
+ {
+ public:
+ void Init(QueuedGroupsList * source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0);
+ void RemoveGroup(GroupQueueInfo * ginfo);
+ };
+
+ EligibleGroups m_EligibleGroups;
+
+ // class to select and invite groups to bg
+ class SelectionPool
+ {
+ public:
+ void Init();
+ void AddGroup(GroupQueueInfo * group);
+ GroupQueueInfo * GetMaximalGroup();
+ void RemoveGroup(GroupQueueInfo * group);
+ uint32 GetPlayerCount() const {return PlayerCount;}
+ public:
+ std::list<GroupQueueInfo *> SelectedGroups;
+ private:
+ uint32 PlayerCount;
+ GroupQueueInfo * MaxGroup;
+ };
+
+ enum SelectionPoolBuildMode
+ {
+ NORMAL_ALLIANCE,
+ NORMAL_HORDE,
+ ONESIDE_ALLIANCE_TEAM1,
+ ONESIDE_ALLIANCE_TEAM2,
+ ONESIDE_HORDE_TEAM1,
+ ONESIDE_HORDE_TEAM2,
+
+ NUM_SELECTION_POOL_TYPES
+ };
+
+ SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES];
+
+ bool BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0);
+
+ private:
+
+ bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side);
};
/*
@@ -116,7 +164,6 @@
uint32 m_PlayersTeam;
};
-
class BattleGroundMgr
{
public:
@@ -132,18 +179,17 @@
void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId);
void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value);
void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);
- void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2);
+ void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0);
void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid);
-
/* Player invitation */
// called from Queue update, or from Addplayer to queue
- void InvitePlayer(Player* plr, uint32 bgInstanceGUID);
+ void InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team);
/* Battlegrounds */
BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); };
BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); };
- BattleGround* GetBattleGround(uint8 ID)
+ BattleGround* GetBattleGround(uint32 ID)
{
BattleGroundSet::iterator i = m_BattleGrounds.find(ID);
if(i != m_BattleGrounds.end())
@@ -152,26 +198,48 @@
return NULL;
};
+ BattleGround * GetBattleGroundTemplate(uint32 bgTypeId);
+ BattleGround * CreateNewBattleGround(uint32 bgTypeId);
+
uint32 CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO);
inline void AddBattleGround(uint32 ID, BattleGround* BG) { m_BattleGrounds[ID] = BG; };
+ void RemoveBattleGround(uint32 instanceID);
void CreateInitialBattleGrounds();
- void SendToBattleGround(Player *pl, uint32 bgTypeId);
+ void SendToBattleGround(Player *pl, uint32 bgTypeId, uint32 team = 0);
/* Battleground queues */
//these queues are instantiated when creating BattlegroundMrg
- BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_TYPES]; // public, because we need to access them in BG handler code
+ BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]; // public, because we need to access them in BG handler code
BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPES];
void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid);
+ bool IsArenaType(uint32 bgTypeId) const;
+ bool IsBattleGroundType(uint32 bgTypeId) const;
+ uint32 BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const;
+ uint32 BGTemplateId(uint32 bgQueueTypeId) const;
+ uint8 BGArenaType(uint32 bgQueueTypeId) const;
+
+ uint32 GetMaxRatingDifference() const {return m_MaxRatingDifference;}
+ uint32 GetRatingDiscardTimer() const {return m_RatingDiscardTimer;}
+
+ void InitAutomaticArenaPointDistribution();
+ void DistributeArenaPoints();
+
private:
/* Battlegrounds */
BattleGroundSet m_BattleGrounds;
+ uint32 m_MaxRatingDifference;
+ uint32 m_RatingDiscardTimer;
+ uint32 m_NextRatingDiscardUpdate;
+ bool m_AutoDistributePoints;
+ uint64 m_NextAutoDistributionTime;
+ uint32 m_AutoDistributionTimeChecker;
};
#define sBattleGroundMgr MaNGOS::Singleton<BattleGroundMgr>::Instance()
Index: src/game/BattleGroundNA.cpp
===================================================================
--- src/game/BattleGroundNA.cpp (revision 5447)
+++ src/game/BattleGroundNA.cpp (working copy)
@@ -73,6 +73,9 @@
for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++)
DoorOpen(i);
+ for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; i++)
+ SpawnBGObject(i, 60);
+
SendMessageToAll(LANG_ARENA_BEGUN);
SetStatus(STATUS_IN_PROGRESS);
SetStartDelayTime(0);
@@ -83,7 +86,13 @@
if(plr)
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
}
- }
+
+ if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
+
+ }
}
/*if(GetStatus() == STATUS_IN_PROGRESS)
@@ -92,9 +101,9 @@
}*/
}
-void BattleGroundNA::AddPlayer(Player *plr)
+void BattleGroundNA::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map, default values are set in constructor
BattleGroundNAScore* sc = new BattleGroundNAScore;
@@ -103,7 +112,13 @@
void BattleGroundNA::RemovePlayer(Player *plr, uint64 guid)
{
-
+ if(GetStatus() == STATUS_WAIT_LEAVE)
+ return;
+
+ if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
}
void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)
@@ -116,16 +131,16 @@
sLog.outError("BattleGroundNA: Killer player not found");
return;
}
-
- uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
-
- ++m_TeamKills[killer_team_index]; // add kills to killer's team
-
- if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))
+if(!GetAlivePlayersCountByTeam(ALLIANCE))
{
// all opponents killed
- EndBattleGround(killer->GetTeam());
+ EndBattleGround(HORDE);
}
+ else if(!GetAlivePlayersCountByTeam(HORDE))
+ {
+ // all opponents killed
+ EndBattleGround(ALLIANCE);
+ }
}
void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)
@@ -134,11 +149,14 @@
return;
uint32 SpellId = 0;
- uint64 buff_guid = 0;
+ GameObject* obj = 0;
switch(Trigger)
{
case 4536: // buff trigger?
+ obj = m_BgObjects[BG_NA_OBJECT_BUFF_1];
+ break;
case 4537: // buff trigger?
+ obj = m_BgObjects[BG_NA_OBJECT_BUFF_2];
break;
default:
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
@@ -146,14 +164,13 @@
break;
}
- if(buff_guid)
- HandleTriggerBuff(buff_guid,Source);
+ if(obj)
+ HandleTriggerBuff(obj->GetGUID(),Source);
}
void BattleGroundNA::ResetBGSubclass()
{
- m_TeamKills[BG_TEAM_ALLIANCE] = 0;
- m_TeamKills[BG_TEAM_HORDE] = 0;
+
}
bool BattleGroundNA::SetupBattleGround()
@@ -162,7 +179,11 @@
if( !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)
- || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY))
+ || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)
+ // buffs
+ || !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941, 2895.250000, 13.052700, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)
+ || !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078, 2946.350098, 13.051300, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120))
+
{
sLog.outErrorDb("BatteGroundNA: Failed to spawn some object!");
return false;
Index: src/game/BattleGroundNA.h
===================================================================
--- src/game/BattleGroundNA.h (revision 5447)
+++ src/game/BattleGroundNA.h (working copy)
@@ -26,7 +26,9 @@
BG_NA_OBJECT_DOOR_2 = 1,
BG_NA_OBJECT_DOOR_3 = 2,
BG_NA_OBJECT_DOOR_4 = 3,
- BG_NA_OBJECT_MAX = 4
+ BG_NA_OBJECT_BUFF_1 = 4,
+ BG_NA_OBJECT_BUFF_2 = 5,
+ BG_NA_OBJECT_MAX = 6
};
enum BattleGroundNAObjects
@@ -34,7 +36,9 @@
BG_NA_OBJECT_TYPE_DOOR_1 = 183978,
BG_NA_OBJECT_TYPE_DOOR_2 = 183980,
BG_NA_OBJECT_TYPE_DOOR_3 = 183977,
- BG_NA_OBJECT_TYPE_DOOR_4 = 183979
+ BG_NA_OBJECT_TYPE_DOOR_4 = 183979,
+ BG_NA_OBJECT_TYPE_BUFF_1 = 184663,
+ BG_NA_OBJECT_TYPE_BUFF_2 = 184664
};
class BattleGroundNAScore : public BattleGroundScore
@@ -55,15 +59,12 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
virtual void ResetBGSubclass();
void HandleKillPlayer(Player* player, Player *killer);
-
- private:
- uint32 m_TeamKills[2]; // count of kills for each team
};
#endif
Index: src/game/BattleGroundRL.cpp
===================================================================
--- src/game/BattleGroundRL.cpp (revision 5447)
+++ src/game/BattleGroundRL.cpp (working copy)
@@ -73,6 +73,9 @@
for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)
DoorOpen(i);
+ for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; i++)
+ SpawnBGObject(i, 60);
+
SendMessageToAll(LANG_ARENA_BEGUN);
SetStatus(STATUS_IN_PROGRESS);
SetStartDelayTime(0);
@@ -83,6 +86,10 @@
if(plr)
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
}
+ if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
}
}
@@ -92,9 +99,9 @@
}*/
}
-void BattleGroundRL::AddPlayer(Player *plr)
+void BattleGroundRL::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map, default values are set in constructor
BattleGroundRLScore* sc = new BattleGroundRLScore;
@@ -103,7 +110,13 @@
void BattleGroundRL::RemovePlayer(Player *plr, uint64 guid)
{
-
+ if(GetStatus() == STATUS_WAIT_LEAVE)
+ return;
+
+ if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
}
void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)
@@ -117,15 +130,15 @@
return;
}
- uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
-
- ++m_TeamKills[killer_team_index]; // add kills to killer's team
-
- if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))
+ if(!GetAlivePlayersCountByTeam(ALLIANCE))
{
- // all opponents killed
- EndBattleGround(killer->GetTeam());
+ EndBattleGround(HORDE);
}
+ else if(!GetAlivePlayersCountByTeam(HORDE))
+ {
+ // all opponents killed
+ EndBattleGround(ALLIANCE);
+ }
}
void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)
@@ -135,11 +148,14 @@
return;
uint32 SpellId = 0;
- uint64 buff_guid = 0;
+ GameObject* obj = 0;
switch(Trigger)
{
case 4696: // buff trigger?
+ obj = m_BgObjects[BG_RL_OBJECT_BUFF_1];
+ break;
case 4697: // buff trigger?
+ obj = m_BgObjects[BG_RL_OBJECT_BUFF_2];
break;
default:
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
@@ -147,21 +163,23 @@
break;
}
- if(buff_guid)
- HandleTriggerBuff(buff_guid,Source);
+ if(obj)
+ HandleTriggerBuff(obj->GetGUID(),Source);
}
void BattleGroundRL::ResetBGSubclass()
{
- m_TeamKills[BG_TEAM_ALLIANCE] = 0;
- m_TeamKills[BG_TEAM_HORDE] = 0;
-}
+ }
bool BattleGroundRL::SetupBattleGround()
{
// gates
if( !AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY)
- || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY))
+ || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY)
+ // buffs
+ || !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)
+ || !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049, 1699.170044, 34.872601, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120))
+
{
sLog.outErrorDb("BatteGroundRL: Failed to spawn some object!");
return false;
Index: src/game/BattleGroundRL.h
===================================================================
--- src/game/BattleGroundRL.h (revision 5447)
+++ src/game/BattleGroundRL.h (working copy)
@@ -24,13 +24,17 @@
{
BG_RL_OBJECT_DOOR_1 = 0,
BG_RL_OBJECT_DOOR_2 = 1,
- BG_RL_OBJECT_MAX = 2
+ BG_RL_OBJECT_BUFF_1 = 2,
+ BG_RL_OBJECT_BUFF_2 = 3,
+ BG_RL_OBJECT_MAX = 4
};
enum BattleGroundRLObjects
{
BG_RL_OBJECT_TYPE_DOOR_1 = 185918,
- BG_RL_OBJECT_TYPE_DOOR_2 = 185917
+ BG_RL_OBJECT_TYPE_DOOR_2 = 185917,
+ BG_RL_OBJECT_TYPE_BUFF_1 = 184663,
+ BG_RL_OBJECT_TYPE_BUFF_2 = 184664
};
class BattleGroundRLScore : public BattleGroundScore
@@ -51,15 +55,12 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
virtual void ResetBGSubclass();
void HandleKillPlayer(Player* player, Player *killer);
-
- private:
- uint32 m_TeamKills[2]; // count of kills for each team
};
#endif
Index: src/game/BattleGroundWS.cpp
===================================================================
--- src/game/BattleGroundWS.cpp (revision 5447)
+++ src/game/BattleGroundWS.cpp (working copy)
@@ -50,12 +50,16 @@
{
m_Events |= 0x01;
- for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++)
+ SpawnBGCreature(i, RESPAWN_IMMEDIATELY);
for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
SpawnBGObject(i, RESPAWN_ONE_DAY);
+ //doors
+ for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+
SetStartDelayTime(START_DELAY0);
}
// After 1 minute, warning is signalled
@@ -74,17 +78,9 @@
else if(GetStartDelayTime() < 0 && !(m_Events & 0x10))
{
m_Events |= 0x10;
- for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; i++)
- DoorOpen(i);
+ for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
+ SpawnBGObject(i, RESPAWN_ONE_DAY);
- for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; i++)
- DoorOpen(i);
-
- SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY);
-
for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
@@ -119,9 +115,9 @@
}
}
-void BattleGroundWS::AddPlayer(Player *plr)
+void BattleGroundWS::AddPlayer(Player *plr, uint32 team)
{
- BattleGround::AddPlayer(plr);
+ BattleGround::AddPlayer(plr, team);
//create score and add it to map, default values are set in constructor
BattleGroundWGScore* sc = new BattleGroundWGScore;
@@ -402,7 +398,7 @@
return;
uint32 SpellId = 0;
- uint64 buff_guid = 0;
+ GameObject* buff_guid = 0;
switch(Trigger)
{
case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().
@@ -445,7 +441,7 @@
}
if(buff_guid)
- HandleTriggerBuff(buff_guid,Source);
+ HandleTriggerBuff(buff_guid->GetGUID(),Source);
}
bool BattleGroundWS::SetupBattleGround()
@@ -506,13 +502,13 @@
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0;
- if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])
+ /*if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])
DelCreature(WS_SPIRIT_MAIN_ALLIANCE);
if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE])
DelCreature(WS_SPIRIT_MAIN_HORDE);
+*/
}
-
void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer)
{
if(GetStatus() != STATUS_IN_PROGRESS)
@@ -550,7 +546,6 @@
break;
}
}
-
void BattleGroundWS::FillInitialWorldStates(WorldPacket& data)
{
data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE));
Index: src/game/BattleGroundWS.h
===================================================================
--- src/game/BattleGroundWS.h (revision 5447)
+++ src/game/BattleGroundWS.h (working copy)
@@ -122,7 +122,7 @@
void Update(time_t diff);
/* inherited from BattlegroundClass */
- virtual void AddPlayer(Player *plr);
+ virtual void AddPlayer(Player *plr, uint32 team = 0);
/* BG Flags */
uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; }
Index: src/game/Channel.cpp
===================================================================
--- src/game/Channel.cpp (revision 5447)
+++ src/game/Channel.cpp (working copy)
@@ -98,7 +98,7 @@
if(m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL) ))
{
MakeJoined(&data, p);
- SendToAll(&data);
+ //SendToAll(&data);
}
data.clear();
@@ -111,7 +111,7 @@
MakeYouJoined(&data);
SendToOne(&data, p);
- JoinNotify(p);
+ //JoinNotify(p);
// if no owner first logged will become
if(!IsConstant() && !m_ownerGUID)
@@ -153,10 +153,10 @@
{
WorldPacket data;
MakeLeft(&data, p);
- SendToAll(&data);
+ //SendToAll(&data);
}
- LeaveNotify(p);
+ //LeaveNotify(p);
if(changeowner)
{
Index: src/game/Chat.cpp
===================================================================
--- src/game/Chat.cpp (revision 5447)
+++ src/game/Chat.cpp (working copy)
@@ -387,6 +387,7 @@
{ "cast", SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand, "", NULL },
{ "castback", SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand, "", NULL },
{ "casttarget", SEC_ADMINISTRATOR, &ChatHandler::HandleCastTargetCommand, "", NULL },
+ { "flusharenapoints", SEC_ADMINISTRATOR, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
//! Development Commands
{ "setvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleSetValue, "", NULL },
Index: src/game/Chat.h
===================================================================
--- src/game/Chat.h (revision 5447)
+++ src/game/Chat.h (working copy)
@@ -329,6 +329,7 @@
bool HandleCastCommand(const char *args);
bool HandleCastBackCommand(const char *args);
bool HandleCastTargetCommand(const char *args);
+ bool HandleFlushArenaPointsCommand(const char *args);
//! Development Commands
bool HandleSetValue(const char* args);
Index: src/game/Language.h
===================================================================
--- src/game/Language.h (revision 5447)
+++ src/game/Language.h (working copy)
@@ -528,6 +528,13 @@
LANG_PLAYER_AFK = 708,
LANG_PLAYER_DND_DEFAULT = 709,
LANG_PLAYER_AFK_DEFAULT = 710,
+
+ LANG_BG_GROUP_TOO_LARGE = 7007, // "Your group is too large for this battleground. Please regroup to join."
+ LANG_ARENA_GROUP_TOO_LARGE = 7008, // "Your group is too large for this arena. Please regroup to join."
+ LANG_ARENA_YOUR_TEAM_ONLY = 7009, // "Your group has members not in your arena team. Please regroup to join."
+ LANG_ARENA_NOT_ENOUGH_PLAYERS = 7010, // "Your group does not have enough players to join this match."
+ LANG_ARENA_GOLD_WINS = 7011, // "The Gold Team wins!"
+ LANG_ARENA_GREEN_WINS = 7012 // "The Green Team wins!"
};
/* NOT USED VALUES
Index: src/game/Level3.cpp
===================================================================
--- src/game/Level3.cpp (revision 5447)
+++ src/game/Level3.cpp (working copy)
@@ -43,6 +43,7 @@
#include "SkillExtraItems.h"
#include "SystemConfig.h"
#include "Config/ConfigEnv.h"
+#include "BattleGroundMgr.h"
//reload commands
bool ChatHandler::HandleReloadCommand(const char* arg)
@@ -4747,3 +4748,9 @@
return true;
}
+
+bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)
+{
+ sBattleGroundMgr.DistributeArenaPoints();
+ return true;
+}
Index: src/game/Map.cpp
===================================================================
--- src/game/Map.cpp (revision 5447)
+++ src/game/Map.cpp (working copy)
@@ -271,6 +271,10 @@
else
i_data = NULL;
+ // flags if gridunloading is enabled / disabled on this map
+ // needed, because bg objects aren't in the db, but added in runtime, and unloading the grids would destroy them
+ i_unloadmap = sWorld.getConfig(CONFIG_GRID_UNLOAD);
+
i_Players.clear();
}
@@ -393,7 +397,7 @@
Guard guard(*this);
if(!getNGrid(p.x_coord, p.y_coord))
{
- setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),
+ setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, i_unloadmap),
p.x_coord, p.y_coord);
// build a linkage between this map and NGridType
@@ -725,8 +729,9 @@
{
// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
- if ((i_id == 489) || (i_id == 529)) // WS, AB
- return;
+ // no longer needed, the unloadmap flag will prevent unloading bg map grids
+ // if ((i_id == 489) || (i_id == 529)) // WS, AB
+ // return;
for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
{
Index: src/game/Map.h
===================================================================
--- src/game/Map.h (revision 5447)
+++ src/game/Map.h (working copy)
@@ -149,6 +149,8 @@
bool GetUnloadFlag(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadFlag(); }
void SetUnloadFlag(const GridPair &p, bool unload) { getNGrid(p.x_coord, p.y_coord)->setUnloadFlag(unload); }
+ void SetUnloadMap(bool unload){ i_unloadmap = unload; }
+ bool GetUnloadMap() const { return i_unloadmap; }
void LoadGrid(const Cell& cell, bool no_unload = false);
bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce);
virtual void UnloadAll(bool pForce);
@@ -208,7 +210,7 @@
bool CanEnter(Player* player) const;
const char* GetMapName() const;
- bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }
+ bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID) || (i_mapEntry->map_type == MAP_BATTLEGROUND) || (i_mapEntry->map_type == MAP_ARENA))); }
// NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
bool IsDungeon() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }
bool IsRaid() const { return(i_mapEntry && (i_mapEntry->map_type == MAP_RAID)); }
@@ -294,6 +296,7 @@
uint32 i_resetDelayTime;
uint32 i_InstanceId;
uint32 i_maxPlayers;
+ bool i_unloadmap;
InstanceData* i_data;
std::string i_script;
Index: src/game/MapInstanced.cpp
===================================================================
--- src/game/MapInstanced.cpp (revision 5447)
+++ src/game/MapInstanced.cpp (working copy)
@@ -44,6 +44,7 @@
{
if (!i->second->HavePlayers())
{
+ DEBUG_LOG("reseting instance in update for instance id = %u and map id = %u named %s",this->GetInstanceId(),this->GetId(),this->GetMapName());
i->second->Reset();
// avoid doing ++ on invalid data
InstancedMaps::iterator i_old = i;
@@ -187,7 +188,7 @@
if (!instantiator && instantiator_online)
{
- sLog.outDebug("MAPINSTANCED: Player '%s' is not in group, instantiating map for player", player->GetName());
+ sLog.outDebug("MAPINSTANCED: Player '%s' is not in group, instantiating map %u for player", player->GetName(), GetId());
instantiator = player;
}
@@ -230,11 +231,13 @@
// check, if we have to generate new instance
if (!instantiator_bound || (InstanceId == 0))
{
+ sLog.outDebug("MAPINSTANCED: Generating new instance id");
// yes, new instance id has to be generated
InstanceId = MapManager::Instance().GenerateInstanceId();
}
else
{
+ sLog.outDebug("MAPINSTANCED: Instantiator bound, finding map...");
// find map of the designated instance and verify it
map = _FindMap(InstanceId);
}
@@ -242,7 +245,7 @@
// now create the instance
CreateInstance(InstanceId, map);
-
+ sLog.outDebug("MAPINSTANCED::GetInstance() Instance Created");
// we do need to bind instance, if the instance we use is valid, not temporary
if (player->m_InstanceValid)
{
@@ -304,6 +307,7 @@
// map for the instance is present, but the instance itself is no more valid, destroy map
Guard guard(*this);
+ DEBUG_LOG("reseting instance in createinstance for instance id = %u and map id = %u named %s",this->GetInstanceId(),this->GetId(),this->GetMapName());
map->Reset();
m_InstancedMaps.erase(InstanceId);
delete map;
@@ -314,10 +318,13 @@
// verify, if we have the map created, and create it if needed
if (!map)
{
+ sLog.outDebug("MAPINSTANCED: CreateInstance, map not found, creating it");
// map does not exist, create it
Guard guard(*this);
map = new Map(GetId(), GetGridExpiry(), InstanceId);
+ // set the unload map flag according to the base map's flag
+ map->SetUnloadMap(GetUnloadMap());
m_InstancedMaps[InstanceId] = map;
}
}
Index: src/game/MapManager.cpp
===================================================================
--- src/game/MapManager.cpp (revision 5447)
+++ src/game/MapManager.cpp (working copy)
@@ -104,7 +104,7 @@
Guard guard(*this);
const MapEntry* entry = sMapStore.LookupEntry(id);
- if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID)))
+ if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID) || (entry->map_type == MAP_BATTLEGROUND) || (entry->map_type == MAP_ARENA)))
{
m = new MapInstanced(id, i_gridCleanUpDelay, 0);
}
Index: src/game/MovementHandler.cpp
===================================================================
--- src/game/MovementHandler.cpp (revision 5447)
+++ src/game/MovementHandler.cpp (working copy)
@@ -102,17 +102,21 @@
{
if(bg->GetMapId() == _player->GetMapId()) // we teleported to bg
{
- if(!bg->GetBgRaid(_player->GetTeam())) // first player joined
+ // get the team this way, because arenas might 'override' the teams.
+ uint32 team = bg->GetPlayerTeam(_player->GetGUID());
+ if(!team)
+ team = _player->GetTeam();
+ if(!bg->GetBgRaid(team)) // first player joined
{
Group *group = new Group;
- bg->SetBgRaid(_player->GetTeam(), group);
+ bg->SetBgRaid(team, group);
group->ConvertToRaid();
group->AddMember(_player->GetGUID(), _player->GetName());
group->ChangeLeader(_player->GetGUID());
}
else // raid already exist
{
- bg->GetBgRaid(_player->GetTeam())->AddMember(_player->GetGUID(), _player->GetName());
+ bg->GetBgRaid(team)->AddMember(_player->GetGUID(), _player->GetName());
}
}
}
@@ -519,3 +523,16 @@
}
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: src/game/Player.cpp
===================================================================
--- src/game/Player.cpp (revision 5447)
+++ src/game/Player.cpp (working copy)
@@ -334,7 +334,7 @@
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
if(!rEntry)
{
- sLog.outError("Race %u not found in DBŃ (Wrong DBC files?)",race);
+ sLog.outError("Race %u not found in DB?(Wrong DBC files?)",race);
return false;
}
@@ -1258,8 +1258,8 @@
bool state = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
- // afk player not allowed in battleground
- if(state && InBattleGround())
+ // afk player not allowed in battleground ( do net check this in arena )
+ if(state && InBattleGround() && GetBattleGround() && GetBattleGround()->isBattleGround())
LeaveBattleground();
return state;
@@ -1442,7 +1442,7 @@
sLog.outDebug( "WORLD: Sent (SMSG_IGNORE_LIST)" );
}
-void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport, bool is_gm_command)
+void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport, bool is_gm_command, bool battleground_port)
{
// preparing unsummon pet if lost (we must get pet before teleportation or will not find it later)
Pet* pet = GetPet();
@@ -1602,7 +1602,8 @@
Map* map = MapManager::Instance().GetMap(mapid, this);
// verify, if it does want to homebind us (but only if we are not in GM state,
// GMs are allowed to teleport everywhere they want to be)
- if (!m_InstanceValid && (!isGameMaster() || !is_gm_command))
+ // battlegrounds do NOT homebind
+ if (!m_InstanceValid && (!isGameMaster() || !is_gm_command) && !battleground_port)
{
// yes, we are going to be homebind, avoid this action :)
SetInstanceId(0); // reset instance id
@@ -2734,6 +2735,32 @@
removeSpell(itr->second.spell);
}
+void Player::RemoveArenaSpellCooldowns()
+{
+ // remove cooldowns on spells that has < 15 min CD
+ SpellCooldowns::iterator itr, next;
+ // iterate spell cooldowns
+ for(itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); itr = next)
+ {
+ next = itr;
+ ++next;
+ SpellEntry const * entry = sSpellStore.LookupEntry(itr->first);
+ // check if spellentry is present and if the cooldown is less than 15 mins
+ if( entry &&
+ (entry->RecoveryTime <= 15 * 60000) &&
+ (entry->CategoryRecoveryTime <= 15 * 60000))
+ {
+ // notify player
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8+4));
+ data << uint32(itr->first);
+ data << GetGUID();
+ GetSession()->SendPacket(&data);
+ // remove cooldown
+ m_spellCooldowns.erase(itr);
+ }
+ }
+}
+
void Player::RemoveAllSpellCooldown()
{
if(!m_spellCooldowns.empty())
@@ -5543,6 +5570,10 @@
uint32 now = time(NULL);
UpdateHonorFields();
+ // do not reward honor in arenas
+ if(InBattleGround() && GetBattleGround() && GetBattleGround()->isArena())
+ return false;
+
if(honor <= 0)
{
if(!uVictim || uVictim == this || uVictim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT))
@@ -5814,7 +5845,7 @@
// flags & 0x00004000 (16384) - outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
// flags & 0x00008000 (32768) - pvp objective area?
- if((zone->flags & 0x800) != 0) // in sanctuary
+ if((zone->flags & 0x800) != 0 || (GetAreaId() == 976) || (GetAreaId() == 35) || (GetAreaId() == 392) || (GetAreaId() == 2255)) // in sanctuary
{
UpdatePvP(false, true); // i'm right? need disable PvP in this area...
@@ -8740,6 +8771,13 @@
pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC)
return EQUIP_ERR_NOT_IN_COMBAT;
+ // do not allow gear change during in-progress arena matches, only weapons / offhands / relics / ammo
+ if( InBattleGround() && GetBattleGround() && GetBattleGround()->isArena() &&
+ (GetBattleGround()->GetStatus() == STATUS_IN_PROGRESS) &&
+ (pProto->Class != ITEM_CLASS_WEAPON) && (pProto->Class != ITEM_CLASS_PROJECTILE) &&
+ (pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD) && (pProto->InventoryType != INVTYPE_RELIC))
+ return EQUIP_ERR_NOT_DURING_ARENA_MATCH;
+
if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0)
return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err
@@ -8867,6 +8905,13 @@
pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC )
return EQUIP_ERR_NOT_IN_COMBAT;
+ // do not allow unequipping gear in in-progress arenas, except weapons, offhands, projectiles, relics
+ if( InBattleGround() && GetBattleGround() && GetBattleGround()->isArena() &&
+ (GetBattleGround()->GetStatus() == STATUS_IN_PROGRESS) &&
+ (pProto->Class != ITEM_CLASS_WEAPON) && (pProto->Class != ITEM_CLASS_PROJECTILE) &&
+ (pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD) && (pProto->InventoryType != INVTYPE_RELIC))
+ return EQUIP_ERR_NOT_DURING_ARENA_MATCH;
+
if(!swap && pItem->IsBag() && !((Bag*)pItem)->IsEmpty())
return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
@@ -9911,6 +9956,54 @@
}
}
+void Player::DestroyConjuredItems( bool update )
+{
+ // used when entering arena
+ // distroys all conjured items
+ sLog.outDebug( "STORAGE: DestroyConjuredItems" );
+
+ // in inventory
+ for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
+ {
+ Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ if( pItem && pItem->GetProto() &&
+ (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
+ (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
+ }
+
+ // in inventory bags
+ for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
+ {
+ Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ if( pBag )
+ {
+ ItemPrototype const *pBagProto = pBag->GetProto();
+ if( pBagProto )
+ {
+ for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
+ {
+ Item* pItem = pBag->GetItemByPos(j);
+ if( pItem && pItem->GetProto() &&
+ (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
+ (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
+ DestroyItem( i, j, update);
+ }
+ }
+ }
+ }
+
+ // in equipment and bag list
+ for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
+ {
+ Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ if( pItem && pItem->GetProto() &&
+ (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
+ (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
+ }
+}
+
void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update )
{
if(!pItem)
@@ -16245,7 +16338,8 @@
bool Player::GetBGAccessByLevel(uint32 bgTypeId) const
{
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
+ // get a template bg instead of running one
+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
if(!bg)
return false;
Index: src/game/Player.h
===================================================================
--- src/game/Player.h (revision 5447)
+++ src/game/Player.h (working copy)
@@ -863,7 +863,7 @@
void AddToWorld();
void RemoveFromWorld();
- void TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange = true, bool ignore_transport = true, bool is_gm_command = false);
+ void TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange = true, bool ignore_transport = true, bool is_gm_command = false, bool battleground_port = false);
void SetSummonPoint(uint32 mapid, float x, float y, float z)
{
@@ -1044,6 +1044,7 @@
void DestroyItem( uint8 bag, uint8 slot, bool update );
void DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check = false);
void DestroyItemCount( Item* item, uint32& count, bool update );
+ void DestroyConjuredItems( bool update );
void DestroyZoneLimitedItem( bool update, uint32 new_zone );
void SplitItem( uint16 src, uint16 dst, uint32 count );
void SwapItem( uint16 src, uint16 dst );
@@ -1352,6 +1353,7 @@
void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
void ProhibitSpellScholl(SpellSchools idSchool, uint32 unTimeMs );
void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); }
+ void RemoveArenaSpellCooldowns();
void RemoveAllSpellCooldown();
void _LoadSpellCooldowns(QueryResult *result);
void _SaveSpellCooldowns();
@@ -1719,9 +1721,11 @@
float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; }
float GetBattleGroundEntryPointZ() const { return m_bgEntryPointZ; }
float GetBattleGroundEntryPointO() const { return m_bgEntryPointO; }
- void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO )
+ uint32 GetBattleGroundEntryPointInstanceId() const { return m_bgEntryPointInstanceId; }
+ void SetBattleGroundEntryPoint(uint32 Map, uint32 InstanceId, float PosX, float PosY, float PosZ, float PosO )
{
m_bgEntryPointMap = Map;
+ m_bgEntryPointInstanceId = InstanceId;
m_bgEntryPointX = PosX;
m_bgEntryPointY = PosY;
m_bgEntryPointZ = PosZ;
@@ -1868,6 +1872,7 @@
*/
uint32 m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES];
uint32 m_bgEntryPointMap;
+ uint32 m_bgEntryPointInstanceId;
float m_bgEntryPointX;
float m_bgEntryPointY;
float m_bgEntryPointZ;
Index: src/game/Spell.cpp
===================================================================
--- src/game/Spell.cpp (revision 5447)
+++ src/game/Spell.cpp (working copy)
@@ -1497,6 +1497,14 @@
{
m_targets = *targets;
+ //only intialize Auto-Repeat spell with target, further handling in Unit::_UpdateAutoRepeatspells
+ if (m_autoRepeat && m_caster->m_AutoRepeatFirstCast)
+ {
+ m_spellState = SPELL_STATE_IDLE;
+ m_caster->SetCurrentCastedSpell( this );
+ return;
+ }
+
m_spellState = SPELL_STATE_PREPARING;
m_castPositionX = m_caster->GetPositionX();
@@ -1551,16 +1559,15 @@
m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
}
- // do first cast of autorepeat spell with recovery time delay (like after any autocast)
- if(IsAutoRepeat())
- m_spellState = SPELL_STATE_FINISHED;
-
if(m_IsTriggeredSpell)
cast(true);
else
{
m_caster->SetCurrentCastedSpell( this );
m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]);
+
+ if (m_autoRepeat) return; //graphics for autorepeat spells handled in Unit::_UpdateAutoRepeatSpells
+
SendSpellStart();
}
}
@@ -1579,6 +1586,9 @@
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
} break;
+
+ case SPELL_STATE_IDLE: //Auto-Repeat spells
+ SendInterrupted(0); break;
case SPELL_STATE_CASTING:
{
@@ -1897,9 +1907,9 @@
catrec = m_spellInfo->CategoryRecoveryTime;
}
- // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
+ // shoot spells (not wand shoot, for easier handling in Unit::_UpdateAutoRepeatSpell) used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
// prevent 0 cooldowns set by another way
- if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351))
+ if (rec <= 0 && catrec <= 0 && (cat == 76))
rec = _player->GetAttackTime(RANGED_ATTACK);
// Now we have cooldown data (if found any), time to apply mods
@@ -1962,23 +1972,10 @@
// update pointers based at it's GUIDs
UpdatePointers();
- if(m_targets.getUnitTargetGUID())
+ if(m_targets.getUnitTargetGUID() && !m_targets.getUnitTarget())
{
- if(!m_targets.getUnitTarget() || !m_targets.getUnitTarget()->isAlive())
- {
- if(m_autoRepeat)
- {
- m_autoRepeat = false;
- m_spellState = SPELL_STATE_FINISHED;
- return;
- }
-
- if(!m_targets.getUnitTarget())
- {
- cancel();
- return;
- }
- }
+ cancel();
+ return;
}
// check if the player caster has moved before the spell finished
@@ -1989,8 +1986,8 @@
// always cancel for channeled spells
if( m_spellState == SPELL_STATE_CASTING )
cancel();
- // don't cancel for melee, autorepeat and instant spells
- else if(!m_meleeSpell && !m_autoRepeat && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
+ // don't cancel for melee, autoshot(not wand shoot) and instant spells
+ else if(!m_meleeSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) || m_spellInfo->Category == 351)
cancel();
}
@@ -2007,7 +2004,7 @@
}
if(m_timer == 0 && !m_meleeSpell)
- cast();
+ cast(m_autoRepeat); //skip check for Auto-Repeat Spells, already checked in Unit::_UpdateAutoRepeatSpells
} break;
case SPELL_STATE_CASTING:
{
@@ -2557,12 +2554,20 @@
Player* p_caster = (Player*)m_caster;
+ // if arena preparation is on, don't take soul shards
+ bool bArenaPrep = p_caster->HasAura(SPELL_ARENA_PREPARATION, 0);
+
for(uint32 x=0;x<8;x++)
{
if(m_spellInfo->Reagent[x] <= 0)
continue;
uint32 itemid = m_spellInfo->Reagent[x];
+
+ // don't take soul shards if arena prep is on
+ if(bArenaPrep && (itemid == 6265))
+ continue;
+
uint32 itemcount = m_spellInfo->ReagentCount[x];
// if CastItem is also spell reagent
@@ -2778,6 +2783,15 @@
if((m_spellInfo->AttributesEx3 & 0x800) != 0)
return SPELL_FAILED_ONLY_BATTLEGROUNDS;
+ // do not allow spells with greater than 15 min CD to be cast in arenas
+ if( m_caster->GetTypeId() == TYPEID_PLAYER &&
+ ((Player*)m_caster)->InBattleGround() &&
+ ((Player*)m_caster)->GetBattleGround() &&
+ ((Player*)m_caster)->GetBattleGround()->isArena() &&
+ (m_spellInfo->RecoveryTime > 15 * 60000 ||
+ m_spellInfo->CategoryRecoveryTime > 15 * 60000) )
+ return SPELL_FAILED_NOT_IN_ARENA;
+
// zone check
uint32 zone_id = m_caster->GetZoneId();
@@ -3768,6 +3782,9 @@
focusObject = ok; // game object found in range
}
+ // check if arena prep is up
+ bool bArenaPrep = p_caster->HasAura(SPELL_ARENA_PREPARATION, 0);
+
for(uint32 i=0;i<8;i++)
{
if(m_spellInfo->Reagent[i] <= 0)
@@ -3775,26 +3792,35 @@
itemid = m_spellInfo->Reagent[i];
itemcount = m_spellInfo->ReagentCount[i];
-
- // if CastItem is also spell reagent
- if( m_CastItem && m_CastItem->GetEntry() == itemid )
+ if( m_CastItem )
{
- ItemPrototype const *proto = m_CastItem->GetProto();
- if(!proto)
- return SPELL_FAILED_ITEM_NOT_READY;
- for(int s=0;s<5;s++)
+ // if CastItem is also spell reagent
+ if( m_CastItem->GetEntry() == itemid )
{
- // CastItem will be used up and does not count as reagent
- int32 charges = m_CastItem->GetSpellCharges(s);
- if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
+ ItemPrototype const *proto = m_CastItem->GetProto();
+ if(!proto)
+ return SPELL_FAILED_ITEM_NOT_READY;
+ for(int s=0;s<5;s++)
{
- ++itemcount;
- break;
+ // CastItem will be used up and does not count as reagent
+ int32 charges = m_CastItem->GetSpellCharges(s);
+ if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
+ {
+ itemcount++;
+ break;
+ }
}
}
+ if( !p_caster->HasItemCount(itemid,itemcount) )
+ return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54
}
- if( !p_caster->HasItemCount(itemid,itemcount) )
- return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54
+ // if arena preparation is up, don't take soul shards, but take other reagents
+ // this cannot happen in case of a m_CastItem, so it's enough to check here
+ else if (!bArenaPrep || itemid != 6265)
+ {
+ if( !p_caster->HasItemCount(itemid,itemcount) )
+ return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54
+ }
}
uint32 totems = 2;
Index: src/game/SpellEffects.cpp
===================================================================
--- src/game/SpellEffects.cpp (revision 5447)
+++ src/game/SpellEffects.cpp (working copy)
@@ -1346,11 +1346,14 @@
// Scatter Shot
case 37506:
{
- if (m_caster->GetTypeId()!=TYPEID_PLAYER)
+ // break Auto Shot and "Attack"
+ m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+ m_caster->AttackStop();
+
+ if (m_caster->GetTypeId()!=TYPEID_PLAYER)
return;
-
- // break Auto Shot
- m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+
+ ((Player*)m_caster)->SendAttackSwingCancelAttack(); //force autoshot cancel
return;
}
Index: src/game/SpellHandler.cpp
===================================================================
--- src/game/SpellHandler.cpp (revision 5447)
+++ src/game/SpellHandler.cpp (working copy)
@@ -66,6 +66,15 @@
return;
}
+ // only allow conjured consumable, bandage
+ if ( pUser->InBattleGround() && pUser->GetBattleGround() && pUser->GetBattleGround()->isArena()
+ && (proto->Class == ITEM_CLASS_CONSUMABLE) && !(proto->Flags & ITEM_FLAGS_CONJURED) && !(proto->SubClass == ITEM_SUBCLASS_BANDAGE))
+ {
+ //send use error: not in arena
+ pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL);
+ return;
+ }
+
if (pUser->isInCombat())
{
for(int i = 0; i < 5; ++i)
@@ -469,7 +478,8 @@
if(((BattleGroundWS*)bg)->GetFlagState(ALLIANCE) != BG_WS_FLAG_STATE_ON_BASE)
return;
// check if it's correct flag
- if(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG] != obj->GetGUID())
+ if(!(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG]) ||
+ (((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG]->GetGUID() != obj->GetGUID()))
return;
// check player team
if(_player->GetTeam() == ALLIANCE)
@@ -484,7 +494,8 @@
if(((BattleGroundWS*)bg)->GetFlagState(HORDE) != BG_WS_FLAG_STATE_ON_BASE)
return;
// check if it's correct flag
- if(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG] != obj->GetGUID())
+ if(!(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG]) ||
+ (((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG]->GetGUID() != obj->GetGUID()))
return;
// check player team
if(_player->GetTeam() == HORDE)
@@ -715,7 +726,6 @@
void WorldSession::HandleCancelAutoRepeatSpellOpcode( WorldPacket& /*recvPacket*/)
{
- // may be better send SMSG_CANCEL_AUTO_REPEAT?
// cancel and prepare for deleting
_player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
}
Index: src/game/Unit.cpp
===================================================================
--- src/game/Unit.cpp (revision 5447)
+++ src/game/Unit.cpp (working copy)
@@ -212,6 +212,8 @@
m_charmInfo = NULL;
m_moveRun = false;
+ m_AutoRepeatFirstCast = true;
+
// remove aurastates allowing special moves
for(int i=0; i < MAX_REACTIVE; ++i)
m_reactiveTimer[i] = 0;
@@ -410,14 +412,16 @@
}
/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
-void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage)
+void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage, uint32 casterLevel)
{
if(!HasAuraType(auraType))
return;
// The chance to dispell an aura depends on the damage taken with respect to the casters level.
uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
- float chance = float(damage) / max_dmg * 100.0f;
+ float chanceDamage = float(damage) / max_dmg * 100.0f * 0.67f;
+ float chanceLevel = float(casterLevel) / getLevel() * 100 * 0.33f;
+ float chance = chanceDamage + chanceLevel;
if (roll_chance_f(chance))
RemoveSpellsCausingAura(auraType);
}
@@ -469,10 +473,10 @@
return;
}
- pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
+ pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage, getLevel());
// root type spells do not dispell the root effect
if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT)
- pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
+ pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage, getLevel());
if(pVictim->GetTypeId() != TYPEID_PLAYER)
{
@@ -570,36 +574,6 @@
if (health <= damage)
{
- // battleground things
- if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
- {
- Player *killed = ((Player*)pVictim);
- Player *killer = NULL;
- if(GetTypeId() == TYPEID_PLAYER)
- killer = ((Player*)this);
- else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
- {
- Unit *owner = GetOwner();
- if(owner && owner->GetTypeId() == TYPEID_PLAYER)
- killer = ((Player*)owner);
- }
-
- if(killer)
- {
- if(BattleGround *bg = killed->GetBattleGround())
- {
- bg->HandleKillPlayer(killed, killer); // drop flags and etc
- // add +1 deaths
- bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);
- if(killer)
- // add +1 kills
- bg->UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
- // to be able to remove insignia
- killed->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
- }
- }
- }
-
DEBUG_LOG("DealDamage: victim just died");
DEBUG_LOG("DealDamageAttackStop");
@@ -845,6 +819,39 @@
he->DuelComplete(DUEL_INTERUPTED);
}
+
+ // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
+ if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
+ {
+ Player *killed = ((Player*)pVictim);
+ Player *killer = NULL;
+ if(GetTypeId() == TYPEID_PLAYER)
+ killer = ((Player*)this);
+ else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
+ {
+ Unit *owner = GetOwner();
+ if(owner && owner->GetTypeId() == TYPEID_PLAYER)
+ killer = ((Player*)owner);
+ }
+
+ if(killer)
+ {
+ if(BattleGround *bg = killed->GetBattleGround())
+ {
+ bg->HandleKillPlayer(killed, killer); // drop flags and etc
+ // add +1 deaths
+ bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);
+ if(killer)
+ {
+ // add +1 kills
+ bg->UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
+ bg->UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
+ }
+ // to be able to remove insignia
+ killed->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
+ }
+ }
+ }
}
else // if (health <= damage)
{
@@ -3266,94 +3273,132 @@
void Unit::_UpdateAutoRepeatSpell()
{
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED)
- {
- //Auto Shot & Shoot
- if( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER )
- {
- // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
- {
- // Shoot
- resetAttackTimer( RANGED_ATTACK );
- }
- else
- {
- // Auto Shoot
- if (m_AutoRepeatFirstCast)
- {
- // first cast only with recovery time (not less)
- if (getAttackTimer( RANGED_ATTACK ) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime)
- setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
- m_AutoRepeatFirstCast = false;
- }
- else
- {
- // second or further casts
- resetAttackTimer( RANGED_ATTACK );
- }
- }
- }
- else
- {
- setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
- }
+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE )
+ {
+ //update the spell's pointers and check the target (not done in spell:update for autorepeat spells)
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->UpdatePointers();
+ if ( !(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTargetGUID() &&
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget() &&
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget()->isAlive()))
+ {
+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+ if(GetTypeId()==TYPEID_PLAYER)
+ ((Player*)this)->SendAttackSwingCancelAttack(); //force autoshot cancel
+
+ return;
+ }
+
+
+ //on First cast we need a prepare animation
+ if(m_AutoRepeatFirstCast) m_AutoRepeatSpellStart =true;
+
+ uint8 result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true);
+ // CanCast check
+ if (result)
+ {
+ // cancel wand shooting and send result
+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
+ {
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);
+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+ return;
+ }
+
+ //else...don't cancel "autoshot" and send result, if "cooldown" is over; except "moving"
+ if (isAttackReady(RANGED_ATTACK) && result!= SPELL_FAILED_MOVING)
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);
+
+ //if interruption is during the prepare animation we additionally need to stop animation
+ if (getAttackTimer(RANGED_ATTACK)<=500 && !m_AutoRepeatFirstCast)
+ {
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendInterrupted(0);
+ }
+ //now we need again our 0.5 sec....
+ m_AutoRepeatFirstCast = true;
+
+ }
+
+ //...we CanCast, now check if we are castig melee spell, or anything else
+ else if ( (m_currentSpells[CURRENT_MELEE_SPELL] &&
+ (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
+ (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)
+ ) ||
+ IsNonMeleeSpellCasted(false, false, true)
+ )
+ {
+ //...of course we need again time to aim ....
+ m_AutoRepeatFirstCast = true;
+ }
+
+ else //ok, nothing casting currently
+ {
+ //handling the 0.5s
+ if(m_AutoRepeatFirstCast == true && getAttackTimer(RANGED_ATTACK) < 500)
+ {
+ setAttackTimer(RANGED_ATTACK, 500);
+ }
+
+ m_AutoRepeatFirstCast = false;
+
+ // handle graphics, 0.5sec of preparing (blizz-like)
+ if( getAttackTimer(RANGED_ATTACK) <= 500 && m_AutoRepeatSpellStart)
+ {
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendSpellStart();
+ m_AutoRepeatSpellStart = false;
+ }
+
+ //now we got it, ...nearly :-)
+ else if(isAttackReady(RANGED_ATTACK) && result != SPELL_FAILED_NOT_READY )
+ {
+ // recheck CanCast() to avoid interruption problems in Spell::prepare
+ if(result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0 )
+ {
+ // start the spell
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
+ resetAttackTimer( RANGED_ATTACK );
+ }
+ else
+ { //the well known procedure...
+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
+ {
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);
+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+ }
+ else m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendInterrupted(0); //break prepare animation
+
+ m_AutoRepeatFirstCast = true;
+ }
+ }
+ }
+ }
+
+ else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_DELAYED)
+ {
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->UpdatePointers();
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
- }
- else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )
- {
- // check if we can cast
- if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0)
- {
- // check movement in player case
- if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving())
- {
- // cancel wand shooting
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- // ELSE delay auto-repeat ranged weapon until player movement stop
- }
- else
- // recheck range and req. items (ammo and gun, etc)
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange(true) == 0 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() == 0 )
- {
- // check, if we are casting melee spell (it blocks autorepeat)
- if ( ! (m_currentSpells[CURRENT_MELEE_SPELL] &&
- (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
- (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)) )
- {
- // check, if we are casting something else, if no then run autorepeat spell
- if (!IsNonMeleeSpellCasted(false, false, true))
- {
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_PREPARING);
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->ReSetTimer();
- }
- }
- }
- else
- {
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- }
- }
- else
- {
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- }
- }
- else if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_PREPARING)
- {
- // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
- if ( m_currentSpells[CURRENT_MELEE_SPELL] ||
- m_currentSpells[CURRENT_GENERIC_SPELL] ||
- m_currentSpells[CURRENT_CHANNELED_SPELL] ||
- !isAttackReady(RANGED_ATTACK) )
- {
- // some other spell is here or ranged attack is not ready, break us to idle state
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->finish(false);
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
- }
- }
+ //check if target is still ok
+ if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTargetGUID() &&
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget() &&
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget()->isAlive())
+ {
+ //store spell information
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id);
+
+ m_AutoRepeatFirstCast = true;
+ m_AutoRepeatSpellStart = true;
+
+ //create and intialize new spell with old target
+ Spell *p_spell = new Spell(this, spellInfo, false, 0);
+ p_spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
+ }
+ else //target not exist....?
+ {
+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+ if(GetTypeId()==TYPEID_PLAYER)
+ ((Player*)this)->SendAttackSwingCancelAttack(); //force autoshot cancel
+
+ }
+ }
}
void Unit::SetCurrentCastedSpell( Spell * pSpell )
@@ -3390,6 +3435,9 @@
// break autorepeat if not Auto Shot
if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+
+ //new casttime for autoshot
+ m_AutoRepeatFirstCast = true;
}
} break;
@@ -3413,12 +3461,7 @@
// generic autorepeats break generic and channeled spells
InterruptSpell(CURRENT_GENERIC_SPELL);
InterruptSpell(CURRENT_CHANNELED_SPELL);
- }
- else
- {
- // special action: set first cast flag for Auto Shoot
- m_AutoRepeatFirstCast = true;
- }
+ }
} break;
default:
@@ -3441,13 +3484,10 @@
if(m_currentSpells[spellType])
{
- // send autorepeat cancel message for autorepeat spells
- if (spellType == CURRENT_AUTOREPEAT_SPELL)
- {
- if(GetTypeId()==TYPEID_PLAYER)
- ((Player*)this)->SendAutoRepeatCancel();
- }
+ // set first cast for autorepeat spells
+ if (spellType == CURRENT_AUTOREPEAT_SPELL) m_AutoRepeatFirstCast = true;
+
if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
m_currentSpells[spellType]->cancel();
m_currentSpells[spellType]->SetDeletable(true);
@@ -3493,9 +3533,7 @@
// autorepeat spells are interrupted if they are not finished or delayed
if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
{
- // send disable autorepeat packet in any case
- if(GetTypeId()==TYPEID_PLAYER)
- ((Player*)this)->SendAutoRepeatCancel();
+ m_AutoRepeatFirstCast = true;
if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
(withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
@@ -4055,6 +4093,19 @@
}
}
+void Unit::RemoveArenaAuras(bool onleave)
+{
+ // in join, remove positive buffs, on end, remove negative
+ // used to remove positive visible auras in arenas
+ for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
+ {
+ if (!iter->second->IsPassive() && (iter->second->IsPositive() ^ onleave))
+ RemoveAura(iter, true);
+ else
+ ++iter;
+ }
+}
+
void Unit::RemoveAllAurasOnDeath()
{
// used just after dieing to remove all visible auras
Index: src/game/Unit.h
===================================================================
--- src/game/Unit.h (revision 5447)
+++ src/game/Unit.h (working copy)
@@ -755,7 +755,7 @@
bool isFrozen() const;
- void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage);
+ void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage, uint32 casterLevel);
bool isTargetableForAttack() const;
virtual bool IsInWater() const;
@@ -823,6 +823,7 @@
void RemoveAreaAurasByOthers(uint64 guid = 0);
void RemoveAllAuras();
+ void RemoveArenaAuras(bool onleave = false);
void RemoveAllAurasOnDeath();
void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime);
bool SetAurDuration(uint32 spellId, uint32 effindex, uint32 duration);
@@ -879,6 +880,7 @@
float m_threatModifier[MAX_SPELL_SCHOOL];
float m_modAttackSpeedPct[3];
+ bool m_AutoRepeatFirstCast;
// Event handler
EventProcessor m_Events;
@@ -1033,7 +1035,7 @@
void _UpdateSpells(uint32 time);
void _UpdateAutoRepeatSpell();
- bool m_AutoRepeatFirstCast;
+ bool m_AutoRepeatSpellStart;
uint32 m_attackTimer[MAX_ATTACK];
Index: src/game/World.cpp
===================================================================
--- src/game/World.cpp (revision 5447)
+++ src/game/World.cpp (working copy)
@@ -509,6 +509,10 @@
m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);
m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false);
+ m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);
+ m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);
+ m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
+
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
{
@@ -846,6 +850,7 @@
///- Initialize Battlegrounds
sLog.outString( "Starting BattleGround System" );
sBattleGroundMgr.CreateInitialBattleGrounds();
+ sBattleGroundMgr.InitAutomaticArenaPointDistribution();
//Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
sLog.outString( "Loading Transports..." );
Index: src/game/World.h
===================================================================
--- src/game/World.h (revision 5447)
+++ src/game/World.h (working copy)
@@ -120,6 +120,9 @@
CONFIG_TALENTS_INSPECTING,
CONFIG_CHAT_FAKE_MESSAGE_PREVENTING,
CONFIG_TCP_NO_DELAY,
+ CONFIG_ARENA_MAX_RATING_DIFFERENCE,
+ CONFIG_ARENA_RATING_DISCARD_TIMER,
+ CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,
CONFIG_VALUE_COUNT
};
Index: src/mangosd/Makefile.am
===================================================================
--- src/mangosd/Makefile.am (revision 5447)
+++ src/mangosd/Makefile.am (working copy)
@@ -33,8 +33,8 @@
WorldRunnable.h
## Link world daemon against the shared library
-mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
-mangos_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/universal/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
+mangos_worldd_LDADD = ../bindings/ScriptDev2/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
+mangos_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/ScriptDev2/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
## Additional files to include when running 'make dist'
# Include world daemon configuration
Index: src/mangosd/mangosd.conf.in
===================================================================
--- src/mangosd/mangosd.conf.in (revision 5447)
+++ src/mangosd/mangosd.conf.in (working copy)
@@ -556,7 +556,7 @@
# Visibility.Distance.Grey.Unit
# Visibility grey distance for creatures/players (fast changing objects)
# addition to appropriate object type Visibility.Distance.* use in case visibility removing to
-# object (except corpse around distences) If ‚ is distance and G is grey distance then object
+# object (except corpse around distences) If ?is distance and G is grey distance then object
# make visible if distance to it <= D but make non visible if distance > D+G
# Default: 1 (yard)
#
@@ -761,3 +761,16 @@
Ra.Port = 3443
Ra.MinLevel = 3
Ra.Secure = 1
+
+# Rated arena matches config
+# MaxRatingDifference: the maximum rating difference between two groups in rated matches
+# Default: 0 (disable, rating difference is discarded)
+# RatingDiscardTimer: after the specified milliseconds has passed, rating information will be discarded when selecting teams for matches
+# also initiates an update by this timer
+# Default: 60000
+# AutoDistributePoints: set if arena points should be distributed weekly automatically, or by GM command
+# Default: 0 (disable) (recommended): use gm command or sql query to distribute the points
+# 1 (enable): arena points are distributed automatically
+Arena.MaxRatingDifference = 0
+Arena.RatingDiscardTimer = 60000
+Arena.AutoDistributePoints = 0