using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

using InfServer.Logic;
using InfServer.Game;
using InfServer.Scripting;
using InfServer.Bots;
using InfServer.Protocol;

using Assets;

namespace InfServer.Script.GameType_Multi
{
    public class KOTH
    {
        private Arena _arena;
        public Team _team1;
        public Team _team2;
        public Team winner;
        private CfgInfo _config;                //The zone config
        private int _deathMatchTimer;
        private int _lastTickerUpdate;
        private int _lastKillStreakUpdate;
        private string _season;
        private bool _isScrim = false;
        private List<Hill> hills;
        private Hill currenthill;
        private int team1Score;
        private int team2Score;
        private int tickLastScore;
        private int tickChangeHill;
        private bool warnNewHill30 = false;
        private bool warnNewHill90 = false;
        private bool warnNewHill120 = false;

        #region Hill Controllers
        private class Hill
        {
            public string name;
            public short posX;
            public short posY;
            public int height;
            public int width;
            public Team controller;
            public bool active;
            private Arena _arena;
            private KOTH _koth;
            private int tickLastWave;

            private List<Player> players;


            public Hill(Arena arena, KOTH koth)
            {
                _koth = koth;
                _arena = arena;
                players = new List<Player>();
                tickLastWave = 0;
            }

            public void poll(int now)
            {
                List<Player> playersInHill = new List<Player>();
                int team1 = 0;
                int team2 = 0;

                playersInHill = _arena.getPlayersInBox(posX, posY, height, width).Where(p => !p.IsDead).ToList();

                team1 = playersInHill.Count(p => p._team == _koth._team1);
                team2 = playersInHill.Count(p => p._team == _koth._team2);

                if (team1 == 0 && team2 == 0)
                {
                    _arena.setTicker(1, 1, 0, String.Format("Hill {0} currently unowned", name));
                    if (now - tickLastWave >= 2500)
                    {
                        Helpers.Player_RouteExplosion(_arena.Players, 3060, posX, posY, 0, 0, 0);
                        tickLastWave = now;
                        //_arena.triggerMessage(0, 500, String.Format("{0} is currently unowned", name));
                    }
                }

                if (team1 > team2)
                {
                    _arena.setTicker(1, 1, 0, String.Format("{0} currently controls hill {1}", _koth._team1._name, name));
                    controller = _koth._team1;
                    if (now - tickLastWave >= 2500)
                    {
                        Helpers.Player_RouteExplosion(_arena.Players, 3055, posX, posY, 0, 0, 0);
                        tickLastWave = now;
                        //_arena.triggerMessage(0, 500, String.Format("{0} has control of hill", controller._name, name));
                    }
                }
                if (team2 > team1)
                {
                    _arena.setTicker(1, 1, 0, String.Format("{0} currently controls hill {1}", _koth._team2._name, name));
                    controller = _koth._team2;
                    if (now - tickLastWave >= 2500)
                    {
                        Helpers.Player_RouteExplosion(_arena.Players, 3059, posX, posY, 0, 0, 0);
                        tickLastWave = now;
                        //_arena.triggerMessage(0, 500, String.Format("{0} has control of hill", controller._name, name));
                    }
                }
                else
                {
                    if (team1 == team2 && team1 > 0 && team2 > 0)
                    {
                        _arena.setTicker(1, 1, 0, String.Format(
                            "Hill {0} is currently contested ({1}={2} vs {3}={4})",
                            name, _koth._team1._name, team1, _koth._team2._name, team2));
                        controller = null;
                        if (now - tickLastWave >= 1500)
                        {
                            Helpers.Player_RouteExplosion(_arena.Players, 3060, posX, posY, 0, 0, 0);
                           // _arena.triggerMessage(0, 500, String.Format("{0} is contested!", name));
                            tickLastWave = now;
                        }
                    }
                }
            }
        }

        #endregion


        #region Stat Recording
        private string FileName;
        private List<Team> activeTeams = null;
        private Team lastTeam1, lastTeam2;  //Records the previous team before overtime starts(We get team stats from this since ot is not recorded)
        public Team victoryTeam = null;
        DateTime startTime;

        /// <summary>
        /// Current game player stats
        /// </summary>
        private Dictionary<string, PlayerStat> _savedPlayerStats;
        /// <summary>
        /// Only used when overtime is about to be initiated
        /// </summary>
        private Dictionary<string, PlayerStat> _lastSavedStats;

        /// <summary>
        /// Stores our player information
        /// </summary>
        private class PlayerStat
        {
            public Player player { get; set; }
            public string teamname { get; set; }
            public string alias { get; set; }
            public string squad { get; set; }
            public long points { get; set; }
            public int kills { get; set; }
            public int deaths { get; set; }
            public int killPoints { get; set; }
            public int assistPoints { get; set; }
            public int bonusPoints { get; set; }
            public int playSeconds { get; set; }
            public bool hasPlayed { get; set; }
            public string classType { get; set; }

            //Kill stats
            public ItemInfo.Projectile lastUsedWep { get; set; }
            public int lastUsedWepKillCount { get; set; }
            public long lastUsedWepTick { get; set; }
            public int lastKillerCount { get; set; }

            //Medic stats
            public int potentialHealthHealed { get; set; }

            public bool onPlayingField { get; set; }
        }
        #endregion

        #region Misc Gameplay Pointers
        private Team BountyA, BountyB;
        private Player lastKiller;

        public KOTH(Arena arena)
        {
            hills = new List<Hill>();

            Hill hill1 = new Hill(arena, this);
            hill1.name = "Purple - F2";
            hill1.posX = 6888;
            hill1.posY = 1633;
            hill1.width = 870;
            hill1.height = 995;
            hill1.active = false;
            hills.Add(hill1);
            Hill hill2 = new Hill(arena, this);
            hill2.name = "White - E3";
            hill2.posX = 6288;
            hill2.posY = 3470;
            hill2.width = 1000;
            hill2.height = 1000;
            hill2.active = false;
            hills.Add(hill2);
            Hill hill3 = new Hill(arena, this);
            hill3.name = "Yellow - E5";
            hill3.posX = 6063;
            hill3.posY = 6030;
            hill3.height = 1205;
            hill3.width = 885;
            hill3.active = false;
            hills.Add(hill3);

            _arena = arena;
            _config = arena._server._zoneConfig;
            _savedPlayerStats = new Dictionary<string, PlayerStat>();
        }

        public void setTeams(Team team1, Team team2, bool isScrim)
        {
            _team1 = team1;
            _team2 = team2;
            _isScrim = isScrim;
        }


        public void Poll(int now)
        {

            if (now - _lastTickerUpdate >= 1000)
            {
                UpdateTickers();
                _lastTickerUpdate = now;
            }

            if (now - _lastKillStreakUpdate >= 500)
            {
                UpdateKillStreaks();
                _lastKillStreakUpdate = now;
            }

            int countdown = tickChangeHill > 0 ? ((tickChangeHill - now) / 1000) : 0;

            if (_arena._bGameRunning)
            {
                //Time to rotate hills?
                if (countdown == 0)
                {
                    foreach (Hill hill in hills)
                    {
                        hill.active = false;
                    }
                    selectHill();
                }
                if (countdown == 120 && !warnNewHill120)
                {
                    _arena.sendArenaMessage(String.Format
                        ("![Active hill = {0}] Defend it to win! New hill in 120 seconds!", currenthill.name), 4);
                    warnNewHill120 = true;
                }
                if (countdown == 90 && !warnNewHill90)
                {
                    _arena.sendArenaMessage(String.Format
                        ("![Active hill = {0}] Defend it to win! New hill in 90 seconds!", currenthill.name), 4);
                    warnNewHill90 = true;
                }
                //Warn them
                if (countdown == 30 && !warnNewHill30)
                {
                    _arena.sendArenaMessage(String.Format
                        ("![Active hill = {0}] Defend it to win! New hill in 30 seconds!", currenthill.name), 4);
                    warnNewHill30 = true;
                }
            }

            if (_arena._bGameRunning)
            {
                if (team1Score == 1000 && team2Score < team1Score)
                {
                    _arena.gameEnd();
                    winner = _team1;
                }
                if (team2Score == 1000 && team1Score < team2Score)
                {
                    _arena.gameEnd();
                    winner = _team2;
                }
            }

            if (currenthill != null && currenthill.active)
            {
                if (currenthill.controller != null)
                {
                    if (now - tickLastScore >= 5000)
                    {
                        if (_team1 == currenthill.controller)
                            team1Score = team1Score + 10;
                        if (_team2 == currenthill.controller)
                            team2Score = team2Score + 10;

                        tickLastScore = now;

                    }
                }

                currenthill.poll(now);
            }

        }
        #endregion

        #region Gametype Events
        public void gameStart(string map)
        {
            if (_arena.ActiveTeams.Count() == 0)
                return;

            ResetKiller(null);

            _savedPlayerStats.Clear();
            foreach (Player p in _arena.Players)
            {
                PlayerStat temp = new PlayerStat();
                temp.teamname = p._team._name;
                temp.alias = p._alias;
                temp.points = 0;
                temp.assistPoints = 0;
                temp.bonusPoints = 0;
                temp.killPoints = 0;
                temp.playSeconds = 0;
                temp.squad = p._squad;
                temp.kills = 0;
                temp.deaths = 0;
                temp.player = p;
                temp.hasPlayed = p.IsSpectator ? false : true;
                if (!p.IsSpectator)
                {
                    if (p._baseVehicle != null)
                        temp.classType = p._baseVehicle._type.Name;
                }

                temp.lastKillerCount = 0;
                temp.lastUsedWep = null;
                temp.lastUsedWepKillCount = 0;
                temp.lastUsedWepTick = -1;
                temp.potentialHealthHealed = 0;
                temp.onPlayingField = false;
                _savedPlayerStats.Add(p._alias, temp);
            }


            UpdateTickers();

            int timer = 1800 * 100;
            if (!_arena._bIsPublic)
            {
                timer = 1800 * 100;
            }

            selectHill();

            //Let everyone know
            _arena.sendArenaMessage("Game has started!");
            _arena.setTicker(1, 3, timer, "Time Left: ",
                delegate ()
                {   //Trigger game end
                    _arena.gameEnd();
                }
            );
        }

        public bool playerFlagAction(Player player, bool bPickup, bool bInPlace, LioInfo.Flag flag)
        {
            return false;
        }

        /// <summary>
        /// Called when the statistical breakdown is displayed
        /// </summary>
        public void individualBreakdown(Player from, bool bCurrent)
        {	//Allows additional "custom" breakdown information
            from.sendMessage(0, "#Team Statistics Breakdown");

            IEnumerable<Team> activeTeams = _arena.Teams.OrderByDescending(entry => entry._currentGameKills).ToList();
            int idx = 3;	//Only display top three teams
            foreach (Team t in activeTeams)
            {
                if (t == null)
                    continue;

                if (idx-- == 0)
                    break;

                string format = "!3rd (K={0} D={1}): {2}";
                switch (idx)
                {
                    case 2:
                        format = "!1st (K={0} D={1}): {2}";
                        break;
                    case 1:
                        format = "!2nd (K={0} D={1}): {2}";
                        break;
                }

                from.sendMessage(0, string.Format(format,
                    t._currentGameKills, t._currentGameDeaths,
                    t._name));
            }

            from.sendMessage(0, "#Individual Statistics Breakdown");
            idx = 3;        //Only display the top 3 players
            List<Player> rankers = new List<Player>();
            foreach (Player p in _arena.Players.ToList())
            {
                if (p == null)
                    continue;
                if (_savedPlayerStats.ContainsKey(p._alias) && _savedPlayerStats[p._alias].hasPlayed)
                    rankers.Add(p);
            }

            if (rankers.Count > 0)
            {
                var rankedPlayerGroups = rankers.Select(player => new
                {
                    Alias = player._alias,
                    Kills = _savedPlayerStats[player._alias].kills,
                    Deaths = _savedPlayerStats[player._alias].deaths
                })
                .GroupBy(pl => pl.Kills)
                .OrderByDescending(k => k.Key)
                .Take(idx)
                .Select(g => g.OrderBy(plyr => plyr.Deaths));

                foreach (var group in rankedPlayerGroups)
                {
                    if (idx <= 0)
                        break;

                    string placeWord = "";
                    string format = " (K={0} D={1}): {2}";
                    switch (idx)
                    {
                        case 3:
                            placeWord = "!1st";
                            break;
                        case 2:
                            placeWord = "!2nd";
                            break;
                        case 1:
                            placeWord = "!3rd";
                            break;
                    }

                    idx -= group.Count();
                    if (group.First() != null)
                        from.sendMessage(0, string.Format(placeWord + format, group.First().Kills,
                            group.First().Deaths, string.Join(", ", group.Select(g => g.Alias))));
                }

                IEnumerable<Player> specialPlayers = rankers.OrderByDescending(player => _savedPlayerStats[player._alias].deaths);
                int topDeaths = (specialPlayers.First() != null ? _savedPlayerStats[specialPlayers.First()._alias].deaths : 0), deaths = 0;
                if (topDeaths > 0)
                {
                    from.sendMessage(0, "Most Deaths");
                    int i = 0;
                    List<string> mostDeaths = new List<string>();
                    foreach (Player p in specialPlayers)
                    {
                        if (p == null)
                            continue;

                        if (_savedPlayerStats.ContainsKey(p._alias))
                        {
                            deaths = _savedPlayerStats[p._alias].deaths;
                            if (deaths == topDeaths)
                            {
                                if (i++ >= 1)
                                    mostDeaths.Add(p._alias);
                                else
                                    mostDeaths.Add(string.Format("(D={0}): {1}", deaths, p._alias));
                            }
                        }
                    }
                    if (mostDeaths.Count > 0)
                    {
                        string s = string.Join(", ", mostDeaths.ToArray());
                        from.sendMessage(0, s);
                    }
                }

                IEnumerable<Player> Healed = rankers.Where(player => _savedPlayerStats[player._alias].potentialHealthHealed > 0);
                if (Healed.Count() > 0)
                {
                    IEnumerable<Player> mostHealed = Healed.OrderByDescending(player => _savedPlayerStats[player._alias].potentialHealthHealed);
                    idx = 3;
                    from.sendMessage(0, "&Most HP Healed");
                    foreach (Player p in mostHealed)
                    {
                        if (p == null) continue;
                        if (_savedPlayerStats[p._alias] != null)
                        {
                            if (idx-- <= 0)
                                break;

                            string placeWord = "&3rd";
                            string format = " (HP Total={0}): {1}";
                            switch (idx)
                            {
                                case 2:
                                    placeWord = "&1st";
                                    break;
                                case 1:
                                    placeWord = "&2nd";
                                    break;
                            }
                            from.sendMessage(0, string.Format(placeWord + format, _savedPlayerStats[p._alias].potentialHealthHealed, p._alias));
                        }
                    }
                }
            }

            //Are they on the list?
            if (_savedPlayerStats.ContainsKey(from._alias))
            {
                string personalFormat = "!Personal Score: (K={0} D={1})";
                from.sendMessage(0, string.Format(personalFormat,
                    _savedPlayerStats[from._alias].kills,
                    _savedPlayerStats[from._alias].deaths));
            }
            //If not, give them the generic one
            else
            {
                string personalFormat = "!Personal Score: (K=0 D=0)";
                from.sendMessage(0, personalFormat);
            }
        }

        public void gameEnd()
        {
            if (winner != null)
            {
                _arena.sendArenaMessage(String.Format("{0} is victorious! ({1}={2} {3}={4})",
                    winner._name, _team1._name, team1Score, _team2._name, team2Score));
            }
            else
            {
                if (team1Score > team2Score)
                {
                    _arena.sendArenaMessage(String.Format("{0} is victorious! ({1}={2} {3}={4})",
                    _team1._name, _team1._name, team1Score, _team2._name, team2Score));
                }
                else
                {
                    _arena.sendArenaMessage(String.Format("{0} is victorious! ({1}={2} {3}={4})",
                    _team2._name, _team2._name, team2Score, _team1._name, team1Score));
                }
            }

            team1Score = 0;
            team2Score = 0;

            foreach (Hill hill in hills)
            {
                hill.active = false;
            }
            currenthill = null;
        }

        public void gameReset()
        {

        }
        #endregion

        #region Player Events
        public bool playerUnspec(Player player)
        {

            //Add them to the list if not in it
            if (!_savedPlayerStats.ContainsKey(player._alias))
            {
                PlayerStat temp = new PlayerStat();
                temp.alias = player._alias;
                temp.squad = player._squad;
                temp.assistPoints = 0;
                temp.bonusPoints = 0;
                temp.killPoints = 0;
                temp.points = 0;
                temp.playSeconds = 0;
                temp.deaths = 0;
                temp.kills = 0;
                temp.player = player;
                temp.onPlayingField = false;
                _savedPlayerStats.Add(player._alias, temp);
            }
            _savedPlayerStats[player._alias].hasPlayed = true;
            if (player._baseVehicle != null)
                _savedPlayerStats[player._alias].classType = player._baseVehicle._type.Name;

            pickTeam(player);

            return true;
        }


        private void pickTeam(Player player)
        {

            if (_team1.ActivePlayerCount <= _team2.ActivePlayerCount)
            {
                if (player._team != _team1)
                {
                    player.unspec(_team1);
                }
            }
            else
            {
                if (player._team != _team2)
                {
                    player.unspec(_team2);
                }
            }
        }

        public void playerSpec(Player player)
        {


        }

        public void playerSpawn(Player player, bool death)
        {
        }

        public void playerEnterArena(Player player)
        {
            //Add them to the list if not in it
            if (!_savedPlayerStats.ContainsKey(player._alias))
            {
                PlayerStat temp = new PlayerStat();
                temp.squad = player._squad;
                temp.assistPoints = 0;
                temp.bonusPoints = 0;
                temp.killPoints = 0;
                temp.points = 0;
                temp.playSeconds = 0;
                temp.alias = player._alias;
                temp.deaths = 0;
                temp.kills = 0;
                temp.player = player;
                temp.onPlayingField = false;
                _savedPlayerStats.Add(player._alias, temp);
            }
            _savedPlayerStats[player._alias].teamname = player._team._name;
            _savedPlayerStats[player._alias].hasPlayed = player.IsSpectator ? false : true;
            if (player._baseVehicle != null)
                _savedPlayerStats[player._alias].classType = player._baseVehicle._type.Name;
        }

        public void playerLeaveArena(Player player)
        {

        }

        /// <summary>
        /// Triggered when a player tries to heal
        /// </summary>
        public void PlayerRepair(Player from, ItemInfo.RepairItem item)
        {
            if (!_savedPlayerStats.ContainsKey(from._alias))
                return;
            if (item.repairType == 0 && item.repairDistance < 0)
            {   //Get all players near
                List<Player> players = _arena.getPlayersInRange(from._state.positionX, from._state.positionY, -item.repairDistance);
                int totalHealth = 0;
                foreach (Player p in players)
                {
                    if (p == null || p == from || p._state.health >= 100 || p._state.health <= 0)
                        continue;
                    totalHealth += (p._baseVehicle._type.Hitpoints - p._state.health);
                }
                _savedPlayerStats[from._alias].potentialHealthHealed += totalHealth;
            }
        }


        public void playerExplosion(Player player, ItemInfo.Projectile weapon, short posX, short posY, short posZ)
        {

        }

        public void playerPlayerKill(Player victim, Player killer)
        {   //Update our kill streak
            UpdateKiller(killer);
            UpdateDeath(victim, killer);

            if (_savedPlayerStats.ContainsKey(killer._alias))
            {
                _savedPlayerStats[killer._alias].kills++;
                long wepTick = _savedPlayerStats[killer._alias].lastUsedWepTick;
                if (wepTick != -1)
                    UpdateWeaponKill(killer);
            }
            if (_savedPlayerStats.ContainsKey(victim._alias))
                _savedPlayerStats[victim._alias].deaths++;

            //Should we award points for a defend?
            if (isOnHill(killer) && killer._team == currenthill.controller)
            {
                _arena.sendArenaMessage(String.Format("{0} has earned his team 5 points for defending hill {1}", killer._alias, currenthill.name));

                if (killer._team == _team1)
                    team1Score = team1Score + 5;
                if (killer._team == _team2)
                    team2Score = team2Score + 5;
            }

            if (killer != null && victim != null && victim._bounty >= 300)
                _arena.sendArenaMessage(string.Format("{0} has ended {1}'s bounty.", killer._alias, victim._alias), 8);
        }

        public void playerDeath(Player victim, Player killer, Helpers.KillType killType, CS_VehicleDeath update)
        {

        }
        #endregion

        #region Koth Helpers

        private bool isOnHill(Player player)
        {
            List<Player> playersInHill = _arena.getPlayersInBox(
                currenthill.posX, currenthill.posY, currenthill.width, 
                currenthill.height).Where(p => !p.IsDead).ToList();

            return playersInHill.Contains(player);
        }

        private void selectHill()
        {
            Random rand = new Random();
            int h = rand.Next(0, 3);
            //First selection!
            if (currenthill == null)
            {

                currenthill = hills[h];
                _arena.sendArenaMessage(String.Format("Hill {0} is now active!", hills[h].name));
                tickChangeHill = (Environment.TickCount + (15000 * 10));
                warnNewHill30 = false;
                warnNewHill90 = false;
                warnNewHill120 = false;
                hills[h].active = true;
                return;
            }
            //Don't use the same hill!
            if (currenthill == hills[h])
            {
                selectHill();
                return;
            }

            _arena.sendArenaMessage(String.Format("Hill {0} is now active!", hills[h].name));
            tickChangeHill = (Environment.TickCount + (15000 * 10));
            warnNewHill30 = false;
            warnNewHill90 = false;
            warnNewHill120 = false;
            hills[h].active = true;
            currenthill = hills[h];
        }
        #endregion

        #region Updation Calls
        /// <summary>
        /// Updates our players kill streak timer
        /// </summary>
        private void UpdateKillStreaks()
        {
            foreach (PlayerStat p in _savedPlayerStats.Values)
            {
                if (p.lastUsedWepTick == -1)
                    continue;

                if (Environment.TickCount - p.lastUsedWepTick <= 0)
                    ResetWeaponTicker(p.player);
            }
        }

        /// <summary>
        /// Updates our tickers
        /// </summary>
        public void UpdateTickers()
        {
            if (!_arena._bGameRunning)
            { return; }

            IEnumerable<Team> active = _arena.ActiveTeams;
            if (activeTeams != null && activeTeams.Count() > 0)
            {
                active = activeTeams;
            }

            Team collie = active.Count() > 1 ? active.ElementAt(1) : _arena.getTeamByName(_config.teams[0].name);
            Team titan = active.Count() > 0 ? active.ElementAt(0) : _arena.getTeamByName(_config.teams[1].name);

            string format = string.Format("{0}={1} - {2}={3}", titan._name, team1Score, collie._name, team2Score);
            //We playing more events at the same time?
            if (active.Count() > 3)
            {
                Team third = active.ElementAt(2);
                Team fourth = active.ElementAt(3);
                format = string.Format("{0}={1} - {2}={3} | {4}={5} - {6}={7}", titan._name, titan._currentGameKills, collie._name, collie._currentGameKills,
                    third._name, third._currentGameKills, fourth._name, fourth._currentGameKills);
            }
            _arena.setTicker(1, 2, 0, format);

            //1st and 2nd place
            List<Player> ranked = new List<Player>();
            foreach (Player p in _arena.Players)
            {
                if (p == null)
                    continue;
                if (_savedPlayerStats.ContainsKey(p._alias) && _savedPlayerStats[p._alias].hasPlayed)
                    ranked.Add(p);
            }

            IEnumerable<Player> ranking = ranked.OrderBy(player => _savedPlayerStats[player._alias].deaths).OrderByDescending(player => _savedPlayerStats[player._alias].kills);
            int idx = 3; format = "";
            foreach (Player rankers in ranking)
            {
                if (idx-- == 0)
                    break;

                switch (idx)
                {
                    case 2:
                        format = string.Format("1st: {0}(K={1} D={2})", rankers._alias,
                          _savedPlayerStats[rankers._alias].kills, _savedPlayerStats[rankers._alias].deaths);
                        break;
                    case 1:
                        format = (format + string.Format(" 2nd: {0}(K={1} D={2})", rankers._alias,
                          _savedPlayerStats[rankers._alias].kills, _savedPlayerStats[rankers._alias].deaths));
                        break;
                }
            }
            if (!_arena.recycling)
                _arena.setTicker(2, 0, 0, format);
        }

        /// <summary>
        /// Resets the last killer object
        /// </summary>
        public void ResetKiller(Player killer)
        {
            lastKiller = killer;
        }

        /// <summary>
        /// Resets the weapon ticker to default (Time Expired)
        /// </summary>
        public void ResetWeaponTicker(Player target)
        {
            if (_savedPlayerStats.ContainsKey(target._alias))
            {
                _savedPlayerStats[target._alias].lastUsedWep = null;
                _savedPlayerStats[target._alias].lastUsedWepKillCount = 0;
                _savedPlayerStats[target._alias].lastUsedWepTick = -1;
            }
        }

        /// <summary>
        /// Updates the killer and their counter
        /// </summary>
        public void UpdateKiller(Player killer)
        {
            if (_savedPlayerStats.ContainsKey(killer._alias))
            {
                _savedPlayerStats[killer._alias].lastKillerCount++;
                switch (_savedPlayerStats[killer._alias].lastKillerCount)
                {
                    case 6:
                        _arena.sendArenaMessage(string.Format("{0} is on fire!", killer._alias), 17);
                        break;
                    case 8:
                        _arena.sendArenaMessage(string.Format("Someone kill {0}!", killer._alias), 18);
                        break;
                    case 10:
                        _arena.sendArenaMessage(string.Format("{0} is dominating!", killer._alias), 19);
                        break;
                    case 12:
                        _arena.sendArenaMessage(string.Format("DEATH TO {0}!", killer._alias), 30);
                        break;
                }
            }

            //Is this first blood?
            if (lastKiller == null)
            {
                //It is, lets make the sound
                _arena.sendArenaMessage(string.Format("{0} has drawn first blood.", killer._alias), 9);
            }
            lastKiller = killer;
        }

        /// <summary>
        /// Updates the victim's kill streaks
        /// </summary>
        public void UpdateDeath(Player victim, Player killer)
        {
            if (_savedPlayerStats.ContainsKey(victim._alias))
            {
                if (_savedPlayerStats[victim._alias].lastKillerCount >= 6)
                {
                    _arena.sendArenaMessage(string.Format("{0}", killer != null ? killer._alias + " has ended " + victim._alias + "'s kill streak." :
                        victim._alias + "'s kill streak has ended."), 7);
                }
                _savedPlayerStats[victim._alias].lastKillerCount = 0;
            }
        }

        /// <summary>
        /// Updates the last fired weapon and the ticker
        /// </summary>
        public void UpdateWeapon(Player from, ItemInfo.Projectile usedWep)
        {
            if (_savedPlayerStats.ContainsKey(from._alias))
            {
                _savedPlayerStats[from._alias].lastUsedWep = usedWep;
                //500 = Alive time for the schrapnel after main weap explosion
                _savedPlayerStats[from._alias].lastUsedWepTick = DateTime.Now.AddTicks(500).Ticks;
            }
        }

        /// <summary>
        /// Updates the last weapon kill counter
        /// </summary>
        public void UpdateWeaponKill(Player from)
        {
            if (_savedPlayerStats.ContainsKey(from._alias))
            {
                _savedPlayerStats[from._alias].lastUsedWepKillCount++;
                ItemInfo.Projectile lastUsedWep = _savedPlayerStats[from._alias].lastUsedWep;
                if (lastUsedWep == null)
                    return;

                if (lastUsedWep.name.Contains("Combat Knife"))
                    _arena.sendArenaMessage(string.Format("{0} is throwing out the knives.", from._alias), 6);

                switch (_savedPlayerStats[from._alias].lastUsedWepKillCount)
                {
                    case 2:
                        _arena.sendArenaMessage(string.Format("{0} just got a double {1} kill.", from._alias, lastUsedWep.name), 13);
                        break;
                    case 3:
                        _arena.sendArenaMessage(string.Format("{0} just got a triple {1} kill.", from._alias, lastUsedWep.name), 14);
                        break;
                    case 4:
                        _arena.sendArenaMessage(string.Format("A 4 {0} kill by {0}?!?", lastUsedWep.name, from._alias), 15);
                        break;
                    case 5:
                        _arena.sendArenaMessage(string.Format("Unbelievable! {0} with the 5 {1} kill?", from._alias, lastUsedWep.name), 16);
                        break;
                }
            }
        }
    }
}
#endregion