[6910] Implemented rewritten arenas. Original author w12x@getmangos.com

Many thanks also to:
  Balrok@github.com for long time updating.
  Triply@github.com for great work in rewriting process.
  All who I forget to name.
Signed-off-by: ApoC <apoc@nymfe.net>
This commit is contained in:
ApoC 2008-12-15 23:52:46 +01:00
parent c51a6bc59e
commit a5331ab517
47 changed files with 3406 additions and 924 deletions

View file

@ -0,0 +1,6 @@
CREATE TABLE `saved_variables` (
`NextArenaPointDistributionTime` bigint(40) UNSIGNED NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Variable Saves';
ALTER TABLE `arena_team_member` ADD COLUMN `personal_rating` int(10) UNSIGNED NOT NULL DEFAULT '0';
ALTER TABLE `characters` ADD COLUMN `arena_pending_points` int(10) UNSIGNED NOT NULL default '0';

View file

@ -0,0 +1,26 @@
DELETE FROM `command` WHERE `name` = "flusharenapoints";
INSERT INTO `command` (`name`, `security`, `help`) VALUES
('flusharenapoints','3','Syntax: .flusharenapoints\r\n\r\nUse it to distribute arena points based on arena team ratings, and start a new week.');
DELETE FROM mangos_string WHERE entry BETWEEN 7007 AND 7023;
INSERT INTO mangos_string (entry, content_default) VALUES
(7007,'Your group is too large for this battleground. Please regroup to join.'),
(7008,'Your group is too large for this arena. Please regroup to join.'),
(7009,'Your group has members not in your arena team. Please regroup to join.'),
(7010,'Your group does not have enough players to join this match.'),
(7011,'The Gold Team wins!'),
(7012,'The Green Team wins!'),
(7013, 'There aren\'t enough players in this battleground. It will end soon unless some more players join to balance the fight.'),
(7014, 'Your group has an offline member. Please remove him before joining.'),
(7015, 'Your group has players from the opposing faction. You can\'t join the battleground as a group.'),
(7016, 'Your group has players from different battleground brakets. You can\'t join as group.'),
(7017, 'Someone in your party is already in this battleground queue. (S)he must leave it before joining as group.'),
(7018, 'Someone in your party is Deserter. You can\'t join as group.'),
(7019, 'Someone in your party is already in three battleground queues. You cannot join as group.'),
(7020, 'You cannot teleport to a battleground or arena map.'),
(7021, 'You cannot summon players to a battleground or arena map.'),
(7022, 'You must be in GM mode to teleport to a player in a battleground.'),
(7023, 'You cannot teleport to a battleground from another battleground. Please leave the current battleground first.');
DELETE FROM mangos_string WHERE entry = 714 OR entry = 716;

View file

@ -44,7 +44,7 @@ ArenaTeam::~ArenaTeam()
}
bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamName)
bool ArenaTeam::Create(uint64 captainGuid, uint32 type, std::string ArenaTeamName)
{
if(!objmgr.GetPlayer(captainGuid)) // player not exist
return false;
@ -67,9 +67,9 @@ bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamNam
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id);
CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) "
"VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')",
Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor);
Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor);
CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES "
"('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id,stats.rating,stats.games_week,stats.wins_week,stats.games_season,stats.wins_season,stats.rank);
"('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id, stats.rating, stats.games_week, stats.wins_week, stats.games_season, stats.wins_season, stats.rank);
CharacterDatabase.CommitTransaction();
@ -77,7 +77,7 @@ bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamNam
return true;
}
bool ArenaTeam::AddMember(uint64 PlayerGuid)
bool ArenaTeam::AddMember(const uint64& PlayerGuid)
{
std::string plName;
uint8 plClass;
@ -132,39 +132,23 @@ bool ArenaTeam::AddMember(uint64 PlayerGuid)
newmember.personal_rating = 1500;
members.push_back(newmember);
CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));
CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid, guid, personal_rating) VALUES ('%u', '%u', '%u')", Id, GUID_LOPART(newmember.guid), newmember.personal_rating );
if(pl)
{
pl->SetInArenaTeam(Id, GetSlot());
pl->SetArenaTeamIdInvited(0);
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, newmember.personal_rating );
// hide promote/remove buttons
if(CaptainGuid != PlayerGuid)
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
}
else
{
Tokens tokens;
if(Player::LoadValuesArrayFromDB(tokens,PlayerGuid))
{
Player::SetUInt32ValueInArray(tokens,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id);
// hide promote/remove buttons
if(CaptainGuid != PlayerGuid)
Player::SetUInt32ValueInArray(tokens,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
Player::SaveValuesArrayInDB(tokens,PlayerGuid);
}
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 1, 1);
}
return true;
}
bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
{
LoadStatsFromDB(ArenaTeamId);
LoadMembersFromDB(ArenaTeamId);
// 0 1 2 3 4 5 6 7 8
QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
if(!result)
@ -184,6 +168,22 @@ bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
delete result;
// only load here, so additional checks can be made
LoadStatsFromDB(ArenaTeamId);
LoadMembersFromDB(ArenaTeamId);
if(Empty())
{
// arena team is empty, delete from db
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
CharacterDatabase.CommitTransaction();
// return false
return false;
}
return true;
}
@ -209,49 +209,37 @@ void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId)
void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
{
Field *fields;
QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
// 0 1 2 3 4 5 6 7
QueryResult *result = CharacterDatabase.PQuery("SELECT member.guid,played_week,wons_week,played_season,wons_season,personal_rating,name,class "
"FROM arena_team_member member "
"INNER JOIN characters chars on member.guid = chars.guid "
"WHERE member.arenateamid = '%u'", ArenaTeamId);
if(!result)
return;
do
{
fields = result->Fetch();
Field *fields = result->Fetch();
ArenaTeamMember newmember;
newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
LoadPlayerStats(&newmember);
newmember.games_week = fields[1].GetUInt32();
newmember.wins_week = fields[2].GetUInt32();
newmember.games_season = fields[3].GetUInt32();
newmember.wins_season = fields[4].GetUInt32();
newmember.personal_rating = fields[5].GetUInt32();
newmember.name = fields[6].GetCppString();
newmember.Class = fields[7].GetUInt8();
members.push_back(newmember);
}while( result->NextRow() );
delete result;
}
void ArenaTeam::LoadPlayerStats(ArenaTeamMember *member)
{
Field *fields;
QueryResult *result = CharacterDatabase.PQuery("SELECT name,class FROM characters WHERE guid = '%u'", GUID_LOPART(member->guid));
if(!result)
return;
fields = result->Fetch();
member->name = fields[0].GetCppString();
member->Class = fields[1].GetUInt8();
delete result;
}
void ArenaTeam::SetCaptain(uint64 guid)
void ArenaTeam::SetCaptain(const uint64& guid)
{
// disable remove/promote buttons
Player *oldcaptain = objmgr.GetPlayer(GetCaptain());
if(oldcaptain)
oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
else
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, GetCaptain());
// set new captain
CaptainGuid = guid;
@ -263,14 +251,11 @@ void ArenaTeam::SetCaptain(uint64 guid)
Player *newcaptain = objmgr.GetPlayer(guid);
if(newcaptain)
newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0);
else
Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0, guid);
}
void ArenaTeam::DelMember(uint64 guid)
{
MemberList::iterator itr;
for (itr = members.begin(); itr != members.end(); itr++)
for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
{
if (itr->guid == guid)
{
@ -280,17 +265,19 @@ void ArenaTeam::DelMember(uint64 guid)
}
Player *player = objmgr.GetPlayer(guid);
if(player)
{
player->SetInArenaTeam(0, GetSlot());
player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
}
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->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);
}
}
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid));
}
void ArenaTeam::Disband(WorldSession *session)
@ -300,23 +287,15 @@ void ArenaTeam::Disband(WorldSession *session)
session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), "");
BroadcastPacket(&data);
uint32 count = members.size();
uint64 *memberGuids = new uint64[count];
MemberList::iterator itr;
uint32 i=0;
for(itr = members.begin(); itr != members.end(); itr++)
while (!members.empty())
{
memberGuids[i] = itr->guid;
++i;
// Removing from members is done in DelMember.
DelMember(members.front().guid);
}
for(uint32 j = 0; j < count; j++)
DelMember(memberGuids[j]);
delete[] memberGuids;
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id); //< this should be alredy done by calling DelMember(memberGuids[j]); for each member
CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
CharacterDatabase.CommitTransaction();
objmgr.RemoveArenaTeam(this);
@ -334,34 +313,18 @@ void ArenaTeam::Roster(WorldSession *session)
for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
{
pl = objmgr.GetPlayer(itr->guid);
if(pl)
{
data << uint64(pl->GetGUID()); // guid
data << uint8(1); // online flag
data << pl->GetName(); // member name
data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
data << uint8(pl->getLevel()); // unknown, probably level
data << uint8(pl->getClass()); // class
data << uint32(itr->games_week); // played this week
data << uint32(itr->wins_week); // wins this week
data << uint32(itr->games_season); // played this season
data << uint32(itr->wins_season); // wins this season
data << uint32(itr->personal_rating); // personal rating
}
else
{
data << uint64(itr->guid); // guid
data << uint8(0); // online flag
data << itr->name; // member name
data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
data << uint8(0); // unknown, level?
data << uint8(itr->Class); // class
data << uint32(itr->games_week); // played this week
data << uint32(itr->wins_week); // wins this week
data << uint32(itr->games_season); // played this season
data << uint32(itr->wins_season); // wins this season
data << uint32(itr->personal_rating); // personal rating
}
data << uint64(itr->guid); // guid
data << uint8((pl ? 1 : 0)); // online flag
data << itr->name; // member name
data << uint32((itr->guid == GetCaptain() ? 0 : 1));// captain flag 0 captain 1 member
data << uint8((pl ? pl->getLevel() : 0)); // unknown, level?
data << uint8(itr->Class); // class
data << uint32(itr->games_week); // played this week
data << uint32(itr->wins_week); // wins this week
data << uint32(itr->games_season); // played this season
data << uint32(itr->wins_season); // wins this season
data << uint32(itr->personal_rating); // personal rating
}
session->SendPacket(&data);
sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
@ -395,6 +358,18 @@ void ArenaTeam::Stats(WorldSession *session)
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)
{
ArenaTeamMember* member = GetMember(guid);
@ -408,8 +383,8 @@ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
data << uint32(stats.rating); // rating
data << uint32(stats.games_season); // season played
data << uint32(stats.wins_season); // season wins
data << member->games_season; // played (count of all games, that the inspected member participated...)
data << member->personal_rating; // personal rating
data << uint32(member->games_season); // played (count of all games, that the inspected member participated...)
data << uint32(member->personal_rating); // personal rating
session->SendPacket(&data);
}
@ -458,18 +433,6 @@ void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
}
}
uint8 ArenaTeam::GetSlot() const
{
uint8 slot = GetSlotByType(GetType());
if(slot >= MAX_ARENA_SLOT)
{
sLog.outError("Unknown arena team type %u for arena team %u", uint32(GetType()), GetId());
return 0; // better return existed slot to prevent untelated data curruption
}
return slot;
}
void ArenaTeam::BroadcastPacket(WorldPacket *packet)
{
for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
@ -490,18 +453,184 @@ uint8 ArenaTeam::GetSlotByType( uint32 type )
default:
break;
}
sLog.outError("FATAL: Unknown arena team type %u for some arena team", type);
return 0xFF;
}
bool ArenaTeam::HaveMember( uint64 guid ) const
bool ArenaTeam::HaveMember( const uint64& guid ) const
{
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
if(itr->guid==guid)
if(itr->guid == guid)
return true;
return false;
}
uint32 ArenaTeam::GetPoints(uint32 MemberRating)
{
// returns how many points would be awarded with this team type with this rating
float points;
uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
if(rating<=1500)
points = (float)rating * 0.22f + 14.0f;
else
points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)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 own_rating, uint32 enemy_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)enemy_rating - (float)own_rating)/400.0f));
}
int32 ArenaTeam::WonAgainst(uint32 againstRating)
{
// called when the team has won
//'chance' calculation - to beat the opponent
float chance = GetChanceAgainst(stats.rating,againstRating);
// calculate the rating modification (ELO system with k=32)
int32 mod = (int32)floor(32.0f * (1.0f - chance));
// modify the team stats accordingly
stats.rating += mod;
stats.games_week += 1;
stats.wins_week += 1;
stats.games_season += 1;
stats.wins_season += 1;
//update team's rank
stats.rank = 1;
ObjectMgr::ArenaTeamMap::iterator i = objmgr.GetArenaTeamMapBegin();
for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
{
if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating)
++stats.rank;
}
// return the rating change, used to display it on the results screen
return mod;
}
int32 ArenaTeam::LostAgainst(uint32 againstRating)
{
// called when the team has lost
//'chance' calculation - to loose to the opponent
float chance = GetChanceAgainst(stats.rating,againstRating);
// calculate the rating modification (ELO system with k=32)
int32 mod = (int32)ceil(32.0f * (0.0f - chance));
// modify the team stats accordingly
stats.rating += mod;
stats.games_week += 1;
stats.games_season += 1;
//update team's rank
stats.rank = 1;
ObjectMgr::ArenaTeamMap::iterator i = objmgr.GetArenaTeamMapBegin();
for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
{
if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating)
++stats.rank;
}
// return the rating change, used to display it on the results screen
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
float chance = GetChanceAgainst(itr->personal_rating, againstRating);
int32 mod = (int32)ceil(32.0f * (0.0f - chance));
itr->ModifyPersonalRating(plr, mod, GetSlot());
// update personal played stats
itr->games_week +=1;
itr->games_season +=1;
// update the unit fields
plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->games_week);
plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->games_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
float chance = GetChanceAgainst(itr->personal_rating, againstRating);
int32 mod = (int32)floor(32.0f * (1.0f - chance));
itr->ModifyPersonalRating(plr, mod, GetSlot());
// update personal stats
itr->games_week +=1;
itr->games_season +=1;
itr->wins_season += 1;
itr->wins_week += 1;
// update unit fields
plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->games_week);
plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->games_season);
return;
}
}
}
void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& PlayerPoints)
{
// 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_week < 10)
return;
// to get points, a player has to participate in at least 30% of the matches
uint32 min_plays = (uint32) ceil(stats.games_week * 0.3);
for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
{
// the player participated in enough games, update his points
uint32 points_to_add = 0;
if (itr->games_week >= min_plays)
points_to_add = GetPoints(itr->personal_rating);
// OBSOLETE : CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.find(GUID_LOPART(itr->guid));
if (plr_itr != PlayerPoints.end())
{
//check if there is already more points
if (plr_itr->second < points_to_add)
PlayerPoints[GUID_LOPART(itr->guid)] = points_to_add;
}
else
PlayerPoints[GUID_LOPART(itr->guid)] = points_to_add;
}
}
void ArenaTeam::SaveToDB()
{
// save team and member stats to db
// called after a match has ended, or when calculating arena_points
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_week, stats.games_season, stats.rank, stats.wins_week, stats.wins_season, 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', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, Id, itr->guid);
}
}
void ArenaTeam::FinishWeek()
{
stats.games_week = 0; // played this week
@ -519,18 +648,18 @@ arenateam fields (id from 2.3.3 client):
1415 - 0=captain, 1=member
1416 - played this week
1417 - played this season
1418 - unk
1418 - unk - rank?
1419 - personal arena rating
1420 - arena team id 3v3
1421 - 0=captain, 1=member
1422 - played this week
1423 - played this season
1424 - unk
1424 - unk - rank?
1425 - personal arena rating
1426 - arena team id 5v5
1427 - 0=captain, 1=member
1428 - played this week
1429 - played this season
1430 - unk
1430 - unk - rank?
1431 - personal arena rating
*/

View file

@ -43,7 +43,9 @@ enum ArenaTeamCommandErrors
ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM = 0x09,
ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS = 0x0A,
ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S = 0x0B,
ERR_ARENA_TEAM_NOT_ALLIED = 0x0C
ERR_ARENA_TEAM_NOT_ALLIED = 0x0C,
ERR_ARENA_TEAM_PLAYER_TO_LOW = 0x15,
ERR_ARENA_TEAM_FULL = 0x16
};
enum ArenaTeamEvents
@ -85,14 +87,22 @@ struct ArenaTeamMember
{
uint64 guid;
std::string name;
//uint32 unk2;
//uint8 unk1;
uint8 Class;
uint32 games_week;
uint32 wins_week;
uint32 games_season;
uint32 wins_season;
uint32 personal_rating;
void ModifyPersonalRating(Player* plr, int32 mod, uint32 slot)
{
if (personal_rating + mod < 0)
personal_rating = 0;
else
personal_rating += mod;
if(plr)
plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot*6) + 5, personal_rating);
}
};
struct ArenaTeamStats
@ -113,58 +123,78 @@ class ArenaTeam
ArenaTeam();
~ArenaTeam();
bool create(uint64 CaptainGuid, uint32 type, std::string ArenaTeamName);
bool Create(uint64 CaptainGuid, uint32 type, std::string ArenaTeamName);
void Disband(WorldSession *session);
typedef std::list<ArenaTeamMember> MemberList;
uint32 GetId() const { return Id; }
uint32 GetType() const { return Type; }
uint8 GetSlot() const;
uint32 GetId() const { return Id; }
uint32 GetType() const { return Type; }
uint8 GetSlot() const { return GetSlotByType(GetType()); }
static uint8 GetSlotByType(uint32 type);
const uint64& GetCaptain() const { return CaptainGuid; }
std::string GetName() const { return Name; }
const uint64& GetCaptain() const { return CaptainGuid; }
std::string GetName() const { return Name; }
const ArenaTeamStats& GetStats() const { return stats; }
void SetStats(uint32 stat_type, uint32 value);
uint32 GetRating() const { return stats.rating; }
uint32 GetRating() const { return stats.rating; }
uint32 GetEmblemStyle() const { return EmblemStyle; }
uint32 GetEmblemColor() const { return EmblemColor; }
uint32 GetBorderStyle() const { return BorderStyle; }
uint32 GetBorderColor() const { return BorderColor; }
uint32 GetEmblemStyle() const { return EmblemStyle; }
uint32 GetEmblemColor() const { return EmblemColor; }
uint32 GetBorderStyle() const { return BorderStyle; }
uint32 GetBorderColor() const { return BorderColor; }
uint32 GetBackgroundColor() const { return BackgroundColor; }
void SetCaptain(uint64 guid);
bool AddMember(uint64 PlayerGuid);
void SetCaptain(const uint64& guid);
bool AddMember(const uint64& PlayerGuid);
// Shouldn't be const uint64& ed, because than can reference guid from members on Disband
// and this method removes given record from list. So invalid reference can happen.
void DelMember(uint64 guid);
void SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor);
uint32 GetMembersSize() const { return members.size(); }
MemberList::iterator membersbegin(){ return members.begin(); }
MemberList::iterator membersEnd(){ return members.end(); }
bool HaveMember(uint64 guid) const;
ArenaTeamMember* GetMember(uint64 guid)
size_t GetMembersSize() const { return members.size(); }
bool Empty() const { return members.empty(); }
MemberList::iterator membersBegin() { return members.begin(); }
MemberList::iterator membersEnd() { return members.end(); }
bool HaveMember(const uint64& guid) const;
ArenaTeamMember* GetMember(const uint64& guid)
{
for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
if(itr->guid==guid)
if(itr->guid == guid)
return &(*itr);
return NULL;
}
ArenaTeamMember* GetMember(std::string& name)
ArenaTeamMember* GetMember(const std::string& name)
{
for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
if(itr->name==name)
if(itr->name == name)
return &(*itr);
return NULL;
}
bool IsFighting() const
{
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
if (Player *p = objmgr.GetPlayer(itr->guid))
{
if (p->GetMap()->IsBattleArena())
return true;
}
}
return false;
}
bool LoadArenaTeamFromDB(uint32 ArenaTeamId);
void LoadMembersFromDB(uint32 ArenaTeamId);
void LoadStatsFromDB(uint32 ArenaTeamId);
void LoadPlayerStats(ArenaTeamMember* member);
void SaveToDB();
void BroadcastPacket(WorldPacket *packet);
@ -173,6 +203,17 @@ class ArenaTeam
void Stats(WorldSession *session);
void InspectStats(WorldSession *session, uint64 guid);
uint32 GetPoints(uint32 MemberRating);
float GetChanceAgainst(uint32 own_rating, uint32 enemy_rating);
int32 WonAgainst(uint32 againstRating);
void MemberWon(Player * plr, uint32 againstRating);
int32 LostAgainst(uint32 againstRating);
void MemberLost(Player * plr, uint32 againstRating);
void UpdateArenaPointsHelper(std::map<uint32, uint32> & PlayerPoints);
void NotifyStatsChanged();
void FinishWeek();
protected:

View file

@ -30,7 +30,6 @@
void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
{
sLog.outDebug("MSG_INSPECT_ARENA_TEAMS");
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 8);
@ -54,7 +53,6 @@ void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data)
{
sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_QUERY" );
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4);
@ -72,7 +70,6 @@ void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data)
void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data)
{
sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_ROSTER" );
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4);
@ -89,7 +86,6 @@ void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data)
void WorldSession::HandleArenaTeamAddMemberOpcode(WorldPacket & recv_data)
{
sLog.outDebug("CMSG_ARENA_TEAM_ADD_MEMBER");
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4+1);
@ -110,15 +106,13 @@ void WorldSession::HandleArenaTeamAddMemberOpcode(WorldPacket & recv_data)
if(!player)
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
return;
}
if(player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
{
//SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S);
// can't find related opcode
SendNotification(LANG_HIS_ARENA_LEVEL_REQ_ERROR, player->GetName());
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", player->GetName(), ERR_ARENA_TEAM_PLAYER_TO_LOW);
return;
}
@ -141,21 +135,19 @@ void WorldSession::HandleArenaTeamAddMemberOpcode(WorldPacket & recv_data)
if(player->GetArenaTeamId(arenateam->GetSlot()))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S);
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S);
return;
}
if(player->GetArenaTeamIdInvited())
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
return;
}
if(arenateam->GetMembersSize() >= arenateam->GetType() * 2)
{
// should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL
// SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL);
SendNotification(LANG_YOUR_ARENA_TEAM_FULL, player->GetName());
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,arenateam->GetName(),"",ERR_ARENA_TEAM_FULL);
return;
}
@ -177,23 +169,25 @@ void WorldSession::HandleArenaTeamInviteAcceptOpcode(WorldPacket & /*recv_data*/
ArenaTeam *at = objmgr.GetArenaTeamById(_player->GetArenaTeamIdInvited());
if(!at)
return;
if(_player->GetArenaTeamIdFromDB(_player->GetGUIDLow(), at->GetType()))
{
// arena team not exist
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,"","",ERR_ALREADY_IN_ARENA_TEAM); // already in arena team that size
return;
}
if(_player->GetArenaTeamId(at->GetSlot()))
{
// already in arena team that size
return;
}
// not let enemies sign petition
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != objmgr.GetPlayerTeamByGUID(at->GetCaptain()))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,"","",ERR_ARENA_TEAM_NOT_ALLIED);// not let enemies sign petition
return;
}
if(!at->AddMember(_player->GetGUID()))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,"","",ERR_ARENA_TEAM_INTERNAL);// arena team not found
return;
}
// event
WorldPacket data;
@ -211,7 +205,6 @@ void WorldSession::HandleArenaTeamInviteDeclineOpcode(WorldPacket & /*recv_data*
void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data)
{
sLog.outDebug("CMSG_ARENA_TEAM_LEAVE");
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4);
@ -220,10 +213,7 @@ void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data)
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
if(!at)
{
// send command result
return;
}
if(_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1)
{
// check for correctness
@ -245,13 +235,13 @@ void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data)
BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEAVE_SS, 2, _player->GetName(), at->GetName(), "");
at->BroadcastPacket(&data);
//SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0);
//send you are no longer member of team
SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0);
}
void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data)
{
sLog.outDebug("CMSG_ARENA_TEAM_DISBAND");
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4);
@ -260,16 +250,13 @@ void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data)
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
if(!at)
{
// arena team not found
return;
}
if(at->GetCaptain() != _player->GetGUID())
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
return;
}
if (at->IsFighting())
return;
at->Disband(this);
delete at;
@ -278,7 +265,6 @@ void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data)
void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
{
sLog.outDebug("CMSG_ARENA_TEAM_REMOVE_FROM_TEAM");
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4+1);
@ -303,11 +289,14 @@ void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
ArenaTeamMember* member = at->GetMember(name);
if(!member) // member not found
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
return;
}
if(at->GetCaptain() == member->guid)
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
return;
}
@ -322,7 +311,6 @@ void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data)
{
sLog.outDebug("CMSG_ARENA_TEAM_PROMOTE_TO_CAPTAIN");
//recv_data.hexlike();
CHECK_PACKET_SIZE(recv_data, 4+1);
@ -347,7 +335,10 @@ void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data
ArenaTeamMember* member = at->GetMember(name);
if(!member) // member not found
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
return;
}
if(at->GetCaptain() == member->guid) // target player already captain
return;
@ -360,13 +351,13 @@ void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data
at->BroadcastPacket(&data);
}
void WorldSession::SendArenaTeamCommandResult(uint32 unk1, const std::string& str1, const std::string& str2, uint32 unk3)
void WorldSession::SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id)
{
WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+str1.length()+1+str2.length()+1+4);
data << unk1;
data << str1;
data << str2;
data << unk3;
WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+team.length()+1+player.length()+1+4);
data << team_action;
data << team;
data << player;
data << error_id;
SendPacket(&data);
}

View file

@ -24,6 +24,7 @@
#include "Language.h"
#include "Chat.h"
#include "SpellAuras.h"
#include "ArenaTeam.h"
#include "World.h"
#include "Util.h"
@ -47,6 +48,8 @@ BattleGround::BattleGround()
m_Name = "";
m_LevelMin = 0;
m_LevelMax = 0;
m_InBGFreeSlotQueue = false;
m_SetDeleteThis = false;
m_MaxPlayersPerTeam = 0;
m_MaxPlayers = 0;
@ -67,21 +70,54 @@ BattleGround::BattleGround()
m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0;
m_TeamStartLocO[BG_TEAM_HORDE] = 0;
m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;
m_ArenaTeamIds[BG_TEAM_HORDE] = 0;
m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;
m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;
m_BgRaids[BG_TEAM_ALLIANCE] = NULL;
m_BgRaids[BG_TEAM_HORDE] = NULL;
m_PlayersCount[BG_TEAM_ALLIANCE] = 0;
m_PlayersCount[BG_TEAM_HORDE] = 0;
m_PrematureCountDown = false;
m_PrematureCountDown = 0;
}
BattleGround::~BattleGround()
{
// remove objects and creatures
// (this is done automatically in mapmanager update, when the instance is reset after the reset time)
int size = m_BgCreatures.size();
for(int i = 0; i < size; ++i)
{
DelCreature(i);
}
size = m_BgObjects.size();
for(int i = 0; i < size; ++i)
{
DelObject(i);
}
// delete creature and go respawn times
WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
// delete instance from db
CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
// remove from battlegrounds
sBattleGroundMgr.RemoveBattleGround(GetInstanceID());
// unload map
if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
if(map->IsBattleGroundOrArena())
((BattleGroundMap*)map)->SetUnload();
// remove from bg free slot queue
this->RemoveFromBGFreeSlotQueue();
}
void BattleGround::Update(time_t diff)
{
if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
//BG is empty
return;
@ -188,6 +224,33 @@ void BattleGround::Update(time_t diff)
m_ResurrectQueue.clear();
}
// if less then minimum players are in on one side, then start premature finish timer
if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
{
if(!m_PrematureCountDown)
{
m_PrematureCountDown = true;
m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
}
else if(m_PrematureCountDownTimer < diff)
{
// time's up!
EndBattleGround(0); // noone wins
m_PrematureCountDown = false;
}
else
{
uint32 newtime = m_PrematureCountDownTimer - diff;
// announce every minute
if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
m_PrematureCountDownTimer = newtime;
}
}
else if (m_PrematureCountDown)
m_PrematureCountDown = false;
if(GetStatus() == STATUS_WAIT_LEAVE)
{
// remove all players from battleground after 2 minutes
@ -239,7 +302,10 @@ void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *
if(!self && sender == plr)
continue;
if(plr->GetTeam() == TeamID)
uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
if(!team) team = plr->GetTeam();
if(team == TeamID)
plr->GetSession()->SendPacket(packet);
}
}
@ -265,7 +331,10 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
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);
@ -285,7 +354,10 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
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);
}
}
@ -302,7 +374,10 @@ void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
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);
}
}
@ -324,7 +399,10 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation,
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);
}
}
@ -345,30 +423,84 @@ void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player
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
SetWinner(WINNER_ALLIANCE);
}
else
else if(winner == HORDE)
{
winmsg = GetMangosString(LANG_BG_H_WINS);
if(isBattleGround())
winmsg = GetMangosString(LANG_BG_H_WINS);
else
winmsg = GetMangosString(LANG_ARENA_GREEN_WINS);
PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
SetWinner(WINNER_HORDE);
}
else
{
SetWinner(3);
}
SetStatus(STATUS_WAIT_LEAVE);
m_EndTime = 0;
// arena rating calculation
if(isArena() && isRated())
{
if(winner == ALLIANCE)
{
winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
}
else if(winner == HORDE)
{
winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
}
if(winner_arena_team && loser_arena_team)
{
loser_rating = loser_arena_team->GetStats().rating;
winner_rating = winner_arena_team->GetStats().rating;
int32 winner_change = winner_arena_team->WonAgainst(loser_rating);
int32 loser_change = loser_arena_team->LostAgainst(winner_rating);
sLog.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating, loser_rating, winner_change, loser_change);
if(winner == ALLIANCE)
{
SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
}
else
{
SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
}
}
else
{
SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
SetArenaTeamRatingChangeForTeam(HORDE, 0);
}
}
for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
@ -378,13 +510,29 @@ void BattleGround::EndBattleGround(uint32 winner)
continue;
}
// should remove spirit of redemption
if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
if(!plr->isAlive())
{
plr->ResurrectPlayer(1.0f);
plr->SpawnCorpseBones();
}
if(plr->GetTeam() == winner)
uint32 team = itr->second.Team;
if(!team) team = plr->GetTeam();
// per player calculation
if(isArena() && isRated() && winner_arena_team && loser_arena_team)
{
if(team == winner)
winner_arena_team->MemberWon(plr,loser_rating);
else
loser_arena_team->MemberLost(plr,winner_rating);
}
if(team == winner)
{
if(!Source)
Source = plr;
@ -404,10 +552,28 @@ void BattleGround::EndBattleGround(uint32 winner)
sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
plr->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
plr->GetSession()->SendPacket(&data);
}
if(isArena() && isRated() && winner_arena_team && loser_arena_team)
{
// update arena points only after increasing the player's match count!
//obsolete: winner_arena_team->UpdateArenaPointsHelper();
//obsolete: loser_arena_team->UpdateArenaPointsHelper();
// save the stat changes
winner_arena_team->SaveToDB();
loser_arena_team->SaveToDB();
// send updated arena team stats to players
// this way all arena team members will get notified, not only the ones who participated in this match
winner_arena_team->NotifyStatsChanged();
loser_arena_team->NotifyStatsChanged();
}
// inform invited players about the removal
sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
if(Source)
{
ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
@ -558,12 +724,16 @@ void BattleGround::BlockMovement(Player *plr)
void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
{
uint32 team = GetPlayerTeam(guid);
bool participant = false;
// Remove from lists/maps
std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
if(itr != m_Players.end())
{
UpdatePlayersCountByTeam(itr->second.Team, true); // -1 player
UpdatePlayersCountByTeam(team, true); // -1 player
m_Players.erase(itr);
// check if the player was a participant of the match, or only entered through gm command (goname)
participant = true;
}
std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
@ -577,6 +747,10 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
Player *plr = objmgr.GetPlayer(guid);
// should remove spirit of redemption
if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
if(plr && !plr->isAlive()) // resurrect on exit
{
plr->ResurrectPlayer(1.0f);
@ -589,66 +763,106 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
{
plr->ClearAfkReports();
if(isArena())
if(participant) // if the player was a match participant, remove auras, calc rating, update queue
{
if(!sWorld.IsFFAPvPRealm())
plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
}
if(!team) team = plr->GetTeam();
WorldPacket data;
if(SendPacket)
{
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
plr->GetSession()->SendPacket(&data);
}
// 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);
DecreaseInvitedCount(plr->GetTeam());
//we should update battleground queue, but only if bg isn't ending
if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType());
if(!plr->GetBattleGroundId())
return;
Group * group = plr->GetGroup();
// remove from raid group if exist
if(group && group == GetBgRaid(plr->GetTeam()))
{
if(!group->RemoveMember(guid, 0)) // group was disbanded
uint32 bgTypeId = GetTypeID();
uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
// if arena, remove the specific arena auras
if(isArena())
{
SetBgRaid(plr->GetTeam(), NULL);
delete group;
plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
// summon old pet if there was one and there isn't a current pet
if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
{
Pet* NewPet = new Pet;
if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
delete NewPet;
(plr)->SetTemporaryUnsummonedPetNumber(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, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
plr->GetSession()->SendPacket(&data);
}
// this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
plr->RemoveBattleGroundQueueId(bgQueueTypeId);
DecreaseInvitedCount(team);
//we should update battleground queue, but only if bg isn't ending
if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
Group * group = plr->GetGroup();
// remove from raid group if exist
if(group && group == GetBgRaid(team))
{
if(!group->RemoveMember(guid, 0)) // group was disbanded
{
SetBgRaid(team, NULL);
delete group;
}
}
// Let others know
sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
SendPacketToTeam(team, &data, plr, false);
}
// Do next only if found in battleground
plr->SetBattleGroundId(0); // We're not in BG.
// Let others know
sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
SendPacketToTeam(plr->GetTeam(), &data, plr, false);
// reset destination bg team
plr->SetBGTeam(0);
if(Transport)
{
plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
//sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);
}
// Log
sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
}
/// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist
// we always should check if BG is in that queue before adding..
if(!GetPlayersSize())
if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
{
Reset();
// if no players left AND no invitees left, set this bg to delete in next update
// direct deletion could cause crashes
m_SetDeleteThis = true;
// return to prevent addition to freeslotqueue
return;
}
// a player exited the battleground, so there are free slots. add to queue
this->AddToBGFreeSlotQueue();
}
// this method is called when no players remains in battleground
@ -660,6 +874,8 @@ void BattleGround::Reset()
SetStartTime(0);
SetEndTime(0);
SetLastResurrectTime(0);
SetArenaType(0);
SetRated(false);
m_Events = 0;
@ -668,6 +884,7 @@ void BattleGround::Reset()
m_InvitedAlliance = 0;
m_InvitedHorde = 0;
m_InBGFreeSlotQueue = false;
m_Players.clear();
m_PlayerScores.clear();
@ -704,10 +921,11 @@ void BattleGround::AddPlayer(Player *plr)
sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
SendPacketToTeam(team, &data, plr, false);
// add arena specific auras
if(isArena())
{
plr->RemoveArenaSpellCooldowns();
//plr->RemoveArenaAuras();
plr->RemoveArenaAuras();
plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
if(team == ALLIANCE) // gold
{
@ -726,6 +944,19 @@ void BattleGround::AddPlayer(Player *plr)
plr->DestroyConjuredItems(true);
Pet* pet = plr->GetPet();
if(pet)
{
if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
{
(plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
(plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
}
(plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
}
else
(plr)->SetTemporaryUnsummonedPetNumber(0);
if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
{
plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
@ -740,9 +971,6 @@ void BattleGround::AddPlayer(Player *plr)
plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells.
}
if(isArena())
plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
// Log
sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
}
@ -750,13 +978,20 @@ void BattleGround::AddPlayer(Player *plr)
/* This method should be called only once ... it adds pointer to queue */
void BattleGround::AddToBGFreeSlotQueue()
{
sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
// make sure to add only once
if(!m_InBGFreeSlotQueue)
{
sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
m_InBGFreeSlotQueue = true;
}
}
/* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
void BattleGround::RemoveFromBGFreeSlotQueue()
{
/* uncomment this code when battlegrounds will work like instances
// set to be able to re-add if needed
m_InBGFreeSlotQueue = false;
// uncomment this code when battlegrounds will work like instances
for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
{
if ((*itr)->GetInstanceID() == m_InstanceID)
@ -764,30 +999,69 @@ void BattleGround::RemoveFromBGFreeSlotQueue()
sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
return;
}
}*/
}
}
/*
this method should decide, if we can invite new player of certain team to BG, it is based on BATTLEGROUND_STATUS
*/
bool BattleGround::HasFreeSlotsForTeam(uint32 Team) const
// get the number of free slots for team
// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
{
//if BG is starting ... invite anyone:
//if BG is starting ... invite anyone
if (GetStatus() == STATUS_WAIT_JOIN)
return GetInvitedCount(Team) < GetMaxPlayersPerTeam();
return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
//if BG is already started .. do not allow to join too much players of one faction
uint32 otherTeam;
uint32 otherIn;
if (Team == ALLIANCE)
{
otherTeam = GetInvitedCount(HORDE);
otherIn = GetPlayersCountByTeam(HORDE);
}
else
{
otherTeam = GetInvitedCount(ALLIANCE);
otherIn = GetPlayersCountByTeam(ALLIANCE);
}
if (GetStatus() == STATUS_IN_PROGRESS)
return (GetInvitedCount(Team) <= otherTeam && GetInvitedCount(Team) < GetMaxPlayersPerTeam());
{
// difference based on ppl invited (not necessarily entered battle)
// default: allow 0
uint32 diff = 0;
// allow join one person if the sides are equal (to fill up bg to minplayersperteam)
if (otherTeam == GetInvitedCount(Team))
diff = 1;
// allow join more ppl if the other side has more players
else if(otherTeam > GetInvitedCount(Team))
diff = otherTeam - GetInvitedCount(Team);
return false;
// difference based on max players per team (don't allow inviting more)
uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
// difference based on players who already entered
// default: allow 0
uint32 diff3 = 0;
// allow join one person if the sides are equal (to fill up bg minplayersperteam)
if (otherIn == GetPlayersCountByTeam(Team))
diff3 = 1;
// allow join more ppl if the other side has more players
else if (otherIn > GetPlayersCountByTeam(Team))
diff3 = otherIn - GetPlayersCountByTeam(Team);
// or other side has less than minPlayersPerTeam
else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam())
diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1;
// return the minimum of the 3 differences
// min of diff and diff 2
diff = diff < diff2 ? diff : diff2;
// min of diff, diff2 and diff3
return diff < diff3 ? diff : diff3 ;
}
return 0;
}
/* this method isn't called already, it will be useful when more battlegrounds of one type will be available */
bool BattleGround::HasFreeSlots() const
{
return GetPlayersSize() < GetMaxPlayers();
@ -813,9 +1087,13 @@ void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
itr->second->HonorableKills += value;
break;
case SCORE_BONUS_HONOR: // Honor bonus
// reward honor instantly
if(Source->RewardHonor(NULL, 1, value))
itr->second->BonusHonor += value;
// do not add honor in arenas
if(isBattleGround())
{
// reward honor instantly
if(Source->RewardHonor(NULL, 1, value))
itr->second->BonusHonor += value;
}
break;
//used only in EY, but in MSG_PVP_LOG_DATA opcode
case SCORE_DAMAGE_DONE: // Damage Done
@ -871,15 +1149,26 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
{
GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
if(!goinfo)
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
if(!map)
return false;
// must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// so we must create it specific for this instance
GameObject * go = new GameObject;
if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
{
sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
delete go;
return false;
}
/*
uint32 guid = go->GetGUIDLow();
uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
// without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
// iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
GameObjectData& data = objmgr.NewGOData(guid);
data.id = entry;
@ -893,13 +1182,13 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float
data.rotation2 = rotation2;
data.rotation3 = rotation3;
data.spawntimesecs = respawnTime;
data.spawnMask = 1;
data.animprogress = 100;
data.go_state = 1;
data.spawnMask = 1;
objmgr.AddGameobjectToGrid(guid, &data);
m_BgObjects[type] = MAKE_NEW_GUID(guid, entry, HIGHGUID_GAMEOBJECT);
*/
// add to world, so it can be later looked up from HashMapHolder
go->AddToWorld();
m_BgObjects[type] = go->GetGUID();
return true;
}
@ -941,6 +1230,9 @@ void BattleGround::DoorOpen(uint32 type)
void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
if(!map)
return;
if( respawntime == 0 )
{
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
@ -949,30 +1241,27 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
//we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
if( obj->getLootState() == GO_JUST_DEACTIVATED )
obj->SetLootState(GO_READY);
obj->Respawn();
obj->SetRespawnTime(0);
map->Add(obj);
}
else
objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0);
}
else
{
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
if(obj)
{
map->Add(obj);
obj->SetRespawnTime(respawntime);
obj->SetLootState(GO_JUST_DEACTIVATED);
}
else
objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, time(NULL) + respawntime);
}
}
Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o)
Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
{
// note: this should normally be FindMap
// but it's a hack to allow the battlegrounds to initialize at server startup
Map * map = MapManager::Instance().GetMap(GetMapId(), 0);
if(!map) return NULL;
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
if(!map)
return NULL;
Creature* pCreature = new Creature;
if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
@ -996,9 +1285,39 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f
map->Add(pCreature);
m_BgCreatures[type] = pCreature->GetGUID();
return pCreature;
}
/*
void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
if(!map)
return false;
if(respawntime == 0)
{
Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
if(obj)
{
//obj->Respawn(); // bugged
obj->SetRespawnTime(0);
objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
map->Add(obj);
}
}
else
{
Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
if(obj)
{
obj->setDeathState(DEAD);
obj->SetRespawnTime(respawntime);
map->Add(obj);
}
}
}
*/
bool BattleGround::DelCreature(uint32 type)
{
Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
@ -1079,8 +1398,11 @@ void BattleGround::SendMessageToAll(int32 entry)
void BattleGround::EndNow()
{
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
SetEndTime(TIME_TO_AUTOREMOVE);
// inform invited players about the removal
sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
}
// Battleground messages are localized using the dbc lang, they are not client language dependent
@ -1158,3 +1480,28 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer )
// to be able to remove insignia
player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
}
// return the player's team based on battlegroundplayer info
// used in same faction arena matches mainly
uint32 BattleGround::GetPlayerTeam(uint64 guid)
{
std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
if(itr!=m_Players.end())
return itr->second.Team;
return 0;
}
uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
{
int count = 0;
for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if(itr->second.Team == Team)
{
Player * pl = objmgr.GetPlayer(itr->first);
if(pl && pl->isAlive())
++count;
}
}
return count;
}

View file

@ -18,6 +18,7 @@
#ifndef __BATTLEGROUND_H
#define __BATTLEGROUND_H
#define ARENA_PATCH
#include "Common.h"
#include "WorldPacket.h"
@ -83,7 +84,7 @@ enum BattleGroundTimeIntervals
{
RESURRECTION_INTERVAL = 30000, // ms
REMIND_INTERVAL = 30000, // ms
INVITE_ACCEPT_WAIT_TIME = 120000, // ms
INVITE_ACCEPT_WAIT_TIME = 80000, // ms
TIME_TO_AUTOREMOVE = 120000, // ms
MAX_OFFLINE_TIME = 300000, // ms
START_DELAY0 = 120000, // ms
@ -143,6 +144,18 @@ enum BattleGroundTypeId
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,
@ -195,6 +208,20 @@ enum BattleGroundTeamId
BG_TEAM_HORDE = 1
};
enum BattleGroundJoinError
{
BG_JOIN_ERR_OK = 0,
BG_JOIN_ERR_OFFLINE_MEMBER = 1,
BG_JOIN_ERR_GROUP_TOO_MANY = 2,
BG_JOIN_ERR_MIXED_FACTION = 3,
BG_JOIN_ERR_MIXED_LEVELS = 4,
BG_JOIN_ERR_MIXED_ARENATEAM = 5,
BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE = 6,
BG_JOIN_ERR_GROUP_DESERTER = 7,
BG_JOIN_ERR_ALL_QUEUES_USED = 8,
BG_JOIN_ERR_GROUP_NOT_ENOUGH = 9
};
class BattleGroundScore
{
public:
@ -224,6 +251,7 @@ class BattleGround
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
@ -296,6 +324,7 @@ class BattleGround
}
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; }
@ -366,6 +395,7 @@ class BattleGround
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)
@ -374,6 +404,12 @@ class BattleGround
++m_PlayersCount[GetTeamIndexByTeamId(Team)];
}
// used for rated arena battles
void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[GetTeamIndexByTeamId(Team)] = ArenaTeamId; }
uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; }
void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 RatingChange) { m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)] = RatingChange; }
int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; }
/* Triggers handle */
// must be implemented in BG subclass
virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}
@ -390,6 +426,7 @@ class BattleGround
virtual WorldSafeLocsEntry const* GetClosestGraveYard(float /*x*/, float /*y*/, float /*z*/, uint32 /*team*/) { return NULL; }
virtual void AddPlayer(Player *plr); // must be implemented in BG subclass
virtual void RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket);
// can be extended in in BG subclass
@ -402,7 +439,8 @@ class BattleGround
BGCreatures m_BgCreatures;
void SpawnBGObject(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);
// void SpawnBGCreature(uint32 type, uint32 respawntime);
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);
@ -411,6 +449,13 @@ class BattleGround
void DoorClose(uint32 type);
const char *GetMangosString(int32 entry);
virtual bool HandlePlayerUnderMap(Player * plr) {return false;}
// 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();
@ -443,6 +488,8 @@ class BattleGround
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
@ -450,6 +497,8 @@ class BattleGround
uint8 m_Winner; // 0=alliance, 1=horde, 2=none
int32 m_StartDelayTime;
bool m_IsRated; // is this battle rated?
bool m_PrematureCountDown;
uint32 m_PrematureCountDownTimer;
char const *m_Name;
/* Player lists */
@ -468,6 +517,11 @@ class BattleGround
/* 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;

View file

@ -50,6 +50,13 @@ void BattleGroundAB::Update(time_t diff)
{
m_Events |= 0x01;
// setup here, only when at least one player has ported to the map
if(!SetupBattleGround())
{
EndNow();
return;
}
sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ...");
// despawn banners, auras and buffs
@ -377,6 +384,7 @@ void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
{
if( !AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team) )
sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
// SpawnBGCreature(node,RESPAWN_IMMEDIATELY);
uint8 capturedNodes = 0;
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)

View file

@ -47,6 +47,12 @@ void BattleGroundBE::Update(time_t diff)
if (!(m_Events & 0x01))
{
m_Events |= 0x01;
// setup here, only when at least one player has ported to the map
if(!SetupBattleGround())
{
EndNow();
return;
}
for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; i++)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
@ -86,6 +92,11 @@ void BattleGroundBE::Update(time_t diff)
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if(Player *plr = objmgr.GetPlayer(itr->first))
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
EndBattleGround(HORDE);
else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
EndBattleGround(ALLIANCE);
}
}
@ -102,11 +113,23 @@ void BattleGroundBE::AddPlayer(Player *plr)
BattleGroundBEScore* sc = new BattleGroundBEScore;
m_PlayerScores[plr->GetGUID()] = sc;
UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE));
}
void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
{
if(GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE));
if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
EndBattleGround(HORDE);
else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
EndBattleGround(ALLIANCE);
}
void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)
@ -120,17 +143,27 @@ void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)
return;
}
BattleGround::HandleKillPlayer(player, killer);
BattleGround::HandleKillPlayer(player,killer);
uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE));
++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);
}
}
bool BattleGroundBE::HandlePlayerUnderMap(Player *player)
{
player->TeleportTo(GetMapId(),6238.930176,262.963470,0.889519,player->GetOrientation(),false);
return true;
}
void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)
@ -159,10 +192,16 @@ void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)
// HandleTriggerBuff(buff_guid,Source);
}
void BattleGroundBE::FillInitialWorldStates(WorldPacket &data)
{
data << uint32(0x9f1) << uint32(GetAlivePlayersCountByTeam(ALLIANCE)); // 7
data << uint32(0x9f0) << uint32(GetAlivePlayersCountByTeam(HORDE)); // 8
data << uint32(0x9f3) << uint32(1); // 9
}
void BattleGroundBE::ResetBGSubclass()
{
m_TeamKills[BG_TEAM_ALLIANCE] = 0;
m_TeamKills[BG_TEAM_HORDE] = 0;
}
bool BattleGroundBE::SetupBattleGround()

View file

@ -64,12 +64,11 @@ class BattleGroundBE : public BattleGround
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
void ResetBGSubclass();
virtual void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player *killer);
bool HandlePlayerUnderMap(Player * plr);
/* Scorekeeping */
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
private:
uint32 m_TeamKills[2]; // count of kills for each team
};
#endif

View file

@ -54,9 +54,18 @@ void BattleGroundEY::Update(time_t diff)
{
m_Events |= 0x01;
// setup here, only when at least one player has ported to the map
if(!SetupBattleGround())
{
EndNow();
return;
}
SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY);
SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY);
// SpawnBGCreature(EY_SPIRIT_MAIN_ALLIANCE, RESPAWN_IMMEDIATELY);
// SpawnBGCreature(EY_SPIRIT_MAIN_HORDE, RESPAWN_IMMEDIATELY);
for(uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i)
SpawnBGObject(i, RESPAWN_ONE_DAY);
@ -572,7 +581,17 @@ void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer)
void BattleGroundEY::EventPlayerDroppedFlag(Player *Source)
{
// Drop allowed in any BG state
if(GetStatus() != STATUS_IN_PROGRESS)
{
// if not running, do not cast things at the dropper player, neither send unnecessary messages
// just take off the aura
if(IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID())
{
SetFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
}
return;
}
if(!IsFlagPickedup())
return;
@ -744,6 +763,8 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
sLog.outError("BatteGroundEY: Failed to spawn spirit guide! point: %u, team: %u, graveyard_id: %u",
Point, Team, m_CapturingPointTypes[Point].GraveYardId);
// SpawnBGCreature(Point,RESPAWN_IMMEDIATELY);
UpdatePointsIcons(Team, Point);
UpdatePointsCount(Team);
}

View file

@ -26,9 +26,11 @@
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Object.h"
#include "Chat.h"
#include "BattleGroundMgr.h"
#include "BattleGroundWS.h"
#include "BattleGround.h"
#include "ArenaTeam.h"
#include "Language.h"
void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
@ -76,18 +78,25 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
uint32 bgTypeId;
uint32 instanceId;
uint8 joinAsGroup;
Group * grp;
recv_data >> guid; // battlemaster guid
recv_data >> bgTypeId; // battleground type id (DBC id)
recv_data >> instanceId; // instance id, 0 if First Available selected
recv_data >> joinAsGroup; // join as group
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT " for BG (Type: %u)", guid, bgTypeId);
if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating?
if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
{
sLog.outError("Battleground: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());
return;
}
// ignore if we already in BG or BG queue
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 player is already in BG
if(_player->InBattleGround())
return;
@ -98,74 +107,82 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
if(!unit->isBattleMaster()) // it's not battlemaster
return;
// check Deserter debuff
if( !_player->CanJoinToBattleground() )
// 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)))
{
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data << (uint32) 0xFFFFFFFE;
_player->GetSession()->SendPacket(&data);
sLog.outError("Battleground: no available bg / template found");
return;
}
// check existence
BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
if(!bg)
return;
if(joinAsGroup && _player->GetGroup())
// check queueing conditions
if(!joinAsGroup)
{
Group *grp = _player->GetGroup();
// check Deserter debuff
if( !_player->CanJoinToBattleground() )
{
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data << (uint32) 0xFFFFFFFE;
_player->GetSession()->SendPacket(&data);
return;
}
// check if already in queue
if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
return;
// check if has free queue slots
if(!_player->HasFreeBattleGroundQueueId())
return;
}
else
{
grp = _player->GetGroup();
// no group found, error
if(!grp)
return;
uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
if (err != BG_JOIN_ERR_OK)
{
SendBattleGroundOrArenaJoinError(err);
return;
}
}
// if we're here, then the conditions to join a bg are met. We can proceed in joining.
// _player->GetGroup() was already checked, grp is already initialized
if(joinAsGroup /* && _player->GetGroup()*/)
{
sLog.outDebug("Battleground: the following players are joining as group:");
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) continue; // this should never happen
if( !member->CanJoinToBattleground() )
{
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data << (uint32) 0xFFFFFFFE;
_player->GetSession()->SendPacket(&data);
continue;
}
if (member->InBattleGroundQueueForBattleGroundType(bgTypeId))
//player is already in this queue
continue;
WorldPacket data;
// add to queue
uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId);
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
// fill data packet
//member->GetSession()->SendPacket(data);
continue;
}
uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
// store entry point coords (same as leader entry point)
member->SetBattleGroundEntryPoint(_player->GetMapId(),_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);
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);
sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
}
sLog.outDebug("Battleground: group end");
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
}
else
{
if (_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
//player is already in this queue
return;
uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
WorldPacket data;
// fill data packet
//SendPacket(data);
return;
}
// already checked if queueSlot is valid, now just get it
uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
// store entry point coords
_player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
@ -173,7 +190,11 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_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());
sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
}
}
@ -247,12 +268,11 @@ void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data )
uint32 bgTypeId;
recv_data >> bgTypeId; // id from DBC
if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating?
return;
// can't be received if player not in BG queue
if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
{
sLog.outError("Battleground: invalid bgtype received.");
return;
}
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
@ -270,80 +290,201 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
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;
if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating?
return;
if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
return;
BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
if(!bg)
return;
uint32 queueSlot = 0;
WorldPacket data;
switch(action)
if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
{
case 1: // port to battleground
// cheating?
if(!_player->IsInvitedForBattleGroundType(bgTypeId))
return;
// check if player is not deserter
if( !_player->CanJoinToBattleground() )
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++)
{
WorldPacket data2;
data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data2 << (uint32) 0xFFFFFFFE;
SendPacket(&data2);
return;
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;
}
// if the player is dead, resurrect him before teleport
if(!_player->isAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
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());
// leave current group
_player->RemoveFromGroup();
if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
{
sLog.outError("Battleground: itrplayerstatus not found.");
return;
}
instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
// packet to player about BG status
queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
_player->GetSession()->SendPacket(&data);
// if action == 1, then instanceId is _required_
if(!instanceId && action == 1)
{
sLog.outError("Battleground: instance not found.");
return;
}
// remove battleground queue status from BGmgr
sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);
BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
// also this required to prevent stuck at old battleground after SetBattleGroundId set to new
if (BattleGround *currentBg = _player->GetBattleGround())
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
// 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);
_player->SetBattleGroundId(bg->GetTypeID());
sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);
bg->AddPlayer(_player);
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
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);
SendPacket(&data);
break;
default:
sLog.outError("Battleground port: unknown action %u", action);
break;
if(!bg)
{
sLog.outError("Battleground: bg not found.");
return;
}
bgTypeId = bg->GetTypeID();
if(_player->InBattleGroundQueue())
{
uint32 queueSlot = 0;
uint32 team = 0;
uint32 arenatype = 0;
uint32 israted = 0;
uint32 rating = 0;
uint32 opponentsRating = 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;
rating = pitr->second.GroupInfo->ArenaTeamRating;
opponentsRating = pitr->second.GroupInfo->OpponentsTeamRating;
}
else
{
sLog.outError("Battleground: Invalid player queue info!");
return;
}
WorldPacket data;
switch(action)
{
case 1: // port to battleground
if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
return; // cheating?
// resurrect the player
if(!_player->isAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
// stop taxi flight at port
if(_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
_player->m_taxi.ClearTaxiDestinations();
}
_player->RemoveFromGroup();
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[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
// also this required to prevent stuck at old battleground after SetBattleGroundId set to new
if( BattleGround *currentBg = _player->GetBattleGround() )
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
// set the destination instance id
_player->SetBattleGroundId(bg->GetInstanceID());
// set the destination team
_player->SetBGTeam(team);
// bg->HandleBeforeTeleportToBattleGround(_player);
sBattleGroundMgr.SendToBattleGround(_player, instanceId);
// add only in HandleMoveWorldPortAck()
// bg->AddPlayer(_player,team);
sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
break;
case 0: // leave queue
queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
/*
if player leaves rated arena match before match start, it is counted as he played but he lost
*/
if (israted)
{
ArenaTeam * at = objmgr.GetArenaTeamById(team);
if (at)
{
sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating);
at->MemberLost(_player, opponentsRating);
at->SaveToDB();
}
}
_player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
// player left queue, we should update it, maybe now his group fits in
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(),arenatype,israted,rating);
SendPacket(&data);
sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId);
break;
default:
sLog.outError("Battleground port: unknown action %u", action);
break;
}
}
}
@ -384,7 +525,8 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
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());
@ -392,15 +534,25 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
}
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);
}
}
@ -411,16 +563,36 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
// we should update all queues? .. i'm not sure if this code is correct
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
if(uint32 queue_id = _player->GetBattleGroundQueueId(i))
uint32 queue_id = _player->GetBattleGroundQueueId(i);
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)
{
if(BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id))
{
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
SendPacket(&data);
}
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, arenatype, isRated);
SendPacket(&data);
}
}
}
/* else // not sure if it needed...
{
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);
SendPacket(&data);
}
}*/
}
void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
@ -480,16 +652,12 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
if(_player->InBattleGround())
return;
for(int qId = 0; qId < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qId)
{
if(_player->GetBattleGroundQueueId(qId) != 0)
return;
}
uint64 guid; // arena Battlemaster guid
uint8 type; // 2v2, 3v3 or 5v5
uint8 asGroup; // asGroup
uint8 isRated; // isRated
Group * grp;
recv_data >> guid >> type >> asGroup >> isRated;
Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
@ -500,6 +668,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
return;
uint8 arenatype = 0;
uint32 arenaRating = 0;
switch(type)
{
@ -517,88 +686,118 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
return;
}
if(isRated && !_player->GetArenaTeamId(type)) // player not in arena team of that size
//check existance
BattleGround* bg = NULL;
if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )
{
_player->GetSession()->SendNotInArenaTeamPacket(arenatype);
sLog.outError("Battleground: template bg (all arenas) not found");
return;
}
if(asGroup && !_player->GetGroup()) // player not in group
return;
uint8 bgTypeId = bg->GetTypeID();
uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
// check existence
BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);
if(!bg)
return;
bg->SetArenaType(arenatype);
bg->SetRated(isRated);
if(asGroup && _player->GetGroup())
// check queueing conditions
if(!asGroup)
{
Group *grp = _player->GetGroup();
// check if already in queue
if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
return;
// check if has free queue slots
if(!_player->HasFreeBattleGroundQueueId())
return;
}
else
{
grp = _player->GetGroup();
// no group found, error
if(!grp)
return;
uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, type);
if (err != BG_JOIN_ERR_OK)
{
SendBattleGroundOrArenaJoinError(err);
return;
}
}
uint32 ateamId = 0;
if(isRated)
{
ateamId = _player->GetArenaTeamId(type);
// check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
if(!at)
{
_player->GetSession()->SendNotInArenaTeamPacket(arenatype);
return;
}
// get the team rating for queueing
arenaRating = at->GetRating();
// the arenateam id must match for everyone in the group
// get the personal ratings for queueing
uint32 avg_pers_rating = 0;
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
// calc avg personal rating
avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (type*6) + 5);
}
if( arenatype )
avg_pers_rating /= arenatype;
// if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating
if(avg_pers_rating + 150 < arenaRating)
arenaRating = avg_pers_rating;
}
if(asGroup)
{
GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId);
sLog.outDebug("Battleground: arena join as group start");
if(isRated)
sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(type),_player->GetName(),arenaRating,arenatype);
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
if(!member) continue;
/*if (!member->CanJoinToBattleground())
//player has deserter aura .. do nothing
*/
if (member->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
//player is already in this queue
continue;
// add to queue
uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
WorldPacket data;
//fill data
//member->GetSession()->SendPacket(data);
continue;
}
uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
// store entry point coords (same as leader entry point)
member->SetBattleGroundEntryPoint(_player->GetMapId(),_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);
sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
}
sLog.outDebug("Battleground: arena join as group end");
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
}
else
{
/*if (!member->CanJoinToBattleground())
//player has deserter aura .. do nothing
*/
if (_player->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
//player is already in this queue
return;
uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);
if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
{
WorldPacket data;
//fill data (player is in 3 queues already)
//SendPacket(data);
return;
}
uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
// store entry point coords
_player->SetBattleGroundEntryPoint(_player->GetMapId(),_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);
sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
}
}
@ -620,3 +819,41 @@ void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
reportedPlayer->ReportedAfkBy(_player);
}
void WorldSession::SendBattleGroundOrArenaJoinError(uint8 err)
{
WorldPacket data;
int32 msg;
switch (err)
{
case BG_JOIN_ERR_OFFLINE_MEMBER:
msg = LANG_BG_GROUP_OFFLINE_MEMBER;
break;
case BG_JOIN_ERR_GROUP_TOO_MANY:
msg = LANG_BG_GROUP_TOO_LARGE;
break;
case BG_JOIN_ERR_MIXED_FACTION:
msg = LANG_BG_GROUP_MIXED_FACTION;
break;
case BG_JOIN_ERR_MIXED_LEVELS:
msg = LANG_BG_GROUP_MIXED_LEVELS;
break;
case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
msg = LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE;
break;
case BG_JOIN_ERR_GROUP_DESERTER:
msg = LANG_BG_GROUP_MEMBER_DESERTER;
break;
case BG_JOIN_ERR_ALL_QUEUES_USED:
msg = LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS;
break;
case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
case BG_JOIN_ERR_MIXED_ARENATEAM:
default:
return;
break;
}
ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(msg), NULL);
SendPacket(&data);
return;
}

File diff suppressed because it is too large Load diff

View file

@ -34,51 +34,99 @@ typedef std::deque<BattleGround*> BGFreeSlotQueueType;
#define MAX_BATTLEGROUND_TYPES 9 // each BG type will be in array
struct PlayerQueueInfo
#define MAX_BATTLEGROUND_QUEUE_TYPES 8
#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day
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
GroupQueueInfo * GroupInfo; // pointer to the associated groupqueueinfo
};
struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!)
{
std::map<uint64, PlayerQueueInfo*> Players; // player queue info map
uint32 Team; // Player team (ALLIANCE/HORDE)
bool IsRated;
bool AsGroup; // uint32 GroupId;
uint8 ArenaType;
};
struct PlayersCount
{
uint32 Alliance;
uint32 Horde;
};
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)
uint32 BgTypeId; // battleground type id
bool IsRated; // rated
uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG
uint32 ArenaTeamId; // team id if rated match
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
uint32 OpponentsTeamRating; // for rated arena matches
};
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, uint32 ArenaTeamId = 0);
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, uint32 excludeTeam = 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, uint32 excludeTeam = 0);
private:
bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side);
};
/*
@ -96,7 +144,6 @@ class BGQueueInviteEvent : public BasicEvent
private:
uint64 m_PlayerGuid;
uint32 m_BgInstanceGUID;
};
/*
@ -116,7 +163,6 @@ class BGQueueRemoveEvent : public BasicEvent
uint32 m_PlayersTeam;
};
class BattleGroundMgr
{
public:
@ -132,18 +178,18 @@ class BattleGroundMgr
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,9 +198,13 @@ class BattleGroundMgr
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();
@ -162,16 +212,39 @@ class BattleGroundMgr
/* 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();
uint32 GetPrematureFinishTime() const {return m_PrematureFinishTimer;}
void ToggleArenaTesting();
const bool isArenaTesting() const { return m_ArenaTesting; }
private:
/* Battlegrounds */
BattleGroundSet m_BattleGrounds;
uint32 m_MaxRatingDifference;
uint32 m_RatingDiscardTimer;
uint32 m_NextRatingDiscardUpdate;
bool m_AutoDistributePoints;
uint64 m_NextAutoDistributionTime;
uint32 m_AutoDistributionTimeChecker;
uint32 m_PrematureFinishTimer;
bool m_ArenaTesting;
};
#define sBattleGroundMgr MaNGOS::Singleton<BattleGroundMgr>::Instance()

View file

@ -47,6 +47,12 @@ void BattleGroundNA::Update(time_t diff)
if (!(m_Events & 0x01))
{
m_Events |= 0x01;
// setup here, only when at least one player has ported to the map
if(!SetupBattleGround())
{
EndNow();
return;
}
for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; i++)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
@ -73,6 +79,9 @@ void BattleGroundNA::Update(time_t diff)
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);
@ -80,6 +89,11 @@ void BattleGroundNA::Update(time_t diff)
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if(Player *plr = objmgr.GetPlayer(itr->first))
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
EndBattleGround(HORDE);
else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
EndBattleGround(ALLIANCE);
}
}
@ -96,11 +110,23 @@ void BattleGroundNA::AddPlayer(Player *plr)
BattleGroundNAScore* sc = new BattleGroundNAScore;
m_PlayerScores[plr->GetGUID()] = sc;
UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE));
}
void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
{
if(GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE));
if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
EndBattleGround(HORDE);
else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
EndBattleGround(ALLIANCE);
}
void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)
@ -114,17 +140,27 @@ void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)
return;
}
BattleGround::HandleKillPlayer(player, killer);
BattleGround::HandleKillPlayer(player,killer);
uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE));
++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);
}
}
bool BattleGroundNA::HandlePlayerUnderMap(Player *player)
{
player->TeleportTo(GetMapId(),4055.504395,2919.660645,13.611241,player->GetOrientation(),false);
return true;
}
void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)
@ -149,19 +185,28 @@ void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)
// HandleTriggerBuff(buff_guid,Source);
}
void BattleGroundNA::FillInitialWorldStates(WorldPacket &data)
{
data << uint32(0xa0f) << uint32(GetAlivePlayersCountByTeam(ALLIANCE)); // 7
data << uint32(0xa10) << uint32(GetAlivePlayersCountByTeam(HORDE)); // 8
data << uint32(0xa11) << uint32(1); // 9
}
void BattleGroundNA::ResetBGSubclass()
{
m_TeamKills[BG_TEAM_ALLIANCE] = 0;
m_TeamKills[BG_TEAM_HORDE] = 0;
}
bool BattleGroundNA::SetupBattleGround()
{
// gates
if( !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY))
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)
// 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;

View file

@ -26,7 +26,9 @@ enum BattleGroundNAObjectTypes
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 @@ enum BattleGroundNAObjects
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
@ -61,9 +65,8 @@ class BattleGroundNA : public BattleGround
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
virtual void ResetBGSubclass();
virtual void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player *killer);
private:
uint32 m_TeamKills[2]; // count of kills for each team
bool HandlePlayerUnderMap(Player * plr);
};
#endif

View file

@ -47,6 +47,13 @@ void BattleGroundRL::Update(time_t diff)
{
m_Events |= 0x01;
// setup here, only when at least one player has ported to the map
if(!SetupBattleGround())
{
EndNow();
return;
}
for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
@ -73,6 +80,9 @@ void BattleGroundRL::Update(time_t diff)
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);
@ -80,6 +90,11 @@ void BattleGroundRL::Update(time_t diff)
for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if(Player *plr = objmgr.GetPlayer(itr->first))
plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
EndBattleGround(HORDE);
else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
EndBattleGround(ALLIANCE);
}
}
@ -96,11 +111,23 @@ void BattleGroundRL::AddPlayer(Player *plr)
BattleGroundRLScore* sc = new BattleGroundRLScore;
m_PlayerScores[plr->GetGUID()] = sc;
UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE));
}
void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
{
if(GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE));
if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
EndBattleGround(HORDE);
else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
EndBattleGround(ALLIANCE);
}
void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)
@ -114,17 +141,27 @@ void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)
return;
}
BattleGround::HandleKillPlayer(player, killer);
BattleGround::HandleKillPlayer(player,killer);
uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());
UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE));
++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);
}
}
bool BattleGroundRL::HandlePlayerUnderMap(Player *player)
{
player->TeleportTo(GetMapId(),1285.810547,1667.896851,39.957642,player->GetOrientation(),false);
return true;
}
void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)
@ -150,17 +187,26 @@ void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)
// HandleTriggerBuff(buff_guid,Source);
}
void BattleGroundRL::FillInitialWorldStates(WorldPacket &data)
{
data << uint32(0xbb8) << uint32(GetAlivePlayersCountByTeam(ALLIANCE)); // 7
data << uint32(0xbb9) << uint32(GetAlivePlayersCountByTeam(HORDE)); // 8
data << uint32(0xbba) << uint32(1); // 9
}
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.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f, RESPAWN_IMMEDIATELY))
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)
// 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;

View file

@ -24,13 +24,17 @@ enum BattleGroundRLObjectTypes
{
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
@ -57,9 +61,8 @@ class BattleGroundRL : public BattleGround
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
virtual void ResetBGSubclass();
virtual void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player *killer);
private:
uint32 m_TeamKills[2]; // count of kills for each team
bool HandlePlayerUnderMap(Player * plr);
};
#endif

View file

@ -49,6 +49,16 @@ void BattleGroundWS::Update(time_t diff)
{
m_Events |= 0x01;
// setup here, only when at least one player has ported to the map
if(!SetupBattleGround())
{
EndNow();
return;
}
// for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++)
// SpawnBGCreature(i, RESPAWN_IMMEDIATELY);
for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
{
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
@ -285,7 +295,32 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source)
void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
{
// Drop allowed in any BG state
if(GetStatus() != STATUS_IN_PROGRESS)
{
// if not running, do not cast things at the dropper player (prevent spawning the "dropped" flag), neither send unnecessary messages
// just take off the aura
if(Source->GetTeam() == ALLIANCE)
{
if(!this->IsHordeFlagPickedup())
return;
if(GetHordeFlagPickerGUID() == Source->GetGUID())
{
SetHordeFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
}
}
else
{
if(!this->IsAllianceFlagPickedup())
return;
if(GetAllianceFlagPickerGUID() == Source->GetGUID())
{
SetAllianceFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
}
}
return;
}
const char *message = "";
uint8 type = 0;

View file

@ -36,6 +36,7 @@
#include "PlayerDump.h"
#include "SocialMgr.h"
#include "Util.h"
#include "ArenaTeam.h"
#include "Language.h"
class LoginQueryHolder : public SqlQueryHolder
@ -59,7 +60,7 @@ bool LoginQueryHolder::Initialize()
// NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
// !!! NOTE: including unused `zone`,`online`
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
@ -79,6 +80,7 @@ bool LoginQueryHolder::Initialize()
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'",GUID_LOPART(m_guid));
// in other case still be dummy query
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid));
return res;
}
@ -411,7 +413,7 @@ void WorldSession::HandleCharDeleteOpcode( WorldPacket & recv_data )
}
// is arena team captain
if(objmgr.GetArenaTeamByCapitan(guid))
if(objmgr.GetArenaTeamByCaptain(guid))
{
WorldPacket data(SMSG_CHAR_DELETE, 1);
data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN;

View file

@ -197,6 +197,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMod32Value, "", NULL },
{ "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleAnimCommand, "", NULL },
{ "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleGetLootRecipient, "", NULL },
{ "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@ -560,6 +561,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "cometome", SEC_ADMINISTRATOR, false, &ChatHandler::HandleComeToMeCommand, "", NULL },
{ "damage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDamageCommand, "", NULL },
{ "combatstop", SEC_GAMEMASTER, false, &ChatHandler::HandleCombatStopCommand, "", NULL },
{ "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
{ "chardelete", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeleteCommand, "", NULL },
{ "sendmessage", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL },
{ "repairitems", SEC_GAMEMASTER, false, &ChatHandler::HandleRepairitemsCommand, "", NULL },

View file

@ -415,6 +415,7 @@ class ChatHandler
bool HandleComeToMeCommand(const char *args);
bool HandleCombatStopCommand(const char *args);
bool HandleSendMessageCommand(const char * args);
bool HandleFlushArenaPointsCommand(const char *args);
bool HandleRepairitemsCommand(const char* args);
bool HandleWaterwalkCommand(const char* args);
@ -429,6 +430,7 @@ class ChatHandler
bool HandleSaveAllCommand(const char* args);
bool HandleGetItemState(const char * args);
bool HandleGetLootRecipient(const char * args);
bool HandleDebugArenaCommand(const char * args);
Player* getSelectedPlayer();
Creature* getSelectedCreature();

View file

@ -363,7 +363,7 @@ uint32 GameEvent::Update() // return the next e
{
uint32 nextEventDelay = max_ge_check_delay; // 1 day
uint32 calcDelay;
for (uint16 itr = 1; itr < mGameEvent.size(); itr++)
for (uint16 itr = 1; itr < mGameEvent.size(); ++itr)
{
//sLog.outErrorDb("Checking event %u",itr);
if (CheckOneGameEvent(itr))

View file

@ -1308,6 +1308,54 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
SendUpdate();
}
uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot)
{
// check for min / max count
uint32 memberscount = GetMembersCount();
if(memberscount < MinPlayerCount)
return BG_JOIN_ERR_GROUP_NOT_ENOUGH;
if(memberscount > MaxPlayerCount)
return BG_JOIN_ERR_GROUP_TOO_MANY;
// get a player as reference, to compare other players' stats to (arena team id, queue id based on level, etc.)
Player * reference = GetFirstMember()->getSource();
// no reference found, can't join this way
if(!reference)
return BG_JOIN_ERR_OFFLINE_MEMBER;
uint32 bgQueueId = reference->GetBattleGroundQueueIdFromLevel();
uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot);
uint32 team = reference->GetTeam();
// check every member of the group to be able to join
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
// offline member? don't let join
if(!member)
return BG_JOIN_ERR_OFFLINE_MEMBER;
// don't allow cross-faction join as group
if(member->GetTeam() != team)
return BG_JOIN_ERR_MIXED_FACTION;
// not in the same battleground level braket, don't let join
if(member->GetBattleGroundQueueIdFromLevel() != bgQueueId)
return BG_JOIN_ERR_MIXED_LEVELS;
// don't let join rated matches if the arena team id doesn't match
if(isRated && member->GetArenaTeamId(arenaSlot) != arenaTeamId)
return BG_JOIN_ERR_MIXED_ARENATEAM;
// don't let join if someone from the group is already in that bg queue
if(member->InBattleGroundQueueForBattleGroundQueueType(bgQueueType))
return BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE;
// check for deserter debuff in case not arena queue
if(bgTypeId != BATTLEGROUND_AA && !member->CanJoinToBattleground())
return BG_JOIN_ERR_GROUP_DESERTER;
// check if member can join any more battleground queues
if(!member->HasFreeBattleGroundQueueId())
return BG_JOIN_ERR_ALL_QUEUES_USED;
}
return BG_JOIN_ERR_OK;
}
//===================================================
//============== Roll ===============================
//===================================================

View file

@ -247,6 +247,7 @@ class MANGOS_DLL_SPEC Group
void ConvertToRaid();
void SetBattlegroundGroup(BattleGround *bg) { m_bgGroup = bg; }
uint32 CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot);
void ChangeMembersGroup(const uint64 &guid, const uint8 &group);
void ChangeMembersGroup(Player *player, const uint8 &group);

View file

@ -641,11 +641,30 @@ enum MangosStrings
LANG_BG_QUEUE_ANNOUNCE_SELF = 711,
LANG_BG_QUEUE_ANNOUNCE_WORLD = 712,
LANG_YOUR_ARENA_LEVEL_REQ_ERROR = 713,
LANG_HIS_ARENA_LEVEL_REQ_ERROR = 714,
// LANG_HIS_ARENA_LEVEL_REQ_ERROR = 714, an opcode exists for this
LANG_YOUR_BG_LEVEL_REQ_ERROR = 715,
LANG_YOUR_ARENA_TEAM_FULL = 716,
// Room for BG/ARENA 717-799 not used
// LANG_YOUR_ARENA_TEAM_FULL = 716, an opcode exists for this
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!"
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 7013, // The battleground will end soon, because there aren't enough players. Get more ppl or win already!
LANG_BG_GROUP_OFFLINE_MEMBER = 7014, // "Your group has an offline member. Please remove him before joining."
LANG_BG_GROUP_MIXED_FACTION = 7015, // "Your group has players from the opposing faction. You can't join the battleground as a group."
LANG_BG_GROUP_MIXED_LEVELS = 7016, // "Your group has players from different battleground brakets. You can't join as group."
LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 7017, // "Someone in your party is already in this battleground queue. (S)he must leave it before joining as group."
LANG_BG_GROUP_MEMBER_DESERTER = 7018, // "Someone in your party is Deserter. You can't join as group."
LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 7019, // "Someone in your party is already in three battleground queues. You cannot join as group."
LANG_CANNOT_TELE_TO_BG = 7020, // "You cannot teleport to a battleground or arena map."
LANG_CANNOT_SUMMON_TO_BG = 7021, // "You cannot summon players to a battleground or arena map."
LANG_CANNOT_GO_TO_BG_GM = 7022, // "You must be in GM mode to teleport to a player in a battleground."
LANG_CANNOT_GO_TO_BG_FROM_BG = 7023, // "You cannot teleport to a battleground from another battleground. Please leave the current battleground first."
// in game strings
// = 800, not used

View file

@ -351,7 +351,14 @@ bool ChatHandler::HandleNamegoCommand(const char* args)
Map* pMap = m_session->GetPlayer()->GetMap();
if(pMap->Instanceable())
if(pMap->IsBattleGroundOrArena())
{
// cannot summon to bg
PSendSysMessage(LANG_CANNOT_SUMMON_TO_BG,chr->GetName());
SetSentErrorMessage(true);
return false;
}
else if(pMap->IsDungeon())
{
Map* cMap = chr->GetMap();
if( cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId() )
@ -435,6 +442,28 @@ bool ChatHandler::HandleGonameCommand(const char* args)
Player *chr = objmgr.GetPlayer(name.c_str());
if (chr)
{
Map* cMap = chr->GetMap();
if(cMap->IsBattleGroundOrArena())
{
// only allow if gm mode is on
if (!_player->isGameMaster())
{
PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,chr->GetName());
SetSentErrorMessage(true);
return false;
}
// if already in a bg, don't let port to other
else if (_player->GetBattleGroundId())
{
PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,chr->GetName());
SetSentErrorMessage(true);
return false;
}
// all's well, set bg id
// when porting out from the bg, it will be reset to 0
_player->SetBattleGroundId(chr->GetBattleGroundId());
}
else if(cMap->IsDungeon())
Map* cMap = chr->GetMap();
if(cMap->Instanceable())
{

View file

@ -47,6 +47,7 @@
#include "Config/ConfigEnv.h"
#include "Util.h"
#include "ItemEnchantmentMgr.h"
#include "BattleGroundMgr.h"
#include "InstanceSaveMgr.h"
#include "InstanceData.h"
@ -6479,6 +6480,12 @@ bool ChatHandler::HandleSendMessageCommand(const char* args)
return true;
}
bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)
{
sBattleGroundMgr.DistributeArenaPoints();
return true;
}
bool ChatHandler::HandleModifyGenderCommand(const char *args)
{
if(!*args)

View file

@ -141,7 +141,17 @@ Map* MapInstanced::GetInstance(const WorldObject* obj)
uint32 NewInstanceId = 0; // instanceId of the resulting map
Player* player = (Player*)obj;
// TODO: battlegrounds and arenas
if(IsBattleGroundOrArena())
{
// instantiate or find existing bg map for player
// the instance id is set in battlegroundid
NewInstanceId = player->GetBattleGroundId();
assert(NewInstanceId);
map = _FindMap(NewInstanceId);
if(!map)
map = CreateBattleGround(NewInstanceId);
return map;
}
InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
InstanceSave *pSave = pBind ? pBind->save : NULL;

View file

@ -107,7 +107,7 @@ MapManager::_GetBaseMap(uint32 id)
Guard guard(*this);
const MapEntry* entry = sMapStore.LookupEntry(id);
if (entry && entry->IsDungeon())
if (entry && entry->Instanceable())
{
m = new MapInstanced(id, i_gridCleanUpDelay);
}

View file

@ -130,22 +130,28 @@ void WorldSession::HandleMoveWorldportAckOpcode()
_player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
// battleground state prepare
if(_player->InBattleGround())
// only add to bg group and object, if the player was invited (else he entered through command)
if(_player->InBattleGround() && _player->IsInvitedForBattleGroundInstance(_player->GetBattleGroundId()))
{
BattleGround *bg = _player->GetBattleGround();
if(bg)
{
bg->AddPlayer(_player);
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->Create(_player->GetGUIDLow(), _player->GetName());
}
else // raid already exist
{
bg->GetBgRaid(_player->GetTeam())->AddMember(_player->GetGUID(), _player->GetName());
bg->GetBgRaid(team)->AddMember(_player->GetGUID(), _player->GetName());
}
}
}
@ -370,20 +376,29 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
if(movementInfo.z < -500.0f)
{
// NOTE: this is actually called many times while falling
// even after the player has been teleported away
// TODO: discard movement packets after the player is rooted
if(GetPlayer()->isAlive())
if(GetPlayer()->InBattleGround()
&& GetPlayer()->GetBattleGround()
&& GetPlayer()->GetBattleGround()->HandlePlayerUnderMap(_player))
{
GetPlayer()->EnvironmentalDamage(GetPlayer()->GetGUID(),DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
// change the death state to CORPSE to prevent the death timer from
// starting in the next player update
GetPlayer()->KillPlayer();
GetPlayer()->BuildPlayerRepop();
// do nothing, the handle already did if returned true
}
else
{
// NOTE: this is actually called many times while falling
// even after the player has been teleported away
// TODO: discard movement packets after the player is rooted
if(GetPlayer()->isAlive())
{
GetPlayer()->EnvironmentalDamage(GetPlayer()->GetGUID(),DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
// change the death state to CORPSE to prevent the death timer from
// starting in the next player update
GetPlayer()->KillPlayer();
GetPlayer()->BuildPlayerRepop();
}
// cancel the death timer here if started
GetPlayer()->RepopAtGraveyard();
// cancel the death timer here if started
GetPlayer()->RepopAtGraveyard();
}
}
}

View file

@ -137,13 +137,13 @@ ObjectMgr::ObjectMgr()
ObjectMgr::~ObjectMgr()
{
for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++ i )
for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++i )
{
delete i->second;
}
mQuestTemplates.clear( );
for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++ i )
for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++i )
{
delete i->second;
}
@ -151,7 +151,7 @@ ObjectMgr::~ObjectMgr()
mAreaTriggers.clear();
for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++ i )
for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++i )
{
delete[] i->second;
}
@ -226,33 +226,43 @@ Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const
return NULL;
}
ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 ArenaTeamId) const
ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 arenateamid) const
{
for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); ++itr)
if ((*itr)->GetId() == ArenaTeamId)
return *itr;
ArenaTeamMap::const_iterator itr = mArenaTeamMap.find(arenateamid);
if (itr != mArenaTeamMap.end())
return itr->second;
return NULL;
}
ArenaTeam* ObjectMgr::GetArenaTeamByName(const std::string& arenateamname) const
{
for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); ++itr)
if ((*itr)->GetName() == arenateamname)
return *itr;
for(ArenaTeamMap::const_iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr)
if (itr->second->GetName() == arenateamname)
return itr->second;
return NULL;
}
ArenaTeam* ObjectMgr::GetArenaTeamByCapitan(uint64 const& guid) const
ArenaTeam* ObjectMgr::GetArenaTeamByCaptain(uint64 const& guid) const
{
for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); ++itr)
if ((*itr)->GetCaptain() == guid)
return *itr;
for(ArenaTeamMap::const_iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr)
if (itr->second->GetCaptain() == guid)
return itr->second;
return NULL;
}
void ObjectMgr::AddArenaTeam(ArenaTeam* arenaTeam)
{
mArenaTeamMap[arenaTeam->GetId()] = arenaTeam;
}
void ObjectMgr::RemoveArenaTeam(ArenaTeam* arenaTeam)
{
mArenaTeamMap.erase( arenaTeam->GetId() );
}
AuctionHouseObject * ObjectMgr::GetAuctionsMap( uint32 location )
{
switch ( location )
@ -4203,7 +4213,7 @@ void ObjectMgr::AddGossipText(GossipText *pGText)
GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
{
GossipTextMap::const_iterator itr;
for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++)
for (itr = mGossipText.begin(); itr != mGossipText.end(); ++itr)
{
if(itr->second->Text_ID == Text_ID)
return itr->second;

View file

@ -282,11 +282,11 @@ class ObjectMgr
typedef std::set< Group * > GroupSet;
typedef std::set< Guild * > GuildSet;
typedef std::set< ArenaTeam * > ArenaTeamSet;
typedef UNORDERED_MAP<uint32, ArenaTeam* > ArenaTeamMap;
typedef UNORDERED_MAP<uint32, Quest*> QuestMap;
typedef UNORDERED_MAP<uint32, AreaTrigger> AreaTriggerMap;
typedef UNORDERED_MAP<uint32, uint32> AreaTriggerScriptMap;
@ -318,11 +318,13 @@ class ObjectMgr
void AddGuild(Guild* guild) { mGuildSet.insert( guild ); }
void RemoveGuild(Guild* guild) { mGuildSet.erase( guild ); }
ArenaTeam* GetArenaTeamById(const uint32 ArenaTeamId) const;
ArenaTeam* GetArenaTeamByName(const std::string& ArenaTeamName) const;
ArenaTeam* GetArenaTeamByCapitan(uint64 const& guid) const;
void AddArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.insert( arenateam ); }
void RemoveArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.erase( arenateam ); }
ArenaTeam* GetArenaTeamById(const uint32 arenateamid) const;
ArenaTeam* GetArenaTeamByName(const std::string& arenateamname) const;
ArenaTeam* GetArenaTeamByCaptain(uint64 const& guid) const;
void AddArenaTeam(ArenaTeam* arenaTeam);
void RemoveArenaTeam(ArenaTeam* arenaTeam);
ArenaTeamMap::iterator GetArenaTeamMapBegin() { return mArenaTeamMap.begin(); }
ArenaTeamMap::iterator GetArenaTeamMapEnd() { return mArenaTeamMap.end(); }
static CreatureInfo const *GetCreatureTemplate( uint32 id );
CreatureModelInfo const *GetCreatureModelInfo( uint32 modelid );
@ -801,7 +803,7 @@ class ObjectMgr
GroupSet mGroupSet;
GuildSet mGuildSet;
ArenaTeamSet mArenaTeamSet;
ArenaTeamMap mArenaTeamMap;
ItemMap mItems;
ItemMap mAitems;

View file

@ -115,14 +115,6 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
return;
}
for(uint8 i = 0; i < MAX_ARENA_SLOT; i++)
{
if(_player->GetArenaTeamId(i) && (i == (unk10-1)))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
return;
}
}
switch(unk10)
{
case 1:
@ -144,6 +136,12 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
sLog.outDebug("unknown selection at buy petition: %u", unk10);
return;
}
if(_player->GetArenaTeamId(unk10-1))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
return;
}
}
if(type == 9)
@ -153,12 +151,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS);
return;
}
if(objmgr.IsReservedName(name))
{
SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID);
return;
}
if(!ObjectMgr::IsValidCharterName(name))
if(objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
{
SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID);
return;
@ -171,12 +164,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
return;
}
if(objmgr.IsReservedName(name))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
return;
}
if(!ObjectMgr::IsValidCharterName(name))
if(objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
return;
@ -216,6 +204,8 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
_player->SendNewItem(charter, 1, true, false);
// a petition is invalid, if both the owner and the type matches
// we checked above, if this player is in an arenateam, so this must be
// datacorruption
QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type);
std::ostringstream ssInvalidPetitionGUIDs;
@ -429,12 +419,7 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data)
SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_EXISTS);
return;
}
if(objmgr.IsReservedName(newname))
{
SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID);
return;
}
if(!ObjectMgr::IsValidCharterName(newname))
if(objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname))
{
SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID);
return;
@ -447,12 +432,7 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
return;
}
if(objmgr.IsReservedName(newname))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
return;
}
if(!ObjectMgr::IsValidCharterName(newname))
if(objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
return;
@ -511,7 +491,13 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
// not let enemies sign guild charter
if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid))
{
if(type != 9)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
else
SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_NOT_ALLIED);
return;
}
QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
@ -527,10 +513,42 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
return;
}
if(type != 9 && _player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
if(type != 9)
{
// player is too low level to join an arena team
SendNotification(LANG_YOUR_ARENA_LEVEL_REQ_ERROR,sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
if(_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_PLAYER_TO_LOW);
return;
}
uint8 slot = ArenaTeam::GetSlotByType(type);
if(slot >= MAX_ARENA_SLOT)
return;
if(_player->GetArenaTeamId(slot))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S);
return;
}
if(_player->GetArenaTeamIdInvited())
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
return;
}
}
else
{
if(_player->GetGuildId())
{
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_IN_GUILD);
return;
}
if(_player->GetGuildIdInvited())
{
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_INVITED_TO_GUILD);
return;
}
return;
}
@ -619,20 +637,63 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data)
uint8 signs = 0;
uint64 petitionguid, plguid;
uint32 petitiontype;
uint32 type;
Player *player;
recv_data >> petitiontype; // 2.0.8 - petition type?
recv_data >> type;
recv_data >> petitionguid; // petition guid
recv_data >> plguid; // player guid
sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", petitiontype, GUID_LOPART(petitionguid), GUID_LOPART(plguid));
sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid));
player = ObjectAccessor::FindPlayer(plguid);
if(!player || player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
return;
// not let offer to enemies
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam() )
{
if(type != 9)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
else
SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_NOT_ALLIED);
return;
}
if(type != 9)
{
if(player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
{
// player is too low level to join an arena team
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_PLAYER_TO_LOW);
return;
}
uint8 slot = ArenaTeam::GetSlotByType(type);
if(slot >= MAX_ARENA_SLOT)
return;
if(player->GetArenaTeamId(slot))
{
// player is already in an arena team
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S);
return;
}
if(player->GetArenaTeamIdInvited())
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
return;
}
}
else
{
if(player->GetGuildId())
{
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_IN_GUILD);
return;
}
if(player->GetGuildIdInvited())
{
SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_INVITED_TO_GUILD);
return;
}
}
QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
if(!result)
@ -811,7 +872,7 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data)
else // or arena team
{
ArenaTeam* at = new ArenaTeam;
if(!at->create(_player->GetGUID(), type, name))
if(!at->Create(_player->GetGUID(), type, name))
{
sLog.outError("PetitionsHandler: arena team create failed.");
delete at;

View file

@ -346,8 +346,8 @@ Player::Player (WorldSession *session): Unit()
m_bgBattleGroundID = 0;
for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++)
{
m_bgBattleGroundQueueID[j].bgType = 0;
m_bgBattleGroundQueueID[j].invited = false;
m_bgBattleGroundQueueID[j].bgQueueType = 0;
m_bgBattleGroundQueueID[j].invitedToInstance = 0;
}
m_bgTeam = 0;
@ -1499,7 +1499,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
MapEntry const* mEntry = sMapStore.LookupEntry(mapid);
// don't let enter battlegrounds without assigned battleground id (for example through areatrigger)...
if(!InBattleGround() && mEntry->IsBattleGround() && !GetSession()->GetSecurity())
// don't let gm level > 1 either
if(!InBattleGround() && mEntry->IsBattleGroundOrArena())
return false;
// client without expansion support
@ -3489,6 +3490,29 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
guild->DelMember(guid);
}
// remove from arena teams
uint32 at_id = GetArenaTeamIdFromDB(playerguid,ARENA_TEAM_2v2);
if(at_id != 0)
{
ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
if(at)
at->DelMember(playerguid);
}
at_id = GetArenaTeamIdFromDB(playerguid,ARENA_TEAM_3v3);
if(at_id != 0)
{
ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
if(at)
at->DelMember(playerguid);
}
at_id = GetArenaTeamIdFromDB(playerguid,ARENA_TEAM_5v5);
if(at_id != 0)
{
ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
if(at)
at->DelMember(playerguid);
}
// the player was uninvited already on logout so just remove from group
QueryResult *resultGroup = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", guid);
if(resultGroup)
@ -7737,19 +7761,34 @@ void Player::SendInitWorldStates()
data << uint32(0xa5f) << uint32(0x0); // 35
break;
case 3698: // Nagrand Arena
data << uint32(0xa0f) << uint32(0x0); // 7
data << uint32(0xa10) << uint32(0x0); // 8
data << uint32(0xa11) << uint32(0x0); // 9
if (bg && bg->GetTypeID() == BATTLEGROUND_NA)
bg->FillInitialWorldStates(data);
else
{
data << uint32(0xa0f) << uint32(0x0); // 7
data << uint32(0xa10) << uint32(0x0); // 8
data << uint32(0xa11) << uint32(0x0); // 9 show
}
break;
case 3702: // Blade's Edge Arena
data << uint32(0x9f0) << uint32(0x0); // 7
data << uint32(0x9f1) << uint32(0x0); // 8
data << uint32(0x9f3) << uint32(0x0); // 9
if (bg && bg->GetTypeID() == BATTLEGROUND_BE)
bg->FillInitialWorldStates(data);
else
{
data << uint32(0x9f0) << uint32(0x0); // 7 gold
data << uint32(0x9f1) << uint32(0x0); // 8 green
data << uint32(0x9f3) << uint32(0x0); // 9 show
}
break;
case 3968: // Ruins of Lordaeron
data << uint32(0xbb8) << uint32(0x0); // 7
data << uint32(0xbb9) << uint32(0x0); // 8
data << uint32(0xbba) << uint32(0x0); // 9
if (bg && bg->GetTypeID() == BATTLEGROUND_RL)
bg->FillInitialWorldStates(data);
else
{
data << uint32(0xbb8) << uint32(0x0); // 7 gold
data << uint32(0xbb9) << uint32(0x0); // 8 green
data << uint32(0xbba) << uint32(0x0); // 9 show
}
break;
case 3703: // Shattrath City
break;
@ -13334,6 +13373,36 @@ void Player::_LoadDeclinedNames(QueryResult* result)
delete result;
}
void Player::_LoadArenaTeamInfo(QueryResult *result)
{
// arenateamid, played_week, played_season, personal_rating
memset((void*)&m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1], 0, sizeof(uint32)*18);
if (!result)
return;
do
{
Field *fields = result->Fetch();
uint32 arenateamid = fields[0].GetUInt32();
uint32 played_week = fields[1].GetUInt32();
uint32 played_season = fields[2].GetUInt32();
uint32 personal_rating = fields[3].GetUInt32();
ArenaTeam* aTeam = objmgr.GetArenaTeamById(arenateamid);
uint8 arenaSlot = aTeam->GetSlot();
m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 3] = arenateamid; // TeamID
m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 3 + 1] = ((aTeam->GetCaptain() == GetGUID()) ? (uint32)0 : (uint32)1); // Captain 0, member 1
m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 3 + 2] = played_week; // Played Week
m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 3 + 3] = played_season; // Played Season
m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 3 + 4] = 0; // Unk
m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 3 + 5] = personal_rating; // Personal Rating
}while (result->NextRow());
delete result;
}
bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid)
{
QueryResult *result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,taxi_path FROM characters WHERE guid = '%u'",GUID_LOPART(guid));
@ -13405,8 +13474,8 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
//// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32
//QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", guid);
//// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 33
//QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", guid);
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
if(!result)
@ -13496,6 +13565,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
_LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP));
_LoadArenaTeamInfo(holder->GetResult(PLAYER_LOGIN_QUERY_LOADARENAINFO));
uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[33].GetUInt32();
if (arena_currency > sWorld.getConfig(CONFIG_MAX_ARENA_POINTS))
arena_currency = sWorld.getConfig(CONFIG_MAX_ARENA_POINTS);
SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, arena_currency);
// check arena teams integrity
for(uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
{
@ -14818,8 +14895,10 @@ void Player::SaveToDB()
// first save/honor gain after midnight will also update the player's honor fields
UpdateHonorFields();
// Must saved before enter into BattleGround
if(InBattleGround())
// players aren't saved on battleground maps
uint32 mapid = IsBeingTeleported() ? GetTeleportDest().mapid : GetMapId();
const MapEntry * me = sMapStore.LookupEntry(mapid);
if(!me || me->IsBattleGroundOrArena())
return;
int is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0;
@ -14857,7 +14936,7 @@ void Player::SaveToDB()
"taximask, online, cinematic, "
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
"death_expire_time, taxi_path) VALUES ("
"death_expire_time, taxi_path, arena_pending_points) VALUES ("
<< GetGUIDLow() << ", "
<< GetSession()->GetAccountId() << ", '"
<< sql_name << "', "
@ -14956,7 +15035,7 @@ void Player::SaveToDB()
ss << ", '";
ss << m_taxi.SaveTaxiDestinationsToString();
ss << "' )";
ss << "', '0' )";
CharacterDatabase.Execute( ss.str().c_str() );
@ -17619,7 +17698,8 @@ bool Player::InArena() const
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;
@ -17657,6 +17737,11 @@ uint32 Player::GetBattleGroundQueueIdFromLevel() const
return 6;
else
return level/10 - 1; // 20..29 -> 1, 30-39 -> 2, ...
/*
assert(bgTypeId < MAX_BATTLEGROUND_TYPES);
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
assert(bg);
return (getLevel() - bg->GetMinLevel()) / 10;*/
}
float Player::GetReputationPriceDiscount( Creature const* pCreature ) const

View file

@ -809,9 +809,10 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS = 15,
PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 16,
PLAYER_LOGIN_QUERY_LOADGUILD = 17,
};
PLAYER_LOGIN_QUERY_LOADARENAINFO = 18,
#define MAX_PLAYER_LOGIN_QUERY 18
MAX_PLAYER_LOGIN_QUERY
};
// Player summoning auto-decline time (in secs)
#define MAX_PLAYER_SUMMON_DELAY (2*MINUTE)
@ -1517,7 +1518,6 @@ class MANGOS_DLL_SPEC Player : public Unit
void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot)
{
SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId);
SaveDataFieldToDB(); // needed?
}
uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6)); }
static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot);
@ -1804,24 +1804,32 @@ class MANGOS_DLL_SPEC Player : public Unit
static uint32 GetMaxLevelForBattleGroundQueueId(uint32 queue_id);
uint32 GetBattleGroundQueueIdFromLevel() const;
uint32 GetBattleGroundQueueId(uint32 index) const { return m_bgBattleGroundQueueID[index].bgType; }
uint32 GetBattleGroundQueueIndex(uint32 bgType) const
bool InBattleGroundQueue() const
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
if (m_bgBattleGroundQueueID[i].bgType == bgType)
if (m_bgBattleGroundQueueID[i].bgQueueType != 0)
return true;
return false;
}
uint32 GetBattleGroundQueueId(uint32 index) const { return m_bgBattleGroundQueueID[index].bgQueueType; }
uint32 GetBattleGroundQueueIndex(uint32 bgQueueType) const
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
if (m_bgBattleGroundQueueID[i].bgQueueType == bgQueueType)
return i;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool IsInvitedForBattleGroundType(uint32 bgType) const
bool IsInvitedForBattleGroundQueueType(uint32 bgQueueType) const
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
if (m_bgBattleGroundQueueID[i].bgType == bgType)
return m_bgBattleGroundQueueID[i].invited;
if (m_bgBattleGroundQueueID[i].bgQueueType == bgQueueType)
return m_bgBattleGroundQueueID[i].invitedToInstance != 0;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool InBattleGroundQueueForBattleGroundType(uint32 bgType) const
bool InBattleGroundQueueForBattleGroundQueueType(uint32 bgQueueType) const
{
return GetBattleGroundQueueIndex(bgType) < PLAYER_MAX_BATTLEGROUND_QUEUES;
return GetBattleGroundQueueIndex(bgQueueType) < PLAYER_MAX_BATTLEGROUND_QUEUES;
}
void SetBattleGroundId(uint32 val) { m_bgBattleGroundID = val; }
@ -1829,34 +1837,47 @@ class MANGOS_DLL_SPEC Player : public Unit
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
if (m_bgBattleGroundQueueID[i].bgType == 0 || m_bgBattleGroundQueueID[i].bgType == val)
if (m_bgBattleGroundQueueID[i].bgQueueType == 0 || m_bgBattleGroundQueueID[i].bgQueueType == val)
{
m_bgBattleGroundQueueID[i].bgType = val;
m_bgBattleGroundQueueID[i].invited = false;
m_bgBattleGroundQueueID[i].bgQueueType = val;
m_bgBattleGroundQueueID[i].invitedToInstance = 0;
return i;
}
}
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool HasFreeBattleGroundQueueId()
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
if (m_bgBattleGroundQueueID[i].bgQueueType == 0)
return true;
return false;
}
void RemoveBattleGroundQueueId(uint32 val)
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
if (m_bgBattleGroundQueueID[i].bgType == val)
if (m_bgBattleGroundQueueID[i].bgQueueType == val)
{
m_bgBattleGroundQueueID[i].bgType = 0;
m_bgBattleGroundQueueID[i].invited = false;
m_bgBattleGroundQueueID[i].bgQueueType = 0;
m_bgBattleGroundQueueID[i].invitedToInstance = 0;
return;
}
}
}
void SetInviteForBattleGroundType(uint32 bgType)
void SetInviteForBattleGroundQueueType(uint32 bgQueueType, uint32 instanceId)
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
if (m_bgBattleGroundQueueID[i].bgType == bgType)
m_bgBattleGroundQueueID[i].invited = true;
if (m_bgBattleGroundQueueID[i].bgQueueType == bgQueueType)
m_bgBattleGroundQueueID[i].invitedToInstance = instanceId;
}
bool IsInvitedForBattleGroundInstance(uint32 instanceId) const
{
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
if (m_bgBattleGroundQueueID[i].invitedToInstance == instanceId)
return true;
return false;
}
uint32 GetBattleGroundEntryPointMap() const { return m_bgEntryPointMap; }
float GetBattleGroundEntryPointX() const { return m_bgEntryPointX; }
float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; }
@ -2053,8 +2074,8 @@ class MANGOS_DLL_SPEC Player : public Unit
*/
struct BgBattleGroundQueueID_Rec
{
uint32 bgType;
bool invited;
uint32 bgQueueType;
uint32 invitedToInstance;
};
BgBattleGroundQueueID_Rec m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES];
uint32 m_bgEntryPointMap;
@ -2099,6 +2120,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void _LoadFriendList(QueryResult *result);
bool _LoadHomeBind(QueryResult *result);
void _LoadDeclinedNames(QueryResult *result);
void _LoadArenaTeamInfo(QueryResult *result);
/*********************************************************/
/*** SAVE SYSTEM ***/

View file

@ -2147,7 +2147,8 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
return;
// final heal
m_target->CastCustomSpell(m_target,33778,&m_modifier.m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
if(m_target->IsInWorld())
m_target->CastCustomSpell(m_target,33778,&m_modifier.m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
}
return;
}

View file

@ -2649,7 +2649,7 @@ void Spell::DoCreateItem(uint32 i, uint32 itemtype)
return;
}
if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
bg->SendRewardMarkByMail(player,newitemid,no_space);
}
}

View file

@ -605,25 +605,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
((Creature*)pVictim)->SetLootRecipient(this);
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
}
DEBUG_LOG("DealDamage: victim just died");
// find player: owner of controlled `this` or `this` itself maybe
@ -762,6 +743,19 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
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);
if(BattleGround *bg = killed->GetBattleGround())
if(player)
bg->HandleKillPlayer(killed, player);
//later we can add support for creature->player kills here i'm
//not sure, but i guess those kills also get counted in av
//else if(GetTypeId() == TYPEID_UNIT)
// bg->HandleKillPlayer(killed,(Creature*)this);
}
}
else // if (health <= damage)
{
@ -4173,6 +4167,22 @@ void Unit::RemoveAllAuras()
}
}
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->GetSpellProto()->AttributesEx4 & (1<<21)) // don't remove stances, shadowform, pally/hunter auras
&& !iter->second->IsPassive() // don't remove passive auras
&& (!(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) || !(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNK8)) // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable)
&& (iter->second->IsPositive() ^ onleave)) // remove positive buffs on enter, negative buffs on leave
RemoveAura(iter);
else
++iter;
}
}
void Unit::RemoveAllAurasOnDeath()
{
// used just after dieing to remove all visible auras

View file

@ -1012,6 +1012,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void RemoveAurasWithDispelType( DispelType type );
void RemoveAllAuras();
void RemoveArenaAuras(bool onleave = false);
void RemoveAllAurasOnDeath();
void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime);

View file

@ -891,6 +891,12 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25);
m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300);
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_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7);
m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
@ -1292,6 +1298,7 @@ void World::SetInitialWorldSettings()
///- 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..." );
@ -2169,7 +2176,7 @@ void World::ScriptsProcess()
void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
{
SessionMap::iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
itr->second->GetPlayer() &&
@ -2236,11 +2243,29 @@ void World::SendWorldText(int32 string_id, ...)
delete data_cache[i][j];
}
/// Send a System Message to all players (except self if mentioned)
void World::SendGlobalText(const char* text, WorldSession *self)
{
WorldPacket data;
// need copy to prevent corruption by strtok call in LineFromMessage original string
char* buf = strdup(text);
char* pos = buf;
while(char* line = ChatHandler::LineFromMessage(pos))
{
ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
SendGlobalMessage(&data, self);
}
free(buf);
}
/// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team)
{
SessionMap::iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
itr->second->GetPlayer() &&

View file

@ -176,6 +176,11 @@ enum WorldConfigs
CONFIG_LISTEN_RANGE_SAY,
CONFIG_LISTEN_RANGE_TEXTEMOTE,
CONFIG_LISTEN_RANGE_YELL,
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,
CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,
CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
CONFIG_VALUE_COUNT
};
@ -396,6 +401,7 @@ class World
void LoadConfigSettings(bool reload = false);
void SendWorldText(int32 string_id, ...);
void SendGlobalText(const char* text, WorldSession *self);
void SendGlobalMessage(WorldPacket *packet, WorldSession *self = 0, uint32 team = 0);
void SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self = 0, uint32 team = 0);
void SendZoneText(uint32 zone, const char *text, WorldSession *self = 0, uint32 team = 0);

View file

@ -177,11 +177,12 @@ class MANGOS_DLL_SPEC WorldSession
// Guild/Arena Team
void SendGuildCommandResult(uint32 typecmd, const std::string& str, uint32 cmdresult);
void SendArenaTeamCommandResult(uint32 unk1, const std::string& str1, const std::string& str2, uint32 unk3);
void SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id);
void BuildArenaTeamEventPacket(WorldPacket *data, uint8 eventid, uint8 str_count, const std::string& str1, const std::string& str2, const std::string& str3);
void SendNotInArenaTeamPacket(uint8 type);
void SendPetitionShowList( uint64 guid );
void SendSaveGuildEmblem( uint32 msg );
void SendBattleGroundOrArenaJoinError(uint8 err);
// Looking For Group
// TRUE values set by client sending CMSG_LFG_SET_AUTOJOIN and CMSG_LFM_CLEAR_AUTOFILL before player login

View file

@ -30,6 +30,7 @@
#include "GossipDef.h"
#include "Language.h"
#include "MapManager.h"
#include "BattleGroundMgr.h"
#include <fstream>
#include "ObjectMgr.h"
@ -518,3 +519,9 @@ bool ChatHandler::HandleGetItemState(const char* args)
return true;
}
bool ChatHandler::HandleDebugArenaCommand(const char * /*args*/)
{
sBattleGroundMgr.ToggleArenaTesting();
return true;
}

View file

@ -1074,6 +1074,48 @@ Death.SicknessLevel = 11
Death.CorpseReclaimDelay.PvP = 1
Death.CorpseReclaimDelay.PvE = 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 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
#
# AutoDistributeInterval: how often should the distribution take place
# if automatic distribution is enabled
# in days
# Default: 7 (weekly)
#
###################################################################################################################
Arena.MaxRatingDifference = 0
Arena.RatingDiscardTimer = 60000
Arena.AutoDistributePoints = 0
Arena.AutoDistributeInterval = 7
###################################################################################################################
#
# Battleground config
#
# PrematureFinishTimer: the time to end the bg if there are less than minplayersperteam on one side
# in milliseconds
# Default: 300000
# 0 - disable
#
###################################################################################################################
BattleGround.PrematureFinishTimer = 300000
###################################################################################################################
#
# NETWORK CONFIG

View file

@ -434,9 +434,10 @@ struct MapEntry
// Helpers
uint32 Expansion() const { return addon; }
bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
// NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; }
bool IsRaid() const { return map_type == MAP_RAID; }
bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; }
bool IsBattleArena() const { return map_type == MAP_ARENA; }

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "6909"
#define REVISION_NR "6910"
#endif // __REVISION_NR_H__