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 Demolition
    {
        private Arena _arena;
        private bool _gameStarted;
        public bool _isScrim = false;
        private Dictionary<string, PlayerStats> _playerStats;
        private Team _team1;
        private Team _team2;
        private string _map;
        private int _lastTickerUpdate;
        private int _lastKillStreakUpdate;

        //demolition variables
        private List<Round> _rounds;
        private int _currentRound;
        public bool _roundStarted;
        private bool _armed;
        private Computer _armedBomb;
        private Player _playerBombArm;
        private int _tickedArmed;
        private int _tickDetonate;
        private bool _eliminationWarn = false;
        private bool _60warning = false;
        private bool _30warning = false;
        private bool _10warning = false;
        private string _bombCoord;
        private Team _winner;
        private int _team1w;
        private int _team2w;
        private int _tickStartDefuse = 0;
        private Player _defusee;
        private Dictionary<string, int> playerDeaths;



        #region Objects
        private class Round
        {
            public Team offense;
            public Team defense;
            public Team winner;
        }

        private Player lastKiller;

        private class PlayerStats
        {
            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 bool eliminated { 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; }
            public int arms { get; set; }
            public int disarms { 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 Main Updaters
        public Demolition(Arena arena)
        {
            _arena = arena;
            _playerStats = new Dictionary<string, PlayerStats>();
        }

        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;
            }

            //Check for round wins!
            if (_roundStarted)
            {
                //Detonation?
                if (_armed)
                {
                    int countdown = _tickDetonate > 0 ? ((_tickDetonate - now) / 1000) : 0;
                    //Give some warnings
                    switch (countdown)
                    {
                        case 10:
                            if (!_10warning)
                            {
                                _rounds[_currentRound - 1].defense.sendArenaMessage(
                                    String.Format("!Defense, we have to defuse that bomb! 10 seconds left to detonation. " +
                                    "Bomb location = {0}", _bombCoord), 23);
                                _10warning = true;
                            }
                            break;
                        case 30:
                            if (!_30warning)
                            {
                                _rounds[_currentRound - 1].defense.sendArenaMessage(
                                    String.Format("!Defense, we have to defuse that bomb! 30 seconds left to detonation. " +
                                    "Bomb location = {0}", _bombCoord), 23);
                                _30warning = true;
                            }
                            break;
                        case 60:
                            if (!_60warning)
                            {
                                _rounds[_currentRound - 1].defense.sendArenaMessage(
                                    String.Format("!Defense, we have to defuse that bomb! 60 seconds left to detonation. " +
                                    "Bomb location = {0}", _bombCoord), 23);
                                _60warning = true;
                            }
                            break;
                        default:
                            //Fission Mailed!
                            if (countdown <= 0)
                            {
                                endRound(_rounds[_currentRound - 1].offense, false, false, true);
                                _armed = false;
                                _tickedArmed = 0;
                                _tickDetonate = 0;
                                _eliminationWarn = false;
                                _armedBomb.kill(null);
                                _armedBomb.destroy(false);
                               

                            }
                            break;
                    }
                }
                //Elimination?
                if (!_armed && _roundStarted)
                {
                    if (_team1.ActivePlayerCount == 0)
                        endRound(_team2, true, false, false);
                    if (_team2.ActivePlayerCount == 0)
                        endRound(_team1, true, false, false);
                }

                if (_armed && _roundStarted)
                {
                    if (_tickStartDefuse > 0)
                    {
                        int countdown = _tickStartDefuse > 0 ? ((_tickStartDefuse - now) / 1000) : 0;
                        if (countdown <= 0)
                        {
                            if (_defusee == null)
                                return;

                            _arena.sendArenaMessage("Bomb has been defused!", 21);


                            //Update stats
                            if (_playerStats.ContainsKey(_defusee._alias))
                                _playerStats[_defusee._alias].disarms++;

                            _armed = false;
                            _tickedArmed = 0;
                            _defusee = null;
                            _tickStartDefuse = 0;
                            //_arena.setTicker(1, 0, 0, "", null);

                            endRound(_rounds[_currentRound - 1].defense, false, true, false);

                        }
                    }
                }
                //Are we armed? Defense still has to defuse!
                if (_armed && _rounds[_currentRound -1].offense.ActivePlayerCount == 0 && !_eliminationWarn && _roundStarted)
                {
                    _rounds[_currentRound - 1].defense.sendArenaMessage(
                        "!Defense, The enemy team is eliminated! Defuse that bomb before it's too late!", 25);
                    _eliminationWarn = true;
                }
                if (_armed && _rounds[_currentRound - 1].defense.ActivePlayerCount == 0 && _roundStarted)
                {
                    endRound(_rounds[_currentRound - 1].offense, true, false, false);
                }
            }
        }
        #endregion

        #region Gametype Events
        public void gameStart(string map)
        {
            _currentRound = 1;
            Team team1 = _arena.getTeamByName("Titan Militia");
            Team team2 = _arena.getTeamByName("Collective Military");
            _map = map;

            _team1w = 0;
            _team2w = 0;

            if (map.Contains("RedBlue"))
            {
                team1 = _arena.getTeamByName("Red");
                team2 = _arena.getTeamByName("Blue");

            }
            if (map.Contains("GreenYellow"))
            {
                team1 = _arena.getTeamByName("Green");
                team2 = _arena.getTeamByName("Yellow");
            }
            if (map.Contains("PinkPurple"))
            {
                team1 = _arena.getTeamByName("Pink");
                team2 = _arena.getTeamByName("Purple");
            }
            if (map.Contains("GoldSilver"))
            {
                team1 = _arena.getTeamByName("Gold");
                team2 = _arena.getTeamByName("Silver");
            }

            //Don't override teams!
            if (!_isScrim)
            {
                _team1 = team1;
                _team2 = team2;
            }

            //Spawn some bomb sites!
            spawnBombSites(_map);


            //Setup our rounds and create some stats
            roundSetup(team1, team2);
            aggregateStats();


            _arena.sendArenaMessage("Game has started!");

            //Lets go!
            startRound();
        }

        public void gameEnd()
        {
            _roundStarted = false;

            if (_isScrim)
            _isScrim = false;

            _arena.sendArenaMessage(String.Format("Game Over! {0} wins!", _winner._name), 27);
        }

        public void gameReset()
        {

        }

        /// <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 Rounds Won Breakdown");
            if (_team1w > _team2w)
            {
                from.sendMessage(0, String.Format("!1st {0} (W={1} L={2})", _team1._name, _team1w, _team2w));
                from.sendMessage(0, String.Format("!2nd {0} (W={1} L={2})", _team2._name, _team2w, _team1w));
            }
            else
            {
                from.sendMessage(0, String.Format("!1st {0} (W={1} L={2})", _team2._name, _team2w, _team1w));
                from.sendMessage(0, String.Format("!2nd {0} (W={1} L={2})", _team1._name, _team1w, _team2w));
            }
        }
        #endregion

        #region Player Events

        public bool playerUnspec(Player player)
        {
            bool newplayer = false;

            //New player?
            if (!_playerStats.ContainsKey(player._alias))
            {
                //Start up some stats for the fella
                aggregateStats(player);
            }

            //Don't allow anyone in during a round!
            if (_roundStarted && player._team._name != "spec")
            {   //Let him know why
                player.sendMessage(0, "A Demolition round is currently in progress," +
                    "you will be automatically unspecced to your starting position next round!");
                return false;
            }
            if (_roundStarted && player._team._name == "spec")
            {
                player.sendMessage(0, "A Demolition round is currently in progress," +
                    "you will be automatically unspecced to your starting position next round!");
                pickTeam(player, newplayer);
                return false;
            }

            pickTeam(player, newplayer);
            return true;
        }

        public void playerSpec(Player player)
        {
        }

        public void playerEnterArena(Player player)
        {
        }

        public void playerLeaveArena(Player player)
        {
        }

        /// <summary>
        /// Handles a player's produce request
        /// </summary>
        [Scripts.Event("Player.Produce")]
        public bool playerProduce(Player player, Computer computer, VehInfo.Computer.ComputerProduct product)
        {
            if (computer._type.Id == 402)
            {


                //Arm?
                if (product.Title == "Arm" && player._team == _rounds[_currentRound - 1].offense)
                {

                    if (_arena.getFlag("Bomb Titan").carrier != player && _arena.getFlag("Bomb Collective").carrier != player)
                        return false;

                    if (!_armed)
                    {

                        //Reset the bomb flag and do some 'splainin
                        _arena.flagReset();
                        _arena.flagSpawn();
                        _bombCoord = Helpers.posToLetterCoord(computer._state.positionX, computer._state.positionY);
                        _arena.sendArenaMessage(String.Format(
                            "&Bomb at {0} has been planted!", _bombCoord), 20);
                        _armed = true;
                        _armedBomb = computer;
                        _tickedArmed = Environment.TickCount;
                        _tickDetonate = (Environment.TickCount + (9000 * 10));
                        _playerBombArm = player;


                        _arena.setTicker(1, 0, 90 * 100, String.Format("{0} bombsite detonation in: ", _bombCoord));


                        //Update stats
                        if (_playerStats.ContainsKey(player._alias))
                        _playerStats[player._alias].arms++;
                    }
                }

                //Disarm?
                if (product.Title == "Disarm" && player._team == _rounds[_currentRound - 1].defense && computer == _armedBomb)
                {
                    //Are we armed?
                    if (_armed)
                    {
                        if (_defusee == null)
                        {
                            _defusee = player;
                            _tickStartDefuse = (Environment.TickCount + (800 * 10));
                            int countdown = _tickStartDefuse > 0 ? ((_tickStartDefuse - Environment.TickCount) / 1000) : 0;
                            player.inventoryModify(20, 1);
                            player.sendMessage(0, String.Format("Defusing in {0} seconds... Don't die!", countdown));
                            _arena.sendArenaMessage(String.Format("{0} is defusing the bomb, Kill them before they finish!", player._alias));
                        }
                    }
                }
            }

            return true;
        }

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

            if (weapon.name.Contains("LAW") || weapon.name.Contains("Hand Grenade")
               || weapon.name.Contains("Grenade Launcher") || weapon.name.Contains("Incendiary Grenade")
               || weapon.name.Contains("Demo Charge") || weapon.name.Contains("Combat Knife"))
                UpdateWeapon(player, weapon);

        }

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

            if (_playerStats.ContainsKey(killer._alias))
            {
                long wepTick = _playerStats[killer._alias].lastUsedWepTick;
                if (wepTick != -1)
                    UpdateWeaponKill(killer);
            }

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

        /// <summary>
        /// Triggered when a player tries to heal
        /// </summary>
        public void PlayerRepair(Player from, ItemInfo.RepairItem item)
        {
            if (!_playerStats.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);
                }
                _playerStats[from._alias].potentialHealthHealed += totalHealth;
            }
        }

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

            UpdateDeath(victim, killer);

            //Are we currently running a round?
            if (_roundStarted)
            {
                if (victim == _defusee)
                {
                    _tickStartDefuse = 0;
                    _defusee = null;
                }

                //Increment stats
                if (_playerStats.ContainsKey(victim._alias))
                    _playerStats[victim._alias].deaths++;
                if (_playerStats.ContainsKey(killer._alias))
                    _playerStats[killer._alias].kills++;

                if (playerDeaths.ContainsKey(victim._alias))
                {
                    playerDeaths[victim._alias]++;
                }

                if (playerDeaths[victim._alias] >= 2)
                {

                    //Single death elimination!
                    _arena.sendArenaMessage(String.Format("!{0} has been eliminated!", victim._alias));
                    victim.spec(victim._team);
                    victim.sendMessage(0, "&You have been eliminated, you will automatically be unspecced onto your team at the start of the next round!");
                }

            }
        }

        public bool playerFlagAction(Player player, bool bPickup, bool bInPlace, LioInfo.Flag flag)
        {

            if (!_playerStats.ContainsKey(player._alias))
                return false;

            if (player._team == _rounds[_currentRound - 1].defense)
                return false;


            return true;
        }

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

        private bool pickTeam(Player player, bool newPlayer)
        {

            //Put him back ingame on his own team if hes already on one
            if (player._team._name != "spec" && !_roundStarted)
            {
                player.unspec(player._team);
                return true;
            }

            if (_roundStarted)

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

                        player.spec(_team2);
                    }
                }
            }

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

                    player.unspec(_team2);
                }
            }
            return true;
        }


        #endregion

        #region Round Updaters

        public void startRound()
        {
            Team offense = _rounds.ElementAt(_currentRound - 1).offense;
            Team defense = _rounds.ElementAt(_currentRound - 1).defense;

            spawnBombSites(_map);

            foreach (Player player in _team1.AllPlayers)
            {
                pickTeam(player, false);
                Logic_Assets.RunEvent(player, _arena._server._zoneConfig.EventInfo.startGame);
            }
            foreach (Player player in _team2.AllPlayers)
            {
                pickTeam(player, false);
                Logic_Assets.RunEvent(player, _arena._server._zoneConfig.EventInfo.startGame);
            }

            playerDeaths = new Dictionary<string, int>();
            foreach (Player player in _arena.PlayersIngame)
            {
                playerDeaths.Add(player._alias, 0);
            }


            //Spawn the bomb for the offense!
           // bombSpawn(_rounds[_currentRound - 1].offense._id);

            //Do some 'splainin
            offense.sendArenaMessage("&Offense: Plant the bomb at either bomb site, or eliminate the enemy team to win!", 24);
            defense.sendArenaMessage("&Defense: Defend the bomb sites or eliminate the enemy team to win!", 24);


            _arena.setTicker(1, 3, 300 * 100, "Time Left: ",
        delegate ()
        {   //Trigger game end
            endRound(_rounds[_currentRound - 1].defense, false, true, false);
        });

            _roundStarted = true;
        }

        public void endRound(Team winner, bool elimination, bool timeExpired, bool detonation)
        {
            _roundStarted = false;
            string wincondition = "";

            
            _arena.setTicker(1, 0, 0, "", null);


            _armed = false;
            _tickedArmed = 0;
            _60warning = false;
            _30warning = false;
            _10warning = false;

            _arena.flagReset();
            _arena.flagSpawn();

            _arena.sendArenaMessage(String.Format("End of Round {0}", _currentRound), 28);
            //Was there a winner? How did they win?
            if (winner != null)
            {
                if (elimination)
                    wincondition = "{0} won round {1} by elimination!";
                if (timeExpired)
                    wincondition = "{0} won round {1} by defense!";
                if (detonation)
                    wincondition = "{0} won round {1} by detonation!";

                _rounds[_currentRound - 1].winner = winner;
            }
            else
            {
                wincondition = "Nobody was victorious!";
            }


            _arena.sendArenaMessage(String.Format(wincondition, winner._name, _currentRound));
            _arena.sendArenaMessage("#Individual Statistics Breakdown");


            List<Player> playersInGame = new List<Player>();
            foreach (Player p in _arena.Players)
            {
                if (_playerStats.ContainsKey(p._alias))
                    playersInGame.Add(p);
            }
            List<Player> rankedPlayers = playersInGame.OrderByDescending
                (player => _playerStats[player._alias].kills).ThenByDescending(
                player => _playerStats[player._alias].deaths).ThenByDescending(
                player => _playerStats[player._alias].arms).ThenByDescending(
                player => _playerStats[player._alias].disarms).ToList();

            int idx = 3;    //Only display top three players

            foreach (Player p in rankedPlayers)
            {   //Do they even have stats?
                if (true ? _playerStats[p._alias] == null : _playerStats[p._alias] == null)
                    continue;

                if (idx-- == 0)
                    break;

                string format = "!3rd (K={0} D={1} Arms={2} Disarms={3}): {4}";

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

                _arena.sendArenaMessage(string.Format(format,
                    (_playerStats[p._alias].kills),
                    (_playerStats[p._alias].deaths),
                    (_playerStats[p._alias].arms),
                    (_playerStats[p._alias].disarms),
                    p._alias));
            }

            //Lets check for potential winners
            if (winner == _team1)
                _team1w++;
            if (winner == _team2)
                _team2w++;

            if (_team1w >= 3)
            {
                _winner = _team1;
                _arena.gameEnd();
                return;
            }
            if (_team2w >= 3)
            {
                _winner = _team2;
                _arena.gameEnd();
                return;
            }

            //Have we reached our maximum amount of rounds?
            if (_currentRound >= Settings.demoRounds)
            {
                _arena.gameEnd();

                foreach (Player player in _team1.AllPlayers)
                {
                    pickTeam(player, false);
                    Logic_Assets.RunEvent(player, _arena._server._zoneConfig.EventInfo.startGame);
                }
                foreach (Player player in _team2.AllPlayers)
                {
                    pickTeam(player, false);
                    Logic_Assets.RunEvent(player, _arena._server._zoneConfig.EventInfo.startGame);
                }

                return;
            }

            _currentRound++;


            _arena.setTicker(1, 3, 15 * 100, "Next round in.. ",
            delegate ()
            {   //Trigger the next round!
                startRound();
            });
        }
        public void roundSetup(Team home, Team away)
        {
            _rounds = new List<Round>();

            //Construct our Rounds
            for (int x = 1; x <= 5; x++)
            {
                Round round = new Round();

                //Even = home defense
                if (x % 2 == 0)
                {
                    round.defense = home;
                    round.offense = away;
                }
                //Odd = away defense
                else
                {
                    round.defense = away;
                    round.offense = home;
                }

                //Add it!
                _rounds.Add(round);
            }
        }
        #endregion

        #region Stats Updaters
        public void aggregateStats()
        {
            _playerStats = new Dictionary<string, PlayerStats>();

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

                stats.lastKillerCount = 0;
                stats.lastUsedWep = null;
                stats.lastUsedWepKillCount = 0;
                stats.lastUsedWepTick = -1;
                stats.potentialHealthHealed = 0;
                stats.onPlayingField = false;
                _playerStats.Add(player._alias, stats);

            }
        }

        public void aggregateStats(Player player)
        {
            //Do nothing if the player already exists!
            if (_playerStats.ContainsKey(player._alias))
                return;

            //Populate some values
            PlayerStats stats = new PlayerStats();
            stats.arms = 0;
            stats.deaths = 0;
            stats.kills = 0;
            stats.disarms = 0;
            stats.teamname = player._team._name;
            stats.alias = player._alias;
            stats.points = 0;
            stats.assistPoints = 0;
            stats.bonusPoints = 0;
            stats.killPoints = 0;
            stats.playSeconds = 0;
            stats.squad = player._squad;
            stats.player = player;
            stats.hasPlayed = player.IsSpectator ? false : true;
            if (!player.IsSpectator)
            {
                if (player._baseVehicle != null)
                    stats.classType = player._baseVehicle._type.Name;
            }

            stats.lastKillerCount = 0;
            stats.lastUsedWep = null;
            stats.lastUsedWepKillCount = 0;
            stats.lastUsedWepTick = -1;
            stats.potentialHealthHealed = 0;
            stats.onPlayingField = false;

            //Add them!
            _playerStats.Add(player._alias, stats);
        }

      
        #endregion

        #region KillStreaks
        /// <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 (_playerStats.ContainsKey(target._alias))
            {
                _playerStats[target._alias].lastUsedWep = null;
                _playerStats[target._alias].lastUsedWepKillCount = 0;
                _playerStats[target._alias].lastUsedWepTick = -1;
            }
        }

        /// <summary>
        /// Updates the killer and their counter
        /// </summary>
        public void UpdateKiller(Player killer)
        {
            if (_playerStats.ContainsKey(killer._alias))
            {
                _playerStats[killer._alias].lastKillerCount++;
                switch (_playerStats[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 (_playerStats.ContainsKey(victim._alias))
            {
                if (_playerStats[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);
                }
                _playerStats[victim._alias].lastKillerCount = 0;
            }
        }

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

        /// <summary>
        /// Updates the last weapon kill counter
        /// </summary>
        public void UpdateWeaponKill(Player from)
        {
            if (_playerStats.ContainsKey(from._alias))
            {
                _playerStats[from._alias].lastUsedWepKillCount++;
                ItemInfo.Projectile lastUsedWep = _playerStats[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 (_playerStats[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;
                }
            }
        }

        private void UpdateKillStreaks()
        {
            foreach (PlayerStats p in _playerStats.Values)
            {
                if (p.lastUsedWepTick == -1)
                    continue;

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

        #region Hides/Flag Methods
        public void bombSpawn(int freq)
        {   //Set offsets
            int levelX = _arena._server._assets.Level.OffsetX * 16;
            int levelY = _arena._server._assets.Level.OffsetY * 16;
            Arena.FlagState fs = _arena.getFlag("Bomb");
            short posX = 0;
            short posY = 0;

            if (freq == 0)
            {
                posX = 39;
                posY = 144;
            }
            if (freq == 1)
            {
                posX = 764;
                posY = 232;
            }


            fs.posX = posX;
            fs.posY = posY;
            fs.oldPosX = fs.posX;
            fs.oldPosY = fs.posY;


            fs.team = null;
            fs.carrier = null;
            fs.bActive = true;

            Helpers.Object_Flags(_arena.Players, fs);
        }

        private void spawnBombSites(string map)
        {

            List<Arena.HideState> bombsites = new List<Arena.HideState>();

            //What map are we on?
            if (map.Contains("RedBlue"))
                bombsites = _arena._hides.FindAll(h => h.Hide.GeneralData.Name.Contains("RedBlue"));
            if (map.Contains("KaiserPass"))
                bombsites = _arena._hides.FindAll(h => h.Hide.GeneralData.Name.Contains("KaiserPass"));
            if (map.Contains("PinkPurple"))
                bombsites = _arena._hides.FindAll(h => h.Hide.GeneralData.Name.Contains("PinkPurple"));

            

            //None to spawn?
            if (bombsites.Count == 0)
                return;

            foreach (Arena.HideState hs in bombsites)
            {

                short posX = (short)(hs.Hide.GeneralData.OffsetX - (_arena._server._assets.Level.OffsetX * 16));
                short posY = (short)(hs.Hide.GeneralData.OffsetY - (_arena._server._assets.Level.OffsetY * 16));

                VehInfo vehicle = _arena._server._assets.getVehicleByID(-hs.Hide.HideData.HideId);

                //Create a suitable state
                Helpers.ObjectState state = new Helpers.ObjectState();

                state.positionX = posX;
                state.positionY = posY;

                Team team = null;
                team = _arena.getTeamByID(hs.Hide.HideData.AssignFrequency);

                _arena.newVehicle(vehicle, team, null, state);
            }
        }
        #endregion

        #region Ticker Updaters
        public void UpdateTickers()
        {
            if (!_arena._bGameRunning)
            { return; }

            IEnumerable<Team> active = _arena.ActiveTeams;

            string format = string.Format("{0}={1} - {2}={3}", _team1._name, _team1w, _team2._name, _team2w);

            _arena.setTicker(1, 2, 0, format);

        }
        #endregion

    } 
}
