Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class Arena : Battleground
|
||||
{
|
||||
public Arena()
|
||||
{
|
||||
StartDelayTimes[BattlegroundConst.EventIdFirst] = BattlegroundStartTimeIntervals.Delay1m;
|
||||
StartDelayTimes[BattlegroundConst.EventIdSecond] = BattlegroundStartTimeIntervals.Delay30s;
|
||||
StartDelayTimes[BattlegroundConst.EventIdThird] = BattlegroundStartTimeIntervals.Delay15s;
|
||||
StartDelayTimes[BattlegroundConst.EventIdFourth] = BattlegroundStartTimeIntervals.None;
|
||||
|
||||
StartMessageIds[BattlegroundConst.EventIdFirst] = CypherStrings.ArenaOneMinute;
|
||||
StartMessageIds[BattlegroundConst.EventIdSecond] = CypherStrings.ArenaThirtySeconds;
|
||||
StartMessageIds[BattlegroundConst.EventIdThird] = CypherStrings.ArenaFifteenSeconds;
|
||||
StartMessageIds[BattlegroundConst.EventIdFourth] = CypherStrings.ArenaHasBegun;
|
||||
}
|
||||
|
||||
public override void AddPlayer(Player player)
|
||||
{
|
||||
base.AddPlayer(player);
|
||||
PlayerScores[player.GetGUID()] = new ArenaScore(player.GetGUID(), player.GetBGTeam());
|
||||
|
||||
if (player.GetBGTeam() == Team.Alliance) // gold
|
||||
{
|
||||
if (player.GetTeam() == Team.Horde)
|
||||
player.CastSpell(player, ArenaSpellIds.HordeGoldFlag, true);
|
||||
else
|
||||
player.CastSpell(player, ArenaSpellIds.AllianceGoldFlag, true);
|
||||
}
|
||||
else // green
|
||||
{
|
||||
if (player.GetTeam() == Team.Horde)
|
||||
player.CastSpell(player, ArenaSpellIds.HordeGreenFlag, true);
|
||||
else
|
||||
player.CastSpell(player, ArenaSpellIds.AllianceGreenFlag, true);
|
||||
}
|
||||
|
||||
UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
public override void RemovePlayer(Player player, ObjectGuid guid, Team team)
|
||||
{
|
||||
if (GetStatus() == BattlegroundStatus.WaitLeave)
|
||||
return;
|
||||
|
||||
UpdateArenaWorldState();
|
||||
CheckWinConditions();
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(ArenaWorldStates.AlivePlayersGreen, (int)GetAlivePlayersCountByTeam(Team.Horde));
|
||||
packet.AddState(ArenaWorldStates.AlivePlayersGold, (int)GetAlivePlayersCountByTeam(Team.Alliance));
|
||||
}
|
||||
|
||||
void UpdateArenaWorldState()
|
||||
{
|
||||
UpdateWorldState(ArenaWorldStates.AlivePlayersGreen, GetAlivePlayersCountByTeam(Team.Horde));
|
||||
UpdateWorldState(ArenaWorldStates.AlivePlayersGold, GetAlivePlayersCountByTeam(Team.Alliance));
|
||||
}
|
||||
|
||||
public override void HandleKillPlayer(Player victim, Player killer)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
base.HandleKillPlayer(victim, killer);
|
||||
|
||||
UpdateArenaWorldState();
|
||||
CheckWinConditions();
|
||||
}
|
||||
|
||||
public override void BuildPvPLogDataPacket(out PVPLogData pvpLogData)
|
||||
{
|
||||
base.BuildPvPLogDataPacket(out pvpLogData);
|
||||
|
||||
if (isRated())
|
||||
{
|
||||
pvpLogData.Ratings.HasValue = true;
|
||||
|
||||
for (byte i = 0; i < SharedConst.BGTeamsCount; ++i)
|
||||
{
|
||||
pvpLogData.Ratings.Value.Postmatch[i] = _arenaTeamScores[i].PostMatchRating;
|
||||
pvpLogData.Ratings.Value.Prematch[i] = _arenaTeamScores[i].PreMatchRating;
|
||||
pvpLogData.Ratings.Value.PrematchMMR[i] = _arenaTeamScores[i].PreMatchMMR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool SendPacket)
|
||||
{
|
||||
if (isRated() && GetStatus() == BattlegroundStatus.InProgress)
|
||||
{
|
||||
var bgPlayer = GetPlayers().LookupByKey(guid);
|
||||
if (bgPlayer != null) // check if the player was a participant of the match, or only entered through gm command (appear)
|
||||
{
|
||||
// if the player was a match participant, calculate rating
|
||||
|
||||
ArenaTeam winnerArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(bgPlayer.Team)));
|
||||
ArenaTeam loserArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(bgPlayer.Team));
|
||||
|
||||
// left a rated match while the encounter was in progress, consider as loser
|
||||
if (winnerArenaTeam != null && loserArenaTeam != null && winnerArenaTeam != loserArenaTeam)
|
||||
{
|
||||
Player player = _GetPlayer(guid, bgPlayer.OfflineRemoveTime != 0, "Arena.RemovePlayerAtLeave");
|
||||
if (player)
|
||||
loserArenaTeam.MemberLost(player, GetArenaMatchmakerRating(GetOtherTeam(bgPlayer.Team)));
|
||||
else
|
||||
loserArenaTeam.OfflineMemberLost(guid, GetArenaMatchmakerRating(GetOtherTeam(bgPlayer.Team)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove player
|
||||
base.RemovePlayerAtLeave(guid, Transport, SendPacket);
|
||||
}
|
||||
|
||||
public override void CheckWinConditions()
|
||||
{
|
||||
if (GetAlivePlayersCountByTeam(Team.Alliance) == 0 && GetPlayersCountByTeam(Team.Horde) != 0)
|
||||
EndBattleground(Team.Horde);
|
||||
else if (GetPlayersCountByTeam(Team.Alliance) != 0 && GetAlivePlayersCountByTeam(Team.Horde) == 0)
|
||||
EndBattleground(Team.Alliance);
|
||||
}
|
||||
|
||||
public override void EndBattleground(Team winner)
|
||||
{
|
||||
// arena rating calculation
|
||||
if (isRated())
|
||||
{
|
||||
uint loserTeamRating = 0;
|
||||
uint loserMatchmakerRating = 0;
|
||||
int loserChange = 0;
|
||||
int loserMatchmakerChange = 0;
|
||||
uint winnerTeamRating = 0;
|
||||
uint winnerMatchmakerRating = 0;
|
||||
int winnerChange = 0;
|
||||
int winnerMatchmakerChange = 0;
|
||||
bool guildAwarded = false;
|
||||
|
||||
// In case of arena draw, follow this logic:
|
||||
// winnerArenaTeam => ALLIANCE, loserArenaTeam => HORDE
|
||||
ArenaTeam winnerArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner == 0 ? Team.Alliance : winner));
|
||||
ArenaTeam loserArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner == 0 ? Team.Horde : GetOtherTeam(winner)));
|
||||
|
||||
if (winnerArenaTeam != null && loserArenaTeam != null && winnerArenaTeam != loserArenaTeam)
|
||||
{
|
||||
// In case of arena draw, follow this logic:
|
||||
// winnerMatchmakerRating => ALLIANCE, loserMatchmakerRating => HORDE
|
||||
loserTeamRating = loserArenaTeam.GetRating();
|
||||
loserMatchmakerRating = GetArenaMatchmakerRating(winner == 0 ? Team.Horde : GetOtherTeam(winner));
|
||||
winnerTeamRating = winnerArenaTeam.GetRating();
|
||||
winnerMatchmakerRating = GetArenaMatchmakerRating(winner == 0 ? Team.Alliance : winner);
|
||||
|
||||
if (winner != 0)
|
||||
{
|
||||
winnerMatchmakerChange = winnerArenaTeam.WonAgainst(winnerMatchmakerRating, loserMatchmakerRating, ref winnerChange);
|
||||
loserMatchmakerChange = loserArenaTeam.LostAgainst(loserMatchmakerRating, winnerMatchmakerRating, ref loserChange);
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "match Type: {0} --- Winner: old rating: {1}, rating gain: {2}, old MMR: {3}, MMR gain: {4} --- Loser: old rating: {5}, " +
|
||||
"rating loss: {6}, old MMR: {7}, MMR loss: {8} ---", GetArenaType(), winnerTeamRating, winnerChange, winnerMatchmakerRating, winnerMatchmakerChange,
|
||||
loserTeamRating, loserChange, loserMatchmakerRating, loserMatchmakerChange);
|
||||
|
||||
SetArenaMatchmakerRating(winner, (uint)(winnerMatchmakerRating + winnerMatchmakerChange));
|
||||
SetArenaMatchmakerRating(GetOtherTeam(winner), (uint)(loserMatchmakerRating + loserMatchmakerChange));
|
||||
|
||||
// bg team that the client expects is different to TeamId
|
||||
// alliance 1, horde 0
|
||||
byte winnerTeam = (byte)(winner == Team.Alliance ? BattlegroundTeamId.Alliance : BattlegroundTeamId.Horde);
|
||||
byte loserTeam = (byte)(winner == Team.Alliance ? BattlegroundTeamId.Horde : BattlegroundTeamId.Alliance);
|
||||
|
||||
_arenaTeamScores[winnerTeam].Assign(winnerTeamRating, (uint)(winnerTeamRating + winnerChange), winnerMatchmakerRating, GetArenaMatchmakerRating(winner));
|
||||
_arenaTeamScores[loserTeam].Assign(loserTeamRating, (uint)(loserTeamRating + loserChange), loserMatchmakerRating, GetArenaMatchmakerRating(GetOtherTeam(winner)));
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "Arena match Type: {0} for Team1Id: {1} - Team2Id: {2} ended. WinnerTeamId: {3}. Winner rating: +{4}, Loser rating: {5}",
|
||||
GetArenaType(), GetArenaTeamIdByIndex(TeamId.Alliance), GetArenaTeamIdByIndex(TeamId.Horde), winnerArenaTeam.GetId(), winnerChange, loserChange);
|
||||
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.ArenaLogExtendedInfo))
|
||||
{
|
||||
foreach (var score in PlayerScores)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(score.Key);
|
||||
if (player)
|
||||
{
|
||||
Log.outDebug(LogFilter.Arena, "Statistics match Type: {0} for {1} (GUID: {2}, Team: {3}, IP: {4}): {5}",
|
||||
GetArenaType(), player.GetName(), score.Key, player.GetArenaTeamId((byte)(GetArenaType() == ArenaTypes.Team5v5 ? 2 : (GetArenaType() == ArenaTypes.Team3v3 ? 1 : 0))),
|
||||
player.GetSession().GetRemoteAddress(), score.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes
|
||||
else
|
||||
{
|
||||
_arenaTeamScores[(int)BattlegroundTeamId.Alliance].Assign(winnerTeamRating, (uint)(winnerTeamRating + SharedConst.ArenaTimeLimitPointsLoss), winnerMatchmakerRating, GetArenaMatchmakerRating(Team.Alliance));
|
||||
_arenaTeamScores[(int)BattlegroundTeamId.Horde].Assign(loserTeamRating, (uint)(loserTeamRating + SharedConst.ArenaTimeLimitPointsLoss), loserMatchmakerRating, GetArenaMatchmakerRating(Team.Horde));
|
||||
|
||||
winnerArenaTeam.FinishGame(SharedConst.ArenaTimeLimitPointsLoss);
|
||||
loserArenaTeam.FinishGame(SharedConst.ArenaTimeLimitPointsLoss);
|
||||
}
|
||||
|
||||
uint aliveWinners = GetAlivePlayersCountByTeam(winner);
|
||||
foreach (var pair in GetPlayers())
|
||||
{
|
||||
Team team = pair.Value.Team;
|
||||
|
||||
if (pair.Value.OfflineRemoveTime != 0)
|
||||
{
|
||||
// if rated arena match - make member lost!
|
||||
if (team == winner)
|
||||
winnerArenaTeam.OfflineMemberLost(pair.Key, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
else
|
||||
{
|
||||
if (winner == 0)
|
||||
winnerArenaTeam.OfflineMemberLost(pair.Key, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
|
||||
loserArenaTeam.OfflineMemberLost(pair.Key, winnerMatchmakerRating, loserMatchmakerChange);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Player player = _GetPlayer(pair.Key, pair.Value.OfflineRemoveTime != 0, "Arena.EndBattleground");
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
// per player calculation
|
||||
if (team == winner)
|
||||
{
|
||||
// update achievement BEFORE personal rating update
|
||||
uint rating = player.GetArenaPersonalRating(winnerArenaTeam.GetSlot());
|
||||
player.UpdateCriteria(CriteriaTypes.WinRatedArena, rating != 0 ? rating : 1);
|
||||
player.UpdateCriteria(CriteriaTypes.WinRatedArena, GetMapId());
|
||||
|
||||
// Last standing - Rated 5v5 arena & be solely alive player
|
||||
if (GetArenaType() == ArenaTypes.Team5v5 && aliveWinners == 1 && player.IsAlive())
|
||||
player.CastSpell(player, ArenaSpellIds.LastManStanding, true);
|
||||
|
||||
if (!guildAwarded)
|
||||
{
|
||||
guildAwarded = true;
|
||||
ulong guildId = GetBgMap().GetOwnerGuildId(player.GetBGTeam());
|
||||
if (guildId != 0)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(guildId);
|
||||
if (guild)
|
||||
guild.UpdateCriteria(CriteriaTypes.WinRatedArena, Math.Max(winnerArenaTeam.GetRating(), 1), 0, 0, null, player);
|
||||
}
|
||||
}
|
||||
|
||||
winnerArenaTeam.MemberWon(player, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (winner == 0)
|
||||
winnerArenaTeam.MemberLost(player, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
|
||||
loserArenaTeam.MemberLost(player, winnerMatchmakerRating, loserMatchmakerChange);
|
||||
|
||||
// Arena lost => reset the win_rated_arena having the "no_lose" condition
|
||||
player.ResetCriteria(CriteriaTypes.WinRatedArena, (uint)CriteriaCondition.NoLose);
|
||||
}
|
||||
}
|
||||
|
||||
// save the stat changes
|
||||
winnerArenaTeam.SaveToDB();
|
||||
loserArenaTeam.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
|
||||
winnerArenaTeam.NotifyStatsChanged();
|
||||
loserArenaTeam.NotifyStatsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// end Battleground
|
||||
base.EndBattleground(winner);
|
||||
}
|
||||
|
||||
public ArenaTeamScore[] _arenaTeamScores = new ArenaTeamScore[SharedConst.BGTeamsCount];
|
||||
}
|
||||
|
||||
struct ArenaWorldStates
|
||||
{
|
||||
public const uint AlivePlayersGreen = 3600;
|
||||
public const uint AlivePlayersGold = 3601;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class ArenaScore : BattlegroundScore
|
||||
{
|
||||
public ArenaScore(ObjectGuid playerGuid, Team team) : base(playerGuid, team)
|
||||
{
|
||||
TeamId = (int)(team == Team.Alliance ? BattlegroundTeamId.Alliance : BattlegroundTeamId.Horde);
|
||||
}
|
||||
|
||||
public override void BuildPvPLogPlayerDataPacket(out PVPLogData.PlayerData playerData)
|
||||
{
|
||||
base.BuildPvPLogPlayerDataPacket(out playerData);
|
||||
|
||||
if (PreMatchRating != 0)
|
||||
playerData.PreMatchRating.Set(PreMatchRating);
|
||||
|
||||
if (PostMatchRating != PreMatchRating)
|
||||
playerData.RatingChange.Set((int)(PostMatchRating - PreMatchRating));
|
||||
|
||||
if (PreMatchMMR != 0)
|
||||
playerData.PreMatchMMR.Set(PreMatchMMR);
|
||||
|
||||
if (PostMatchMMR != PreMatchMMR)
|
||||
playerData.MmrChange.Set((int)(PostMatchMMR - PreMatchMMR));
|
||||
}
|
||||
|
||||
// For Logging purpose
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Damage done: {DamageDone} Healing done: {HealingDone} Killing blows: {KillingBlows} PreMatchRating: {PreMatchRating} " +
|
||||
$"PreMatchMMR: {PreMatchMMR} PostMatchRating: {PostMatchRating} PostMatchMMR: {PostMatchMMR}";
|
||||
}
|
||||
|
||||
uint PreMatchRating;
|
||||
uint PreMatchMMR;
|
||||
uint PostMatchRating;
|
||||
uint PostMatchMMR;
|
||||
}
|
||||
|
||||
public class ArenaTeamScore
|
||||
{
|
||||
public void Assign(uint preMatchRating, uint postMatchRating, uint preMatchMMR, uint postMatchMMR)
|
||||
{
|
||||
PreMatchRating = preMatchRating;
|
||||
PostMatchRating = postMatchRating;
|
||||
PreMatchMMR = preMatchMMR;
|
||||
PostMatchMMR = postMatchMMR;
|
||||
}
|
||||
|
||||
public uint PreMatchRating;
|
||||
public uint PostMatchRating;
|
||||
public uint PreMatchMMR;
|
||||
public uint PostMatchMMR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,871 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class ArenaTeam
|
||||
{
|
||||
public ArenaTeam()
|
||||
{
|
||||
stats.Rating = (ushort)WorldConfig.GetIntValue(WorldCfg.ArenaStartRating);
|
||||
}
|
||||
|
||||
public bool Create(ObjectGuid captainGuid, byte _type, string arenaTeamName, uint backgroundColor, byte emblemStyle, uint emblemColor, byte borderStyle, uint borderColor)
|
||||
{
|
||||
// Check if captain is present
|
||||
if (!Global.ObjAccessor.FindPlayer(captainGuid))
|
||||
return false;
|
||||
|
||||
// Check if arena team name is already taken
|
||||
if (Global.ArenaTeamMgr.GetArenaTeamByName(arenaTeamName) != null)
|
||||
return false;
|
||||
|
||||
// Generate new arena team id
|
||||
teamId = Global.ArenaTeamMgr.GenerateArenaTeamId();
|
||||
|
||||
// Assign member variables
|
||||
CaptainGuid = captainGuid;
|
||||
type = _type;
|
||||
TeamName = arenaTeamName;
|
||||
BackgroundColor = backgroundColor;
|
||||
EmblemStyle = emblemStyle;
|
||||
EmblemColor = emblemColor;
|
||||
BorderStyle = borderStyle;
|
||||
BorderColor = borderColor;
|
||||
ulong captainLowGuid = captainGuid.GetCounter();
|
||||
|
||||
// Save arena team to db
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ARENA_TEAM);
|
||||
stmt.AddValue(0, teamId);
|
||||
stmt.AddValue(1, TeamName);
|
||||
stmt.AddValue(2, captainLowGuid);
|
||||
stmt.AddValue(3, type);
|
||||
stmt.AddValue(4, stats.Rating);
|
||||
stmt.AddValue(5, BackgroundColor);
|
||||
stmt.AddValue(6, EmblemStyle);
|
||||
stmt.AddValue(7, EmblemColor);
|
||||
stmt.AddValue(8, BorderStyle);
|
||||
stmt.AddValue(9, BorderColor);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
// Add captain as member
|
||||
AddMember(CaptainGuid);
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "New ArenaTeam created Id: {0}, Name: {1} Type: {2} Captain low GUID: {3}", GetId(), GetName(), GetArenaType(), captainLowGuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddMember(ObjectGuid playerGuid)
|
||||
{
|
||||
string playerName;
|
||||
Class playerClass;
|
||||
|
||||
// Check if arena team is full (Can't have more than type * 2 players)
|
||||
if (GetMembersSize() >= GetArenaType() * 2)
|
||||
return false;
|
||||
|
||||
// Get player name and class either from db or ObjectMgr
|
||||
CharacterInfo characterInfo;
|
||||
Player player = Global.ObjAccessor.FindPlayer(playerGuid);
|
||||
if (player)
|
||||
{
|
||||
playerClass = player.GetClass();
|
||||
playerName = player.GetName();
|
||||
}
|
||||
else if ((characterInfo = Global.WorldMgr.GetCharacterInfo(playerGuid)) != null)
|
||||
{
|
||||
playerName = characterInfo.Name;
|
||||
playerClass = characterInfo.ClassID;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
// Check if player is already in a similar arena team
|
||||
if ((player && player.GetArenaTeamId(GetSlot()) != 0) || Player.GetArenaTeamIdFromDB(playerGuid, GetArenaType()) != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Arena, "Arena: {0} {1} already has an arena team of type {2}", playerGuid.ToString(), playerName, GetArenaType());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set player's personal rating
|
||||
uint personalRating = 0;
|
||||
|
||||
if (WorldConfig.GetIntValue(WorldCfg.ArenaStartPersonalRating) > 0)
|
||||
personalRating = WorldConfig.GetUIntValue(WorldCfg.ArenaStartPersonalRating);
|
||||
else if (GetRating() >= 1000)
|
||||
personalRating = 1000;
|
||||
|
||||
// Try to get player's match maker rating from db and fall back to config setting if not found
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MATCH_MAKER_RATING);
|
||||
stmt.AddValue(0, playerGuid.GetCounter());
|
||||
stmt.AddValue(1, GetSlot());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
uint matchMakerRating;
|
||||
if (!result.IsEmpty())
|
||||
matchMakerRating = result.Read<ushort>(0);
|
||||
else
|
||||
matchMakerRating = WorldConfig.GetUIntValue(WorldCfg.ArenaStartMatchmakerRating);
|
||||
|
||||
// Remove all player signatures from other petitions
|
||||
// This will prevent player from joining too many arena teams and corrupt arena team data integrity
|
||||
//Player.RemovePetitionsAndSigns(playerGuid, GetArenaType());
|
||||
|
||||
// Feed data to the struct
|
||||
ArenaTeamMember newMember = new ArenaTeamMember();
|
||||
newMember.Name = playerName;
|
||||
newMember.Guid = playerGuid;
|
||||
newMember.Class = (byte)playerClass;
|
||||
newMember.SeasonGames = 0;
|
||||
newMember.WeekGames = 0;
|
||||
newMember.SeasonWins = 0;
|
||||
newMember.WeekWins = 0;
|
||||
newMember.PersonalRating = (ushort)(uint)0;
|
||||
newMember.MatchMakerRating = (ushort)matchMakerRating;
|
||||
|
||||
Members.Add(newMember);
|
||||
|
||||
// Save player's arena team membership to db
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ARENA_TEAM_MEMBER);
|
||||
stmt.AddValue(0, teamId);
|
||||
stmt.AddValue(1, playerGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
// Inform player if online
|
||||
if (player)
|
||||
{
|
||||
player.SetInArenaTeam(teamId, GetSlot(), GetArenaType());
|
||||
player.SetArenaTeamIdInvited(0);
|
||||
|
||||
// Hide promote/remove buttons
|
||||
if (CaptainGuid != playerGuid)
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.Member, 1);
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [{1}] joined arena team type: {2} [Id: {3}, Name: {4}].", playerName, playerGuid.ToString(), GetArenaType(), GetId(), GetName());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LoadArenaTeamFromDB(SQLResult result)
|
||||
{
|
||||
if (result.IsEmpty())
|
||||
return false;
|
||||
|
||||
teamId = result.Read<uint>(0);
|
||||
TeamName = result.Read<string>(1);
|
||||
CaptainGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(2));
|
||||
type = result.Read<byte>(3);
|
||||
BackgroundColor = result.Read<uint>(4);
|
||||
EmblemStyle = result.Read<byte>(5);
|
||||
EmblemColor = result.Read<uint>(6);
|
||||
BorderStyle = result.Read<byte>(7);
|
||||
BorderColor = result.Read<uint>(8);
|
||||
stats.Rating = result.Read<ushort>(9);
|
||||
stats.WeekGames = result.Read<ushort>(10);
|
||||
stats.WeekWins = result.Read<ushort>(11);
|
||||
stats.SeasonGames = result.Read<ushort>(12);
|
||||
stats.SeasonWins = result.Read<ushort>(13);
|
||||
stats.Rank = result.Read<uint>(14);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LoadMembersFromDB(SQLResult result)
|
||||
{
|
||||
if (result.IsEmpty())
|
||||
return false;
|
||||
|
||||
bool captainPresentInTeam = false;
|
||||
|
||||
do
|
||||
{
|
||||
uint arenaTeamId = result.Read<uint>(0);
|
||||
|
||||
// We loaded all members for this arena_team already, break cycle
|
||||
if (arenaTeamId > teamId)
|
||||
break;
|
||||
|
||||
ArenaTeamMember newMember = new ArenaTeamMember();
|
||||
newMember.Guid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(1));
|
||||
newMember.WeekGames = result.Read<ushort>(2);
|
||||
newMember.WeekWins = result.Read<ushort>(3);
|
||||
newMember.SeasonGames = result.Read<ushort>(4);
|
||||
newMember.SeasonWins = result.Read<ushort>(5);
|
||||
newMember.Name = result.Read<string>(6);
|
||||
newMember.Class = result.Read<byte>(7);
|
||||
newMember.PersonalRating = result.Read<ushort>(8);
|
||||
newMember.MatchMakerRating = (ushort)(result.Read<ushort>(9) > 0 ? result.Read<ushort>(9) : 1500);
|
||||
|
||||
// Delete member if character information is missing
|
||||
if (string.IsNullOrEmpty(newMember.Name))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "ArenaTeam {0} has member with empty name - probably {1} doesn't exist, deleting him from memberlist!", arenaTeamId, newMember.Guid.ToString());
|
||||
DelMember(newMember.Guid, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if team team has a valid captain
|
||||
if (newMember.Guid == GetCaptain())
|
||||
captainPresentInTeam = true;
|
||||
|
||||
// Put the player in the team
|
||||
Members.Add(newMember);
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
if (Empty() || !captainPresentInTeam)
|
||||
{
|
||||
// Arena team is empty or captain is not in team, delete from db
|
||||
Log.outDebug(LogFilter.Arena, "ArenaTeam {0} does not have any members or its captain is not in team, disbanding it...", teamId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetName(string name)
|
||||
{
|
||||
if (TeamName == name || string.IsNullOrEmpty(name) || name.Length > 24 || Global.ObjectMgr.IsReservedName(name) || !ObjectManager.IsValidCharterName(name))
|
||||
return false;
|
||||
|
||||
TeamName = name;
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_NAME);
|
||||
stmt.AddValue(0, TeamName);
|
||||
stmt.AddValue(1, GetId());
|
||||
DB.Characters.Execute(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetCaptain(ObjectGuid guid)
|
||||
{
|
||||
// Disable remove/promote buttons
|
||||
Player oldCaptain = Global.ObjAccessor.FindPlayer(GetCaptain());
|
||||
if (oldCaptain)
|
||||
oldCaptain.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.Member, 1);
|
||||
|
||||
// Set new captain
|
||||
CaptainGuid = guid;
|
||||
|
||||
// Update database
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_CAPTAIN);
|
||||
stmt.AddValue(0, guid.GetCounter());
|
||||
stmt.AddValue(1, GetId());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
// Enable remove/promote buttons
|
||||
Player newCaptain = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (newCaptain)
|
||||
{
|
||||
newCaptain.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.Member, 0);
|
||||
if (oldCaptain)
|
||||
{
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [GUID: {1}] promoted player: {2} [GUID: {3}] to leader of arena team [Id: {4}, Name: {5}] [Type: {6}].",
|
||||
oldCaptain.GetName(), oldCaptain.GetGUID().ToString(), newCaptain.GetName(),
|
||||
newCaptain.GetGUID().ToString(), GetId(), GetName(), GetArenaType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DelMember(ObjectGuid guid, bool cleanDb)
|
||||
{
|
||||
// Remove member from team
|
||||
foreach (var member in Members)
|
||||
if (member.Guid == guid)
|
||||
{
|
||||
Members.Remove(member);
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove arena team info from player data
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
{
|
||||
// delete all info regarding this team
|
||||
for (uint i = 0; i < (int)ArenaTeamInfoType.End; ++i)
|
||||
player.SetArenaTeamInfoField(GetSlot(), (ArenaTeamInfoType)i, 0);
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [GUID: {1}] left arena team type: {2} [Id: {3}, Name: {4}].", player.GetName(), player.GetGUID().ToString(), GetArenaType(), GetId(), GetName());
|
||||
}
|
||||
|
||||
// Only used for single member deletion, for arena team disband we use a single query for more efficiency
|
||||
if (cleanDb)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM_MEMBER);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, guid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
public void Disband(WorldSession session)
|
||||
{
|
||||
// Broadcast update
|
||||
if (session != null)
|
||||
{
|
||||
Player player = session.GetPlayer();
|
||||
if (player)
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [GUID: {1}] disbanded arena team type: {2} [Id: {3}, Name: {4}].", player.GetName(), player.GetGUID().ToString(), GetArenaType(), GetId(), GetName());
|
||||
}
|
||||
|
||||
// Remove all members from arena team
|
||||
while (!Members.Empty())
|
||||
DelMember(Members.FirstOrDefault().Guid, false);
|
||||
|
||||
// Update database
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM_MEMBERS);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// Remove arena team from ObjectMgr
|
||||
Global.ArenaTeamMgr.RemoveArenaTeam(teamId);
|
||||
}
|
||||
|
||||
public void Disband()
|
||||
{
|
||||
// Remove all members from arena team
|
||||
while (!Members.Empty())
|
||||
DelMember(Members.First().Guid, false);
|
||||
|
||||
// Update database
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM_MEMBERS);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// Remove arena team from ObjectMgr
|
||||
Global.ArenaTeamMgr.RemoveArenaTeam(teamId);
|
||||
}
|
||||
|
||||
public void SendStats(WorldSession session)
|
||||
{
|
||||
/*WorldPacket data = new WorldPacket(ServerOpcodes.ArenaTeamStats);
|
||||
data.WriteUInt32(GetId()); // team id
|
||||
data.WriteUInt32(stats.Rating); // rating
|
||||
data.WriteUInt32(stats.WeekGames); // games this week
|
||||
data.WriteUInt32(stats.WeekWins); // wins this week
|
||||
data.WriteUInt32(stats.SeasonGames); // played this season
|
||||
data.WriteUInt32(stats.SeasonWins); // wins this season
|
||||
data.WriteUInt32(stats.Rank); // rank
|
||||
session.SendPacket(data);*/
|
||||
}
|
||||
|
||||
public void 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!)
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
SendStats(player.GetSession());
|
||||
}
|
||||
}
|
||||
|
||||
public void Inspect(WorldSession session, ObjectGuid guid)
|
||||
{
|
||||
ArenaTeamMember member = GetMember(guid);
|
||||
if (member == null)
|
||||
return;
|
||||
|
||||
WorldPacket data = new WorldPacket(ServerOpcodes.InspectPvp);
|
||||
data.WritePackedGuid(guid); // player guid
|
||||
data.WriteUInt8(GetSlot()); // slot (0...2)
|
||||
data.WriteUInt32(GetId()); // arena team id
|
||||
data.WriteUInt32(stats.Rating); // rating
|
||||
data.WriteUInt32(stats.SeasonGames); // season played
|
||||
data.WriteUInt32(stats.SeasonWins); // season wins
|
||||
data.WriteUInt32(member.SeasonGames); // played (count of all games, that the inspected member participated...)
|
||||
data.WriteUInt32(member.PersonalRating); // personal rating
|
||||
//session.SendPacket(data);
|
||||
}
|
||||
|
||||
void BroadcastPacket(ServerPacket packet)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte GetSlotByType(uint type)
|
||||
{
|
||||
switch ((ArenaTypes)type)
|
||||
{
|
||||
case ArenaTypes.Team2v2: return 0;
|
||||
case ArenaTypes.Team3v3: return 1;
|
||||
case ArenaTypes.Team5v5: return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Log.outError(LogFilter.Arena, "FATAL: Unknown arena team type {0} for some arena team", type);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public static byte GetTypeBySlot(byte slot)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case 0: return (byte)ArenaTypes.Team2v2;
|
||||
case 1: return (byte)ArenaTypes.Team3v3;
|
||||
case 2: return (byte)ArenaTypes.Team5v5;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Log.outError(LogFilter.Arena, "FATAL: Unknown arena team slot {0} for some arena team", slot);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public bool IsMember(ObjectGuid guid)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
if (member.Guid == guid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetAverageMMR(Group group)
|
||||
{
|
||||
if (!group)
|
||||
return 0;
|
||||
|
||||
uint matchMakerRating = 0;
|
||||
uint playerDivider = 0;
|
||||
foreach (var member in Members)
|
||||
{
|
||||
// Skip if player is not online
|
||||
if (!Global.ObjAccessor.FindPlayer(member.Guid))
|
||||
continue;
|
||||
|
||||
// Skip if player is not a member of group
|
||||
if (!group.IsMember(member.Guid))
|
||||
continue;
|
||||
|
||||
matchMakerRating += member.MatchMakerRating;
|
||||
++playerDivider;
|
||||
}
|
||||
|
||||
// x/0 = crash
|
||||
if (playerDivider == 0)
|
||||
playerDivider = 1;
|
||||
|
||||
matchMakerRating /= playerDivider;
|
||||
|
||||
return matchMakerRating;
|
||||
}
|
||||
|
||||
float GetChanceAgainst(uint ownRating, uint opponentRating)
|
||||
{
|
||||
// Returns the chance to win against a team with the given rating, used in the rating adjustment calculation
|
||||
// ELO system
|
||||
return (float)(1.0f / (1.0f + Math.Exp(Math.Log(10.0f) * ((float)opponentRating - (float)ownRating) / 650.0f)));
|
||||
}
|
||||
|
||||
int GetMatchmakerRatingMod(uint ownRating, uint opponentRating, bool won)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
float won_mod = (won) ? 1.0f : 0.0f;
|
||||
float mod = won_mod - chance;
|
||||
|
||||
// Work in progress:
|
||||
/*
|
||||
// This is a simulation, as there is not much info on how it really works
|
||||
float confidence_mod = min(1.0f - fabs(mod), 0.5f);
|
||||
|
||||
// Apply confidence factor to the mod:
|
||||
mod *= confidence_factor
|
||||
|
||||
// And only after that update the new confidence factor
|
||||
confidence_factor -= ((confidence_factor - 1.0f) * confidence_mod) / confidence_factor;
|
||||
*/
|
||||
|
||||
// Real rating modification
|
||||
mod *= WorldConfig.GetFloatValue(WorldCfg.ArenaMatchmakerRatingModifier);
|
||||
|
||||
return (int)Math.Ceiling(mod);
|
||||
}
|
||||
|
||||
int GetRatingMod(uint ownRating, uint opponentRating, bool won)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
|
||||
// Calculate the rating modification
|
||||
float mod;
|
||||
|
||||
// todo Replace this hack with using the confidence factor (limiting the factor to 2.0f)
|
||||
if (won)
|
||||
{
|
||||
if (ownRating < 1300)
|
||||
{
|
||||
float win_rating_modifier1 = WorldConfig.GetFloatValue(WorldCfg.ArenaWinRatingModifier1);
|
||||
|
||||
if (ownRating < 1000)
|
||||
mod = win_rating_modifier1 * (1.0f - chance);
|
||||
else
|
||||
mod = ((win_rating_modifier1 / 2.0f) + ((win_rating_modifier1 / 2.0f) * (1300.0f - ownRating) / 300.0f)) * (1.0f - chance);
|
||||
}
|
||||
else
|
||||
mod = WorldConfig.GetFloatValue(WorldCfg.ArenaWinRatingModifier2) * (1.0f - chance);
|
||||
}
|
||||
else
|
||||
mod = WorldConfig.GetFloatValue(WorldCfg.ArenaLoseRatingModifier) * (-chance);
|
||||
|
||||
return (int)Math.Ceiling(mod);
|
||||
}
|
||||
|
||||
public void FinishGame(int mod)
|
||||
{
|
||||
// Rating can only drop to 0
|
||||
if (stats.Rating + mod < 0)
|
||||
stats.Rating = 0;
|
||||
else
|
||||
{
|
||||
stats.Rating += (ushort)mod;
|
||||
|
||||
// Check if rating related achivements are met
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
player.UpdateCriteria(CriteriaTypes.HighestTeamRating, stats.Rating, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Update number of games played per season or week
|
||||
stats.WeekGames += 1;
|
||||
stats.SeasonGames += 1;
|
||||
|
||||
// Update team's rank, start with rank 1 and increase until no team with more rating was found
|
||||
stats.Rank = 1;
|
||||
foreach (var i in Global.ArenaTeamMgr.GetArenaTeamMap())
|
||||
{
|
||||
if (i.Value.GetArenaType() == type && i.Value.GetStats().Rating > stats.Rating)
|
||||
++stats.Rank;
|
||||
}
|
||||
}
|
||||
|
||||
public int WonAgainst(uint ownMMRating, uint opponentMMRating, ref int ratingChange)
|
||||
{
|
||||
// Called when the team has won
|
||||
// Change in Matchmaker rating
|
||||
int mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, true);
|
||||
|
||||
// Change in Team Rating
|
||||
ratingChange = GetRatingMod(stats.Rating, opponentMMRating, true);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(ratingChange);
|
||||
|
||||
// Update number of wins per season and week
|
||||
stats.WeekWins += 1;
|
||||
stats.SeasonWins += 1;
|
||||
|
||||
// Return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
public int LostAgainst(uint ownMMRating, uint opponentMMRating, ref int ratingChange)
|
||||
{
|
||||
// Called when the team has lost
|
||||
// Change in Matchmaker Rating
|
||||
int mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, false);
|
||||
|
||||
// Change in Team Rating
|
||||
ratingChange = GetRatingMod(stats.Rating, opponentMMRating, false);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(ratingChange);
|
||||
|
||||
// return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
public void MemberLost(Player player, uint againstMatchmakerRating, int matchmakerRatingChange = -12)
|
||||
{
|
||||
// Called for each participant of a match after losing
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (member.Guid == player.GetGUID())
|
||||
{
|
||||
// Update personal rating
|
||||
int mod = GetRatingMod(member.PersonalRating, againstMatchmakerRating, false);
|
||||
member.ModifyPersonalRating(player, mod, GetArenaType());
|
||||
|
||||
// Update matchmaker rating
|
||||
member.ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
|
||||
|
||||
// Update personal played stats
|
||||
member.WeekGames += 1;
|
||||
member.SeasonGames += 1;
|
||||
|
||||
// update the unit fields
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesWeek, member.WeekGames);
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesSeason, member.SeasonGames);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OfflineMemberLost(ObjectGuid guid, uint againstMatchmakerRating, int matchmakerRatingChange = -12)
|
||||
{
|
||||
// Called for offline player after ending rated arena match!
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (member.Guid == guid)
|
||||
{
|
||||
// update personal rating
|
||||
int mod = GetRatingMod(member.PersonalRating, againstMatchmakerRating, false);
|
||||
member.ModifyPersonalRating(null, mod, GetArenaType());
|
||||
|
||||
// update matchmaker rating
|
||||
member.ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
|
||||
|
||||
// update personal played stats
|
||||
member.WeekGames += 1;
|
||||
member.SeasonGames += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MemberWon(Player player, uint againstMatchmakerRating, int matchmakerRatingChange)
|
||||
{
|
||||
// called for each participant after winning a match
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (member.Guid == player.GetGUID())
|
||||
{
|
||||
// update personal rating
|
||||
int mod = GetRatingMod(member.PersonalRating, againstMatchmakerRating, true);
|
||||
member.ModifyPersonalRating(player, mod, GetArenaType());
|
||||
|
||||
// update matchmaker rating
|
||||
member.ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
|
||||
|
||||
// update personal stats
|
||||
member.WeekGames += 1;
|
||||
member.SeasonGames += 1;
|
||||
member.SeasonWins += 1;
|
||||
member.WeekWins += 1;
|
||||
// update unit fields
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesWeek, member.WeekGames);
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesSeason, member.SeasonGames);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveToDB()
|
||||
{
|
||||
// Save team and member stats to db
|
||||
// Called after a match has ended or when calculating arena_points
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_STATS);
|
||||
stmt.AddValue(0, stats.Rating);
|
||||
stmt.AddValue(1, stats.WeekGames);
|
||||
stmt.AddValue(2, stats.WeekWins);
|
||||
stmt.AddValue(3, stats.SeasonGames);
|
||||
stmt.AddValue(4, stats.SeasonWins);
|
||||
stmt.AddValue(5, stats.Rank);
|
||||
stmt.AddValue(6, GetId());
|
||||
trans.Append(stmt);
|
||||
|
||||
foreach (var member in Members)
|
||||
{
|
||||
// Save the effort and go
|
||||
if (member.WeekGames == 0)
|
||||
continue;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_MEMBER);
|
||||
stmt.AddValue(0, member.PersonalRating);
|
||||
stmt.AddValue(1, member.WeekGames);
|
||||
stmt.AddValue(2, member.WeekWins);
|
||||
stmt.AddValue(3, member.SeasonGames);
|
||||
stmt.AddValue(4, member.SeasonWins);
|
||||
stmt.AddValue(5, GetId());
|
||||
stmt.AddValue(6, member.Guid.GetCounter());
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_CHARACTER_ARENA_STATS);
|
||||
stmt.AddValue(0, member.Guid.GetCounter());
|
||||
stmt.AddValue(1, GetSlot());
|
||||
stmt.AddValue(2, member.MatchMakerRating);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public bool FinishWeek()
|
||||
{
|
||||
// No need to go further than this
|
||||
if (stats.WeekGames == 0)
|
||||
return false;
|
||||
|
||||
// Reset team stats
|
||||
stats.WeekGames = 0;
|
||||
stats.WeekWins = 0;
|
||||
|
||||
// Reset member stats
|
||||
foreach (var member in Members)
|
||||
{
|
||||
member.WeekGames = 0;
|
||||
member.WeekWins = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsFighting()
|
||||
{
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
if (player.GetMap().IsBattleArena())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ArenaTeamMember GetMember(string name)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
if (member.Name == name)
|
||||
return member;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArenaTeamMember GetMember(ObjectGuid guid)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
if (member.Guid == guid)
|
||||
return member;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public uint GetId() { return teamId; }
|
||||
public byte GetArenaType() { return type; }
|
||||
public byte GetSlot() { return GetSlotByType(GetArenaType()); }
|
||||
|
||||
public ObjectGuid GetCaptain() { return CaptainGuid; }
|
||||
public string GetName() { return TeamName; }
|
||||
public ArenaTeamStats GetStats() { return stats; }
|
||||
public uint GetRating() { return stats.Rating; }
|
||||
|
||||
public int GetMembersSize() { return Members.Count; }
|
||||
bool Empty() { return Members.Empty(); }
|
||||
public List<ArenaTeamMember> GetMembers()
|
||||
{
|
||||
return Members;
|
||||
}
|
||||
|
||||
uint teamId;
|
||||
byte type;
|
||||
string TeamName;
|
||||
ObjectGuid CaptainGuid;
|
||||
|
||||
uint BackgroundColor; // ARGB format
|
||||
byte EmblemStyle; // icon id
|
||||
uint EmblemColor; // ARGB format
|
||||
byte BorderStyle; // border image id
|
||||
uint BorderColor; // ARGB format
|
||||
|
||||
List<ArenaTeamMember> Members = new List<ArenaTeamMember>();
|
||||
ArenaTeamStats stats;
|
||||
}
|
||||
|
||||
public class ArenaTeamMember
|
||||
{
|
||||
public ObjectGuid Guid;
|
||||
public string Name;
|
||||
public byte Class;
|
||||
public ushort WeekGames;
|
||||
public ushort WeekWins;
|
||||
public ushort SeasonGames;
|
||||
public ushort SeasonWins;
|
||||
public ushort PersonalRating;
|
||||
public ushort MatchMakerRating;
|
||||
|
||||
public void ModifyPersonalRating(Player player, int mod, uint type)
|
||||
{
|
||||
if (PersonalRating + mod < 0)
|
||||
PersonalRating = 0;
|
||||
else
|
||||
PersonalRating += (ushort)mod;
|
||||
|
||||
if (player)
|
||||
{
|
||||
player.SetArenaTeamInfoField(ArenaTeam.GetSlotByType(type), ArenaTeamInfoType.PersonalRating, PersonalRating);
|
||||
player.UpdateCriteria(CriteriaTypes.HighestPersonalRating, PersonalRating, type);
|
||||
}
|
||||
}
|
||||
|
||||
public void ModifyMatchmakerRating(int mod, uint slot)
|
||||
{
|
||||
if (MatchMakerRating + mod < 0)
|
||||
MatchMakerRating = 0;
|
||||
else
|
||||
MatchMakerRating += (ushort)mod;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ArenaTeamStats
|
||||
{
|
||||
public ushort Rating;
|
||||
public ushort WeekGames;
|
||||
public ushort WeekWins;
|
||||
public ushort SeasonGames;
|
||||
public ushort SeasonWins;
|
||||
public uint Rank;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class ArenaTeamManager : Singleton<ArenaTeamManager>
|
||||
{
|
||||
ArenaTeamManager()
|
||||
{
|
||||
NextArenaTeamId = 1;
|
||||
}
|
||||
|
||||
public ArenaTeam GetArenaTeamById(uint arenaTeamId)
|
||||
{
|
||||
return ArenaTeamStorage.LookupByKey(arenaTeamId);
|
||||
}
|
||||
|
||||
public ArenaTeam GetArenaTeamByName(string arenaTeamName)
|
||||
{
|
||||
string search = arenaTeamName.ToLower();
|
||||
foreach (var team in ArenaTeamStorage.Values)
|
||||
{
|
||||
string teamName = team.GetName().ToLower();
|
||||
if (search == teamName)
|
||||
return team;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArenaTeam GetArenaTeamByCaptain(ObjectGuid guid)
|
||||
{
|
||||
foreach (var pair in ArenaTeamStorage)
|
||||
if (pair.Value.GetCaptain() == guid)
|
||||
return pair.Value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void AddArenaTeam(ArenaTeam arenaTeam)
|
||||
{
|
||||
ArenaTeamStorage[arenaTeam.GetId()] = arenaTeam;
|
||||
}
|
||||
|
||||
public void RemoveArenaTeam(uint arenaTeamId)
|
||||
{
|
||||
ArenaTeamStorage.Remove(arenaTeamId);
|
||||
}
|
||||
|
||||
public uint GenerateArenaTeamId()
|
||||
{
|
||||
if (NextArenaTeamId >= 0xFFFFFFFE)
|
||||
{
|
||||
Log.outError(LogFilter.Battleground, "Arena team ids overflow!! Can't continue, shutting down server. ");
|
||||
Global.WorldMgr.StopNow();
|
||||
}
|
||||
return NextArenaTeamId++;
|
||||
}
|
||||
|
||||
public void LoadArenaTeams()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
// Clean out the trash before loading anything
|
||||
DB.Characters.Execute("DELETE FROM arena_team_member WHERE arenaTeamId NOT IN (SELECT arenaTeamId FROM arena_team)"); // One-time query
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
SQLResult result = DB.Characters.Query("SELECT arenaTeamId, name, captainGuid, type, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor, " +
|
||||
// 9 10 11 12 13 14
|
||||
"rating, weekGames, weekWins, seasonGames, seasonWins, rank FROM arena_team ORDER BY arenaTeamId ASC");
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 arena teams. DB table `arena_team` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
SQLResult result2 = DB.Characters.Query(
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
"SELECT arenaTeamId, atm.guid, atm.weekGames, atm.weekWins, atm.seasonGames, atm.seasonWins, c.name, class, personalRating, matchMakerRating FROM arena_team_member atm" +
|
||||
" INNER JOIN arena_team ate USING (arenaTeamId) LEFT JOIN characters AS c ON atm.guid = c.guid" +
|
||||
" LEFT JOIN character_arena_stats AS cas ON c.guid = cas.guid AND (cas.slot = 0 AND ate.type = 2 OR cas.slot = 1 AND ate.type = 3 OR cas.slot = 2 AND ate.type = 5)" +
|
||||
" ORDER BY atm.arenateamid ASC");
|
||||
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
ArenaTeam newArenaTeam = new ArenaTeam();
|
||||
|
||||
if (!newArenaTeam.LoadArenaTeamFromDB(result) || !newArenaTeam.LoadMembersFromDB(result2))
|
||||
{
|
||||
newArenaTeam.Disband(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
AddArenaTeam(newArenaTeam);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} arena teams in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void SetNextArenaTeamId(uint Id) { NextArenaTeamId = Id; }
|
||||
|
||||
public Dictionary<uint, ArenaTeam> GetArenaTeamMap() { return ArenaTeamStorage; }
|
||||
|
||||
uint NextArenaTeamId;
|
||||
Dictionary<uint, ArenaTeam> ArenaTeamStorage = new Dictionary<uint, ArenaTeam>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class BladesEdgeArena : Arena
|
||||
{
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = BladeEdgeObjectTypes.Door1; i <= BladeEdgeObjectTypes.Door4; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
|
||||
for (int i = BladeEdgeObjectTypes.Buff1; i <= BladeEdgeObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnOneDay);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = BladeEdgeObjectTypes.Door1; i <= BladeEdgeObjectTypes.Door4; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = BladeEdgeObjectTypes.Buff1; i <= BladeEdgeObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4538: // buff trigger?
|
||||
case 4539: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0x9f3, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door1, BladeEfgeGameObjects.Door1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door2, BladeEfgeGameObjects.Door2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door3, BladeEfgeGameObjects.Door3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door4, BladeEfgeGameObjects.Door4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "BatteGroundBE: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(BladeEdgeObjectTypes.Buff1, BladeEfgeGameObjects.Buff1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Buff2, BladeEfgeGameObjects.Buff2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "BladesEdgeArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
struct BladeEdgeObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Door3 = 2;
|
||||
public const int Door4 = 3;
|
||||
public const int Buff1 = 4;
|
||||
public const int Buff2 = 5;
|
||||
public const int Max = 6;
|
||||
}
|
||||
|
||||
struct BladeEfgeGameObjects
|
||||
{
|
||||
public const uint Door1 = 183971;
|
||||
public const uint Door2 = 183973;
|
||||
public const uint Door3 = 183970;
|
||||
public const uint Door4 = 183972;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class DalaranSewersArena : Arena
|
||||
{
|
||||
public DalaranSewersArena()
|
||||
{
|
||||
_events = new EventMap();
|
||||
}
|
||||
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = DalaranSewersObjectTypes.Door1; i <= DalaranSewersObjectTypes.Door2; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = DalaranSewersObjectTypes.Door1; i <= DalaranSewersObjectTypes.Door2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = DalaranSewersObjectTypes.Buff1; i <= DalaranSewersObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallWarning, RandomHelper.URand(DalaranSewersData.WaterfallTimerMin, DalaranSewersData.WaterfallTimerMax));
|
||||
_events.ScheduleEvent(DalaranSewersEvents.PipeKnockback, DalaranSewersData.PipeKnockbackFirstDelay);
|
||||
|
||||
SpawnBGObject(DalaranSewersObjectTypes.Water2, BattlegroundConst.RespawnImmediately);
|
||||
|
||||
DoorOpen(DalaranSewersObjectTypes.Water1); // Turn off collision
|
||||
DoorOpen(DalaranSewersObjectTypes.Water2);
|
||||
|
||||
// Remove effects of Demonic Circle Summon
|
||||
foreach (var pair in GetPlayers())
|
||||
{
|
||||
Player player = _GetPlayer(pair, "BattlegroundDS::StartingEventOpenDoors");
|
||||
if (player)
|
||||
player.RemoveAurasDueToSpell(DalaranSewersSpells.DemonicCircle);
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 5347:
|
||||
case 5348:
|
||||
// Remove effects of Demonic Circle Summon
|
||||
player.RemoveAurasDueToSpell(DalaranSewersSpells.DemonicCircle);
|
||||
|
||||
// Someone has get back into the pipes and the knockback has already been performed,
|
||||
// so we reset the knockback count for kicking the player again into the arena.
|
||||
_events.ScheduleEvent(DalaranSewersEvents.PipeKnockback, DalaranSewersData.PipeKnockbackDelay);
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(3610, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(DalaranSewersObjectTypes.Door1, DalaranSewersGameObjects.Door1, 1350.95f, 817.2f, 20.8096f, 3.15f, 0, 0, 0.99627f, 0.0862864f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(DalaranSewersObjectTypes.Door2, DalaranSewersGameObjects.Door2, 1232.65f, 764.913f, 20.0729f, 6.3f, 0, 0, 0.0310211f, -0.999519f, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "DalaranSewersArena: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// buffs
|
||||
result &= AddObject(DalaranSewersObjectTypes.Buff1, DalaranSewersGameObjects.Buff1, 1291.7f, 813.424f, 7.11472f, 4.64562f, 0, 0, 0.730314f, -0.683111f, 120);
|
||||
result &= AddObject(DalaranSewersObjectTypes.Buff2, DalaranSewersGameObjects.Buff2, 1291.7f, 768.911f, 7.11472f, 1.55194f, 0, 0, 0.700409f, 0.713742f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "DalaranSewersArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(DalaranSewersObjectTypes.Water1, DalaranSewersGameObjects.Water1, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120);
|
||||
result &= AddObject(DalaranSewersObjectTypes.Water2, DalaranSewersGameObjects.Water2, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120);
|
||||
result &= AddCreature(DalaranSewersData.NpcWaterSpout, DalaranSewersCreatureTypes.WaterfallKnockback, 1292.587f, 790.2205f, 7.19796f, 3.054326f, TeamId.Neutral, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddCreature(DalaranSewersData.NpcWaterSpout, DalaranSewersCreatureTypes.PipeKnockback1, 1369.977f, 817.2882f, 16.08718f, 3.106686f, TeamId.Neutral, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddCreature(DalaranSewersData.NpcWaterSpout, DalaranSewersCreatureTypes.PipeKnockback2, 1212.833f, 765.3871f, 16.09484f, 0.0f, TeamId.Neutral, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "DalaranSewersArena: Failed to spawn collision object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PostUpdateImpl(uint diff)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case DalaranSewersEvents.WaterfallWarning:
|
||||
// Add the water
|
||||
DoorClose(DalaranSewersObjectTypes.Water2);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallOn, DalaranSewersData.WaterWarningDuration);
|
||||
break;
|
||||
case DalaranSewersEvents.WaterfallOn:
|
||||
// Active collision and start knockback timer
|
||||
DoorClose(DalaranSewersObjectTypes.Water1);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallOff, DalaranSewersData.WaterfallDuration);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallKnockback, DalaranSewersData.WaterfallKnockbackTimer);
|
||||
break;
|
||||
case DalaranSewersEvents.WaterfallOff:
|
||||
// Remove collision and water
|
||||
DoorOpen(DalaranSewersObjectTypes.Water1);
|
||||
DoorOpen(DalaranSewersObjectTypes.Water2);
|
||||
_events.CancelEvent(DalaranSewersEvents.WaterfallKnockback);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallWarning, RandomHelper.URand(DalaranSewersData.WaterfallTimerMin, DalaranSewersData.WaterfallTimerMax));
|
||||
break;
|
||||
case DalaranSewersEvents.WaterfallKnockback:
|
||||
{
|
||||
// Repeat knockback while the waterfall still active
|
||||
Creature waterSpout = GetBGCreature(DalaranSewersCreatureTypes.WaterfallKnockback);
|
||||
if (waterSpout)
|
||||
waterSpout.CastSpell(waterSpout, DalaranSewersSpells.WaterSpout, true);
|
||||
_events.ScheduleEvent(eventId, DalaranSewersData.WaterfallKnockbackTimer);
|
||||
}
|
||||
break;
|
||||
case DalaranSewersEvents.PipeKnockback:
|
||||
{
|
||||
for (int i = DalaranSewersCreatureTypes.PipeKnockback1; i <= DalaranSewersCreatureTypes.PipeKnockback2; ++i)
|
||||
{
|
||||
Creature waterSpout = GetBGCreature(i);
|
||||
if (waterSpout)
|
||||
waterSpout.CastSpell(waterSpout, DalaranSewersSpells.Flush, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EventMap _events;
|
||||
}
|
||||
|
||||
struct DalaranSewersEvents
|
||||
{
|
||||
public const int WaterfallWarning = 1; // Water starting to fall, but no LoS Blocking nor movement blocking
|
||||
public const uint WaterfallOn = 2; // LoS and Movement blocking active
|
||||
public const uint WaterfallOff = 3;
|
||||
public const uint WaterfallKnockback = 4;
|
||||
|
||||
public const uint PipeKnockback = 5;
|
||||
}
|
||||
|
||||
struct DalaranSewersObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Water1 = 2; // Collision
|
||||
public const int Water2 = 3;
|
||||
public const int Buff1 = 4;
|
||||
public const int Buff2 = 5;
|
||||
public const int Max = 6;
|
||||
}
|
||||
|
||||
struct DalaranSewersGameObjects
|
||||
{
|
||||
public const uint Door1 = 192642;
|
||||
public const uint Door2 = 192643;
|
||||
public const uint Water1 = 194395; // Collision
|
||||
public const uint Water2 = 191877;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
|
||||
struct DalaranSewersCreatureTypes
|
||||
{
|
||||
public const int WaterfallKnockback = 0;
|
||||
public const int PipeKnockback1 = 1;
|
||||
public const int PipeKnockback2 = 2;
|
||||
public const int Max = 3;
|
||||
}
|
||||
|
||||
struct DalaranSewersData
|
||||
{
|
||||
// These values are NOT blizzlike... need the correct data!
|
||||
public const uint WaterfallTimerMin = 30000;
|
||||
public const uint WaterfallTimerMax = 60000;
|
||||
public const uint WaterWarningDuration = 5000;
|
||||
public const uint WaterfallDuration = 30000;
|
||||
public const uint WaterfallKnockbackTimer = 1500;
|
||||
|
||||
public const uint PipeKnockbackFirstDelay = 5000;
|
||||
public const uint PipeKnockbackDelay = 3000;
|
||||
public const uint PipeKnockbackTotalCount = 2;
|
||||
|
||||
public const uint NpcWaterSpout = 28567;
|
||||
}
|
||||
|
||||
struct DalaranSewersSpells
|
||||
{
|
||||
public const uint Flush = 57405; // Visual And Target Selector For The Starting Knockback From The Pipe
|
||||
public const uint FlushKnockback = 61698; // Knockback Effect For Previous Spell (Triggered, Not Needed To Be Cast)
|
||||
public const uint WaterSpout = 58873; // Knockback Effect Of The Central Waterfall
|
||||
|
||||
public const uint DemonicCircle = 48018; // Demonic Circle Summon
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class NagrandArena : Arena
|
||||
{
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = NagrandArenaObjectTypes.Door1; i <= NagrandArenaObjectTypes.Door4; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = NagrandArenaObjectTypes.Door1; i <= NagrandArenaObjectTypes.Door4; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = NagrandArenaObjectTypes.Buff1; i <= NagrandArenaObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4536: // buff trigger?
|
||||
case 4537: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0xa11, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door1, NagrandArenaObjects.Door1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door2, NagrandArenaObjects.Door2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door3, NagrandArenaObjects.Door3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door4, NagrandArenaObjects.Door4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "NagrandArena: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(NagrandArenaObjectTypes.Buff1, NagrandArenaObjects.Buff1, 4009.189941f, 2895.250000f, 13.052700f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Buff2, NagrandArenaObjects.Buff2, 4103.330078f, 2946.350098f, 13.051300f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "NagrandArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
struct NagrandArenaObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Door3 = 2;
|
||||
public const int Door4 = 3;
|
||||
public const int Buff1 = 4;
|
||||
public const int Buff2 = 5;
|
||||
public const int Max = 6;
|
||||
}
|
||||
|
||||
struct NagrandArenaObjects
|
||||
{
|
||||
public const uint Door1 = 183978;
|
||||
public const uint Door2 = 183980;
|
||||
public const uint Door3 = 183977;
|
||||
public const uint Door4 = 183979;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class RingofValorArena : Arena
|
||||
{
|
||||
public RingofValorArena()
|
||||
{
|
||||
_events = new EventMap();
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(RingofValorObjectTypes.Elevator1, RingofValorGameObjects.Elevator1, 763.536377f, -294.535767f, 0.505383f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Elevator2, RingofValorGameObjects.Elevator2, 763.506348f, -273.873352f, 0.505383f, 0.000000f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn elevator object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Buff1, RingofValorGameObjects.Buff1, 735.551819f, -284.794678f, 28.276682f, 0.034906f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Buff2, RingofValorGameObjects.Buff2, 791.224487f, -284.794464f, 28.276682f, 2.600535f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Fire1, RingofValorGameObjects.Fire1, 743.543457f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Fire2, RingofValorGameObjects.Fire2, 782.971802f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Firedoor1, RingofValorGameObjects.Firedoor1, 743.711060f, -284.099609f, 27.542587f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Firedoor2, RingofValorGameObjects.Firedoor2, 783.221252f, -284.133362f, 27.535686f, 0.000000f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn fire/firedoor object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Gear1, RingofValorGameObjects.Gear1, 763.664551f, -261.872986f, 26.686588f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Gear2, RingofValorGameObjects.Gear2, 763.578979f, -306.146149f, 26.665222f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pulley1, RingofValorGameObjects.Pulley1, 700.722290f, -283.990662f, 39.517582f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pulley2, RingofValorGameObjects.Pulley2, 826.303833f, -283.996429f, 39.517582f, 0.000000f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn gear/pully object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar1, RingofValorGameObjects.Pilar1, 763.632385f, -306.162384f, 25.909504f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar2, RingofValorGameObjects.Pilar2, 723.644287f, -284.493256f, 24.648525f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar3, RingofValorGameObjects.Pilar3, 763.611145f, -261.856750f, 25.909504f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar4, RingofValorGameObjects.Pilar4, 802.211609f, -284.493256f, 24.648525f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision1, RingofValorGameObjects.PilarCollision1, 763.632385f, -306.162384f, 30.639660f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision2, RingofValorGameObjects.PilarCollision2, 723.644287f, -284.493256f, 32.382710f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision3, RingofValorGameObjects.PilarCollision3, 763.611145f, -261.856750f, 30.639660f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision4, RingofValorGameObjects.PilarCollision4, 802.211609f, -284.493256f, 32.382710f, 3.141593f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn pilar object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
// Buff respawn
|
||||
SpawnBGObject(RingofValorObjectTypes.Buff1, 90);
|
||||
SpawnBGObject(RingofValorObjectTypes.Buff2, 90);
|
||||
// Elevators
|
||||
DoorOpen(RingofValorObjectTypes.Elevator1);
|
||||
DoorOpen(RingofValorObjectTypes.Elevator2);
|
||||
|
||||
_events.ScheduleEvent(RingofValorEvents.OpenFences, 20133);
|
||||
|
||||
// Should be false at first, TogglePillarCollision will do it.
|
||||
TogglePillarCollision(true);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 5224:
|
||||
case 5226:
|
||||
// fire was removed in 3.2.0
|
||||
case 5473:
|
||||
case 5474:
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0xe1a, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override void PostUpdateImpl(uint diff)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case RingofValorEvents.OpenFences:
|
||||
// Open fire (only at game start)
|
||||
for (byte i = RingofValorObjectTypes.Fire1; i <= RingofValorObjectTypes.Firedoor2; ++i)
|
||||
DoorOpen(i);
|
||||
_events.ScheduleEvent(RingofValorEvents.CloseFire, 5000);
|
||||
break;
|
||||
case RingofValorEvents.CloseFire:
|
||||
for (byte i = RingofValorObjectTypes.Fire1; i <= RingofValorObjectTypes.Firedoor2; ++i)
|
||||
DoorClose(i);
|
||||
// Fire got closed after five seconds, leaves twenty seconds before toggling pillars
|
||||
_events.ScheduleEvent(RingofValorEvents.SwitchPillars, 20000);
|
||||
break;
|
||||
case RingofValorEvents.SwitchPillars:
|
||||
TogglePillarCollision(true);
|
||||
_events.Repeat(25000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TogglePillarCollision(bool enable)
|
||||
{
|
||||
// Toggle visual pillars, pulley, gear, and collision based on previous state
|
||||
for (int i = RingofValorObjectTypes.Pilar1; i <= RingofValorObjectTypes.Gear2; ++i)
|
||||
{
|
||||
if (enable)
|
||||
DoorOpen(i);
|
||||
else
|
||||
DoorClose(i);
|
||||
}
|
||||
|
||||
for (byte i = RingofValorObjectTypes.Pilar2; i <= RingofValorObjectTypes.Pulley2; ++i)
|
||||
{
|
||||
if (enable)
|
||||
DoorClose(i);
|
||||
else
|
||||
DoorOpen(i);
|
||||
}
|
||||
|
||||
for (byte i = RingofValorObjectTypes.Pilar1; i <= RingofValorObjectTypes.PilarCollision4; ++i)
|
||||
{
|
||||
GameObject go = GetBGObject(i);
|
||||
if (go)
|
||||
{
|
||||
if (i >= RingofValorObjectTypes.PilarCollision1)
|
||||
{
|
||||
GameObjectState state = ((go.GetGoInfo().Door.startOpen != 0) == enable) ? GameObjectState.Active : GameObjectState.Ready;
|
||||
go.SetGoState(state);
|
||||
}
|
||||
|
||||
foreach (var guid in GetPlayers().Keys)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
go.SendUpdateToPlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EventMap _events;
|
||||
}
|
||||
|
||||
struct RingofValorEvents
|
||||
{
|
||||
public const int OpenFences = 0;
|
||||
public const int SwitchPillars = 1;
|
||||
public const int CloseFire = 2;
|
||||
}
|
||||
|
||||
struct RingofValorObjectTypes
|
||||
{
|
||||
public const int Buff1 = 1;
|
||||
public const int Buff2 = 2;
|
||||
public const int Fire1 = 3;
|
||||
public const int Fire2 = 4;
|
||||
public const int Firedoor1 = 5;
|
||||
public const int Firedoor2 = 6;
|
||||
|
||||
public const int Pilar1 = 7;
|
||||
public const int Pilar3 = 8;
|
||||
public const int Gear1 = 9;
|
||||
public const int Gear2 = 10;
|
||||
|
||||
public const int Pilar2 = 11;
|
||||
public const int Pilar4 = 12;
|
||||
public const int Pulley1 = 13;
|
||||
public const int Pulley2 = 14;
|
||||
|
||||
public const int PilarCollision1 = 15;
|
||||
public const int PilarCollision2 = 16;
|
||||
public const int PilarCollision3 = 17;
|
||||
public const int PilarCollision4 = 18;
|
||||
|
||||
public const int Elevator1 = 19;
|
||||
public const int Elevator2= 20;
|
||||
public const int Max = 21;
|
||||
}
|
||||
|
||||
struct RingofValorGameObjects
|
||||
{
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
public const uint Fire1 = 192704;
|
||||
public const uint Fire2 = 192705;
|
||||
|
||||
public const uint Firedoor2 = 192387;
|
||||
public const uint Firedoor1 = 192388;
|
||||
public const uint Pulley1 = 192389;
|
||||
public const uint Pulley2 = 192390;
|
||||
public const uint Gear1 = 192393;
|
||||
public const uint Gear2 = 192394;
|
||||
public const uint Elevator1 = 194582;
|
||||
public const uint Elevator2 = 194586;
|
||||
|
||||
public const uint PilarCollision1 = 194580; // Axe
|
||||
public const uint PilarCollision2 = 194579; // Arena
|
||||
public const uint PilarCollision3 = 194581; // Lightning
|
||||
public const uint PilarCollision4 = 194578; // Ivory
|
||||
|
||||
public const uint Pilar1 = 194583; // Axe
|
||||
public const uint Pilar2 = 194584; // Arena
|
||||
public const uint Pilar3 = 194585; // Lightning
|
||||
public const uint Pilar4 = 194587; // Ivory
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class RuinsofLordaeronArena : Arena
|
||||
{
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Door1, RuinsofLordaeronObjectTypes.Door1, 1293.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f);
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Door2, RuinsofLordaeronObjectTypes.Door2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RuinsofLordaeronArena: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Buff1, RuinsofLordaeronObjectTypes.Buff1, 1328.719971f, 1632.719971f, 36.730400f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120);
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Buff2, RuinsofLordaeronObjectTypes.Buff2, 1243.300049f, 1699.170044f, 34.872601f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RuinsofLordaeronArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = RuinsofLordaeronObjectTypes.Door1; i <= RuinsofLordaeronObjectTypes.Door2; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = RuinsofLordaeronObjectTypes.Door1; i <= RuinsofLordaeronObjectTypes.Door2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = RuinsofLordaeronObjectTypes.Buff1; i <= RuinsofLordaeronObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4696: // buff trigger?
|
||||
case 4697: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0xbba, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
}
|
||||
|
||||
struct RuinsofLordaeronObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Buff1 = 2;
|
||||
public const int Buff2 = 3;
|
||||
public const int Max = 4;
|
||||
}
|
||||
|
||||
struct RuinsofLordaeronGameObjects
|
||||
{
|
||||
public const uint Door1 = 185918;
|
||||
public const uint Door2 = 185917;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class TigersPeak
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class TolvironArena
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user