Code:
/*
* Ascent MMORPG Server
* Copyright (C) 2005-2008 Ascent Team <http://www.ascentcommunity.com/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "StdAfx.h"
#define ARENA_PREPARATION 32727
#define ARENA_WORLD_STATE_A_PLAYER_COUNT 2544
#define ARENA_WORLD_STATE_H_PLAYER_COUNT 2545
#define GREEN_TEAM 0
#define GOLD_TEAM 1
Arena::Arena(MapMgr * mgr, uint32 id, uint32 lgroup, uint32 t, uint32 players_per_side) : CBattleground(mgr, id, lgroup, t)
{
m_started = false;
m_playerCountPerTeam = players_per_side;
switch(t)
{
case BATTLEGROUND_ARENA_5V5:
m_arenateamtype=2;
break;
case BATTLEGROUND_ARENA_3V3:
m_arenateamtype=1;
break;
case BATTLEGROUND_ARENA_2V2:
m_arenateamtype=0;
break;
default:
m_arenateamtype=0;
break;
}
rated_match=false;
}
Arena::~Arena()
{
}
void Arena::OnAddPlayer(Player * plr)
{
if(!m_started && plr->IsInWorld())
{
/* cast arena readyness buff */
if(plr->isDead())
plr->ResurrectPlayer();
plr->SetUInt32Value(UNIT_FIELD_HEALTH, plr->GetUInt32Value(UNIT_FIELD_MAXHEALTH));
plr->SetUInt32Value(UNIT_FIELD_POWER1, plr->GetUInt32Value(UNIT_FIELD_MAXPOWER1));
plr->SetUInt32Value(UNIT_FIELD_POWER4, plr->GetUInt32Value(UNIT_FIELD_MAXPOWER4));
sEventMgr.AddEvent(plr, &Player::FullHPMP, EVENT_PLAYER_UPDATE, 500, 1, 0);
sEventMgr.AddEvent(plr, &Player::ResetAllCooldowns, EVENT_PLAYER_UPDATE, 500, 1, 0);
}
plr->m_deathVision = true;
// remove all buffs (exclude talents, include flasks)
for(uint32 x=0;x<MAX_AURAS;x++)
{
if(plr->m_auras[x])
{
if(plr->m_auras[x] && !plr->m_auras[x]->GetSpellProto()->durationIndex && plr->m_auras[x]->GetSpellProto()->attributesExC & ATTRIBUTESEXC_CAN_PERSIST_AND_CASTED_WHILE_DEAD)
continue;
else
{
plr->m_auras[x]->Remove();
}
}
}
plr->GetItemInterface()->RemoveAllConjured();
plr->ResetAllCooldowns();
if (plr->GetSummon() != NULL)
plr->GetSummon()->Dismiss(false);
if( !m_started )
plr->CastSpell(plr, ARENA_PREPARATION, true);
UpdatePlayerCounts();
/* Add the green/gold team flag */
Aura * aura = new Aura(dbcSpell.LookupEntry(32725-plr->m_bgTeam), -1, plr, plr);
plr->AddAura(aura, NULL);
/* Set FFA PvP Flag */
if(!plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAG_FREE_FOR_ALL_PVP))
plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAG_FREE_FOR_ALL_PVP);
/* update arena team stats */
if(rated_match && plr->m_arenaTeams[m_arenateamtype] != NULL)
{
ArenaTeam * t = plr->m_arenaTeams[m_arenateamtype];
ArenaTeamMember * tp = t->GetMember(plr->m_playerInfo);
if(doneteams.find(t) == doneteams.end())
{
t->m_stat_gamesplayedseason++;
t->m_stat_gamesplayedweek++;
doneteams.insert(t);
}
if(tp != NULL)
{
tp->Played_ThisWeek++;
tp->Played_ThisSeason++;
}
t->SaveToDB();
}
}
void Arena::OnRemovePlayer(Player * plr)
{
/* remove arena readyness buff */
plr->m_deathVision = false;
plr->RemoveAura(ARENA_PREPARATION);
UpdatePlayerCounts();
plr->RemoveAura(32725-plr->m_bgTeam);
if(plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAG_FREE_FOR_ALL_PVP))
plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_FREE_FOR_ALL_PVP);
}
void Arena::HookOnPlayerKill(Player * plr, Unit * pVictim)
{
plr->m_bgScore.KillingBlows++;
UpdatePlayerCounts();
}
void Arena::HookOnHK(Player * plr)
{
plr->m_bgScore.HonorableKills++;
}
void Arena::HookOnPlayerDeath(Player * plr)
{
}
void Arena::OnCreate()
{
GameObject * obj;
switch(m_mapMgr->GetMapId())
{
/* loraedeon */
case 572: {
obj = SpawnGameObject(185917, 572, 1278.647705f, 1730.556641f, 31.605574f, 1.684245f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.746058f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, 0.665881f);
m_gates.insert(obj);
obj = SpawnGameObject(185918, 572, 1293.560791f, 1601.937988f, 31.605574f, -1.457349f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, -0.665881f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, 0.746058f);
m_gates.insert(obj);
}break;
/* blades edge arena */
case 562: {
obj = SpawnGameObject(183972, 562, 6177.707520f, 227.348145f, 3.604374f, -2.260201f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.90445f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, -0.426569f);
obj->PushToWorld(m_mapMgr);
obj = SpawnGameObject(183973, 562, 6189.546387f, 241.709854f, 3.101481f, 0.881392f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.426569f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, 0.904455f);
m_gates.insert(obj);
obj = SpawnGameObject(183970, 562, 6299.115723f, 296.549438f, 3.308032f, 0.881392f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.426569f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, 0.904455f);
obj->PushToWorld(m_mapMgr);
obj = SpawnGameObject(183971, 562, 6287.276855f, 282.187714f, 3.810925f, -2.260201f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.904455f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, -0.426569f);
m_gates.insert(obj);
}break;
/* nagrand arena */
case 559: {
obj = SpawnGameObject(183979, 559, 4090.064453f, 2858.437744f, 10.236313f, 0.492805f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.243916f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, 0.969796f);
obj->PushToWorld(m_mapMgr);
obj = SpawnGameObject(183980, 559, 4081.178955f, 2874.970459f, 12.391714f, 0.492805f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.243916f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, 0.969796f);
m_gates.insert(obj);
obj = SpawnGameObject(183977, 559, 4023.709473f, 2981.776611f, 10.701169f, -2.648788f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.969796f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, -0.243916f);
obj->PushToWorld(m_mapMgr);
obj = SpawnGameObject(183978, 559, 4031.854248f, 2966.833496f, 12.646200f, -2.648788f, 32, 1375, 1.0f);
obj->SetUInt32Value(GAMEOBJECT_STATE, 1);
obj->SetFloatValue(GAMEOBJECT_ROTATION_02, 0.969796f);
obj->SetFloatValue(GAMEOBJECT_ROTATION_03, -0.243916f);
m_gates.insert(obj);
}break;
}
/* push gates into world */
for(set<GameObject*>::iterator itr = m_gates.begin(); itr != m_gates.end(); ++itr)
(*itr)->PushToWorld(m_mapMgr);
SetWorldState(0x08D4 ,0x0000);
SetWorldState(0x08D8 ,0x0000);
SetWorldState(0x08D7 ,0x0000);
SetWorldState(0x08D6 ,0x0000);
SetWorldState(0x08D5 ,0x0000);
SetWorldState(0x08D3 ,0x0000);
SetWorldState(0x09F1 ,0x0000);
SetWorldState(0x09F0 ,0x0000);
SetWorldState(0x0C0D ,0x017B);
SetWorldState(0x09F3 ,0x0001);
}
void Arena::OnStart()
{
/* remove arena readyness buff */
for(uint32 i = 0; i < 2; ++i) {
for(set<Player*>::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) {
(*itr)->RemoveAura(ARENA_PREPARATION);
}
}
/* open gates */
for(set<GameObject*>::iterator itr = m_gates.begin(); itr != m_gates.end(); ++itr)
{
(*itr)->SetUInt32Value(GAMEOBJECT_FLAGS, 64);
(*itr)->SetUInt32Value(GAMEOBJECT_STATE, 0);
}
m_started = true;
/* Incase all players left */
UpdatePlayerCounts();
}
void Arena::UpdatePlayerCounts()
{
if(m_ended)
return;
uint32 players[2] = {0,0};
for(uint32 i = 0; i < 2; ++i) {
for(set<Player*>::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) {
if((*itr)->isAlive())
players[i]++;
}
}
SetWorldState(ARENA_WORLD_STATE_A_PLAYER_COUNT, players[0]);
SetWorldState(ARENA_WORLD_STATE_H_PLAYER_COUNT, players[1]);
if(!m_started)
return;
if(players[1] == 0)
m_winningteam = 0;
else if(players[0] == 0)
m_winningteam = 1;
else
return;
Finish();
}
void Arena::Finish()
{
m_ended = true;
m_nextPvPUpdateTime = 0;
UpdatePvPData();
PlaySoundToAll(m_winningteam ? SOUND_ALLIANCEWINS : SOUND_HORDEWINS);
sEventMgr.RemoveEvents(this, EVENT_BATTLEGROUND_CLOSE);
sEventMgr.AddEvent(((CBattleground*)this), &CBattleground::Close, EVENT_BATTLEGROUND_CLOSE, 120000, 1,0);
/* update arena team stats */
doneteams.clear();
if(rated_match)
{
uint32 averageRating[2] = {0,0};
for(uint32 i = 0; i < 2; ++i) {
uint32 teamCount = 0;
for(set<Player*>::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
{
Player * plr = *itr;
if(plr->m_arenaTeams[m_arenateamtype] != NULL)
{
ArenaTeam * t = plr->m_arenaTeams[m_arenateamtype];
if(doneteams.find(t) == doneteams.end())
{
averageRating[i] += t->m_stat_rating;
teamCount++;
doneteams.insert(t);
}
}
}
if(teamCount)
averageRating[i] /= teamCount;
}
doneteams.clear();
for (uint32 i = 0; i < 2; ++i) {
uint32 j = i ? 0 : 1; // opposing side
bool outcome;
outcome = (i == m_winningteam);
// ---- Elo Rating System ----
// Expected Chance to Win for Team A vs Team B
// 1
// -------------------------------------------
// (PB - PA)/400
// 1 + 10
double power = (int)(averageRating[j] - averageRating[i]) / 400.0f;
double divisor = pow(((double)(10.0)), power);
divisor += 1.0;
double winChance = 1.0 / divisor;
for(set<Player*>::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
{
Player * plr = *itr;
if(plr->m_arenaTeams[m_arenateamtype] != NULL)
{
ArenaTeam * t = plr->m_arenaTeams[m_arenateamtype];
ArenaTeamMember * tp = t->GetMember(plr->m_playerInfo);
if(doneteams.find(t) == doneteams.end())
{
if (outcome)
{
t->m_stat_gameswonseason++;
t->m_stat_gameswonweek++;
}
// New Rating Calculation via Elo
// New Rating = Old Rating + K * (outcome - Expected Win Chance)
// outcome = 1 for a win and 0 for a loss (0.5 for a draw ... but we cant have that)
// K is the maximum possible change
// Through investigation, K was estimated to be 32 (same as chess)
double multiplier = (outcome ? 1.0 : 0.0) - winChance;
double deltaRating = 32.0 * multiplier;
if ( deltaRating < 0 && (-1.0 * deltaRating) > t->m_stat_rating )
t->m_stat_rating = 0;
else
t->m_stat_rating += long2int32(deltaRating);
objmgr.UpdateArenaTeamRankings();
doneteams.insert(t);
}
if(tp != NULL && outcome)
{
tp->Won_ThisWeek++;
tp->Won_ThisSeason++;
}
t->SaveToDB();
}
}
}
}
for(int i = 0; i < 2; i++)
{
bool victorious = (i == m_winningteam);
set<Player*>::iterator itr = m_players[i].begin();
for(; itr != m_players[i].end(); itr++)
{
Player * plr = (Player *)(*itr);
sHookInterface.OnArenaFinish(plr, plr->m_arenaTeams[m_arenateamtype], victorious, rated_match);
}
}
}
LocationVector Arena::GetStartingCoords(uint32 Team)
{
// 559, 562, 572
/*
A start
H start
Repop
572 1295.322388 1585.953369 31.605387
572 1277.105103 1743.956177 31.603209
572 1286.112061 1668.334961 39.289127
562 6184.806641 236.643463 5.037095
562 6292.032227 287.570343 5.003577
562 6241.171875 261.067322 0.891833
559 4085.861328 2866.750488 12.417445
559 4027.004883 2976.964844 11.600499
559 4057.042725 2918.686523 13.051933
*/
switch(m_mapMgr->GetMapId())
{
/* loraedeon */
case 572:
{
if(Team)
return LocationVector(1277.105103f, 1743.956177f, 31.603209f);
else
return LocationVector(1295.322388f, 1585.953369f, 31.605387f);
}break;
/* blades edge arena */
case 562:
{
if(Team)
return LocationVector(6292.032227f, 287.570343f, 5.003577f);
else
return LocationVector(6184.806641f, 236.643463f, 5.037095f);
}break;
/* nagrand arena */
case 559:
{
if(Team)
return LocationVector(4027.004883f, 2976.964844f, 11.600499f);
else
return LocationVector(4085.861328f, 2866.750488f, 12.417445f);
}break;
}
return LocationVector(0,0,0,0);
}
bool Arena::HookHandleRepop(Player * plr)
{
// 559, 562, 572
/*
A start
H start
Repop
572 1295.322388 1585.953369 31.605387
572 1277.105103 1743.956177 31.603209
572 1286.112061 1668.334961 39.289127
562 6184.806641 236.643463 5.037095
562 6292.032227 287.570343 5.003577
562 6241.171875 261.067322 0.891833
559 4085.861328 2866.750488 12.417445
559 4027.004883 2976.964844 11.600499
559 4057.042725 2918.686523 13.051933
*/
LocationVector dest(0,0,0,0);
switch(m_mapMgr->GetMapId())
{
/* loraedeon */
case 572: {
dest.ChangeCoords(1286.112061f, 1668.334961f, 39.289127f);
}break;
/* blades edge arena */
case 562: {
dest.ChangeCoords(6241.171875f, 261.067322f, 0.891833f);
}break;
/* nagrand arena */
case 559: {
dest.ChangeCoords(4057.042725f, 2918.686523f, 13.051933f);
}break;
}
plr->SafeTeleport(m_mapMgr->GetMapId(), m_mapMgr->GetInstanceID(), dest);
return true;
}
void Arena::HookOnAreaTrigger(Player * plr, uint32 id)
{
}
void Player::FullHPMP()
{
if(isDead())
ResurrectPlayer();
SetUInt32Value(UNIT_FIELD_HEALTH, GetUInt32Value(UNIT_FIELD_MAXHEALTH));
SetUInt32Value(UNIT_FIELD_POWER1, GetUInt32Value(UNIT_FIELD_MAXPOWER1));
SetUInt32Value(UNIT_FIELD_POWER4, GetUInt32Value(UNIT_FIELD_MAXPOWER4));
}